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 /*****************************************************************************/ 40 namespace android { 41 42 43 typedef struct { 44 size_t count; 45 size_t ignore; 46 const void** addrs; 47 } stack_crawl_state_t; 48 49 static 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 68 static 69 int 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 81 static 82 const 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 94 static 95 int32_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 115 class 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, uint64_t* start) { 124 mapinfo* mi = getMapInfoList(); 125 while(mi) { 126 if ((pc >= mi->start) && (pc < mi->end)) { 127 if (start) 128 *start = mi->start; 129 return mi->name; 130 } 131 mi = mi->next; 132 } 133 if (start) 134 *start = 0; 135 return def; 136 } 137 138 mapinfo *parse_maps_line(char *line) { 139 mapinfo *mi; 140 int len = strlen(line); 141 if (len < 1) return 0; 142 line[--len] = 0; 143 if (len < 50) return 0; 144 if (line[20] != 'x') return 0; 145 mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47)); 146 if (mi == 0) return 0; 147 mi->start = strtoull(line, 0, 16); 148 mi->end = strtoull(line + 9, 0, 16); 149 mi->next = 0; 150 strcpy(mi->name, line + 49); 151 return mi; 152 } 153 154 mapinfo* getMapInfoList() { 155 Mutex::Autolock _l(mLock); 156 if (milist == 0) { 157 char data[1024]; 158 FILE *fp; 159 sprintf(data, "/proc/%d/maps", getpid()); 160 fp = fopen(data, "r"); 161 if (fp) { 162 while(fgets(data, 1024, fp)) { 163 mapinfo *mi = parse_maps_line(data); 164 if(mi) { 165 mi->next = milist; 166 milist = mi; 167 } 168 } 169 fclose(fp); 170 } 171 } 172 return milist; 173 } 174 mapinfo* milist; 175 Mutex mLock; 176 static MapInfo sMapInfo; 177 178 public: 179 MapInfo() 180 : milist(0) { 181 } 182 183 ~MapInfo() { 184 while (milist) { 185 mapinfo *next = milist->next; 186 free(milist); 187 milist = next; 188 } 189 } 190 191 static const char *mapAddressToName(const void* pc, const char* def, 192 void const** start) 193 { 194 uint64_t s; 195 char const* name = sMapInfo.map_to_name(uint64_t(uintptr_t(pc)), def, &s); 196 if (start) { 197 *start = (void*)s; 198 } 199 return name; 200 } 201 202 }; 203 204 /*****************************************************************************/ 205 206 MapInfo MapInfo::sMapInfo; 207 208 /*****************************************************************************/ 209 210 CallStack::CallStack() 211 : mCount(0) 212 { 213 } 214 215 CallStack::CallStack(const CallStack& rhs) 216 : mCount(rhs.mCount) 217 { 218 if (mCount) { 219 memcpy(mStack, rhs.mStack, mCount*sizeof(void*)); 220 } 221 } 222 223 CallStack::~CallStack() 224 { 225 } 226 227 CallStack& CallStack::operator = (const CallStack& rhs) 228 { 229 mCount = rhs.mCount; 230 if (mCount) { 231 memcpy(mStack, rhs.mStack, mCount*sizeof(void*)); 232 } 233 return *this; 234 } 235 236 bool CallStack::operator == (const CallStack& rhs) const { 237 if (mCount != rhs.mCount) 238 return false; 239 return !mCount || (memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) == 0); 240 } 241 242 bool CallStack::operator != (const CallStack& rhs) const { 243 return !operator == (rhs); 244 } 245 246 bool CallStack::operator < (const CallStack& rhs) const { 247 if (mCount != rhs.mCount) 248 return mCount < rhs.mCount; 249 return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) < 0; 250 } 251 252 bool CallStack::operator >= (const CallStack& rhs) const { 253 return !operator < (rhs); 254 } 255 256 bool CallStack::operator > (const CallStack& rhs) const { 257 if (mCount != rhs.mCount) 258 return mCount > rhs.mCount; 259 return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) > 0; 260 } 261 262 bool CallStack::operator <= (const CallStack& rhs) const { 263 return !operator > (rhs); 264 } 265 266 const void* CallStack::operator [] (int index) const { 267 if (index >= int(mCount)) 268 return 0; 269 return mStack[index]; 270 } 271 272 273 void CallStack::clear() 274 { 275 mCount = 0; 276 } 277 278 void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) 279 { 280 if (maxDepth > MAX_DEPTH) 281 maxDepth = MAX_DEPTH; 282 mCount = backtrace(mStack, ignoreDepth, maxDepth); 283 } 284 285 // Return the stack frame name on the designated level 286 String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const 287 { 288 String8 res; 289 char namebuf[1024]; 290 char tmp[256]; 291 char tmp1[32]; 292 char tmp2[32]; 293 void *offs; 294 295 const void* ip = mStack[level]; 296 if (!ip) return res; 297 298 if (prefix) res.append(prefix); 299 snprintf(tmp1, 32, "#%02d ", level); 300 res.append(tmp1); 301 302 const char* name = lookup_symbol(ip, &offs, namebuf, sizeof(namebuf)); 303 if (name) { 304 if (linux_gcc_demangler(name, tmp, 256) != 0) 305 name = tmp; 306 snprintf(tmp1, 32, "0x%p: <", ip); 307 snprintf(tmp2, 32, ">+0x%p", offs); 308 res.append(tmp1); 309 res.append(name); 310 res.append(tmp2); 311 } else { 312 void const* start = 0; 313 name = MapInfo::mapAddressToName(ip, "<unknown>", &start); 314 snprintf(tmp, 256, "pc %08lx %s", 315 long(uintptr_t(ip)-uintptr_t(start)), name); 316 res.append(tmp); 317 } 318 res.append("\n"); 319 320 return res; 321 } 322 323 // Dump a stack trace to the log 324 void CallStack::dump(const char* prefix) const 325 { 326 /* 327 * Sending a single long log may be truncated since the stack levels can 328 * get very deep. So we request function names of each frame individually. 329 */ 330 for (int i=0; i<int(mCount); i++) { 331 LOGD("%s", toStringSingleLevel(prefix, i).string()); 332 } 333 } 334 335 // Return a string (possibly very long) containing the complete stack trace 336 String8 CallStack::toString(const char* prefix) const 337 { 338 String8 res; 339 340 for (int i=0; i<int(mCount); i++) { 341 res.append(toStringSingleLevel(prefix, i).string()); 342 } 343 344 return res; 345 } 346 347 /*****************************************************************************/ 348 349 }; // namespace android 350