pluto uses the libstrongswan leak detective and a stripped-down version of library_t
[strongswan.git] / src / libstrongswan / utils / backtrace.c
1 /*
2 * Copyright (C) 2006-2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #define _GNU_SOURCE
19
20 #ifdef HAVE_DLADDR
21 # include <dlfcn.h>
22 #endif /* HAVE_DLADDR */
23
24 #ifdef HAVE_BACKTRACE
25 # include <execinfo.h>
26 #endif /* HAVE_BACKTRACE */
27
28 #include <string.h>
29
30 #include "backtrace.h"
31
32 typedef struct private_backtrace_t private_backtrace_t;
33
34 /**
35 * Private data of an backtrace_t object.
36 */
37 struct private_backtrace_t {
38
39 /**
40 * Public backtrace_t interface.
41 */
42 backtrace_t public;
43
44 /**
45 * Number of stacks frames obtained in stack_frames
46 */
47 int frame_count;
48
49 /**
50 * Recorded stack frames.
51 */
52 void *frames[];
53 };
54
55 /**
56 * Implementation of backtrace_t.log
57 */
58 static void log_(private_backtrace_t *this, FILE *file)
59 {
60 #ifdef HAVE_BACKTRACE
61 size_t i;
62 char **strings;
63
64 strings = backtrace_symbols(this->frames, this->frame_count);
65
66 fprintf(file, " dumping %d stack frame addresses:\n", this->frame_count);
67 for (i = 0; i < this->frame_count; i++)
68 {
69 #ifdef HAVE_DLADDR
70 Dl_info info;
71
72 if (dladdr(this->frames[i], &info))
73 {
74 char cmd[1024];
75 FILE *output;
76 char c;
77 void *ptr = this->frames[i];
78
79 if (strstr(info.dli_fname, ".so"))
80 {
81 ptr = (void*)(this->frames[i] - info.dli_fbase);
82 }
83 snprintf(cmd, sizeof(cmd), "addr2line -e %s %p", info.dli_fname, ptr);
84 if (info.dli_sname)
85 {
86 fprintf(file, " \e[33m%s\e[0m @ %p (\e[31m%s\e[0m+0x%x) [%p]\n",
87 info.dli_fname, info.dli_fbase, info.dli_sname,
88 this->frames[i] - info.dli_saddr, this->frames[i]);
89 }
90 else
91 {
92 fprintf(file, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname,
93 info.dli_fbase, this->frames[i]);
94 }
95 fprintf(file, " -> \e[32m");
96 output = popen(cmd, "r");
97 if (output)
98 {
99 while (TRUE)
100 {
101 c = getc(output);
102 if (c == '\n' || c == EOF)
103 {
104 break;
105 }
106 fputc(c, file);
107 }
108 pclose(output);
109 }
110 else
111 {
112 #endif /* HAVE_DLADDR */
113 fprintf(file, " %s\n", strings[i]);
114 #ifdef HAVE_DLADDR
115 }
116 fprintf(file, "\n\e[0m");
117 }
118 else
119 {
120 fprintf(file, " %s\n", strings[i]);
121 }
122 #endif /* HAVE_DLADDR */
123 }
124 free (strings);
125 #else /* !HAVE_BACKTRACE */
126 fprintf(file, "C library does not support backtrace().\n");
127 #endif /* HAVE_BACKTRACE */
128 }
129
130 /**
131 * Implementation of backtrace_t.contains_function
132 */
133 static bool contains_function(private_backtrace_t *this, char *function)
134 {
135 #ifdef HAVE_DLADDR
136 int i;
137
138 for (i = 0; i< this->frame_count; i++)
139 {
140 Dl_info info;
141
142 if (dladdr(this->frames[i], &info) && info.dli_sname)
143 {
144 if (streq(info.dli_sname, function))
145 {
146 return TRUE;
147 }
148 }
149 }
150 #endif /* HAVE_DLADDR */
151 return FALSE;
152 }
153
154 /**
155 * Implementation of backtrace_t.destroy.
156 */
157 static void destroy(private_backtrace_t *this)
158 {
159 free(this);
160 }
161
162 /**
163 * See header
164 */
165 backtrace_t *backtrace_create(int skip)
166 {
167 private_backtrace_t *this;
168 void *frames[50];
169 int frame_count = 0;
170
171 #ifdef HAVE_BACKTRACE
172 frame_count = backtrace(frames, countof(frames));
173 #endif /* HAVE_BACKTRACE */
174 frame_count = max(frame_count - skip, 0);
175 this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
176 memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
177 this->frame_count = frame_count;
178
179 this->public.log = (void(*)(backtrace_t*,FILE*))log_;
180 this->public.contains_function = (bool(*)(backtrace_t*, char *function))contains_function;
181 this->public.destroy = (void(*)(backtrace_t*))destroy;
182
183 return &this->public;
184 }
185