]> git.cworth.org Git - apitrace/blob - common/trace_backtrace.cpp
730cfef0bed765be2747b57aa3810a183b9f1664
[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
74     void addPrefix(char* startbuf, int n) {
75         std::set<pstring>::iterator elem = pset.find(pstring(startbuf, n));
76         bool replace = elem != pset.end() && n < elem->n;
77         if (replace) {
78             pset.erase(elem);
79         }
80         if (replace || elem == pset.end()) {
81             pset.insert(pstring(startbuf, n));
82         }
83     }
84 public:
85     StringPrefixes(const char* source);
86
87     bool contain(const char* s) {
88         return pset.find(pstring(s, strlen(s) + 1)) != pset.end();
89     }
90 };
91
92 bool backtrace_is_needed(const char* fname) {
93     static StringPrefixes backtraceFunctionNamePrefixes(APITRACE_FNAMES_SOURCE);
94     return backtraceFunctionNamePrefixes.contain(fname);
95 }
96
97 } /* namespace trace */
98
99 #ifdef ANDROID
100
101 #include <dlfcn.h>
102 #include "os.hpp"
103 #include <vector>
104
105 namespace trace {
106
107 StringPrefixes::StringPrefixes(const char* source) {
108     char* buf = (char*)malloc(sizeof(char) * PREFIX_BUF_SIZE);
109     char* startbuf = buf;
110     int n = 0;
111     FILE* f = fopen(source, "r");
112     if (f == NULL) {
113         os::log("Cannot open " APITRACE_FNAMES_FILE);
114     }
115     while ((startbuf = fgets(startbuf, PREFIX_MAX_FUNC_NAME, f))) {
116         n = strlen(startbuf);
117         if (startbuf[n - 1] == '\n') {
118             n--;
119         }
120         if (n > 2 && startbuf[0] != '#') {
121             int psize;
122             if (startbuf[n - 1] != '*') {
123                 startbuf[n] = '\0';
124                 psize = n + 1;
125             }
126             else {
127                 psize = n - 1;
128             }
129             addPrefix(startbuf, psize);
130             startbuf += n + 1;
131             n = 0;
132         }
133     }
134     fclose(f);
135 }
136
137
138 /* The following two declarations are copied from Android sources */
139
140 enum DebugTargetKind {
141     kDebugTargetUnknown = 0,
142     kDebugTargetLog,
143     kDebugTargetFile,
144 };
145
146 struct DebugOutputTarget {
147     DebugTargetKind which;
148
149     union {
150         struct {
151             int priority;
152             const char* tag;
153         } log;
154         struct {
155             FILE* fp;
156         } file;
157     } data;
158 };
159
160 #define THREAD_SELF_NAME "_Z13dvmThreadSelfv"
161 #define CREATE_DEBUG_TARGET_NAME "_Z25dvmCreateFileOutputTargetP17DebugOutputTargetP7__sFILE"
162 #define DUMP_BACKTRACE_NAME "_Z18dvmDumpThreadStackPK17DebugOutputTargetP6Thread"
163
164
165 class DalvikBacktraceProvider {
166 private:
167     bool errorOccured;
168     void* (*threadself)(void);
169     FILE* streamInMemory;
170     char* buf;
171     size_t bufSize;
172     void (*dumpBacktrace)(const DebugOutputTarget*, void*);
173     DebugOutputTarget debugTarget;
174     Id nextFrameId;
175 public:
176     DalvikBacktraceProvider() {
177         nextFrameId = 0;
178         FILE* (*open_memstream_exp)(char**, size_t*);
179         void (*createDebugTarget)(DebugOutputTarget*, FILE*);
180         void* handle = dlopen("/system/lib/libdvm.so", 0);
181         errorOccured = true;
182         if (!handle) {
183             os::log("dlopen failed\n");
184             return;
185         }
186         threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
187         if (threadself == NULL) {
188             os::log("dlsym ThreadSelf failed\n");
189             return;
190         }
191         createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
192         if (createDebugTarget == NULL) {
193             os::log("dlsym CreateFileOutput failed\n");
194             return;
195         }
196         dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
197         if (dumpBacktrace == NULL) {
198             os::log("dlsym DumpThreadStack failed\n");
199             return;
200         }
201         void* handle2 = dlopen("/system/lib/libcutils.so", 0);
202         if (!handle2) {
203             os::log("dlopen failed\n");
204             return;
205         }
206         open_memstream_exp = (FILE* (*)(char**, size_t*))dlsym(handle2, "open_memstream");
207         if (open_memstream_exp == NULL) {
208             os::log("dlsym open_memstream failed\n");
209             return;
210         }
211         streamInMemory = open_memstream_exp(&buf, &bufSize);
212         if (streamInMemory == NULL) {
213             os::log("open_memstream failed\n");
214             return;
215         }
216         createDebugTarget(&debugTarget, streamInMemory);
217         errorOccured = false;
218     }
219
220     inline char* getBacktrace() {
221         if (errorOccured) {
222             return NULL;
223         }
224         rewind(streamInMemory);
225         dumpBacktrace(&debugTarget, threadself());
226         fflush(streamInMemory);
227         return buf;
228     }
229 /*
230  * Parse a stack frame, expecting:
231  * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
232  * or
233  * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
234  */
235     std::vector<RawStackFrame> parseBacktrace(char *rawBacktrace) {
236         std::vector<RawStackFrame> parsedBacktrace;
237         char* rawBacktrace_it = rawBacktrace;
238         while (*rawBacktrace_it != '\0') {
239             RawStackFrame stackFrame;
240             // TODO: Keep a cache of stack frames
241             stackFrame.id = nextFrameId++;
242             /* skip leading space */
243             while (*rawBacktrace_it == ' ') {
244                 rawBacktrace_it++;
245             }
246             /* Skip "at " */
247             rawBacktrace_it += 3;
248             stackFrame.function = rawBacktrace_it;
249             while (*rawBacktrace_it != '(') {
250                 rawBacktrace_it++;
251             }
252             *rawBacktrace_it = '\0';
253             stackFrame.filename = rawBacktrace_it + 1;
254             while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
255                 rawBacktrace_it++;
256             }
257             if (*rawBacktrace_it == ':') {
258                 const char *linenumber = rawBacktrace_it + 1;
259                 *rawBacktrace_it = '\0';
260                 while (*rawBacktrace_it != ')') {
261                     rawBacktrace_it++;
262                 }
263                 *rawBacktrace_it = '\0';
264                 rawBacktrace_it++;
265                 stackFrame.linenumber = atoi(linenumber);
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     char* 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     Id nextFrameId;
346 private:
347 /*
348  * Parse a stack frame, expecting:
349  * /lib/libc.so.6.1(__libc_start_main+0x50308) [0x2000000000097630]
350  * or
351  * /lib/libc.so.6.1(+0x50308) [0x2000000000097630]
352  * or
353  * /lib/libc.so.6.1() [0x2000000000097630]
354  */
355     RawStackFrame* parseFrame(void* frame, char* frame_symbol) {
356         if (cache.find(frame) == cache.end()) {
357             char* frame_symbol_copy = new char[strlen(frame_symbol) + 1];
358             strcpy(frame_symbol_copy, frame_symbol);
359             RawStackFrame* parsedFrame = new RawStackFrame;
360             parsedFrame->id = nextFrameId++;
361             char* frame_it = frame_symbol_copy;
362             parsedFrame->module = frame_it;
363             char* offset = NULL;
364             while (true) {
365                 switch (*frame_it) {
366                 case '(':
367                     *frame_it = '\0';
368                     frame_it++;
369                     if (*frame_it != ')' && *frame_it != '+') {
370                         parsedFrame->function = frame_it;
371                         while (*frame_it != '+' && *frame_it != ')') {
372                             frame_it++;
373                         }
374                         *frame_it = '\0';
375                         frame_it++;
376                     }
377                     break;
378                 case '[':
379                     *frame_it = '\0';
380                     frame_it++;
381                     offset = frame_it;
382                     break;
383                 case ']':
384                     *frame_it = '\0';
385                     sscanf(offset, "%llx", &parsedFrame->offset);
386                     cache[frame] = parsedFrame;
387                     return parsedFrame;
388                 case '\0':
389                     cache[frame] = NULL;
390                     delete[] frame_symbol_copy;
391                     delete[] parsedFrame;
392                     return NULL;
393                 default:
394                     frame_it++;
395                 }
396             }
397         }
398         else {
399             return cache[frame];
400         }
401     }
402 public:
403     GlibcBacktraceProvider() :
404       numOfNestedFunctions(0),
405       nextFrameId(0)
406     {}
407
408     std::vector<RawStackFrame> getParsedBacktrace() {
409         std::vector<RawStackFrame> parsedBacktrace;
410         void *array[numOfNestedFunctions + BT_DEPTH];
411         size_t size;
412         char **strings;
413         size_t i;
414         const char* firstModule;
415         size = backtrace(array, numOfNestedFunctions + BT_DEPTH);
416         strings = backtrace_symbols(array, size);
417         for (i = numOfNestedFunctions; i < size; i++) {
418             RawStackFrame* parsedFrame = parseFrame(array[i], strings[i]);
419             if (numOfNestedFunctions == 0) {
420                 if (i == 0) {
421                     firstModule = parsedFrame->module;
422                 }
423                 else {
424                     if (strcmp(firstModule, parsedFrame->module)) {
425                         numOfNestedFunctions = i;
426                         free(strings);
427                         parsedBacktrace = getParsedBacktrace();
428                         numOfNestedFunctions--;
429                         return parsedBacktrace;
430                     }
431                 }
432             } else {
433                 if (parsedFrame != NULL) {
434                     parsedBacktrace.push_back(*parsedFrame);
435                 }
436             }
437         }
438         free(strings);
439         return parsedBacktrace;
440     }
441 };
442
443
444 std::vector<RawStackFrame> get_backtrace() {
445     static GlibcBacktraceProvider backtraceProvider;
446     return backtraceProvider.getParsedBacktrace();
447 }
448
449 #endif /* LINUX */
450
451 } /* namespace trace */
452
453 #endif /* ANDROID or LINUX */