X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Faddr2line.c;h=0ce854f6a911123263459491ac5b5c55ffda6d03;hb=82c3b58b54026d061a4d81ad95f3023d5d883ab2;hp=50fc2b38c367e4fcf5c0f1309a79c372d9feb2f0;hpb=a286dd013ef8d46edf013efc0908822a59d8ac81;p=platform%2Fupstream%2Felfutils.git diff --git a/src/addr2line.c b/src/addr2line.c index 50fc2b3..0ce854f 100644 --- a/src/addr2line.c +++ b/src/addr2line.c @@ -1,5 +1,5 @@ /* Locate source files and line information for given addresses - Copyright (C) 2005-2010, 2012, 2013 Red Hat, Inc. + Copyright (C) 2005-2010, 2012, 2013, 2015 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper , 2005. @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -51,11 +50,17 @@ ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Values for the parameters which have no short form. */ #define OPT_DEMANGLER 0x100 +#define OPT_PRETTY 0x101 /* 'p' is already used to select the process. */ /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = { - { NULL, 0, NULL, 0, N_("Output selection options:"), 2 }, + { NULL, 0, NULL, 0, N_("Input format options:"), 2 }, + { "section", 'j', "NAME", 0, + N_("Treat addresses as offsets relative to NAME section."), 0 }, + + { NULL, 0, NULL, 0, N_("Output format options:"), 3 }, + { "addresses", 'a', NULL, 0, N_("Print address before each entry"), 0 }, { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 }, { "absolute", 'A', NULL, 0, N_("Show absolute file names using compilation directory"), 0 }, @@ -63,16 +68,17 @@ static const struct argp_option options[] = { "symbols", 'S', NULL, 0, N_("Also show symbol or section names"), 0 }, { "symbols-sections", 'x', NULL, 0, N_("Also show symbol and the section names"), 0 }, { "flags", 'F', NULL, 0, N_("Also show line table flags"), 0 }, - { "section", 'j', "NAME", 0, - N_("Treat addresses as offsets relative to NAME section."), 0 }, { "inlines", 'i', NULL, 0, N_("Show all source locations that caused inline expansion of subroutines at the address."), 0 }, + { "demangle", 'C', "ARG", OPTION_ARG_OPTIONAL, + N_("Show demangled symbols (ARG is always ignored)"), 0 }, + { "pretty-print", OPT_PRETTY, NULL, 0, + N_("Print all information on one line, and indent inlines"), 0 }, { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, /* Unsupported options. */ { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 }, - { "demangle", 'C', "ARG", OPTION_HIDDEN | OPTION_ARG_OPTIONAL, NULL, 0 }, { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 }, { NULL, 0, NULL, 0, NULL, 0 } }; @@ -99,6 +105,8 @@ static const struct argp argp = /* Handle ADDR. */ static int handle_address (const char *addr, Dwfl *dwfl); +/* True when we should print the address for each entry. */ +static bool print_addresses; /* True if only base names of files should be shown. */ static bool only_basenames; @@ -124,6 +132,16 @@ static const char *just_section; /* True if all inlined subroutines of the current address should be shown. */ static bool show_inlines; +/* True if all names need to be demangled. */ +static bool demangle; + +/* True if all information should be printed on one line. */ +static bool pretty; + +#ifdef USE_DEMANGLE +static size_t demangle_buffer_len = 0; +static char *demangle_buffer = NULL; +#endif int main (int argc, char *argv[]) @@ -131,9 +149,6 @@ main (int argc, char *argv[]) int remaining; int result = 0; - /* Make memory leak detection possible. */ - mtrace (); - /* We use no threads here which can interfere with handling a stream. */ (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); @@ -184,6 +199,11 @@ main (int argc, char *argv[]) } dwfl_end (dwfl); + +#ifdef USE_DEMANGLE + free (demangle_buffer); +#endif + return result; } @@ -212,10 +232,14 @@ parse_opt (int key, char *arg, struct argp_state *state) state->child_inputs[0] = state->input; break; + case 'a': + print_addresses = true; + break; + case 'b': case 'C': case OPT_DEMANGLER: - /* Ignored for compatibility. */ + demangle = true; break; case 's': @@ -251,12 +275,49 @@ parse_opt (int key, char *arg, struct argp_state *state) show_inlines = true; break; + case OPT_PRETTY: + pretty = true; + break; + default: return ARGP_ERR_UNKNOWN; } return 0; } +static const char * +symname (const char *name) +{ +#ifdef USE_DEMANGLE + // Require GNU v3 ABI by the "_Z" prefix. + if (demangle && name[0] == '_' && name[1] == 'Z') + { + int status = -1; + char *dsymname = __cxa_demangle (name, demangle_buffer, + &demangle_buffer_len, &status); + if (status == 0) + name = demangle_buffer = dsymname; + } +#endif + return name; +} + +static const char * +get_diename (Dwarf_Die *die) +{ + Dwarf_Attribute attr; + const char *name; + + name = dwarf_formstring (dwarf_attr_integrate (die, DW_AT_MIPS_linkage_name, + &attr) + ?: dwarf_attr_integrate (die, DW_AT_linkage_name, + &attr)); + + if (name == NULL) + name = dwarf_diename (die) ?: "??"; + + return name; +} static bool print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr) @@ -269,24 +330,36 @@ print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr) if (nscopes <= 0) return false; + bool res = false; for (int i = 0; i < nscopes; ++i) switch (dwarf_tag (&scopes[i])) { case DW_TAG_subprogram: { - const char *name = dwarf_diename (&scopes[i]); + const char *name = get_diename (&scopes[i]); if (name == NULL) - return false; - puts (name); - return true; + goto done; + printf ("%s%c", symname (name), pretty ? ' ' : '\n'); + res = true; + goto done; } case DW_TAG_inlined_subroutine: { - const char *name = dwarf_diename (&scopes[i]); + const char *name = get_diename (&scopes[i]); if (name == NULL) - return false; - printf ("%s inlined", name); + goto done; + + /* When using --pretty-print we only show inlines on their + own line. Just print the first subroutine name. */ + if (pretty) + { + printf ("%s ", symname (name)); + res = true; + goto done; + } + else + printf ("%s inlined", symname (name)); Dwarf_Files *files; if (dwarf_getsrcfiles (cudie, &files, NULL) == 0) @@ -344,7 +417,9 @@ print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr) } } - return false; +done: + free (scopes); + return res; } static void @@ -361,12 +436,13 @@ print_addrsym (Dwfl_Module *mod, GElf_Addr addr) if (i >= 0) name = dwfl_module_relocation_info (mod, i, NULL); if (name == NULL) - puts ("??"); + printf ("??%c", pretty ? ' ': '\n'); else - printf ("(%s)+%#" PRIx64 "\n", name, addr); + printf ("(%s)+%#" PRIx64 "%c", name, addr, pretty ? ' ' : '\n'); } else { + name = symname (name); if (off == 0) printf ("%s", name); else @@ -391,27 +467,10 @@ print_addrsym (Dwfl_Module *mod, GElf_Addr addr) } } } - puts (""); + printf ("%c", pretty ? ' ' : '\n'); } } -static void -print_diesym (Dwarf_Die *die) -{ - Dwarf_Attribute attr; - const char *name; - - name = dwarf_formstring (dwarf_attr_integrate (die, DW_AT_MIPS_linkage_name, - &attr) - ?: dwarf_attr_integrate (die, DW_AT_linkage_name, - &attr)); - - if (name == NULL) - name = dwarf_diename (die) ?: "??"; - - puts (name); -} - static int see_one_module (Dwfl_Module *mod, void **userdata __attribute__ ((unused)), @@ -531,11 +590,34 @@ print_src (const char *src, int lineno, int linecol, Dwarf_Die *cu) } static int +get_addr_width (Dwfl_Module *mod) +{ + // Try to find the address width if possible. + static int width = 0; + if (width == 0 && mod != NULL) + { + Dwarf_Addr bias; + Elf *elf = dwfl_module_getelf (mod, &bias); + if (elf != NULL) + { + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr != NULL) + width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16; + } + } + if (width == 0) + width = 16; + + return width; +} + +static int handle_address (const char *string, Dwfl *dwfl) { char *endp; - uintmax_t addr = strtoumax (string, &endp, 0); - if (endp == string) + uintmax_t addr = strtoumax (string, &endp, 16); + if (endp == string || *endp != '\0') { bool parsed = false; int i, j; @@ -584,17 +666,30 @@ handle_address (const char *string, Dwfl *dwfl) Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr); + if (print_addresses) + { + int width = get_addr_width (mod); + printf ("0x%.*" PRIx64 "%s", width, addr, pretty ? ": " : "\n"); + } + if (show_functions) { /* First determine the function name. Use the DWARF information if possible. */ if (! print_dwarf_function (mod, addr) && !show_symbols) - puts (dwfl_module_addrname (mod, addr) ?: "??"); + { + const char *name = dwfl_module_addrname (mod, addr); + name = name != NULL ? symname (name) : "??"; + printf ("%s%c", name, pretty ? ' ' : '\n'); + } } if (show_symbols) print_addrsym (mod, addr); + if ((show_functions || show_symbols) && pretty) + printf ("at "); + Dwfl_Line *line = dwfl_module_getsrc (mod, addr); const char *src; @@ -654,6 +749,7 @@ handle_address (const char *string, Dwfl *dwfl) dwarf_offdie (dwfl_module_getdwarf (mod, &bias), dieoff, &subroutine); free (scopes); + scopes = NULL; nscopes = dwarf_getscopes_die (&subroutine, &scopes); if (nscopes > 1) @@ -671,8 +767,29 @@ handle_address (const char *string, Dwfl *dwfl) if (dwarf_tag (die) != DW_TAG_inlined_subroutine) continue; + if (pretty) + printf (" (inlined by) "); + if (show_functions) - print_diesym (&scopes[i + 1]); + { + /* Search for the parent inline or function. It + might not be directly above this inline -- e.g. + there could be a lexical_block in between. */ + for (int j = i + 1; j < nscopes; j++) + { + Dwarf_Die *parent = &scopes[j]; + int tag = dwarf_tag (parent); + if (tag == DW_TAG_inlined_subroutine + || tag == DW_TAG_entry_point + || tag == DW_TAG_subprogram) + { + printf ("%s%s", + symname (get_diename (parent)), + pretty ? " at " : "\n"); + break; + } + } + } src = NULL; lineno = 0;