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;
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;
81 if (replace || elem == pset.end()) {
82 pset.insert(pstring(startbuf, n));
86 StringPrefixes(const char* source);
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);
97 bool backtrace_is_needed(const char* fname) {
98 static StringPrefixes backtraceFunctionNamePrefixes(APITRACE_FNAMES_SOURCE);
99 return backtraceFunctionNamePrefixes.contain(fname);
102 } /* namespace trace */
112 StringPrefixes::StringPrefixes(const char* source) {
113 buf = (char*)malloc(sizeof(char) * PREFIX_BUF_SIZE);
114 char* startbuf = buf;
116 FILE* f = fopen(source, "r");
118 os::log("Cannot open " APITRACE_FNAMES_FILE);
120 while ((startbuf = fgets(startbuf, PREFIX_MAX_FUNC_NAME, f))) {
121 n = strlen(startbuf);
122 if (startbuf[n - 1] == '\n') {
125 if (n > 2 && startbuf[0] != '#') {
127 if (startbuf[n - 1] != '*') {
134 addPrefix(startbuf, psize);
143 /* The following two declarations are copied from Android sources */
145 enum DebugTargetKind {
146 kDebugTargetUnknown = 0,
151 struct DebugOutputTarget {
152 DebugTargetKind which;
165 #define THREAD_SELF_NAME "_Z13dvmThreadSelfv"
166 #define CREATE_DEBUG_TARGET_NAME "_Z25dvmCreateFileOutputTargetP17DebugOutputTargetP7__sFILE"
167 #define DUMP_BACKTRACE_NAME "_Z18dvmDumpThreadStackPK17DebugOutputTargetP6Thread"
170 class DalvikBacktraceProvider {
173 void* (*threadself)(void);
174 FILE* streamInMemory;
177 void (*dumpBacktrace)(const DebugOutputTarget*, void*);
178 DebugOutputTarget debugTarget;
180 DalvikBacktraceProvider() {
181 FILE* (*open_memstream_exp)(char**, size_t*);
182 void (*createDebugTarget)(DebugOutputTarget*, FILE*);
183 void* handle = dlopen("/system/lib/libdvm.so", 0);
186 os::log("dlopen failed\n");
189 threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
190 if (threadself == NULL) {
191 os::log("dlsym ThreadSelf failed\n");
194 createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
195 if (createDebugTarget == NULL) {
196 os::log("dlsym CreateFileOutput failed\n");
199 dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
200 if (dumpBacktrace == NULL) {
201 os::log("dlsym DumpThreadStack failed\n");
204 void* handle2 = dlopen("/system/lib/libcutils.so", 0);
206 os::log("dlopen failed\n");
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");
214 streamInMemory = open_memstream_exp(&buf, &bufSize);
215 if (streamInMemory == NULL) {
216 os::log("open_memstream failed\n");
219 createDebugTarget(&debugTarget, streamInMemory);
220 errorOccured = false;
223 inline char* getBacktrace() {
227 rewind(streamInMemory);
228 dumpBacktrace(&debugTarget, threadself());
229 fflush(streamInMemory);
233 * Parse a stack frame, expecting:
234 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
236 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
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 == ' ') {
248 rawBacktrace_it += 3;
249 stackFrame.function = rawBacktrace_it;
250 while (*rawBacktrace_it != '(') {
253 *rawBacktrace_it = '\0';
254 stackFrame.filename = rawBacktrace_it + 1;
255 while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
258 if (*rawBacktrace_it == ':') {
259 stackFrame.linenumber = rawBacktrace_it + 1;
260 *rawBacktrace_it = '\0';
261 while (*rawBacktrace_it != ')') {
264 *rawBacktrace_it = '\0';
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 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;
347 * Parse a stack frame, expecting:
348 * /lib/libc.so.6.1(__libc_start_main+0x50308) [0x2000000000097630]
350 * /lib/libc.so.6.1(+0x50308) [0x2000000000097630]
352 * /lib/libc.so.6.1() [0x2000000000097630]
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;
366 if (*frame_it != ')' && *frame_it != '+') {
367 parsedFrame->function = frame_it;
368 while (*frame_it != '+' && *frame_it != ')') {
378 parsedFrame->offset = frame_it;
382 cache[frame] = parsedFrame;
386 delete[] frame_symbol_copy;
387 delete[] parsedFrame;
399 GlibcBacktraceProvider() :
400 numOfNestedFunctions(0) {
402 std::vector<RawStackFrame> getParsedBacktrace() {
403 std::vector<RawStackFrame> parsedBacktrace;
404 void *array[numOfNestedFunctions + BT_DEPTH];
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) {
415 firstModule = parsedFrame->module;
418 if (strcmp(firstModule, parsedFrame->module)) {
419 numOfNestedFunctions = i;
421 parsedBacktrace = getParsedBacktrace();
422 numOfNestedFunctions--;
423 return parsedBacktrace;
427 if (parsedFrame != NULL) {
428 parsedBacktrace.push_back(*parsedFrame);
433 return parsedBacktrace;
438 std::vector<RawStackFrame> get_backtrace() {
439 static GlibcBacktraceProvider backtraceProvider;
440 return backtraceProvider.getParsedBacktrace();
445 } /* namespace trace */
447 #endif /* ANDROID or LINUX */