tools/debugedit.c

Go to the documentation of this file.
00001 /* Copyright (C) 2001, 2002, 2003 Red Hat, Inc.
00002    Written by Alexander Larsson <alexl@redhat.com>, 2002
00003    Based on code by Jakub Jelinek <jakub@redhat.com>, 2001.
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2, or (at your option)
00008    any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software Foundation,
00017    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00018 
00019 /* Needed for libelf */
00020 #define _FILE_OFFSET_BITS 64
00021 
00022 #include <assert.h>
00023 #include <byteswap.h>
00024 #include <endian.h>
00025 #include <errno.h>
00026 #include <error.h>
00027 #include <limits.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <unistd.h>
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <fcntl.h>
00034 #include <popt.h>
00035 
00036 #include <gelf.h>
00037 #include <dwarf.h>
00038 
00039 #include "hashtab.h"
00040 
00041 #define DW_TAG_partial_unit 0x3c
00042 
00043 char *base_dir = NULL;
00044 char *dest_dir = NULL;
00045 char *list_file = NULL;
00046 int list_file_fd = -1; 
00047 
00048 typedef unsigned int uint_32;
00049 typedef unsigned short uint_16;
00050 
00051 typedef struct
00052 {
00053   Elf *elf;
00054   GElf_Ehdr ehdr;
00055   Elf_Scn **scn;
00056   const char *filename;
00057   int lastscn;
00058   GElf_Shdr shdr[0];
00059 } DSO;
00060 
00061 typedef struct
00062 {
00063   unsigned char *ptr;
00064   uint_32 addend;
00065 } REL;
00066 
00067 #define read_uleb128(ptr) ({            \
00068   unsigned int ret = 0;                 \
00069   unsigned int c;                       \
00070   int shift = 0;                        \
00071   do                                    \
00072     {                                   \
00073       c = *ptr++;                       \
00074       ret |= (c & 0x7f) << shift;       \
00075       shift += 7;                       \
00076     } while (c & 0x80);                 \
00077                                         \
00078   if (shift >= 35)                      \
00079     ret = UINT_MAX;                     \
00080   ret;                                  \
00081 })
00082 
00083 static uint_16 (*do_read_16) (unsigned char *ptr);
00084 static uint_32 (*do_read_32) (unsigned char *ptr);
00085 static void (*write_32) (unsigned char *ptr, GElf_Addr val);
00086 
00087 static int ptr_size;
00088 
00089 static inline uint_16
00090 buf_read_ule16 (unsigned char *data)
00091 {
00092   return data[0] | (data[1] << 8);
00093 }
00094 
00095 static inline uint_16
00096 buf_read_ube16 (unsigned char *data)
00097 {
00098   return data[1] | (data[0] << 8);
00099 }
00100 
00101 static inline uint_32
00102 buf_read_ule32 (unsigned char *data)
00103 {
00104   return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
00105 }
00106 
00107 static inline uint_32
00108 buf_read_ube32 (unsigned char *data)
00109 {
00110   return data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
00111 }
00112 
00113 static const char *
00114 strptr (DSO *dso, int sec, off_t offset)
00115 {
00116   Elf_Scn *scn;
00117   Elf_Data *data;
00118 
00119   scn = dso->scn[sec];
00120   if (offset >= 0 && (GElf_Addr) offset < dso->shdr[sec].sh_size)
00121     {
00122       data = NULL;
00123       while ((data = elf_rawdata (scn, data)) != NULL)
00124         {
00125           if (data->d_buf
00126               && offset >= data->d_off
00127               && offset < data->d_off + data->d_size)
00128             return (const char *) data->d_buf + (offset - data->d_off);
00129         }
00130     }
00131 
00132   return NULL;
00133 }
00134 
00135 
00136 #define read_1(ptr) *ptr++
00137 
00138 #define read_16(ptr) ({                                 \
00139   uint_16 ret = do_read_16 (ptr);                       \
00140   ptr += 2;                                             \
00141   ret;                                                  \
00142 })
00143 
00144 #define read_32(ptr) ({                                 \
00145   uint_32 ret = do_read_32 (ptr);                       \
00146   ptr += 4;                                             \
00147   ret;                                                  \
00148 })
00149 
00150 REL *relptr, *relend;
00151 int reltype;
00152 
00153 #define do_read_32_relocated(ptr) ({                    \
00154   uint_32 dret = do_read_32 (ptr);                      \
00155   if (relptr)                                           \
00156     {                                                   \
00157       while (relptr < relend && relptr->ptr < ptr)      \
00158         ++relptr;                                       \
00159       if (relptr < relend && relptr->ptr == ptr)        \
00160         {                                               \
00161           if (reltype == SHT_REL)                       \
00162             dret += relptr->addend;                     \
00163           else                                          \
00164             dret = relptr->addend;                      \
00165         }                                               \
00166     }                                                   \
00167   dret;                                                 \
00168 })
00169 
00170 #define read_32_relocated(ptr) ({                       \
00171   uint_32 ret = do_read_32_relocated (ptr);             \
00172   ptr += 4;                                             \
00173   ret;                                                  \
00174 })
00175 
00176 static void
00177 dwarf2_write_le32 (unsigned char *p, GElf_Addr val)
00178 {
00179   uint_32 v = (uint_32) val;
00180 
00181   p[0] = v;
00182   p[1] = v >> 8;
00183   p[2] = v >> 16;
00184   p[3] = v >> 24;
00185 }
00186 
00187 
00188 static void
00189 dwarf2_write_be32 (unsigned char *p, GElf_Addr val)
00190 {
00191   uint_32 v = (uint_32) val;
00192 
00193   p[3] = v;
00194   p[2] = v >> 8;
00195   p[1] = v >> 16;
00196   p[0] = v >> 24;
00197 }
00198 
00199 static struct
00200   {
00201     const char *name;
00202     unsigned char *data;
00203     Elf_Data *elf_data;
00204     size_t size;
00205     int sec, relsec;
00206   } debug_sections[] =
00207   {
00208 #define DEBUG_INFO      0
00209 #define DEBUG_ABBREV    1
00210 #define DEBUG_LINE      2
00211 #define DEBUG_ARANGES   3
00212 #define DEBUG_PUBNAMES  4
00213 #define DEBUG_MACINFO   5
00214 #define DEBUG_LOC       6
00215 #define DEBUG_STR       7
00216 #define DEBUG_FRAME     8
00217 #define DEBUG_RANGES    9
00218     { ".debug_info", NULL, NULL, 0, 0, 0 },
00219     { ".debug_abbrev", NULL, NULL, 0, 0, 0 },
00220     { ".debug_line", NULL, NULL, 0, 0, 0 },
00221     { ".debug_aranges", NULL, NULL, 0, 0, 0 },
00222     { ".debug_pubnames", NULL, NULL, 0, 0, 0 },
00223     { ".debug_macinfo", NULL, NULL, 0, 0, 0 },
00224     { ".debug_loc", NULL, NULL, 0, 0, 0 },
00225     { ".debug_str", NULL, NULL, 0, 0, 0 },
00226     { ".debug_frame", NULL, NULL, 0, 0, 0 },
00227     { ".debug_ranges", NULL, NULL, 0, 0, 0 },
00228     { NULL, NULL, NULL, 0, 0, 0 }
00229   };
00230 
00231 struct abbrev_attr
00232   {
00233     unsigned int attr;
00234     unsigned int form;
00235   };
00236 
00237 struct abbrev_tag
00238   {
00239     unsigned int entry;
00240     unsigned int tag;
00241     int nattr;
00242     struct abbrev_attr attr[0];
00243   };
00244 
00245 static hashval_t
00246 abbrev_hash (const void *p)
00247 {
00248   struct abbrev_tag *t = (struct abbrev_tag *)p;
00249 
00250   return t->entry;
00251 }
00252 
00253 static int
00254 abbrev_eq (const void *p, const void *q)
00255 {
00256   struct abbrev_tag *t1 = (struct abbrev_tag *)p;
00257   struct abbrev_tag *t2 = (struct abbrev_tag *)q;
00258 
00259   return t1->entry == t2->entry;
00260 }
00261 
00262 static void
00263 abbrev_del (void *p)
00264 {
00265   free (p);
00266 }
00267 
00268 static htab_t
00269 read_abbrev (DSO *dso, unsigned char *ptr)
00270 {
00271   htab_t h = htab_try_create (50, abbrev_hash, abbrev_eq, abbrev_del);
00272   unsigned int attr, form;
00273   struct abbrev_tag *t;
00274   int size;
00275   void **slot;
00276 
00277   if (h == NULL)
00278     {
00279 no_memory:
00280       error (0, ENOMEM, "%s: Could not read .debug_abbrev", dso->filename);
00281       if (h)
00282         htab_delete (h);
00283       return NULL;
00284     }
00285 
00286   while ((attr = read_uleb128 (ptr)) != 0)
00287     {
00288       size = 10;
00289       t = malloc (sizeof (*t) + size * sizeof (struct abbrev_attr));
00290       if (t == NULL)
00291         goto no_memory;
00292       t->entry = attr;
00293       t->nattr = 0;
00294       slot = htab_find_slot (h, t, INSERT);
00295       if (slot == NULL)
00296         {
00297           free (t);
00298           goto no_memory;
00299         }
00300       if (*slot != NULL)
00301         {
00302           error (0, 0, "%s: Duplicate DWARF-2 abbreviation %d", dso->filename,
00303                  t->entry);
00304           free (t);
00305           htab_delete (h);
00306           return NULL;
00307         }
00308       t->tag = read_uleb128 (ptr);
00309       ++ptr; /* skip children flag.  */
00310       while ((attr = read_uleb128 (ptr)) != 0)
00311         {
00312           if (t->nattr == size)
00313             {
00314               size += 10;
00315               t = realloc (t, sizeof (*t) + size * sizeof (struct abbrev_attr));
00316               if (t == NULL)
00317                 goto no_memory;
00318             }
00319           form = read_uleb128 (ptr);
00320           if (form == 2 || form > DW_FORM_indirect)
00321             {
00322               error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename, form);
00323               htab_delete (h);
00324               return NULL;
00325             }
00326 
00327           t->attr[t->nattr].attr = attr;
00328           t->attr[t->nattr++].form = form;
00329         }
00330       if (read_uleb128 (ptr) != 0)
00331         {
00332           error (0, 0, "%s: DWARF-2 abbreviation does not end with 2 zeros",
00333                  dso->filename);
00334           htab_delete (h);
00335           return NULL;
00336         }
00337       *slot = t;
00338     }
00339 
00340   return h;
00341 }
00342 
00343 #define IS_DIR_SEPARATOR(c) ((c)=='/')
00344 
00345 static char *
00346 canonicalize_path (char *s, char *d)
00347 {
00348   char *rv = d;
00349   char *sroot, *droot;
00350 
00351   if (d == 0)
00352     rv = d = s;
00353 
00354   if (IS_DIR_SEPARATOR (*s))
00355     {
00356       *d++ = *s++;
00357       if (IS_DIR_SEPARATOR (*s) && !IS_DIR_SEPARATOR (s[1]))
00358         {
00359           /* Special case for "//foo" meaning a Posix namespace
00360              escape.  */
00361           *d++ = *s++;
00362         }
00363       while (IS_DIR_SEPARATOR (*s))
00364         s++;
00365     }
00366   droot = d;
00367   sroot = s;
00368 
00369   while (*s)
00370     {
00371       /* At this point, we're always at the beginning of a path
00372          segment.  */
00373 
00374       if (s[0] == '.' && (s[1] == 0 || IS_DIR_SEPARATOR (s[1])))
00375         {
00376           s ++;
00377           if (*s)
00378             s++;
00379           else if (d > droot)
00380             d--;
00381         }
00382 
00383       else if (s[0] == '.' && s[1] == '.'
00384                && (s[2] == 0 || IS_DIR_SEPARATOR (s[2])))
00385         {
00386           char *pre = d-1; /* includes slash */
00387           while (droot < pre && IS_DIR_SEPARATOR (*pre))
00388             pre--;
00389           if (droot <= pre && ! IS_DIR_SEPARATOR (*pre))
00390             {
00391               d = pre;
00392               while (droot < d && ! IS_DIR_SEPARATOR (*d))
00393                 d--;
00394               /* d now points to the slash */
00395               if (droot < d)
00396                 d++;
00397               s += 2;
00398               if (*s)
00399                 s++;
00400               else if (d > droot)
00401                 d--;
00402             }
00403           else
00404             {
00405               *d++ = *s++;
00406               *d++ = *s++;
00407               if (*s)
00408                 *d++ = *s++;
00409             }
00410         }
00411 
00412       else
00413         {
00414           while (*s && ! IS_DIR_SEPARATOR (*s))
00415             *d++ = *s++;
00416         }
00417 
00418       if (IS_DIR_SEPARATOR (*s))
00419         {
00420           *d++ = *s++;
00421           while (IS_DIR_SEPARATOR (*s))
00422             s++;
00423         }
00424     }
00425   while (droot < d && IS_DIR_SEPARATOR (d[-1]))
00426     --d;
00427   if (d == rv)
00428     *d++ = '.';
00429   *d = 0;
00430 
00431   return rv;
00432 }
00433 
00434 static int
00435 has_prefix (const char  *str,
00436             const char  *prefix)
00437 {
00438   int str_len;
00439   int prefix_len;
00440   
00441   str_len = strlen (str);
00442   prefix_len = strlen (prefix);
00443 
00444   if (str_len < prefix_len)
00445     return 0;
00446   
00447   return strncmp (str, prefix, prefix_len) == 0;
00448 }
00449 
00450 static int
00451 edit_dwarf2_line (DSO *dso, uint_32 off, char *comp_dir, int phase)
00452 {
00453   unsigned char *ptr = debug_sections[DEBUG_LINE].data, *dir;
00454   unsigned char **dirt;
00455   unsigned char *endsec = ptr + debug_sections[DEBUG_LINE].size;
00456   unsigned char *endcu, *endprol;
00457   unsigned char opcode_base;
00458   uint_32 value, dirt_cnt;
00459   size_t comp_dir_len = strlen (comp_dir);
00460   size_t abs_file_cnt = 0, abs_dir_cnt = 0;
00461 
00462   if (phase != 0)
00463     return 0;
00464   
00465   ptr += off;
00466   
00467   endcu = ptr + 4;
00468   endcu += read_32 (ptr);
00469   if (endcu == ptr + 0xffffffff)
00470     {
00471       error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
00472       return 1;
00473     }
00474 
00475   if (endcu > endsec)
00476     {
00477       error (0, 0, "%s: .debug_line CU does not fit into section",
00478              dso->filename);
00479       return 1;
00480     }
00481 
00482   value = read_16 (ptr);
00483   if (value != 2)
00484     {
00485       error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
00486              value);
00487       return 1;
00488     }
00489   
00490   endprol = ptr + 4;
00491   endprol += read_32 (ptr);
00492   if (endprol > endcu)
00493     {
00494       error (0, 0, "%s: .debug_line CU prologue does not fit into CU",
00495              dso->filename);
00496       return 1;
00497     }
00498   
00499   opcode_base = ptr[4];
00500   ptr = dir = ptr + 4 + opcode_base;
00501   
00502   /* dir table: */
00503   value = 1;
00504   while (*ptr != 0)
00505     {
00506       ptr = strchr (ptr, 0) + 1;
00507       ++value;
00508     }
00509 
00510   dirt = (unsigned char **) alloca (value * sizeof (unsigned char *));
00511   dirt[0] = ".";
00512   dirt_cnt = 1;
00513   ptr = dir;
00514   while (*ptr != 0)
00515     {
00516       dirt[dirt_cnt++] = ptr;
00517       ptr = strchr (ptr, 0) + 1;
00518     }
00519   ptr++;
00520 
00521   /* file table: */
00522   while (*ptr != 0)
00523     {
00524       char *s, *file;
00525       size_t file_len, dir_len;
00526 
00527       file = ptr;
00528       ptr = strchr (ptr, 0) + 1;
00529       value = read_uleb128 (ptr);
00530 
00531       if (value >= dirt_cnt)
00532         {
00533           error (0, 0, "%s: Wrong directory table index %u",
00534                  dso->filename, value);
00535           return 1;
00536         }
00537       file_len = strlen (file);
00538       dir_len = strlen (dirt[value]);
00539       s = malloc (comp_dir_len + 1 + file_len + 1 + dir_len + 1);
00540       if (s == NULL)
00541         {
00542           error (0, ENOMEM, "%s: Reading file table", dso->filename);
00543           return 1;
00544         }
00545       if (*file == '/')
00546         {
00547           memcpy (s, file, file_len + 1);
00548           if (dest_dir && has_prefix (file, base_dir))
00549             ++abs_file_cnt;
00550         }
00551       else if (*dirt[value] == '/')
00552         {
00553           memcpy (s, dirt[value], dir_len);
00554           s[dir_len] = '/';
00555           memcpy (s + dir_len + 1, file, file_len + 1);
00556         }
00557       else
00558         {
00559           memcpy (s, comp_dir, comp_dir_len);
00560           s[comp_dir_len] = '/';
00561           memcpy (s + comp_dir_len + 1, dirt[value], dir_len);
00562           s[comp_dir_len + 1 + dir_len] = '/';
00563           memcpy (s + comp_dir_len + 1 + dir_len + 1, file, file_len + 1);
00564         }
00565       canonicalize_path (s, s);
00566       if (base_dir == NULL ||
00567           has_prefix (s, base_dir))
00568         {
00569           char *p;
00570           size_t size;
00571           ssize_t ret;
00572           if (base_dir)
00573             p = s + strlen (base_dir);
00574           else
00575             p = s;
00576           
00577           if (list_file_fd != -1)
00578             {
00579               size = strlen (p) + 1;
00580               while (size > 0)
00581                 {
00582                   ret = write (list_file_fd, p, size);
00583                   if (ret == -1)
00584                     break;
00585                   size -= ret;
00586                   p += ret;
00587                 }
00588             }
00589         }
00590 
00591       free (s);
00592       
00593       read_uleb128 (ptr);
00594       read_uleb128 (ptr);
00595     }
00596   ++ptr;
00597   
00598   if (dest_dir)
00599     {
00600       unsigned char *srcptr, *buf = NULL;
00601       size_t base_len = strlen (base_dir);
00602       size_t dest_len = strlen (dest_dir);
00603 
00604       if (dest_len == base_len)
00605         abs_file_cnt = 0;
00606       if (abs_file_cnt)
00607         {
00608           srcptr = buf = malloc (ptr - dir);
00609           memcpy (srcptr, dir, ptr - dir);
00610           ptr = dir;
00611         }
00612       else
00613         ptr = srcptr = dir;
00614       while (*srcptr != 0)
00615         {
00616           size_t len = strlen (srcptr) + 1;
00617 
00618           if (*srcptr == '/' && has_prefix (srcptr, base_dir))
00619             {
00620               memcpy (ptr, dest_dir, dest_len);
00621               if (dest_len < base_len)
00622                 {
00623                   memmove (ptr + dest_len, srcptr + base_len,
00624                            len - base_len);
00625                   ptr += dest_len - base_len;
00626                   ++abs_dir_cnt;
00627                 }
00628               elf_flagdata (debug_sections[DEBUG_STR].elf_data,
00629                             ELF_C_SET, ELF_F_DIRTY);
00630             }
00631           else if (ptr != srcptr)
00632             memmove (ptr, srcptr, len);
00633           srcptr += len;
00634           ptr += len;
00635         }
00636 
00637       if (abs_dir_cnt + abs_file_cnt != 0)
00638         {
00639           size_t len = (abs_dir_cnt + abs_file_cnt) * (base_len - dest_len);
00640 
00641           if (len == 1)
00642             error (EXIT_FAILURE, 0, "-b arg has to be either the same length as -d arg, or more than 1 char shorter");
00643           memset (ptr, 'X', len - 1);
00644           ptr += len - 1;
00645           *ptr++ = '\0';
00646         }
00647       *ptr++ = '\0';
00648       ++srcptr;
00649 
00650       while (*srcptr != 0)
00651         {
00652           size_t len = strlen (srcptr) + 1;
00653 
00654           if (*srcptr == '/' && has_prefix (srcptr, base_dir))
00655             {
00656               memcpy (ptr, dest_dir, dest_len);
00657               if (dest_len < base_len)
00658                 {
00659                   memmove (ptr + dest_len, srcptr + base_len,
00660                            len - base_len);
00661                   ptr += dest_len - base_len;
00662                 }
00663               elf_flagdata (debug_sections[DEBUG_STR].elf_data,
00664                             ELF_C_SET, ELF_F_DIRTY);
00665             }
00666           else if (ptr != srcptr)
00667             memmove (ptr, srcptr, len);
00668           srcptr += len;
00669           ptr += len;
00670           dir = srcptr;
00671           read_uleb128 (srcptr);
00672           read_uleb128 (srcptr);
00673           read_uleb128 (srcptr);
00674           if (ptr != dir)
00675             memmove (ptr, dir, srcptr - dir);
00676           ptr += srcptr - dir;
00677         }
00678       *ptr = '\0';
00679       free (buf);
00680     }
00681   return 0;
00682 }
00683 
00684 
00685 
00686 static unsigned char *
00687 edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase)
00688 {
00689   int i;
00690   uint_32 list_offs;
00691   int found_list_offs;
00692   unsigned char *comp_dir;
00693   
00694   comp_dir = NULL;
00695   list_offs = 0;
00696   found_list_offs = 0;
00697   for (i = 0; i < t->nattr; ++i)
00698     {
00699       uint_32 form = t->attr[i].form;
00700       uint_32 len = 0;
00701       int base_len, dest_len;
00702       
00703 
00704       while (1)
00705         {
00706           if (t->attr[i].attr == DW_AT_stmt_list)
00707             {
00708               if (form == DW_FORM_data4)
00709                 {
00710                   list_offs = do_read_32_relocated (ptr);
00711                   found_list_offs = 1;
00712                 }
00713             }
00714 
00715             if (t->attr[i].attr == DW_AT_comp_dir) {
00716                 if (form == DW_FORM_strp &&
00717               debug_sections[DEBUG_STR].data)
00718             {
00719               char *dir;
00720               
00721               dir = debug_sections[DEBUG_STR].data
00722                     + do_read_32_relocated (ptr);
00723               free (comp_dir);
00724               comp_dir = strdup (dir);
00725 
00726               if (phase == 1 && dest_dir && has_prefix (dir, base_dir))
00727                 {
00728                   base_len = strlen (base_dir);
00729                   dest_len = strlen (dest_dir);
00730                   
00731                   memcpy (dir, dest_dir, dest_len);
00732                   if (dest_len < base_len)
00733                     {
00734                       memmove (dir + dest_len, dir + base_len,
00735                                strlen (dir + base_len) + 1);
00736                     }
00737                   elf_flagdata (debug_sections[DEBUG_STR].elf_data,
00738                                 ELF_C_SET, ELF_F_DIRTY);
00739                 }
00740             }
00741                 else if (form == DW_FORM_string) {
00742                         free(comp_dir);
00743                         comp_dir = strdup (ptr);                        
00744                 }
00745             }
00746           else if ((t->tag == DW_TAG_compile_unit
00747                     || t->tag == DW_TAG_partial_unit)
00748                    && t->attr[i].attr == DW_AT_name
00749                    && form == DW_FORM_strp
00750                    && debug_sections[DEBUG_STR].data)
00751             {
00752               char *name;
00753               
00754               name = debug_sections[DEBUG_STR].data
00755                      + do_read_32_relocated (ptr);
00756               if (*name == '/' && comp_dir == NULL)
00757                 {
00758                   char *enddir = strrchr (name, '/');
00759 
00760                   if (enddir != name)
00761                     {
00762                       comp_dir = malloc (enddir - name + 1);
00763                       memcpy (comp_dir, name, enddir - name);
00764                       comp_dir [enddir - name] = '\0';
00765                     }
00766                   else
00767                     comp_dir = strdup ("/");
00768                 }
00769 
00770               if (phase == 1 && dest_dir && has_prefix (name, base_dir))
00771                 {
00772                   base_len = strlen (base_dir);
00773                   dest_len = strlen (dest_dir);
00774                   
00775                   memcpy (name, dest_dir, dest_len);
00776                   if (dest_len < base_len)
00777                     {
00778                       memmove (name + dest_len, name + base_len,
00779                                strlen (name + base_len) + 1);
00780                     }
00781                   elf_flagdata (debug_sections[DEBUG_STR].elf_data,
00782                                 ELF_C_SET, ELF_F_DIRTY);
00783                 }
00784             }
00785 
00786           switch (form)
00787             {
00788             case DW_FORM_addr:
00789               ptr += ptr_size;
00790               break;
00791             case DW_FORM_ref1:
00792             case DW_FORM_flag:
00793             case DW_FORM_data1:
00794               ++ptr;
00795               break;
00796             case DW_FORM_ref2:
00797             case DW_FORM_data2:
00798               ptr += 2;
00799               break;
00800             case DW_FORM_ref4:
00801             case DW_FORM_data4:
00802               ptr += 4;
00803               break;
00804             case DW_FORM_ref8:
00805             case DW_FORM_data8:
00806               ptr += 8;
00807               break;
00808             case DW_FORM_sdata:
00809             case DW_FORM_ref_udata:
00810             case DW_FORM_udata:
00811               read_uleb128 (ptr);
00812               break;
00813             case DW_FORM_ref_addr:
00814             case DW_FORM_strp:
00815               ptr += 4;
00816               break;
00817             case DW_FORM_string:
00818               ptr = strchr (ptr, '\0') + 1;
00819               break;
00820             case DW_FORM_indirect:
00821               form = read_uleb128 (ptr);
00822               continue;
00823             case DW_FORM_block1:
00824               len = *ptr++;
00825               break;
00826             case DW_FORM_block2:
00827               len = read_16 (ptr);
00828               form = DW_FORM_block1;
00829               break;
00830             case DW_FORM_block4:
00831               len = read_32 (ptr);
00832               form = DW_FORM_block1;
00833               break;
00834             case DW_FORM_block:
00835               len = read_uleb128 (ptr);
00836               form = DW_FORM_block1;
00837               assert (len < UINT_MAX);
00838               break;
00839             default:
00840               error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename,
00841                      form);
00842               return NULL;
00843             }
00844 
00845           if (form == DW_FORM_block1)
00846             ptr += len;
00847           
00848           break;
00849         }
00850     }
00851   if (found_list_offs && comp_dir)
00852     edit_dwarf2_line (dso, list_offs, comp_dir, phase);
00853 
00854   free (comp_dir);
00855 
00856   return ptr;
00857 }
00858 
00859 static int
00860 rel_cmp (const void *a, const void *b)
00861 {
00862   REL *rela = (REL *) a, *relb = (REL *) b;
00863 
00864   if (rela->ptr < relb->ptr)
00865     return -1;
00866 
00867   if (rela->ptr > relb->ptr)
00868     return 1;
00869 
00870   return 0;
00871 }
00872 
00873 static int
00874 edit_dwarf2 (DSO *dso)
00875 {
00876   Elf_Data *data;
00877   Elf_Scn *scn;
00878   int i, j;
00879 
00880   for (i = 0; debug_sections[i].name; ++i)
00881     {
00882       debug_sections[i].data = NULL;
00883       debug_sections[i].size = 0;
00884       debug_sections[i].sec = 0;
00885       debug_sections[i].relsec = 0;
00886     }
00887   ptr_size = 0;
00888 
00889   for (i = 1; i < dso->ehdr.e_shnum; ++i)
00890     if (! (dso->shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR))
00891         && dso->shdr[i].sh_size)
00892       {
00893         const char *name = strptr (dso, dso->ehdr.e_shstrndx,
00894                                    dso->shdr[i].sh_name);
00895 
00896         if (strncmp (name, ".debug_", sizeof (".debug_") - 1) == 0)
00897           {
00898             for (j = 0; debug_sections[j].name; ++j)
00899               if (strcmp (name, debug_sections[j].name) == 0)
00900                 {
00901                   if (debug_sections[j].data)
00902                     {
00903                       error (0, 0, "%s: Found two copies of %s section",
00904                              dso->filename, name);
00905                       return 1;
00906                     }
00907 
00908                   scn = dso->scn[i]; 
00909                   data = elf_rawdata (scn, NULL);
00910                   assert (data != NULL && data->d_buf != NULL);
00911                   assert (elf_rawdata (scn, data) == NULL);
00912                   assert (data->d_off == 0);
00913                   assert (data->d_size == dso->shdr[i].sh_size);
00914                   debug_sections[j].data = data->d_buf;
00915                   debug_sections[j].elf_data = data;
00916                   debug_sections[j].size = data->d_size;
00917                   debug_sections[j].sec = i;
00918                   break;
00919                 }
00920 
00921             if (debug_sections[j].name == NULL)
00922               {
00923                 error (0, 0, "%s: Unknown debugging section %s",
00924                        dso->filename, name);
00925               }
00926           }
00927         else if (dso->ehdr.e_type == ET_REL
00928                  && ((dso->shdr[i].sh_type == SHT_REL
00929                       && strncmp (name, ".rel.debug_",
00930                                   sizeof (".rel.debug_") - 1) == 0)
00931                      || (dso->shdr[i].sh_type == SHT_RELA
00932                          && strncmp (name, ".rela.debug_",
00933                                      sizeof (".rela.debug_") - 1) == 0)))
00934           {
00935             for (j = 0; debug_sections[j].name; ++j)
00936               if (strcmp (name + sizeof (".rel") - 1
00937                           + (dso->shdr[i].sh_type == SHT_RELA),
00938                           debug_sections[j].name) == 0)
00939                 {
00940                   debug_sections[j].relsec = i;
00941                   break;
00942                 }
00943           }
00944       }
00945 
00946   if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
00947     {
00948       do_read_16 = buf_read_ule16;
00949       do_read_32 = buf_read_ule32;
00950       write_32 = dwarf2_write_le32;
00951     }
00952   else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
00953     {
00954       do_read_16 = buf_read_ube16;
00955       do_read_32 = buf_read_ube32;
00956       write_32 = dwarf2_write_be32;
00957     }
00958   else
00959     {
00960       error (0, 0, "%s: Wrong ELF data enconding", dso->filename);
00961       return 1;
00962     }
00963 
00964   if (debug_sections[DEBUG_INFO].data != NULL)
00965     {
00966       unsigned char *ptr, *endcu, *endsec;
00967       uint_32 value;
00968       htab_t abbrev;
00969       struct abbrev_tag tag, *t;
00970       int phase;
00971       REL *relbuf = NULL;
00972 
00973       if (debug_sections[DEBUG_INFO].relsec)
00974         {
00975           int ndx, maxndx;
00976           GElf_Rel rel;
00977           GElf_Rela rela;
00978           GElf_Sym sym;
00979           GElf_Addr base = dso->shdr[debug_sections[DEBUG_INFO].sec].sh_addr;
00980           Elf_Data *symdata = NULL;
00981           int rtype;
00982 
00983           i = debug_sections[DEBUG_INFO].relsec;
00984           scn = dso->scn[i]; 
00985           data = elf_getdata (scn, NULL);
00986           assert (data != NULL && data->d_buf != NULL);
00987           assert (elf_getdata (scn, data) == NULL);
00988           assert (data->d_off == 0);
00989           assert (data->d_size == dso->shdr[i].sh_size);
00990           maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize;
00991           relbuf = malloc (maxndx * sizeof (REL));
00992           reltype = dso->shdr[i].sh_type;
00993           if (relbuf == NULL)
00994             error (1, errno, "%s: Could not allocate memory", dso->filename);
00995 
00996           symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL);
00997           assert (symdata != NULL && symdata->d_buf != NULL);
00998           assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata)
00999                   == NULL);
01000           assert (symdata->d_off == 0);
01001           assert (symdata->d_size
01002                   == dso->shdr[dso->shdr[i].sh_link].sh_size);
01003 
01004           for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx)
01005             {
01006               if (dso->shdr[i].sh_type == SHT_REL)
01007                 {
01008                   gelf_getrel (data, ndx, &rel);
01009                   rela.r_offset = rel.r_offset;
01010                   rela.r_info = rel.r_info;
01011                   rela.r_addend = 0;
01012                 }
01013               else
01014                 gelf_getrela (data, ndx, &rela);
01015               gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym);
01016               /* Relocations against section symbols are uninteresting
01017                  in REL.  */
01018               if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0)
01019                 continue;
01020               /* Only consider relocations against .debug_str, .debug_line
01021                  and .debug_abbrev.  */
01022               if (sym.st_shndx != debug_sections[DEBUG_STR].sec
01023                   && sym.st_shndx != debug_sections[DEBUG_LINE].sec
01024                   && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec)
01025                 continue;
01026               rela.r_addend += sym.st_value;
01027               rtype = ELF64_R_TYPE (rela.r_info);
01028               switch (dso->ehdr.e_machine)
01029                 {
01030                 case EM_SPARC:
01031                 case EM_SPARC32PLUS:
01032                 case EM_SPARCV9:
01033                   if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32)
01034                     goto fail;
01035                   break;
01036                 case EM_386:
01037                   if (rtype != R_386_32)
01038                     goto fail;
01039                   break;
01040                 case EM_PPC:
01041                 case EM_PPC64:
01042                   if (rtype != R_PPC_ADDR32 || rtype != R_PPC_UADDR32)
01043                     goto fail;
01044                   break;
01045                 case EM_S390:
01046                   if (rtype != R_390_32)
01047                     goto fail;
01048                   break;
01049                 case EM_IA_64:
01050                   if (rtype != R_IA64_SECREL32LSB)
01051                     goto fail;
01052                   break;
01053                 case EM_X86_64:
01054                   if (rtype != R_X86_64_32)
01055                     goto fail;
01056                   break;
01057                 case EM_ALPHA:
01058                   if (rtype != R_ALPHA_REFLONG)
01059                     goto fail;
01060                   break;
01061                 default:
01062                 fail:
01063                   error (1, 0, "%s: Unhandled relocation %d in .debug_info section",
01064                          dso->filename, rtype);
01065                 }
01066               relend->ptr = debug_sections[DEBUG_INFO].data
01067                             + (rela.r_offset - base);
01068               relend->addend = rela.r_addend;
01069               ++relend;
01070             }
01071           if (relbuf == relend)
01072             {
01073               free (relbuf);
01074               relbuf = NULL;
01075               relend = NULL;
01076             }
01077           else
01078             qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp);
01079         }
01080 
01081       for (phase = 0; phase < 2; phase++)
01082         {
01083           ptr = debug_sections[DEBUG_INFO].data;
01084           relptr = relbuf;
01085           endsec = ptr + debug_sections[DEBUG_INFO].size;
01086           while (ptr < endsec)
01087             {
01088               if (ptr + 11 > endsec)
01089                 {
01090                   error (0, 0, "%s: .debug_info CU header too small",
01091                          dso->filename);
01092                   return 1;
01093                 }
01094 
01095               endcu = ptr + 4;
01096               endcu += read_32 (ptr);
01097               if (endcu == ptr + 0xffffffff)
01098                 {
01099                   error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
01100                   return 1;
01101                 }
01102               
01103               if (endcu > endsec)
01104                 {
01105                   error (0, 0, "%s: .debug_info too small", dso->filename);
01106                   return 1;
01107                 }
01108               
01109               value = read_16 (ptr);
01110               if (value != 2)
01111                 {
01112                   error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
01113                          value);
01114                   return 1;
01115                 }
01116               
01117               value = read_32_relocated (ptr);
01118               if (value >= debug_sections[DEBUG_ABBREV].size)
01119                 {
01120                   if (debug_sections[DEBUG_ABBREV].data == NULL)
01121                     error (0, 0, "%s: .debug_abbrev not present", dso->filename);
01122                   else
01123                     error (0, 0, "%s: DWARF-2 CU abbrev offset too large",
01124                            dso->filename);
01125                   return 1;
01126                 }
01127               
01128               if (ptr_size == 0)
01129                 {
01130                   ptr_size = read_1 (ptr);
01131                   if (ptr_size != 4 && ptr_size != 8)
01132                     {
01133                       error (0, 0, "%s: Invalid DWARF-2 pointer size %d",
01134                              dso->filename, ptr_size);
01135                       return 1;
01136                     }
01137                 }
01138               else if (read_1 (ptr) != ptr_size)
01139                 {
01140                   error (0, 0, "%s: DWARF-2 pointer size differs between CUs",
01141                          dso->filename);
01142                   return 1;
01143                 }
01144               
01145               abbrev = read_abbrev (dso,
01146                                     debug_sections[DEBUG_ABBREV].data + value);
01147               if (abbrev == NULL)
01148                 return 1;
01149               
01150               while (ptr < endcu)
01151                 {
01152                   tag.entry = read_uleb128 (ptr);
01153                   if (tag.entry == 0)
01154                     continue;
01155                   t = htab_find_with_hash (abbrev, &tag, tag.entry);
01156                   if (t == NULL)
01157                     {
01158                       error (0, 0, "%s: Could not find DWARF-2 abbreviation %d",
01159                              dso->filename, tag.entry);
01160                       htab_delete (abbrev);
01161                       return 1;
01162                     }
01163                   
01164                   ptr = edit_attributes (dso, ptr, t, phase);
01165                   if (ptr == NULL)
01166                     break;
01167                 }
01168               
01169               htab_delete (abbrev);
01170             }
01171         }
01172       free (relbuf);
01173     }
01174   
01175   return 0;
01176 }
01177 
01178 static struct poptOption optionsTable[] = {
01179     { "base-dir",  'b', POPT_ARG_STRING, &base_dir, 0,
01180       "base build directory of objects", NULL },
01181     { "dest-dir",  'd', POPT_ARG_STRING, &dest_dir, 0,
01182       "directory to rewrite base-dir into", NULL },
01183     { "list-file",  'l', POPT_ARG_STRING, &list_file, 0,
01184       "file where to put list of source and header file names", NULL },
01185       POPT_AUTOHELP
01186     { NULL, 0, 0, NULL, 0, NULL, NULL }
01187 };
01188 
01189 static DSO *
01190 fdopen_dso (int fd, const char *name)
01191 {
01192   Elf *elf = NULL;
01193   GElf_Ehdr ehdr;
01194   int i;
01195   DSO *dso = NULL;
01196 
01197   elf = elf_begin (fd, ELF_C_RDWR_MMAP, NULL);
01198   if (elf == NULL)
01199     {
01200       error (0, 0, "cannot open ELF file: %s", elf_errmsg (-1));
01201       goto error_out;
01202     }
01203 
01204   if (elf_kind (elf) != ELF_K_ELF)
01205     {
01206       error (0, 0, "\"%s\" is not an ELF file", name);
01207       goto error_out;
01208     }
01209 
01210   if (gelf_getehdr (elf, &ehdr) == NULL)
01211     {
01212       error (0, 0, "cannot get the ELF header: %s",
01213              elf_errmsg (-1));
01214       goto error_out;
01215     }
01216 
01217   if (ehdr.e_type != ET_DYN && ehdr.e_type != ET_EXEC && ehdr.e_type != ET_REL)
01218     {
01219       error (0, 0, "\"%s\" is not a shared library", name);
01220       goto error_out;
01221     }
01222 
01223   /* Allocate DSO structure. Leave place for additional 20 new section
01224      headers.  */
01225   dso = (DSO *)
01226         malloc (sizeof(DSO) + (ehdr.e_shnum + 20) * sizeof(GElf_Shdr)
01227                 + (ehdr.e_shnum + 20) * sizeof(Elf_Scn *));
01228   if (!dso)
01229     {
01230       error (0, ENOMEM, "Could not open DSO");
01231       goto error_out;
01232     }
01233 
01234   elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT);
01235   
01236   memset (dso, 0, sizeof(DSO));
01237   dso->elf = elf;
01238   dso->ehdr = ehdr;
01239   dso->scn = (Elf_Scn **) &dso->shdr[ehdr.e_shnum + 20];
01240 
01241   for (i = 0; i < ehdr.e_shnum; ++i)
01242     {
01243       dso->scn[i] = elf_getscn (elf, i);
01244       gelf_getshdr (dso->scn[i], dso->shdr + i);
01245     }
01246 
01247   dso->filename = (const char *) strdup (name);
01248   return dso;
01249 
01250 error_out:
01251   if (dso)
01252     {
01253       free ((char *) dso->filename);
01254       free (dso);
01255     }
01256   if (elf)
01257     elf_end (elf);
01258   if (fd != -1)
01259     close (fd);
01260   return NULL;
01261 }
01262 
01263 
01264 int
01265 main (int argc, char *argv[])
01266 {
01267   DSO *dso;
01268   int fd, i;
01269   const char *file;
01270   poptContext optCon;   /* context for parsing command-line options */
01271   int nextopt;
01272   const char **args;
01273   struct stat stat_buf;
01274   char *p;
01275   
01276   optCon = poptGetContext("debugedit", argc, (const char **)argv,
01277                           optionsTable, 0);
01278   
01279   while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT)
01280     /* do nothing */ ;
01281 
01282   if (nextopt != -1)
01283     {
01284       fprintf (stderr, "Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n",
01285               poptBadOption (optCon, 0),
01286               poptStrerror (nextopt),
01287               argv[0]);
01288       exit (1);
01289     }
01290   
01291   args = poptGetArgs (optCon);
01292   if (args == NULL || args[0] == NULL || args[1] != NULL)
01293     {
01294       poptPrintHelp(optCon, stdout, 0);
01295       exit (1);
01296     }
01297 
01298   if (dest_dir != NULL)
01299     {
01300       if (base_dir == NULL)
01301         {
01302           fprintf (stderr, "You must specify a base dir if you specify a dest dir\n");
01303           exit (1);
01304         }
01305       if (strlen (dest_dir) > strlen (base_dir))
01306         {
01307           fprintf (stderr, "Only dest dir longer than base dir not supported\n");
01308           exit (1);
01309         }
01310     }
01311 
01312   /* Make sure there are trailing slashes in dirs */
01313   if (base_dir != NULL && base_dir[strlen (base_dir)-1] != '/')
01314     {
01315       p = malloc (strlen (base_dir) + 2);
01316       strcpy (p, base_dir);
01317       strcat (p, "/");
01318       free (base_dir);
01319       base_dir = p;
01320     }
01321   if (dest_dir != NULL && dest_dir[strlen (dest_dir)-1] != '/')
01322     {
01323       p = malloc (strlen (dest_dir) + 2);
01324       strcpy (p, dest_dir);
01325       strcat (p, "/");
01326       free (dest_dir);
01327       dest_dir = p;
01328     }
01329   
01330   if (list_file != NULL)
01331     {
01332       list_file_fd = open (list_file, O_WRONLY|O_CREAT|O_APPEND, 0644);
01333     }
01334   
01335   file = args[0];
01336 
01337   if (elf_version(EV_CURRENT) == EV_NONE)
01338     {
01339       fprintf (stderr, "library out of date\n");
01340       exit (1);
01341     }
01342 
01343   if (stat(file, &stat_buf) < 0)
01344     {
01345       fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno));
01346       exit (1);
01347     }
01348 
01349   /* Make sure we can read and write */
01350   chmod (file, stat_buf.st_mode | S_IRUSR | S_IWUSR);
01351 
01352   fd = open (file, O_RDWR);
01353   if (fd < 0)
01354     {
01355       fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno));
01356       exit (1);
01357     }
01358 
01359   dso = fdopen_dso (fd, file);
01360   if (dso == NULL)
01361     exit (1);
01362 
01363   for (i = 1; i < dso->ehdr.e_shnum; i++)
01364     {
01365       const char *name;
01366       
01367       switch (dso->shdr[i].sh_type)
01368         {
01369         case SHT_PROGBITS:
01370           name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
01371           /* TODO: Handle stabs */
01372 #if 0
01373           if (strcmp (name, ".stab") == 0)
01374             edit_stabs (dso, i);
01375 #endif
01376           if (strcmp (name, ".debug_info") == 0)
01377             edit_dwarf2 (dso);
01378           
01379           break;
01380         default:
01381           break;
01382         }
01383     }
01384 
01385   if (elf_update (dso->elf, ELF_C_WRITE) < 0)
01386     {
01387       fprintf (stderr, "Failed to write file: %s\n", elf_errmsg (elf_errno()));
01388       exit (1);
01389     }
01390   if (elf_end (dso->elf) < 0)
01391     {
01392       fprintf (stderr, "elf_end failed: %s\n", elf_errmsg (elf_errno()));
01393       exit (1);
01394     }
01395   close (fd);
01396 
01397   /* Restore old access rights */
01398   chmod (file, stat_buf.st_mode);
01399   
01400   poptFreeContext (optCon);
01401 
01402   return 0;
01403 }

Generated on Tue Feb 19 23:28:22 2008 for rpm by  doxygen 1.5.1