summaryrefslogtreecommitdiff
path: root/src/addr2line.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2005-08-11 07:03:55 +0000
committerRoland McGrath <roland@redhat.com>2005-08-11 07:03:55 +0000
commit1c83bf1fd46b74492297694b642df36d18c6e7b5 (patch)
treedd0dae0bd10b58f0be08a91457c8a91c5c626367 /src/addr2line.c
parentd2c5996f70844ae7816034b56e769ce163251718 (diff)
downloadelfutils-1c83bf1fd46b74492297694b642df36d18c6e7b5.tar.gz
merge of 0bdc7517571447282c23ea28a69147eabf574048
and b0183df71043735ade5c882809fed6c7ca571b2a
Diffstat (limited to 'src/addr2line.c')
-rw-r--r--src/addr2line.c250
1 files changed, 96 insertions, 154 deletions
diff --git a/src/addr2line.c b/src/addr2line.c
index 60fcdf63..97eaed10 100644
--- a/src/addr2line.c
+++ b/src/addr2line.c
@@ -21,9 +21,9 @@
#include <errno.h>
#include <error.h>
#include <fcntl.h>
-#include <gelf.h>
#include <inttypes.h>
-#include <libdw.h>
+#include <libdwfl.h>
+#include <dwarf.h>
#include <libintl.h>
#include <locale.h>
#include <mcheck.h>
@@ -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");