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:
Roland McGrath
2005-08-23 08:20:21 +00:00
parent 3712b288d1
commit d17fac7e89
29 changed files with 1213 additions and 156 deletions
+17
View File
@@ -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
+3 -1
View File
@@ -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
View File
@@ -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;
+16
View File
@@ -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
+30
View File
@@ -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
+103
View File
@@ -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,
+3
View File
@@ -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
View File
@@ -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;
}
+231
View File
@@ -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)
+4 -1
View File
@@ -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;
}
+33
View File
@@ -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;
}
+2
View File
@@ -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)
+24 -8
View File
@@ -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)
+7
View File
@@ -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;
+41
View File
@@ -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
View File
@@ -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
{
+46
View File
@@ -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;
}
+11 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+78
View File
@@ -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
View File
@@ -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);
-7
View File
@@ -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)
{
+14
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.