From 044966aef3c9b58e798d624138ae21c85967ecb9 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Wed, 19 Oct 2011 20:32:43 -0700 Subject: Use libcorkscrew for stack unwinding. Change-Id: Iee1ee5a2018ab8cfc1ce12ec2a124809245eaa02 --- libs/utils/Android.mk | 3 +- libs/utils/CallStack.cpp | 324 +++++++++-------------------------------------- 2 files changed, 60 insertions(+), 267 deletions(-) (limited to 'libs/utils') diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index 831d9e3..d168d19 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -105,7 +105,8 @@ LOCAL_SHARED_LIBRARIES := \ libz \ liblog \ libcutils \ - libdl + libdl \ + libcorkscrew LOCAL_MODULE:= libutils include $(BUILD_SHARED_LIBRARY) diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp index 55b6024..d79a757 100644 --- a/libs/utils/CallStack.cpp +++ b/libs/utils/CallStack.cpp @@ -17,218 +17,33 @@ #define LOG_TAG "CallStack" #include -#include -#include - -#if HAVE_DLADDR -#include -#endif - -#if HAVE_CXXABI -#include -#endif - -#include #include #include #include -#include - +#include /*****************************************************************************/ 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; } @@ -236,7 +51,7 @@ CallStack& CallStack::operator = (const CallStack& rhs) 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 { @@ -246,7 +61,7 @@ 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 { @@ -256,7 +71,7 @@ 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 { @@ -266,84 +81,61 @@ 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(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, "", &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 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 : ""; + 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; iname : ""; + 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 -- cgit v1.1