aboutsummaryrefslogtreecommitdiff
path: root/debug/backtracesyms.c
diff options
context:
space:
mode:
Diffstat (limited to 'debug/backtracesyms.c')
-rw-r--r--debug/backtracesyms.c81
1 files changed, 73 insertions, 8 deletions
diff --git a/debug/backtracesyms.c b/debug/backtracesyms.c
index a010664..3fabf26 100644
--- a/debug/backtracesyms.c
+++ b/debug/backtracesyms.c
@@ -1,5 +1,5 @@
/* Return list with names for address in backtrace.
- Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1998-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -17,13 +17,20 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <assert.h>
#include <execinfo.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ldsodefs.h>
-/* Assume the worst for the width of an address. */
-#define WORD_WIDTH 16
+#if __ELF_NATIVE_CLASS == 32
+# define WORD_WIDTH 8
+#else
+/* We assyme 64bits. */
+# define WORD_WIDTH 16
+#endif
char **
@@ -31,16 +38,37 @@ __backtrace_symbols (array, size)
void *const *array;
int size;
{
+ Dl_info info[size];
+ int status[size];
int cnt;
size_t total = 0;
char **result;
- /* We can compute the text size needed for the symbols since we print
- them all as "[+0x<addr>]". */
- total = size * (WORD_WIDTH + 6);
+ /* Fill in the information we can get from `dladdr'. */
+ for (cnt = 0; cnt < size; ++cnt)
+ {
+ struct link_map *map;
+ status[cnt] = _dl_addr (array[cnt], &info[cnt], &map, NULL);
+ if (status[cnt] && info[cnt].dli_fname && info[cnt].dli_fname[0] != '\0')
+ {
+ /* We have some info, compute the length of the string which will be
+ "<file-name>(<sym-name>+offset) [address]. */
+ total += (strlen (info[cnt].dli_fname ?: "")
+ + strlen (info[cnt].dli_sname ?: "")
+ + 3 + WORD_WIDTH + 3 + WORD_WIDTH + 5);
+
+ /* The load bias is more useful to the user than the load
+ address. The use of these addresses is to calculate an
+ address in the ELF file, so its prelinked bias is not
+ something we want to subtract out. */
+ info[cnt].dli_fbase = (void *) map->l_addr;
+ }
+ else
+ total += 5 + WORD_WIDTH;
+ }
/* Allocate memory for the result. */
- result = malloc (size * sizeof (char *) + total);
+ result = (char **) malloc (size * sizeof (char *) + total);
if (result != NULL)
{
char *last = (char *) (result + size);
@@ -48,8 +76,45 @@ __backtrace_symbols (array, size)
for (cnt = 0; cnt < size; ++cnt)
{
result[cnt] = last;
- last += 1 + sprintf (last, "[+%p]", array[cnt]);
+
+ if (status[cnt]
+ && info[cnt].dli_fname != NULL && info[cnt].dli_fname[0] != '\0')
+ {
+ if (info[cnt].dli_sname == NULL)
+ /* We found no symbol name to use, so describe it as
+ relative to the file. */
+ info[cnt].dli_saddr = info[cnt].dli_fbase;
+
+ if (info[cnt].dli_sname == NULL && info[cnt].dli_saddr == 0)
+ last += 1 + sprintf (last, "%s(%s) [%p]",
+ info[cnt].dli_fname ?: "",
+ info[cnt].dli_sname ?: "",
+ array[cnt]);
+ else
+ {
+ char sign;
+ ptrdiff_t offset;
+ if (array[cnt] >= (void *) info[cnt].dli_saddr)
+ {
+ sign = '+';
+ offset = array[cnt] - info[cnt].dli_saddr;
+ }
+ else
+ {
+ sign = '-';
+ offset = info[cnt].dli_saddr - array[cnt];
+ }
+
+ last += 1 + sprintf (last, "%s(%s%c%#tx) [%p]",
+ info[cnt].dli_fname ?: "",
+ info[cnt].dli_sname ?: "",
+ sign, offset, array[cnt]);
+ }
+ }
+ else
+ last += 1 + sprintf (last, "[%p]", array[cnt]);
}
+ assert (last <= (char *) result + size * sizeof (char *) + total);
}
return result;