OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / uClibc / libubacktrace / backtracesyms.c
1 /* Return list with names for address in backtrace.
2    Copyright (C) 1998,1999,2000,2001,2003 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.
20
21    Based on glibc/sysdeps/generic/elf/backtracesyms.c
22
23    Copyright (C) 2010 STMicroelectronics Ltd
24    Author(s): Carmelo Amoroso <carmelo.amoroso@st.com>
25    * Modified to work with uClibc
26      - updated headers inclusion
27      - updated formatting and style
28      - updated to use dladdr from libdl */
29
30 #include <execinfo.h>
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <dlfcn.h>
37 #include <link.h>       /* required for __ELF_NATIVE_CLASS */
38
39 #if __ELF_NATIVE_CLASS == 32
40 # define WORD_WIDTH 8
41 #else
42 /* We assyme 64bits.  */
43 # define WORD_WIDTH 16
44 #endif
45
46
47 char ** backtrace_symbols (void *const *array,  int size)
48 {
49         Dl_info info[size];
50         int status[size];
51         int cnt;
52         size_t total = 0;
53         char **result;
54
55         /* Fill in the information we can get from `dladdr'.  */
56         for (cnt = 0; cnt < size; ++cnt) {
57                 status[cnt] = dladdr (array[cnt], &info[cnt]);
58                 if (status[cnt] && info[cnt].dli_fname &&
59                         info[cnt].dli_fname[0] != '\0')
60                 /*
61                  * We have some info, compute the length of the string which will be
62                  * "<file-name>(<sym-name>) [+offset].
63                  */
64                 total += (strlen (info[cnt].dli_fname ?: "") +
65                                   (info[cnt].dli_sname ?
66                                   strlen (info[cnt].dli_sname) + 3 + WORD_WIDTH + 3 : 1)
67                                   + WORD_WIDTH + 5);
68                 else
69                         total += 5 + WORD_WIDTH;
70         }
71
72         /* Allocate memory for the result.  */
73         result = (char **) malloc (size * sizeof (char *) + total);
74         if (result != NULL) {
75                 char *last = (char *) (result + size);
76                 for (cnt = 0; cnt < size; ++cnt) {
77                         result[cnt] = last;
78
79                         if (status[cnt] && info[cnt].dli_fname
80                                 && info[cnt].dli_fname[0] != '\0') {
81
82                                 char buf[20];
83
84                                 if (array[cnt] >= (void *) info[cnt].dli_saddr)
85                                         sprintf (buf, "+%#lx",
86                                                         (unsigned long)(array[cnt] - info[cnt].dli_saddr));
87                                 else
88                                         sprintf (buf, "-%#lx",
89                                         (unsigned long)(info[cnt].dli_saddr - array[cnt]));
90
91                                 last += 1 + sprintf (last, "%s%s%s%s%s[%p]",
92                                 info[cnt].dli_fname ?: "",
93                                 info[cnt].dli_sname ? "(" : "",
94                                 info[cnt].dli_sname ?: "",
95                                 info[cnt].dli_sname ? buf : "",
96                                 info[cnt].dli_sname ? ") " : " ",
97                                 array[cnt]);
98                         } else
99                                 last += 1 + sprintf (last, "[%p]", array[cnt]);
100                 }
101                 assert (last <= (char *) result + size * sizeof (char *) + total);
102         }
103
104         return result;
105 }