27e6691014395865a4dd35af22dae8cb3e205e3c
[platform/upstream/rpm.git] / tools / debugedit.c
1 /* Copyright (C) 2001, 2002, 2003, 2005, 2007 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 "system.h"
20
21 /* Needed for libelf */
22 #define _FILE_OFFSET_BITS 64
23
24 #include <assert.h>
25 #include <byteswap.h>
26 #include <endian.h>
27 #include <errno.h>
28 #include <error.h>
29 #include <limits.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdint.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <popt.h>
38
39 #include <gelf.h>
40 #include <dwarf.h>
41
42 #include <rpm/rpmio.h>
43 #include <rpm/rpmpgp.h>
44 #include "tools/hashtab.h"
45
46 #define DW_TAG_partial_unit 0x3c
47
48 char *base_dir = NULL;
49 char *dest_dir = NULL;
50 char *list_file = NULL;
51 int list_file_fd = -1;
52 int do_build_id = 0;
53
54 typedef struct
55 {
56   Elf *elf;
57   GElf_Ehdr ehdr;
58   Elf_Scn **scn;
59   const char *filename;
60   int lastscn;
61   GElf_Shdr shdr[0];
62 } DSO;
63
64 typedef struct
65 {
66   unsigned char *ptr;
67   uint32_t addend;
68 } REL;
69
70 #define read_uleb128(ptr) ({            \
71   unsigned int ret = 0;                 \
72   unsigned int c;                       \
73   int shift = 0;                        \
74   do                                    \
75     {                                   \
76       c = *ptr++;                       \
77       ret |= (c & 0x7f) << shift;       \
78       shift += 7;                       \
79     } while (c & 0x80);                 \
80                                         \
81   if (shift >= 35)                      \
82     ret = UINT_MAX;                     \
83   ret;                                  \
84 })
85
86 static uint16_t (*do_read_16) (unsigned char *ptr);
87 static uint32_t (*do_read_32) (unsigned char *ptr);
88 static void (*write_32) (unsigned char *ptr, GElf_Addr val);
89
90 static int ptr_size;
91
92 static inline uint16_t
93 buf_read_ule16 (unsigned char *data)
94 {
95   return data[0] | (data[1] << 8);
96 }
97
98 static inline uint16_t
99 buf_read_ube16 (unsigned char *data)
100 {
101   return data[1] | (data[0] << 8);
102 }
103
104 static inline uint32_t
105 buf_read_ule32 (unsigned char *data)
106 {
107   return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
108 }
109
110 static inline uint32_t
111 buf_read_ube32 (unsigned char *data)
112 {
113   return data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
114 }
115
116 static const char *
117 strptr (DSO *dso, int sec, off_t offset)
118 {
119   Elf_Scn *scn;
120   Elf_Data *data;
121
122   scn = dso->scn[sec];
123   if (offset >= 0 && (GElf_Addr) offset < dso->shdr[sec].sh_size)
124     {
125       data = NULL;
126       while ((data = elf_rawdata (scn, data)) != NULL)
127         {
128           if (data->d_buf
129               && offset >= data->d_off
130               && offset < data->d_off + data->d_size)
131             return (const char *) data->d_buf + (offset - data->d_off);
132         }
133     }
134
135   return NULL;
136 }
137
138
139 #define read_1(ptr) *ptr++
140
141 #define read_16(ptr) ({                                 \
142   uint16_t ret = do_read_16 (ptr);                      \
143   ptr += 2;                                             \
144   ret;                                                  \
145 })
146
147 #define read_32(ptr) ({                                 \
148   uint32_t ret = do_read_32 (ptr);                      \
149   ptr += 4;                                             \
150   ret;                                                  \
151 })
152
153 REL *relptr, *relend;
154 int reltype;
155
156 #define do_read_32_relocated(ptr) ({                    \
157   uint32_t dret = do_read_32 (ptr);                     \
158   if (relptr)                                           \
159     {                                                   \
160       while (relptr < relend && relptr->ptr < ptr)      \
161         ++relptr;                                       \
162       if (relptr < relend && relptr->ptr == ptr)        \
163         {                                               \
164           if (reltype == SHT_REL)                       \
165             dret += relptr->addend;                     \
166           else                                          \
167             dret = relptr->addend;                      \
168         }                                               \
169     }                                                   \
170   dret;                                                 \
171 })
172
173 #define read_32_relocated(ptr) ({                       \
174   uint32_t ret = do_read_32_relocated (ptr);            \
175   ptr += 4;                                             \
176   ret;                                                  \
177 })
178
179 static void
180 dwarf2_write_le32 (unsigned char *p, GElf_Addr val)
181 {
182   uint32_t v = (uint32_t) val;
183
184   p[0] = v;
185   p[1] = v >> 8;
186   p[2] = v >> 16;
187   p[3] = v >> 24;
188 }
189
190
191 static void
192 dwarf2_write_be32 (unsigned char *p, GElf_Addr val)
193 {
194   uint32_t v = (uint32_t) val;
195
196   p[3] = v;
197   p[2] = v >> 8;
198   p[1] = v >> 16;
199   p[0] = v >> 24;
200 }
201
202 static struct
203   {
204     const char *name;
205     unsigned char *data;
206     Elf_Data *elf_data;
207     size_t size;
208     int sec, relsec;
209   } debug_sections[] =
210   {
211 #define DEBUG_INFO      0
212 #define DEBUG_ABBREV    1
213 #define DEBUG_LINE      2
214 #define DEBUG_ARANGES   3
215 #define DEBUG_PUBNAMES  4
216 #define DEBUG_MACINFO   5
217 #define DEBUG_LOC       6
218 #define DEBUG_STR       7
219 #define DEBUG_FRAME     8
220 #define DEBUG_RANGES    9
221     { ".debug_info", NULL, NULL, 0, 0, 0 },
222     { ".debug_abbrev", NULL, NULL, 0, 0, 0 },
223     { ".debug_line", NULL, NULL, 0, 0, 0 },
224     { ".debug_aranges", NULL, NULL, 0, 0, 0 },
225     { ".debug_pubnames", NULL, NULL, 0, 0, 0 },
226     { ".debug_macinfo", NULL, NULL, 0, 0, 0 },
227     { ".debug_loc", NULL, NULL, 0, 0, 0 },
228     { ".debug_str", NULL, NULL, 0, 0, 0 },
229     { ".debug_frame", NULL, NULL, 0, 0, 0 },
230     { ".debug_ranges", NULL, NULL, 0, 0, 0 },
231     { NULL, NULL, NULL, 0, 0, 0 }
232   };
233
234 struct abbrev_attr
235   {
236     unsigned int attr;
237     unsigned int form;
238   };
239
240 struct abbrev_tag
241   {
242     unsigned int entry;
243     unsigned int tag;
244     int nattr;
245     struct abbrev_attr attr[0];
246   };
247
248 static hashval_t
249 abbrev_hash (const void *p)
250 {
251   struct abbrev_tag *t = (struct abbrev_tag *)p;
252
253   return t->entry;
254 }
255
256 static int
257 abbrev_eq (const void *p, const void *q)
258 {
259   struct abbrev_tag *t1 = (struct abbrev_tag *)p;
260   struct abbrev_tag *t2 = (struct abbrev_tag *)q;
261
262   return t1->entry == t2->entry;
263 }
264
265 static void
266 abbrev_del (void *p)
267 {
268   free (p);
269 }
270
271 static htab_t
272 read_abbrev (DSO *dso, unsigned char *ptr)
273 {
274   htab_t h = htab_try_create (50, abbrev_hash, abbrev_eq, abbrev_del);
275   unsigned int attr, form;
276   struct abbrev_tag *t;
277   int size;
278   void **slot;
279
280   if (h == NULL)
281     {
282 no_memory:
283       error (0, ENOMEM, "%s: Could not read .debug_abbrev", dso->filename);
284       if (h)
285         htab_delete (h);
286       return NULL;
287     }
288
289   while ((attr = read_uleb128 (ptr)) != 0)
290     {
291       size = 10;
292       t = malloc (sizeof (*t) + size * sizeof (struct abbrev_attr));
293       if (t == NULL)
294         goto no_memory;
295       t->entry = attr;
296       t->nattr = 0;
297       slot = htab_find_slot (h, t, INSERT);
298       if (slot == NULL)
299         {
300           free (t);
301           goto no_memory;
302         }
303       if (*slot != NULL)
304         {
305           error (0, 0, "%s: Duplicate DWARF-2 abbreviation %d", dso->filename,
306                  t->entry);
307           free (t);
308           htab_delete (h);
309           return NULL;
310         }
311       t->tag = read_uleb128 (ptr);
312       ++ptr; /* skip children flag.  */
313       while ((attr = read_uleb128 (ptr)) != 0)
314         {
315           if (t->nattr == size)
316             {
317               size += 10;
318               t = realloc (t, sizeof (*t) + size * sizeof (struct abbrev_attr));
319               if (t == NULL)
320                 goto no_memory;
321             }
322           form = read_uleb128 (ptr);
323           if (form == 2 || form > DW_FORM_indirect)
324             {
325               error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename, form);
326               htab_delete (h);
327               return NULL;
328             }
329
330           t->attr[t->nattr].attr = attr;
331           t->attr[t->nattr++].form = form;
332         }
333       if (read_uleb128 (ptr) != 0)
334         {
335           error (0, 0, "%s: DWARF-2 abbreviation does not end with 2 zeros",
336                  dso->filename);
337           htab_delete (h);
338           return NULL;
339         }
340       *slot = t;
341     }
342
343   return h;
344 }
345
346 #define IS_DIR_SEPARATOR(c) ((c)=='/')
347
348 static char *
349 canonicalize_path (const char *s, char *d)
350 {
351   char *rv = d;
352   const char *sroot;
353   char *droot;
354
355   if (IS_DIR_SEPARATOR (*s))
356     {
357       *d++ = *s++;
358       if (IS_DIR_SEPARATOR (*s) && !IS_DIR_SEPARATOR (s[1]))
359         {
360           /* Special case for "//foo" meaning a Posix namespace
361              escape.  */
362           *d++ = *s++;
363         }
364       while (IS_DIR_SEPARATOR (*s))
365         s++;
366     }
367   droot = d;
368   sroot = s;
369
370   while (*s)
371     {
372       /* At this point, we're always at the beginning of a path
373          segment.  */
374
375       if (s[0] == '.' && (s[1] == 0 || IS_DIR_SEPARATOR (s[1])))
376         {
377           s++;
378           if (*s)
379             while (IS_DIR_SEPARATOR (*s))
380               ++s;
381         }
382
383       else if (s[0] == '.' && s[1] == '.'
384                && (s[2] == 0 || IS_DIR_SEPARATOR (s[2])))
385         {
386           char *pre = d - 1; /* includes slash */
387           while (droot < pre && IS_DIR_SEPARATOR (*pre))
388             pre--;
389           if (droot <= pre && ! IS_DIR_SEPARATOR (*pre))
390             {
391               while (droot < pre && ! IS_DIR_SEPARATOR (*pre))
392                 pre--;
393               /* pre now points to the slash */
394               if (droot < pre)
395                 pre++;
396               if (pre + 3 == d && pre[0] == '.' && pre[1] == '.')
397                 {
398                   *d++ = *s++;
399                   *d++ = *s++;
400                 }
401               else
402                 {
403                   d = pre;
404                   s += 2;
405                   if (*s)
406                     while (IS_DIR_SEPARATOR (*s))
407                       s++;
408                 }
409             }
410           else
411             {
412               *d++ = *s++;
413               *d++ = *s++;
414             }
415         }
416       else
417         {
418           while (*s && ! IS_DIR_SEPARATOR (*s))
419             *d++ = *s++;
420         }
421
422       if (IS_DIR_SEPARATOR (*s))
423         {
424           *d++ = *s++;
425           while (IS_DIR_SEPARATOR (*s))
426             s++;
427         }
428     }
429   while (droot < d && IS_DIR_SEPARATOR (d[-1]))
430     --d;
431   if (d == rv)
432     *d++ = '.';
433   *d = 0;
434
435   return rv;
436 }
437
438 static int
439 has_prefix (const char  *str,
440             const char  *prefix)
441 {
442   size_t str_len;
443   size_t prefix_len;
444   
445   str_len = strlen (str);
446   prefix_len = strlen (prefix);
447
448   if (str_len < prefix_len)
449     return 0;
450   
451   return strncmp (str, prefix, prefix_len) == 0;
452 }
453
454 static int
455 edit_dwarf2_line (DSO *dso, uint32_t off, char *comp_dir, int phase)
456 {
457   unsigned char *ptr = debug_sections[DEBUG_LINE].data, *dir;
458   unsigned char **dirt;
459   unsigned char *endsec = ptr + debug_sections[DEBUG_LINE].size;
460   unsigned char *endcu, *endprol;
461   unsigned char opcode_base;
462   uint32_t value, dirt_cnt;
463   size_t comp_dir_len = strlen (comp_dir);
464   size_t abs_file_cnt = 0, abs_dir_cnt = 0;
465
466   if (phase != 0)
467     return 0;
468   
469   ptr += off;
470   
471   endcu = ptr + 4;
472   endcu += read_32 (ptr);
473   if (endcu == ptr + 0xffffffff)
474     {
475       error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
476       return 1;
477     }
478
479   if (endcu > endsec)
480     {
481       error (0, 0, "%s: .debug_line CU does not fit into section",
482              dso->filename);
483       return 1;
484     }
485
486   value = read_16 (ptr);
487   if (value != 2)
488     {
489       error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
490              value);
491       return 1;
492     }
493   
494   endprol = ptr + 4;
495   endprol += read_32 (ptr);
496   if (endprol > endcu)
497     {
498       error (0, 0, "%s: .debug_line CU prologue does not fit into CU",
499              dso->filename);
500       return 1;
501     }
502   
503   opcode_base = ptr[4];
504   ptr = dir = ptr + 4 + opcode_base;
505   
506   /* dir table: */
507   value = 1;
508   while (*ptr != 0)
509     {
510       ptr = (unsigned char *) strchr ((char *)ptr, 0) + 1;
511       ++value;
512     }
513
514   dirt = (unsigned char **) alloca (value * sizeof (unsigned char *));
515   dirt[0] = (unsigned char *) ".";
516   dirt_cnt = 1;
517   ptr = dir;
518   while (*ptr != 0)
519     {
520       dirt[dirt_cnt++] = ptr;
521       ptr = (unsigned char *) strchr ((char *)ptr, 0) + 1;
522     }
523   ptr++;
524
525   /* file table: */
526   while (*ptr != 0)
527     {
528       char *s, *file;
529       size_t file_len, dir_len;
530
531       file = (char *) ptr;
532       ptr = (unsigned char *) strchr ((char *)ptr, 0) + 1;
533       value = read_uleb128 (ptr);
534
535       if (value >= dirt_cnt)
536         {
537           error (0, 0, "%s: Wrong directory table index %u",
538                  dso->filename, value);
539           return 1;
540         }
541       file_len = strlen (file);
542       dir_len = strlen ((char *)dirt[value]);
543       s = malloc (comp_dir_len + 1 + file_len + 1 + dir_len + 1);
544       if (s == NULL)
545         {
546           error (0, ENOMEM, "%s: Reading file table", dso->filename);
547           return 1;
548         }
549       if (*file == '/')
550         {
551           memcpy (s, file, file_len + 1);
552           if (dest_dir && has_prefix (file, base_dir))
553             ++abs_file_cnt;
554         }
555       else if (*dirt[value] == '/')
556         {
557           memcpy (s, dirt[value], dir_len);
558           s[dir_len] = '/';
559           memcpy (s + dir_len + 1, file, file_len + 1);
560         }
561       else
562         {
563           char *p = s;
564           if (comp_dir_len != 0)
565             {
566               memcpy (s, comp_dir, comp_dir_len);
567               s[comp_dir_len] = '/';
568               p += comp_dir_len + 1;
569             }
570           memcpy (p, dirt[value], dir_len);
571           p[dir_len] = '/';
572           memcpy (p + dir_len + 1, file, file_len + 1);
573         }
574       canonicalize_path (s, s);
575       if (list_file_fd != -1)
576         {
577           char *p = NULL;
578           if (base_dir == NULL)
579             p = s;
580           else if (has_prefix (s, base_dir))
581             p = s + strlen (base_dir);
582           else if (has_prefix (s, dest_dir))
583             p = s + strlen (dest_dir);
584
585           if (p)
586             {
587               size_t size = strlen (p) + 1;
588               while (size > 0)
589                 {
590                   ssize_t ret = write (list_file_fd, p, size);
591                   if (ret == -1)
592                     break;
593                   size -= ret;
594                   p += ret;
595                 }
596             }
597         }
598
599       free (s);
600       
601       read_uleb128 (ptr);
602       read_uleb128 (ptr);
603     }
604   ++ptr;
605   
606   if (dest_dir)
607     {
608       unsigned char *srcptr, *buf = NULL;
609       size_t base_len = strlen (base_dir);
610       size_t dest_len = strlen (dest_dir);
611       size_t shrank = 0;
612
613       if (dest_len == base_len)
614         abs_file_cnt = 0;
615       if (abs_file_cnt)
616         {
617           srcptr = buf = malloc (ptr - dir);
618           memcpy (srcptr, dir, ptr - dir);
619           ptr = dir;
620         }
621       else
622         ptr = srcptr = dir;
623       while (*srcptr != 0)
624         {
625           size_t len = strlen ((char *)srcptr) + 1;
626           const unsigned char *readptr = srcptr;
627
628           if (*srcptr == '/' && has_prefix ((char *)srcptr, base_dir))
629             {
630               if (dest_len < base_len)
631                   ++abs_dir_cnt;
632               memcpy (ptr, dest_dir, dest_len);
633               ptr += dest_len;
634               readptr += base_len;
635                 }
636           srcptr += len;
637
638           shrank += srcptr - readptr;
639           canonicalize_path ((char *)readptr, (char *)ptr);
640           len = strlen ((char *)ptr) + 1;
641           shrank -= len;
642           ptr += len;
643
644               elf_flagdata (debug_sections[DEBUG_STR].elf_data,
645                             ELF_C_SET, ELF_F_DIRTY);
646             }
647
648       if (shrank > 0)
649         {
650           if (--shrank == 0)
651             error (EXIT_FAILURE, 0,
652                    "canonicalization unexpectedly shrank by one character");
653           else
654             {       
655               memset (ptr, 'X', shrank);
656               ptr += shrank;
657               *ptr++ = '\0';
658             }
659         }
660
661       if (abs_dir_cnt + abs_file_cnt != 0)
662         {
663           size_t len = (abs_dir_cnt + abs_file_cnt) * (base_len - dest_len);
664
665           if (len == 1)
666             error (EXIT_FAILURE, 0, "-b arg has to be either the same length as -d arg, or more than 1 char shorter");
667           memset (ptr, 'X', len - 1);
668           ptr += len - 1;
669           *ptr++ = '\0';
670         }
671       *ptr++ = '\0';
672       ++srcptr;
673
674       while (*srcptr != 0)
675         {
676           size_t len = strlen ((char *)srcptr) + 1;
677
678           if (*srcptr == '/' && has_prefix ((char *)srcptr, base_dir))
679             {
680               memcpy (ptr, dest_dir, dest_len);
681               if (dest_len < base_len)
682                 {
683                   memmove (ptr + dest_len, srcptr + base_len,
684                            len - base_len);
685                   ptr += dest_len - base_len;
686                 }
687               elf_flagdata (debug_sections[DEBUG_STR].elf_data,
688                             ELF_C_SET, ELF_F_DIRTY);
689             }
690           else if (ptr != srcptr)
691             memmove (ptr, srcptr, len);
692           srcptr += len;
693           ptr += len;
694           dir = srcptr;
695           read_uleb128 (srcptr);
696           read_uleb128 (srcptr);
697           read_uleb128 (srcptr);
698           if (ptr != dir)
699             memmove (ptr, dir, srcptr - dir);
700           ptr += srcptr - dir;
701         }
702       *ptr = '\0';
703       free (buf);
704     }
705   return 0;
706 }
707
708
709
710 static unsigned char *
711 edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase)
712 {
713   int i;
714   uint32_t list_offs;
715   int found_list_offs;
716   char *comp_dir;
717   
718   comp_dir = NULL;
719   list_offs = 0;
720   found_list_offs = 0;
721   for (i = 0; i < t->nattr; ++i)
722     {
723       uint32_t form = t->attr[i].form;
724       size_t len = 0;
725       size_t base_len, dest_len;
726       
727
728       while (1)
729         {
730           if (t->attr[i].attr == DW_AT_stmt_list)
731             {
732               if (form == DW_FORM_data4)
733                 {
734                   list_offs = do_read_32_relocated (ptr);
735                   found_list_offs = 1;
736                 }
737             }
738
739           if (t->attr[i].attr == DW_AT_comp_dir)
740           {
741               if ( form == DW_FORM_string )
742               {
743                   free (comp_dir);
744                   comp_dir = strdup ((char *)ptr);
745                   
746                   if (phase == 1 && dest_dir && has_prefix ((char *)ptr, base_dir))
747                   {
748                       base_len = strlen (base_dir);
749                       dest_len = strlen (dest_dir);
750                       
751                       memcpy (ptr, dest_dir, dest_len);
752                       if (dest_len < base_len)
753                       {
754                           memset(ptr + dest_len, '/',
755                                  base_len - dest_len);
756                           
757                       }
758                       elf_flagdata (debug_sections[DEBUG_INFO].elf_data,
759                                     ELF_C_SET, ELF_F_DIRTY);
760                   }
761               }
762           
763               else if (form == DW_FORM_strp &&
764                        debug_sections[DEBUG_STR].data)
765               {
766                   char *dir;
767
768                   dir = (char *) debug_sections[DEBUG_STR].data
769                       + do_read_32_relocated (ptr);
770
771                   free (comp_dir);
772                   comp_dir = strdup (dir);
773
774                   if (phase == 1 && dest_dir && has_prefix (dir, base_dir))
775                   {
776                       base_len = strlen (base_dir);
777                       dest_len = strlen (dest_dir);
778                   
779                       memcpy (dir, dest_dir, dest_len);
780                       if (dest_len < base_len)
781                       {
782                           memmove (dir + dest_len, dir + base_len,
783                                    strlen (dir + base_len) + 1);
784                       }
785                       elf_flagdata (debug_sections[DEBUG_STR].elf_data,
786                                     ELF_C_SET, ELF_F_DIRTY);
787                   }
788               }
789           }
790           else if ((t->tag == DW_TAG_compile_unit
791                     || t->tag == DW_TAG_partial_unit)
792                    && t->attr[i].attr == DW_AT_name
793                    && form == DW_FORM_strp
794                    && debug_sections[DEBUG_STR].data)
795             {
796               char *name;
797               
798               name = (char *) debug_sections[DEBUG_STR].data
799                      + do_read_32_relocated (ptr);
800               if (*name == '/' && comp_dir == NULL)
801                 {
802                   char *enddir = strrchr (name, '/');
803
804                   if (enddir != name)
805                     {
806                       comp_dir = malloc (enddir - name + 1);
807                       memcpy (comp_dir, name, enddir - name);
808                       comp_dir [enddir - name] = '\0';
809                     }
810                   else
811                     comp_dir = strdup ("/");
812                 }
813
814               if (phase == 1 && dest_dir && has_prefix (name, base_dir))
815                 {
816                   base_len = strlen (base_dir);
817                   dest_len = strlen (dest_dir);
818                   
819                   memcpy (name, dest_dir, dest_len);
820                   if (dest_len < base_len)
821                     {
822                       memmove (name + dest_len, name + base_len,
823                                strlen (name + base_len) + 1);
824                     }
825                   elf_flagdata (debug_sections[DEBUG_STR].elf_data,
826                                 ELF_C_SET, ELF_F_DIRTY);
827                 }
828             }
829
830           switch (form)
831             {
832             case DW_FORM_ref_addr: /* ptr_size in DWARF 2, offset in DWARF 3 */
833             case DW_FORM_addr:
834               ptr += ptr_size;
835               break;
836             case DW_FORM_ref1:
837             case DW_FORM_flag:
838             case DW_FORM_data1:
839               ++ptr;
840               break;
841             case DW_FORM_ref2:
842             case DW_FORM_data2:
843               ptr += 2;
844               break;
845             case DW_FORM_ref4:
846             case DW_FORM_data4:
847               ptr += 4;
848               break;
849             case DW_FORM_ref8:
850             case DW_FORM_data8:
851               ptr += 8;
852               break;
853             case DW_FORM_sdata:
854             case DW_FORM_ref_udata:
855             case DW_FORM_udata:
856               read_uleb128 (ptr);
857               break;
858             case DW_FORM_strp:
859               ptr += 4;
860               break;
861             case DW_FORM_string:
862               ptr = (unsigned char *) strchr ((char *)ptr, '\0') + 1;
863               break;
864             case DW_FORM_indirect:
865               form = read_uleb128 (ptr);
866               continue;
867             case DW_FORM_block1:
868               len = *ptr++;
869               break;
870             case DW_FORM_block2:
871               len = read_16 (ptr);
872               form = DW_FORM_block1;
873               break;
874             case DW_FORM_block4:
875               len = read_32 (ptr);
876               form = DW_FORM_block1;
877               break;
878             case DW_FORM_block:
879               len = read_uleb128 (ptr);
880               form = DW_FORM_block1;
881               assert (len < UINT_MAX);
882               break;
883             default:
884               error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename,
885                      form);
886               return NULL;
887             }
888
889           if (form == DW_FORM_block1)
890             ptr += len;
891           
892           break;
893         }
894     }
895   if (found_list_offs && comp_dir)
896     edit_dwarf2_line (dso, list_offs, comp_dir, phase);
897
898   free (comp_dir);
899
900   return ptr;
901 }
902
903 static int
904 rel_cmp (const void *a, const void *b)
905 {
906   REL *rela = (REL *) a, *relb = (REL *) b;
907
908   if (rela->ptr < relb->ptr)
909     return -1;
910
911   if (rela->ptr > relb->ptr)
912     return 1;
913
914   return 0;
915 }
916
917 static int
918 edit_dwarf2 (DSO *dso)
919 {
920   Elf_Data *data;
921   Elf_Scn *scn;
922   int i, j;
923
924   for (i = 0; debug_sections[i].name; ++i)
925     {
926       debug_sections[i].data = NULL;
927       debug_sections[i].size = 0;
928       debug_sections[i].sec = 0;
929       debug_sections[i].relsec = 0;
930     }
931   ptr_size = 0;
932
933   for (i = 1; i < dso->ehdr.e_shnum; ++i)
934     if (! (dso->shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR))
935         && dso->shdr[i].sh_size)
936       {
937         const char *name = strptr (dso, dso->ehdr.e_shstrndx,
938                                    dso->shdr[i].sh_name);
939
940         if (strncmp (name, ".debug_", sizeof (".debug_") - 1) == 0)
941           {
942             for (j = 0; debug_sections[j].name; ++j)
943               if (strcmp (name, debug_sections[j].name) == 0)
944                 {
945                   if (debug_sections[j].data)
946                     {
947                       error (0, 0, "%s: Found two copies of %s section",
948                              dso->filename, name);
949                       return 1;
950                     }
951
952                   scn = dso->scn[i]; 
953                   data = elf_rawdata (scn, NULL);
954                   assert (data != NULL && data->d_buf != NULL);
955                   assert (elf_rawdata (scn, data) == NULL);
956                   assert (data->d_off == 0);
957                   assert (data->d_size == dso->shdr[i].sh_size);
958                   debug_sections[j].data = data->d_buf;
959                   debug_sections[j].elf_data = data;
960                   debug_sections[j].size = data->d_size;
961                   debug_sections[j].sec = i;
962                   break;
963                 }
964
965             if (debug_sections[j].name == NULL)
966               {
967                 error (0, 0, "%s: Unknown debugging section %s",
968                        dso->filename, name);
969               }
970           }
971         else if (dso->ehdr.e_type == ET_REL
972                  && ((dso->shdr[i].sh_type == SHT_REL
973                       && strncmp (name, ".rel.debug_",
974                                   sizeof (".rel.debug_") - 1) == 0)
975                      || (dso->shdr[i].sh_type == SHT_RELA
976                          && strncmp (name, ".rela.debug_",
977                                      sizeof (".rela.debug_") - 1) == 0)))
978           {
979             for (j = 0; debug_sections[j].name; ++j)
980               if (strcmp (name + sizeof (".rel") - 1
981                           + (dso->shdr[i].sh_type == SHT_RELA),
982                           debug_sections[j].name) == 0)
983                 {
984                   debug_sections[j].relsec = i;
985                   break;
986                 }
987           }
988       }
989
990   if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
991     {
992       do_read_16 = buf_read_ule16;
993       do_read_32 = buf_read_ule32;
994       write_32 = dwarf2_write_le32;
995     }
996   else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
997     {
998       do_read_16 = buf_read_ube16;
999       do_read_32 = buf_read_ube32;
1000       write_32 = dwarf2_write_be32;
1001     }
1002   else
1003     {
1004       error (0, 0, "%s: Wrong ELF data enconding", dso->filename);
1005       return 1;
1006     }
1007
1008   if (debug_sections[DEBUG_INFO].data != NULL)
1009     {
1010       unsigned char *ptr, *endcu, *endsec;
1011       uint32_t value;
1012       htab_t abbrev;
1013       struct abbrev_tag tag, *t;
1014       int phase;
1015       REL *relbuf = NULL;
1016
1017       if (debug_sections[DEBUG_INFO].relsec)
1018         {
1019           int ndx, maxndx;
1020           GElf_Rel rel;
1021           GElf_Rela rela;
1022           GElf_Sym sym;
1023           GElf_Addr base = dso->shdr[debug_sections[DEBUG_INFO].sec].sh_addr;
1024           Elf_Data *symdata = NULL;
1025           int rtype;
1026
1027           i = debug_sections[DEBUG_INFO].relsec;
1028           scn = dso->scn[i]; 
1029           data = elf_getdata (scn, NULL);
1030           assert (data != NULL && data->d_buf != NULL);
1031           assert (elf_getdata (scn, data) == NULL);
1032           assert (data->d_off == 0);
1033           assert (data->d_size == dso->shdr[i].sh_size);
1034           maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize;
1035           relbuf = malloc (maxndx * sizeof (REL));
1036           reltype = dso->shdr[i].sh_type;
1037           if (relbuf == NULL)
1038             error (1, errno, "%s: Could not allocate memory", dso->filename);
1039
1040           symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL);
1041           assert (symdata != NULL && symdata->d_buf != NULL);
1042           assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata)
1043                   == NULL);
1044           assert (symdata->d_off == 0);
1045           assert (symdata->d_size
1046                   == dso->shdr[dso->shdr[i].sh_link].sh_size);
1047
1048           for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx)
1049             {
1050               if (dso->shdr[i].sh_type == SHT_REL)
1051                 {
1052                   gelf_getrel (data, ndx, &rel);
1053                   rela.r_offset = rel.r_offset;
1054                   rela.r_info = rel.r_info;
1055                   rela.r_addend = 0;
1056                 }
1057               else
1058                 gelf_getrela (data, ndx, &rela);
1059               gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym);
1060               /* Relocations against section symbols are uninteresting
1061                  in REL.  */
1062               if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0)
1063                 continue;
1064               /* Only consider relocations against .debug_str, .debug_line
1065                  and .debug_abbrev.  */
1066               if (sym.st_shndx != debug_sections[DEBUG_STR].sec
1067                   && sym.st_shndx != debug_sections[DEBUG_LINE].sec
1068                   && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec)
1069                 continue;
1070               rela.r_addend += sym.st_value;
1071               rtype = ELF64_R_TYPE (rela.r_info);
1072               switch (dso->ehdr.e_machine)
1073                 {
1074                 case EM_SPARC:
1075                 case EM_SPARC32PLUS:
1076                 case EM_SPARCV9:
1077                   if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32)
1078                     goto fail;
1079                   break;
1080                 case EM_386:
1081                   if (rtype != R_386_32)
1082                     goto fail;
1083                   break;
1084                 case EM_PPC:
1085                 case EM_PPC64:
1086                   if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32)
1087                     goto fail;
1088                   break;
1089                 case EM_S390:
1090                   if (rtype != R_390_32)
1091                     goto fail;
1092                   break;
1093                 case EM_IA_64:
1094                   if (rtype != R_IA64_SECREL32LSB)
1095                     goto fail;
1096                   break;
1097                 case EM_X86_64:
1098                   if (rtype != R_X86_64_32)
1099                     goto fail;
1100                   break;
1101                 case EM_ALPHA:
1102                   if (rtype != R_ALPHA_REFLONG)
1103                     goto fail;
1104                   break;
1105                 default:
1106                 fail:
1107                   error (1, 0, "%s: Unhandled relocation %d in .debug_info section",
1108                          dso->filename, rtype);
1109                 }
1110               relend->ptr = debug_sections[DEBUG_INFO].data
1111                             + (rela.r_offset - base);
1112               relend->addend = rela.r_addend;
1113               ++relend;
1114             }
1115           if (relbuf == relend)
1116             {
1117               free (relbuf);
1118               relbuf = NULL;
1119               relend = NULL;
1120             }
1121           else
1122             qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp);
1123         }
1124
1125       for (phase = 0; phase < 2; phase++)
1126         {
1127           ptr = debug_sections[DEBUG_INFO].data;
1128           relptr = relbuf;
1129           endsec = ptr + debug_sections[DEBUG_INFO].size;
1130           while (ptr < endsec)
1131             {
1132               if (ptr + 11 > endsec)
1133                 {
1134                   error (0, 0, "%s: .debug_info CU header too small",
1135                          dso->filename);
1136                   return 1;
1137                 }
1138
1139               endcu = ptr + 4;
1140               endcu += read_32 (ptr);
1141               if (endcu == ptr + 0xffffffff)
1142                 {
1143                   error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
1144                   return 1;
1145                 }
1146               
1147               if (endcu > endsec)
1148                 {
1149                   error (0, 0, "%s: .debug_info too small", dso->filename);
1150                   return 1;
1151                 }
1152               
1153               value = read_16 (ptr);
1154               if (value != 2)
1155                 {
1156                   error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
1157                          value);
1158                   return 1;
1159                 }
1160               
1161               value = read_32_relocated (ptr);
1162               if (value >= debug_sections[DEBUG_ABBREV].size)
1163                 {
1164                   if (debug_sections[DEBUG_ABBREV].data == NULL)
1165                     error (0, 0, "%s: .debug_abbrev not present", dso->filename);
1166                   else
1167                     error (0, 0, "%s: DWARF-2 CU abbrev offset too large",
1168                            dso->filename);
1169                   return 1;
1170                 }
1171               
1172               if (ptr_size == 0)
1173                 {
1174                   ptr_size = read_1 (ptr);
1175                   if (ptr_size != 4 && ptr_size != 8)
1176                     {
1177                       error (0, 0, "%s: Invalid DWARF-2 pointer size %d",
1178                              dso->filename, ptr_size);
1179                       return 1;
1180                     }
1181                 }
1182               else if (read_1 (ptr) != ptr_size)
1183                 {
1184                   error (0, 0, "%s: DWARF-2 pointer size differs between CUs",
1185                          dso->filename);
1186                   return 1;
1187                 }
1188               
1189               abbrev = read_abbrev (dso,
1190                                     debug_sections[DEBUG_ABBREV].data + value);
1191               if (abbrev == NULL)
1192                 return 1;
1193               
1194               while (ptr < endcu)
1195                 {
1196                   tag.entry = read_uleb128 (ptr);
1197                   if (tag.entry == 0)
1198                     continue;
1199                   t = htab_find_with_hash (abbrev, &tag, tag.entry);
1200                   if (t == NULL)
1201                     {
1202                       error (0, 0, "%s: Could not find DWARF-2 abbreviation %d",
1203                              dso->filename, tag.entry);
1204                       htab_delete (abbrev);
1205                       return 1;
1206                     }
1207                   
1208                   ptr = edit_attributes (dso, ptr, t, phase);
1209                   if (ptr == NULL)
1210                     break;
1211                 }
1212               
1213               htab_delete (abbrev);
1214             }
1215         }
1216       free (relbuf);
1217     }
1218   
1219   return 0;
1220 }
1221
1222 static struct poptOption optionsTable[] = {
1223     { "base-dir",  'b', POPT_ARG_STRING, &base_dir, 0,
1224       "base build directory of objects", NULL },
1225     { "dest-dir",  'd', POPT_ARG_STRING, &dest_dir, 0,
1226       "directory to rewrite base-dir into", NULL },
1227     { "list-file",  'l', POPT_ARG_STRING, &list_file, 0,
1228       "file where to put list of source and header file names", NULL },
1229     { "build-id",  'i', POPT_ARG_NONE, &do_build_id, 0,
1230       "recompute build ID note and print ID on stdout", NULL },
1231       POPT_AUTOHELP
1232     { NULL, 0, 0, NULL, 0, NULL, NULL }
1233 };
1234
1235 static DSO *
1236 fdopen_dso (int fd, const char *name)
1237 {
1238   Elf *elf = NULL;
1239   GElf_Ehdr ehdr;
1240   int i;
1241   DSO *dso = NULL;
1242
1243   elf = elf_begin (fd, ELF_C_RDWR_MMAP, NULL);
1244   if (elf == NULL)
1245     {
1246       error (0, 0, "cannot open ELF file: %s", elf_errmsg (-1));
1247       goto error_out;
1248     }
1249
1250   if (elf_kind (elf) != ELF_K_ELF)
1251     {
1252       error (0, 0, "\"%s\" is not an ELF file", name);
1253       goto error_out;
1254     }
1255
1256   if (gelf_getehdr (elf, &ehdr) == NULL)
1257     {
1258       error (0, 0, "cannot get the ELF header: %s",
1259              elf_errmsg (-1));
1260       goto error_out;
1261     }
1262
1263   if (ehdr.e_type != ET_DYN && ehdr.e_type != ET_EXEC && ehdr.e_type != ET_REL)
1264     {
1265       error (0, 0, "\"%s\" is not a shared library", name);
1266       goto error_out;
1267     }
1268
1269   /* Allocate DSO structure. Leave place for additional 20 new section
1270      headers.  */
1271   dso = (DSO *)
1272         malloc (sizeof(DSO) + (ehdr.e_shnum + 20) * sizeof(GElf_Shdr)
1273                 + (ehdr.e_shnum + 20) * sizeof(Elf_Scn *));
1274   if (!dso)
1275     {
1276       error (0, ENOMEM, "Could not open DSO");
1277       goto error_out;
1278     }
1279
1280   elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT);
1281   
1282   memset (dso, 0, sizeof(DSO));
1283   dso->elf = elf;
1284   dso->ehdr = ehdr;
1285   dso->scn = (Elf_Scn **) &dso->shdr[ehdr.e_shnum + 20];
1286
1287   for (i = 0; i < ehdr.e_shnum; ++i)
1288     {
1289       dso->scn[i] = elf_getscn (elf, i);
1290       gelf_getshdr (dso->scn[i], dso->shdr + i);
1291     }
1292
1293   dso->filename = (const char *) strdup (name);
1294   return dso;
1295
1296 error_out:
1297   if (dso)
1298     {
1299       free ((char *) dso->filename);
1300       free (dso);
1301     }
1302   if (elf)
1303     elf_end (elf);
1304   if (fd != -1)
1305     close (fd);
1306   return NULL;
1307 }
1308
1309 static const pgpHashAlgo algorithms[] = { PGPHASHALGO_MD5,
1310   PGPHASHALGO_SHA1, PGPHASHALGO_SHA256, PGPHASHALGO_SHA384, PGPHASHALGO_SHA512 };
1311
1312 /* Compute a fresh build ID bit-string from the editted file contents.  */
1313 static void
1314 handle_build_id (DSO *dso, Elf_Data *build_id,
1315                  size_t build_id_offset, size_t build_id_size)
1316 {
1317   DIGEST_CTX ctx;
1318   pgpHashAlgo algorithm;
1319   int i = sizeof(algorithms)/sizeof(algorithms[0]);
1320   void *digest = NULL;
1321   size_t len;
1322
1323   rpmInitCrypto();
1324
1325   while (i-- > 0)
1326     {
1327       algorithm = algorithms[i];
1328       if (rpmDigestLength(algorithm) == build_id_size)
1329         break;
1330     }
1331   if (i < 0)
1332     {
1333       fprintf (stderr, "Cannot handle %Zu-byte build ID\n", build_id_size);
1334       exit (1);
1335     }
1336
1337   if (elf_update (dso->elf, ELF_C_NULL) < 0)
1338     {
1339       fprintf (stderr, "Failed to update file: %s\n",
1340                elf_errmsg (elf_errno ()));
1341       exit (1);
1342     }
1343
1344   /* Clear the old bits so they do not affect the new hash.  */
1345   memset ((char *) build_id->d_buf + build_id_offset, 0, build_id_size);
1346
1347   ctx = rpmDigestInit(algorithm, 0);
1348
1349   /* Slurp the relevant header bits and section contents and feed them
1350      into the hash function.  The only bits we ignore are the offset
1351      fields in ehdr and shdrs, since the semantically identical ELF file
1352      could be written differently if it doesn't change the phdr layout.
1353      We always use the GElf (i.e. Elf64) formats for the bits to hash
1354      since it is convenient.  It doesn't matter whether this is an Elf32
1355      or Elf64 object, only that we are consistent in what bits feed the
1356      hash so it comes out the same for the same file contents.  */
1357   {
1358     union
1359     {
1360       GElf_Ehdr ehdr;
1361       GElf_Phdr phdr;
1362       GElf_Shdr shdr;
1363     } u;
1364     Elf_Data x = { .d_version = EV_CURRENT, .d_buf = &u };
1365
1366     x.d_type = ELF_T_EHDR;
1367     x.d_size = sizeof u.ehdr;
1368     u.ehdr = dso->ehdr;
1369     u.ehdr.e_phoff = u.ehdr.e_shoff = 0;
1370     if (elf64_xlatetom (&x, &x, dso->ehdr.e_ident[EI_DATA]) == NULL)
1371       {
1372       bad:
1373         fprintf (stderr, "Failed to compute header checksum: %s\n",
1374                  elf_errmsg (elf_errno ()));
1375         exit (1);
1376       }
1377
1378     x.d_type = ELF_T_PHDR;
1379     x.d_size = sizeof u.phdr;
1380     for (i = 0; i < dso->ehdr.e_phnum; ++i)
1381       {
1382         if (gelf_getphdr (dso->elf, i, &u.phdr) == NULL)
1383           goto bad;
1384         if (elf64_xlatetom (&x, &x, dso->ehdr.e_ident[EI_DATA]) == NULL)
1385           goto bad;
1386         rpmDigestUpdate(ctx, x.d_buf, x.d_size);
1387       }
1388
1389     x.d_type = ELF_T_SHDR;
1390     x.d_size = sizeof u.shdr;
1391     for (i = 0; i < dso->ehdr.e_shnum; ++i)
1392       if (dso->scn[i] != NULL)
1393         {
1394           u.shdr = dso->shdr[i];
1395           u.shdr.sh_offset = 0;
1396           if (elf64_xlatetom (&x, &x, dso->ehdr.e_ident[EI_DATA]) == NULL)
1397             goto bad;
1398           rpmDigestUpdate(ctx, x.d_buf, x.d_size);
1399
1400           if (u.shdr.sh_type != SHT_NOBITS)
1401             {
1402               Elf_Data *d = elf_rawdata (dso->scn[i], NULL);
1403               if (d == NULL)
1404                 goto bad;
1405               rpmDigestUpdate(ctx, d->d_buf, d->d_size);
1406             }
1407         }
1408   }
1409
1410   rpmDigestFinal(ctx, &digest, &len, 0);
1411   memcpy((unsigned char *)build_id->d_buf + build_id_offset, digest, build_id_size);
1412   free(digest);
1413
1414   elf_flagdata (build_id, ELF_C_SET, ELF_F_DIRTY);
1415
1416   /* Now format the build ID bits in hex to print out.  */
1417   {
1418     const uint8_t * id = (uint8_t *)build_id->d_buf + build_id_offset;
1419     char *hex = pgpHexStr(id, build_id_size);
1420     puts (hex);
1421     free(hex);
1422   }
1423 }
1424
1425 int
1426 main (int argc, char *argv[])
1427 {
1428   DSO *dso;
1429   int fd, i;
1430   const char *file;
1431   poptContext optCon;   /* context for parsing command-line options */
1432   int nextopt;
1433   const char **args;
1434   struct stat stat_buf;
1435   char *p;
1436   Elf_Data *build_id = NULL;
1437   size_t build_id_offset = 0, build_id_size = 0;
1438
1439   optCon = poptGetContext("debugedit", argc, (const char **)argv, optionsTable, 0);
1440   
1441   while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT)
1442     /* do nothing */ ;
1443
1444   if (nextopt != -1)
1445     {
1446       fprintf (stderr, "Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n",
1447               poptBadOption (optCon, 0),
1448               poptStrerror (nextopt),
1449               argv[0]);
1450       exit (1);
1451     }
1452   
1453   args = poptGetArgs (optCon);
1454   if (args == NULL || args[0] == NULL || args[1] != NULL)
1455     {
1456       poptPrintHelp(optCon, stdout, 0);
1457       exit (1);
1458     }
1459
1460   if (dest_dir != NULL)
1461     {
1462       if (base_dir == NULL)
1463         {
1464           fprintf (stderr, "You must specify a base dir if you specify a dest dir\n");
1465           exit (1);
1466         }
1467       if (strlen (dest_dir) > strlen (base_dir))
1468         {
1469           fprintf (stderr, "Only dest dir longer than base dir not supported\n");
1470           exit (1);
1471         }
1472     }
1473
1474   /* Make sure there are trailing slashes in dirs */
1475   if (base_dir != NULL && base_dir[strlen (base_dir)-1] != '/')
1476     {
1477       p = malloc (strlen (base_dir) + 2);
1478       strcpy (p, base_dir);
1479       strcat (p, "/");
1480       free (base_dir);
1481       base_dir = p;
1482     }
1483   if (dest_dir != NULL && dest_dir[strlen (dest_dir)-1] != '/')
1484     {
1485       p = malloc (strlen (dest_dir) + 2);
1486       strcpy (p, dest_dir);
1487       strcat (p, "/");
1488       free (dest_dir);
1489       dest_dir = p;
1490     }
1491   
1492   if (list_file != NULL)
1493     {
1494       list_file_fd = open (list_file, O_WRONLY|O_CREAT|O_APPEND, 0644);
1495     }
1496   
1497   file = args[0];
1498
1499   if (elf_version(EV_CURRENT) == EV_NONE)
1500     {
1501       fprintf (stderr, "library out of date\n");
1502       exit (1);
1503     }
1504
1505   if (stat(file, &stat_buf) < 0)
1506     {
1507       fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno));
1508       exit (1);
1509     }
1510
1511   /* Make sure we can read and write */
1512   chmod (file, stat_buf.st_mode | S_IRUSR | S_IWUSR);
1513
1514   fd = open (file, O_RDWR);
1515   if (fd < 0)
1516     {
1517       fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno));
1518       exit (1);
1519     }
1520
1521   dso = fdopen_dso (fd, file);
1522   if (dso == NULL)
1523     exit (1);
1524
1525   for (i = 1; i < dso->ehdr.e_shnum; i++)
1526     {
1527       const char *name;
1528       
1529       switch (dso->shdr[i].sh_type)
1530         {
1531         case SHT_PROGBITS:
1532           name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
1533           /* TODO: Handle stabs */
1534 #if 0
1535           if (strcmp (name, ".stab") == 0)
1536             edit_stabs (dso, i);
1537 #endif
1538           if (strcmp (name, ".debug_info") == 0)
1539             edit_dwarf2 (dso);
1540
1541           break;
1542         case SHT_NOTE:
1543           if (do_build_id
1544               && build_id == NULL && (dso->shdr[i].sh_flags & SHF_ALLOC))
1545             {
1546               /* Look for a build-ID note here.  */
1547               Elf_Data *data = elf_rawdata (elf_getscn (dso->elf, i), NULL);
1548               Elf32_Nhdr nh;
1549               Elf_Data dst =
1550                 {
1551                   .d_version = EV_CURRENT, .d_type = ELF_T_NHDR,
1552                   .d_buf = &nh, .d_size = sizeof nh
1553                 };
1554               Elf_Data src = dst;
1555               src.d_buf = data->d_buf;
1556               assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
1557               while ((char *) data->d_buf + data->d_size - 
1558                      (char *) src.d_buf > (int) sizeof nh
1559                      && elf32_xlatetom (&dst, &src, dso->ehdr.e_ident[EI_DATA]))
1560                 {
1561                   Elf32_Word len = sizeof nh + nh.n_namesz;
1562                   len = (len + 3) & ~3;
1563
1564                   if (nh.n_namesz == sizeof "GNU" && nh.n_type == 3
1565                       && !memcmp ((char *) src.d_buf + sizeof nh, "GNU", sizeof "GNU"))
1566                     {
1567                       build_id = data;
1568                       build_id_offset = (char *) src.d_buf + len - 
1569                                         (char *) data->d_buf;
1570                       build_id_size = nh.n_descsz;
1571                       break;
1572                     }
1573
1574                   len += nh.n_descsz;
1575                   len = (len + 3) & ~3;
1576                   src.d_buf = (char *) src.d_buf + len;
1577                 }
1578             }
1579           break;
1580         default:
1581           break;
1582         }
1583     }
1584
1585   if (do_build_id && build_id != NULL)
1586     handle_build_id (dso, build_id, build_id_offset, build_id_size);
1587
1588   if (elf_update (dso->elf, ELF_C_WRITE) < 0)
1589     {
1590       fprintf (stderr, "Failed to write file: %s\n", elf_errmsg (elf_errno()));
1591       exit (1);
1592     }
1593   if (elf_end (dso->elf) < 0)
1594     {
1595       fprintf (stderr, "elf_end failed: %s\n", elf_errmsg (elf_errno()));
1596       exit (1);
1597     }
1598   close (fd);
1599
1600   /* Restore old access rights */
1601   chmod (file, stat_buf.st_mode);
1602   
1603   poptFreeContext (optCon);
1604
1605   return 0;
1606 }