#include <errno.h>
#include <error.h>
#include <fcntl.h>
+#include <gelf.h>
#include <inttypes.h>
-#include <libdwfl.h>
-#include <dwarf.h>
+#include <libdw.h>
#include <libintl.h>
#include <locale.h>
#include <mcheck.h>
/* 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 },
/* 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;
/* 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. */
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;
}
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;
}
/* 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;
}
-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");
/* 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)
{
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;
}
/* 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);
/* 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
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);
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);
}
/* Number of sections. */
- size_t shnum;
if (unlikely (elf_getshnum (elf, &shnum) < 0))
{
error (0, 0, gettext ("cannot determine number of sections: %s"),
}
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);
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)
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)
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)
{
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. */
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;
{
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
{
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;
}
/* 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);
/* 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++;
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;