[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[committed][PATCH] Handle unsorted section header table



Hi,

Committed as attached.

Thanks,
- Tom
Handle unsorted section header table

Consider a hello world, with .gdb_index added by the gold linker.  When
running dwz, we run into this error:
...
$ gcc hello.c -g -fuse-ld=gold -Wl,--gdb-index
$ dwz a.out
dwz: Section offsets in a.out not monotonically increasing
...

Inspecting the section offsets around .gdb_index:
...
$ readelf -S a.out | grep '[[]' | egrep -C1  'Offset|\.gdb_index'
  [Nr] Name              Type             Address           Offset
  [ 0]                   NULL             0000000000000000  00000000
--
  [31] .debug_str        PROGBITS         0000000000000000  00001b2f
  [32] .gdb_index        PROGBITS         0000000000000000  000034b0
  [33] .debug_ranges     PROGBITS         0000000000000000  000021f0
...
indeed shows that the offsets are not monotonically increasing.

Handle unsorted section header table in write_dso by rewriting the file
offfset alignment updating loops to loop in file offset order.

2019-03-23  Tom de Vries  <tdevries@suse.de>

	PR dwz/24249
	* Makefile (TEST_EXECS): Add hello-gold-gdb-index.
	(hello-gold-gdb-index): New target.
	* dwz.c (write_dso): Handle aligning file offsets of unordered section
	header table.
	* testsuite/dwz.tests/dwz-tests.exp: Require hello-gold-gdb-index for
	gold-gdb-index.sh.
	* testsuite/dwz.tests/gold-gdb-index.sh: New test.

---
 Makefile                              |  6 +++++-
 dwz.c                                 | 31 +++++++++++++------------------
 testsuite/dwz.tests/dwz-tests.exp     |  3 +++
 testsuite/dwz.tests/gold-gdb-index.sh |  7 +++++++
 4 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/Makefile b/Makefile
index 2d9ba4e..1193283 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ PWD:=$(shell pwd -P)
 
 TEST_SRC = $(srcdir)/testsuite/dwz.tests
 TEST_EXECS = hello dw2-restrict py-section-script dwz-for-test min two-typedef \
-	dw2-skip-prologue start implptr-64bit-d2o4a8r8t0
+	dw2-skip-prologue start implptr-64bit-d2o4a8r8t0 hello-gold-gdb-index
 
 hello:
 	$(CC) $(TEST_SRC)/hello.c -o $@ -g
@@ -62,6 +62,10 @@ implptr-64bit-d2o4a8r8t0:
 	$(CC) $(TEST_SRC)/implptr-64bit-d2o4a8r8t0.S $(TEST_SRC)/main.c -o $@ \
 	  -g || touch $@
 
+hello-gold-gdb-index:
+	$(CC) $(TEST_SRC)/hello.c -g -fuse-ld=gold -Wl,--gdb-index -o $@ \
+	    || touch $@
+
 # On some systems we need to set and export DEJAGNU to suppress
 # WARNING: Couldn't find the global config file.
 DEJAGNU ?= /dev/null
diff --git a/dwz.c b/dwz.c
index 3389ff0..a73fe38 100644
--- a/dwz.c
+++ b/dwz.c
@@ -10667,9 +10667,12 @@ write_dso (DSO *dso, const char *file, struct stat *st)
 	     >= min_shoff aren't non-ALLOC.  */
 	  GElf_Off last_shoff = 0;
 	  int k = -1;
-	  bool shdr_placed = false;
-	  for (j = 1; j < dso->ehdr.e_shnum; ++j)
-	    if (dso->shdr[j].sh_offset < min_shoff && !last_shoff)
+	  int l;
+	  for (l = 1, j = sorted_section_numbers[l]; l <= dso->ehdr.e_shnum;
+	       ++l, j = sorted_section_numbers[l])
+	    if (j == dso->ehdr.e_shnum)
+	      continue;
+	    else if (dso->shdr[j].sh_offset < min_shoff && !last_shoff)
 	      continue;
 	    else if ((dso->shdr[j].sh_flags & SHF_ALLOC) != 0)
 	      {
@@ -10677,35 +10680,27 @@ write_dso (DSO *dso, const char *file, struct stat *st)
 			     "ones", dso->filename);
 		return 1;
 	      }
-	    else if (dso->shdr[j].sh_offset < last_shoff)
-	      {
-		error (0, 0, "Section offsets in %s not monotonically "
-			     "increasing", dso->filename);
-		return 1;
-	      }
 	    else
 	      {
+		assert (dso->shdr[j].sh_offset >= last_shoff);
+
 		if (k == -1)
-		  k = j;
+		  k = l;
 		last_shoff = dso->shdr[j].sh_offset + dso->shdr[j].sh_size;
 	      }
 	  last_shoff = min_shoff;
-	  for (j = k; j <= dso->ehdr.e_shnum; ++j)
+	  for (l = k, j = sorted_section_numbers[l]; l <= dso->ehdr.e_shnum;
+	       ++l, j = sorted_section_numbers[l])
 	    {
-	      if (!shdr_placed
-		  && ehdr.e_shoff >= min_shoff
-		  && (j == dso->ehdr.e_shnum
-		      || ehdr.e_shoff < dso->shdr[j].sh_offset))
+	      if (j == dso->ehdr.e_shnum)
 		{
 		  if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
 		    ehdr.e_shoff = (last_shoff + 7) & -8;
 		  else
 		    ehdr.e_shoff = (last_shoff + 3) & -4;
 		  last_shoff = ehdr.e_shoff + ehdr.e_shnum * ehdr.e_shentsize;
-		  shdr_placed = true;
+		  continue;
 		}
-	      if (j == dso->ehdr.e_shnum)
-		break;
 	      dso->shdr[j].sh_offset = last_shoff;
 	      if (dso->shdr[j].sh_addralign > 1)
 		dso->shdr[j].sh_offset
diff --git a/testsuite/dwz.tests/dwz-tests.exp b/testsuite/dwz.tests/dwz-tests.exp
index c1f913a..108b167 100644
--- a/testsuite/dwz.tests/dwz-tests.exp
+++ b/testsuite/dwz.tests/dwz-tests.exp
@@ -42,6 +42,9 @@ foreach test $tests {
     if { $basename == "pr24170.sh" } {
 	lappend required_execs "implptr-64bit-d2o4a8r8t0"
     }
+    if { $basename == "gold-gdb-index.sh" } {
+	lappend required_execs "hello-gold-gdb-index"
+    }
     if { ![istarget x86_64-*-*] } {
 	if { $basename == "pr24468.sh" } {
 	    unsupported "$test"
diff --git a/testsuite/dwz.tests/gold-gdb-index.sh b/testsuite/dwz.tests/gold-gdb-index.sh
new file mode 100644
index 0000000..eb2a164
--- /dev/null
+++ b/testsuite/dwz.tests/gold-gdb-index.sh
@@ -0,0 +1,7 @@
+cp ../hello-gold-gdb-index 1
+
+dwz 1
+
+smaller-than.sh 1 ../hello-gold-gdb-index
+
+rm -f 1