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
33 #include "os_backtrace.hpp"
48 # include <backtrace.h>
57 * Pascal string (with zero terminator optionally omitted)
58 * This is a helper class for storing a set of exact strings or prefixes
59 * to match a zero-terminated string against later.
60 * Two zero-terminated pstrings compare equal iff they are the same.
61 * Otherwise, they compare equal iff one is a prefix of the other
62 * (a zero-terminated pstring cannot be a prefix)
68 pstring(const char* s, int n)
73 bool operator<(const pstring q2) const
75 return memcmp(s, q2.s, n < q2.n? n : q2.n) < 0;
80 class StringPrefixes {
82 std::set<pstring> pset;
84 void addPrefix(char* startbuf, int n) {
85 std::set<pstring>::iterator elem = pset.find(pstring(startbuf, n));
86 bool replace = elem != pset.end() && n < elem->n;
90 if (replace || elem == pset.end()) {
91 pset.insert(pstring(startbuf, n));
97 bool contain(const char* s) {
98 return pset.find(pstring(s, strlen(s) + 1)) != pset.end();
102 StringPrefixes::StringPrefixes() {
103 char *list = getenv("APITRACE_BACKTRACE");
106 for (char *t = strdup(list); ; t = NULL) {
107 char *tok = strtok(t, " \t\r\n");
112 if (tok[strlen(tok) - 1] == '*')
113 addPrefix(tok, strlen(tok) - 1);
115 addPrefix(tok, strlen(tok) + 1);
120 bool backtrace_is_needed(const char* fname) {
121 static StringPrefixes backtraceFunctionNamePrefixes;
122 return backtraceFunctionNamePrefixes.contain(fname);
127 /* The following two declarations are copied from Android sources */
129 enum DebugTargetKind {
130 kDebugTargetUnknown = 0,
135 struct DebugOutputTarget {
136 DebugTargetKind which;
149 #define THREAD_SELF_NAME "_Z13dvmThreadSelfv"
150 #define CREATE_DEBUG_TARGET_NAME "_Z25dvmCreateFileOutputTargetP17DebugOutputTargetP7__sFILE"
151 #define DUMP_BACKTRACE_NAME "_Z18dvmDumpThreadStackPK17DebugOutputTargetP6Thread"
154 class DalvikBacktraceProvider {
157 void* (*threadself)(void);
158 FILE* streamInMemory;
161 void (*dumpBacktrace)(const DebugOutputTarget*, void*);
162 DebugOutputTarget debugTarget;
165 DalvikBacktraceProvider() {
167 FILE* (*open_memstream_exp)(char**, size_t*);
168 void (*createDebugTarget)(DebugOutputTarget*, FILE*);
169 void* handle = dlopen("/system/lib/libdvm.so", 0);
172 os::log("dlopen failed\n");
175 threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
176 if (threadself == NULL) {
177 os::log("dlsym ThreadSelf failed\n");
180 createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
181 if (createDebugTarget == NULL) {
182 os::log("dlsym CreateFileOutput failed\n");
185 dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
186 if (dumpBacktrace == NULL) {
187 os::log("dlsym DumpThreadStack failed\n");
190 void* handle2 = dlopen("/system/lib/libcutils.so", 0);
192 os::log("dlopen failed\n");
195 open_memstream_exp = (FILE* (*)(char**, size_t*))dlsym(handle2, "open_memstream");
196 if (open_memstream_exp == NULL) {
197 os::log("dlsym open_memstream failed\n");
200 streamInMemory = open_memstream_exp(&buf, &bufSize);
201 if (streamInMemory == NULL) {
202 os::log("open_memstream failed\n");
205 createDebugTarget(&debugTarget, streamInMemory);
206 errorOccured = false;
209 inline char* getBacktrace() {
213 rewind(streamInMemory);
214 dumpBacktrace(&debugTarget, threadself());
215 fflush(streamInMemory);
219 * Parse a stack frame, expecting:
220 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
222 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
224 std::vector<RawStackFrame> parseBacktrace(char *rawBacktrace) {
225 std::vector<RawStackFrame> parsedBacktrace;
226 char* rawBacktrace_it = rawBacktrace;
227 while (*rawBacktrace_it != '\0') {
228 RawStackFrame stackFrame;
229 // TODO: Keep a cache of stack frames
230 stackFrame.id = nextFrameId++;
231 /* skip leading space */
232 while (*rawBacktrace_it == ' ') {
236 rawBacktrace_it += 3;
237 stackFrame.function = rawBacktrace_it;
238 while (*rawBacktrace_it != '(') {
241 *rawBacktrace_it = '\0';
242 stackFrame.filename = rawBacktrace_it + 1;
243 while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
246 if (*rawBacktrace_it == ':') {
247 const char *linenumber = rawBacktrace_it + 1;
248 *rawBacktrace_it = '\0';
249 while (*rawBacktrace_it != ')') {
252 *rawBacktrace_it = '\0';
254 stackFrame.linenumber = atoi(linenumber);
257 stackFrame.filename = NULL;
258 while (*rawBacktrace_it != '\n') {
262 while (*rawBacktrace_it == '\n' || *rawBacktrace_it == ' ') {
265 parsedBacktrace.push_back(stackFrame); /* module */
267 return parsedBacktrace;
271 std::vector<RawStackFrame> get_backtrace() {
272 static DalvikBacktraceProvider backtraceProvider;
273 return backtraceProvider.parseBacktrace(backtraceProvider.getBacktrace());
276 void dump_backtrace() {
284 static char* format(uintptr_t num, int base, char *buf, int maxlen)
286 static const char digits[] = "0123456789abcdef";
289 *--buf = digits[num % base];
292 } while (num != 0 && maxlen != 0);
296 static void dump(const char *str, int len)
298 static int fd = dup(STDERR_FILENO);
299 if (write(fd, str, len) != len) {
304 static void dumpFrame(const RawStackFrame &frame)
306 char buf[sizeof(long long) * 2], *p;
307 #define DUMP(string) dump(string, strlen(string))
308 DUMP(frame.module ? frame.module : "?");
309 if (frame.function) {
311 DUMP(frame.function);
313 if (frame.offset >= 0) {
315 p = format((uintptr_t) frame.offset, 16, buf, sizeof(buf));
316 dump(p, buf + sizeof(buf) - p);
318 if (frame.filename) {
320 DUMP(frame.filename);
321 if (frame.linenumber >= 0) {
323 p = format((uintptr_t) frame.linenumber, 10, buf, sizeof(buf));
324 dump(p, buf + sizeof(buf) - p);
334 class libbacktraceProvider {
335 struct backtrace_state *state;
338 std::map<uintptr_t, std::vector<RawStackFrame> > cache;
339 std::vector<RawStackFrame> *current, *current_frames;
340 RawStackFrame *current_frame;
343 static void bt_err_callback(void *vdata, const char *msg, int errnum)
345 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
347 this_->missingDwarf = true;
349 os::log("libbacktrace: %s: %s\n", msg, strerror(errnum));
351 os::log("libbacktrace: %s\n", msg);
354 static int bt_countskip(void *vdata, uintptr_t pc)
356 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
357 Dl_info info1, info2;
358 if (!dladdr((void*)bt_countskip, &info2)) {
359 os::log("dladdr failed, cannot cull stack traces\n");
362 if (!dladdr((void*)pc, &info1))
364 if (info1.dli_fbase != info2.dli_fbase)
370 static int bt_full_callback(void *vdata, uintptr_t pc,
371 const char *file, int line, const char *func)
373 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
374 RawStackFrame frame = *this_->current_frame;
375 frame.id = this_->nextFrameId++;
376 frame.filename = file;
377 frame.linenumber = line;
379 frame.function = func;
381 if (func && (func = abi::__cxa_demangle(func, NULL, NULL, &status)))
382 frame.function = func;
383 this_->current_frames->push_back(frame);
387 static void dl_fill(RawStackFrame *frame, uintptr_t pc)
390 dladdr((void*)pc, &info);
391 frame->module = info.dli_fname;
392 frame->function = info.dli_sname;
393 frame->offset = info.dli_saddr ? pc - (uintptr_t)info.dli_saddr
394 : pc - (uintptr_t)info.dli_fbase;
397 static int bt_callback(void *vdata, uintptr_t pc)
399 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
400 std::vector<RawStackFrame> &frames = this_->cache[pc];
401 if (!frames.size()) {
404 this_->current_frame = &frame;
405 this_->current_frames = &frames;
406 backtrace_pcinfo(this_->state, pc, bt_full_callback, bt_err_callback, vdata);
407 if (!frames.size()) {
408 frame.id = this_->nextFrameId++;
409 frames.push_back(frame);
412 this_->current->insert(this_->current->end(), frames.begin(), frames.end());
413 return this_->current->size() >= BT_DEPTH;
416 static int bt_full_dump_callback(void *vdata, uintptr_t pc,
417 const char *file, int line, const char *func)
419 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
420 RawStackFrame *frame = this_->current_frame;
421 frame->filename = file;
422 frame->linenumber = line;
424 frame->function = func;
429 static int bt_dump_callback(void *vdata, uintptr_t pc)
431 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
434 this_->current_frame = &frame;
435 this_->missingDwarf = false;
436 backtrace_pcinfo(this_->state, pc, bt_full_dump_callback, bt_err_callback, vdata);
437 if (this_->missingDwarf)
443 libbacktraceProvider():
444 state(backtrace_create_state(NULL, 0, bt_err_callback, NULL))
446 backtrace_simple(state, 0, bt_countskip, bt_err_callback, this);
449 std::vector<RawStackFrame> getParsedBacktrace()
451 std::vector<RawStackFrame> parsedBacktrace;
452 current = &parsedBacktrace;
453 backtrace_simple(state, skipFrames, bt_callback, bt_err_callback, this);
454 return parsedBacktrace;
459 backtrace_simple(state, 0, bt_dump_callback, bt_err_callback, this);
463 std::vector<RawStackFrame> get_backtrace() {
464 static libbacktraceProvider backtraceProvider;
465 return backtraceProvider.getParsedBacktrace();
468 void dump_backtrace() {
469 static libbacktraceProvider backtraceProvider;
470 backtraceProvider.dumpBacktrace();
474 #else /* !HAVE_BACKTRACE */
476 std::vector<RawStackFrame> get_backtrace() {
477 return std::vector<RawStackFrame>();
480 void dump_backtrace() {