1 /**************************************************************************
3 * Copyright 2013 Samsung
4 * Contributed by Eugene Velesevich
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
25 **************************************************************************/
28 * Wrapper for platform-specific code for obtaining symbolic backtraces
29 * on Android and Linux
34 #include "trace_backtrace.hpp"
36 #if defined(ANDROID) or defined(__linux__)
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)
56 pstring(const char* s, int n)
61 bool operator<(const pstring q2) const
63 return memcmp(s, q2.s, n < q2.n? n : q2.n) < 0;
68 #define PREFIX_BUF_SIZE (PREFIX_MAX_FUNC_NAME * MAX_BT_FUNC)
70 class StringPrefixes {
72 std::set<pstring> pset;
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;
80 if (replace || elem == pset.end()) {
81 pset.insert(pstring(startbuf, n));
85 StringPrefixes(const char* source);
87 bool contain(const char* s) {
88 return pset.find(pstring(s, strlen(s) + 1)) != pset.end();
92 bool backtrace_is_needed(const char* fname) {
93 static StringPrefixes backtraceFunctionNamePrefixes(APITRACE_FNAMES_SOURCE);
94 return backtraceFunctionNamePrefixes.contain(fname);
97 } /* namespace trace */
107 StringPrefixes::StringPrefixes(const char* source) {
108 char* buf = (char*)malloc(sizeof(char) * PREFIX_BUF_SIZE);
109 char* startbuf = buf;
111 FILE* f = fopen(source, "r");
113 os::log("Cannot open " APITRACE_FNAMES_FILE);
115 while ((startbuf = fgets(startbuf, PREFIX_MAX_FUNC_NAME, f))) {
116 n = strlen(startbuf);
117 if (startbuf[n - 1] == '\n') {
120 if (n > 2 && startbuf[0] != '#') {
122 if (startbuf[n - 1] != '*') {
129 addPrefix(startbuf, psize);
138 /* The following two declarations are copied from Android sources */
140 enum DebugTargetKind {
141 kDebugTargetUnknown = 0,
146 struct DebugOutputTarget {
147 DebugTargetKind which;
160 #define THREAD_SELF_NAME "_Z13dvmThreadSelfv"
161 #define CREATE_DEBUG_TARGET_NAME "_Z25dvmCreateFileOutputTargetP17DebugOutputTargetP7__sFILE"
162 #define DUMP_BACKTRACE_NAME "_Z18dvmDumpThreadStackPK17DebugOutputTargetP6Thread"
165 class DalvikBacktraceProvider {
168 void* (*threadself)(void);
169 FILE* streamInMemory;
172 void (*dumpBacktrace)(const DebugOutputTarget*, void*);
173 DebugOutputTarget debugTarget;
176 DalvikBacktraceProvider() {
178 FILE* (*open_memstream_exp)(char**, size_t*);
179 void (*createDebugTarget)(DebugOutputTarget*, FILE*);
180 void* handle = dlopen("/system/lib/libdvm.so", 0);
183 os::log("dlopen failed\n");
186 threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
187 if (threadself == NULL) {
188 os::log("dlsym ThreadSelf failed\n");
191 createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
192 if (createDebugTarget == NULL) {
193 os::log("dlsym CreateFileOutput failed\n");
196 dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
197 if (dumpBacktrace == NULL) {
198 os::log("dlsym DumpThreadStack failed\n");
201 void* handle2 = dlopen("/system/lib/libcutils.so", 0);
203 os::log("dlopen failed\n");
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");
211 streamInMemory = open_memstream_exp(&buf, &bufSize);
212 if (streamInMemory == NULL) {
213 os::log("open_memstream failed\n");
216 createDebugTarget(&debugTarget, streamInMemory);
217 errorOccured = false;
220 inline char* getBacktrace() {
224 rewind(streamInMemory);
225 dumpBacktrace(&debugTarget, threadself());
226 fflush(streamInMemory);
230 * Parse a stack frame, expecting:
231 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
233 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
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 == ' ') {
247 rawBacktrace_it += 3;
248 stackFrame.function = rawBacktrace_it;
249 while (*rawBacktrace_it != '(') {
252 *rawBacktrace_it = '\0';
253 stackFrame.filename = rawBacktrace_it + 1;
254 while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
257 if (*rawBacktrace_it == ':') {
258 const char *linenumber = rawBacktrace_it + 1;
259 *rawBacktrace_it = '\0';
260 while (*rawBacktrace_it != ')') {
263 *rawBacktrace_it = '\0';
265 stackFrame.linenumber = atoi(linenumber);
268 stackFrame.filename = NULL;
269 while (*rawBacktrace_it != '\n') {
273 while (*rawBacktrace_it == '\n' || *rawBacktrace_it == ' ') {
276 parsedBacktrace.push_back(stackFrame); /* module */
278 return parsedBacktrace;
282 std::vector<RawStackFrame> get_backtrace() {
283 static DalvikBacktraceProvider backtraceProvider;
284 return backtraceProvider.parseBacktrace(backtraceProvider.getBacktrace());
288 #elif defined __linux__
290 #include <execinfo.h>
300 StringPrefixes::StringPrefixes(const char* source) {
301 char* buf = (char*)malloc(sizeof(char) * PREFIX_BUF_SIZE);
302 char* startbuf = buf;
304 char* s = getenv(source);
310 strncpy(buf + 1, s, PREFIX_BUF_SIZE - 2);
311 while (end != '\0') {
313 while (*(startbuf + n) != ';' && *(startbuf + n) != '\0') {
317 if (n > 2 && startbuf[0] != '#') {
319 if (startbuf[n - 1] != '*') {
326 addPrefix(startbuf, psize);
336 class GlibcBacktraceProvider {
338 std::map<void*, RawStackFrame*> cache;
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.
344 int numOfNestedFunctions;
348 * Parse a stack frame, expecting:
349 * /lib/libc.so.6.1(__libc_start_main+0x50308) [0x2000000000097630]
351 * /lib/libc.so.6.1(+0x50308) [0x2000000000097630]
353 * /lib/libc.so.6.1() [0x2000000000097630]
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;
369 if (*frame_it != ')' && *frame_it != '+') {
370 parsedFrame->function = frame_it;
371 while (*frame_it != '+' && *frame_it != ')') {
385 sscanf(offset, "%llx", &parsedFrame->offset);
386 cache[frame] = parsedFrame;
390 delete[] frame_symbol_copy;
391 delete[] parsedFrame;
403 GlibcBacktraceProvider() :
404 numOfNestedFunctions(0),
408 std::vector<RawStackFrame> getParsedBacktrace() {
409 std::vector<RawStackFrame> parsedBacktrace;
410 void *array[numOfNestedFunctions + BT_DEPTH];
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) {
421 firstModule = parsedFrame->module;
424 if (strcmp(firstModule, parsedFrame->module)) {
425 numOfNestedFunctions = i;
427 parsedBacktrace = getParsedBacktrace();
428 numOfNestedFunctions--;
429 return parsedBacktrace;
433 if (parsedFrame != NULL) {
434 parsedBacktrace.push_back(*parsedFrame);
439 return parsedBacktrace;
444 std::vector<RawStackFrame> get_backtrace() {
445 static GlibcBacktraceProvider backtraceProvider;
446 return backtraceProvider.getParsedBacktrace();
451 } /* namespace trace */
453 #endif /* ANDROID or LINUX */