Home | History | Annotate | Download | only in utils
      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