- update to elfutils-0.56.
[platform/upstream/rpm.git] / tools / debugedit.c
1 /* Copyright (C) 2001, 2002 Red Hat, Inc.
2    Written by Alexander Larsson <alexl@redhat.com>, 2002
3    Based on code by Jakub Jelinek <jakub@redhat.com>, 2001.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19 /* Needed for libelf */
20 #define _FILE_OFFSET_BITS 64
21
22 #include <assert.h>
23 #include <byteswap.h>
24 #include <endian.h>
25 #include <errno.h>
26 #include <error.h>
27 #include <limits.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <popt.h>
35
36 #include <gelf.h>
37 #include <dwarf.h>
38
39 #include "hashtab.h"
40
41 char *base_dir = NULL;
42 char *dest_dir = NULL;
43 char *list_file = NULL;
44 int list_file_fd = -1; 
45
46 typedef unsigned int uint_32;
47 typedef unsigned short uint_16;
48
49 typedef struct
50 {
51   Elf *elf;
52   GElf_Ehdr ehdr;
53   GElf_Phdr *phdr;
54   Elf_Scn **scn;
55   const char *filename;
56   int lastscn;
57   GElf_Shdr shdr[0];
58 } DSO;
59
60 #define read_uleb128(ptr) ({            \
61   unsigned int ret = 0;                 \
62   unsigned int c;                       \
63   int shift = 0;                        \
64   do                                    \
65     {                                   \
66       c = *ptr++;                       \
67       ret |= (c & 0x7f) << shift;       \
68       shift += 7;                       \
69     } while (c & 0x80);                 \
70                                         \
71   if (shift >= 35)                      \
72     ret = UINT_MAX;                     \
73   ret;                                  \
74 })
75
76 static uint_16 (*do_read_16) (unsigned char *ptr);
77 static uint_32 (*do_read_32) (unsigned char *ptr);
78 static void (*write_32) (unsigned char *ptr, GElf_Addr val);
79
80 static int ptr_size;
81
82 static inline uint_16
83 buf_read_ule16 (unsigned char *data)
84 {
85   return data[0] | (data[1] << 8);
86 }
87
88 static inline uint_16
89 buf_read_ube16 (unsigned char *data)
90 {
91   return data[1] | (data[0] << 8);
92 }
93
94 static inline uint_32
95 buf_read_ule32 (unsigned char *data)
96 {
97   return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
98 }
99
100 static inline uint_32
101 buf_read_ube32 (unsigned char *data)
102 {
103   return data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
104 }
105
106 static const char *
107 strptr (DSO *dso, int sec, off_t offset)
108 {
109   Elf_Scn *scn;
110   Elf_Data *data;
111
112   scn = dso->scn[sec];
113   if (offset >= 0 && offset < dso->shdr[sec].sh_size)
114     {
115       data = NULL;
116       while ((data = elf_rawdata (scn, data)) != NULL)
117         {
118           if (data->d_buf
119               && offset >= data->d_off
120               && offset < data->d_off + data->d_size)
121             return (const char *) data->d_buf + (offset - data->d_off);
122         }
123     }
124
125   return NULL;
126 }
127
128
129 #define read_1(ptr) *ptr++
130
131 #define read_16(ptr) ({                 \
132   uint_16 ret = do_read_16 (ptr);       \
133   ptr += 2;                             \
134   ret;                                  \
135 })
136
137 #define read_32(ptr) ({                 \
138   uint_32 ret = do_read_32 (ptr);       \
139   ptr += 4;                             \
140   ret;                                  \
141 })
142
143 static void
144 dwarf2_write_le32 (unsigned char *p, GElf_Addr val)
145 {
146   uint_32 v = (uint_32) val;
147
148   p[0] = v;
149   p[1] = v >> 8;
150   p[2] = v >> 16;
151   p[3] = v >> 24;
152 }
153
154
155 static void
156 dwarf2_write_be32 (unsigned char *p, GElf_Addr val)
157 {
158   uint_32 v = (uint_32) val;
159
160   p[3] = v;
161   p[2] = v >> 8;
162   p[1] = v >> 16;
163   p[0] = v >> 24;
164 }
165
166 static struct
167   {
168     const char *name;
169     unsigned char *data;
170     Elf_Data *elf_data;
171     size_t size;
172     int sec;
173   } debug_sections[] =
174   {
175 #define DEBUG_INFO      0
176 #define DEBUG_ABBREV    1
177 #define DEBUG_LINE      2
178 #define DEBUG_ARANGES   3
179 #define DEBUG_PUBNAMES  4
180 #define DEBUG_MACINFO   5
181 #define DEBUG_LOC       6
182 #define DEBUG_STR       7
183 #define DEBUG_FRAME     8
184 #define DEBUG_RANGES    9
185     { ".debug_info", NULL, 0, 0 },
186     { ".debug_abbrev", NULL, 0, 0 },
187     { ".debug_line", NULL, 0, 0 },
188     { ".debug_aranges", NULL, 0, 0 },
189     { ".debug_pubnames", NULL, 0, 0 },
190     { ".debug_macinfo", NULL, 0, 0 },
191     { ".debug_loc", NULL, 0, 0 },
192     { ".debug_str", NULL, 0, 0 },
193     { ".debug_frame", NULL, 0, 0 },
194     { ".debug_ranges", NULL, 0, 0 },
195     { NULL, NULL, 0 }
196   };
197
198 struct abbrev_attr
199   {
200     unsigned int attr;
201     unsigned int form;
202   };
203
204 struct abbrev_tag
205   {
206     unsigned int entry;
207     unsigned int tag;
208     int nattr;
209     struct abbrev_attr attr[0];
210   };
211
212 static hashval_t
213 abbrev_hash (const void *p)
214 {
215   struct abbrev_tag *t = (struct abbrev_tag *)p;
216
217   return t->entry;
218 }
219
220 static int
221 abbrev_eq (const void *p, const void *q)
222 {
223   struct abbrev_tag *t1 = (struct abbrev_tag *)p;
224   struct abbrev_tag *t2 = (struct abbrev_tag *)p;
225
226   return t1->entry == t2->entry;
227 }
228
229 static void
230 abbrev_del (void *p)
231 {
232   free (p);
233 }
234
235 static htab_t
236 read_abbrev (DSO *dso, unsigned char *ptr)
237 {
238   htab_t h = htab_try_create (50, abbrev_hash, abbrev_eq, abbrev_del);
239   unsigned int attr, form;
240   struct abbrev_tag *t;
241   int size;
242   void **slot;
243
244   if (h == NULL)
245     {
246 no_memory:
247       error (0, ENOMEM, "%s: Could not read .debug_abbrev", dso->filename);
248       if (h)
249         htab_delete (h);
250       return NULL;
251     }
252
253   while ((attr = read_uleb128 (ptr)) != 0)
254     {
255       size = 10;
256       t = malloc (sizeof (*t) + size * sizeof (struct abbrev_attr));
257       if (t == NULL)
258         goto no_memory;
259       t->entry = attr;
260       t->nattr = 0;
261       slot = htab_find_slot (h, t, INSERT);
262       if (slot == NULL)
263         {
264           free (t);
265           goto no_memory;
266         }
267       if (*slot != NULL)
268         {
269           error (0, 0, "%s: Duplicate DWARF-2 abbreviation %d", dso->filename,
270                  t->entry);
271           free (t);
272           htab_delete (h);
273           return NULL;
274         }
275       t->tag = read_uleb128 (ptr);
276       ++ptr; /* skip children flag.  */
277       while ((attr = read_uleb128 (ptr)) != 0)
278         {
279           if (t->nattr == size)
280             {
281               size += 10;
282               t = realloc (t, sizeof (*t) + size * sizeof (struct abbrev_attr));
283               if (t == NULL)
284                 goto no_memory;
285             }
286           form = read_uleb128 (ptr);
287           if (form == 2 || form > DW_FORM_indirect)
288             {
289               error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename, form);
290               htab_delete (h);
291               return NULL;
292             }
293
294           t->attr[t->nattr].attr = attr;
295           t->attr[t->nattr++].form = form;
296         }
297       if (read_uleb128 (ptr) != 0)
298         {
299           error (0, 0, "%s: DWARF-2 abbreviation does not end with 2 zeros",
300                  dso->filename);
301           htab_delete (h);
302           return NULL;
303         }
304       *slot = t;
305     }
306
307   return h;
308 }
309
310 #define IS_DIR_SEPARATOR(c) ((c)=='/')
311
312 static char *
313 canonicalize_path (char *s, char *d)
314 {
315   char *rv = d;
316   char *sroot, *droot;
317
318   if (d == 0)
319     rv = d = s;
320
321   if (IS_DIR_SEPARATOR (*s))
322     {
323       *d++ = *s++;
324       if (IS_DIR_SEPARATOR (*s) && !IS_DIR_SEPARATOR (s[1]))
325         {
326           /* Special case for "//foo" meaning a Posix namespace
327              escape.  */
328           *d++ = *s++;
329         }
330       while (IS_DIR_SEPARATOR (*s))
331         s++;
332     }
333   droot = d;
334   sroot = s;
335
336   while (*s)
337     {
338       /* At this point, we're always at the beginning of a path
339          segment.  */
340
341       if (s[0] == '.' && (s[1] == 0 || IS_DIR_SEPARATOR (s[1])))
342         {
343           s ++;
344           if (*s)
345             s++;
346           else if (d > droot)
347             d--;
348         }
349
350       else if (s[0] == '.' && s[1] == '.'
351                && (s[2] == 0 || IS_DIR_SEPARATOR (s[2])))
352         {
353           char *pre = d-1; /* includes slash */
354           while (droot < pre && IS_DIR_SEPARATOR (*pre))
355             pre--;
356           if (droot <= pre && ! IS_DIR_SEPARATOR (*pre))
357             {
358               d = pre;
359               while (droot < d && ! IS_DIR_SEPARATOR (*d))
360                 d--;
361               /* d now points to the slash */
362               if (droot < d)
363                 d++;
364               s += 2;
365               if (*s)
366                 s++;
367               else if (d > droot)
368                 d--;
369             }
370           else
371             {
372               *d++ = *s++;
373               *d++ = *s++;
374               if (*s)
375                 *d++ = *s++;
376             }
377         }
378
379       else
380         {
381           while (*s && ! IS_DIR_SEPARATOR (*s))
382             *d++ = *s++;
383         }
384
385       if (IS_DIR_SEPARATOR (*s))
386         {
387           *d++ = *s++;
388           while (IS_DIR_SEPARATOR (*s))
389             s++;
390         }
391     }
392   while (droot < d && IS_DIR_SEPARATOR (d[-1]))
393     --d;
394   if (d == rv)
395     *d++ = '.';
396   *d = 0;
397
398   return rv;
399 }
400
401 static int
402 has_prefix (const char  *str,
403             const char  *prefix)
404 {
405   int str_len;
406   int prefix_len;
407   
408   str_len = strlen (str);
409   prefix_len = strlen (prefix);
410
411   if (str_len < prefix_len)
412     return 0;
413   
414   return strncmp (str, prefix, prefix_len) == 0;
415 }
416
417 static int
418 edit_dwarf2_line (DSO *dso, uint_32 off, char *comp_dir, int phase)
419 {
420   unsigned char *ptr = debug_sections[DEBUG_LINE].data;
421   unsigned char *endsec = ptr + debug_sections[DEBUG_LINE].size;
422   unsigned char *endcu, *endprol;
423   unsigned char opcode_base;
424   uint_32 value;
425   int s;
426
427   if (phase != 0)
428     return 0;
429   
430   s = 0;
431
432   ptr += off;
433   
434   endcu = ptr + 4;
435   endcu += read_32 (ptr);
436   if (endcu == ptr + 0xffffffff)
437     {
438       error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
439       return 1;
440     }
441   
442   if (endcu > endsec)
443     {
444       error (0, 0, "%s: .debug_line CU does not fit into section",
445              dso->filename);
446       return 1;
447     }
448   
449   value = read_16 (ptr);
450   if (value != 2)
451     {
452       error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
453              value);
454       return 1;
455     }
456   
457   endprol = ptr + 4;
458   endprol += read_32 (ptr);
459   if (endprol > endcu)
460     {
461       error (0, 0, "%s: .debug_line CU prologue does not fit into CU",
462              dso->filename);
463       return 1;
464     }
465   
466   opcode_base = ptr[4];
467   ptr = ptr + 4 + opcode_base;
468   
469   /* dir table: */
470   while (*ptr != 0)
471     {
472       ptr = strchr(ptr, 0) + 1;
473     }
474   ptr++;
475   
476   /* file table: */
477   while (*ptr != 0)
478     {
479       char *s;
480       if (*ptr == '/')
481         {
482           s = strdup (ptr);
483         }
484       else
485         {
486           s = malloc (strlen (comp_dir) + 1 + strlen (ptr) + 1);
487           strcpy (s, comp_dir);
488           strcat (s, "/");
489           strcat (s, ptr);
490           canonicalize_path (s, s);
491         }
492       if (base_dir == NULL ||
493           has_prefix (s, base_dir))
494         {
495           char *p;
496           size_t size;
497           ssize_t ret;
498           if (base_dir)
499             p = s + strlen (base_dir);
500           else
501             p = s;
502           
503           if (list_file_fd != -1)
504             {
505               size = strlen (p) + 1;
506               while (size > 0)
507                 {
508                   ret = write (list_file_fd, p, size);
509                   if (ret == -1)
510                     break;
511                   size -= ret;
512                   p += ret;
513                 }
514             }
515           
516         }
517       
518       free (s);
519       
520         
521       ptr = strchr(ptr, 0) + 1;
522       read_uleb128(ptr);
523       read_uleb128(ptr);
524       read_uleb128(ptr);
525     }
526   
527   return 0;
528 }
529
530
531
532 static unsigned char *
533 edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase)
534 {
535   int i;
536   uint_32 list_offs;
537   int found_list_offs;
538   unsigned char *comp_dir;
539   
540   comp_dir = NULL;
541   list_offs = 0;
542   found_list_offs = 0;
543   for (i = 0; i < t->nattr; ++i)
544     {
545       uint_32 form = t->attr[i].form;
546       uint_32 len = 0;
547       int base_len, dest_len;
548       
549
550       while (1)
551         {
552           if (t->attr[i].attr == DW_AT_stmt_list)
553             {
554               if (form == DW_FORM_data4)
555                 {
556                   list_offs = do_read_32 (ptr);
557                   found_list_offs = 1;
558                 }
559             }
560
561           if (debug_sections[DEBUG_STR].data &&
562               t->attr[i].attr == DW_AT_comp_dir &&
563               form == DW_FORM_strp)
564             {
565               char *dir;
566               
567               dir = debug_sections[DEBUG_STR].data + do_read_32 (ptr);
568               comp_dir = strdup (dir);
569
570               if (phase == 1 && dest_dir && has_prefix (dir, base_dir))
571                 {
572                   base_len = strlen (base_dir);
573                   dest_len = strlen (dest_dir);
574                   
575                   memcpy (dir, dest_dir, dest_len);
576                   if (dest_len < base_len)
577                     {
578                       memcpy (dir + dest_len, dir + base_len,
579                               strlen (dir + base_len) + 1);
580                     }
581                   elf_flagdata (debug_sections[DEBUG_STR].elf_data,
582                                 ELF_C_SET, ELF_F_DIRTY);
583                 }
584             }
585           
586           switch (form)
587             {
588             case DW_FORM_addr:
589               ptr += ptr_size;
590               break;
591             case DW_FORM_ref1:
592             case DW_FORM_flag:
593             case DW_FORM_data1:
594               ++ptr;
595               break;
596             case DW_FORM_ref2:
597             case DW_FORM_data2:
598               ptr += 2;
599               break;
600             case DW_FORM_ref4:
601             case DW_FORM_data4:
602               ptr += 4;
603               break;
604             case DW_FORM_ref8:
605             case DW_FORM_data8:
606               ptr += 8;
607               break;
608             case DW_FORM_sdata:
609             case DW_FORM_ref_udata:
610             case DW_FORM_udata:
611               read_uleb128 (ptr);
612               break;
613             case DW_FORM_ref_addr:
614             case DW_FORM_strp:
615               ptr += 4;
616               break;
617             case DW_FORM_string:
618               ptr = strchr (ptr, '\0') + 1;
619               break;
620             case DW_FORM_indirect:
621               form = read_uleb128 (ptr);
622               continue;
623             case DW_FORM_block1:
624               len = *ptr++;
625               break;
626             case DW_FORM_block2:
627               len = read_16 (ptr);
628               form = DW_FORM_block1;
629               break;
630             case DW_FORM_block4:
631               len = read_32 (ptr);
632               form = DW_FORM_block1;
633               break;
634             case DW_FORM_block:
635               len = read_uleb128 (ptr);
636               form = DW_FORM_block1;
637               assert (len < UINT_MAX);
638               break;
639             default:
640               error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename,
641                      form);
642               return NULL;
643             }
644
645           if (form == DW_FORM_block1)
646             ptr += len;
647           
648           break;
649         }
650     }
651   if (found_list_offs && comp_dir)
652     edit_dwarf2_line (dso, list_offs, comp_dir, phase);
653
654   return ptr;
655 }
656
657 static int
658 edit_dwarf2 (DSO *dso, int n)
659 {
660   Elf_Data *data;
661   Elf_Scn *scn;
662   int i, j;
663
664   for (i = 0; debug_sections[i].name; ++i)
665     {
666       debug_sections[i].data = NULL;
667       debug_sections[i].size = 0;
668       debug_sections[i].sec = 0;
669     }
670   ptr_size = 0;
671
672   for (i = 1; i < dso->ehdr.e_shnum; ++i)
673     if (! (dso->shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR))
674         && dso->shdr[i].sh_size)
675       {
676         const char *name = strptr (dso, dso->ehdr.e_shstrndx,
677                                    dso->shdr[i].sh_name);
678
679         if (strncmp (name, ".debug_", sizeof (".debug_") - 1) == 0)
680           {
681             for (j = 0; debug_sections[j].name; ++j)
682               if (strcmp (name, debug_sections[j].name) == 0)
683                 {
684                   if (debug_sections[j].data)
685                     {
686                       error (0, 0, "%s: Found two copies of %s section",
687                              dso->filename, name);
688                       return 1;
689                     }
690
691                   scn = dso->scn[i]; 
692                   data = elf_rawdata (scn, NULL);
693                   assert (data != NULL && data->d_buf != NULL);
694                   assert (elf_rawdata (scn, data) == NULL);
695                   assert (data->d_off == 0);
696                   assert (data->d_size == dso->shdr[i].sh_size);
697                   debug_sections[j].data = data->d_buf;
698                   debug_sections[j].elf_data = data;
699                   debug_sections[j].size = data->d_size;
700                   debug_sections[j].sec = i;
701                   break;
702                 }
703
704             if (debug_sections[j].name == NULL)
705               {
706                 error (0, 0, "%s: Unknown debugging section %s",
707                        dso->filename, name);
708               }
709           }
710       }
711
712   if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
713     {
714       do_read_16 = buf_read_ule16;
715       do_read_32 = buf_read_ule32;
716       write_32 = dwarf2_write_le32;
717     }
718   else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
719     {
720       do_read_16 = buf_read_ube16;
721       do_read_32 = buf_read_ube32;
722       write_32 = dwarf2_write_be32;
723     }
724   else
725     {
726       error (0, 0, "%s: Wrong ELF data enconding", dso->filename);
727       return 1;
728     }
729
730   if (debug_sections[DEBUG_INFO].data != NULL)
731     {
732       unsigned char *ptr, *endcu, *endsec;
733       uint_32 value;
734       htab_t abbrev;
735       struct abbrev_tag tag, *t;
736       int phase;
737
738       for (phase = 0; phase < 2; phase++)
739         {
740           ptr = debug_sections[DEBUG_INFO].data;
741           endsec = ptr + debug_sections[DEBUG_INFO].size;
742           while (ptr < endsec)
743             {
744               if (ptr + 11 > endsec)
745                 {
746                   error (0, 0, "%s: .debug_info CU header too small",
747                          dso->filename);
748                   return 1;
749                 }
750
751               endcu = ptr + 4;
752               endcu += read_32 (ptr);
753               if (endcu == ptr + 0xffffffff)
754                 {
755                   error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
756                   return 1;
757                 }
758               
759               if (endcu > endsec)
760                 {
761                   error (0, 0, "%s: .debug_info too small", dso->filename);
762                   return 1;
763                 }
764               
765               value = read_16 (ptr);
766               if (value != 2)
767                 {
768                   error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
769                          value);
770                   return 1;
771                 }
772               
773               value = read_32 (ptr);
774               if (value >= debug_sections[DEBUG_ABBREV].size)
775                 {
776                   if (debug_sections[DEBUG_ABBREV].data == NULL)
777                     error (0, 0, "%s: .debug_abbrev not present", dso->filename);
778                   else
779                     error (0, 0, "%s: DWARF-2 CU abbrev offset too large",
780                            dso->filename);
781                   return 1;
782                 }
783               
784               if (ptr_size == 0)
785                 {
786                   ptr_size = read_1 (ptr);
787                   if (ptr_size != 4 && ptr_size != 8)
788                     {
789                       error (0, 0, "%s: Invalid DWARF-2 pointer size %d",
790                              dso->filename, ptr_size);
791                       return 1;
792                     }
793                 }
794               else if (read_1 (ptr) != ptr_size)
795                 {
796                   error (0, 0, "%s: DWARF-2 pointer size differs between CUs",
797                          dso->filename);
798                   return 1;
799                 }
800               
801               abbrev = read_abbrev (dso,
802                                     debug_sections[DEBUG_ABBREV].data + value);
803               if (abbrev == NULL)
804                 return 1;
805               
806               while (ptr < endcu)
807                 {
808                   tag.entry = read_uleb128 (ptr);
809                   if (tag.entry == 0)
810                     continue;
811                   t = htab_find_with_hash (abbrev, &tag, tag.entry);
812                   if (t == NULL)
813                     {
814                       error (0, 0, "%s: Could not find DWARF-2 abbreviation %d",
815                              dso->filename, tag.entry);
816                       htab_delete (abbrev);
817                       return 1;
818                     }
819                   
820                   ptr = edit_attributes (dso, ptr, t, phase);
821                   if (ptr == NULL)
822                     break;
823                 }
824               
825               htab_delete (abbrev);
826             }
827         }
828     }
829   
830   return 0;
831 }
832
833 static struct poptOption optionsTable[] = {
834     { "base-dir",  'b', POPT_ARG_STRING, &base_dir, 0,
835       "base build directory of objects", NULL },
836     { "dest-dir",  'd', POPT_ARG_STRING, &dest_dir, 0,
837       "directory to rewrite base-dir into", NULL },
838     { "list-file",  'l', POPT_ARG_STRING, &list_file, 0,
839       "directory to rewrite base-dir into", NULL },
840       POPT_AUTOHELP
841     { NULL, 0, 0, NULL, 0 }
842 };
843
844 static DSO *
845 fdopen_dso (int fd, const char *name)
846 {
847   Elf *elf = NULL;
848   GElf_Ehdr ehdr;
849   int i;
850   DSO *dso = NULL;
851
852   elf = elf_begin (fd, ELF_C_RDWR_MMAP, NULL);
853   if (elf == NULL)
854     {
855       error (0, 0, "cannot open ELF file: %s", elf_errmsg (-1));
856       goto error_out;
857     }
858
859   if (elf_kind (elf) != ELF_K_ELF)
860     {
861       error (0, 0, "\"%s\" is not an ELF file", name);
862       goto error_out;
863     }
864
865   if (gelf_getehdr (elf, &ehdr) == NULL)
866     {
867       error (0, 0, "cannot get the ELF header: %s",
868              elf_errmsg (-1));
869       goto error_out;
870     }
871
872   if (ehdr.e_type != ET_DYN && ehdr.e_type != ET_EXEC)
873     {
874       error (0, 0, "\"%s\" is not a shared library", name);
875       goto error_out;
876     }
877
878   /* Allocate DSO structure. Leave place for additional 20 new section
879      headers.  */
880   dso = (DSO *)
881         malloc (sizeof(DSO) + (ehdr.e_shnum + 20) * sizeof(GElf_Shdr)
882                 + (ehdr.e_phnum + 1) * sizeof(GElf_Phdr)
883                 + (ehdr.e_shnum + 20) * sizeof(Elf_Scn *));
884   if (!dso)
885     {
886       error (0, ENOMEM, "Could not open DSO");
887       goto error_out;
888     }
889
890   elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT);
891   
892   memset (dso, 0, sizeof(DSO));
893   dso->elf = elf;
894   dso->ehdr = ehdr;
895   dso->phdr = (GElf_Phdr *) &dso->shdr[ehdr.e_shnum + 20];
896   dso->scn = (Elf_Scn **) &dso->phdr[ehdr.e_phnum + 1];
897   for (i = 0; i < ehdr.e_phnum; ++i)
898     gelf_getphdr (elf, i, dso->phdr + i);
899
900   for (i = 0; i < ehdr.e_shnum; ++i)
901     {
902       dso->scn[i] = elf_getscn (elf, i);
903       gelf_getshdr (dso->scn[i], dso->shdr + i);
904     }
905
906   dso->filename = (const char *) strdup (name);
907   return dso;
908
909 error_out:
910   if (dso)
911     {
912       free ((char *) dso->filename);
913       free (dso);
914     }
915   if (elf)
916     elf_end (elf);
917   if (fd != -1)
918     close (fd);
919   return NULL;
920 }
921
922
923 int
924 main (int argc, char *argv[])
925 {
926   DSO *dso;
927   int fd, i;
928   const char *file;
929   poptContext optCon;   /* context for parsing command-line options */
930   int nextopt;
931   const char **args;
932   struct stat stat_buf;
933   char *p;
934   
935   optCon = poptGetContext("debugedit", argc, (const char **)argv,
936                           optionsTable, 0);
937   
938   while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT)
939     /* do nothing */ ;
940
941   if (nextopt != -1)
942     {
943       fprintf (stderr, "Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n",
944               poptBadOption (optCon, 0),
945               poptStrerror (nextopt),
946               argv[0]);
947       exit (1);
948     }
949   
950   args = poptGetArgs (optCon);
951   if (args == NULL || args[0] == NULL || args[1] != NULL)
952     {
953       poptPrintHelp(optCon, stdout, 0);
954       exit (1);
955     }
956
957   if (dest_dir != NULL)
958     {
959       if (base_dir == NULL)
960         {
961           fprintf (stderr, "You must specify a base dir if you specify a dest dir\n");
962           exit (1);
963         }
964       if (strlen (dest_dir) > strlen (base_dir))
965         {
966           fprintf (stderr, "Only dest dir longer than base dir not supported\n");
967           exit (1);
968         }
969     }
970
971   /* Make sure there are trailing slashes in dirs */
972   if (base_dir != NULL && base_dir[strlen (base_dir)-1] != '/')
973     {
974       p = malloc (strlen (base_dir) + 2);
975       strcpy (p, base_dir);
976       strcat (p, "/");
977       free (base_dir);
978       base_dir = p;
979     }
980   if (dest_dir != NULL && dest_dir[strlen (dest_dir)-1] != '/')
981     {
982       p = malloc (strlen (dest_dir) + 2);
983       strcpy (p, dest_dir);
984       strcat (p, "/");
985       free (dest_dir);
986       dest_dir = p;
987     }
988   
989   if (list_file != NULL)
990     {
991       list_file_fd = open (list_file, O_WRONLY|O_CREAT|O_APPEND, 0644);
992     }
993   
994   file = args[0];
995
996   if (elf_version(EV_CURRENT) == EV_NONE)
997     {
998       fprintf (stderr, "library out of date\n");
999       exit (1);
1000     }
1001
1002   if (stat(file, &stat_buf) < 0)
1003     {
1004       fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno));
1005       exit (1);
1006     }
1007
1008   /* Make sure we can read and write */
1009   chmod (file, stat_buf.st_mode | S_IRUSR | S_IWUSR);
1010
1011   fd = open (file, O_RDWR);
1012   if (fd < 0)
1013     {
1014       fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno));
1015       exit (1);
1016     }
1017
1018   dso = fdopen_dso (fd, file);
1019   
1020   for (i = 1; i < dso->ehdr.e_shnum; i++)
1021     {
1022       const char *name;
1023       
1024       switch (dso->shdr[i].sh_type)
1025         {
1026         case SHT_PROGBITS:
1027           name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
1028           /* TODO: Handle stabs */
1029 #if 0
1030           if (strcmp (name, ".stab") == 0)
1031             edit_stabs (dso, i);
1032 #endif
1033           if (strcmp (name, ".debug_info") == 0)
1034             edit_dwarf2 (dso, i);
1035           
1036           break;
1037         default:
1038           break;
1039         }
1040     }
1041
1042   if (elf_update (dso->elf, ELF_C_WRITE) < 0)
1043     {
1044       fprintf (stderr, "Failed to write file: %s\n", elf_errmsg (elf_errno()));
1045       exit (1);
1046     }
1047   if (elf_end (dso->elf) < 0)
1048     {
1049       fprintf (stderr, "elf_end failed: %s\n", elf_errmsg (elf_errno()));
1050       exit (1);
1051     }
1052   close (fd);
1053
1054   /* Restore old access rights */
1055   chmod (file, stat_buf.st_mode);
1056   
1057   poptFreeContext (optCon);
1058
1059   return 0;
1060 }
1061
1062