mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
1a61077e0e
commit
e561a9920c
|
|
@ -1,7 +1,39 @@
|
||||||
|
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>
|
2012-10-04 Gerald Pfeifer <gerald@pfeifer.com>
|
||||||
|
|
||||||
* btest.c (f23): Avoid uninitialized variable warning.
|
* btest.c (f23): Avoid uninitialized variable warning.
|
||||||
|
|
||||||
2012-10-04 Ian Lance Taylor <iant@google.com>
|
2012-10-04 Ian Lance Taylor <iant@google.com>
|
||||||
|
|
||||||
* dwarf.c: If the system header files do not declare strnlen,
|
* dwarf.c: If the system header files do not declare strnlen,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@
|
||||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||||
#undef HAVE_DLFCN_H
|
#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 */
|
/* Define to 1 if you have the fcntl function */
|
||||||
#undef HAVE_FCNTL
|
#undef HAVE_FCNTL
|
||||||
|
|
||||||
|
|
@ -19,6 +22,9 @@
|
||||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
#undef HAVE_INTTYPES_H
|
#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. */
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
#undef HAVE_MEMORY_H
|
#undef HAVE_MEMORY_H
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12182,6 +12182,53 @@ if test "$ALLOC_FILE" = "alloc.lo"; then
|
||||||
fi
|
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.
|
# Check for the fcntl function.
|
||||||
if test -n "${with_target_subdir}"; then
|
if test -n "${with_target_subdir}"; then
|
||||||
case "${host}" in
|
case "${host}" in
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,24 @@ if test "$ALLOC_FILE" = "alloc.lo"; then
|
||||||
fi
|
fi
|
||||||
AC_SUBST(BACKTRACE_USES_MALLOC)
|
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.
|
# Check for the fcntl function.
|
||||||
if test -n "${with_target_subdir}"; then
|
if test -n "${with_target_subdir}"; then
|
||||||
case "${host}" in
|
case "${host}" in
|
||||||
|
|
|
||||||
|
|
@ -333,6 +333,10 @@ struct unit_addrs_vector
|
||||||
|
|
||||||
struct dwarf_data
|
struct dwarf_data
|
||||||
{
|
{
|
||||||
|
/* The data for the next file we know about. */
|
||||||
|
struct dwarf_data *next;
|
||||||
|
/* The base address for this file. */
|
||||||
|
uintptr_t base_address;
|
||||||
/* A sorted list of address ranges. */
|
/* A sorted list of address ranges. */
|
||||||
struct unit_addrs *addrs;
|
struct unit_addrs *addrs;
|
||||||
/* Number of address ranges in list. */
|
/* Number of address ranges in list. */
|
||||||
|
|
@ -831,12 +835,18 @@ function_addrs_search (const void *vkey, const void *ventry)
|
||||||
success, 0 on failure. */
|
success, 0 on failure. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
add_unit_addr (struct backtrace_state *state, struct unit_addrs addrs,
|
add_unit_addr (struct backtrace_state *state, uintptr_t base_address,
|
||||||
|
struct unit_addrs addrs,
|
||||||
backtrace_error_callback error_callback, void *data,
|
backtrace_error_callback error_callback, void *data,
|
||||||
struct unit_addrs_vector *vec)
|
struct unit_addrs_vector *vec)
|
||||||
{
|
{
|
||||||
struct unit_addrs *p;
|
struct unit_addrs *p;
|
||||||
|
|
||||||
|
/* Add in the base address of the module here, so that we can look
|
||||||
|
up the PC directly. */
|
||||||
|
addrs.low += base_address;
|
||||||
|
addrs.high += base_address;
|
||||||
|
|
||||||
/* Try to merge with the last entry. */
|
/* Try to merge with the last entry. */
|
||||||
if (vec->count > 0)
|
if (vec->count > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -1156,9 +1166,10 @@ lookup_abbrev (struct abbrevs *abbrevs, uint64_t code,
|
||||||
1 on success, 0 on failure. */
|
1 on success, 0 on failure. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
add_unit_ranges (struct backtrace_state *state, struct unit *u,
|
add_unit_ranges (struct backtrace_state *state, uintptr_t base_address,
|
||||||
uint64_t ranges, uint64_t base, int is_bigendian,
|
struct unit *u, uint64_t ranges, uint64_t base,
|
||||||
const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
|
int is_bigendian, const unsigned char *dwarf_ranges,
|
||||||
|
size_t dwarf_ranges_size,
|
||||||
backtrace_error_callback error_callback, void *data,
|
backtrace_error_callback error_callback, void *data,
|
||||||
struct unit_addrs_vector *addrs)
|
struct unit_addrs_vector *addrs)
|
||||||
{
|
{
|
||||||
|
|
@ -1202,7 +1213,8 @@ add_unit_ranges (struct backtrace_state *state, struct unit *u,
|
||||||
a.low = low + base;
|
a.low = low + base;
|
||||||
a.high = high + base;
|
a.high = high + base;
|
||||||
a.u = u;
|
a.u = u;
|
||||||
if (!add_unit_addr (state, a, error_callback, data, addrs))
|
if (!add_unit_addr (state, base_address, a, error_callback, data,
|
||||||
|
addrs))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1218,7 +1230,7 @@ add_unit_ranges (struct backtrace_state *state, struct unit *u,
|
||||||
on success, 0 on failure. */
|
on success, 0 on failure. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
build_address_map (struct backtrace_state *state,
|
build_address_map (struct backtrace_state *state, uintptr_t base_address,
|
||||||
const unsigned char *dwarf_info, size_t dwarf_info_size,
|
const unsigned char *dwarf_info, size_t dwarf_info_size,
|
||||||
const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size,
|
const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size,
|
||||||
const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
|
const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
|
||||||
|
|
@ -1417,9 +1429,10 @@ build_address_map (struct backtrace_state *state,
|
||||||
|
|
||||||
if (have_ranges)
|
if (have_ranges)
|
||||||
{
|
{
|
||||||
if (!add_unit_ranges (state, u, ranges, lowpc, is_bigendian,
|
if (!add_unit_ranges (state, base_address, u, ranges, lowpc,
|
||||||
dwarf_ranges, dwarf_ranges_size,
|
is_bigendian, dwarf_ranges,
|
||||||
error_callback, data, addrs))
|
dwarf_ranges_size, error_callback, data,
|
||||||
|
addrs))
|
||||||
{
|
{
|
||||||
free_abbrevs (state, &u->abbrevs, error_callback, data);
|
free_abbrevs (state, &u->abbrevs, error_callback, data);
|
||||||
backtrace_free (state, u, sizeof *u, error_callback, data);
|
backtrace_free (state, u, sizeof *u, error_callback, data);
|
||||||
|
|
@ -1434,7 +1447,8 @@ build_address_map (struct backtrace_state *state,
|
||||||
a.high = highpc;
|
a.high = highpc;
|
||||||
a.u = u;
|
a.u = u;
|
||||||
|
|
||||||
if (!add_unit_addr (state, a, error_callback, data, addrs))
|
if (!add_unit_addr (state, base_address, a, error_callback, data,
|
||||||
|
addrs))
|
||||||
{
|
{
|
||||||
free_abbrevs (state, &u->abbrevs, error_callback, data);
|
free_abbrevs (state, &u->abbrevs, error_callback, data);
|
||||||
backtrace_free (state, u, sizeof *u, error_callback, data);
|
backtrace_free (state, u, sizeof *u, error_callback, data);
|
||||||
|
|
@ -1463,8 +1477,9 @@ build_address_map (struct backtrace_state *state,
|
||||||
building. Returns 1 on success, 0 on failure. */
|
building. Returns 1 on success, 0 on failure. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
add_line (struct backtrace_state *state, uintptr_t pc, const char *filename,
|
add_line (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||||
int lineno, backtrace_error_callback error_callback, void *data,
|
uintptr_t pc, const char *filename, int lineno,
|
||||||
|
backtrace_error_callback error_callback, void *data,
|
||||||
struct line_vector *vec)
|
struct line_vector *vec)
|
||||||
{
|
{
|
||||||
struct line *ln;
|
struct line *ln;
|
||||||
|
|
@ -1484,7 +1499,10 @@ add_line (struct backtrace_state *state, uintptr_t pc, const char *filename,
|
||||||
if (ln == NULL)
|
if (ln == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ln->pc = pc;
|
/* Add in the base address here, so that we can look up the PC
|
||||||
|
directly. */
|
||||||
|
ln->pc = pc + ddata->base_address;
|
||||||
|
|
||||||
ln->filename = filename;
|
ln->filename = filename;
|
||||||
ln->lineno = lineno;
|
ln->lineno = lineno;
|
||||||
|
|
||||||
|
|
@ -1672,9 +1690,9 @@ read_line_header (struct backtrace_state *state, struct unit *u,
|
||||||
success, 0 on failure. */
|
success, 0 on failure. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
read_line_program (struct backtrace_state *state, struct unit *u,
|
read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||||
const struct line_header *hdr, struct dwarf_buf *line_buf,
|
struct unit *u, const struct line_header *hdr,
|
||||||
struct line_vector *vec)
|
struct dwarf_buf *line_buf, struct line_vector *vec)
|
||||||
{
|
{
|
||||||
uint64_t address;
|
uint64_t address;
|
||||||
unsigned int op_index;
|
unsigned int op_index;
|
||||||
|
|
@ -1706,8 +1724,8 @@ read_line_program (struct backtrace_state *state, struct unit *u,
|
||||||
/ hdr->max_ops_per_insn);
|
/ hdr->max_ops_per_insn);
|
||||||
op_index = (op_index + advance) % hdr->max_ops_per_insn;
|
op_index = (op_index + advance) % hdr->max_ops_per_insn;
|
||||||
lineno += hdr->line_base + (int) (op % hdr->line_range);
|
lineno += hdr->line_base + (int) (op % hdr->line_range);
|
||||||
add_line (state, address, filename, lineno, line_buf->error_callback,
|
add_line (state, ddata, address, filename, lineno,
|
||||||
line_buf->data, vec);
|
line_buf->error_callback, line_buf->data, vec);
|
||||||
}
|
}
|
||||||
else if (op == DW_LNS_extended_op)
|
else if (op == DW_LNS_extended_op)
|
||||||
{
|
{
|
||||||
|
|
@ -1795,7 +1813,7 @@ read_line_program (struct backtrace_state *state, struct unit *u,
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case DW_LNS_copy:
|
case DW_LNS_copy:
|
||||||
add_line (state, address, filename, lineno,
|
add_line (state, ddata, address, filename, lineno,
|
||||||
line_buf->error_callback, line_buf->data, vec);
|
line_buf->error_callback, line_buf->data, vec);
|
||||||
break;
|
break;
|
||||||
case DW_LNS_advance_pc:
|
case DW_LNS_advance_pc:
|
||||||
|
|
@ -1923,7 +1941,7 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||||
if (!read_line_header (state, u, is_dwarf64, &line_buf, hdr))
|
if (!read_line_header (state, u, is_dwarf64, &line_buf, hdr))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (!read_line_program (state, u, hdr, &line_buf, &vec))
|
if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (line_buf.reported_underflow)
|
if (line_buf.reported_underflow)
|
||||||
|
|
@ -2076,13 +2094,18 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
|
||||||
success, 0 on error. */
|
success, 0 on error. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
add_function_range (struct backtrace_state *state, struct function *function,
|
add_function_range (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||||
uint64_t lowpc, uint64_t highpc,
|
struct function *function, uint64_t lowpc, uint64_t highpc,
|
||||||
backtrace_error_callback error_callback,
|
backtrace_error_callback error_callback,
|
||||||
void *data, struct function_vector *vec)
|
void *data, struct function_vector *vec)
|
||||||
{
|
{
|
||||||
struct function_addrs *p;
|
struct function_addrs *p;
|
||||||
|
|
||||||
|
/* Add in the base address here, so that we can look up the PC
|
||||||
|
directly. */
|
||||||
|
lowpc += ddata->base_address;
|
||||||
|
highpc += ddata->base_address;
|
||||||
|
|
||||||
if (vec->count > 0)
|
if (vec->count > 0)
|
||||||
{
|
{
|
||||||
p = (struct function_addrs *) vec->vec.base + vec->count - 1;
|
p = (struct function_addrs *) vec->vec.base + vec->count - 1;
|
||||||
|
|
@ -2153,8 +2176,8 @@ add_function_ranges (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||||
base = high;
|
base = high;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!add_function_range (state, function, low + base, high + base,
|
if (!add_function_range (state, ddata, function, low + base,
|
||||||
error_callback, data, vec))
|
high + base, error_callback, data, vec))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2364,7 +2387,7 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||||
{
|
{
|
||||||
if (highpc_is_relative)
|
if (highpc_is_relative)
|
||||||
highpc += lowpc;
|
highpc += lowpc;
|
||||||
if (!add_function_range (state, function, lowpc, highpc,
|
if (!add_function_range (state, ddata, function, lowpc, highpc,
|
||||||
error_callback, data, vec))
|
error_callback, data, vec))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -2522,15 +2545,17 @@ report_inlined_functions (uintptr_t pc, struct function *function,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the file/line information for a PC using the DWARF mapping
|
/* Look for a PC in the DWARF mapping for one module. On success,
|
||||||
we built earlier. */
|
call CALLBACK and return whatever it returns. On error, call
|
||||||
|
ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found,
|
||||||
|
0 if not. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
|
dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||||
backtrace_full_callback callback,
|
uintptr_t pc, backtrace_full_callback callback,
|
||||||
backtrace_error_callback error_callback, void *data)
|
backtrace_error_callback error_callback, void *data,
|
||||||
|
int *found)
|
||||||
{
|
{
|
||||||
struct dwarf_data *ddata;
|
|
||||||
struct unit_addrs *entry;
|
struct unit_addrs *entry;
|
||||||
struct unit *u;
|
struct unit *u;
|
||||||
int new_data;
|
int new_data;
|
||||||
|
|
@ -2542,14 +2567,17 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
|
||||||
int lineno;
|
int lineno;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ddata = (struct dwarf_data *) state->fileline_data;
|
*found = 1;
|
||||||
|
|
||||||
/* Find an address range that includes PC. */
|
/* Find an address range that includes PC. */
|
||||||
entry = bsearch (&pc, ddata->addrs, ddata->addrs_count,
|
entry = bsearch (&pc, ddata->addrs, ddata->addrs_count,
|
||||||
sizeof (struct unit_addrs), unit_addrs_search);
|
sizeof (struct unit_addrs), unit_addrs_search);
|
||||||
|
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
return callback (data, pc, NULL, 0, NULL);
|
{
|
||||||
|
*found = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* If there are multiple ranges that contain PC, use the last one,
|
/* If there are multiple ranges that contain PC, use the last one,
|
||||||
in order to produce predictable results. If we assume that all
|
in order to produce predictable results. If we assume that all
|
||||||
|
|
@ -2656,7 +2684,8 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
|
||||||
try again to see if there is a better compilation unit for
|
try again to see if there is a better compilation unit for
|
||||||
this PC. */
|
this PC. */
|
||||||
if (new_data)
|
if (new_data)
|
||||||
dwarf_fileline (state, pc, callback, error_callback, data);
|
return dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
|
||||||
|
data, found);
|
||||||
return callback (data, pc, NULL, 0, NULL);
|
return callback (data, pc, NULL, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2705,39 +2734,93 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
|
||||||
return callback (data, pc, filename, lineno, function->name);
|
return callback (data, pc, filename, lineno, function->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build our data structures from the .debug_info and .debug_line
|
|
||||||
sections. Set *FILELINE_FN and *FILELINE_DATA. Return 1 on
|
|
||||||
success, 0 on failure. */
|
|
||||||
|
|
||||||
int
|
/* Return the file/line information for a PC using the DWARF mapping
|
||||||
backtrace_dwarf_initialize (struct backtrace_state *state,
|
we built earlier. */
|
||||||
const unsigned char *dwarf_info,
|
|
||||||
size_t dwarf_info_size,
|
static int
|
||||||
const unsigned char *dwarf_line,
|
dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
|
||||||
size_t dwarf_line_size,
|
backtrace_full_callback callback,
|
||||||
const unsigned char *dwarf_abbrev,
|
backtrace_error_callback error_callback, void *data)
|
||||||
size_t dwarf_abbrev_size,
|
{
|
||||||
const unsigned char *dwarf_ranges,
|
struct dwarf_data *ddata;
|
||||||
size_t dwarf_ranges_size,
|
int found;
|
||||||
const unsigned char *dwarf_str,
|
int ret;
|
||||||
size_t dwarf_str_size,
|
|
||||||
int is_bigendian,
|
if (!state->threaded)
|
||||||
backtrace_error_callback error_callback,
|
{
|
||||||
void *data, fileline *fileline_fn)
|
for (ddata = (struct dwarf_data *) state->fileline_data;
|
||||||
|
ddata != NULL;
|
||||||
|
ddata = ddata->next)
|
||||||
|
{
|
||||||
|
ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
|
||||||
|
data, &found);
|
||||||
|
if (ret != 0 || found)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct dwarf_data **pp;
|
||||||
|
|
||||||
|
pp = (struct dwarf_data **) &state->fileline_data;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
ddata = *pp;
|
||||||
|
/* Atomic load. */
|
||||||
|
while (!__sync_bool_compare_and_swap (pp, ddata, ddata))
|
||||||
|
ddata = *pp;
|
||||||
|
|
||||||
|
if (ddata == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
|
||||||
|
data, &found);
|
||||||
|
if (ret != 0 || found)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
pp = &ddata->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: See if any libraries have been dlopen'ed. */
|
||||||
|
|
||||||
|
return callback (data, pc, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize our data structures from the DWARF debug info for a
|
||||||
|
file. Return NULL on failure. */
|
||||||
|
|
||||||
|
static struct dwarf_data *
|
||||||
|
build_dwarf_data (struct backtrace_state *state,
|
||||||
|
uintptr_t base_address,
|
||||||
|
const unsigned char *dwarf_info,
|
||||||
|
size_t dwarf_info_size,
|
||||||
|
const unsigned char *dwarf_line,
|
||||||
|
size_t dwarf_line_size,
|
||||||
|
const unsigned char *dwarf_abbrev,
|
||||||
|
size_t dwarf_abbrev_size,
|
||||||
|
const unsigned char *dwarf_ranges,
|
||||||
|
size_t dwarf_ranges_size,
|
||||||
|
const unsigned char *dwarf_str,
|
||||||
|
size_t dwarf_str_size,
|
||||||
|
int is_bigendian,
|
||||||
|
backtrace_error_callback error_callback,
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
struct unit_addrs_vector addrs_vec;
|
struct unit_addrs_vector addrs_vec;
|
||||||
struct unit_addrs *addrs;
|
struct unit_addrs *addrs;
|
||||||
size_t addrs_count;
|
size_t addrs_count;
|
||||||
struct dwarf_data *fdata;
|
struct dwarf_data *fdata;
|
||||||
|
|
||||||
if (!build_address_map (state, dwarf_info, dwarf_info_size, dwarf_abbrev,
|
if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size,
|
||||||
dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size,
|
dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges,
|
||||||
dwarf_str, dwarf_str_size, is_bigendian,
|
dwarf_ranges_size, dwarf_str, dwarf_str_size,
|
||||||
error_callback, data, &addrs_vec))
|
is_bigendian, error_callback, data, &addrs_vec))
|
||||||
return 0;
|
return NULL;
|
||||||
|
|
||||||
if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data))
|
if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data))
|
||||||
return 0;
|
return NULL;
|
||||||
addrs = (struct unit_addrs *) addrs_vec.vec.base;
|
addrs = (struct unit_addrs *) addrs_vec.vec.base;
|
||||||
addrs_count = addrs_vec.count;
|
addrs_count = addrs_vec.count;
|
||||||
qsort (addrs, addrs_count, sizeof (struct unit_addrs), unit_addrs_compare);
|
qsort (addrs, addrs_count, sizeof (struct unit_addrs), unit_addrs_compare);
|
||||||
|
|
@ -2746,8 +2829,10 @@ backtrace_dwarf_initialize (struct backtrace_state *state,
|
||||||
backtrace_alloc (state, sizeof (struct dwarf_data),
|
backtrace_alloc (state, sizeof (struct dwarf_data),
|
||||||
error_callback, data));
|
error_callback, data));
|
||||||
if (fdata == NULL)
|
if (fdata == NULL)
|
||||||
return 0;
|
return NULL;
|
||||||
|
|
||||||
|
fdata->next = NULL;
|
||||||
|
fdata->base_address = base_address;
|
||||||
fdata->addrs = addrs;
|
fdata->addrs = addrs;
|
||||||
fdata->addrs_count = addrs_count;
|
fdata->addrs_count = addrs_count;
|
||||||
fdata->dwarf_info = dwarf_info;
|
fdata->dwarf_info = dwarf_info;
|
||||||
|
|
@ -2761,7 +2846,77 @@ backtrace_dwarf_initialize (struct backtrace_state *state,
|
||||||
fdata->is_bigendian = is_bigendian;
|
fdata->is_bigendian = is_bigendian;
|
||||||
memset (&fdata->fvec, 0, sizeof fdata->fvec);
|
memset (&fdata->fvec, 0, sizeof fdata->fvec);
|
||||||
|
|
||||||
state->fileline_data = fdata;
|
return fdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build our data structures from the DWARF sections for a module.
|
||||||
|
Set FILELINE_FN and STATE->FILELINE_DATA. Return 1 on success, 0
|
||||||
|
on failure. */
|
||||||
|
|
||||||
|
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,
|
||||||
|
size_t dwarf_line_size,
|
||||||
|
const unsigned char *dwarf_abbrev,
|
||||||
|
size_t dwarf_abbrev_size,
|
||||||
|
const unsigned char *dwarf_ranges,
|
||||||
|
size_t dwarf_ranges_size,
|
||||||
|
const unsigned char *dwarf_str,
|
||||||
|
size_t dwarf_str_size,
|
||||||
|
int is_bigendian,
|
||||||
|
backtrace_error_callback error_callback,
|
||||||
|
void *data, fileline *fileline_fn)
|
||||||
|
{
|
||||||
|
struct dwarf_data *fdata;
|
||||||
|
|
||||||
|
fdata = build_dwarf_data (state, base_address, dwarf_info, dwarf_info_size,
|
||||||
|
dwarf_line, dwarf_line_size, dwarf_abbrev,
|
||||||
|
dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size,
|
||||||
|
dwarf_str, dwarf_str_size, is_bigendian,
|
||||||
|
error_callback, data);
|
||||||
|
if (fdata == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!state->threaded)
|
||||||
|
{
|
||||||
|
struct dwarf_data **pp;
|
||||||
|
|
||||||
|
for (pp = (struct dwarf_data **) &state->fileline_data;
|
||||||
|
*pp != NULL;
|
||||||
|
pp = &(*pp)->next)
|
||||||
|
;
|
||||||
|
*pp = fdata;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
struct dwarf_data **pp;
|
||||||
|
|
||||||
|
pp = (struct dwarf_data **) &state->fileline_data;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
struct dwarf_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, fdata))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*fileline_fn = dwarf_fileline;
|
*fileline_fn = dwarf_fileline;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,36 @@ POSSIBILITY OF SUCH DAMAGE. */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_DL_ITERATE_PHDR
|
||||||
|
#include <link.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "backtrace.h"
|
#include "backtrace.h"
|
||||||
#include "internal.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
|
/* 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,
|
ELF. We could make this code test and support either possibility,
|
||||||
but there is no point. This code only works for the currently
|
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"
|
#error "Unknown BACKTRACE_ELF_SIZE"
|
||||||
#endif
|
#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. */
|
/* Basic types. */
|
||||||
|
|
||||||
typedef uint16_t Elf_Half;
|
typedef uint16_t Elf_Half;
|
||||||
|
|
@ -214,6 +268,8 @@ struct elf_symbol
|
||||||
|
|
||||||
struct elf_syminfo_data
|
struct elf_syminfo_data
|
||||||
{
|
{
|
||||||
|
/* Symbols for the next module. */
|
||||||
|
struct elf_syminfo_data *next;
|
||||||
/* The ELF symbols, sorted by address. */
|
/* The ELF symbols, sorted by address. */
|
||||||
struct elf_symbol *symbols;
|
struct elf_symbol *symbols;
|
||||||
/* The number of 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),
|
qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),
|
||||||
elf_symbol_compare);
|
elf_symbol_compare);
|
||||||
|
|
||||||
|
sdata->next = NULL;
|
||||||
sdata->symbols = elf_symbols;
|
sdata->symbols = elf_symbols;
|
||||||
sdata->count = elf_symbol_count;
|
sdata->count = elf_symbol_count;
|
||||||
|
|
||||||
return 1;
|
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. */
|
/* Return the symbol name and value for a PC. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -364,14 +466,12 @@ elf_syminfo (struct backtrace_state *state, uintptr_t pc,
|
||||||
callback (data, pc, sym->name, sym->address);
|
callback (data, pc, sym->name, sym->address);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the backtrace data we need from an ELF executable. At
|
/* Add the backtrace data for one ELF file. */
|
||||||
the ELF level, all we need to do is find the debug info
|
|
||||||
sections. */
|
|
||||||
|
|
||||||
int
|
static int
|
||||||
backtrace_initialize (struct backtrace_state *state, int descriptor,
|
elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
|
||||||
backtrace_error_callback error_callback,
|
backtrace_error_callback error_callback, void *data,
|
||||||
void *data, fileline *fileline_fn)
|
fileline *fileline_fn, int *found_sym, int *found_dwarf)
|
||||||
{
|
{
|
||||||
struct backtrace_view ehdr_view;
|
struct backtrace_view ehdr_view;
|
||||||
Elf_Ehdr ehdr;
|
Elf_Ehdr ehdr;
|
||||||
|
|
@ -400,6 +500,9 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
|
||||||
struct backtrace_view debug_view;
|
struct backtrace_view debug_view;
|
||||||
int debug_view_valid;
|
int debug_view_valid;
|
||||||
|
|
||||||
|
*found_sym = 0;
|
||||||
|
*found_dwarf = 0;
|
||||||
|
|
||||||
shdrs_view_valid = 0;
|
shdrs_view_valid = 0;
|
||||||
names_view_valid = 0;
|
names_view_valid = 0;
|
||||||
symtab_view_valid = 0;
|
symtab_view_valid = 0;
|
||||||
|
|
@ -516,6 +619,8 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
|
||||||
dynsym_shndx = 0;
|
dynsym_shndx = 0;
|
||||||
|
|
||||||
memset (sections, 0, sizeof sections);
|
memset (sections, 0, sizeof sections);
|
||||||
|
|
||||||
|
/* Look for the symbol table. */
|
||||||
for (i = 1; i < shnum; ++i)
|
for (i = 1; i < shnum; ++i)
|
||||||
{
|
{
|
||||||
const Elf_Shdr *shdr;
|
const Elf_Shdr *shdr;
|
||||||
|
|
@ -552,12 +657,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
|
||||||
|
|
||||||
if (symtab_shndx == 0)
|
if (symtab_shndx == 0)
|
||||||
symtab_shndx = dynsym_shndx;
|
symtab_shndx = dynsym_shndx;
|
||||||
if (symtab_shndx == 0)
|
if (symtab_shndx != 0)
|
||||||
{
|
|
||||||
state->syminfo_fn = elf_nosyms;
|
|
||||||
state->syminfo_data = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
const Elf_Shdr *symtab_shdr;
|
const Elf_Shdr *symtab_shdr;
|
||||||
unsigned int strtab_shndx;
|
unsigned int strtab_shndx;
|
||||||
|
|
@ -604,8 +704,9 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
|
||||||
string table permanently. */
|
string table permanently. */
|
||||||
backtrace_release_view (state, &symtab_view, error_callback, data);
|
backtrace_release_view (state, &symtab_view, error_callback, data);
|
||||||
|
|
||||||
state->syminfo_fn = elf_syminfo;
|
*found_sym = 1;
|
||||||
state->syminfo_data = sdata;
|
|
||||||
|
elf_add_syminfo_data (state, sdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Need to handle compressed debug sections. */
|
/* 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))
|
if (!backtrace_close (descriptor, error_callback, data))
|
||||||
goto fail;
|
goto fail;
|
||||||
*fileline_fn = elf_nodebug;
|
*fileline_fn = elf_nodebug;
|
||||||
state->fileline_data = NULL;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -654,21 +754,23 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
|
||||||
sections[i].data = ((const unsigned char *) debug_view.data
|
sections[i].data = ((const unsigned char *) debug_view.data
|
||||||
+ (sections[i].offset - min_offset));
|
+ (sections[i].offset - min_offset));
|
||||||
|
|
||||||
if (!backtrace_dwarf_initialize (state,
|
if (!backtrace_dwarf_add (state, base_address,
|
||||||
sections[DEBUG_INFO].data,
|
sections[DEBUG_INFO].data,
|
||||||
sections[DEBUG_INFO].size,
|
sections[DEBUG_INFO].size,
|
||||||
sections[DEBUG_LINE].data,
|
sections[DEBUG_LINE].data,
|
||||||
sections[DEBUG_LINE].size,
|
sections[DEBUG_LINE].size,
|
||||||
sections[DEBUG_ABBREV].data,
|
sections[DEBUG_ABBREV].data,
|
||||||
sections[DEBUG_ABBREV].size,
|
sections[DEBUG_ABBREV].size,
|
||||||
sections[DEBUG_RANGES].data,
|
sections[DEBUG_RANGES].data,
|
||||||
sections[DEBUG_RANGES].size,
|
sections[DEBUG_RANGES].size,
|
||||||
sections[DEBUG_STR].data,
|
sections[DEBUG_STR].data,
|
||||||
sections[DEBUG_STR].size,
|
sections[DEBUG_STR].size,
|
||||||
ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
|
ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
|
||||||
error_callback, data, fileline_fn))
|
error_callback, data, fileline_fn))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
*found_dwarf = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|
@ -686,3 +788,115 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
|
||||||
backtrace_close (descriptor, error_callback, data);
|
backtrace_close (descriptor, error_callback, data);
|
||||||
return 0;
|
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,21 +215,22 @@ extern int backtrace_initialize (struct backtrace_state *state,
|
||||||
void *data,
|
void *data,
|
||||||
fileline *fileline_fn);
|
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,
|
||||||
const unsigned char* dwarf_info,
|
uintptr_t base_address,
|
||||||
size_t dwarf_info_size,
|
const unsigned char* dwarf_info,
|
||||||
const unsigned char *dwarf_line,
|
size_t dwarf_info_size,
|
||||||
size_t dwarf_line_size,
|
const unsigned char *dwarf_line,
|
||||||
const unsigned char *dwarf_abbrev,
|
size_t dwarf_line_size,
|
||||||
size_t dwarf_abbrev_size,
|
const unsigned char *dwarf_abbrev,
|
||||||
const unsigned char *dwarf_ranges,
|
size_t dwarf_abbrev_size,
|
||||||
size_t dwarf_range_size,
|
const unsigned char *dwarf_ranges,
|
||||||
const unsigned char *dwarf_str,
|
size_t dwarf_range_size,
|
||||||
size_t dwarf_str_size,
|
const unsigned char *dwarf_str,
|
||||||
int is_bigendian,
|
size_t dwarf_str_size,
|
||||||
backtrace_error_callback error_callback,
|
int is_bigendian,
|
||||||
void *data, fileline *fileline_fn);
|
backtrace_error_callback error_callback,
|
||||||
|
void *data, fileline *fileline_fn);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue