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