]> git.cworth.org Git - apitrace/blob - common/trace_backtrace.cpp
Backtrace via call detail
[apitrace] / common / trace_backtrace.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013 Samsung
4  * Contributed by Eugene Velesevich
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 /*
28  *  Wrapper for platform-specific code for obtaining symbolic backtraces
29  *  on Android and Linux
30  */
31
32
33
34 #include "trace_backtrace.hpp"
35
36 #if defined(ANDROID) or defined(__linux__)
37
38 #include <set>
39 #include "os.hpp"
40
41
42 namespace trace {
43
44 /*
45  * Pascal string (with zero terminator optionally omitted)
46  * This is a helper class for storing a set of exact strings or prefixes
47  * to match a zero-terminated string against later.
48  * Two zero-terminated pstrings compare equal iff they are the same.
49  * Otherwise, they compare equal iff one is a prefix of the other
50  * (a zero-terminated pstring cannot be a prefix)
51  */
52
53 struct pstring {
54     const char* s;
55     int n;
56     pstring(const char* s, int n)
57     {
58         this->s = s;
59         this->n = n;
60     }
61     bool operator<(const pstring q2) const
62     {
63         return memcmp(s, q2.s, n < q2.n? n : q2.n) < 0;
64     }
65 };
66
67
68 #define PREFIX_BUF_SIZE (PREFIX_MAX_FUNC_NAME * MAX_BT_FUNC)
69
70 class StringPrefixes {
71 private:
72     std::set<pstring> pset;
73     char* buf;
74 private:
75     void addPrefix(char* startbuf, int n) {
76         std::set<pstring>::iterator elem = pset.find(pstring(startbuf, n));
77         bool replace = elem != pset.end() && n < elem->n;
78         if (replace) {
79             pset.erase(elem);
80         }
81         if (replace || elem == pset.end()) {
82             pset.insert(pstring(startbuf, n));
83         }
84     }
85 public:
86     StringPrefixes(const char* source);
87
88     bool contain(const char* s) {
89         if (pset.find(pstring(s, strlen(s) + 1)) != pset.end()) {
90             os::log("Backtrace for %s is enabled", s);
91             return true;
92         }
93         return false;
94     }
95 };
96
97 bool backtrace_is_needed(const char* fname) {
98     static StringPrefixes backtraceFunctionNamePrefixes(APITRACE_FNAMES_SOURCE);
99     return backtraceFunctionNamePrefixes.contain(fname);
100 }
101
102 } /* namespace trace */
103
104 #ifdef ANDROID
105
106 #include <dlfcn.h>
107 #include "os.hpp"
108 #include <vector>
109
110 namespace trace {
111
112 StringPrefixes::StringPrefixes(const char* source) {
113     buf = (char*)malloc(sizeof(char) * PREFIX_BUF_SIZE);
114     char* startbuf = buf;
115     int n = 0;
116     FILE* f = fopen(source, "r");
117     if (f == NULL) {
118         os::log("Cannot open " APITRACE_FNAMES_FILE);
119     }
120     while ((startbuf = fgets(startbuf, PREFIX_MAX_FUNC_NAME, f))) {
121         n = strlen(startbuf);
122         if (startbuf[n - 1] == '\n') {
123             n--;
124         }
125         if (n > 2 && startbuf[0] != '#') {
126             int psize;
127             if (startbuf[n - 1] != '*') {
128                 startbuf[n] = '\0';
129                 psize = n + 1;
130             }
131             else {
132                 psize = n - 1;
133             }
134             addPrefix(startbuf, psize);
135             startbuf += n + 1;
136             n = 0;
137         }
138     }
139     fclose(f);
140 }
141
142
143 /* The following two declarations are copied from Android sources */
144
145 enum DebugTargetKind {
146     kDebugTargetUnknown = 0,
147     kDebugTargetLog,
148     kDebugTargetFile,
149 };
150
151 struct DebugOutputTarget {
152     DebugTargetKind which;
153
154     union {
155         struct {
156             int priority;
157             const char* tag;
158         } log;
159         struct {
160             FILE* fp;
161         } file;
162     } data;
163 };
164
165 #define THREAD_SELF_NAME "_Z13dvmThreadSelfv"
166 #define CREATE_DEBUG_TARGET_NAME "_Z25dvmCreateFileOutputTargetP17DebugOutputTargetP7__sFILE"
167 #define DUMP_BACKTRACE_NAME "_Z18dvmDumpThreadStackPK17DebugOutputTargetP6Thread"
168
169
170 class DalvikBacktraceProvider {
171 private:
172     bool errorOccured;
173     void* (*threadself)(void);
174     FILE* streamInMemory;
175     char* buf;
176     size_t bufSize;
177     void (*dumpBacktrace)(const DebugOutputTarget*, void*);
178     DebugOutputTarget debugTarget;
179 public:
180     DalvikBacktraceProvider() {
181         FILE* (*open_memstream_exp)(char**, size_t*);
182         void (*createDebugTarget)(DebugOutputTarget*, FILE*);
183         void* handle = dlopen("/system/lib/libdvm.so", 0);
184         errorOccured = true;
185         if (!handle) {
186             os::log("dlopen failed\n");
187             return;
188         }
189         threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
190         if (threadself == NULL) {
191             os::log("dlsym ThreadSelf failed\n");
192             return;
193         }
194         createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
195         if (createDebugTarget == NULL) {
196             os::log("dlsym CreateFileOutput failed\n");
197             return;
198         }
199         dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
200         if (dumpBacktrace == NULL) {
201             os::log("dlsym DumpThreadStack failed\n");
202             return;
203         }
204         void* handle2 = dlopen("/system/lib/libcutils.so", 0);
205         if (!handle2) {
206             os::log("dlopen failed\n");
207             return;
208         }
209         open_memstream_exp = (FILE* (*)(char**, size_t*))dlsym(handle2, "open_memstream");
210         if (open_memstream_exp == NULL) {
211             os::log("dlsym open_memstream failed\n");
212             return;
213         }
214         streamInMemory = open_memstream_exp(&buf, &bufSize);
215         if (streamInMemory == NULL) {
216             os::log("open_memstream failed\n");
217             return;
218         }
219         createDebugTarget(&debugTarget, streamInMemory);
220         errorOccured = false;
221     }
222
223     inline char* getBacktrace() {
224         if (errorOccured) {
225             return NULL;
226         }
227         rewind(streamInMemory);
228         dumpBacktrace(&debugTarget, threadself());
229         fflush(streamInMemory);
230         return buf;
231     }
232 /*
233  * Parse a stack frame, expecting:
234  * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
235  * or
236  * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
237  */
238     std::vector<RawStackFrame> parseBacktrace(char *rawBacktrace) {
239         std::vector<RawStackFrame> parsedBacktrace;
240         char* rawBacktrace_it = rawBacktrace;
241         while (*rawBacktrace_it != '\0') {
242             RawStackFrame stackFrame;
243             /* skip leading space */
244             while (*rawBacktrace_it == ' ') {
245                 rawBacktrace_it++;
246             }
247             /* Skip "at " */
248             rawBacktrace_it += 3;
249             stackFrame.function = rawBacktrace_it;
250             while (*rawBacktrace_it != '(') {
251                 rawBacktrace_it++;
252             }
253             *rawBacktrace_it = '\0';
254             stackFrame.filename = rawBacktrace_it + 1;
255             while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
256                 rawBacktrace_it++;
257             }
258             if (*rawBacktrace_it == ':') {
259                 stackFrame.linenumber = rawBacktrace_it + 1;
260                 *rawBacktrace_it = '\0';
261                 while (*rawBacktrace_it != ')') {
262                     rawBacktrace_it++;
263                 }
264                 *rawBacktrace_it = '\0';
265                 rawBacktrace_it++;
266             }
267             else {
268                 stackFrame.filename = NULL;
269                 while (*rawBacktrace_it != '\n') {
270                     rawBacktrace_it++;
271                 }
272             }
273             while (*rawBacktrace_it == '\n' || *rawBacktrace_it == ' ') {
274                     rawBacktrace_it++;
275             }
276             parsedBacktrace.push_back(stackFrame); /* module */
277         }
278         return parsedBacktrace;
279     }
280 };
281
282 std::vector<RawStackFrame> get_backtrace() {
283     static DalvikBacktraceProvider backtraceProvider;
284     return backtraceProvider.parseBacktrace(backtraceProvider.getBacktrace());
285 }
286
287 /* end ANDROID */
288 #elif defined __linux__
289
290 #include <execinfo.h>
291 #include <string.h>
292 #include <stdlib.h>
293 #include <map>
294 #include <vector>
295 #include <stdio.h>
296
297 namespace trace {
298
299
300 StringPrefixes::StringPrefixes(const char* source) {
301     buf = (char*)malloc(sizeof(char) * PREFIX_BUF_SIZE);
302     char* startbuf = buf;
303     int n = 0;
304     char* s = getenv(source);
305     char end = ';';
306     if (s == NULL) {
307         return;
308     }
309     *buf = ';';
310     strncpy(buf + 1, s, PREFIX_BUF_SIZE - 2);
311     while (end != '\0') {
312         startbuf++;
313         while (*(startbuf + n) != ';' && *(startbuf + n) != '\0') {
314             n++;
315         }
316         end = startbuf[n];
317         if (n > 2 && startbuf[0] != '#') {
318             int psize;
319             if (startbuf[n - 1] != '*') {
320                 startbuf[n] = '\0';
321                 psize = n + 1;
322             }
323             else {
324                 psize = n - 1;
325             }
326             addPrefix(startbuf, psize);
327             startbuf += n;
328             n = 0;
329         }
330     }
331 }
332
333
334 #define BT_DEPTH 10
335
336 class GlibcBacktraceProvider {
337 private:
338     std::map<void*, RawStackFrame*> cache;
339     /*
340      * Backtrace being returned by glibc backtrace() contains stack frames
341      * belonging to apitrace wrapper module. We count the number of apitrace
342      * functions on the stack to avoid recording these frames.
343      */
344     int numOfNestedFunctions;
345 private:
346 /*
347  * Parse a stack frame, expecting:
348  * /lib/libc.so.6.1(__libc_start_main+0x50308) [0x2000000000097630]
349  * or
350  * /lib/libc.so.6.1(+0x50308) [0x2000000000097630]
351  * or
352  * /lib/libc.so.6.1() [0x2000000000097630]
353  */
354     RawStackFrame* parseFrame(void* frame, char* frame_symbol) {
355         if (cache.find(frame) == cache.end()) {
356             char* frame_symbol_copy = new char[strlen(frame_symbol) + 1];
357             strcpy(frame_symbol_copy, frame_symbol);
358             RawStackFrame* parsedFrame = new RawStackFrame;
359             char* frame_it = frame_symbol_copy;
360             parsedFrame->module = frame_it;
361             while (true) {
362                 switch (*frame_it) {
363                 case '(':
364                     *frame_it = '\0';
365                     frame_it++;
366                     if (*frame_it != ')' && *frame_it != '+') {
367                         parsedFrame->function = frame_it;
368                         while (*frame_it != '+' && *frame_it != ')') {
369                             frame_it++;
370                         }
371                         *frame_it = '\0';
372                         frame_it++;
373                     }
374                     break;
375                 case '[':
376                     *frame_it = '\0';
377                     frame_it++;
378                     parsedFrame->offset = frame_it;
379                     break;
380                 case ']':
381                     *frame_it = '\0';
382                     cache[frame] = parsedFrame;
383                     return parsedFrame;
384                 case '\0':
385                     cache[frame] = NULL;
386                     delete[] frame_symbol_copy;
387                     delete[] parsedFrame;
388                     return NULL;
389                 default:
390                     frame_it++;
391                 }
392             }
393         }
394         else {
395             return cache[frame];
396         }
397     }
398 public:
399     GlibcBacktraceProvider() :
400       numOfNestedFunctions(0) {
401     }
402     std::vector<RawStackFrame> getParsedBacktrace() {
403         std::vector<RawStackFrame> parsedBacktrace;
404         void *array[numOfNestedFunctions + BT_DEPTH];
405         size_t size;
406         char **strings;
407         size_t i;
408         const char* firstModule;
409         size = backtrace(array, numOfNestedFunctions + BT_DEPTH);
410         strings = backtrace_symbols(array, size);
411         for (i = numOfNestedFunctions; i < size; i++) {
412             RawStackFrame* parsedFrame = parseFrame(array[i], strings[i]);
413             if (numOfNestedFunctions == 0) {
414                 if (i == 0) {
415                     firstModule = parsedFrame->module;
416                 }
417                 else {
418                     if (strcmp(firstModule, parsedFrame->module)) {
419                         numOfNestedFunctions = i;
420                         free(strings);
421                         parsedBacktrace = getParsedBacktrace();
422                         numOfNestedFunctions--;
423                         return parsedBacktrace;
424                     }
425                 }
426             } else {
427                 if (parsedFrame != NULL) {
428                     parsedBacktrace.push_back(*parsedFrame);
429                 }
430             }
431         }
432         free(strings);
433         return parsedBacktrace;
434     }
435 };
436
437
438 std::vector<RawStackFrame> get_backtrace() {
439     static GlibcBacktraceProvider backtraceProvider;
440     return backtraceProvider.getParsedBacktrace();
441 }
442
443 #endif /* LINUX */
444
445 } /* namespace trace */
446
447 #endif /* ANDROID or LINUX */