Subject: Fix path canonicalization issues in debugedit

This patch fixes multiple problems with path canonicalization in
debugedit. This version of debugedit is taken from the dwarftools repository.

---
 tools/debugedit.c |  168 ++++++++++++++++++++++++++----------------------------
 1 file changed, 82 insertions(+), 86 deletions(-)

Index: tools/debugedit.c
===================================================================
--- tools/debugedit.c.orig	2011-07-29 15:48:10.000000000 +0200
+++ tools/debugedit.c	2011-07-29 15:50:11.000000000 +0200
@@ -157,7 +157,7 @@ strptr (DSO *dso, int sec, off_t offset)
 	{
 	  if (data->d_buf
 	      && offset >= data->d_off
-	      && offset < data->d_off + data->d_size)
+	      && offset < data->d_off + (off_t)data->d_size)
 	    return (const char *) data->d_buf + (offset - data->d_off);
 	}
     }
@@ -471,13 +471,13 @@ has_prefix (const char  *str,
 {
   int str_len;
   int prefix_len;
-  
+
   str_len = strlen (str);
   prefix_len = strlen (prefix);
 
   if (str_len < prefix_len)
     return 0;
-  
+
   return strncmp (str, prefix, prefix_len) == 0;
 }
 
@@ -485,20 +485,23 @@ static int
 edit_dwarf2_line (DSO *dso, uint_32 off, char *comp_dir, int phase)
 {
   unsigned char *ptr = debug_sections[DEBUG_LINE].data, *dir;
-  unsigned char **dirt;
+  char **dirt;
   unsigned char *endsec = ptr + debug_sections[DEBUG_LINE].size;
   unsigned char *endcu, *endprol;
+  char line_base;
   unsigned char opcode_base;
   uint_32 value, dirt_cnt;
   size_t comp_dir_len = strlen (comp_dir);
   size_t abs_file_cnt = 0, abs_dir_cnt = 0;
   int comp_dir_used = 0;
+  unsigned char *prologue_length_ptr;
+  uint_32 prologue_length;
 
   if (phase != 0)
     return 0;
-  
+
   ptr += off;
-  
+
   endcu = ptr + 4;
   endcu += read_32 (ptr);
   if (endcu == ptr + 0xffffffff)
@@ -521,35 +524,38 @@ edit_dwarf2_line (DSO *dso, uint_32 off,
 	     value);
       return 1;
     }
-  
+
   endprol = ptr + 4;
-  endprol += read_32 (ptr);
+  prologue_length_ptr = ptr;
+  prologue_length = read_32 (ptr);
+  endprol += prologue_length;
   if (endprol > endcu)
     {
       error (0, 0, "%s: .debug_line CU prologue does not fit into CU",
 	     dso->filename);
       return 1;
     }
-  
+
+  line_base = (char) (ptr[2] & 0xff);
   opcode_base = ptr[4];
   ptr = dir = ptr + 4 + opcode_base;
-  
+
   /* dir table: */
   value = 1;
   while (*ptr != 0)
     {
-      ptr = strchr (ptr, 0) + 1;
+      ptr = (unsigned char *)strchr ((char *)ptr, 0) + 1;
       ++value;
     }
 
-  dirt = (unsigned char **) alloca (value * sizeof (unsigned char *));
+  dirt = (char **) alloca (value * sizeof (char *));
   dirt[0] = ".";
   dirt_cnt = 1;
   ptr = dir;
   while (*ptr != 0)
     {
-      dirt[dirt_cnt++] = ptr;
-      ptr = strchr (ptr, 0) + 1;
+      dirt[dirt_cnt++] = (char *)ptr;
+      ptr = (unsigned char *)strchr ((char *)ptr, 0) + 1;
     }
   ptr++;
 
@@ -559,8 +565,8 @@ edit_dwarf2_line (DSO *dso, uint_32 off,
       char *s, *file;
       size_t file_len, dir_len;
 
-      file = ptr;
-      ptr = strchr (ptr, 0) + 1;
+      file = (char *)ptr;
+      ptr = (unsigned char *)strchr ((char *)ptr, 0) + 1;
       value = read_uleb128 (ptr);
 
       if (value >= dirt_cnt)
@@ -629,7 +635,7 @@ edit_dwarf2_line (DSO *dso, uint_32 off,
 	}
 
       free (s);
-      
+
       read_uleb128 (ptr);
       read_uleb128 (ptr);
     }
@@ -661,7 +667,7 @@ edit_dwarf2_line (DSO *dso, uint_32 off,
 
   if (dest_dir)
     {
-      unsigned char *srcptr, *buf = NULL;
+      char *srcptr, *srcstart, *buf = NULL;
       size_t base_len = strlen (base_dir);
       size_t dest_len = strlen (dest_dir);
       size_t shrank = 0;
@@ -675,12 +681,16 @@ edit_dwarf2_line (DSO *dso, uint_32 off,
 	  ptr = dir;
 	}
       else
-	ptr = srcptr = dir;
-      unsigned char *srcstart=srcptr;
+	{
+	  ptr = dir;
+	  srcptr = (char *)dir;
+	}
+
+      srcstart = srcptr;
       while (*srcptr != 0)
 	{
-	  size_t len = strlen (srcptr) + 1;
-	  const unsigned char *readptr = srcptr;
+	  size_t len = strlen (srcptr);
+	  const char *readptr = srcptr;
 
 	  if (*srcptr == '/' && has_prefix (srcptr, base_dir))
 	    {
@@ -689,39 +699,28 @@ edit_dwarf2_line (DSO *dso, uint_32 off,
 	      memcpy (ptr, dest_dir, dest_len);
 	      ptr += dest_len;
 	      readptr += base_len;
-		}
+	    }
 	  srcptr += len;
 
 	  shrank += srcptr - readptr;
-	  canonicalize_path (readptr, ptr);
-	  len = strlen (ptr) + 1;
+	  canonicalize_path (readptr, (char *)ptr);
+	  len = strlen ((char *)ptr);
+
+#ifdef DEBUG
+	  if ((srcptr - readptr) > len)
+	    error(0, 0,"canonicalization unexpectedly shrank (%lu): \"%s\"\n",
+		  (long unsigned int)(srcptr - readptr) - len, ptr);
+#endif
+
 	  shrank -= len;
 	  ptr += len;
 
-	      elf_flagdata (debug_sections[DEBUG_STR].elf_data,
-			    ELF_C_SET, ELF_F_DIRTY);
-	    }
-
-      if (shrank > 0)
-	{
-	  if (--shrank == 0)
-	    error (EXIT_FAILURE, 0,
-		   "canonicalization unexpectedly shrank by one character");
-	  memset (ptr, 'X', shrank);
-	  ptr += shrank;
-	  *ptr++ = '\0';
+	  elf_flagdata (debug_sections[DEBUG_STR].elf_data,
+			ELF_C_SET, ELF_F_DIRTY);
+	  ++ptr;
+	  ++srcptr;
 	}
 
-      if (abs_dir_cnt + abs_file_cnt != 0)
-	{
-	  size_t len = (abs_dir_cnt + abs_file_cnt) * (base_len - dest_len);
-
-	  if (len == 1)
-	    error (EXIT_FAILURE, 0, "-b arg has to be either the same length as -d arg, or more than 1 char shorter");
-	  memset (ptr, 'X', len - 1);
-	  ptr += len - 1;
-	  *ptr++ = '\0';
-	}
       *ptr++ = '\0';
       ++srcptr;
 
@@ -741,21 +740,32 @@ edit_dwarf2_line (DSO *dso, uint_32 off,
 	      elf_flagdata (debug_sections[DEBUG_STR].elf_data,
 			    ELF_C_SET, ELF_F_DIRTY);
 	    }
-	  else if (ptr != srcptr)
+	  else if ((char *)ptr != srcptr)
 	    memmove (ptr, srcptr, len);
 	  srcptr += len;
 	  ptr += len;
-	  dir = srcptr;
+	  dir = (unsigned char *)srcptr;
 	  read_uleb128 (srcptr);
 	  read_uleb128 (srcptr);
 	  read_uleb128 (srcptr);
 	  if (ptr != dir)
-	    memmove (ptr, dir, srcptr - dir);
-	  ptr += srcptr - dir;
+	    memmove (ptr, dir, (unsigned char *)srcptr - dir);
+	  ptr += (unsigned char *)srcptr - dir;
 	}
       *ptr = '\0';
       free (buf);
     }
+
+  ptr++;
+  /* fill the rest until the line number program starts with NOP opcode */
+  memset(ptr, opcode_base - line_base, endprol - ptr);
+  /* There's a consistency check in elfutils/libdw/dwarf_getsrclines,
+     that the line number program starts directly after the file tables.
+     That isn't supported by the standard, but there we are.  Hence also
+     modify the prologue length.  */
+  prologue_length -= endprol - ptr;
+  write_32 (prologue_length_ptr, prologue_length);
+  /* don't touch the line number program */
   return 0;
 }
 
@@ -767,17 +777,13 @@ edit_attributes (DSO *dso, unsigned char
   int i;
   uint_32 list_offs;
   int found_list_offs;
-  unsigned char *comp_dir;
-  
-  comp_dir = NULL;
-  list_offs = 0;
-  found_list_offs = 0;
+  char *comp_dir = NULL;
+
   for (i = 0; i < t->nattr; ++i)
     {
       uint_32 form = t->attr[i].form;
       uint_32 len = 0;
       int base_len, dest_len;
-      
 
       while (1)
 	{
@@ -791,56 +797,55 @@ edit_attributes (DSO *dso, unsigned char
 	    }
 
 	  if (t->attr[i].attr == DW_AT_comp_dir)
-	  {
+	    {
 	      if ( form == DW_FORM_string )
-	      {
+		{
 		  free (comp_dir);
-		  comp_dir = strdup (ptr);
-		  
-		  if (phase == 1 && dest_dir && has_prefix (ptr, base_dir))
-		  {
+		  comp_dir = strdup ((char *)ptr);
+
+		  if (phase == 1 && dest_dir
+		      && has_prefix ((char *)ptr, base_dir))
+		    {
 		      base_len = strlen (base_dir);
 		      dest_len = strlen (dest_dir);
-		      
+
 		      memcpy (ptr, dest_dir, dest_len);
 		      if (dest_len < base_len)
-		      {
+			{
 			  memset(ptr + dest_len, '/',
 				 base_len - dest_len);
-			  
-		      }
+			}
 		      elf_flagdata (debug_sections[DEBUG_INFO].elf_data,
 				    ELF_C_SET, ELF_F_DIRTY);
-		  }
-	      }
-	  
+		    }
+		}
 	      else if (form == DW_FORM_strp &&
 		       debug_sections[DEBUG_STR].data)
-	      {
+		{
 		  char *dir;
 
-		  dir = debug_sections[DEBUG_STR].data
-		      + do_read_32_relocated (ptr);
+		  dir = (char *)debug_sections[DEBUG_STR].data
+		    + do_read_32_relocated (ptr);
 
 		  free (comp_dir);
 		  comp_dir = strdup (dir);
 
 		  if (phase == 1 && dest_dir && has_prefix (dir, base_dir))
-		  {
+		    {
 		      base_len = strlen (base_dir);
 		      dest_len = strlen (dest_dir);
-		  
+
 		      memcpy (dir, dest_dir, dest_len);
 		      if (dest_len < base_len)
-		      {
+			{
 			  memmove (dir + dest_len, dir + base_len,
 				   strlen (dir + base_len) + 1);
-		      }
+			}
 		      elf_flagdata (debug_sections[DEBUG_STR].elf_data,
 				    ELF_C_SET, ELF_F_DIRTY);
-		  }
-	      }
-	  }
+		    }
+		}
+	    }
 	  else if ((t->tag == DW_TAG_compile_unit
 		    || t->tag == DW_TAG_partial_unit)
 		   && t->attr[i].attr == DW_AT_name
@@ -848,9 +853,9 @@ edit_attributes (DSO *dso, unsigned char
 		   && debug_sections[DEBUG_STR].data)
 	    {
 	      char *name;
-	      
-	      name = debug_sections[DEBUG_STR].data
-		     + do_read_32_relocated (ptr);
+
+	      name = (char *)debug_sections[DEBUG_STR].data
+		+ do_read_32_relocated (ptr);
 	      if (*name == '/' && comp_dir == NULL)
 		{
 		  char *enddir = strrchr (name, '/');
@@ -869,7 +874,7 @@ edit_attributes (DSO *dso, unsigned char
 		{
 		  base_len = strlen (base_dir);
 		  dest_len = strlen (dest_dir);
-		  
+
 		  memcpy (name, dest_dir, dest_len);
 		  if (dest_len < base_len)
 		    {
@@ -913,7 +918,7 @@ edit_attributes (DSO *dso, unsigned char
 	      ptr += 4;
 	      break;
 	    case DW_FORM_string:
-	      ptr = strchr (ptr, '\0') + 1;
+	      ptr = (unsigned char *)strchr ((char *)ptr, '\0') + 1;
 	      break;
 	    case DW_FORM_indirect:
 	      form = read_uleb128 (ptr);
@@ -1470,10 +1475,11 @@ handle_build_id (DSO *dso, Elf_Data *bui
     const unsigned char * id = build_id->d_buf + build_id_offset;
     char hex[build_id_size * 2 + 1];
     int n = snprintf (hex, 3, "%02" PRIx8, id[0]);
+    size_t size;
     assert (n == 2);
-    for (i = 1; i < build_id_size; ++i)
+    for (size = 1; size < build_id_size; ++size)
       {
-	n = snprintf (&hex[i * 2], 3, "%02" PRIx8, id[i]);
+	n = snprintf (&hex[size * 2], 3, "%02" PRIx8, id[size]);
 	assert (n == 2);
       }
     puts (hex);
