Coverity: Core module errors fixed
[scilab.git] / scilab / modules / core / src / c / backtrace.c
1 /*
2   Copyright (C) 2006  EDF - Code Saturne
3   Copyright (C) 2011 - DIGITEO - Sylvestre LEDRU. Adapted for Scilab
4   Copyright (C) 2011 - DIGITEO - Bruno JOFRET. Trace parse algorithm rewrite.
5
6   This 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   This 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 this library; if not, write to the Free Software
18   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20
21 #include <assert.h>//
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "machine.h"
28 #include "sci_malloc.h"
29
30 #if defined(HAVE_GLIBC_BACKTRACE)
31 #include <memory.h>
32 #include <execinfo.h>
33 #endif
34
35 #if defined(HAVE_GLIBC_BACKTRACE) && defined(__GNUC__)
36 #define _GNU_SOURCE
37 #endif
38
39 #define __USE_GNU
40 #ifndef _MSC_VER
41 #include <dlfcn.h>
42 #endif
43
44 #include "backtrace.h"
45
46 /*-----------------------------------------------------------------------------
47  * Local type definitions
48  *-----------------------------------------------------------------------------*/
49
50 /*
51  * BFT backtrace descriptor
52  */
53
54 struct _sci_backtrace_t
55 {
56
57     int size;               /* Total depth of backtrace */
58
59     char **s_file;          /* File names */
60     char **s_func;          /* Function names */
61     char **s_addr;          /* Addresses */
62
63 };
64
65 /* Associated typedef documentation (for backtrace.h) */
66
67 /*============================================================================
68  * Public function definitions
69  *============================================================================*/
70
71 /*
72  * Build a backtrace description structure.
73  *
74  * @return pointer to sci_backtrace_t backtrace descriptor (NULL in case of
75  *         error, or if backtracing is unavailable on this architecture).
76  */
77
78 sci_backtrace_t *sci_backtrace_create(void)
79 {
80 #if defined(HAVE_GLIBC_BACKTRACE)
81
82     sci_backtrace_t *bt = NULL;
83
84     /* Create backtrace structure */
85
86     bt = malloc(sizeof(sci_backtrace_t));
87
88     if (bt != NULL)
89     {
90
91         void * tr_array[200];
92         int tr_size = backtrace(tr_array, 200);
93         int i = 0;
94         Dl_info * infos = NULL;
95
96         /* Create arrays; we use malloc() here instead of BFT_MALLOC, as a
97           * backtrace is useful mainly in case of severe errors, so we avoid
98           * higher level constructs as much as possible at this stage. */
99
100         if (tr_size < 2)// || tr_strings == NULL)
101         {
102             free(bt);
103             return NULL;
104         }
105
106         bt->size = tr_size;
107
108         bt->s_file = malloc(tr_size * sizeof(char *));
109         bt->s_func = malloc(tr_size * sizeof(char *));
110         bt->s_addr = malloc(tr_size * sizeof(char *));
111
112         /* If allocation has failed, free other allocated arrays, and return NULL */
113
114         if (bt->s_file == NULL || bt->s_func == NULL || bt->s_addr == NULL)
115         {
116
117             if (bt->s_file != NULL)
118             {
119                 free(bt->s_file);
120             }
121             if (bt->s_func != NULL)
122             {
123                 free(bt->s_func);
124             }
125             if (bt->s_addr != NULL)
126             {
127                 free(bt->s_addr);
128             }
129
130             free(bt);
131             return NULL;
132
133         }
134
135         infos = (Dl_info *)MALLOC(sizeof(Dl_info));
136
137         for (i = 0; i < bt->size; i++)
138         {
139             char buffer[32];
140             void * p = tr_array[i];
141
142             bt->s_file[i] = NULL;
143             bt->s_func[i] = NULL;
144             bt->s_addr[i] = NULL;
145
146             if (dladdr(p, infos))
147             {
148                 bt->s_func[i] = infos->dli_sname ? strdup(infos->dli_sname) : strdup(" ");
149                 bt->s_file[i] = infos->dli_fname ? strdup(infos->dli_fname) : strdup(" ");
150
151                 // we calculate the relative address in the library
152                 snprintf(buffer, 32, "%p", (void*)(p - infos->dli_fbase));
153                 bt->s_addr[i] = strdup(buffer);
154             }
155         }
156
157         FREE(infos);
158         infos = NULL;
159     }
160
161     return bt;
162
163 #else /* defined(HAVE_GLIBC_BACKTRACE) */
164     return NULL;
165 #endif
166 }
167
168 /*
169  * Free a backtrace description structure.
170  *
171  * @param [in, out] bt pointer to backtrace description structure.
172  * @return NULL pointer.
173  */
174
175 sci_backtrace_t *sci_backtrace_destroy(sci_backtrace_t * bt)
176 {
177     int i;
178
179     if (bt != NULL)
180     {
181
182         for (i = 0; i < bt->size; i++)
183         {
184
185             if (bt->s_file[i] != NULL)
186             {
187                 free(bt->s_file[i]);
188             }
189             if (bt->s_func[i] != NULL)
190             {
191                 free(bt->s_func[i]);
192             }
193             if (bt->s_addr[i] != NULL)
194             {
195                 free(bt->s_addr[i]);
196             }
197
198         }
199
200         if (bt->s_file != NULL)
201         {
202             free(bt->s_file);
203         }
204         if (bt->s_func != NULL)
205         {
206             free(bt->s_func);
207         }
208         if (bt->s_addr != NULL)
209         {
210             free(bt->s_addr);
211         }
212
213         free(bt);
214
215     }
216
217     return NULL;
218 }
219
220 /*
221  * Demangle a backtrace description structure (for C++).
222  *
223  * @param [in, out] bt pointer to backtrace description structure.
224  */
225
226 void sci_backtrace_demangle(sci_backtrace_t * bt)
227 {
228 #if defined(HAVE_GLIBC_BACKTRACE) && defined(HAVE_CPLUS_DEMANGLE)
229     int i, l;
230
231     if (bt != NULL)
232     {
233         for (i = 0; i < bt->size; i++)
234         {
235
236             char *s_cplus_func_p = NULL;
237             char *s_cplus_func = NULL;
238             size_t funcnamesize = 0;
239             int status = 0;
240
241             if (bt->s_func[i] == NULL)
242             {
243                 continue;
244             }
245
246             s_cplus_func_p = sci_demangle(bt->s_func[i], NULL, &funcnamesize, &status);
247
248             if (s_cplus_func_p == NULL)
249             {
250                 continue;
251             }
252
253             if (status)
254             {
255                 free(s_cplus_func_p);
256                 continue;
257             }
258
259             l = strlen(s_cplus_func_p);
260
261             if (l == 0)
262             {
263                 free(s_cplus_func_p);
264                 continue;
265             }
266
267             s_cplus_func = malloc(l + 1);
268
269             if (s_cplus_func != NULL)
270             {
271                 strncpy(s_cplus_func, s_cplus_func_p, l + 1);
272                 s_cplus_func[l] = '\0';
273                 free(bt->s_func[i]);
274                 bt->s_func[i] = s_cplus_func;
275             }
276
277             free(s_cplus_func_p);
278         }
279
280     }
281
282 #endif /* defined(HAVE_GLIBC_BACKTRACE) && defined(HAVE_CPLUS_DEMANGLE) */
283 }
284
285 /*
286  * Return the depth of a backtrace.
287  *
288  * @param [in] bt pointer to backtrace description structure.
289  * @return backtrace depth.
290  */
291
292 int sci_backtrace_size(const sci_backtrace_t * bt)
293 {
294     return bt->size;
295 }
296
297 /*
298  * Return file name associated with a backtrace at a given depth.
299  *
300  * @param [in] bt pointer to backtrace description structure.
301  * @param [in] depth index in backtrace structure (< sci_backtrace_size(bt)).
302  * @return file name at the given depth, or NULL.
303  */
304
305 const char *sci_backtrace_file(sci_backtrace_t * bt, int depth)
306 {
307     const char *retval = NULL;
308
309     if (bt != NULL)
310     {
311         if (depth < bt->size)
312         {
313             retval = bt->s_file[depth];
314         }
315     }
316
317     return retval;
318 }
319
320 /*
321  * Return function name associated with a backtrace at a given depth.
322  *
323  * @param [in] bt pointer to backtrace description structure.
324  * @param [in] depth index in backtrace structure (< sci_backtrace_size(bt)).
325  * @return function name at the given depth, or NULL.
326  */
327
328 const char *sci_backtrace_function(sci_backtrace_t * bt, int depth)
329 {
330     const char *retval = NULL;
331
332     if (bt != NULL)
333     {
334         if (depth < bt->size)
335         {
336             retval = bt->s_func[depth];
337         }
338     }
339
340     return retval;
341 }
342
343 /*
344  * Return address associated with a backtrace at a given depth.
345  *
346  * @param [in] bt pointer to backtrace description structure.
347  * @param [in] depth index in backtrace structure (< sci_backtrace_size(bt)).
348  * @return  address at the given depth, or NULL.
349  */
350
351 const char *sci_backtrace_address(sci_backtrace_t * bt, int depth)
352 {
353     const char *retval = NULL;
354
355     if (bt != NULL)
356     {
357         if (depth < bt->size)
358         {
359             retval = bt->s_addr[depth];
360         }
361     }
362
363     return retval;
364 }