blob: 05007d965af542d9c412508929654c0e568c90a4 [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
Christopher Ferris17e91d42013-10-21 13:30:52 -070024#include <string>
25
26#include <backtrace/Backtrace.h>
Christopher Ferris46756822014-01-14 20:16:30 -080027#include <backtrace/BacktraceMap.h>
Christopher Ferris17e91d42013-10-21 13:30:52 -070028
Christopher Ferrisdf290612014-01-22 19:21:07 -080029#include "BacktraceImpl.h"
Christopher Ferrise2960912014-03-07 19:42:19 -080030#include "BacktraceLog.h"
Christopher Ferris17e91d42013-10-21 13:30:52 -070031#include "thread_utils.h"
32
33//-------------------------------------------------------------------------
Christopher Ferris17e91d42013-10-21 13:30:52 -070034// Backtrace functions.
35//-------------------------------------------------------------------------
Christopher Ferris46756822014-01-14 20:16:30 -080036Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map)
37 : pid_(pid), tid_(-1), map_(map), map_shared_(true), impl_(impl) {
Christopher Ferris17e91d42013-10-21 13:30:52 -070038 impl_->SetParent(this);
Christopher Ferris98464972014-01-06 19:16:33 -080039
Christopher Ferris46756822014-01-14 20:16:30 -080040 if (map_ == NULL) {
Christopher Ferrisdf290612014-01-22 19:21:07 -080041 map_ = BacktraceMap::Create(pid);
Christopher Ferris46756822014-01-14 20:16:30 -080042 map_shared_ = false;
Christopher Ferris98464972014-01-06 19:16:33 -080043 }
Christopher Ferris17e91d42013-10-21 13:30:52 -070044}
45
46Backtrace::~Backtrace() {
Christopher Ferris17e91d42013-10-21 13:30:52 -070047 if (impl_) {
48 delete impl_;
49 impl_ = NULL;
50 }
Christopher Ferrisdf290612014-01-22 19:21:07 -080051
52 if (map_ && !map_shared_) {
53 delete map_;
54 map_ = NULL;
55 }
Christopher Ferris17e91d42013-10-21 13:30:52 -070056}
57
58bool Backtrace::Unwind(size_t num_ignore_frames) {
59 return impl_->Unwind(num_ignore_frames);
60}
61
Christopher Ferris8ed46272013-10-29 15:44:25 -070062extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
63 int* status);
Christopher Ferris17e91d42013-10-21 13:30:52 -070064
65std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
66 std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
67 if (!func_name.empty()) {
68#if defined(__APPLE__)
69 // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
Christopher Ferrisf67c6412014-01-10 00:43:54 -080070 if (func_name[0] != '_') {
Christopher Ferris17e91d42013-10-21 13:30:52 -070071 return func_name;
72 }
73#endif
74 char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
75 if (name) {
76 func_name = name;
77 free(name);
78 }
79 }
80 return func_name;
81}
82
Pavel Chupinc6c194c2013-11-21 23:17:20 +040083bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
84 if (ptr & (sizeof(word_t)-1)) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070085 BACK_LOGW("invalid pointer %p", (void*)ptr);
Pavel Chupinc6c194c2013-11-21 23:17:20 +040086 *out_value = (word_t)-1;
Christopher Ferris17e91d42013-10-21 13:30:52 -070087 return false;
88 }
89 return true;
90}
91
Christopher Ferris17e91d42013-10-21 13:30:52 -070092std::string Backtrace::FormatFrameData(size_t frame_num) {
Christopher Ferris46756822014-01-14 20:16:30 -080093 if (frame_num >= frames_.size()) {
94 return "";
95 }
96 return FormatFrameData(&frames_[frame_num]);
Christopher Ferris20303f82014-01-10 16:33:16 -080097}
98
99std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700100 const char* map_name;
Christopher Ferris46756822014-01-14 20:16:30 -0800101 if (frame->map && !frame->map->name.empty()) {
102 map_name = frame->map->name.c_str();
Christopher Ferris17e91d42013-10-21 13:30:52 -0700103 } else {
104 map_name = "<unknown>";
105 }
Christopher Ferris46756822014-01-14 20:16:30 -0800106
Christopher Ferris17e91d42013-10-21 13:30:52 -0700107 uintptr_t relative_pc;
Christopher Ferris46756822014-01-14 20:16:30 -0800108 if (frame->map) {
109 relative_pc = frame->pc - frame->map->start;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700110 } else {
111 relative_pc = frame->pc;
112 }
113
114 char buf[512];
Christopher Ferris46756822014-01-14 20:16:30 -0800115 if (!frame->func_name.empty() && frame->func_offset) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700116 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")",
Christopher Ferris20303f82014-01-10 16:33:16 -0800117 frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
Christopher Ferris46756822014-01-14 20:16:30 -0800118 frame->func_name.c_str(), frame->func_offset);
119 } else if (!frame->func_name.empty()) {
Christopher Ferris20303f82014-01-10 16:33:16 -0800120 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame->num,
Christopher Ferris46756822014-01-14 20:16:30 -0800121 (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name.c_str());
Christopher Ferris17e91d42013-10-21 13:30:52 -0700122 } else {
Christopher Ferris20303f82014-01-10 16:33:16 -0800123 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame->num,
Christopher Ferris17e91d42013-10-21 13:30:52 -0700124 (int)sizeof(uintptr_t)*2, relative_pc, map_name);
125 }
126
127 return buf;
128}
129
Christopher Ferris46756822014-01-14 20:16:30 -0800130const backtrace_map_t* Backtrace::FindMap(uintptr_t pc) {
Christopher Ferris46756822014-01-14 20:16:30 -0800131 return map_->Find(pc);
132}
133
Christopher Ferris17e91d42013-10-21 13:30:52 -0700134//-------------------------------------------------------------------------
135// BacktraceCurrent functions.
136//-------------------------------------------------------------------------
Christopher Ferris98464972014-01-06 19:16:33 -0800137BacktraceCurrent::BacktraceCurrent(
Christopher Ferris46756822014-01-14 20:16:30 -0800138 BacktraceImpl* impl, BacktraceMap* map) : Backtrace(impl, getpid(), map) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700139}
140
141BacktraceCurrent::~BacktraceCurrent() {
142}
143
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400144bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700145 if (!VerifyReadWordArgs(ptr, out_value)) {
146 return false;
147 }
148
Christopher Ferris46756822014-01-14 20:16:30 -0800149 const backtrace_map_t* map = FindMap(ptr);
150 if (map && map->flags & PROT_READ) {
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400151 *out_value = *reinterpret_cast<word_t*>(ptr);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700152 return true;
153 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700154 BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400155 *out_value = static_cast<word_t>(-1);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700156 return false;
157 }
158}
159
160//-------------------------------------------------------------------------
161// BacktracePtrace functions.
162//-------------------------------------------------------------------------
Christopher Ferris98464972014-01-06 19:16:33 -0800163BacktracePtrace::BacktracePtrace(
Christopher Ferris46756822014-01-14 20:16:30 -0800164 BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map)
165 : Backtrace(impl, pid, map) {
166 tid_ = tid;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700167}
168
169BacktracePtrace::~BacktracePtrace() {
170}
171
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400172bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700173 if (!VerifyReadWordArgs(ptr, out_value)) {
174 return false;
175 }
176
177#if defined(__APPLE__)
Christopher Ferris8ed46272013-10-29 15:44:25 -0700178 BACK_LOGW("MacOS does not support reading from another pid.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700179 return false;
180#else
181 // ptrace() returns -1 and sets errno when the operation fails.
182 // To disambiguate -1 from a valid result, we clear errno beforehand.
183 errno = 0;
184 *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400185 if (*out_value == static_cast<word_t>(-1) && errno) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700186 BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
187 reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
Christopher Ferris17e91d42013-10-21 13:30:52 -0700188 return false;
189 }
190 return true;
191#endif
192}
193
Christopher Ferris46756822014-01-14 20:16:30 -0800194Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
Christopher Ferriscbfc7302013-11-05 11:04:12 -0800195 if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) {
Christopher Ferrisbc12d632013-11-12 10:54:16 -0800196 if (tid == BACKTRACE_CURRENT_THREAD || tid == gettid()) {
Christopher Ferris46756822014-01-14 20:16:30 -0800197 return CreateCurrentObj(map);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700198 } else {
Christopher Ferris46756822014-01-14 20:16:30 -0800199 return CreateThreadObj(tid, map);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700200 }
Christopher Ferrisbc12d632013-11-12 10:54:16 -0800201 } else if (tid == BACKTRACE_CURRENT_THREAD) {
Christopher Ferris46756822014-01-14 20:16:30 -0800202 return CreatePtraceObj(pid, pid, map);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700203 } else {
Christopher Ferris46756822014-01-14 20:16:30 -0800204 return CreatePtraceObj(pid, tid, map);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700205 }
206}