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