mirror of
https://github.com/openharmony/third_party_elfutils.git
synced 2026-07-01 06:41:51 -04:00
2005-08-23 Roland McGrath <roland@redhat.com>
* dwarf_attr_integrate.c (dwarf_attr_integrate): Treat DW_AT_specification the same as DW_AT_abstract_origin.
This commit is contained in:
@@ -1,3 +1,20 @@
|
||||
2005-08-23 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* dwarf_attr_integrate.c (dwarf_attr_integrate): Treat
|
||||
DW_AT_specification the same as DW_AT_abstract_origin.
|
||||
|
||||
2005-08-20 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* libdw.map: Add dwfl_cumodule, remove dwfl_linecu.
|
||||
Add dwfl_linux_kernel_report_offline, dwfl_offline_section_address,
|
||||
and dwfl_report_offline.
|
||||
|
||||
2005-08-19 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* libdw.map: Bump version to ELFUTILS_0.114 for libdwfl changes.
|
||||
Add dwfl_module_relocate_address, dwfl_module_relocations,
|
||||
dwfl_module_relocation_info.
|
||||
|
||||
2005-08-18 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* dwarf_getscopes.c (dwarf_getscopes): Include the CU itself as
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Return specific DWARF attribute of a DIE, integrating DW_AT_abstract_origin.
|
||||
/* Return specific DWARF attribute of a DIE, integrating indirections.
|
||||
Copyright (C) 2005 Red Hat, Inc.
|
||||
|
||||
This program is Open Source software; you can redistribute it and/or
|
||||
@@ -31,6 +31,8 @@ dwarf_attr_integrate (Dwarf_Die *die, unsigned int search_name,
|
||||
return attr;
|
||||
|
||||
attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, result);
|
||||
if (attr == NULL)
|
||||
attr = INTUSE(dwarf_attr) (die, DW_AT_specification, result);
|
||||
if (attr == NULL)
|
||||
break;
|
||||
|
||||
|
||||
+9
-1
@@ -96,19 +96,21 @@ ELFUTILS_0.114 {
|
||||
dwfl_addrdwarf;
|
||||
dwfl_addrmodule;
|
||||
dwfl_begin;
|
||||
dwfl_cumodule;
|
||||
dwfl_end;
|
||||
dwfl_errmsg;
|
||||
dwfl_errno;
|
||||
dwfl_getdwarf;
|
||||
dwfl_getmodules;
|
||||
dwfl_getsrc;
|
||||
dwfl_linecu;
|
||||
dwfl_getsrclines;
|
||||
dwfl_lineinfo;
|
||||
dwfl_linemodule;
|
||||
dwfl_linux_kernel_find_elf;
|
||||
dwfl_linux_kernel_module_section_address;
|
||||
dwfl_linux_kernel_report_kernel;
|
||||
dwfl_linux_kernel_report_modules;
|
||||
dwfl_linux_kernel_report_offline;
|
||||
dwfl_linux_proc_find_elf;
|
||||
dwfl_linux_proc_report;
|
||||
dwfl_module_addrdie;
|
||||
@@ -119,11 +121,17 @@ ELFUTILS_0.114 {
|
||||
dwfl_module_getsrc_file;
|
||||
dwfl_module_info;
|
||||
dwfl_module_nextcu;
|
||||
dwfl_module_relocate_address;
|
||||
dwfl_module_relocation_info;
|
||||
dwfl_module_relocations;
|
||||
dwfl_nextcu;
|
||||
dwfl_offline_section_address;
|
||||
dwfl_onesrcline;
|
||||
dwfl_report_begin;
|
||||
dwfl_report_elf;
|
||||
dwfl_report_end;
|
||||
dwfl_report_module;
|
||||
dwfl_report_offline;
|
||||
dwfl_standard_argp;
|
||||
dwfl_standard_find_debuginfo;
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
* dev+ino+mtime hash table, global
|
||||
** share fd; if !isrel, share Elf*,Ebl*,Dwarf*
|
||||
|
||||
* find_debuginfo
|
||||
When local search fails, try "yum install-debugfor elf-file".
|
||||
i.e., yum install `rpm -qf elffile --qf '%{SOURCERPM} %{V}-%{R} %{ARCH}\n' | awk '{ print substr($1, 1, length($1)-length("-" $2 ".src.rpm")) "-debuginfo-" $2 "." $3 }' `
|
||||
done in rpm-python inside yum(?)
|
||||
** all yum ops should have a -qf mode, means `rpm -qf --qf %{name}.%{arch}`
|
||||
plus debug-of modifier to name.arch or -qf *
|
||||
|
||||
* libdw_findcu reads all cu hdrs from beginning
|
||||
** good for dwarf_offdie: find cu containing that offset
|
||||
** bad for dwarf_addrdie: reads in whole debuginfo file
|
||||
** when from aranges (dwarf_addrdie), could read cuhdr offset directly w/o scan
|
||||
*** aranges really store cu header offset, but libdw adds in header size to
|
||||
get cu die offset; but libdw_findcu interning should start with header
|
||||
@@ -0,0 +1,30 @@
|
||||
* regexp on multiple formats to yield records (pc, mod, sym, offset, size?)
|
||||
|
||||
glibc backtrace_symbols_fd:
|
||||
|
||||
foo.so(sym+0x123)[0x345]
|
||||
foo.so(sym-0x123)[0x345]
|
||||
foobar[0x12345678]
|
||||
|
||||
i386 kernel oops:
|
||||
|
||||
st_size
|
||||
[<%x>] sym+0x123/0x32
|
||||
[<%x>] sym-0x123/0x32
|
||||
[<%x>] sym+0x123/0x32 [mod]
|
||||
|
||||
x86-64 oops:
|
||||
|
||||
[<%x>]
|
||||
<%x>{sym+%d}
|
||||
<%x>{sym-%d}
|
||||
<%x>{:mod:sym+%d}
|
||||
<%x>{:mod:sym-%d}
|
||||
|
||||
kernel `uname -r`:
|
||||
|
||||
... Not tainted (%s)
|
||||
... Tainted: [A-Z]* (%s)
|
||||
|
||||
|
||||
* guess mod loadbase from sym+ofs==pc -> pc-(symval+ofs)==bias
|
||||
@@ -1,8 +1,111 @@
|
||||
2005-08-22 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* dwfl_validate_address.c: New file.
|
||||
* Makefile.am (libdwfl_a_SOURCES): Add it.
|
||||
* libdwfl.h: Declare dwfl_validate_address.
|
||||
|
||||
* derelocate.c (dwfl_module_relocate_address): Add INTDEF.
|
||||
* libdwflP.h: Add INTDECL.
|
||||
|
||||
* dwfl_module_getdwarf.c (find_symtab): Use elf_getdata instead of
|
||||
elf_rawdata for symbol-related sections.
|
||||
|
||||
* offline.c (dwfl_report_offline): Move offline_next_address outside
|
||||
module's range, in case it's an ET_EXEC using fixed segment locations.
|
||||
* libdwfl.h: Update comment.
|
||||
|
||||
* dwfl_report_elf.c (dwfl_report_elf): Align BASE to first segment's
|
||||
required alignment.
|
||||
|
||||
2005-08-20 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* linux-kernel-modules.c (report_kernel): Take new argument PREDICATE,
|
||||
function to choose whether to report.
|
||||
(dwfl_linux_kernel_report_offline): Likewise.
|
||||
* libdwfl.h: Update decl.
|
||||
* argp-std.c (parse_opt): Update caller.
|
||||
|
||||
* dwfl_getsrclines.c: New file.
|
||||
* dwfl_onesrcline.c: New file.
|
||||
* Makefile.am (libdwfl_a_SOURCES): Add them.
|
||||
* libdwfl.h: Declare dwfl_getsrclines, dwfl_onesrcline.
|
||||
|
||||
* linux-kernel-modules.c (dwfl_linux_kernel_find_elf): Don't leak
|
||||
MODULESDIR[0]. Call fts_close on failure.
|
||||
|
||||
* dwfl_module_getdwarf.c (load_dw): Take dwfl_file * instead of Elf *.
|
||||
Close ET_REL file descriptors after relocation.
|
||||
(find_dw): Update caller.
|
||||
* offline.c (dwfl_report_offline): Get the file into memory and close
|
||||
the file descriptor.
|
||||
|
||||
* dwfl_module_getdwarf.c (find_debuginfo): Do nothing when
|
||||
MOD->debug.elf is already set.
|
||||
|
||||
* find-debuginfo.c (try_open): Use TEMP_FAILURE_RETRY.
|
||||
(dwfl_standard_find_debuginfo): Fail on errors not ENOENT or ENOTDIR.
|
||||
|
||||
* argp-std.c (options, parse_opt): Grok -K/--offline-kernel, use
|
||||
dwfl_linux_kernel_report_offline with offline_callbacks.
|
||||
|
||||
* linux-kernel-modules.c (report_kernel): New function, broken out of
|
||||
...
|
||||
(dwfl_linux_kernel_report_kernel): ... here. Use it.
|
||||
(dwfl_linux_kernel_report_offline): New function.
|
||||
* libdwfl.h: Declare it.
|
||||
* libdwflP.h: Add INTDECL.
|
||||
|
||||
2005-08-19 Roland McGrath <roland@redhat.com>
|
||||
|
||||
Use standard debuginfo search path to look for vmlinux.
|
||||
* find-debuginfo.c (dwfl_standard_find_debuginfo): Don't check CRC if
|
||||
passed zero.
|
||||
* linux-kernel-modules.c (try_kernel_name): New function, broken out
|
||||
of ...
|
||||
(dwfl_linux_kernel_report_kernel): ... here. Use it.
|
||||
|
||||
* argp-std.c (offline_callbacks): New variable.
|
||||
(parse_opt): Use it for -e. Allow multiple -e options.
|
||||
|
||||
* offline.c: New file.
|
||||
* Makefile.am (libdwfl_a_SOURCES): Add it.
|
||||
* libdwfl.h: Declare dwfl_offline_section_address, dwfl_report_offline.
|
||||
* libdwflP.h: Add INTDECLs.
|
||||
(OFFLINE_REDZONE): New macro.
|
||||
(struct Dwfl): New member `offline_next_address'.
|
||||
* dwfl_begin.c (dwfl_begin): Initialize it.
|
||||
* dwfl_module.c (dwfl_report_begin): Likewise.
|
||||
|
||||
* dwfl_report_elf.c (dwfl_report_elf): Accept all types. When ET_REL,
|
||||
do a nominal absolute section layout starting at BASE.
|
||||
* libdwfl.h: Update comment.
|
||||
|
||||
2005-08-18 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* dwfl_module_getsrc_file.c (dwfl_module_getsrc_file): Do
|
||||
dwfl_module_getdwarf if necessary.
|
||||
|
||||
* dwfl_report_elf.c (dwfl_report_elf): Permit ET_REL with BASE==0.
|
||||
* libdwfl.h: Update comment.
|
||||
|
||||
* derelocate.c: New file.
|
||||
* Makefile.am (libdwfl_a_SOURCES): Add it.
|
||||
|
||||
* libdwflP.h (struct Dwfl_Module): isrel -> e_type.
|
||||
* dwfl_report_elf.c (dwfl_report_elf): Initialize it.
|
||||
* dwfl_module_getdwarf.c (open_elf): Update initialization.
|
||||
(load_dw, dwfl_module_addrname): Update uses.
|
||||
* relocate.c (__libdwfl_relocate): Likewise.
|
||||
|
||||
2005-08-04 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* libdwfl.h (Dwfl_Callbacks.section_address): Take additional
|
||||
arguments SHNDX, SHDR.
|
||||
(dwfl_linux_kernel_module_section_address): Update prototype.
|
||||
* relocate.c (__libdwfl_relocate_value): Update caller.
|
||||
* linux-kernel-modules.c (dwfl_linux_kernel_module_section_address):
|
||||
Take the new arguments.
|
||||
|
||||
2005-08-10 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* relocate.c (__libdwfl_relocate): Take argument DEBUGFILE,
|
||||
|
||||
@@ -35,14 +35,17 @@ euinclude_HEADERS = libdwfl.h
|
||||
|
||||
libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c \
|
||||
dwfl_module.c dwfl_report_elf.c relocate.c \
|
||||
derelocate.c offline.c \
|
||||
dwfl_module_info.c dwfl_getmodules.c \
|
||||
dwfl_module_getdwarf.c dwfl_getdwarf.c \
|
||||
dwfl_validate_address.c \
|
||||
argp-std.c find-debuginfo.c \
|
||||
linux-kernel-modules.c linux-proc-maps.c \
|
||||
dwfl_addrmodule.c dwfl_addrdwarf.c \
|
||||
cu.c dwfl_module_nextcu.c dwfl_nextcu.c dwfl_cumodule.c \
|
||||
dwfl_module_addrdie.c dwfl_addrdie.c \
|
||||
lines.c dwfl_lineinfo.c dwfl_linemodule.c \
|
||||
dwfl_getsrclines.c dwfl_onesrcline.c \
|
||||
dwfl_module_getsrc.c dwfl_getsrc.c \
|
||||
dwfl_module_getsrc_file.c \
|
||||
libdwfl_crc32.c libdwfl_crc32_file.c \
|
||||
|
||||
+49
-15
@@ -30,6 +30,8 @@ static const struct argp_option options[] =
|
||||
{ "pid", 'p', "PID", 0,
|
||||
N_("Find addresses in files mapped into process PID"), 0 },
|
||||
{ "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
|
||||
{ "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
|
||||
N_("Kernel with all modules"), 0 },
|
||||
{ "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
|
||||
N_("Search path for separate debuginfo files"), 0 },
|
||||
{ NULL, 0, NULL, 0, NULL, 0 }
|
||||
@@ -37,6 +39,14 @@ static const struct argp_option options[] =
|
||||
|
||||
static char *debuginfo_path;
|
||||
|
||||
static const Dwfl_Callbacks offline_callbacks =
|
||||
{
|
||||
.find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
|
||||
.debuginfo_path = &debuginfo_path,
|
||||
|
||||
.section_address = INTUSE(dwfl_offline_section_address),
|
||||
};
|
||||
|
||||
static const Dwfl_Callbacks proc_callbacks =
|
||||
{
|
||||
.find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
|
||||
@@ -78,19 +88,29 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
if (state->hook == NULL)
|
||||
{
|
||||
Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
|
||||
if (INTUSE(dwfl_report_elf) (dwfl, "", arg, -1, 0) == NULL)
|
||||
return fail (-1, arg);
|
||||
state->hook = dwfl;
|
||||
}
|
||||
else
|
||||
{
|
||||
toomany:
|
||||
argp_error (state, "%s", _("only one -e, -p, or -k option allowed"));
|
||||
return EINVAL;
|
||||
}
|
||||
{
|
||||
Dwfl *dwfl = state->hook;
|
||||
if (dwfl == NULL)
|
||||
{
|
||||
dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
|
||||
if (dwfl == NULL)
|
||||
return fail (-1, arg);
|
||||
state->hook = dwfl;
|
||||
}
|
||||
if (dwfl->callbacks == &offline_callbacks)
|
||||
{
|
||||
if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
|
||||
return fail (-1, arg);
|
||||
state->hook = dwfl;
|
||||
}
|
||||
else
|
||||
{
|
||||
toomany:
|
||||
argp_error (state,
|
||||
"%s", _("only one of -e, -p, -k, or -K allowed"));
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
@@ -123,6 +143,20 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
goto toomany;
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
if (state->hook == NULL)
|
||||
{
|
||||
Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
|
||||
int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
|
||||
NULL);
|
||||
if (result != 0)
|
||||
return fail (result, _("cannot find kernel or modules"));
|
||||
state->hook = dwfl;
|
||||
}
|
||||
else
|
||||
goto toomany;
|
||||
break;
|
||||
|
||||
case ARGP_KEY_SUCCESS:
|
||||
{
|
||||
Dwfl *dwfl = state->hook;
|
||||
@@ -131,8 +165,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
/* Default if no -e, -p, or -k, is "-e a.out". */
|
||||
arg = "a.out";
|
||||
dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
|
||||
if (INTUSE(dwfl_report_elf) (dwfl, "", arg, -1, 0) == NULL)
|
||||
dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
|
||||
if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
|
||||
return fail (-1, arg);
|
||||
state->hook = dwfl;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/* Recover relocatibility for addresses computed from debug information.
|
||||
Copyright (C) 2005 Red Hat, Inc.
|
||||
|
||||
This program is Open Source software; you can redistribute it and/or
|
||||
modify it under the terms of the Open Software License version 1.0 as
|
||||
published by the Open Source Initiative.
|
||||
|
||||
You should have received a copy of the Open Software License along
|
||||
with this program; if not, you may obtain a copy of the Open Software
|
||||
License version 1.0 from http://www.opensource.org/licenses/osl.php or
|
||||
by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
|
||||
3001 King Ranch Road, Ukiah, CA 95482. */
|
||||
|
||||
#include "libdwflP.h"
|
||||
|
||||
struct dwfl_relocation
|
||||
{
|
||||
size_t count;
|
||||
struct
|
||||
{
|
||||
Elf_Scn *scn;
|
||||
const char *name;
|
||||
GElf_Addr start, end;
|
||||
} refs[0];
|
||||
};
|
||||
|
||||
|
||||
struct secref
|
||||
{
|
||||
struct secref *next;
|
||||
Elf_Scn *scn;
|
||||
const char *name;
|
||||
GElf_Addr start, end;
|
||||
};
|
||||
|
||||
static int
|
||||
compare_secrefs (const void *a, const void *b)
|
||||
{
|
||||
struct secref *const *p1 = a;
|
||||
struct secref *const *p2 = b;
|
||||
|
||||
return (*p1)->start - (*p2)->start;
|
||||
}
|
||||
|
||||
static int
|
||||
cache_sections (Dwfl_Module *mod)
|
||||
{
|
||||
size_t symshstrndx;
|
||||
if (elf_getshstrndx (mod->symfile->elf, &symshstrndx) < 0)
|
||||
{
|
||||
__libdwfl_seterrno (DWFL_E_LIBELF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct secref *refs = NULL;
|
||||
size_t nrefs = 0;
|
||||
|
||||
Elf_Scn *scn = NULL;
|
||||
while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
|
||||
{
|
||||
GElf_Shdr shdr_mem;
|
||||
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
||||
if (shdr == NULL)
|
||||
return -1;
|
||||
|
||||
if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr != 0)
|
||||
{
|
||||
const char *name = elf_strptr (mod->symfile->elf, symshstrndx,
|
||||
shdr->sh_name);
|
||||
if (name == NULL)
|
||||
return -1;
|
||||
|
||||
struct secref *newref = alloca (sizeof *newref);
|
||||
newref->scn = scn;
|
||||
newref->name = name;
|
||||
newref->start = shdr->sh_addr;
|
||||
newref->end = shdr->sh_addr + shdr->sh_size;
|
||||
newref->next = refs;
|
||||
refs = newref;
|
||||
++nrefs;
|
||||
}
|
||||
}
|
||||
|
||||
mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
|
||||
if (mod->reloc_info == NULL)
|
||||
{
|
||||
__libdwfl_seterrno (DWFL_E_NOMEM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct secref *sortrefs[nrefs];
|
||||
for (size_t i = nrefs; i-- > 0; refs = refs->next)
|
||||
sortrefs[i] = refs;
|
||||
assert (refs == NULL);
|
||||
|
||||
qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
|
||||
|
||||
mod->reloc_info->count = nrefs;
|
||||
for (size_t i = 0; i < nrefs; ++i)
|
||||
{
|
||||
mod->reloc_info->refs[i].name = sortrefs[i]->name;
|
||||
mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
|
||||
mod->reloc_info->refs[i].start = sortrefs[i]->start;
|
||||
mod->reloc_info->refs[i].end = sortrefs[i]->end;
|
||||
}
|
||||
|
||||
return nrefs;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
dwfl_module_relocations (Dwfl_Module *mod)
|
||||
{
|
||||
if (mod == NULL)
|
||||
return -1;
|
||||
|
||||
if (mod->reloc_info != NULL)
|
||||
return mod->reloc_info->count;
|
||||
|
||||
if (mod->dw == NULL)
|
||||
{
|
||||
Dwarf_Addr bias;
|
||||
if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (mod->e_type)
|
||||
{
|
||||
case ET_REL:
|
||||
return cache_sections (mod);
|
||||
|
||||
case ET_DYN:
|
||||
return 1;
|
||||
|
||||
case ET_EXEC:
|
||||
assert (mod->debug.bias == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
|
||||
Elf32_Word *shndxp)
|
||||
{
|
||||
if (mod == NULL)
|
||||
return NULL;
|
||||
|
||||
switch (mod->e_type)
|
||||
{
|
||||
case ET_REL:
|
||||
break;
|
||||
|
||||
case ET_DYN:
|
||||
if (idx != 0)
|
||||
return NULL;
|
||||
if (shndxp)
|
||||
*shndxp = SHN_ABS;
|
||||
return "";
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (unlikely (mod->reloc_info == NULL) && cache_sections (mod) < 0)
|
||||
return NULL;
|
||||
|
||||
struct dwfl_relocation *sections = mod->reloc_info;
|
||||
|
||||
if (idx >= sections->count)
|
||||
return NULL;
|
||||
|
||||
if (shndxp)
|
||||
*shndxp = elf_ndxscn (sections->refs[idx].scn);
|
||||
|
||||
return sections->refs[idx].name;
|
||||
}
|
||||
|
||||
int
|
||||
dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
|
||||
{
|
||||
if (mod == NULL)
|
||||
return -1;
|
||||
|
||||
if (mod->dw == NULL)
|
||||
{
|
||||
Dwarf_Addr bias;
|
||||
if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mod->e_type != ET_REL)
|
||||
{
|
||||
*addr -= mod->debug.bias;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely (mod->reloc_info == NULL) && cache_sections (mod) < 0)
|
||||
return -1;
|
||||
|
||||
struct dwfl_relocation *sections = mod->reloc_info;
|
||||
|
||||
/* The sections are sorted by address, so we can use binary search. */
|
||||
size_t l = 0, u = sections->count;
|
||||
while (l < u)
|
||||
{
|
||||
size_t idx = (l + u) / 2;
|
||||
if (*addr < sections->refs[idx].start)
|
||||
u = idx;
|
||||
else if (*addr > sections->refs[idx].end)
|
||||
l = idx + 1;
|
||||
else
|
||||
{
|
||||
/* Consider the limit of a section to be inside it, unless it's
|
||||
inside the next one. A section limit address can appear in
|
||||
line records. */
|
||||
if (*addr == sections->refs[idx].end
|
||||
&& idx < sections->count
|
||||
&& *addr == sections->refs[idx + 1].start)
|
||||
++idx;
|
||||
|
||||
*addr -= sections->refs[idx].start;
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
__libdw_seterrno (DWARF_E_NO_MATCH);
|
||||
return -1;
|
||||
}
|
||||
INTDEF (dwfl_module_relocate_address)
|
||||
@@ -26,7 +26,10 @@ dwfl_begin (const Dwfl_Callbacks *callbacks)
|
||||
if (dwfl == NULL)
|
||||
__libdwfl_seterrno (DWFL_E_NOMEM);
|
||||
else
|
||||
dwfl->callbacks = callbacks;
|
||||
{
|
||||
dwfl->callbacks = callbacks;
|
||||
dwfl->offline_next_address = OFFLINE_REDZONE;
|
||||
}
|
||||
|
||||
return dwfl;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Fetch source line information for CU.
|
||||
Copyright (C) 2005 Red Hat, Inc.
|
||||
|
||||
This program is Open Source software; you can redistribute it and/or
|
||||
modify it under the terms of the Open Software License version 1.0 as
|
||||
published by the Open Source Initiative.
|
||||
|
||||
You should have received a copy of the Open Software License along
|
||||
with this program; if not, you may obtain a copy of the Open Software
|
||||
License version 1.0 from http://www.opensource.org/licenses/osl.php or
|
||||
by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
|
||||
3001 King Ranch Road, Ukiah, CA 95482. */
|
||||
|
||||
#include "libdwflP.h"
|
||||
|
||||
int
|
||||
dwfl_getsrclines (Dwarf_Die *cudie, size_t *nlines)
|
||||
{
|
||||
struct dwfl_cu *cu = (struct dwfl_cu *) cudie;
|
||||
|
||||
if (cu->lines == NULL)
|
||||
{
|
||||
Dwfl_Error error = __libdwfl_cu_getsrclines (cu);
|
||||
if (error != DWFL_E_NOERROR)
|
||||
{
|
||||
__libdwfl_seterrno (error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*nlines = cu->die.cu->lines->nlines;
|
||||
return -1;
|
||||
}
|
||||
@@ -68,6 +68,8 @@ dwfl_report_begin (Dwfl *dwfl)
|
||||
free (dwfl->modules);
|
||||
dwfl->modules = NULL;
|
||||
dwfl->nmodules = 0;
|
||||
|
||||
dwfl->offline_next_address = OFFLINE_REDZONE;
|
||||
}
|
||||
INTDEF (dwfl_report_begin)
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "libdwflP.h"
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "../libdw/libdwP.h" /* DWARF_E_* values are here. */
|
||||
|
||||
|
||||
@@ -34,7 +35,7 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
|
||||
if (ehdr == NULL)
|
||||
return DWFL_E (LIBELF, elf_errno ());
|
||||
|
||||
mod->isrel = ehdr->e_type == ET_REL;
|
||||
mod->e_type = ehdr->e_type;
|
||||
|
||||
file->bias = 0;
|
||||
for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
|
||||
@@ -74,6 +75,9 @@ find_file (Dwfl_Module *mod)
|
||||
static Dwfl_Error
|
||||
find_debuginfo (Dwfl_Module *mod)
|
||||
{
|
||||
if (mod->debug.elf != NULL)
|
||||
return DWFL_E_NOERROR;
|
||||
|
||||
size_t shstrndx;
|
||||
if (elf_getshstrndx (mod->main.elf, &shstrndx) < 0)
|
||||
return DWFL_E_LIBELF;
|
||||
@@ -279,9 +283,9 @@ find_symtab (Dwfl_Module *mod)
|
||||
|
||||
/* Try to start up libdw on DEBUGFILE. */
|
||||
static Dwfl_Error
|
||||
load_dw (Dwfl_Module *mod, Elf *debugfile)
|
||||
load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
|
||||
{
|
||||
if (mod->isrel)
|
||||
if (mod->e_type == ET_REL)
|
||||
{
|
||||
const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
|
||||
|
||||
@@ -299,12 +303,24 @@ load_dw (Dwfl_Module *mod, Elf *debugfile)
|
||||
find_symtab (mod);
|
||||
Dwfl_Error result = mod->symerr;
|
||||
if (result == DWFL_E_NOERROR)
|
||||
result = __libdwfl_relocate (mod, debugfile);
|
||||
result = __libdwfl_relocate (mod, debugfile->elf);
|
||||
if (result != DWFL_E_NOERROR)
|
||||
return result;
|
||||
|
||||
/* Don't keep the file descriptors around. */
|
||||
if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
|
||||
{
|
||||
close (mod->main.fd);
|
||||
mod->main.fd = -1;
|
||||
}
|
||||
if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0)
|
||||
{
|
||||
close (debugfile->fd);
|
||||
debugfile->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
mod->dw = INTUSE(dwarf_begin_elf) (debugfile, DWARF_C_READ, NULL);
|
||||
mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
|
||||
if (mod->dw == NULL)
|
||||
{
|
||||
int err = INTUSE(dwarf_errno) ();
|
||||
@@ -331,7 +347,7 @@ find_dw (Dwfl_Module *mod)
|
||||
return;
|
||||
|
||||
/* First see if the main ELF file has the debugging information. */
|
||||
mod->dwerr = load_dw (mod, mod->main.elf);
|
||||
mod->dwerr = load_dw (mod, &mod->main);
|
||||
switch (mod->dwerr)
|
||||
{
|
||||
case DWFL_E_NOERROR:
|
||||
@@ -351,7 +367,7 @@ find_dw (Dwfl_Module *mod)
|
||||
switch (mod->dwerr)
|
||||
{
|
||||
case DWFL_E_NOERROR:
|
||||
mod->dwerr = load_dw (mod, mod->debug.elf);
|
||||
mod->dwerr = load_dw (mod, &mod->debug);
|
||||
break;
|
||||
|
||||
case DWFL_E_CB: /* The find_debuginfo hook failed. */
|
||||
@@ -435,7 +451,7 @@ dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr addr)
|
||||
if (sym->st_shndx != SHN_XINDEX)
|
||||
shndx = sym->st_shndx;
|
||||
|
||||
if (mod->isrel)
|
||||
if (mod->e_type == ET_REL)
|
||||
/* In an ET_REL file, the symbol table values are relative
|
||||
to the section, not to the module's load base. */
|
||||
switch (shndx)
|
||||
|
||||
@@ -23,6 +23,13 @@ dwfl_module_getsrc_file (Dwfl_Module *mod,
|
||||
if (mod == NULL)
|
||||
return -1;
|
||||
|
||||
if (mod->dw == NULL)
|
||||
{
|
||||
Dwarf_Addr bias;
|
||||
if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool is_basename = strchr (fname, '/') == NULL;
|
||||
|
||||
size_t max_match = *nsrcs ?: ~0u;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Return one of the sources lines of a CU.
|
||||
Copyright (C) 2005 Red Hat, Inc.
|
||||
|
||||
This program is Open Source software; you can redistribute it and/or
|
||||
modify it under the terms of the Open Software License version 1.0 as
|
||||
published by the Open Source Initiative.
|
||||
|
||||
You should have received a copy of the Open Software License along
|
||||
with this program; if not, you may obtain a copy of the Open Software
|
||||
License version 1.0 from http://www.opensource.org/licenses/osl.php or
|
||||
by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
|
||||
3001 King Ranch Road, Ukiah, CA 95482. */
|
||||
|
||||
#include "libdwflP.h"
|
||||
|
||||
Dwfl_Line *
|
||||
dwfl_onesrcline (Dwarf_Die *cudie, size_t idx)
|
||||
{
|
||||
struct dwfl_cu *cu = (struct dwfl_cu *) cudie;
|
||||
|
||||
if (cudie == NULL)
|
||||
return NULL;
|
||||
|
||||
if (cu->lines == NULL)
|
||||
{
|
||||
Dwfl_Error error = __libdwfl_cu_getsrclines (cu);
|
||||
if (error != DWFL_E_NOERROR)
|
||||
{
|
||||
__libdwfl_seterrno (error);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx >= cu->die.cu->lines->nlines)
|
||||
{
|
||||
__libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_LINE_IDX));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &cu->lines->idx[idx];
|
||||
}
|
||||
+83
-29
@@ -45,41 +45,94 @@ dwfl_report_elf (Dwfl *dwfl, const char *name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GElf_Addr start = 0, end = 0;
|
||||
for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
|
||||
GElf_Addr start = 0, end = 0, bias = 0;
|
||||
switch (ehdr->e_type)
|
||||
{
|
||||
GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
|
||||
if (ph == NULL)
|
||||
goto elf_error;
|
||||
if (ph->p_type == PT_LOAD)
|
||||
case ET_REL:
|
||||
/* For a relocatable object, we do an arbitrary section layout.
|
||||
By updating the section header in place, we leave the layout
|
||||
information to be found by relocation. */
|
||||
|
||||
start = end = base;
|
||||
|
||||
Elf_Scn *scn = NULL;
|
||||
while ((scn = elf_nextscn (elf, scn)) != NULL)
|
||||
{
|
||||
start = base + (ph->p_vaddr & -ph->p_align);
|
||||
break;
|
||||
}
|
||||
}
|
||||
GElf_Shdr shdr_mem;
|
||||
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
||||
if (shdr == NULL)
|
||||
goto elf_error;
|
||||
|
||||
for (uint_fast16_t i = ehdr->e_phnum; i-- > 0;)
|
||||
{
|
||||
GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
|
||||
if (ph == NULL)
|
||||
goto elf_error;
|
||||
if (ph->p_type == PT_LOAD)
|
||||
if (shdr->sh_flags & SHF_ALLOC)
|
||||
{
|
||||
const GElf_Xword align = shdr->sh_addralign ?: 1;
|
||||
shdr->sh_addr = (end + align - 1) & -align;
|
||||
if (end == base)
|
||||
/* This is the first section assigned a location.
|
||||
Use its aligned address as the module's base. */
|
||||
start = shdr->sh_addr;
|
||||
end = shdr->sh_addr + shdr->sh_size;
|
||||
if (! gelf_update_shdr (scn, shdr))
|
||||
goto elf_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (end == start)
|
||||
{
|
||||
end = base + (ph->p_vaddr + ph->p_memsz);
|
||||
break;
|
||||
__libdwfl_seterrno (DWFL_E_BADELF);
|
||||
if (closefd)
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Everything else has to have program headers. */
|
||||
|
||||
case ET_EXEC:
|
||||
case ET_CORE:
|
||||
/* An assigned base address is meaningless for these. */
|
||||
base = 0;
|
||||
|
||||
case ET_DYN:
|
||||
default:
|
||||
for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
|
||||
{
|
||||
GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
|
||||
if (ph == NULL)
|
||||
goto elf_error;
|
||||
if (ph->p_type == PT_LOAD)
|
||||
{
|
||||
if ((base & (ph->p_align - 1)) != 0)
|
||||
base = (base + ph->p_align - 1) & -ph->p_align;
|
||||
start = base + (ph->p_vaddr & -ph->p_align);
|
||||
break;
|
||||
}
|
||||
}
|
||||
bias = base;
|
||||
|
||||
for (uint_fast16_t i = ehdr->e_phnum; i-- > 0;)
|
||||
{
|
||||
GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
|
||||
if (ph == NULL)
|
||||
goto elf_error;
|
||||
if (ph->p_type == PT_LOAD)
|
||||
{
|
||||
end = base + (ph->p_vaddr + ph->p_memsz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (end == 0)
|
||||
{
|
||||
__libdwfl_seterrno (DWFL_E_NO_PHDR);
|
||||
if (closefd)
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (end == 0)
|
||||
{
|
||||
__libdwfl_seterrno (DWFL_E_NO_PHDR);
|
||||
if (closefd)
|
||||
close (fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name,
|
||||
base + start, base + end);
|
||||
Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, start, end);
|
||||
if (m != NULL)
|
||||
{
|
||||
if (m->main.name == NULL)
|
||||
@@ -103,7 +156,8 @@ dwfl_report_elf (Dwfl *dwfl, const char *name,
|
||||
if (m->main.elf == NULL)
|
||||
{
|
||||
m->main.elf = elf;
|
||||
m->main.bias = base;
|
||||
m->main.bias = bias;
|
||||
m->e_type = ehdr->e_type;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Validate an address and the relocatability of an offset from it.
|
||||
Copyright (C) 2005 Red Hat, Inc.
|
||||
|
||||
This program is Open Source software; you can redistribute it and/or
|
||||
modify it under the terms of the Open Software License version 1.0 as
|
||||
published by the Open Source Initiative.
|
||||
|
||||
You should have received a copy of the Open Software License along
|
||||
with this program; if not, you may obtain a copy of the Open Software
|
||||
License version 1.0 from http://www.opensource.org/licenses/osl.php or
|
||||
by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
|
||||
3001 King Ranch Road, Ukiah, CA 95482. */
|
||||
|
||||
#include "libdwflP.h"
|
||||
|
||||
int
|
||||
dwfl_validate_address (Dwfl *dwfl, Dwarf_Addr address, Dwarf_Sword offset)
|
||||
{
|
||||
Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (dwfl, address);
|
||||
if (mod == NULL)
|
||||
return -1;
|
||||
|
||||
Dwarf_Addr relative = address;
|
||||
int idx = INTUSE(dwfl_module_relocate_address) (mod, &relative);
|
||||
if (idx < 0)
|
||||
return -1;
|
||||
|
||||
if (offset != 0)
|
||||
{
|
||||
int offset_idx = -1;
|
||||
relative = address + offset;
|
||||
if (relative >= mod->low_addr && relative <= mod->high_addr)
|
||||
{
|
||||
offset_idx = INTUSE(dwfl_module_relocate_address) (mod, &relative);
|
||||
if (offset_idx < 0)
|
||||
return -1;
|
||||
}
|
||||
if (offset_idx != idx)
|
||||
{
|
||||
__libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ try_open (const char *dir, const char *subdir, const char *debuglink,
|
||||
if (fname == NULL)
|
||||
return -1;
|
||||
|
||||
int fd = open64 (fname, O_RDONLY);
|
||||
int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY));
|
||||
if (fd < 0)
|
||||
free (fname);
|
||||
else
|
||||
@@ -59,7 +59,7 @@ check_crc (int fd, GElf_Word debuglink_crc)
|
||||
}
|
||||
|
||||
int
|
||||
dwfl_standard_find_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
|
||||
dwfl_standard_find_debuginfo (Dwfl_Module *mod,
|
||||
void **userdata __attribute__ ((unused)),
|
||||
const char *modname __attribute__ ((unused)),
|
||||
GElf_Addr base __attribute__ ((unused)),
|
||||
@@ -68,7 +68,7 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
|
||||
GElf_Word debuglink_crc,
|
||||
char **debuginfo_file_name)
|
||||
{
|
||||
bool cancheck = true;
|
||||
bool cancheck = debuglink_crc != (GElf_Word) 0;
|
||||
|
||||
const char *file_basename = file_name == NULL ? NULL : basename (file_name);
|
||||
if (debuglink_file == NULL)
|
||||
@@ -141,7 +141,14 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
|
||||
char *fname;
|
||||
int fd = try_open (dir, subdir, debuglink_file, &fname);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
switch (errno)
|
||||
{
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
continue;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if (!check || check_crc (fd, debuglink_crc))
|
||||
{
|
||||
*debuginfo_file_name = fname;
|
||||
|
||||
+81
-8
@@ -38,11 +38,15 @@ typedef struct
|
||||
const char *debuglink_file, GElf_Word debuglink_crc,
|
||||
char **debuginfo_file_name);
|
||||
|
||||
/* Fill *ADDR with the loaded address of the
|
||||
section called SECNAME in the given module. */
|
||||
/* Fill *ADDR with the loaded address of the section called SECNAME in
|
||||
the given module. This is called exactly once for each SHF_ALLOC
|
||||
section that relocations affecting DWARF data refer to, so it can
|
||||
easily be used to collect state about the sections referenced. */
|
||||
int (*section_address) (Dwfl_Module *mod, void **userdata,
|
||||
const char *modname, Dwarf_Addr base,
|
||||
const char *secname, Dwarf_Addr *addr);
|
||||
const char *secname,
|
||||
Elf32_Word shndx, const GElf_Shdr *shdr,
|
||||
Dwarf_Addr *addr);
|
||||
|
||||
char **debuginfo_path; /* See dwfl_standard_find_debuginfo. */
|
||||
} Dwfl_Callbacks;
|
||||
@@ -66,7 +70,7 @@ extern const char *dwfl_errmsg (int err);
|
||||
|
||||
|
||||
/* Start reporting the current set of modules to the library. No calls but
|
||||
dwfl_report_module can be made on DWFL until dwfl_report_end is called. */
|
||||
dwfl_report_* can be made on DWFL until dwfl_report_end is called. */
|
||||
extern void dwfl_report_begin (Dwfl *dwfl);
|
||||
|
||||
/* Report that a module called NAME spans addresses [START, END).
|
||||
@@ -76,13 +80,22 @@ extern Dwfl_Module *dwfl_report_module (Dwfl *dwfl, const char *name,
|
||||
Dwarf_Addr start, Dwarf_Addr end);
|
||||
|
||||
/* Report a module with start and end addresses computed from the ELF
|
||||
program headers in the given file, plus BASE. FD may be -1 to open
|
||||
FILE_NAME. On success, FD is consumed by the library, and the
|
||||
`find_elf' callback will not be used for this module. */
|
||||
program headers in the given file, plus BASE. For an ET_REL file,
|
||||
does a simple absolute section layout starting at BASE.
|
||||
FD may be -1 to open FILE_NAME. On success, FD is consumed by the
|
||||
library, and the `find_elf' callback will not be used for this module. */
|
||||
extern Dwfl_Module *dwfl_report_elf (Dwfl *dwfl, const char *name,
|
||||
const char *file_name, int fd,
|
||||
GElf_Addr base);
|
||||
|
||||
/* Similar, but report the module for offline use. All ET_EXEC files
|
||||
being reported must be reported before any relocatable objects.
|
||||
If this is used, dwfl_report_module and dwfl_report_elf may not be
|
||||
used in the same reporting session. */
|
||||
extern Dwfl_Module *dwfl_report_offline (Dwfl *dwfl, const char *name,
|
||||
const char *file_name, int fd);
|
||||
|
||||
|
||||
/* Finish reporting the current set of modules to the library.
|
||||
If REMOVED is not null, it's called for each module that
|
||||
existed before but was not included in the current report.
|
||||
@@ -150,13 +163,23 @@ extern int dwfl_standard_find_debuginfo (Dwfl_Module *, void **,
|
||||
GElf_Word, char **);
|
||||
|
||||
|
||||
/* This callback must be used when using dwfl_offline_* to report modules,
|
||||
if ET_REL is to be supported. */
|
||||
extern int dwfl_offline_section_address (Dwfl_Module *, void **,
|
||||
const char *, Dwarf_Addr,
|
||||
const char *, Elf32_Word,
|
||||
const GElf_Shdr *,
|
||||
Dwarf_Addr *addr);
|
||||
|
||||
|
||||
/* Callbacks for working with kernel modules in the running Linux kernel. */
|
||||
extern int dwfl_linux_kernel_find_elf (Dwfl_Module *, void **,
|
||||
const char *, Dwarf_Addr,
|
||||
char **, Elf **);
|
||||
extern int dwfl_linux_kernel_module_section_address (Dwfl_Module *, void **,
|
||||
const char *, Dwarf_Addr,
|
||||
const char *,
|
||||
const char *, Elf32_Word,
|
||||
const GElf_Shdr *,
|
||||
Dwarf_Addr *addr);
|
||||
|
||||
/* Call dwfl_report_elf for the running Linux kernel.
|
||||
@@ -169,6 +192,21 @@ extern int dwfl_linux_kernel_report_kernel (Dwfl *dwfl);
|
||||
or an errno code if reading the list of modules failed. */
|
||||
extern int dwfl_linux_kernel_report_modules (Dwfl *dwfl);
|
||||
|
||||
/* Report a kernel and its modules found on disk, for offline use.
|
||||
If RELEASE starts with '/', it names a directory to look in;
|
||||
if not, it names a directory to find under /lib/modules/;
|
||||
if null, /lib/modules/`uname -r` is used.
|
||||
Returns zero on success, -1 if dwfl_report_module failed,
|
||||
or an errno code if finding the files on disk failed.
|
||||
|
||||
If PREDICATE is not null, it is called with each module to be reported;
|
||||
its arguments are the module name, and the ELF file name or null if unknown,
|
||||
and its return value should be zero to skip the module, one to report it,
|
||||
or -1 to cause the call to fail and return errno. */
|
||||
extern int dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
|
||||
int (*predicate) (const char *,
|
||||
const char *));
|
||||
|
||||
|
||||
/* Call dwfl_report_module for each file mapped into the address space of PID.
|
||||
Returns zero on success, -1 if dwfl_report_module failed,
|
||||
@@ -187,6 +225,34 @@ struct argp;
|
||||
extern const struct argp *dwfl_standard_argp (void) __attribute__ ((const));
|
||||
|
||||
|
||||
/*** Relocation of addresses from Dwfl ***/
|
||||
|
||||
/* Return the number of relocatable bases associated with the module,
|
||||
which is zero for ET_EXEC and one for ET_DYN. Returns -1 for errors. */
|
||||
extern int dwfl_module_relocations (Dwfl_Module *mod);
|
||||
|
||||
/* Return the relocation base index associated with the *ADDRESS location,
|
||||
and adjust *ADDRESS to be an offset relative to that base.
|
||||
Returns -1 for errors. */
|
||||
extern int dwfl_module_relocate_address (Dwfl_Module *mod,
|
||||
Dwarf_Addr *address);
|
||||
|
||||
/* Return the ELF section name for the given relocation base index;
|
||||
if SHNDXP is not null, set *SHNDXP to the ELF section index.
|
||||
For ET_DYN, returns "" and sets *SHNDXP to SHN_ABS; the relocation
|
||||
base is the runtime start address reported for the module.
|
||||
Returns null for errors. */
|
||||
extern const char *dwfl_module_relocation_info (Dwfl_Module *mod,
|
||||
unsigned int idx,
|
||||
Elf32_Word *shndxp);
|
||||
|
||||
/* Validate that ADDRESS and ADDRESS+OFFSET lie in a known module
|
||||
and both within the same contiguous region for relocation purposes.
|
||||
Returns zero for success and -1 for errors. */
|
||||
extern int dwfl_validate_address (Dwfl *dwfl,
|
||||
Dwarf_Addr address, Dwarf_Sword offset);
|
||||
|
||||
|
||||
/*** Dwarf access functions ***/
|
||||
|
||||
/* Find the module containing the given address. */
|
||||
@@ -235,6 +301,13 @@ extern Dwarf_Die *dwfl_module_nextcu (Dwfl_Module *mod,
|
||||
extern Dwfl_Module *dwfl_cumodule (Dwarf_Die *cudie);
|
||||
|
||||
|
||||
/* Cache the source line information fo the CU and return the
|
||||
number of Dwfl_Line entries it has. */
|
||||
extern int dwfl_getsrclines (Dwarf_Die *cudie, size_t *nlines);
|
||||
|
||||
/* Access one line number entry within the CU. */
|
||||
extern Dwfl_Line *dwfl_onesrcline (Dwarf_Die *cudie, size_t idx);
|
||||
|
||||
/* Get source for address. */
|
||||
extern Dwfl_Line *dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr);
|
||||
extern Dwfl_Line *dwfl_getsrc (Dwfl *dwfl, Dwarf_Addr addr);
|
||||
|
||||
+12
-2
@@ -71,8 +71,12 @@ struct Dwfl
|
||||
|
||||
Dwfl_Module **modules;
|
||||
size_t nmodules;
|
||||
|
||||
GElf_Addr offline_next_address;
|
||||
};
|
||||
|
||||
#define OFFLINE_REDZONE 0x10000
|
||||
|
||||
struct dwfl_file
|
||||
{
|
||||
char *name;
|
||||
@@ -85,7 +89,7 @@ struct dwfl_file
|
||||
struct Dwfl_Module
|
||||
{
|
||||
Dwfl *dwfl;
|
||||
struct Dwfl_Module *next; /* Link on Dwfl.moduelist. */
|
||||
struct Dwfl_Module *next; /* Link on Dwfl.modulelist. */
|
||||
|
||||
void *userdata;
|
||||
|
||||
@@ -94,9 +98,11 @@ struct Dwfl_Module
|
||||
|
||||
struct dwfl_file main, debug;
|
||||
Ebl *ebl;
|
||||
bool isrel; /* True iff this is an ET_REL file. */
|
||||
GElf_Half e_type; /* GElf_Ehdr.e_type cache. */
|
||||
Dwfl_Error elferr; /* Previous failure to open main file. */
|
||||
|
||||
struct dwfl_relocation *reloc_info; /* Relocatable sections. */
|
||||
|
||||
struct dwfl_file *symfile; /* Either main or debug. */
|
||||
Elf_Data *symdata; /* Data in the ELF symbol table section. */
|
||||
size_t syments; /* sh_size / sh_entsize of that section. */
|
||||
@@ -227,6 +233,7 @@ INTDECL (dwfl_module_getsrc)
|
||||
INTDECL (dwfl_report_elf)
|
||||
INTDECL (dwfl_report_begin)
|
||||
INTDECL (dwfl_report_module)
|
||||
INTDECL (dwfl_report_offline)
|
||||
INTDECL (dwfl_report_end)
|
||||
INTDECL (dwfl_standard_find_debuginfo)
|
||||
INTDECL (dwfl_linux_kernel_find_elf)
|
||||
@@ -235,6 +242,9 @@ INTDECL (dwfl_linux_proc_report)
|
||||
INTDECL (dwfl_linux_proc_find_elf)
|
||||
INTDECL (dwfl_linux_kernel_report_kernel)
|
||||
INTDECL (dwfl_linux_kernel_report_modules)
|
||||
INTDECL (dwfl_linux_kernel_report_offline)
|
||||
INTDECL (dwfl_offline_section_address)
|
||||
INTDECL (dwfl_module_relocate_address)
|
||||
|
||||
/* Leading arguments standard to callbacks passed a Dwfl_Module. */
|
||||
#define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr
|
||||
|
||||
+187
-23
@@ -33,6 +33,28 @@
|
||||
#define SECADDRFMT "/sys/module/%s/sections/%s"
|
||||
|
||||
|
||||
/* Try to open the given file as it is or under the debuginfo directory. */
|
||||
static int
|
||||
try_kernel_name (Dwfl *dwfl, char **fname)
|
||||
{
|
||||
if (*fname == NULL)
|
||||
return -1;
|
||||
|
||||
int fd = TEMP_FAILURE_RETRY (open64 (*fname, O_RDONLY));
|
||||
if (fd < 0)
|
||||
{
|
||||
char *debugfname = NULL;
|
||||
Dwfl_Module fakemod = { .dwfl = dwfl };
|
||||
fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
|
||||
*fname, basename (*fname), 0,
|
||||
&debugfname);
|
||||
free (*fname);
|
||||
*fname = debugfname;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
kernel_release (void)
|
||||
{
|
||||
@@ -43,47 +65,183 @@ kernel_release (void)
|
||||
return utsname.release;
|
||||
}
|
||||
|
||||
/* Find the ELF file for the running kernel and dwfl_report_elf it. */
|
||||
int
|
||||
dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
|
||||
static int
|
||||
report_kernel (Dwfl *dwfl, const char *release,
|
||||
int (*predicate) (const char *module, const char *file))
|
||||
{
|
||||
if (dwfl == NULL)
|
||||
return -1;
|
||||
|
||||
const char *release = kernel_release ();
|
||||
if (release == NULL)
|
||||
return errno;
|
||||
|
||||
char *fname = NULL;
|
||||
asprintf (&fname, "/boot/vmlinux-%s", release);
|
||||
if (fname == NULL)
|
||||
return -1;
|
||||
int fd = open64 (fname, O_RDONLY);
|
||||
if (fd < 0)
|
||||
if (release[0] == '/')
|
||||
asprintf (&fname, "%s/vmlinux", release);
|
||||
else
|
||||
asprintf (&fname, "/boot/vmlinux-%s", release);
|
||||
int fd = try_kernel_name (dwfl, &fname);
|
||||
if (fd < 0 && release[0] != '/')
|
||||
{
|
||||
free (fname);
|
||||
fname = NULL;
|
||||
asprintf (&fname, "/usr/lib/debug" MODULEDIRFMT "/vmlinux", release);
|
||||
if (fname == NULL)
|
||||
return -1;
|
||||
fd = open64 (fname, O_RDONLY);
|
||||
asprintf (&fname, MODULEDIRFMT "/vmlinux", release);
|
||||
fd = try_kernel_name (dwfl, &fname);
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
if (fd < 0)
|
||||
result = errno;
|
||||
else if (INTUSE(dwfl_report_elf) (dwfl, "kernel", fname, fd, 0) == NULL)
|
||||
result = (predicate != NULL && !(*predicate) ("kernel", NULL)) ? 0 : errno;
|
||||
else
|
||||
{
|
||||
close (fd);
|
||||
result = -1;
|
||||
bool report = true;
|
||||
|
||||
if (predicate != NULL)
|
||||
{
|
||||
/* Let the predicate decide whether to use this one. */
|
||||
int want = (*predicate) ("kernel", fname);
|
||||
if (want < 0)
|
||||
result = errno;
|
||||
report = want > 0;
|
||||
}
|
||||
|
||||
if (report
|
||||
&& INTUSE(dwfl_report_elf) (dwfl, "kernel", fname, fd, 0) == NULL)
|
||||
{
|
||||
close (fd);
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
|
||||
free (fname);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Report a kernel and all its modules found on disk, for offline use.
|
||||
If RELEASE starts with '/', it names a directory to look in;
|
||||
if not, it names a directory to find under /lib/modules/;
|
||||
if null, /lib/modules/`uname -r` is used.
|
||||
Returns zero on success, -1 if dwfl_report_module failed,
|
||||
or an errno code if finding the files on disk failed. */
|
||||
int
|
||||
dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
|
||||
int (*predicate) (const char *module,
|
||||
const char *file))
|
||||
{
|
||||
if (release == NULL)
|
||||
{
|
||||
release = kernel_release ();
|
||||
if (release == NULL)
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* First report the kernel. */
|
||||
int result = report_kernel (dwfl, release, predicate);
|
||||
if (result == 0)
|
||||
{
|
||||
/* Do "find /lib/modules/RELEASE/kernel -name *.ko". */
|
||||
|
||||
char *modulesdir[] = { NULL, NULL };
|
||||
if (release[0] == '/')
|
||||
modulesdir[0] = (char *) release;
|
||||
else
|
||||
{
|
||||
asprintf (&modulesdir[0], MODULEDIRFMT "/kernel", release);
|
||||
if (modulesdir[0] == NULL)
|
||||
return errno;
|
||||
}
|
||||
|
||||
FTS *fts = fts_open (modulesdir, FTS_LOGICAL | FTS_NOSTAT, NULL);
|
||||
if (modulesdir[0] == (char *) release)
|
||||
modulesdir[0] = NULL;
|
||||
if (fts == NULL)
|
||||
{
|
||||
free (modulesdir[0]);
|
||||
return errno;
|
||||
}
|
||||
|
||||
FTSENT *f;
|
||||
while ((f = fts_read (fts)) != NULL)
|
||||
{
|
||||
switch (f->fts_info)
|
||||
{
|
||||
case FTS_F:
|
||||
case FTS_NSOK:
|
||||
/* See if this file name matches "*.ko". */
|
||||
if (f->fts_namelen > 3
|
||||
&& !memcmp (f->fts_name + f->fts_namelen - 3, ".ko", 4))
|
||||
{
|
||||
/* We have a .ko file to report. Following the algorithm
|
||||
by which the kernel makefiles set KBUILD_MODNAME, we
|
||||
replace all ',' or '-' with '_' in the file name and
|
||||
call that the module name. Modules could well be
|
||||
built using different embedded names than their file
|
||||
names. To handle that, we would have to look at the
|
||||
__this_module.name contents in the module's text. */
|
||||
|
||||
char name[f->fts_namelen - 3 + 1];
|
||||
for (size_t i = 0; i < f->fts_namelen - 3U; ++i)
|
||||
if (f->fts_name[i] == '-' || f->fts_name[i] == ',')
|
||||
name[i] = '_';
|
||||
else
|
||||
name[i] = f->fts_name[i];
|
||||
name[f->fts_namelen - 3] = '\0';
|
||||
|
||||
if (predicate != NULL)
|
||||
{
|
||||
/* Let the predicate decide whether to use this one. */
|
||||
int want = (*predicate) (name, f->fts_path);
|
||||
if (want < 0)
|
||||
{
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
if (!want)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dwfl_report_offline (dwfl, name,
|
||||
f->fts_path, -1) == NULL)
|
||||
{
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case FTS_ERR:
|
||||
case FTS_DNR:
|
||||
case FTS_NS:
|
||||
result = f->fts_errno;
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We only get here in error cases. */
|
||||
break;
|
||||
}
|
||||
fts_close (fts);
|
||||
free (modulesdir[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
INTDEF (dwfl_linux_kernel_report_offline)
|
||||
|
||||
|
||||
/* Find the ELF file for the running kernel and dwfl_report_elf it. */
|
||||
int
|
||||
dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
|
||||
{
|
||||
const char *release = kernel_release ();
|
||||
if (release == NULL)
|
||||
return errno;
|
||||
|
||||
return report_kernel (dwfl, release, NULL);
|
||||
}
|
||||
INTDEF (dwfl_linux_kernel_report_kernel)
|
||||
|
||||
|
||||
/* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules. */
|
||||
|
||||
int
|
||||
@@ -96,9 +254,9 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
|
||||
{
|
||||
const char *release = kernel_release ();
|
||||
if (release == NULL)
|
||||
return -1;
|
||||
return errno;
|
||||
|
||||
/* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko". */
|
||||
/* Do "find /lib/modules/`uname -r`/kernel -name MODULE_NAME.ko". */
|
||||
|
||||
char *modulesdir[] = { NULL, NULL };
|
||||
asprintf (&modulesdir[0], MODULEDIRFMT "/kernel", release);
|
||||
@@ -165,6 +323,7 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
|
||||
int fd = open64 (f->fts_accpath, O_RDONLY);
|
||||
*file_name = strdup (f->fts_path);
|
||||
fts_close (fts);
|
||||
free (modulesdir[0]);
|
||||
if (fd < 0)
|
||||
free (*file_name);
|
||||
else if (*file_name == NULL)
|
||||
@@ -187,11 +346,14 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
|
||||
}
|
||||
}
|
||||
|
||||
fts_close (fts);
|
||||
free (modulesdir[0]);
|
||||
errno = error;
|
||||
return -1;
|
||||
}
|
||||
INTDEF (dwfl_linux_kernel_find_elf)
|
||||
|
||||
|
||||
/* Dwfl_Callbacks.section_address for kernel modules in the running Linux.
|
||||
We read the information from /sys/module directly. */
|
||||
|
||||
@@ -200,7 +362,9 @@ dwfl_linux_kernel_module_section_address
|
||||
(Dwfl_Module *mod __attribute__ ((unused)),
|
||||
void **userdata __attribute__ ((unused)),
|
||||
const char *modname, Dwarf_Addr base __attribute__ ((unused)),
|
||||
const char *secname, Dwarf_Addr *addr)
|
||||
const char *secname, Elf32_Word shndx __attribute__ ((unused)),
|
||||
const GElf_Shdr *shdr __attribute__ ((unused)),
|
||||
Dwarf_Addr *addr)
|
||||
{
|
||||
char *sysfile = NULL;
|
||||
asprintf (&sysfile, SECADDRFMT, modname, secname);
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/* Recover relocatibility for addresses computed from debug information.
|
||||
Copyright (C) 2005 Red Hat, Inc.
|
||||
|
||||
This program is Open Source software; you can redistribute it and/or
|
||||
modify it under the terms of the Open Software License version 1.0 as
|
||||
published by the Open Source Initiative.
|
||||
|
||||
You should have received a copy of the Open Software License along
|
||||
with this program; if not, you may obtain a copy of the Open Software
|
||||
License version 1.0 from http://www.opensource.org/licenses/osl.php or
|
||||
by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
|
||||
3001 King Ranch Road, Ukiah, CA 95482. */
|
||||
|
||||
#include "libdwflP.h"
|
||||
#include <unistd.h>
|
||||
|
||||
/* Since dwfl_report_elf lays out the sections already, this will only be
|
||||
called when the section headers of the debuginfo file are being
|
||||
consulted instead. With binutils strip-to-debug, the symbol table
|
||||
is in the debuginfo file and relocation looks there. */
|
||||
int
|
||||
dwfl_offline_section_address (Dwfl_Module *mod,
|
||||
void **userdata __attribute__ ((unused)),
|
||||
const char *modname __attribute__ ((unused)),
|
||||
Dwarf_Addr base __attribute__ ((unused)),
|
||||
const char *secname __attribute__ ((unused)),
|
||||
Elf32_Word shndx,
|
||||
const GElf_Shdr *shdr __attribute__ ((unused)),
|
||||
Dwarf_Addr *addr)
|
||||
{
|
||||
assert (mod->symfile != &mod->main);
|
||||
|
||||
GElf_Shdr shdr_mem;
|
||||
GElf_Shdr *main_shdr = gelf_getshdr (elf_getscn (mod->main.elf, shndx),
|
||||
&shdr_mem);
|
||||
if (unlikely (main_shdr == NULL))
|
||||
return -1;
|
||||
|
||||
assert (shdr->sh_addr == 0);
|
||||
assert (shdr->sh_flags & SHF_ALLOC);
|
||||
assert (main_shdr->sh_addr != 0);
|
||||
assert (main_shdr->sh_flags == shdr->sh_flags);
|
||||
|
||||
*addr = main_shdr->sh_addr;
|
||||
return 0;
|
||||
}
|
||||
INTDEF (dwfl_offline_section_address)
|
||||
|
||||
Dwfl_Module *
|
||||
dwfl_report_offline (Dwfl *dwfl, const char *name,
|
||||
const char *file_name, int fd)
|
||||
{
|
||||
if (dwfl == NULL)
|
||||
return NULL;
|
||||
|
||||
Dwfl_Module *mod = INTUSE(dwfl_report_elf) (dwfl, name, file_name, fd,
|
||||
dwfl->offline_next_address);
|
||||
if (mod != NULL)
|
||||
{
|
||||
/* If this is an ET_EXEC file with fixed addresses, the address range
|
||||
it consumed may or may not intersect with the arbitrary range we
|
||||
will use for relocatable modules. Make sure we always use a free
|
||||
range for the offline allocations. */
|
||||
if (dwfl->offline_next_address >= mod->low_addr
|
||||
&& dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
|
||||
dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
|
||||
|
||||
/* Don't keep the file descriptor around. */
|
||||
if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
|
||||
{
|
||||
close (mod->main.fd);
|
||||
mod->main.fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
INTDEF (dwfl_report_offline)
|
||||
+3
-2
@@ -37,7 +37,8 @@ __libdwfl_relocate_value (Dwfl_Module *mod, size_t symshstrndx,
|
||||
if (name == NULL)
|
||||
return DWFL_E_LIBELF;
|
||||
|
||||
if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod), name,
|
||||
if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
|
||||
name, shndx, refshdr,
|
||||
&refshdr->sh_addr))
|
||||
return CBFAIL;
|
||||
|
||||
@@ -63,7 +64,7 @@ Dwfl_Error
|
||||
internal_function_def
|
||||
__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
|
||||
{
|
||||
assert (mod->isrel);
|
||||
assert (mod->e_type == ET_REL);
|
||||
|
||||
GElf_Ehdr ehdr_mem;
|
||||
const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
|
||||
|
||||
@@ -507,13 +507,6 @@ static const int length_map[2][3] =
|
||||
};
|
||||
|
||||
|
||||
struct global_name
|
||||
{
|
||||
Dwarf_Global global;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
global_compare (const void *p1, const void *p2)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
2005-08-22 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* run-line2addr.sh: Add a case.
|
||||
* testfile23.bz2: New data file.
|
||||
* Makefile.am (EXTRA_DIST): Add it.
|
||||
|
||||
2005-08-18 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* run-addrscopes.sh: New file.
|
||||
@@ -51,6 +57,14 @@
|
||||
|
||||
* Makefile.am (dwflmodtest_LDADD): Add $(libebl).
|
||||
|
||||
2005-06-01 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* line2addr.c: Rewritten using libdwfl.
|
||||
* run-line2addr.sh: Update test for changed arguments.
|
||||
* Makefile.am (INCLUDES): Add libdwfl source directory to path.
|
||||
(libdwfl): New variable.
|
||||
(line2addr_LDADD): Use it.
|
||||
|
||||
2005-07-28 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* dwflmodtest.c: New file, moved from ../libdwfl/ptest.c to here.
|
||||
|
||||
+2
-2
@@ -69,7 +69,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
|
||||
testfile18.bz2 testfile19.bz2 testfile19.index.bz2 \
|
||||
testfile20.bz2 testfile20.index.bz2 \
|
||||
testfile21.bz2 testfile21.index.bz2 \
|
||||
testfile22.bz2
|
||||
testfile22.bz2 testfile23.bz2
|
||||
|
||||
if MUDFLAP
|
||||
static_build=yes
|
||||
@@ -111,7 +111,7 @@ get_files_LDADD = $(libdw) $(libelf) $(libmudflap)
|
||||
get_aranges_LDADD = $(libdw) $(libelf) $(libmudflap)
|
||||
allfcts_LDADD = $(libdw) $(libelf) $(libmudflap)
|
||||
line2addr_no_Wformat = yes
|
||||
line2addr_LDADD = $(libdw) $(libelf) $(libmudflap)
|
||||
line2addr_LDADD = $(libdw) $(libmudflap)
|
||||
addrscopes_LDADD = $(libdw) $(libmudflap)
|
||||
#show_ciefde_LDADD = ../libdwarf/libdwarf.so $(libelf) $(libmudflap)
|
||||
asm_tst1_LDADD = $(libasm) $(libebl) $(libelf) $(libmudflap) -ldl
|
||||
|
||||
+103
-42
@@ -1,64 +1,125 @@
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libdw.h>
|
||||
#include <assert.h>
|
||||
#include <libdwfl.h>
|
||||
#include <argp.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <error.h>
|
||||
|
||||
|
||||
static void
|
||||
print_address (Dwfl_Module *mod, Dwarf_Addr address)
|
||||
{
|
||||
int n = dwfl_module_relocations (mod);
|
||||
if (n < 0)
|
||||
error (0, 0, "dwfl_module_relocations: %s", dwfl_errmsg (-1));
|
||||
else if (n > 0)
|
||||
{
|
||||
int i = dwfl_module_relocate_address (mod, &address);
|
||||
if (i < 0)
|
||||
error (0, 0, "dwfl_module_relocate_address: %s", dwfl_errmsg (-1));
|
||||
else
|
||||
{
|
||||
const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL);
|
||||
const char *secname = dwfl_module_relocation_info (mod, i, NULL);
|
||||
if (n > 1 || secname[0] != '\0')
|
||||
printf ("%s(%s)+%#" PRIx64, modname, secname, address);
|
||||
else
|
||||
printf ("%s(%s)+%#" PRIx64, modname, secname, address);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printf ("%#" PRIx64, address);
|
||||
}
|
||||
|
||||
|
||||
struct args
|
||||
{
|
||||
const char *arg;
|
||||
char *file;
|
||||
int line;
|
||||
};
|
||||
|
||||
static int
|
||||
handle_module (Dwfl_Module *mod __attribute__ ((unused)),
|
||||
void **udata __attribute__ ((unused)),
|
||||
const char *modname, Dwarf_Addr base __attribute__ ((unused)),
|
||||
Dwarf *dbg __attribute__ ((unused)),
|
||||
Dwarf_Addr bias __attribute__ ((unused)), void *arg)
|
||||
{
|
||||
const struct args *const a = arg;
|
||||
|
||||
Dwfl_Line **lines = NULL;
|
||||
size_t nlines = 0;
|
||||
|
||||
if (dwfl_module_getsrc_file (mod, a->file, a->line, 0, &lines, &nlines) == 0)
|
||||
{
|
||||
for (size_t inner = 0; inner < nlines; ++inner)
|
||||
{
|
||||
Dwarf_Addr addr;
|
||||
int line = a->line, col = 0;
|
||||
const char *file = dwfl_lineinfo (lines[inner], &addr, &line, &col,
|
||||
NULL, NULL);
|
||||
if (file != NULL)
|
||||
{
|
||||
printf ("%s -> ", a->arg);
|
||||
print_address (mod, addr);
|
||||
if (modname[0] != '\0')
|
||||
printf (" (%s:", modname);
|
||||
if (strcmp (file, a->file) || line != a->line || col != 0)
|
||||
printf (" %s%s:%d", modname[0] != '\0' ? "" : "(",
|
||||
file, line);
|
||||
if (col != 0)
|
||||
printf (":%d");
|
||||
if (modname[0] != '\0'
|
||||
|| strcmp (file, a->file) || line != a->line || col != 0)
|
||||
puts (")");
|
||||
else
|
||||
puts ("");
|
||||
}
|
||||
}
|
||||
free (lines);
|
||||
}
|
||||
|
||||
return DWARF_CB_OK;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
for (int cnt = 1; cnt < argc; ++cnt)
|
||||
{
|
||||
char *fname;
|
||||
char *file;
|
||||
int line;
|
||||
int cnt;
|
||||
|
||||
switch (sscanf (argv[cnt], "%a[^:]:%a[^:]:%d",
|
||||
&fname, &file, &line))
|
||||
/* Set locale. */
|
||||
(void) setlocale (LC_ALL, "");
|
||||
|
||||
Dwfl *dwfl = NULL;
|
||||
(void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &cnt, &dwfl);
|
||||
assert (dwfl != NULL);
|
||||
|
||||
for (; cnt < argc; ++cnt)
|
||||
{
|
||||
struct args a = { .arg = argv[cnt] };
|
||||
|
||||
switch (sscanf (a.arg, "%a[^:]:%d", &a.file, &a.line))
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
case 1:
|
||||
printf ("ignored %s\n", argv[cnt]);
|
||||
continue;
|
||||
case 1:
|
||||
a.line = 0;
|
||||
break;
|
||||
case 2:
|
||||
line = 0;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
}
|
||||
|
||||
int fd = open (fname, O_RDONLY);
|
||||
if (fd == -1)
|
||||
continue;
|
||||
(void) dwfl_getdwarf (dwfl, &handle_module, &a, 0);
|
||||
|
||||
Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ);
|
||||
if (dbg != NULL)
|
||||
{
|
||||
Dwarf_Line **lines = NULL;
|
||||
size_t nlines = 0;
|
||||
|
||||
if (dwarf_getsrc_file (dbg, file, line, 0, &lines, &nlines) == 0)
|
||||
{
|
||||
for (size_t inner = 0; inner < nlines; ++inner)
|
||||
{
|
||||
Dwarf_Addr addr;
|
||||
if (dwarf_lineaddr (lines[inner], &addr) == 0)
|
||||
printf ("%s -> %#" PRIxMAX "\n",
|
||||
argv[cnt], (uintmax_t) addr);
|
||||
}
|
||||
|
||||
free (lines);
|
||||
}
|
||||
|
||||
dwarf_end (dbg);
|
||||
}
|
||||
|
||||
close (fd);
|
||||
free (fname);
|
||||
free (file);
|
||||
free (a.file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+21
-11
@@ -25,20 +25,30 @@ bunzip2 -c $srcdir/testfile8.bz2 > testfile8 2>/dev/null || exit 0
|
||||
# Don't fail if we cannot decompress the file.
|
||||
bunzip2 -c $srcdir/testfile14.bz2 > testfile14 2>/dev/null || exit 0
|
||||
|
||||
./line2addr testfile:f.c:4 testfile:f.c:8 testfile2:m.c:6 testfile2:b.c:1 testfile8:strip.c:953 testfile8:strip.c:365 testfile14:v.c:6 > line2addr.out
|
||||
# Don't fail if we cannot decompress the file.
|
||||
bunzip2 -c $srcdir/testfile23.bz2 > testfile23 2>/dev/null || exit 0
|
||||
|
||||
(./line2addr -e testfile f.c:4 testfile f.c:8
|
||||
./line2addr -e testfile2 m.c:6 b.c:1
|
||||
./line2addr -e testfile8 strip.c:953 strip.c:365
|
||||
./line2addr -e testfile14 v.c:6
|
||||
./line2addr -e testfile23 foo.c:2 foo.c:6
|
||||
) > line2addr.out
|
||||
|
||||
diff -u line2addr.out - <<"EOF"
|
||||
testfile:f.c:4 -> 0x804846b
|
||||
testfile2:m.c:6 -> 0x100004cc
|
||||
testfile2:b.c:1 -> 0x10000470
|
||||
testfile8:strip.c:953 -> 0x169f
|
||||
testfile8:strip.c:953 -> 0x16aa
|
||||
testfile8:strip.c:365 -> 0x278b
|
||||
testfile8:strip.c:365 -> 0x2797
|
||||
testfile14:v.c:6 -> 0x400468
|
||||
testfile14:v.c:6 -> 0x400487
|
||||
f.c:4 -> 0x804846b (/home/drepper/gnu/new-bu/build/ttt/f.c:4)
|
||||
m.c:6 -> 0x100004cc (/shoggoth/drepper/m.c:6)
|
||||
b.c:1 -> 0x10000470 (/shoggoth/drepper/b.c:4)
|
||||
strip.c:953 -> (.text)+0x169f (/home/drepper/gnu/elfutils/build/src/../../src/strip.c:953)
|
||||
strip.c:953 -> (.text)+0x16aa (/home/drepper/gnu/elfutils/build/src/../../src/strip.c:953)
|
||||
strip.c:365 -> (.text)+0x278b (/home/drepper/gnu/elfutils/build/src/../../src/strip.c:365)
|
||||
strip.c:365 -> (.text)+0x2797 (/home/drepper/gnu/elfutils/build/src/../../src/strip.c:365)
|
||||
v.c:6 -> 0x400468 (/home/drepper/local/elfutils-build/20050425/v.c:6)
|
||||
v.c:6 -> 0x400487 (/home/drepper/local/elfutils-build/20050425/v.c:6)
|
||||
foo.c:2 -> (.init.text)+0xc (/home/roland/stock-elfutils-build/foo.c:2)
|
||||
foo.c:6 -> (.text)+0xc (/home/roland/stock-elfutils-build/foo.c:6)
|
||||
EOF
|
||||
|
||||
rm -f testfile testfile2 testfile8 testfile14 line2addr.out
|
||||
rm -f testfile testfile2 testfile8 testfile14 testfile22 line2addr.out
|
||||
|
||||
exit 0
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user