From ce4550aefd57ab68f6f279a5b662eb1716d7b361 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 10 Aug 2005 08:10:07 +0000 Subject: [PATCH] Update DW_LNS_set_epilogue_begin uses to correct misspelling. --- NEWS | 4 +- libdw/ChangeLog | 6 +- src/ChangeLog | 26 +---- src/Makefile.am | 6 +- src/addr2line.c | 250 +++++++++++++++++++++++++++++------------------- src/strip.c | 78 +++++++++------ 6 files changed, 213 insertions(+), 157 deletions(-) diff --git a/NEWS b/NEWS index 803b6058e..d03953abc 100644 --- a/NEWS +++ b/NEWS @@ -4,8 +4,6 @@ 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. @@ -29,7 +27,7 @@ elfcmp: little usability tweak, name and index of differing section is printed. Version 0.110: -libelf: fix a number of problems with elf_update +libelf: fix a numbe rof problems with elf_update elfcmp: fix a few bugs. Compare gaps. diff --git a/libdw/ChangeLog b/libdw/ChangeLog index c5d1503c7..010deda6b 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,7 +1,7 @@ -2005-08-10 Ulrich Drepper +2005-08-10 Roland McGrath - * dwarf_getsrclines.c (dwarf_getsrclines): Correct fallout of renaming - of DW_LNS_set_epilog_begin. + * dwarf_getsrclines.c (dwarf_getsrclines): Update + DW_LNS_set_epilogue_begin use to correct misspelling. 2005-08-09 Roland McGrath diff --git a/src/ChangeLog b/src/ChangeLog index 7aae3f98a..701c2196a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,25 +1,7 @@ -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. +2005-08-10 Roland McGrath + + * readelf.c (print_debug_line_section): Update + DW_LNS_set_epilogue_begin use to correct misspelling. 2005-08-08 Roland McGrath diff --git a/src/Makefile.am b/src/Makefile.am index 3f1c75626..73c82dc68 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,9 +24,7 @@ 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)/../libdw -I$(srcdir)/../libdwfl \ - -I$(srcdir)/../lib -I.. +INCLUDES = -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl -I$(srcdir)/../lib -I$(srcdir)/../libdw -I.. YACC = @YACC@ -d AM_YFLAGS = -pld @@ -92,7 +90,7 @@ endif ld_LDFLAGS = -rdynamic elflint_LDADD = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl findtextrel_LDADD = $(libdw) $(libelf) $(libmudflap) -addr2line_LDADD = $(libdw) $(libmudflap) +addr2line_LDADD = $(libdw) $(libelf) $(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 97eaed10c..60fcdf639 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,6 +49,9 @@ 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 }, @@ -71,18 +74,19 @@ 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 const struct argp argp = +static struct argp argp = { - options, parse_opt, args_doc, doc, argp_children, NULL, NULL + options, parse_opt, args_doc, doc, NULL, NULL, NULL }; /* Handle ADDR. */ -static void handle_address (GElf_Addr addr, Dwfl *dwfl); +static void handle_address (GElf_Addr addr, Elf *elf, Dwarf *dw); + +/* Name of the executable. */ +static const char *executable = "a.out"; /* True if only base names of files should be shown. */ static bool only_basenames; @@ -112,11 +116,55 @@ main (int argc, char *argv[]) /* Initialize the message catalog. */ (void) textdomain (PACKAGE); - /* 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); + /* 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); + } /* Now handle the addresses. In case none are given on the command line, read from stdin. */ @@ -135,7 +183,7 @@ main (int argc, char *argv[]) char *endp; uintmax_t addr = strtoumax (buf, &endp, 0); if (endp != buf) - handle_address (addr, dwfl); + handle_address (addr, elf2 ?: elf, dw); else result = 1; } @@ -149,7 +197,7 @@ main (int argc, char *argv[]) char *endp; uintmax_t addr = strtoumax (argv[remaining], &endp, 0); if (endp != argv[remaining]) - handle_address (addr, dwfl); + handle_address (addr, elf2 ?: elf, dw); else result = 1; } @@ -176,21 +224,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 __attribute__ ((unused)), - struct argp_state *state) +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) { 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; @@ -206,108 +254,118 @@ parse_opt (int key, char *arg __attribute__ ((unused)), } -static const char * -dwarf_diename_integrate (Dwarf_Die *die) +struct func_arg +{ + GElf_Addr addr; + const char *name; +}; + + +static int +match_func (Dwarf_Func *func, void *arg) { - Dwarf_Attribute attr_mem; - return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); + 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; } -static bool -print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr) + +static const char * +elf_getname (GElf_Addr addr, Elf *elf) { - 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: - { - const char *name = dwarf_diename_integrate (&scopes[i]); - if (name == NULL) - return false; - puts (name); - return true; - } + /* The DWARF information is not available. Use the ELF + symbol table. */ + Elf_Scn *scn = NULL; + Elf_Scn *dynscn = NULL; - case DW_TAG_inlined_subroutine: + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL) { - 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; + if (shdr->sh_type == SHT_SYMTAB) + break; + if (shdr->sh_type == SHT_DYNSYM) + dynscn = scn; } - } + } + 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); + } + } - return false; + return NULL; } + static void -handle_address (GElf_Addr addr, Dwfl *dwfl) +handle_address (GElf_Addr addr, Elf *elf, Dwarf *dw) { - Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr); + Dwarf_Die die_mem; + Dwarf_Die *die = dwarf_addrdie (dw, addr, &die_mem); if (show_functions) { /* First determine the function name. Use the DWARF information if possible. */ - if (! print_dwarf_function (mod, addr)) - puts (dwfl_module_addrname (mod, addr) ?: "??"); + 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 ?: "??"); } - Dwfl_Line *line = dwfl_module_getsrc (mod, addr); + Dwarf_Line *line; const char *src; - int lineno, linecol; - if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol, - NULL, NULL)) != NULL) + if ((line = dwarf_getsrc_die (die, addr)) != NULL + && (src = dwarf_linesrc (line, NULL, NULL)) != NULL) { if (only_basenames) src = basename (src); - if (linecol != 0) - printf ("%s:%d:%d\n", src, lineno, linecol); + 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); + } else - printf ("%s:%d\n", src, lineno); + printf ("%s:0\n", src); } else puts ("??:0"); diff --git a/src/strip.c b/src/strip.c index 42e13b46b..37f9eb0e0 100644 --- a/src/strip.c +++ b/src/strip.c @@ -199,7 +199,8 @@ 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) +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) { switch (key) { @@ -368,10 +369,14 @@ 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; @@ -457,8 +462,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, } /* Get the information from the old file. */ - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + ehdr = gelf_getehdr (elf, &ehdr_mem); if (ehdr == NULL) INTERNAL_ERROR (fname); @@ -470,7 +474,6 @@ 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 @@ -490,7 +493,9 @@ 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 = gelf_getphdr (elf, cnt, &phdr_mem); + GElf_Phdr *phdr; + + phdr = gelf_getphdr (elf, cnt, &phdr_mem); if (phdr == NULL || unlikely (gelf_update_phdr (newelf, cnt, phdr) == 0)) INTERNAL_ERROR (fname); @@ -514,7 +519,9 @@ 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 = gelf_getphdr (elf, cnt, &phdr_mem); + GElf_Phdr *phdr; + + phdr = gelf_getphdr (elf, cnt, &phdr_mem); if (phdr == NULL || unlikely (gelf_update_phdr (debugelf, cnt, phdr) == 0)) INTERNAL_ERROR (fname); @@ -522,7 +529,6 @@ 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"), @@ -590,6 +596,9 @@ 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); @@ -597,8 +606,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, INTERNAL_ERROR (fname); /* XXX Fix for unaligned access. */ - Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; - size_t inner; + grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf; for (inner = 1; inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word); ++inner) @@ -657,14 +665,16 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, idx = shdr_info[cnt].group_idx; while (idx != 0) { - /* The section group data is already loaded. */ - assert (shdr_info[idx].data != NULL); - /* 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; + 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; --shdr_info[idx].group_cnt; if ((!is_comdat && shdr_info[idx].group_cnt == 1) @@ -710,6 +720,10 @@ 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) { @@ -718,7 +732,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (shdr_info[cnt].data == NULL) INTERNAL_ERROR (fname); } - Elf_Data *symdata = shdr_info[cnt].data; + symdata = shdr_info[cnt].data; /* If there is an extended section index table load it as well. */ @@ -733,13 +747,11 @@ 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); } - Elf_Data *xndxdata - = shdr_info[shdr_info[cnt].symtab_idx].data; + xndxdata = shdr_info[shdr_info[cnt].symtab_idx].data; /* Go through all symbols and make sure the section they reference is not removed. */ - size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, - ehdr->e_version); + elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); for (size_t inner = 0; inner < shdr_info[cnt].data->d_size / elsize; @@ -747,13 +759,15 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, { GElf_Sym sym_mem; Elf32_Word xndx; - GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata, - inner, &sym_mem, - &xndx); + GElf_Sym *sym; + size_t scnidx; + + sym = gelf_getsymshndx (symdata, xndxdata, inner, + &sym_mem, &xndx); if (sym == NULL) INTERNAL_ERROR (fname); - size_t scnidx = sym->st_shndx; + scnidx = sym->st_shndx; if (scnidx == SHN_UNDEF || scnidx >= shnum || (scnidx >= SHN_LORESERVE && scnidx <= SHN_HIRESERVE @@ -816,17 +830,20 @@ 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)); - bool discard_section = (shdr_info[cnt].idx > 0 - && cnt != ehdr->e_shstrndx); + discard_section = shdr_info[cnt].idx > 0 && cnt != ehdr->e_shstrndx; /* Set the section header in the new file. */ - GElf_Shdr debugshdr = shdr_info[cnt].shdr; + debugshdr = shdr_info[cnt].shdr; if (discard_section) debugshdr.sh_type = SHT_NOBITS; @@ -843,7 +860,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. */ - Elf_Data *debugdata = elf_newdata (scn); + debugdata = elf_newdata (scn); if (debugdata == NULL) INTERNAL_ERROR (fname); @@ -914,6 +931,9 @@ 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++; @@ -944,8 +964,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)); - char *debug_basename = basename (debug_fname_embed ?: debug_fname); - off_t crc_offset = strlen (debug_basename) + 1; + debug_basename = basename (debug_fname_embed ?: debug_fname); + crc_offset = strlen (debug_basename) + 1; /* Align to 4 byte boundary */ crc_offset = ((crc_offset - 1) & ~3) + 4; -- 2.47.2