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