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) || defined(__ELF__)
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 class StringPrefixes {
70 std::set<pstring> pset;
72 void addPrefix(char* startbuf, int n) {
73 std::set<pstring>::iterator elem = pset.find(pstring(startbuf, n));
74 bool replace = elem != pset.end() && n < elem->n;
78 if (replace || elem == pset.end()) {
79 pset.insert(pstring(startbuf, n));
85 bool contain(const char* s) {
86 return pset.find(pstring(s, strlen(s) + 1)) != pset.end();
90 StringPrefixes::StringPrefixes() {
91 char *list = getenv("APITRACE_BACKTRACE");
94 for (char *t = strdup(list); ; t = NULL) {
95 char *tok = strtok(t, " \t\r\n");
100 if (tok[strlen(tok) - 1] == '*')
101 addPrefix(tok, strlen(tok) - 1);
103 addPrefix(tok, strlen(tok) + 1);
108 bool backtrace_is_needed(const char* fname) {
109 static StringPrefixes backtraceFunctionNamePrefixes;
110 return backtraceFunctionNamePrefixes.contain(fname);
113 } /* namespace trace */
123 /* The following two declarations are copied from Android sources */
125 enum DebugTargetKind {
126 kDebugTargetUnknown = 0,
131 struct DebugOutputTarget {
132 DebugTargetKind which;
145 #define THREAD_SELF_NAME "_Z13dvmThreadSelfv"
146 #define CREATE_DEBUG_TARGET_NAME "_Z25dvmCreateFileOutputTargetP17DebugOutputTargetP7__sFILE"
147 #define DUMP_BACKTRACE_NAME "_Z18dvmDumpThreadStackPK17DebugOutputTargetP6Thread"
150 class DalvikBacktraceProvider {
153 void* (*threadself)(void);
154 FILE* streamInMemory;
157 void (*dumpBacktrace)(const DebugOutputTarget*, void*);
158 DebugOutputTarget debugTarget;
161 DalvikBacktraceProvider() {
163 FILE* (*open_memstream_exp)(char**, size_t*);
164 void (*createDebugTarget)(DebugOutputTarget*, FILE*);
165 void* handle = dlopen("/system/lib/libdvm.so", 0);
168 os::log("dlopen failed\n");
171 threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
172 if (threadself == NULL) {
173 os::log("dlsym ThreadSelf failed\n");
176 createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
177 if (createDebugTarget == NULL) {
178 os::log("dlsym CreateFileOutput failed\n");
181 dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
182 if (dumpBacktrace == NULL) {
183 os::log("dlsym DumpThreadStack failed\n");
186 void* handle2 = dlopen("/system/lib/libcutils.so", 0);
188 os::log("dlopen failed\n");
191 open_memstream_exp = (FILE* (*)(char**, size_t*))dlsym(handle2, "open_memstream");
192 if (open_memstream_exp == NULL) {
193 os::log("dlsym open_memstream failed\n");
196 streamInMemory = open_memstream_exp(&buf, &bufSize);
197 if (streamInMemory == NULL) {
198 os::log("open_memstream failed\n");
201 createDebugTarget(&debugTarget, streamInMemory);
202 errorOccured = false;
205 inline char* getBacktrace() {
209 rewind(streamInMemory);
210 dumpBacktrace(&debugTarget, threadself());
211 fflush(streamInMemory);
215 * Parse a stack frame, expecting:
216 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
218 * " at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
220 std::vector<RawStackFrame> parseBacktrace(char *rawBacktrace) {
221 std::vector<RawStackFrame> parsedBacktrace;
222 char* rawBacktrace_it = rawBacktrace;
223 while (*rawBacktrace_it != '\0') {
224 RawStackFrame stackFrame;
225 // TODO: Keep a cache of stack frames
226 stackFrame.id = nextFrameId++;
227 /* skip leading space */
228 while (*rawBacktrace_it == ' ') {
232 rawBacktrace_it += 3;
233 stackFrame.function = rawBacktrace_it;
234 while (*rawBacktrace_it != '(') {
237 *rawBacktrace_it = '\0';
238 stackFrame.filename = rawBacktrace_it + 1;
239 while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
242 if (*rawBacktrace_it == ':') {
243 const char *linenumber = rawBacktrace_it + 1;
244 *rawBacktrace_it = '\0';
245 while (*rawBacktrace_it != ')') {
248 *rawBacktrace_it = '\0';
250 stackFrame.linenumber = atoi(linenumber);
253 stackFrame.filename = NULL;
254 while (*rawBacktrace_it != '\n') {
258 while (*rawBacktrace_it == '\n' || *rawBacktrace_it == ' ') {
261 parsedBacktrace.push_back(stackFrame); /* module */
263 return parsedBacktrace;
267 std::vector<RawStackFrame> get_backtrace() {
268 static DalvikBacktraceProvider backtraceProvider;
269 return backtraceProvider.parseBacktrace(backtraceProvider.getBacktrace());
273 #elif defined(__ELF__)
281 #include <backtrace.h>
290 class libbacktraceProvider {
291 struct backtrace_state *state;
294 std::map<uintptr_t, std::vector<RawStackFrame> > cache;
295 std::vector<RawStackFrame> *current, *current_frames;
296 RawStackFrame *current_frame;
298 static void bt_err_callback(void *vdata, const char *msg, int errnum)
301 return;// no debug/sym info
303 os::log("libbacktrace: %s: %s\n", msg, strerror(errnum));
305 os::log("libbacktrace: %s\n", msg);
308 static int bt_countskip(void *vdata, uintptr_t pc)
310 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
311 Dl_info info1, info2;
312 if (!dladdr((void*)bt_countskip, &info2)) {
313 os::log("dladdr failed, cannot cull stack traces\n");
316 if (!dladdr((void*)pc, &info1))
318 if (info1.dli_fbase != info2.dli_fbase)
324 static int bt_full_callback(void *vdata, uintptr_t pc,
325 const char *file, int line, const char *func)
327 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
328 RawStackFrame frame = *this_->current_frame;
329 frame.id = this_->nextFrameId++;
330 frame.filename = file;
331 frame.linenumber = line;
333 frame.function = func;
335 if (func && (func = abi::__cxa_demangle(func, NULL, NULL, &status)))
336 frame.function = func;
337 this_->current_frames->push_back(frame);
341 static int bt_callback(void *vdata, uintptr_t pc)
343 libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
344 std::vector<RawStackFrame> &frames = this_->cache[pc];
345 if (!frames.size()) {
348 dladdr((void*)pc, &info);
349 frame.module = info.dli_fname;
350 frame.function = info.dli_sname;
351 frame.offset = info.dli_saddr ? pc - (uintptr_t)info.dli_saddr
352 : pc - (uintptr_t)info.dli_fbase;
353 this_->current_frame = &frame;
354 this_->current_frames = &frames;
355 backtrace_pcinfo(this_->state, pc, bt_full_callback, bt_err_callback, vdata);
356 if (!frames.size()) {
357 frame.id = this_->nextFrameId++;
358 frames.push_back(frame);
361 this_->current->insert(this_->current->end(), frames.begin(), frames.end());
362 return this_->current->size() >= BT_DEPTH;
366 libbacktraceProvider():
367 state(backtrace_create_state(NULL, 0, bt_err_callback, NULL))
369 backtrace_simple(state, 0, bt_countskip, bt_err_callback, this);
372 std::vector<RawStackFrame> getParsedBacktrace()
374 std::vector<RawStackFrame> parsedBacktrace;
375 current = &parsedBacktrace;
376 backtrace_simple(state, skipFrames, bt_callback, bt_err_callback, this);
377 return parsedBacktrace;
381 std::vector<RawStackFrame> get_backtrace() {
382 static libbacktraceProvider backtraceProvider;
383 return backtraceProvider.getParsedBacktrace();
388 } /* namespace trace */
390 #endif /* ANDROID or LINUX */