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 const char *linenumber = rawBacktrace_it + 1;
260 *rawBacktrace_it = '\0';
261 while (*rawBacktrace_it != ')') {
264 *rawBacktrace_it = '\0';
266 stackFrame.linenumber = atoi(linenumber);
269 stackFrame.filename = NULL;
270 while (*rawBacktrace_it != '\n') {
274 while (*rawBacktrace_it == '\n' || *rawBacktrace_it == ' ') {
277 parsedBacktrace.push_back(stackFrame); /* module */
279 return parsedBacktrace;
283 std::vector<RawStackFrame> get_backtrace() {
284 static DalvikBacktraceProvider backtraceProvider;
285 return backtraceProvider.parseBacktrace(backtraceProvider.getBacktrace());
289 #elif defined __linux__
291 #include <execinfo.h>
301 StringPrefixes::StringPrefixes(const char* source) {
302 buf = (char*)malloc(sizeof(char) * PREFIX_BUF_SIZE);
303 char* startbuf = buf;
305 char* s = getenv(source);
311 strncpy(buf + 1, s, PREFIX_BUF_SIZE - 2);
312 while (end != '\0') {
314 while (*(startbuf + n) != ';' && *(startbuf + n) != '\0') {
318 if (n > 2 && startbuf[0] != '#') {
320 if (startbuf[n - 1] != '*') {
327 addPrefix(startbuf, psize);
337 class GlibcBacktraceProvider {
339 std::map<void*, RawStackFrame*> cache;
341 * Backtrace being returned by glibc backtrace() contains stack frames
342 * belonging to apitrace wrapper module. We count the number of apitrace
343 * functions on the stack to avoid recording these frames.
345 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 char* frame_it = frame_symbol_copy;
361 parsedFrame->module = frame_it;
368 if (*frame_it != ')' && *frame_it != '+') {
369 parsedFrame->function = frame_it;
370 while (*frame_it != '+' && *frame_it != ')') {
384 sscanf(offset, "%llx", &parsedFrame->offset);
385 cache[frame] = parsedFrame;
389 delete[] frame_symbol_copy;
390 delete[] parsedFrame;
402 GlibcBacktraceProvider() :
403 numOfNestedFunctions(0) {
405 std::vector<RawStackFrame> getParsedBacktrace() {
406 std::vector<RawStackFrame> parsedBacktrace;
407 void *array[numOfNestedFunctions + BT_DEPTH];
411 const char* firstModule;
412 size = backtrace(array, numOfNestedFunctions + BT_DEPTH);
413 strings = backtrace_symbols(array, size);
414 for (i = numOfNestedFunctions; i < size; i++) {
415 RawStackFrame* parsedFrame = parseFrame(array[i], strings[i]);
416 if (numOfNestedFunctions == 0) {
418 firstModule = parsedFrame->module;
421 if (strcmp(firstModule, parsedFrame->module)) {
422 numOfNestedFunctions = i;
424 parsedBacktrace = getParsedBacktrace();
425 numOfNestedFunctions--;
426 return parsedBacktrace;
430 if (parsedFrame != NULL) {
431 parsedBacktrace.push_back(*parsedFrame);
436 return parsedBacktrace;
441 std::vector<RawStackFrame> get_backtrace() {
442 static GlibcBacktraceProvider backtraceProvider;
443 return backtraceProvider.getParsedBacktrace();
448 } /* namespace trace */
450 #endif /* ANDROID or LINUX */