#define LOG_TAG "CallStack"
#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#if HAVE_DLADDR
-#include <dlfcn.h>
-#endif
-
-#if HAVE_CXXABI
-#include <cxxabi.h>
-#endif
-
-#include <unwind.h>
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/CallStack.h>
-#include <utils/threads.h>
-
+#include <corkscrew/backtrace.h>
/*****************************************************************************/
namespace android {
-
-typedef struct {
- size_t count;
- size_t ignore;
- const void** addrs;
-} stack_crawl_state_t;
-
-static
-_Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg)
-{
- stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
- if (state->count) {
- void* ip = (void*)_Unwind_GetIP(context);
- if (ip) {
- if (state->ignore) {
- state->ignore--;
- } else {
- state->addrs[0] = ip;
- state->addrs++;
- state->count--;
- }
- }
- }
- return _URC_NO_REASON;
-}
-
-static
-int backtrace(const void** addrs, size_t ignore, size_t size)
-{
- stack_crawl_state_t state;
- state.count = size;
- state.ignore = ignore;
- state.addrs = addrs;
- _Unwind_Backtrace(trace_function, (void*)&state);
- return size - state.count;
-}
-
-/*****************************************************************************/
-
-static
-const char *lookup_symbol(const void* addr, void **offset, char* name, size_t bufSize)
-{
-#if HAVE_DLADDR
- Dl_info info;
- if (dladdr(addr, &info)) {
- *offset = info.dli_saddr;
- return info.dli_sname;
- }
-#endif
- return NULL;
+CallStack::CallStack() :
+ mCount(0) {
}
-static
-int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size_t buffersize)
-{
- size_t out_len = 0;
-#if HAVE_CXXABI
- int status = 0;
- char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status);
- if (status == 0) {
- // OK
- if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len);
- else out_len = 0;
- free(demangled);
- } else {
- out_len = 0;
- }
-#endif
- return out_len;
-}
-
-/*****************************************************************************/
-
-class MapInfo {
- struct mapinfo {
- struct mapinfo *next;
- uint64_t start;
- uint64_t end;
- char name[];
- };
-
- const char *map_to_name(uint64_t pc, const char* def, uint64_t* start) {
- mapinfo* mi = getMapInfoList();
- while(mi) {
- if ((pc >= mi->start) && (pc < mi->end)) {
- if (start)
- *start = mi->start;
- return mi->name;
- }
- mi = mi->next;
- }
- if (start)
- *start = 0;
- return def;
- }
-
- mapinfo *parse_maps_line(char *line) {
- mapinfo *mi;
- int len = strlen(line);
- if (len < 1) return 0;
- line[--len] = 0;
- if (len < 50) return 0;
- if (line[20] != 'x') return 0;
- mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47));
- if (mi == 0) return 0;
- mi->start = strtoull(line, 0, 16);
- mi->end = strtoull(line + 9, 0, 16);
- mi->next = 0;
- strcpy(mi->name, line + 49);
- return mi;
- }
-
- mapinfo* getMapInfoList() {
- Mutex::Autolock _l(mLock);
- if (milist == 0) {
- char data[1024];
- FILE *fp;
- sprintf(data, "/proc/%d/maps", getpid());
- fp = fopen(data, "r");
- if (fp) {
- while(fgets(data, 1024, fp)) {
- mapinfo *mi = parse_maps_line(data);
- if(mi) {
- mi->next = milist;
- milist = mi;
- }
- }
- fclose(fp);
- }
- }
- return milist;
- }
- mapinfo* milist;
- Mutex mLock;
- static MapInfo sMapInfo;
-
-public:
- MapInfo()
- : milist(0) {
- }
-
- ~MapInfo() {
- while (milist) {
- mapinfo *next = milist->next;
- free(milist);
- milist = next;
- }
- }
-
- static const char *mapAddressToName(const void* pc, const char* def,
- void const** start)
- {
- uint64_t s;
- char const* name = sMapInfo.map_to_name(uint64_t(uintptr_t(pc)), def, &s);
- if (start) {
- *start = (void*)s;
- }
- return name;
- }
-
-};
-
-/*****************************************************************************/
-
-MapInfo MapInfo::sMapInfo;
-
-/*****************************************************************************/
-
-CallStack::CallStack()
- : mCount(0)
-{
-}
-
-CallStack::CallStack(const CallStack& rhs)
- : mCount(rhs.mCount)
-{
+CallStack::CallStack(const CallStack& rhs) :
+ mCount(rhs.mCount) {
if (mCount) {
- memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
+ memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
}
}
-CallStack::~CallStack()
-{
+CallStack::~CallStack() {
}
-CallStack& CallStack::operator = (const CallStack& rhs)
-{
+CallStack& CallStack::operator = (const CallStack& rhs) {
mCount = rhs.mCount;
if (mCount) {
- memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
+ memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
}
return *this;
}
bool CallStack::operator == (const CallStack& rhs) const {
if (mCount != rhs.mCount)
return false;
- return !mCount || (memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) == 0);
+ return !mCount || memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) == 0;
}
bool CallStack::operator != (const CallStack& rhs) const {
bool CallStack::operator < (const CallStack& rhs) const {
if (mCount != rhs.mCount)
return mCount < rhs.mCount;
- return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) < 0;
+ return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) < 0;
}
bool CallStack::operator >= (const CallStack& rhs) const {
bool CallStack::operator > (const CallStack& rhs) const {
if (mCount != rhs.mCount)
return mCount > rhs.mCount;
- return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) > 0;
+ return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) > 0;
}
bool CallStack::operator <= (const CallStack& rhs) const {
const void* CallStack::operator [] (int index) const {
if (index >= int(mCount))
return 0;
- return mStack[index];
+ return reinterpret_cast<const void*>(mStack[index].absolute_pc);
}
-
-void CallStack::clear()
-{
+void CallStack::clear() {
mCount = 0;
}
-void CallStack::update(int32_t ignoreDepth, int32_t maxDepth)
-{
- if (maxDepth > MAX_DEPTH)
+void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) {
+ if (maxDepth > MAX_DEPTH) {
maxDepth = MAX_DEPTH;
- mCount = backtrace(mStack, ignoreDepth, maxDepth);
-}
-
-// Return the stack frame name on the designated level
-String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
-{
- String8 res;
- char namebuf[1024];
- char tmp[256];
- char tmp1[32];
- char tmp2[32];
- void *offs;
-
- const void* ip = mStack[level];
- if (!ip) return res;
-
- if (prefix) res.append(prefix);
- snprintf(tmp1, 32, "#%02d ", level);
- res.append(tmp1);
-
- const char* name = lookup_symbol(ip, &offs, namebuf, sizeof(namebuf));
- if (name) {
- if (linux_gcc_demangler(name, tmp, 256) != 0)
- name = tmp;
- snprintf(tmp1, 32, "0x%p: <", ip);
- snprintf(tmp2, 32, ">+0x%p", offs);
- res.append(tmp1);
- res.append(name);
- res.append(tmp2);
- } else {
- void const* start = 0;
- name = MapInfo::mapAddressToName(ip, "<unknown>", &start);
- snprintf(tmp, 256, "pc %08lx %s",
- long(uintptr_t(ip)-uintptr_t(start)), name);
- res.append(tmp);
}
- res.append("\n");
-
- return res;
-}
-
-// Dump a stack trace to the log
-void CallStack::dump(const char* prefix) const
-{
- /*
- * Sending a single long log may be truncated since the stack levels can
- * get very deep. So we request function names of each frame individually.
- */
- for (int i=0; i<int(mCount); i++) {
- LOGD("%s", toStringSingleLevel(prefix, i).string());
+ ssize_t count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
+ mCount = count > 0 ? count : 0;
+}
+
+void CallStack::dump(const char* prefix) const {
+ backtrace_symbol_t symbols[mCount];
+
+ get_backtrace_symbols(mStack, mCount, symbols);
+ for (size_t i = 0; i < mCount; i++) {
+ const backtrace_frame_t& frame = mStack[i];
+ const backtrace_symbol_t& symbol = symbols[i];
+ const char* mapName = symbol.map_info ? symbol.map_info->name : "<unknown>";
+ const char* symbolName = symbol.demangled_name ? symbol.demangled_name : symbol.name;
+ if (symbolName) {
+ LOGD("%s#%02d pc %08x %s (%s)\n", prefix,
+ int(i), uint32_t(symbol.relative_pc), mapName, symbolName);
+ } else {
+ LOGD("%s#%02d pc %08x %s\n", prefix,
+ int(i), uint32_t(symbol.relative_pc), mapName);
+ }
}
-}
-
-// Return a string (possibly very long) containing the complete stack trace
-String8 CallStack::toString(const char* prefix) const
-{
- String8 res;
-
- for (int i=0; i<int(mCount); i++) {
- res.append(toStringSingleLevel(prefix, i).string());
+ free_backtrace_symbols(symbols, mCount);
+}
+
+String8 CallStack::toString(const char* prefix) const {
+ String8 str;
+ backtrace_symbol_t symbols[mCount];
+
+ get_backtrace_symbols(mStack, mCount, symbols);
+ for (size_t i = 0; i < mCount; i++) {
+ const backtrace_frame_t& frame = mStack[i];
+ const backtrace_symbol_t& symbol = symbols[i];
+ const char* mapName = symbol.map_info ? symbol.map_info->name : "<unknown>";
+ const char* symbolName = symbol.demangled_name ? symbol.demangled_name : symbol.name;
+ if (symbolName) {
+ str.appendFormat("%s#%02d pc %08x %s (%s)\n", prefix,
+ int(i), uint32_t(symbol.relative_pc), mapName, symbolName);
+ } else {
+ str.appendFormat("%s#%02d pc %08x %s\n", prefix,
+ int(i), uint32_t(symbol.relative_pc), mapName);
+ }
}
-
- return res;
+ free_backtrace_symbols(symbols, mCount);
+ return str;
}
-/*****************************************************************************/
-
}; // namespace android