1 /* Copyright (C) 2001, 2002 Red Hat, Inc.
2 Written by Alexander Larsson <alexl@redhat.com>, 2002
3 Based on code by Jakub Jelinek <jakub@redhat.com>, 2001.
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)
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.
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. */
28 #include <sys/types.h>
38 char *base_dir = NULL;
39 char *dest_dir = NULL;
40 char *list_file = NULL;
41 int list_file_fd = -1;
43 typedef unsigned int uint_32;
44 typedef unsigned short uint_16;
57 #define read_uleb128(ptr) ({ \
58 unsigned int ret = 0; \
64 ret |= (c & 0x7f) << shift; \
73 static uint_16 (*do_read_16) (unsigned char *ptr);
74 static uint_32 (*do_read_32) (unsigned char *ptr);
75 static void (*write_32) (unsigned char *ptr, GElf_Addr val);
80 buf_read_ule16 (unsigned char *data)
82 return data[0] | (data[1] << 8);
86 buf_read_ube16 (unsigned char *data)
88 return data[1] | (data[0] << 8);
92 buf_read_ule32 (unsigned char *data)
94 return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
98 buf_read_ube32 (unsigned char *data)
100 return data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
104 strptr (DSO *dso, int sec, off_t offset)
110 if (offset >= 0 && offset < dso->shdr[sec].sh_size)
113 while ((data = elf_getdata (scn, data)) != NULL)
116 && offset >= data->d_off
117 && offset < data->d_off + data->d_size)
118 return (const char *) data->d_buf + (offset - data->d_off);
126 #define read_1(ptr) *ptr++
128 #define read_16(ptr) ({ \
129 uint_16 ret = do_read_16 (ptr); \
134 #define read_32(ptr) ({ \
135 uint_32 ret = do_read_32 (ptr); \
141 dwarf2_write_le32 (unsigned char *p, GElf_Addr val)
143 uint_32 v = (uint_32) val;
153 dwarf2_write_be32 (unsigned char *p, GElf_Addr val)
155 uint_32 v = (uint_32) val;
173 #define DEBUG_ABBREV 1
175 #define DEBUG_ARANGES 3
176 #define DEBUG_PUBNAMES 4
177 #define DEBUG_MACINFO 5
180 #define DEBUG_FRAME 8
181 #define DEBUG_RANGES 9
182 { ".debug_info", NULL, 0, 0 },
183 { ".debug_abbrev", NULL, 0, 0 },
184 { ".debug_line", NULL, 0, 0 },
185 { ".debug_aranges", NULL, 0, 0 },
186 { ".debug_pubnames", NULL, 0, 0 },
187 { ".debug_macinfo", NULL, 0, 0 },
188 { ".debug_loc", NULL, 0, 0 },
189 { ".debug_str", NULL, 0, 0 },
190 { ".debug_frame", NULL, 0, 0 },
191 { ".debug_ranges", NULL, 0, 0 },
206 struct abbrev_attr attr[0];
210 abbrev_hash (const void *p)
212 struct abbrev_tag *t = (struct abbrev_tag *)p;
218 abbrev_eq (const void *p, const void *q)
220 struct abbrev_tag *t1 = (struct abbrev_tag *)p;
221 struct abbrev_tag *t2 = (struct abbrev_tag *)p;
223 return t1->entry == t2->entry;
233 read_abbrev (DSO *dso, unsigned char *ptr)
235 htab_t h = htab_try_create (50, abbrev_hash, abbrev_eq, abbrev_del);
236 unsigned int attr, form;
237 struct abbrev_tag *t;
244 error (0, ENOMEM, "%s: Could not read .debug_abbrev", dso->filename);
250 while ((attr = read_uleb128 (ptr)) != 0)
253 t = malloc (sizeof (*t) + size * sizeof (struct abbrev_attr));
258 slot = htab_find_slot (h, t, INSERT);
266 error (0, 0, "%s: Duplicate DWARF-2 abbreviation %d", dso->filename,
272 t->tag = read_uleb128 (ptr);
273 ++ptr; /* skip children flag. */
274 while ((attr = read_uleb128 (ptr)) != 0)
276 if (t->nattr == size)
279 t = realloc (t, sizeof (*t) + size * sizeof (struct abbrev_attr));
283 form = read_uleb128 (ptr);
284 if (form == 2 || form > DW_FORM_indirect)
286 error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename, form);
291 t->attr[t->nattr].attr = attr;
292 t->attr[t->nattr++].form = form;
294 if (read_uleb128 (ptr) != 0)
296 error (0, 0, "%s: DWARF-2 abbreviation does not end with 2 zeros",
307 #define IS_DIR_SEPARATOR(c) ((c)=='/')
310 canonicalize_path (char *s, char *d)
318 if (IS_DIR_SEPARATOR (*s))
321 if (IS_DIR_SEPARATOR (*s) && !IS_DIR_SEPARATOR (s[1]))
323 /* Special case for "//foo" meaning a Posix namespace
327 while (IS_DIR_SEPARATOR (*s))
335 /* At this point, we're always at the beginning of a path
338 if (s[0] == '.' && (s[1] == 0 || IS_DIR_SEPARATOR (s[1])))
347 else if (s[0] == '.' && s[1] == '.'
348 && (s[2] == 0 || IS_DIR_SEPARATOR (s[2])))
350 char *pre = d-1; /* includes slash */
351 while (droot < pre && IS_DIR_SEPARATOR (*pre))
353 if (droot <= pre && ! IS_DIR_SEPARATOR (*pre))
356 while (droot < d && ! IS_DIR_SEPARATOR (*d))
358 /* d now points to the slash */
378 while (*s && ! IS_DIR_SEPARATOR (*s))
382 if (IS_DIR_SEPARATOR (*s))
385 while (IS_DIR_SEPARATOR (*s))
389 while (droot < d && IS_DIR_SEPARATOR (d[-1]))
399 has_prefix (const char *str,
405 str_len = strlen (str);
406 prefix_len = strlen (prefix);
408 if (str_len < prefix_len)
411 return strncmp (str, prefix, prefix_len) == 0;
415 edit_dwarf2_line (DSO *dso, uint_32 off, char *comp_dir, int phase)
417 unsigned char *ptr = debug_sections[DEBUG_LINE].data;
418 unsigned char *endsec = ptr + debug_sections[DEBUG_LINE].size;
419 unsigned char *endcu, *endprol;
420 unsigned char opcode_base;
432 endcu += read_32 (ptr);
433 if (endcu == ptr + 0xffffffff)
435 error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
441 error (0, 0, "%s: .debug_line CU does not fit into section",
446 value = read_16 (ptr);
449 error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
455 endprol += read_32 (ptr);
458 error (0, 0, "%s: .debug_line CU prologue does not fit into CU",
463 opcode_base = ptr[4];
464 ptr = ptr + 4 + opcode_base;
469 ptr = strchr(ptr, 0) + 1;
483 s = malloc (strlen (comp_dir) + 1 + strlen (ptr) + 1);
484 strcpy (s, comp_dir);
487 canonicalize_path (s, s);
489 if (base_dir == NULL ||
490 has_prefix (s, base_dir))
496 p = s + strlen (base_dir);
500 if (list_file_fd != -1)
502 size = strlen (p) + 1;
505 ret = write (list_file_fd, p, size);
518 ptr = strchr(ptr, 0) + 1;
529 static unsigned char *
530 edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase)
535 unsigned char *comp_dir;
540 for (i = 0; i < t->nattr; ++i)
542 uint_32 form = t->attr[i].form;
544 int base_len, dest_len;
549 if (t->attr[i].attr == DW_AT_stmt_list)
551 if (form == DW_FORM_data4)
553 list_offs = do_read_32 (ptr);
558 if (debug_sections[DEBUG_STR].data &&
559 t->attr[i].attr == DW_AT_comp_dir &&
560 form == DW_FORM_strp)
564 dir = debug_sections[DEBUG_STR].data + do_read_32 (ptr);
565 comp_dir = strdup (dir);
567 if (phase == 1 && dest_dir && has_prefix (dir, base_dir))
569 base_len = strlen (base_dir);
570 dest_len = strlen (dest_dir);
572 memcpy (dir, dest_dir, dest_len);
573 if (dest_len < base_len)
575 memcpy (dir + dest_len, dir + base_len,
576 strlen (dir + base_len) + 1);
578 elf_flagdata (debug_sections[DEBUG_STR].elf_data, ELF_C_SET,
606 case DW_FORM_ref_udata:
610 case DW_FORM_ref_addr:
615 ptr = strchr (ptr, '\0') + 1;
617 case DW_FORM_indirect:
618 form = read_uleb128 (ptr);
625 form = DW_FORM_block1;
629 form = DW_FORM_block1;
632 len = read_uleb128 (ptr);
633 form = DW_FORM_block1;
634 assert (len < UINT_MAX);
637 error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename,
642 if (form == DW_FORM_block1)
648 if (found_list_offs && comp_dir)
649 edit_dwarf2_line (dso, list_offs, comp_dir, phase);
655 edit_dwarf2 (DSO *dso, int n)
661 for (i = 0; debug_sections[i].name; ++i)
663 debug_sections[i].data = NULL;
664 debug_sections[i].size = 0;
665 debug_sections[i].sec = 0;
669 for (i = 1; i < dso->ehdr.e_shnum; ++i)
670 if (! (dso->shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR))
671 && dso->shdr[i].sh_size)
673 const char *name = strptr (dso, dso->ehdr.e_shstrndx,
674 dso->shdr[i].sh_name);
676 if (strncmp (name, ".debug_", sizeof (".debug_") - 1) == 0)
678 for (j = 0; debug_sections[j].name; ++j)
679 if (strcmp (name, debug_sections[j].name) == 0)
681 if (debug_sections[j].data)
683 error (0, 0, "%s: Found two copies of %s section",
684 dso->filename, name);
689 data = elf_getdata (scn, NULL);
690 assert (data != NULL && data->d_buf != NULL);
691 assert (elf_getdata (scn, data) == NULL);
692 assert (data->d_off == 0);
693 assert (data->d_size == dso->shdr[i].sh_size);
694 debug_sections[j].data = data->d_buf;
695 debug_sections[j].elf_data = data;
696 debug_sections[j].size = data->d_size;
697 debug_sections[j].sec = i;
701 if (debug_sections[j].name == NULL)
703 error (0, 0, "%s: Unknown debugging section %s",
704 dso->filename, name);
709 if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
711 do_read_16 = buf_read_ule16;
712 do_read_32 = buf_read_ule32;
713 write_32 = dwarf2_write_le32;
715 else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
717 do_read_16 = buf_read_ube16;
718 do_read_32 = buf_read_ube32;
719 write_32 = dwarf2_write_be32;
723 error (0, 0, "%s: Wrong ELF data enconding", dso->filename);
727 if (debug_sections[DEBUG_INFO].data != NULL)
729 unsigned char *ptr, *endcu, *endsec;
732 struct abbrev_tag tag, *t;
735 for (phase = 0; phase < 2; phase++)
737 ptr = debug_sections[DEBUG_INFO].data;
738 endsec = ptr + debug_sections[DEBUG_INFO].size;
741 if (ptr + 11 > endsec)
743 error (0, 0, "%s: .debug_info CU header too small",
749 endcu += read_32 (ptr);
750 if (endcu == ptr + 0xffffffff)
752 error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
758 error (0, 0, "%s: .debug_info too small", dso->filename);
762 value = read_16 (ptr);
765 error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
770 value = read_32 (ptr);
771 if (value >= debug_sections[DEBUG_ABBREV].size)
773 if (debug_sections[DEBUG_ABBREV].data == NULL)
774 error (0, 0, "%s: .debug_abbrev not present", dso->filename);
776 error (0, 0, "%s: DWARF-2 CU abbrev offset too large",
783 ptr_size = read_1 (ptr);
784 if (ptr_size != 4 && ptr_size != 8)
786 error (0, 0, "%s: Invalid DWARF-2 pointer size %d",
787 dso->filename, ptr_size);
791 else if (read_1 (ptr) != ptr_size)
793 error (0, 0, "%s: DWARF-2 pointer size differs between CUs",
798 abbrev = read_abbrev (dso,
799 debug_sections[DEBUG_ABBREV].data + value);
805 tag.entry = read_uleb128 (ptr);
808 t = htab_find_with_hash (abbrev, &tag, tag.entry);
811 error (0, 0, "%s: Could not find DWARF-2 abbreviation %d",
812 dso->filename, tag.entry);
813 htab_delete (abbrev);
817 ptr = edit_attributes (dso, ptr, t, phase);
822 htab_delete (abbrev);
827 elf_flagscn (dso->scn[n], ELF_C_SET, ELF_F_DIRTY);
831 static struct poptOption optionsTable[] = {
832 { "base-dir", 'b', POPT_ARG_STRING, &base_dir, 0,
833 "base build directory of objects", NULL },
834 { "dest-dir", 'd', POPT_ARG_STRING, &dest_dir, 0,
835 "directory to rewrite base-dir into", NULL },
836 { "list-file", 'l', POPT_ARG_STRING, &list_file, 0,
837 "directory to rewrite base-dir into", NULL },
839 { NULL, 0, 0, NULL, 0 }
843 fdopen_dso (int fd, const char *name)
850 static int section_cmp (const void *A, const void *B)
855 if (dso->shdr[*a].sh_offset < dso->shdr[*b].sh_offset)
857 if (dso->shdr[*a].sh_offset > dso->shdr[*b].sh_offset)
864 elf = elf_begin (fd, ELF_C_RDWR, NULL);
867 error (0, 0, "cannot open ELF file: %s", elf_errmsg (-1));
871 if (elf_kind (elf) != ELF_K_ELF)
873 error (0, 0, "\"%s\" is not an ELF file", name);
877 if (gelf_getehdr (elf, &ehdr) == NULL)
879 error (0, 0, "cannot get the ELF header: %s",
884 if (ehdr.e_type != ET_DYN && ehdr.e_type != ET_EXEC)
886 error (0, 0, "\"%s\" is not a shared library", name);
890 /* Allocate DSO structure. Leave place for additional 20 new section
893 malloc (sizeof(DSO) + (ehdr.e_shnum + 20) * sizeof(GElf_Shdr)
894 + (ehdr.e_phnum + 1) * sizeof(GElf_Phdr)
895 + (ehdr.e_shnum + 20) * sizeof(Elf_Scn *));
898 error (0, ENOMEM, "Could not open DSO");
902 elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT);
904 memset (dso, 0, sizeof(DSO));
907 dso->phdr = (GElf_Phdr *) &dso->shdr[ehdr.e_shnum + 20];
908 dso->scn = (Elf_Scn **) &dso->phdr[ehdr.e_phnum + 1];
909 for (i = 0; i < ehdr.e_phnum; ++i)
910 gelf_getphdr (elf, i, dso->phdr + i);
912 for (i = 0; i < ehdr.e_shnum; ++i)
914 dso->scn[i] = elf_getscn (elf, i);
915 gelf_getshdr (dso->scn[i], dso->shdr + i);
918 dso->filename = (const char *) strdup (name);
924 free ((char *) dso->filename);
936 main (int argc, char *argv[])
941 poptContext optCon; /* context for parsing command-line options */
946 optCon = poptGetContext("debugedit", argc, (const char **)argv,
949 while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT)
954 fprintf (stderr, "Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n",
955 poptBadOption (optCon, 0),
956 poptStrerror (nextopt),
961 args = poptGetArgs (optCon);
962 if (args == NULL || args[0] == NULL || args[1] != NULL)
964 poptPrintHelp(optCon, stdout, 0);
968 if (dest_dir != NULL)
970 if (base_dir == NULL)
972 fprintf (stderr, "You must specify a base dir if you specify a dest dir\n");
975 if (strlen (dest_dir) > strlen (base_dir))
977 fprintf (stderr, "Only dest dir longer than base dir not supported\n");
982 /* Make sure there are trailing slashes in dirs */
983 if (base_dir != NULL && base_dir[strlen (base_dir)-1] != '/')
985 p = malloc (strlen (base_dir) + 2);
986 strcpy (p, base_dir);
991 if (dest_dir != NULL && dest_dir[strlen (dest_dir)-1] != '/')
993 p = malloc (strlen (dest_dir) + 2);
994 strcpy (p, dest_dir);
1000 if (list_file != NULL)
1002 list_file_fd = open (list_file, O_WRONLY|O_CREAT|O_APPEND, 0644);
1007 if (elf_version(EV_CURRENT) == EV_NONE)
1009 fprintf (stderr, "library out of date\n");
1013 fd = open (file, O_RDWR);
1016 fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno));
1020 dso = fdopen_dso (fd, file);
1022 for (i = 1; i < dso->ehdr.e_shnum; i++)
1026 switch (dso->shdr[i].sh_type)
1029 name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
1030 /* TODO: Handle stabs */
1032 if (strcmp (name, ".stab") == 0)
1033 edit_stabs (dso, i);
1035 if (strcmp (name, ".debug_info") == 0)
1036 edit_dwarf2 (dso, i);
1044 elf_update (dso->elf, ELF_C_WRITE);
1048 poptFreeContext (optCon);