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 "os_backtrace.hpp"
36 #if defined(ANDROID) || defined(__ELF__)
46 * Pascal string (with zero terminator optionally omitted)
47 * This is a helper class for storing a set of exact strings or prefixes
48 * to match a zero-terminated string against later.
49 * Two zero-terminated pstrings compare equal iff they are the same.
50 * Otherwise, they compare equal iff one is a prefix of the other
51 * (a zero-terminated pstring cannot be a prefix)
57 pstring(const char* s, int n)
62 bool operator<(const pstring q2) const
64 return memcmp(s, q2.s, n < q2.n? n : q2.n) < 0;
69 class StringPrefixes {
71 std::set<pstring> pset;
73 void addPrefix(char* startbuf, int n) {
74 std::set<pstring>::iterator elem = pset.find(pstring(startbuf, n));
75 bool replace = elem != pset.end() && n < elem->n;
79 if (replace || elem == pset.end()) {
80 pset.insert(pstring(startbuf, n));
86 bool contain(const char* s) {
87 return pset.find(pstring(s, strlen(s) + 1)) != pset.end();
91 StringPrefixes::StringPrefixes() {
92 char *list = getenv("APITRACE_BACKTRACE");
95 for (char *t = strdup(list); ; t = NULL) {
96 char *tok = strtok(t, " \t\r\n");
101 if (tok[strlen(tok) - 1] == '*')
102 addPrefix(tok, strlen(tok) - 1);
104 addPrefix(tok, strlen(tok) + 1);
109 bool backtrace_is_needed(const char* fname) {
110 static StringPrefixes backtraceFunctionNamePrefixes;
111 return backtraceFunctionNamePrefixes.contain(fname);
124 /* The following two declarations are copied from Android sources */
126 enum DebugTargetKind {
127 kDebugTargetUnknown = 0,
132 struct DebugOutputTarget {
133 DebugTargetKind which;
146 #define THREAD_SELF_NAME "_Z13dvmThreadSelfv"
147 #define CREATE_DEBUG_TARGET_NAME "_Z25dvmCreateFileOutputTargetP17DebugOutputTargetP7__sFILE"
148 #define DUMP_BACKTRACE_NAME "_Z18dvmDumpThreadStackPK17DebugOutputTargetP6Thread"
151 class DalvikBacktraceProvider {
154 void* (*threadself)(void);
155 FILE* streamInMemory;
158 void (*dumpBacktrace)(const DebugOutputTarget*, void*);
159 DebugOutputTarget debugTarget;
162 DalvikBacktraceProvider() {
164 FILE* (*open_memstream_exp)(char**, size_t*);
165 void (*createDebugTarget)(DebugOutputTarget*, FILE*);
166 void* handle = dlopen("/system/lib/libdvm.so", 0);
169 os::log("dlopen failed\n");
172 threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
173 if (threadself == NULL) {
174 os::log("dlsym ThreadSelf failed\n");
177 createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
178 if (createDebugTarget == NULL) {
179 os::log("dlsym CreateFileOutput failed\n");
182 dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
183 if (dumpBacktrace == NULL) {
184 os::log("dlsym DumpThreadStack failed\n");
187 void* handle2 = dlopen("/system/lib/libcutils.so", 0);
189 os::log("dlopen failed\n");
192 open_memstream_exp = (FILE* (*)(char**, size_t*))dlsym(handle2, "open_memstream");
193 if (open_memstream_exp == NULL) {
194 os::log("dlsym open_memstream failed\n");
197 streamInMemory = open_memstream_exp(&buf, &bufSize);
198 if (streamInMemory == NULL) {
199 os::log("open_memstream failed\n");
202 createDebugTarget(&debugTarget, streamInMemory);
203 errorOccured = false;
206 inline char* getBacktrace() {
210 rewind(streamInMemory);
211 dumpBacktrace(&debugTarget, threadself());
212 fflush(streamInMemory);
216 * Parse a stack frame, expecting:
217 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
219 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
221 std::vector<RawStackFrame> parseBacktrace(char *rawBacktrace) {
222 std::vector<RawStackFrame> parsedBacktrace;
223 char* rawBacktrace_it = rawBacktrace;
224 while (*rawBacktrace_it != '\0') {
225 RawStackFrame stackFrame;
226 // TODO: Keep a cache of stack frames
227 stackFrame.id = nextFrameId++;
228 /* skip leading space */
229 while (*rawBacktrace_it == ' ') {
233 rawBacktrace_it += 3;
234 stackFrame.function = rawBacktrace_it;
235 while (*rawBacktrace_it != '(') {
238 *rawBacktrace_it = '\0';
239 stackFrame.filename = rawBacktrace_it + 1;
240 while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
243 if (*rawBacktrace_it == ':') {
244 const char *linenumber = rawBacktrace_it + 1;
245 *rawBacktrace_it = '\0';
246 while (*rawBacktrace_it != ')') {
249 *rawBacktrace_it = '\0';
251 stackFrame.linenumber = atoi(linenumber);
254 stackFrame.filename = NULL;
255 while (*rawBacktrace_it != '\n') {
259 while (*rawBacktrace_it == '\n' || *rawBacktrace_it == ' ') {
262 parsedBacktrace.push_back(stackFrame); /* module */
264 return parsedBacktrace;
268 std::vector<RawStackFrame> get_backtrace() {
269 static DalvikBacktraceProvider backtraceProvider;
270 return backtraceProvider.parseBacktrace(backtraceProvider.getBacktrace());
276 #elif defined(__ELF__)
285 #include <backtrace.h>
289 static char* format(uintptr_t num, int base, char *buf, int maxlen)
291 static const char digits[] = "0123456789abcdef";
294 *--buf = digits[num % base];
297 } while (num != 0 && maxlen != 0);
301 static void dump(const char *str, int len)
303 static int fd = dup(STDERR_FILENO);
304 if (write(fd, str, len) != len) {
309 static void dumpFrame(const RawStackFrame &frame)
311 char buf[sizeof(long long) * 2], *p;
312 #define DUMP(string) dump(string, strlen(string))
313 DUMP(frame.module ? frame.module : "?");
314 if (frame.function) {
316 DUMP(frame.function);
318 if (frame.offset >= 0) {
320 p = format((uintptr_t) frame.offset, 16, buf, sizeof(buf));
321 dump(p, buf + sizeof(buf) - p);
323 if (frame.filename) {
325 DUMP(frame.filename);
326 if (frame.linenumber >= 0) {
328 p = format((uintptr_t) frame.linenumber, 10, buf, sizeof(buf));
329 dump(p, buf + sizeof(buf) - p);
339 class libbacktraceProvider {
340 struct backtrace_state *state;
343 std::map<uintptr_t, std::vector<RawStackFrame> > cache;
344 std::vector<RawStackFrame> *current, *current_frames;
345 RawStackFrame *current_frame;
348 static void bt_err_callback(void *vdata, const char *msg, int errnum)
350 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
352 this_->missingDwarf = true;
354 os::log("libbacktrace: %s: %s\n", msg, strerror(errnum));
356 os::log("libbacktrace: %s\n", msg);
359 static int bt_countskip(void *vdata, uintptr_t pc)
361 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
362 Dl_info info1, info2;
363 if (!dladdr((void*)bt_countskip, &info2)) {
364 os::log("dladdr failed, cannot cull stack traces\n");
367 if (!dladdr((void*)pc, &info1))
369 if (info1.dli_fbase != info2.dli_fbase)
375 static int bt_full_callback(void *vdata, uintptr_t pc,
376 const char *file, int line, const char *func)
378 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
379 RawStackFrame frame = *this_->current_frame;
380 frame.id = this_->nextFrameId++;
381 frame.filename = file;
382 frame.linenumber = line;
384 frame.function = func;
386 if (func && (func = abi::__cxa_demangle(func, NULL, NULL, &status)))
387 frame.function = func;
388 this_->current_frames->push_back(frame);
392 static void dl_fill(RawStackFrame *frame, uintptr_t pc)
395 dladdr((void*)pc, &info);
396 frame->module = info.dli_fname;
397 frame->function = info.dli_sname;
398 frame->offset = info.dli_saddr ? pc - (uintptr_t)info.dli_saddr
399 : pc - (uintptr_t)info.dli_fbase;
402 static int bt_callback(void *vdata, uintptr_t pc)
404 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
405 std::vector<RawStackFrame> &frames = this_->cache[pc];
406 if (!frames.size()) {
409 this_->current_frame = &frame;
410 this_->current_frames = &frames;
411 backtrace_pcinfo(this_->state, pc, bt_full_callback, bt_err_callback, vdata);
412 if (!frames.size()) {
413 frame.id = this_->nextFrameId++;
414 frames.push_back(frame);
417 this_->current->insert(this_->current->end(), frames.begin(), frames.end());
418 return this_->current->size() >= BT_DEPTH;
421 static int bt_full_dump_callback(void *vdata, uintptr_t pc,
422 const char *file, int line, const char *func)
424 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
425 RawStackFrame *frame = this_->current_frame;
426 frame->filename = file;
427 frame->linenumber = line;
429 frame->function = func;
434 static int bt_dump_callback(void *vdata, uintptr_t pc)
436 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
439 this_->current_frame = &frame;
440 this_->missingDwarf = false;
441 backtrace_pcinfo(this_->state, pc, bt_full_dump_callback, bt_err_callback, vdata);
442 if (this_->missingDwarf)
448 libbacktraceProvider():
449 state(backtrace_create_state(NULL, 0, bt_err_callback, NULL))
451 backtrace_simple(state, 0, bt_countskip, bt_err_callback, this);
454 std::vector<RawStackFrame> getParsedBacktrace()
456 std::vector<RawStackFrame> parsedBacktrace;
457 current = &parsedBacktrace;
458 backtrace_simple(state, skipFrames, bt_callback, bt_err_callback, this);
459 return parsedBacktrace;
464 backtrace_simple(state, 0, bt_dump_callback, bt_err_callback, this);
468 std::vector<RawStackFrame> get_backtrace() {
469 static libbacktraceProvider backtraceProvider;
470 return backtraceProvider.getParsedBacktrace();
473 void dump_backtrace() {
474 static libbacktraceProvider backtraceProvider;
475 backtraceProvider.dumpBacktrace();
483 #endif /* ANDROID or LINUX */