From faf4d19ddeaca1e7fd97b025ccd376eaa3afb30a Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 11 Aug 2005 05:12:05 +0000 Subject: [PATCH] Change addr2line to use dwfl_* functions. Minor strip cleanups. --- NEWS | 2 + src/ChangeLog | 16 ++++ src/Makefile.am | 6 +- src/addr2line.c | 250 +++++++++++++++++++----------------------------- src/strip.c | 75 ++++++--------- 5 files changed, 146 insertions(+), 203 deletions(-) diff --git a/NEWS b/NEWS index 5111a4811..803b6058e 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ elflint: relax a bit. Allow version definitions for defined symbols against DSO versions also for symbols in nobits sections. Allow .rodata section to have STRINGS and MERGE flag set. +strip: add some more compatibility with binutils. + Version 0.112: elfcmp: some more relaxation. diff --git a/src/ChangeLog b/src/ChangeLog index 6c7040de0..7aae3f98a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,6 +1,22 @@ +2005-07-28 Roland McGrath + + * addr2line.c (options, parse_opt): Don't handle -e here. + (executable): Variable removed. + (argp_children): New static variable. + (argp): Use it. Make const. + (main): Fill in argp_children from dwfl_standard_argp (). + Let libdwfl handle file selection, pass Dwfl handle to handle_address. + (print_dwarf_function): New function. Try to figure out inline chain. + (elf_getname): Function removed, libdwfl does it for us. + (handle_address): Take Dwfl handle instead of Elf, Dwarf handles. + Use dwfl_module_addrname instead of elf_getname. + Use dwfl_module_getsrc and dwfl_lineinfo instead of libdw calls. + * Makefile.am (INCLUDES): Add libdwfl directory to path. + 2005-08-10 Ulrich Drepper * strip.c (parse_opt): STATE parameter is now used. + Various little cleanups. * readelf.c (print_debug_line_section): Correct fallout of renaming of DW_LNS_set_epilog_begin. diff --git a/src/Makefile.am b/src/Makefile.am index 73c82dc68..3f1c75626 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,9 @@ AM_CFLAGS += -Wall -Wshadow -std=gnu99 $(native_ld_cflags) \ $(if $($(*F)_no_Wunused),,-Wunused -Wextra) \ $(if $($(*F)_no_Wformat),,-Wformat=2) -INCLUDES = -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl -I$(srcdir)/../lib -I$(srcdir)/../libdw -I.. +INCLUDES = -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl \ + -I$(srcdir)/../libdw -I$(srcdir)/../libdwfl \ + -I$(srcdir)/../lib -I.. YACC = @YACC@ -d AM_YFLAGS = -pld @@ -90,7 +92,7 @@ endif ld_LDFLAGS = -rdynamic elflint_LDADD = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl findtextrel_LDADD = $(libdw) $(libelf) $(libmudflap) -addr2line_LDADD = $(libdw) $(libelf) $(libmudflap) +addr2line_LDADD = $(libdw) $(libmudflap) elfcmp_LDADD = $(libebl) $(libelf) $(libmudflap) -ldl objdump_LDADD = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl diff --git a/src/addr2line.c b/src/addr2line.c index 60fcdf639..97eaed10c 100644 --- a/src/addr2line.c +++ b/src/addr2line.c @@ -21,9 +21,9 @@ #include #include #include -#include #include -#include +#include +#include #include #include #include @@ -49,9 +49,6 @@ const char *argp_program_bug_address = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = { - { NULL, 0, NULL, 0, N_("Input Selection:"), 0 }, - { "exe", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 }, - { NULL, 0, NULL, 0, N_("Output Selection:"), 0 }, { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 }, { "functions", 'f', NULL, 0, N_("Additional show function names"), 0 }, @@ -74,19 +71,18 @@ static const char args_doc[] = N_("[ADDR...]"); /* Prototype for option handler. */ static error_t parse_opt (int key, char *arg, struct argp_state *state); +static struct argp_child argp_children[2]; /* [0] is set in main. */ + /* Data structure to communicate with argp functions. */ -static struct argp argp = +static const struct argp argp = { - options, parse_opt, args_doc, doc, NULL, NULL, NULL + options, parse_opt, args_doc, doc, argp_children, NULL, NULL }; /* Handle ADDR. */ -static void handle_address (GElf_Addr addr, Elf *elf, Dwarf *dw); - +static void handle_address (GElf_Addr addr, Dwfl *dwfl); -/* Name of the executable. */ -static const char *executable = "a.out"; /* True if only base names of files should be shown. */ static bool only_basenames; @@ -116,55 +112,11 @@ main (int argc, char *argv[]) /* Initialize the message catalog. */ (void) textdomain (PACKAGE); - /* Parse and process arguments. */ - (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); - - /* Tell the library which version we are expecting. */ - elf_version (EV_CURRENT); - - /* Open the file. */ - int fd = open64 (executable, O_RDONLY); - if (fd == -1) - error (1, errno, gettext ("cannot open '%s'"), executable); - - /* Create the ELF descriptor. */ - Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); - if (elf == NULL) - { - close (fd); - error (1, 0, gettext ("cannot create ELF descriptor: %s"), - elf_errmsg (-1)); - } - - /* Try to get a DWARF descriptor. If it fails, we try to locate the - debuginfo file. */ - Dwarf *dw = dwarf_begin_elf (elf, DWARF_C_READ, NULL); - int fd2 = -1; - Elf *elf2 = NULL; - if (dw == NULL) - { - char *canon = canonicalize_file_name (executable); - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); - - if (canon != NULL && ehdr != NULL) - { - const char *debuginfo_dir; - if (ehdr->e_ident[EI_CLASS] == ELFCLASS32 - || ehdr->e_machine == EM_IA_64 || ehdr->e_machine == EM_ALPHA) - debuginfo_dir = "/usr/lib/debug"; - else - debuginfo_dir = "/usr/lib64/debug"; - - char *difname = alloca (strlen (debuginfo_dir) + strlen (canon) + 1); - strcpy (stpcpy (difname, debuginfo_dir), canon); - fd2 = open64 (difname, O_RDONLY); - if (fd2 != -1) - dw = dwarf_begin_elf (elf2, DWARF_C_READ, NULL); - } - - free (canon); - } + /* Parse and process arguments. This includes opening the modules. */ + argp_children[0].argp = dwfl_standard_argp (); + Dwfl *dwfl = NULL; + (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl); + assert (dwfl != NULL); /* Now handle the addresses. In case none are given on the command line, read from stdin. */ @@ -183,7 +135,7 @@ main (int argc, char *argv[]) char *endp; uintmax_t addr = strtoumax (buf, &endp, 0); if (endp != buf) - handle_address (addr, elf2 ?: elf, dw); + handle_address (addr, dwfl); else result = 1; } @@ -197,7 +149,7 @@ main (int argc, char *argv[]) char *endp; uintmax_t addr = strtoumax (argv[remaining], &endp, 0); if (endp != argv[remaining]) - handle_address (addr, elf2 ?: elf, dw); + handle_address (addr, dwfl); else result = 1; } @@ -224,21 +176,21 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ /* Handle program arguments. */ static error_t -parse_opt (int key, char *arg, - struct argp_state *state __attribute__ ((unused))) +parse_opt (int key, char *arg __attribute__ ((unused)), + struct argp_state *state) { switch (key) { + case ARGP_KEY_INIT: + state->child_inputs[0] = state->input; + break; + case 'b': case 'C': case OPT_DEMANGLER: /* Ignored for compatibility. */ break; - case 'e': - executable = arg; - break; - case 's': only_basenames = true; break; @@ -254,118 +206,108 @@ parse_opt (int key, char *arg, } -struct func_arg -{ - GElf_Addr addr; - const char *name; -}; - - -static int -match_func (Dwarf_Func *func, void *arg) +static const char * +dwarf_diename_integrate (Dwarf_Die *die) { - struct func_arg *func_arg = (struct func_arg *) arg; - Dwarf_Addr addr; - - if (dwarf_func_lowpc (func, &addr) == 0 && addr <= func_arg->addr - && dwarf_func_highpc (func, &addr) == 0 && func_arg->addr < addr) - { - func_arg->name = dwarf_func_name (func); - return DWARF_CB_ABORT; - } - - return DWARF_CB_OK; + Dwarf_Attribute attr_mem; + return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); } - -static const char * -elf_getname (GElf_Addr addr, Elf *elf) +static bool +print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr) { - /* The DWARF information is not available. Use the ELF - symbol table. */ - Elf_Scn *scn = NULL; - Elf_Scn *dynscn = NULL; - - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr != NULL) + Dwarf_Addr bias = 0; + Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias); + + Dwarf_Die *scopes; + int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes); + if (nscopes <= 0) + return false; + + for (int i = 0; i < nscopes; ++i) + switch (dwarf_tag (&scopes[i])) + { + case DW_TAG_subprogram: { - if (shdr->sh_type == SHT_SYMTAB) - break; - if (shdr->sh_type == SHT_DYNSYM) - dynscn = scn; + const char *name = dwarf_diename_integrate (&scopes[i]); + if (name == NULL) + return false; + puts (name); + return true; } - } - if (scn == NULL) - scn = dynscn; - if (scn != NULL) - { - /* Look through the symbol table for a matching symbol. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - assert (shdr != NULL); - - Elf_Data *data = elf_getdata (scn, NULL); - if (data != NULL) - for (int cnt = 1; cnt < (int) (shdr->sh_size / shdr->sh_entsize); - ++cnt) - { - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (data, cnt, &sym_mem); - if (sym != NULL - && sym->st_value <= addr - && addr < sym->st_value + sym->st_size) - return elf_strptr (elf, shdr->sh_link, sym->st_name); - } - } + case DW_TAG_inlined_subroutine: + { + const char *name = dwarf_diename_integrate (&scopes[i]); + if (name == NULL) + return false; + printf ("%s inlined", name); + + Dwarf_Files *files; + if (dwarf_getsrcfiles (cudie, &files, NULL) == 0) + { + Dwarf_Attribute attr_mem; + Dwarf_Word val; + if (dwarf_formudata (dwarf_attr (&scopes[i], + DW_AT_call_file, + &attr_mem), &val) == 0) + { + const char *file = dwarf_filesrc (files, val, NULL, NULL); + int lineno = 0, colno = 0; + if (dwarf_formudata (dwarf_attr (&scopes[i], + DW_AT_call_line, + &attr_mem), &val) == 0) + lineno = val; + if (dwarf_formudata (dwarf_attr (&scopes[i], + DW_AT_call_column, + &attr_mem), &val) == 0) + colno = val; + if (lineno == 0) + { + if (file != NULL) + printf (" from %s", file); + } + else if (colno == 0) + printf (" at %s:%u", file, lineno); + else + printf (" at %s:%u:%u", file, lineno, colno); + } + } + printf (" in "); + continue; + } + } - return NULL; + return false; } - static void -handle_address (GElf_Addr addr, Elf *elf, Dwarf *dw) +handle_address (GElf_Addr addr, Dwfl *dwfl) { - Dwarf_Die die_mem; - Dwarf_Die *die = dwarf_addrdie (dw, addr, &die_mem); + Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr); if (show_functions) { /* First determine the function name. Use the DWARF information if possible. */ - struct func_arg arg; - arg.addr = addr; - arg.name = NULL; - - if (dwarf_getfuncs (die, match_func, &arg, 0) <= 0) - arg.name = elf_getname (addr, elf); - - puts (arg.name ?: "??"); + if (! print_dwarf_function (mod, addr)) + puts (dwfl_module_addrname (mod, addr) ?: "??"); } + Dwfl_Line *line = dwfl_module_getsrc (mod, addr); - Dwarf_Line *line; const char *src; - if ((line = dwarf_getsrc_die (die, addr)) != NULL - && (src = dwarf_linesrc (line, NULL, NULL)) != NULL) + int lineno, linecol; + if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol, + NULL, NULL)) != NULL) { if (only_basenames) src = basename (src); - int lineno; - if (dwarf_lineno (line, &lineno) != -1) - { - int linecol; - if (dwarf_linecol (line, &linecol) != -1 && linecol != 0) - printf ("%s:%d:%d\n", src, lineno, linecol); - else - printf ("%s:%d\n", src, lineno); - } + if (linecol != 0) + printf ("%s:%d:%d\n", src, lineno, linecol); else - printf ("%s:0\n", src); + printf ("%s:%d\n", src, lineno); } else puts ("??:0"); diff --git a/src/strip.c b/src/strip.c index aefea9382..42e13b46b 100644 --- a/src/strip.c +++ b/src/strip.c @@ -368,14 +368,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, size_t fname_len = strlen (fname) + 1; char *fullname = alloca (prefix_len + 1 + fname_len); char *cp = fullname; - Elf *newelf; Elf *debugelf = NULL; char *tmp_debug_fname = NULL; int result = 0; - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr; size_t shstrndx; - size_t shnum; struct shdr_info { Elf_Scn *scn; @@ -461,7 +457,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, } /* Get the information from the old file. */ - ehdr = gelf_getehdr (elf, &ehdr_mem); + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); if (ehdr == NULL) INTERNAL_ERROR (fname); @@ -473,6 +470,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* We now create a new ELF descriptor for the same file. We construct it almost exactly in the same way with some information dropped. */ + Elf *newelf; if (output_fname != NULL) newelf = elf_begin (fd, ELF_C_WRITE_MMAP, NULL); else @@ -492,9 +490,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) { GElf_Phdr phdr_mem; - GElf_Phdr *phdr; - - phdr = gelf_getphdr (elf, cnt, &phdr_mem); + GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem); if (phdr == NULL || unlikely (gelf_update_phdr (newelf, cnt, phdr) == 0)) INTERNAL_ERROR (fname); @@ -518,9 +514,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) { GElf_Phdr phdr_mem; - GElf_Phdr *phdr; - - phdr = gelf_getphdr (elf, cnt, &phdr_mem); + GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem); if (phdr == NULL || unlikely (gelf_update_phdr (debugelf, cnt, phdr) == 0)) INTERNAL_ERROR (fname); @@ -528,6 +522,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, } /* Number of sections. */ + size_t shnum; if (unlikely (elf_getshnum (elf, &shnum) < 0)) { error (0, 0, gettext ("cannot determine number of sections: %s"), @@ -595,9 +590,6 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, } else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GROUP)) { - Elf32_Word *grpref; - size_t inner; - /* Cross-reference the sections contained in the section group. */ shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL); @@ -605,7 +597,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, INTERNAL_ERROR (fname); /* XXX Fix for unaligned access. */ - grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; + Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; + size_t inner; for (inner = 1; inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); ++inner) @@ -664,16 +657,14 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, idx = shdr_info[cnt].group_idx; while (idx != 0) { - /* If the references section group is a normal section - group and has one element remaining, or if it is an - empty COMDAT section group it is removed. */ - bool is_comdat; - /* The section group data is already loaded. */ assert (shdr_info[idx].data != NULL); - is_comdat = (((Elf32_Word *) shdr_info[idx].data->d_buf)[0] - & GRP_COMDAT) != 0; + /* If the references section group is a normal section + group and has one element remaining, or if it is an + empty COMDAT section group it is removed. */ + bool is_comdat = (((Elf32_Word *) shdr_info[idx].data->d_buf)[0] + & GRP_COMDAT) != 0; --shdr_info[idx].group_cnt; if ((!is_comdat && shdr_info[idx].group_cnt == 1) @@ -719,10 +710,6 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) { - Elf_Data *symdata; - Elf_Data *xndxdata; - size_t elsize; - /* Make sure the data is loaded. */ if (shdr_info[cnt].data == NULL) { @@ -731,7 +718,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (shdr_info[cnt].data == NULL) INTERNAL_ERROR (fname); } - symdata = shdr_info[cnt].data; + Elf_Data *symdata = shdr_info[cnt].data; /* If there is an extended section index table load it as well. */ @@ -746,11 +733,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (shdr_info[shdr_info[cnt].symtab_idx].data == NULL) INTERNAL_ERROR (fname); } - xndxdata = shdr_info[shdr_info[cnt].symtab_idx].data; + Elf_Data *xndxdata + = shdr_info[shdr_info[cnt].symtab_idx].data; /* Go through all symbols and make sure the section they reference is not removed. */ - elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); + size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, + ehdr->e_version); for (size_t inner = 0; inner < shdr_info[cnt].data->d_size / elsize; @@ -758,15 +747,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, { GElf_Sym sym_mem; Elf32_Word xndx; - GElf_Sym *sym; - size_t scnidx; - - sym = gelf_getsymshndx (symdata, xndxdata, inner, - &sym_mem, &xndx); + GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata, + inner, &sym_mem, + &xndx); if (sym == NULL) INTERNAL_ERROR (fname); - scnidx = sym->st_shndx; + size_t scnidx = sym->st_shndx; if (scnidx == SHN_UNDEF || scnidx >= shnum || (scnidx >= SHN_LORESERVE && scnidx <= SHN_HIRESERVE @@ -829,20 +816,17 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, { for (cnt = 1; cnt < shnum; ++cnt) { - Elf_Data *debugdata; - GElf_Shdr debugshdr; - bool discard_section; - scn = elf_newscn (debugelf); if (scn == NULL) error (EXIT_FAILURE, 0, gettext ("while generating output file: %s"), elf_errmsg (-1)); - discard_section = shdr_info[cnt].idx > 0 && cnt != ehdr->e_shstrndx; + bool discard_section = (shdr_info[cnt].idx > 0 + && cnt != ehdr->e_shstrndx); /* Set the section header in the new file. */ - debugshdr = shdr_info[cnt].shdr; + GElf_Shdr debugshdr = shdr_info[cnt].shdr; if (discard_section) debugshdr.sh_type = SHT_NOBITS; @@ -859,7 +843,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, } /* Set the data. This is done by copying from the old file. */ - debugdata = elf_newdata (scn); + Elf_Data *debugdata = elf_newdata (scn); if (debugdata == NULL) INTERNAL_ERROR (fname); @@ -930,9 +914,6 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Create the reference to the file with the debug info. */ if (debug_fname != NULL) { - char *debug_basename; - off_t crc_offset; - /* Add the section header string table section name. */ shdr_info[cnt].se = ebl_strtabadd (shst, ".gnu_debuglink", 15); shdr_info[cnt].idx = idx++; @@ -963,8 +944,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"), elf_errmsg (-1)); - debug_basename = basename (debug_fname_embed ?: debug_fname); - crc_offset = strlen (debug_basename) + 1; + char *debug_basename = basename (debug_fname_embed ?: debug_fname); + off_t crc_offset = strlen (debug_basename) + 1; /* Align to 4 byte boundary */ crc_offset = ((crc_offset - 1) & ~3) + 4; -- 2.47.2