b3382b
2006-09-19  Jakub Jelinek  <jakub@redhat.com>
b3382b
b3382b
	* strip.c (handle_elf): Formatting.  If any relocation sections
b3382b
	stripped into separate debug info reference symtab that is kept,
b3382b
	emit symtab/strtab also into the separate debug info file.
b3382b
b3382b
--- elfutils/src/strip.c
b3382b
+++ elfutils/src/strip.c
b3382b
@@ -399,6 +399,7 @@ handle_elf (int fd, Elf *elf, const char
b3382b
     Elf_Scn *newscn;
b3382b
     struct Ebl_Strent *se;
b3382b
     Elf32_Word *newsymidx;
b3382b
+    void *debug_data;
b3382b
   } *shdr_info = NULL;
b3382b
   Elf_Scn *scn;
b3382b
   size_t cnt;
2d93f1
@@ -826,6 +827,37 @@ handle_elf (int fd, Elf *elf, const char
b3382b
      The ones that are not removed in the stripped file are SHT_NOBITS.  */
b3382b
   if (debug_fname != NULL)
b3382b
     {
b3382b
+      /* libbfd and apps using it don't cope with separate debuginfo objects
b3382b
+	 with relocation sections against SHT_NOBITS .symtab/.strtab
b3382b
+	 - libbfd isn't able to look up the .symtab/.strtab in the stripped
b3382b
+	 object instead.  As a workaround, emit .symtab/.strtab in both
b3382b
+	 places.  */
2d93f1
+      for (cnt = 1; cnt < shnum; ++cnt)
2d93f1
+	{
b3382b
+	  if (shdr_info[cnt].idx == 0
b3382b
+	      && (shdr_info[cnt].shdr.sh_type == SHT_REL
b3382b
+		  || shdr_info[cnt].shdr.sh_type == SHT_RELA)
b3382b
+	      && (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
b3382b
+	    {
b3382b
+	      Elf32_Word symtabidx = shdr_info[cnt].old_sh_link;
b3382b
+	      struct shdr_info *si = &shdr_info[symtabidx];
b3382b
+	      si->debug_data = "";
b3382b
+	      shdr_info[si->old_sh_link].debug_data = "";
b3382b
+	      if (si->symtab_idx)
b3382b
+		shdr_info[si->symtab_idx].debug_data = "";
b3382b
+
b3382b
+	      if (si->shdr.sh_type != SHT_SYMTAB
b3382b
+		  || (si->shdr.sh_flags & SHF_ALLOC)
b3382b
+		  || shdr_info[si->old_sh_link].shdr.sh_type != SHT_STRTAB
b3382b
+		  || (shdr_info[si->old_sh_link].shdr.sh_flags & SHF_ALLOC)
b3382b
+		  || (si->symtab_idx
b3382b
+		      && (shdr_info[si->symtab_idx].shdr.sh_flags
b3382b
+			  & SHF_ALLOC)))
b3382b
+		error (EXIT_FAILURE, 0,
b3382b
+		       gettext ("invalid symtab/strtab referenced by nonallocated section"));
b3382b
+	    }
b3382b
+	}
b3382b
+
2d93f1
       for (cnt = 1; cnt < shnum; ++cnt)
2d93f1
 	{
b3382b
 	  scn = elf_newscn (debugelf);
2d93f1
@@ -835,6 +867,7 @@ handle_elf (int fd, Elf *elf, const char
b3382b
 		   elf_errmsg (-1));
b3382b
 
b3382b
 	  bool discard_section = (shdr_info[cnt].idx > 0
2d93f1
+				  && shdr_info[cnt].debug_data == NULL
2d93f1
 				  && shdr_info[cnt].shdr.sh_type != SHT_NOTE
2d93f1
 				  && cnt != ehdr->e_shstrndx);
b3382b
 
2d93f1
@@ -865,6 +898,13 @@ handle_elf (int fd, Elf *elf, const char
b3382b
 	  *debugdata = *shdr_info[cnt].data;
b3382b
 	  if (discard_section)
b3382b
 	    debugdata->d_buf = NULL;
b3382b
+	  else if (shdr_info[cnt].debug_data != NULL)
b3382b
+	    {
b3382b
+	      shdr_info[cnt].debug_data = xmalloc (debugdata->d_size);
b3382b
+	      memcpy (shdr_info[cnt].debug_data, debugdata->d_buf,
b3382b
+		      debugdata->d_size);
b3382b
+	      debugdata->d_buf = shdr_info[cnt].debug_data;
b3382b
+	    }
b3382b
 	}
b3382b
 
b3382b
       /* Finish the ELF header.  Fill in the fields not handled by
2d93f1
@@ -1056,7 +1096,7 @@ handle_elf (int fd, Elf *elf, const char
b3382b
 	    shdr_info[shdr_info[cnt].shdr.sh_info].idx;
b3382b
 
b3382b
 	/* Get the data from the old file if necessary.  We already
b3382b
-           created the data for the section header string table.  */
b3382b
+	   created the data for the section header string table.  */
b3382b
 	if (cnt < shnum)
b3382b
 	  {
b3382b
 	    if (shdr_info[cnt].data == NULL)
2d93f1
@@ -1283,6 +1323,13 @@ handle_elf (int fd, Elf *elf, const char
b3382b
 	      if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx == NULL)
b3382b
 		continue;
b3382b
 
b3382b
+	      /* If the symbol table is not discarded, but additionally
b3382b
+		 duplicated in separate debug file and this section
b3382b
+		 is discarded, don't adjust anything.  */
b3382b
+	      if (shdr_info[cnt].idx == 0
b3382b
+		  && shdr_info[shdr_info[cnt].old_sh_link].debug_data != NULL)
b3382b
+		continue;
b3382b
+
b3382b
 	      Elf32_Word *newsymidx
b3382b
 		= shdr_info[shdr_info[cnt].old_sh_link].newsymidx;
b3382b
 	      Elf_Data *d = elf_getdata (shdr_info[cnt].idx == 0
2d93f1
@@ -1341,6 +1388,13 @@ handle_elf (int fd, Elf *elf, const char
b3382b
 	      if (shdr_info[symtabidx].newsymidx == NULL)
b3382b
 		continue;
b3382b
 
b3382b
+	      /* If the symbol table is not discarded, but additionally
b3382b
+		 duplicated in separate debug file and this section
b3382b
+		 is discarded, don't adjust anything.  */
b3382b
+	      if (shdr_info[cnt].idx == 0
b3382b
+		  && shdr_info[symtabidx].debug_data != NULL)
b3382b
+		continue;
b3382b
+
b3382b
 	      assert (shdr_info[cnt].idx > 0);
b3382b
 
b3382b
 	      /* The hash section in the new file.  */
2d93f1
@@ -1460,7 +1514,7 @@ handle_elf (int fd, Elf *elf, const char
b3382b
 			  chain[hidx] = inner;
b3382b
 			}
b3382b
 		    }
b3382b
-	        }
b3382b
+		}
b3382b
 	    }
b3382b
 	  else if (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym)
b3382b
 	    {
2d93f1
@@ -1473,6 +1527,13 @@ handle_elf (int fd, Elf *elf, const char
b3382b
 	      if (shdr_info[symtabidx].newsymidx == NULL)
b3382b
 		continue;
b3382b
 
b3382b
+	      /* If the symbol table is not discarded, but additionally
b3382b
+		 duplicated in separate debug file and this section
b3382b
+		 is discarded, don't adjust anything.  */
b3382b
+	      if (shdr_info[cnt].idx == 0
b3382b
+		  && shdr_info[symtabidx].debug_data != NULL)
b3382b
+		continue;
b3382b
+
b3382b
 	      assert (shdr_info[cnt].idx > 0);
b3382b
 
b3382b
 	      /* The symbol version section in the new file.  */
2d93f1
@@ -1515,20 +1576,27 @@ handle_elf (int fd, Elf *elf, const char
b3382b
 	  else if (shdr_info[cnt].shdr.sh_type == SHT_GROUP)
b3382b
 	    {
b3382b
 	      /* Check whether the associated symbol table changed.  */
b3382b
-	      if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx != NULL)
b3382b
-		{
b3382b
-		  /* Yes the symbol table changed.  Update the section
b3382b
-		     header of the section group.  */
b3382b
-		  scn = elf_getscn (newelf, shdr_info[cnt].idx);
b3382b
-		  GElf_Shdr shdr_mem;
b3382b
-		  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
b3382b
-		  assert (shdr != NULL);
b3382b
+	      if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx == NULL)
b3382b
+		continue;
b3382b
 
b3382b
-		  size_t stabidx = shdr_info[cnt].old_sh_link;
b3382b
-		  shdr->sh_info = shdr_info[stabidx].newsymidx[shdr->sh_info];
b3382b
+	      /* If the symbol table is not discarded, but additionally
b3382b
+		 duplicated in separate debug file and this section
b3382b
+		 is discarded, don't adjust anything.  */
b3382b
+	      if (shdr_info[cnt].idx == 0
b3382b
+		  && shdr_info[shdr_info[cnt].old_sh_link].debug_data != NULL)
b3382b
+		continue;
b3382b
 
b3382b
-		  (void) gelf_update_shdr (scn, shdr);
b3382b
-		}
b3382b
+	      /* Yes the symbol table changed.  Update the section
b3382b
+		 header of the section group.  */
b3382b
+	      scn = elf_getscn (newelf, shdr_info[cnt].idx);
b3382b
+	      GElf_Shdr shdr_mem;
b3382b
+	      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
b3382b
+	      assert (shdr != NULL);
b3382b
+
b3382b
+	      size_t stabidx = shdr_info[cnt].old_sh_link;
b3382b
+	      shdr->sh_info = shdr_info[stabidx].newsymidx[shdr->sh_info];
b3382b
+
b3382b
+	      (void) gelf_update_shdr (scn, shdr);
b3382b
 	    }
b3382b
 	}
b3382b
     }
2d93f1
@@ -1658,7 +1726,10 @@ handle_elf (int fd, Elf *elf, const char
b3382b
 	 table indices.  */
b3382b
       if (any_symtab_changes)
b3382b
 	for (cnt = 1; cnt <= shdridx; ++cnt)
b3382b
-	  free (shdr_info[cnt].newsymidx);
b3382b
+	  {
b3382b
+	    free (shdr_info[cnt].newsymidx);
b3382b
+	    free (shdr_info[cnt].debug_data);
b3382b
+	  }
b3382b
 
b3382b
       /* Free the memory.  */
b3382b
       if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC)
2d93f1
--- elfutils/tests/run-strip-test5.sh.~1~
2d93f1
+++ elfutils/tests/run-strip-test5.sh
b3382b
@@ -1,5 +1,5 @@
b3382b
 original=testfile8
b3382b
-stripped=testfile16
b3382b
-debugfile=testfile16.debug
b3382b
+stripped=testfile16.symtab
b3382b
+debugfile=testfile16.symtab.debug
b3382b
 
b3382b
 . $srcdir/run-strip-test.sh
b3382b