]> git.cworth.org Git - apitrace/blob - common/trace_backtrace.cpp
Use ids for frames.
[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     Id nextFrameId;
180 public:
181     DalvikBacktraceProvider() {
182         nextFrameId = 0;
183         FILE* (*open_memstream_exp)(char**, size_t*);
184         void (*createDebugTarget)(DebugOutputTarget*, FILE*);
185         void* handle = dlopen("/system/lib/libdvm.so", 0);
186         errorOccured = true;
187         if (!handle) {
188             os::log("dlopen failed\n");
189             return;
190         }
191         threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
192         if (threadself == NULL) {
193             os::log("dlsym ThreadSelf failed\n");
194             return;
195         }
196         createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
197         if (createDebugTarget == NULL) {
198             os::log("dlsym CreateFileOutput failed\n");
199             return;
200         }
201         dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
202         if (dumpBacktrace == NULL) {
203             os::log("dlsym DumpThreadStack failed\n");
204             return;
205         }
206         void* handle2 = dlopen("/system/lib/libcutils.so", 0);
207         if (!handle2) {
208             os::log("dlopen failed\n");
209             return;
210         }
211         open_memstream_exp = (FILE* (*)(char**, size_t*))dlsym(handle2, "open_memstream");
212         if (open_memstream_exp == NULL) {
213             os::log("dlsym open_memstream failed\n");
214             return;
215         }
216         streamInMemory = open_memstream_exp(&buf, &bufSize);
217         if (streamInMemory == NULL) {
218             os::log("open_memstream failed\n");
219             return;
220         }
221         createDebugTarget(&debugTarget, streamInMemory);
222         errorOccured = false;
223     }
224
225     inline char* getBacktrace() {
226         if (errorOccured) {
227             return NULL;
228         }
229         rewind(streamInMemory);
230         dumpBacktrace(&debugTarget, threadself());
231         fflush(streamInMemory);
232         return buf;
233     }
234 /*
235  * Parse a stack frame, expecting:
236  * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
237  * or
238  * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
239  */
240     std::vector<RawStackFrame> parseBacktrace(char *rawBacktrace) {
241         std::vector<RawStackFrame> parsedBacktrace;
242         char* rawBacktrace_it = rawBacktrace;
243         while (*rawBacktrace_it != '\0') {
244             RawStackFrame stackFrame;
245             // TODO: Keep a cache of stack frames
246             stackFrame->id = nextFrameId++;
247             /* skip leading space */
248             while (*rawBacktrace_it == ' ') {
249                 rawBacktrace_it++;
250             }
251             /* Skip "at " */
252             rawBacktrace_it += 3;
253             stackFrame.function = rawBacktrace_it;
254             while (*rawBacktrace_it != '(') {
255                 rawBacktrace_it++;
256             }
257             *rawBacktrace_it = '\0';
258             stackFrame.filename = rawBacktrace_it + 1;
259             while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
260                 rawBacktrace_it++;
261             }
262             if (*rawBacktrace_it == ':') {
263                 const char *linenumber = rawBacktrace_it + 1;
264                 *rawBacktrace_it = '\0';
265                 while (*rawBacktrace_it != ')') {
266                     rawBacktrace_it++;
267                 }
268                 *rawBacktrace_it = '\0';
269                 rawBacktrace_it++;
270                 stackFrame.linenumber = atoi(linenumber);
271             }
272             else {
273                 stackFrame.filename = NULL;
274                 while (*rawBacktrace_it != '\n') {
275                     rawBacktrace_it++;
276                 }
277             }
278             while (*rawBacktrace_it == '\n' || *rawBacktrace_it == ' ') {
279                     rawBacktrace_it++;
280             }
281             parsedBacktrace.push_back(stackFrame); /* module */
282         }
283         return parsedBacktrace;
284     }
285 };
286
287 std::vector<RawStackFrame> get_backtrace() {
288     static DalvikBacktraceProvider backtraceProvider;
289     return backtraceProvider.parseBacktrace(backtraceProvider.getBacktrace());
290 }
291
292 /* end ANDROID */
293 #elif defined __linux__
294
295 #include <execinfo.h>
296 #include <string.h>
297 #include <stdlib.h>
298 #include <map>
299 #include <vector>
300 #include <stdio.h>
301
302 namespace trace {
303
304
305 StringPrefixes::StringPrefixes(const char* source) {
306     buf = (char*)malloc(sizeof(char) * PREFIX_BUF_SIZE);
307     char* startbuf = buf;
308     int n = 0;
309     char* s = getenv(source);
310     char end = ';';
311     if (s == NULL) {
312         return;
313     }
314     *buf = ';';
315     strncpy(buf + 1, s, PREFIX_BUF_SIZE - 2);
316     while (end != '\0') {
317         startbuf++;
318         while (*(startbuf + n) != ';' && *(startbuf + n) != '\0') {
319             n++;
320         }
321         end = startbuf[n];
322         if (n > 2 && startbuf[0] != '#') {
323             int psize;
324             if (startbuf[n - 1] != '*') {
325                 startbuf[n] = '\0';
326                 psize = n + 1;
327             }
328             else {
329                 psize = n - 1;
330             }
331             addPrefix(startbuf, psize);
332             startbuf += n;
333             n = 0;
334         }
335     }
336 }
337
338
339 #define BT_DEPTH 10
340
341 class GlibcBacktraceProvider {
342 private:
343     std::map<void*, RawStackFrame*> cache;
344     /*
345      * Backtrace being returned by glibc backtrace() contains stack frames
346      * belonging to apitrace wrapper module. We count the number of apitrace
347      * functions on the stack to avoid recording these frames.
348      */
349     int numOfNestedFunctions;
350     Id nextFrameId;
351 private:
352 /*
353  * Parse a stack frame, expecting:
354  * /lib/libc.so.6.1(__libc_start_main+0x50308) [0x2000000000097630]
355  * or
356  * /lib/libc.so.6.1(+0x50308) [0x2000000000097630]
357  * or
358  * /lib/libc.so.6.1() [0x2000000000097630]
359  */
360     RawStackFrame* parseFrame(void* frame, char* frame_symbol) {
361         if (cache.find(frame) == cache.end()) {
362             char* frame_symbol_copy = new char[strlen(frame_symbol) + 1];
363             strcpy(frame_symbol_copy, frame_symbol);
364             RawStackFrame* parsedFrame = new RawStackFrame;
365             parsedFrame->id = nextFrameId++;
366             char* frame_it = frame_symbol_copy;
367             parsedFrame->module = frame_it;
368             char* offset = NULL;
369             while (true) {
370                 switch (*frame_it) {
371                 case '(':
372                     *frame_it = '\0';
373                     frame_it++;
374                     if (*frame_it != ')' && *frame_it != '+') {
375                         parsedFrame->function = frame_it;
376                         while (*frame_it != '+' && *frame_it != ')') {
377                             frame_it++;
378                         }
379                         *frame_it = '\0';
380                         frame_it++;
381                     }
382                     break;
383                 case '[':
384                     *frame_it = '\0';
385                     frame_it++;
386                     offset = frame_it;
387                     break;
388                 case ']':
389                     *frame_it = '\0';
390                     sscanf(offset, "%llx", &parsedFrame->offset);
391                     cache[frame] = parsedFrame;
392                     return parsedFrame;
393                 case '\0':
394                     cache[frame] = NULL;
395                     delete[] frame_symbol_copy;
396                     delete[] parsedFrame;
397                     return NULL;
398                 default:
399                     frame_it++;
400                 }
401             }
402         }
403         else {
404             return cache[frame];
405         }
406     }
407 public:
408     GlibcBacktraceProvider() :
409       numOfNestedFunctions(0),
410       nextFrameId(0)
411     {}
412
413     std::vector<RawStackFrame> getParsedBacktrace() {
414         std::vector<RawStackFrame> parsedBacktrace;
415         void *array[numOfNestedFunctions + BT_DEPTH];
416         size_t size;
417         char **strings;
418         size_t i;
419         const char* firstModule;
420         size = backtrace(array, numOfNestedFunctions + BT_DEPTH);
421         strings = backtrace_symbols(array, size);
422         for (i = numOfNestedFunctions; i < size; i++) {
423             RawStackFrame* parsedFrame = parseFrame(array[i], strings[i]);
424             if (numOfNestedFunctions == 0) {
425                 if (i == 0) {
426                     firstModule = parsedFrame->module;
427                 }
428                 else {
429                     if (strcmp(firstModule, parsedFrame->module)) {
430                         numOfNestedFunctions = i;
431                         free(strings);
432                         parsedBacktrace = getParsedBacktrace();
433                         numOfNestedFunctions--;
434                         return parsedBacktrace;
435                     }
436                 }
437             } else {
438                 if (parsedFrame != NULL) {
439                     parsedBacktrace.push_back(*parsedFrame);
440                 }
441             }
442         }
443         free(strings);
444         return parsedBacktrace;
445     }
446 };
447
448
449 std::vector<RawStackFrame> get_backtrace() {
450     static GlibcBacktraceProvider backtraceProvider;
451     return backtraceProvider.getParsedBacktrace();
452 }
453
454 #endif /* LINUX */
455
456 } /* namespace trace */
457
458 #endif /* ANDROID or LINUX */