blob: ccfce81a0ec0b1e67be2b7a1f40754535d1cdf91 [file] [log] [blame]
Christopher Ferris17e91d42013-10-21 13:30:52 -07001/*
2 * Copyright (C) 2013 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#include <errno.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/ptrace.h>
21#include <sys/types.h>
22#include <unistd.h>
23
24#define __STDC_FORMAT_MACROS
25#include <inttypes.h>
26
27#include <string>
28
29#include <backtrace/Backtrace.h>
30#include <cutils/log.h>
31
32#include "Backtrace.h"
33#include "thread_utils.h"
34
35//-------------------------------------------------------------------------
36// BacktraceImpl functions.
37//-------------------------------------------------------------------------
38backtrace_t* BacktraceImpl::GetBacktraceData() {
39 return &backtrace_obj_->backtrace_;
40}
41
42//-------------------------------------------------------------------------
43// Backtrace functions.
44//-------------------------------------------------------------------------
Christopher Ferris98464972014-01-06 19:16:33 -080045Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, backtrace_map_info_t* map_info)
46 : impl_(impl), map_info_(map_info), map_info_requires_delete_(false) {
Christopher Ferris17e91d42013-10-21 13:30:52 -070047 impl_->SetParent(this);
48 backtrace_.num_frames = 0;
Christopher Ferris98464972014-01-06 19:16:33 -080049 backtrace_.pid = pid;
Christopher Ferris17e91d42013-10-21 13:30:52 -070050 backtrace_.tid = -1;
Christopher Ferris98464972014-01-06 19:16:33 -080051
52 if (map_info_ == NULL) {
53 // Create the map and manage it internally.
54 map_info_ = backtrace_create_map_info_list(pid);
55 map_info_requires_delete_ = true;
56 }
Christopher Ferris17e91d42013-10-21 13:30:52 -070057}
58
59Backtrace::~Backtrace() {
60 for (size_t i = 0; i < NumFrames(); i++) {
61 if (backtrace_.frames[i].func_name) {
62 free(backtrace_.frames[i].func_name);
63 backtrace_.frames[i].func_name = NULL;
64 }
65 }
66
Christopher Ferris98464972014-01-06 19:16:33 -080067 if (map_info_ && map_info_requires_delete_) {
Christopher Ferris17e91d42013-10-21 13:30:52 -070068 backtrace_destroy_map_info_list(map_info_);
69 map_info_ = NULL;
70 }
71
72 if (impl_) {
73 delete impl_;
74 impl_ = NULL;
75 }
76}
77
78bool Backtrace::Unwind(size_t num_ignore_frames) {
79 return impl_->Unwind(num_ignore_frames);
80}
81
Christopher Ferris8ed46272013-10-29 15:44:25 -070082extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
83 int* status);
Christopher Ferris17e91d42013-10-21 13:30:52 -070084
85std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
86 std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
87 if (!func_name.empty()) {
88#if defined(__APPLE__)
89 // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
90 if (symbol_name[0] != '_') {
91 return func_name;
92 }
93#endif
94 char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
95 if (name) {
96 func_name = name;
97 free(name);
98 }
99 }
100 return func_name;
101}
102
103bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
104 if (ptr & 3) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700105 BACK_LOGW("invalid pointer %p", (void*)ptr);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700106 *out_value = (uint32_t)-1;
107 return false;
108 }
109 return true;
110}
111
112const char* Backtrace::GetMapName(uintptr_t pc, uintptr_t* map_start) {
113 const backtrace_map_info_t* map_info = FindMapInfo(pc);
114 if (map_info) {
115 if (map_start) {
116 *map_start = map_info->start;
117 }
118 return map_info->name;
119 }
120 return NULL;
121}
122
123const backtrace_map_info_t* Backtrace::FindMapInfo(uintptr_t ptr) {
124 return backtrace_find_map_info(map_info_, ptr);
125}
126
127std::string Backtrace::FormatFrameData(size_t frame_num) {
128 backtrace_frame_data_t* frame = &backtrace_.frames[frame_num];
129 const char* map_name;
130 if (frame->map_name) {
131 map_name = frame->map_name;
132 } else {
133 map_name = "<unknown>";
134 }
135 uintptr_t relative_pc;
136 if (frame->map_offset) {
137 relative_pc = frame->map_offset;
138 } else {
139 relative_pc = frame->pc;
140 }
141
142 char buf[512];
143 if (frame->func_name && frame->func_offset) {
144 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")",
145 frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
146 frame->func_name, frame->func_offset);
147 } else if (frame->func_name) {
148 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame_num,
149 (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name);
150 } else {
151 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame_num,
152 (int)sizeof(uintptr_t)*2, relative_pc, map_name);
153 }
154
155 return buf;
156}
157
158//-------------------------------------------------------------------------
159// BacktraceCurrent functions.
160//-------------------------------------------------------------------------
Christopher Ferris98464972014-01-06 19:16:33 -0800161BacktraceCurrent::BacktraceCurrent(
162 BacktraceImpl* impl, backtrace_map_info_t *map_info) : Backtrace(impl, getpid(), map_info) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700163
164 backtrace_.pid = getpid();
165}
166
167BacktraceCurrent::~BacktraceCurrent() {
168}
169
170bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
171 if (!VerifyReadWordArgs(ptr, out_value)) {
172 return false;
173 }
174
175 const backtrace_map_info_t* map_info = FindMapInfo(ptr);
176 if (map_info && map_info->is_readable) {
177 *out_value = *reinterpret_cast<uint32_t*>(ptr);
178 return true;
179 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700180 BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
Christopher Ferris17e91d42013-10-21 13:30:52 -0700181 *out_value = static_cast<uint32_t>(-1);
182 return false;
183 }
184}
185
186//-------------------------------------------------------------------------
187// BacktracePtrace functions.
188//-------------------------------------------------------------------------
Christopher Ferris98464972014-01-06 19:16:33 -0800189BacktracePtrace::BacktracePtrace(
190 BacktraceImpl* impl, pid_t pid, pid_t tid, backtrace_map_info_t* map_info)
191 : Backtrace(impl, pid, map_info) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700192 backtrace_.tid = tid;
193}
194
195BacktracePtrace::~BacktracePtrace() {
196}
197
198bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
199 if (!VerifyReadWordArgs(ptr, out_value)) {
200 return false;
201 }
202
203#if defined(__APPLE__)
Christopher Ferris8ed46272013-10-29 15:44:25 -0700204 BACK_LOGW("MacOS does not support reading from another pid.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700205 return false;
206#else
207 // ptrace() returns -1 and sets errno when the operation fails.
208 // To disambiguate -1 from a valid result, we clear errno beforehand.
209 errno = 0;
210 *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
211 if (*out_value == static_cast<uint32_t>(-1) && errno) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700212 BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
213 reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
Christopher Ferris17e91d42013-10-21 13:30:52 -0700214 return false;
215 }
216 return true;
217#endif
218}
219
Christopher Ferris98464972014-01-06 19:16:33 -0800220Backtrace* Backtrace::Create(pid_t pid, pid_t tid, backtrace_map_info_t* map_info) {
Christopher Ferriscbfc7302013-11-05 11:04:12 -0800221 if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) {
222 if (tid == BACKTRACE_NO_TID || tid == gettid()) {
Christopher Ferris98464972014-01-06 19:16:33 -0800223 return CreateCurrentObj(map_info);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700224 } else {
Christopher Ferris98464972014-01-06 19:16:33 -0800225 return CreateThreadObj(tid, map_info);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700226 }
Christopher Ferriscbfc7302013-11-05 11:04:12 -0800227 } else if (tid == BACKTRACE_NO_TID) {
Christopher Ferris98464972014-01-06 19:16:33 -0800228 return CreatePtraceObj(pid, pid, map_info);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700229 } else {
Christopher Ferris98464972014-01-06 19:16:33 -0800230 return CreatePtraceObj(pid, tid, map_info);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700231 }
232}
233
234//-------------------------------------------------------------------------
235// Common interface functions.
236//-------------------------------------------------------------------------
Christopher Ferris98464972014-01-06 19:16:33 -0800237bool backtrace_create_context_with_map(
238 backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames,
239 backtrace_map_info_t* map_info) {
240 Backtrace* backtrace = Backtrace::Create(pid, tid, map_info);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700241 if (!backtrace) {
242 return false;
243 }
244 if (!backtrace->Unwind(num_ignore_frames)) {
245 delete backtrace;
246 return false;
247 }
248
249 context->data = backtrace;
250 context->backtrace = backtrace->GetBacktrace();
251 return true;
252}
253
Christopher Ferris98464972014-01-06 19:16:33 -0800254bool backtrace_create_context(
255 backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames) {
256 return backtrace_create_context_with_map(context, pid, tid, num_ignore_frames, NULL);
257}
258
259
Christopher Ferris17e91d42013-10-21 13:30:52 -0700260void backtrace_destroy_context(backtrace_context_t* context) {
261 if (context->data) {
262 Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
263 delete backtrace;
264 context->data = NULL;
265 }
266 context->backtrace = NULL;
267}
268
269const backtrace_t* backtrace_get_data(backtrace_context_t* context) {
270 if (context && context->data) {
271 Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
272 return backtrace->GetBacktrace();
273 }
274 return NULL;
275}
276
277bool backtrace_read_word(const backtrace_context_t* context, uintptr_t ptr, uint32_t* value) {
278 if (context->data) {
279 Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
280 return backtrace->ReadWord(ptr, value);
281 }
282 return true;
283}
284
285const char* backtrace_get_map_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start) {
286 if (context->data) {
287 Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
288 return backtrace->GetMapName(pc, map_start);
289 }
290 return NULL;
291}
292
293char* backtrace_get_func_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset) {
294 if (context->data) {
295 Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
296 std::string func_name = backtrace->GetFunctionName(pc, func_offset);
297 if (!func_name.empty()) {
298 return strdup(func_name.c_str());
299 }
300 }
301 return NULL;
302}
303
304void backtrace_format_frame_data(
305 const backtrace_context_t* context, size_t frame_num, char* buf,
306 size_t buf_size) {
307 if (buf_size == 0 || buf == NULL) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700308 BACK_LOGW("bad call buf %p buf_size %zu", buf, buf_size);
309 } else if (context->data) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700310 Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
311 std::string line = backtrace->FormatFrameData(frame_num);
312 if (line.size() > buf_size) {
313 memcpy(buf, line.c_str(), buf_size-1);
314 buf[buf_size] = '\0';
315 } else {
316 memcpy(buf, line.c_str(), line.size()+1);
317 }
318 }
319}