blob: 4968666733b4e758f63165bbbec5ec7e57b8f758 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
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, uint32_t *offset, char* name, size_t bufSize)
83{
84#if HAVE_DLADDR
85 Dl_info info;
86 if (dladdr(addr, &info)) {
87 *offset = (uint32_t)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 unsigned start;
119 unsigned end;
120 char name[];
121 };
122
123 const char *map_to_name(unsigned 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 = strtoul(line, 0, 16);
143 mi->end = strtoul(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((unsigned)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 uint32_t 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%08x: <", (size_t)ip);
295 snprintf(tmp2, 32, ">+0x%08x", 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 %08x %s", (size_t)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