(__backtrace_symbols): Minimal cleanups. Add assert to ensure memory
[kopensolaris-gnu/glibc.git] / sysdeps / generic / elf / backtracesyms.c
1 /* Return list with names for address in backtrace.
2    Copyright (C) 1998, 1999, 2000, 2001 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 Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    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    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <assert.h>
22 #include <execinfo.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <ldsodefs.h>
28
29 #if __ELF_NATIVE_CLASS == 32
30 # define WORD_WIDTH 8
31 #else
32 /* We assyme 64bits.  */
33 # define WORD_WIDTH 16
34 #endif
35
36
37 char **
38 __backtrace_symbols (array, size)
39      void *const *array;
40      int size;
41 {
42   Dl_info info[size];
43   int status[size];
44   int cnt;
45   size_t total = 0;
46   char **result;
47
48   /* Fill in the information we can get from `dladdr'.  */
49   for (cnt = 0; cnt < size; ++cnt)
50     {
51       status[cnt] = _dl_addr (array[cnt], &info[cnt]);
52       if (status[cnt] && info[cnt].dli_fname && info[cnt].dli_fname[0] != '\0')
53         /* We have some info, compute the length of the string which will be
54            "<file-name>(<sym-name>) [+offset].  */
55         total += (strlen (info[cnt].dli_fname ?: "")
56                   + (info[cnt].dli_sname
57                      ? strlen (info[cnt].dli_sname) + 3 + WORD_WIDTH + 3
58                      : 1)
59                   + WORD_WIDTH + 5);
60       else
61         total += 5 + WORD_WIDTH;
62     }
63
64   /* Allocate memory for the result.  */
65   result = (char **) malloc (size * sizeof (char *) + total);
66   if (result != NULL)
67     {
68       char *last = (char *) (result + size);
69
70       for (cnt = 0; cnt < size; ++cnt)
71         {
72           result[cnt] = last;
73
74           if (status[cnt] && info[cnt].dli_fname
75               && info[cnt].dli_fname[0] != '\0')
76             {
77               char buf[20];
78
79               if (array[cnt] >= (void *) info[cnt].dli_saddr)
80                 sprintf (buf, "+%#lx",
81                          (unsigned long)(array[cnt] - info[cnt].dli_saddr));
82               else
83                 sprintf (buf, "-%#lx",
84                          (unsigned long)(info[cnt].dli_saddr - array[cnt]));
85
86               last += 1 + sprintf (last, "%s%s%s%s%s[%p]",
87                                    info[cnt].dli_fname ?: "",
88                                    info[cnt].dli_sname ? "(" : "",
89                                    info[cnt].dli_sname ?: "",
90                                    info[cnt].dli_sname ? buf : "",
91                                    info[cnt].dli_sname ? ") " : " ",
92                                    array[cnt]);
93             }
94           else
95             last += 1 + sprintf (last, "[%p]", array[cnt]);
96         }
97       assert (last <= (char *) result + size * sizeof (char *) + total);
98     }
99
100   return result;
101 }
102 weak_alias (__backtrace_symbols, backtrace_symbols)