Commit e561a992 by Ian Lance Taylor Committed by Ian Lance Taylor

Add support for tracing through shared libraries.

	* configure.ac: Check for link.h and dl_iterate_phdr.
	* elf.c: #include <link.h> if system has dl_iterate_phdr.  #undef
	ELF macros before #defining them.
	(dl_phdr_info, dl_iterate_phdr): Define if system does not have
	dl_iterate_phdr.
	(struct elf_syminfo_data): Add next field.
	(elf_initialize_syminfo): Initialize next field.
	(elf_add_syminfo_data): New static function.
	(elf_add): New static function, broken out of
	backtrace_initialize.  Call backtrace_dwarf_add instead of
	backtrace_dwarf_initialize.
	(struct phdr_data): Define.
	(phdr_callback): New static function.
	(backtrace_initialize): Call elf_add.
	* dwarf.c (struct dwarf_data): Add next and base_address fields.
	(add_unit_addr): Add base_address parameter.  Change all callers.
	(add_unit_ranges, build_address_map): Likewise.
	(add_line): Add ddata parameter.  Change all callers.
	(read_line_program, add_function_range): Likewise.
	(dwarf_lookup_pc): New static function, broken out of
	dwarf_fileline.
	(dwarf_fileline): Call dwarf_lookup_pc.
	(build_dwarf_data): New static function.
	(backtrace_dwarf_add): New function.
	(backtrace_dwarf_initialize): Remove.
	* internal.h (backtrace_dwarf_initialize): Don't declare.
	(backtrace_dwarf_add): Declare.
	* configure, config.h.in: Rebuild.

From-SVN: r192267
parent 1a61077e
2012-10-09 Ian Lance Taylor <iant@google.com>
Add support for tracing through shared libraries.
* configure.ac: Check for link.h and dl_iterate_phdr.
* elf.c: #include <link.h> if system has dl_iterate_phdr. #undef
ELF macros before #defining them.
(dl_phdr_info, dl_iterate_phdr): Define if system does not have
dl_iterate_phdr.
(struct elf_syminfo_data): Add next field.
(elf_initialize_syminfo): Initialize next field.
(elf_add_syminfo_data): New static function.
(elf_add): New static function, broken out of
backtrace_initialize. Call backtrace_dwarf_add instead of
backtrace_dwarf_initialize.
(struct phdr_data): Define.
(phdr_callback): New static function.
(backtrace_initialize): Call elf_add.
* dwarf.c (struct dwarf_data): Add next and base_address fields.
(add_unit_addr): Add base_address parameter. Change all callers.
(add_unit_ranges, build_address_map): Likewise.
(add_line): Add ddata parameter. Change all callers.
(read_line_program, add_function_range): Likewise.
(dwarf_lookup_pc): New static function, broken out of
dwarf_fileline.
(dwarf_fileline): Call dwarf_lookup_pc.
(build_dwarf_data): New static function.
(backtrace_dwarf_add): New function.
(backtrace_dwarf_initialize): Remove.
* internal.h (backtrace_dwarf_initialize): Don't declare.
(backtrace_dwarf_add): Declare.
* configure, config.h.in: Rebuild.
2012-10-04 Gerald Pfeifer <gerald@pfeifer.com>
* btest.c (f23): Avoid uninitialized variable warning.
......
......@@ -10,6 +10,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define if dl_iterate_phdr is available. */
#undef HAVE_DL_ITERATE_PHDR
/* Define to 1 if you have the fcntl function */
#undef HAVE_FCNTL
......@@ -19,6 +22,9 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <link.h> header file. */
#undef HAVE_LINK_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
......
......@@ -12182,6 +12182,53 @@ if test "$ALLOC_FILE" = "alloc.lo"; then
fi
# Check for dl_iterate_phdr.
for ac_header in link.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "link.h" "ac_cv_header_link_h" "$ac_includes_default"
if test "x$ac_cv_header_link_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LINK_H 1
_ACEOF
fi
done
if test "$ac_cv_header_link_h" = "no"; then
have_dl_iterate_phdr=no
else
if test -n "${with_target_subdir}"; then
# When built as a GCC target library, we can't do a link test.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <link.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "dl_iterate_phdr" >/dev/null 2>&1; then :
have_dl_iterate_phdr=yes
else
have_dl_iterate_phdr=no
fi
rm -f conftest*
else
ac_fn_c_check_func "$LINENO" "dl_iterate_phdr" "ac_cv_func_dl_iterate_phdr"
if test "x$ac_cv_func_dl_iterate_phdr" = x""yes; then :
have_dl_iterate_phdr=yes
else
have_dl_iterate_phdr=no
fi
fi
fi
if test "$have_dl_iterate_phdr" = "yes"; then
$as_echo "#define HAVE_DL_ITERATE_PHDR 1" >>confdefs.h
fi
# Check for the fcntl function.
if test -n "${with_target_subdir}"; then
case "${host}" in
......
......@@ -226,6 +226,24 @@ if test "$ALLOC_FILE" = "alloc.lo"; then
fi
AC_SUBST(BACKTRACE_USES_MALLOC)
# Check for dl_iterate_phdr.
AC_CHECK_HEADERS(link.h)
if test "$ac_cv_header_link_h" = "no"; then
have_dl_iterate_phdr=no
else
if test -n "${with_target_subdir}"; then
# When built as a GCC target library, we can't do a link test.
AC_EGREP_HEADER([dl_iterate_phdr], [link.h], [have_dl_iterate_phdr=yes],
[have_dl_iterate_phdr=no])
else
AC_CHECK_FUNC([dl_iterate_phdr], [have_dl_iterate_phdr=yes],
[have_dl_iterate_phdr=no])
fi
fi
if test "$have_dl_iterate_phdr" = "yes"; then
AC_DEFINE(HAVE_DL_ITERATE_PHDR, 1, [Define if dl_iterate_phdr is available.])
fi
# Check for the fcntl function.
if test -n "${with_target_subdir}"; then
case "${host}" in
......
......@@ -36,9 +36,36 @@ POSSIBILITY OF SUCH DAMAGE. */
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_DL_ITERATE_PHDR
#include <link.h>
#endif
#include "backtrace.h"
#include "internal.h"
#ifndef HAVE_DL_ITERATE_PHDR
/* Dummy version of dl_iterate_phdr for systems that don't have it. */
#define dl_phdr_info x_dl_phdr_info
#define dl_iterate_phdr x_dl_iterate_phdr
struct dl_phdr_info
{
uintptr_t dlpi_addr;
const char *dlpi_name;
};
static int
dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
size_t, void *) ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
return 0;
}
#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */
/* The configure script must tell us whether we are 32-bit or 64-bit
ELF. We could make this code test and support either possibility,
but there is no point. This code only works for the currently
......@@ -49,6 +76,33 @@ POSSIBILITY OF SUCH DAMAGE. */
#error "Unknown BACKTRACE_ELF_SIZE"
#endif
/* <link.h> might #include <elf.h> which might define our constants
with slightly different values. Undefine them to be safe. */
#undef EI_NIDENT
#undef EI_MAG0
#undef EI_MAG1
#undef EI_MAG2
#undef EI_MAG3
#undef EI_CLASS
#undef EI_DATA
#undef EI_VERSION
#undef ELF_MAG0
#undef ELF_MAG1
#undef ELF_MAG2
#undef ELF_MAG3
#undef ELFCLASS32
#undef ELFCLASS64
#undef ELFDATA2LSB
#undef ELFDATA2MSB
#undef EV_CURRENT
#undef SHN_LORESERVE
#undef SHN_XINDEX
#undef SHT_SYMTAB
#undef SHT_STRTAB
#undef SHT_DYNSYM
#undef STT_FUNC
/* Basic types. */
typedef uint16_t Elf_Half;
......@@ -214,6 +268,8 @@ struct elf_symbol
struct elf_syminfo_data
{
/* Symbols for the next module. */
struct elf_syminfo_data *next;
/* The ELF symbols, sorted by address. */
struct elf_symbol *symbols;
/* The number of symbols. */
......@@ -337,12 +393,58 @@ elf_initialize_syminfo (struct backtrace_state *state,
qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),
elf_symbol_compare);
sdata->next = NULL;
sdata->symbols = elf_symbols;
sdata->count = elf_symbol_count;
return 1;
}
/* Add EDATA to the list in STATE. */
static void
elf_add_syminfo_data (struct backtrace_state *state,
struct elf_syminfo_data *edata)
{
if (!state->threaded)
{
struct elf_syminfo_data **pp;
for (pp = (struct elf_syminfo_data **) &state->syminfo_data;
*pp != NULL;
pp = &(*pp)->next)
;
*pp = edata;
}
else
{
while (1)
{
struct elf_syminfo_data **pp;
pp = (struct elf_syminfo_data **) &state->syminfo_data;
while (1)
{
struct elf_syminfo_data *p;
/* Atomic load. */
p = *pp;
while (!__sync_bool_compare_and_swap (pp, p, p))
p = *pp;
if (p == NULL)
break;
pp = &p->next;
}
if (__sync_bool_compare_and_swap (pp, NULL, edata))
break;
}
}
}
/* Return the symbol name and value for a PC. */
static void
......@@ -364,14 +466,12 @@ elf_syminfo (struct backtrace_state *state, uintptr_t pc,
callback (data, pc, sym->name, sym->address);
}
/* Initialize the backtrace data we need from an ELF executable. At
the ELF level, all we need to do is find the debug info
sections. */
/* Add the backtrace data for one ELF file. */
int
backtrace_initialize (struct backtrace_state *state, int descriptor,
backtrace_error_callback error_callback,
void *data, fileline *fileline_fn)
static int
elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
backtrace_error_callback error_callback, void *data,
fileline *fileline_fn, int *found_sym, int *found_dwarf)
{
struct backtrace_view ehdr_view;
Elf_Ehdr ehdr;
......@@ -400,6 +500,9 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
struct backtrace_view debug_view;
int debug_view_valid;
*found_sym = 0;
*found_dwarf = 0;
shdrs_view_valid = 0;
names_view_valid = 0;
symtab_view_valid = 0;
......@@ -516,6 +619,8 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
dynsym_shndx = 0;
memset (sections, 0, sizeof sections);
/* Look for the symbol table. */
for (i = 1; i < shnum; ++i)
{
const Elf_Shdr *shdr;
......@@ -552,12 +657,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
if (symtab_shndx == 0)
symtab_shndx = dynsym_shndx;
if (symtab_shndx == 0)
{
state->syminfo_fn = elf_nosyms;
state->syminfo_data = NULL;
}
else
if (symtab_shndx != 0)
{
const Elf_Shdr *symtab_shdr;
unsigned int strtab_shndx;
......@@ -604,8 +704,9 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
string table permanently. */
backtrace_release_view (state, &symtab_view, error_callback, data);
state->syminfo_fn = elf_syminfo;
state->syminfo_data = sdata;
*found_sym = 1;
elf_add_syminfo_data (state, sdata);
}
/* FIXME: Need to handle compressed debug sections. */
......@@ -635,7 +736,6 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
if (!backtrace_close (descriptor, error_callback, data))
goto fail;
*fileline_fn = elf_nodebug;
state->fileline_data = NULL;
return 1;
}
......@@ -654,7 +754,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
sections[i].data = ((const unsigned char *) debug_view.data
+ (sections[i].offset - min_offset));
if (!backtrace_dwarf_initialize (state,
if (!backtrace_dwarf_add (state, base_address,
sections[DEBUG_INFO].data,
sections[DEBUG_INFO].size,
sections[DEBUG_LINE].data,
......@@ -669,6 +769,8 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
error_callback, data, fileline_fn))
goto fail;
*found_dwarf = 1;
return 1;
fail:
......@@ -686,3 +788,115 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
backtrace_close (descriptor, error_callback, data);
return 0;
}
/* Data passed to phdr_callback. */
struct phdr_data
{
struct backtrace_state *state;
backtrace_error_callback error_callback;
void *data;
fileline *fileline_fn;
int *found_sym;
int *found_dwarf;
};
/* Callback passed to dl_iterate_phdr. Load debug info from shared
libraries. */
static int
phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
void *pdata)
{
struct phdr_data *pd = (struct phdr_data *) pdata;
int descriptor;
fileline elf_fileline_fn;
int found_dwarf;
/* There is not much we can do if we don't have the module name. If
the base address is 0, this is probably the executable, which we
already loaded. */
if (info->dlpi_name == NULL
|| info->dlpi_name[0] == '\0'
|| info->dlpi_addr == 0)
return 0;
descriptor = backtrace_open (info->dlpi_name, pd->error_callback, pd->data);
if (descriptor < 0)
return 0;
if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback,
pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf))
{
if (found_dwarf)
{
*pd->found_dwarf = 1;
*pd->fileline_fn = elf_fileline_fn;
}
}
return 0;
}
/* Initialize the backtrace data we need from an ELF executable. At
the ELF level, all we need to do is find the debug info
sections. */
int
backtrace_initialize (struct backtrace_state *state, int descriptor,
backtrace_error_callback error_callback,
void *data, fileline *fileline_fn)
{
int found_sym;
int found_dwarf;
syminfo elf_syminfo_fn;
fileline elf_fileline_fn;
struct phdr_data pd;
if (!elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
&found_sym, &found_dwarf))
return 0;
pd.state = state;
pd.error_callback = error_callback;
pd.data = data;
pd.fileline_fn = fileline_fn;
pd.found_sym = &found_sym;
pd.found_dwarf = &found_dwarf;
dl_iterate_phdr (phdr_callback, (void *) &pd);
elf_syminfo_fn = found_sym ? elf_syminfo : elf_nosyms;
if (!state->threaded)
{
if (state->syminfo_fn == NULL || found_sym)
state->syminfo_fn = elf_syminfo_fn;
}
else
{
__sync_bool_compare_and_swap (&state->syminfo_fn, NULL, elf_syminfo_fn);
if (found_sym)
__sync_bool_compare_and_swap (&state->syminfo_fn, elf_nosyms,
elf_syminfo_fn);
}
if (!state->threaded)
{
if (state->fileline_fn == NULL || state->fileline_fn == elf_nodebug)
*fileline_fn = elf_fileline_fn;
}
else
{
fileline current_fn;
/* Atomic load. */
current_fn = state->fileline_fn;
while (!__sync_bool_compare_and_swap (&state->fileline_fn, current_fn,
current_fn))
current_fn = state->fileline_fn;
if (current_fn == NULL || current_fn == elf_nodebug)
*fileline_fn = elf_fileline_fn;
}
return 1;
}
......@@ -215,9 +215,10 @@ extern int backtrace_initialize (struct backtrace_state *state,
void *data,
fileline *fileline_fn);
/* Prepare to read file/line information from DWARF debug data. */
/* Add file/line information for a DWARF module. */
extern int backtrace_dwarf_initialize (struct backtrace_state *state,
extern int backtrace_dwarf_add (struct backtrace_state *state,
uintptr_t base_address,
const unsigned char* dwarf_info,
size_t dwarf_info_size,
const unsigned char *dwarf_line,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment