backtrace->contains_function takes multiple names, speeding up whitelist check drasti...
[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
16 #define _GNU_SOURCE
17
18 #ifdef HAVE_DLADDR
19 # include <dlfcn.h>
20 #endif /* HAVE_DLADDR */
21
22 #ifdef HAVE_BACKTRACE
23 # include <execinfo.h>
24 #endif /* HAVE_BACKTRACE */
25
26 #include <string.h>
27
28 #include "backtrace.h"
29
30 typedef struct private_backtrace_t private_backtrace_t;
31
32 /**
33 * Private data of an backtrace_t object.
34 */
35 struct private_backtrace_t {
36
37 /**
38 * Public backtrace_t interface.
39 */
40 backtrace_t public;
41
42 /**
43 * Number of stacks frames obtained in stack_frames
44 */
45 int frame_count;
46
47 /**
48 * Recorded stack frames.
49 */
50 void *frames[];
51 };
52
53 /**
54 * Implementation of backtrace_t.log
55 */
56 static void log_(private_backtrace_t *this, FILE *file, bool detailed)
57 {
58 #ifdef HAVE_BACKTRACE
59 size_t i;
60 char **strings;
61
62 strings = backtrace_symbols(this->frames, this->frame_count);
63
64 fprintf(file, " dumping %d stack frame addresses:\n", this->frame_count);
65 for (i = 0; i < this->frame_count; i++)
66 {
67 #ifdef HAVE_DLADDR
68 Dl_info info;
69
70 if (dladdr(this->frames[i], &info))
71 {
72 char cmd[1024];
73 FILE *output;
74 int c;
75 void *ptr = this->frames[i];
76
77 if (strstr(info.dli_fname, ".so"))
78 {
79 ptr = (void*)(this->frames[i] - info.dli_fbase);
80 }
81 if (info.dli_sname)
82 {
83 fprintf(file, " \e[33m%s\e[0m @ %p (\e[31m%s\e[0m+0x%x) [%p]\n",
84 info.dli_fname, info.dli_fbase, info.dli_sname,
85 this->frames[i] - info.dli_saddr, this->frames[i]);
86 }
87 else
88 {
89 fprintf(file, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname,
90 info.dli_fbase, this->frames[i]);
91 }
92 if (detailed)
93 {
94 fprintf(file, " -> \e[32m");
95 snprintf(cmd, sizeof(cmd), "addr2line -e %s %p",
96 info.dli_fname, ptr);
97 output = popen(cmd, "r");
98 if (output)
99 {
100 while (TRUE)
101 {
102 c = getc(output);
103 if (c == '\n' || c == EOF)
104 {
105 break;
106 }
107 fputc(c, file);
108 }
109 pclose(output);
110 }
111 else
112 {
113 #endif /* HAVE_DLADDR */
114 fprintf(file, " %s\n", strings[i]);
115 #ifdef HAVE_DLADDR
116 }
117 fprintf(file, "\n\e[0m");
118 }
119 }
120 else
121 {
122 fprintf(file, " %s\n", strings[i]);
123 }
124 #endif /* HAVE_DLADDR */
125 }
126 free (strings);
127 #else /* !HAVE_BACKTRACE */
128 fprintf(file, "C library does not support backtrace().\n");
129 #endif /* HAVE_BACKTRACE */
130 }
131
132 /**
133 * Implementation of backtrace_t.contains_function
134 */
135 static bool contains_function(private_backtrace_t *this,
136 char *function[], int count)
137 {
138 #ifdef HAVE_DLADDR
139 int i, j;
140
141 for (i = 0; i< this->frame_count; i++)
142 {
143 Dl_info info;
144
145 if (dladdr(this->frames[i], &info) && info.dli_sname)
146 {
147 for (j = 0; j < count; j++)
148 {
149 if (streq(info.dli_sname, function[j]))
150 {
151 return TRUE;
152 }
153 }
154 }
155 }
156 #endif /* HAVE_DLADDR */
157 return FALSE;
158 }
159
160 /**
161 * Implementation of backtrace_t.destroy.
162 */
163 static void destroy(private_backtrace_t *this)
164 {
165 free(this);
166 }
167
168 /**
169 * See header
170 */
171 backtrace_t *backtrace_create(int skip)
172 {
173 private_backtrace_t *this;
174 void *frames[50];
175 int frame_count = 0;
176
177 #ifdef HAVE_BACKTRACE
178 frame_count = backtrace(frames, countof(frames));
179 #endif /* HAVE_BACKTRACE */
180 frame_count = max(frame_count - skip, 0);
181 this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
182 memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
183 this->frame_count = frame_count;
184
185 this->public.log = (void(*)(backtrace_t*,FILE*,bool))log_;
186 this->public.contains_function = (bool(*)(backtrace_t*, char *function[], int count))contains_function;
187 this->public.destroy = (void(*)(backtrace_t*))destroy;
188
189 return &this->public;
190 }
191