OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / libs / utils / CallStack.cpp
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