CallStack.cpp revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "CallStack" 18 19#include <string.h> 20#include <stdlib.h> 21#include <stdio.h> 22 23#if HAVE_DLADDR 24#include <dlfcn.h> 25#endif 26 27#if HAVE_CXXABI 28#include <cxxabi.h> 29#endif 30 31#include <unwind.h> 32 33#include <utils/Log.h> 34#include <utils/Errors.h> 35#include <utils/CallStack.h> 36#include <utils/threads.h> 37 38 39/*****************************************************************************/ 40namespace android { 41 42 43typedef struct { 44 size_t count; 45 size_t ignore; 46 const void** addrs; 47} stack_crawl_state_t; 48 49static 50_Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg) 51{ 52 stack_crawl_state_t* state = (stack_crawl_state_t*)arg; 53 if (state->count) { 54 void* ip = (void*)_Unwind_GetIP(context); 55 if (ip) { 56 if (state->ignore) { 57 state->ignore--; 58 } else { 59 state->addrs[0] = ip; 60 state->addrs++; 61 state->count--; 62 } 63 } 64 } 65 return _URC_NO_REASON; 66} 67 68static 69int backtrace(const void** addrs, size_t ignore, size_t size) 70{ 71 stack_crawl_state_t state; 72 state.count = size; 73 state.ignore = ignore; 74 state.addrs = addrs; 75 _Unwind_Backtrace(trace_function, (void*)&state); 76 return size - state.count; 77} 78 79/*****************************************************************************/ 80 81static 82const char *lookup_symbol(const void* addr, void **offset, char* name, size_t bufSize) 83{ 84#if HAVE_DLADDR 85 Dl_info info; 86 if (dladdr(addr, &info)) { 87 *offset = info.dli_saddr; 88 return info.dli_sname; 89 } 90#endif 91 return NULL; 92} 93 94static 95int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size_t buffersize) 96{ 97 size_t out_len = 0; 98#if HAVE_CXXABI 99 int status = 0; 100 char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status); 101 if (status == 0) { 102 // OK 103 if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len); 104 else out_len = 0; 105 free(demangled); 106 } else { 107 out_len = 0; 108 } 109#endif 110 return out_len; 111} 112 113/*****************************************************************************/ 114 115class MapInfo { 116 struct mapinfo { 117 struct mapinfo *next; 118 uint64_t start; 119 uint64_t end; 120 char name[]; 121 }; 122 123 const char *map_to_name(uint64_t pc, const char* def) { 124 mapinfo* mi = getMapInfoList(); 125 while(mi) { 126 if ((pc >= mi->start) && (pc < mi->end)) 127 return mi->name; 128 mi = mi->next; 129 } 130 return def; 131 } 132 133 mapinfo *parse_maps_line(char *line) { 134 mapinfo *mi; 135 int len = strlen(line); 136 if (len < 1) return 0; 137 line[--len] = 0; 138 if (len < 50) return 0; 139 if (line[20] != 'x') return 0; 140 mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47)); 141 if (mi == 0) return 0; 142 mi->start = strtoull(line, 0, 16); 143 mi->end = strtoull(line + 9, 0, 16); 144 mi->next = 0; 145 strcpy(mi->name, line + 49); 146 return mi; 147 } 148 149 mapinfo* getMapInfoList() { 150 Mutex::Autolock _l(mLock); 151 if (milist == 0) { 152 char data[1024]; 153 FILE *fp; 154 sprintf(data, "/proc/%d/maps", getpid()); 155 fp = fopen(data, "r"); 156 if (fp) { 157 while(fgets(data, 1024, fp)) { 158 mapinfo *mi = parse_maps_line(data); 159 if(mi) { 160 mi->next = milist; 161 milist = mi; 162 } 163 } 164 fclose(fp); 165 } 166 } 167 return milist; 168 } 169 mapinfo* milist; 170 Mutex mLock; 171 static MapInfo sMapInfo; 172 173public: 174 MapInfo() 175 : milist(0) { 176 } 177 178 ~MapInfo() { 179 while (milist) { 180 mapinfo *next = milist->next; 181 free(milist); 182 milist = next; 183 } 184 } 185 186 static const char *mapAddressToName(const void* pc, const char* def) { 187 return sMapInfo.map_to_name((uint64_t)pc, def); 188 } 189 190}; 191 192/*****************************************************************************/ 193 194MapInfo MapInfo::sMapInfo; 195 196/*****************************************************************************/ 197 198CallStack::CallStack() 199 : mCount(0) 200{ 201} 202 203CallStack::CallStack(const CallStack& rhs) 204 : mCount(rhs.mCount) 205{ 206 if (mCount) { 207 memcpy(mStack, rhs.mStack, mCount*sizeof(void*)); 208 } 209} 210 211CallStack::~CallStack() 212{ 213} 214 215CallStack& CallStack::operator = (const CallStack& rhs) 216{ 217 mCount = rhs.mCount; 218 if (mCount) { 219 memcpy(mStack, rhs.mStack, mCount*sizeof(void*)); 220 } 221 return *this; 222} 223 224bool CallStack::operator == (const CallStack& rhs) const { 225 if (mCount != rhs.mCount) 226 return false; 227 return !mCount || (memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) == 0); 228} 229 230bool CallStack::operator != (const CallStack& rhs) const { 231 return !operator == (rhs); 232} 233 234bool CallStack::operator < (const CallStack& rhs) const { 235 if (mCount != rhs.mCount) 236 return mCount < rhs.mCount; 237 return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) < 0; 238} 239 240bool CallStack::operator >= (const CallStack& rhs) const { 241 return !operator < (rhs); 242} 243 244bool CallStack::operator > (const CallStack& rhs) const { 245 if (mCount != rhs.mCount) 246 return mCount > rhs.mCount; 247 return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) > 0; 248} 249 250bool CallStack::operator <= (const CallStack& rhs) const { 251 return !operator > (rhs); 252} 253 254const void* CallStack::operator [] (int index) const { 255 if (index >= int(mCount)) 256 return 0; 257 return mStack[index]; 258} 259 260 261void CallStack::clear() 262{ 263 mCount = 0; 264} 265 266void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) 267{ 268 if (maxDepth > MAX_DEPTH) 269 maxDepth = MAX_DEPTH; 270 mCount = backtrace(mStack, ignoreDepth, maxDepth); 271} 272 273// Return the stack frame name on the designated level 274String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const 275{ 276 String8 res; 277 char namebuf[1024]; 278 char tmp[256]; 279 char tmp1[32]; 280 char tmp2[32]; 281 void *offs; 282 283 const void* ip = mStack[level]; 284 if (!ip) return res; 285 286 if (prefix) res.append(prefix); 287 snprintf(tmp1, 32, "#%02d ", level); 288 res.append(tmp1); 289 290 const char* name = lookup_symbol(ip, &offs, namebuf, sizeof(namebuf)); 291 if (name) { 292 if (linux_gcc_demangler(name, tmp, 256) != 0) 293 name = tmp; 294 snprintf(tmp1, 32, "0x%p: <", ip); 295 snprintf(tmp2, 32, ">+0x%p", offs); 296 res.append(tmp1); 297 res.append(name); 298 res.append(tmp2); 299 } else { 300 name = MapInfo::mapAddressToName(ip, "<unknown>"); 301 snprintf(tmp, 256, "pc %p %s", ip, name); 302 res.append(tmp); 303 } 304 res.append("\n"); 305 306 return res; 307} 308 309// Dump a stack trace to the log 310void CallStack::dump(const char* prefix) const 311{ 312 /* 313 * Sending a single long log may be truncated since the stack levels can 314 * get very deep. So we request function names of each frame individually. 315 */ 316 for (int i=0; i<int(mCount); i++) { 317 LOGD("%s", toStringSingleLevel(prefix, i).string()); 318 } 319} 320 321// Return a string (possibly very long) containing the complete stack trace 322String8 CallStack::toString(const char* prefix) const 323{ 324 String8 res; 325 326 for (int i=0; i<int(mCount); i++) { 327 res.append(toStringSingleLevel(prefix, i).string()); 328 } 329 330 return res; 331} 332 333/*****************************************************************************/ 334 335}; // namespace android 336