CallStack.cpp revision 83c0446f27b9542d6c2e724817b2b2d8d1f55085
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, 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
178public:
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
206MapInfo MapInfo::sMapInfo;
207
208/*****************************************************************************/
209
210CallStack::CallStack()
211    : mCount(0)
212{
213}
214
215CallStack::CallStack(const CallStack& rhs)
216    : mCount(rhs.mCount)
217{
218    if (mCount) {
219        memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
220    }
221}
222
223CallStack::~CallStack()
224{
225}
226
227CallStack& 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
236bool 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
242bool CallStack::operator != (const CallStack& rhs) const {
243    return !operator == (rhs);
244}
245
246bool 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
252bool CallStack::operator >= (const CallStack& rhs) const {
253    return !operator < (rhs);
254}
255
256bool 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
262bool CallStack::operator <= (const CallStack& rhs) const {
263    return !operator > (rhs);
264}
265
266const void* CallStack::operator [] (int index) const {
267    if (index >= int(mCount))
268        return 0;
269    return mStack[index];
270}
271
272
273void CallStack::clear()
274{
275    mCount = 0;
276}
277
278void 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
286String8 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
324void 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
336String8 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