blob: 855810e5b14e9135235c6f0d9c36b750cca8c9ef [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 Ferris17e91d42013-10-21 13:30:52 -070030#include "thread_utils.h"
31
32//-------------------------------------------------------------------------
Christopher Ferris17e91d42013-10-21 13:30:52 -070033// Backtrace functions.
34//-------------------------------------------------------------------------
Christopher Ferris46756822014-01-14 20:16:30 -080035Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map)
36 : pid_(pid), tid_(-1), map_(map), map_shared_(true), impl_(impl) {
Christopher Ferris17e91d42013-10-21 13:30:52 -070037 impl_->SetParent(this);
Christopher Ferris98464972014-01-06 19:16:33 -080038
Christopher Ferris46756822014-01-14 20:16:30 -080039 if (map_ == NULL) {
Christopher Ferrisdf290612014-01-22 19:21:07 -080040 map_ = BacktraceMap::Create(pid);
Christopher Ferris46756822014-01-14 20:16:30 -080041 map_shared_ = false;
Christopher Ferris98464972014-01-06 19:16:33 -080042 }
Christopher Ferris17e91d42013-10-21 13:30:52 -070043}
44
45Backtrace::~Backtrace() {
Christopher Ferris17e91d42013-10-21 13:30:52 -070046 if (impl_) {
47 delete impl_;
48 impl_ = NULL;
49 }
Christopher Ferrisdf290612014-01-22 19:21:07 -080050
51 if (map_ && !map_shared_) {
52 delete map_;
53 map_ = NULL;
54 }
Christopher Ferris17e91d42013-10-21 13:30:52 -070055}
56
57bool Backtrace::Unwind(size_t num_ignore_frames) {
58 return impl_->Unwind(num_ignore_frames);
59}
60
Christopher Ferris8ed46272013-10-29 15:44:25 -070061extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
62 int* status);
Christopher Ferris17e91d42013-10-21 13:30:52 -070063
64std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
65 std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
66 if (!func_name.empty()) {
67#if defined(__APPLE__)
68 // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
Christopher Ferrisf67c6412014-01-10 00:43:54 -080069 if (func_name[0] != '_') {
Christopher Ferris17e91d42013-10-21 13:30:52 -070070 return func_name;
71 }
72#endif
73 char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
74 if (name) {
75 func_name = name;
76 free(name);
77 }
78 }
79 return func_name;
80}
81
Pavel Chupinc6c194c2013-11-21 23:17:20 +040082bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
83 if (ptr & (sizeof(word_t)-1)) {
Christopher Ferris8ed46272013-10-29 15:44:25 -070084 BACK_LOGW("invalid pointer %p", (void*)ptr);
Pavel Chupinc6c194c2013-11-21 23:17:20 +040085 *out_value = (word_t)-1;
Christopher Ferris17e91d42013-10-21 13:30:52 -070086 return false;
87 }
88 return true;
89}
90
Christopher Ferris17e91d42013-10-21 13:30:52 -070091std::string Backtrace::FormatFrameData(size_t frame_num) {
Christopher Ferris46756822014-01-14 20:16:30 -080092 if (frame_num >= frames_.size()) {
93 return "";
94 }
95 return FormatFrameData(&frames_[frame_num]);
Christopher Ferris20303f82014-01-10 16:33:16 -080096}
97
98std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
Christopher Ferris17e91d42013-10-21 13:30:52 -070099 const char* map_name;
Christopher Ferris46756822014-01-14 20:16:30 -0800100 if (frame->map && !frame->map->name.empty()) {
101 map_name = frame->map->name.c_str();
Christopher Ferris17e91d42013-10-21 13:30:52 -0700102 } else {
103 map_name = "<unknown>";
104 }
Christopher Ferris46756822014-01-14 20:16:30 -0800105
Christopher Ferris17e91d42013-10-21 13:30:52 -0700106 uintptr_t relative_pc;
Christopher Ferris46756822014-01-14 20:16:30 -0800107 if (frame->map) {
108 relative_pc = frame->pc - frame->map->start;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700109 } else {
110 relative_pc = frame->pc;
111 }
112
113 char buf[512];
Christopher Ferris46756822014-01-14 20:16:30 -0800114 if (!frame->func_name.empty() && frame->func_offset) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700115 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")",
Christopher Ferris20303f82014-01-10 16:33:16 -0800116 frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
Christopher Ferris46756822014-01-14 20:16:30 -0800117 frame->func_name.c_str(), frame->func_offset);
118 } else if (!frame->func_name.empty()) {
Christopher Ferris20303f82014-01-10 16:33:16 -0800119 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame->num,
Christopher Ferris46756822014-01-14 20:16:30 -0800120 (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name.c_str());
Christopher Ferris17e91d42013-10-21 13:30:52 -0700121 } else {
Christopher Ferris20303f82014-01-10 16:33:16 -0800122 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame->num,
Christopher Ferris17e91d42013-10-21 13:30:52 -0700123 (int)sizeof(uintptr_t)*2, relative_pc, map_name);
124 }
125
126 return buf;
127}
128
Christopher Ferris46756822014-01-14 20:16:30 -0800129const backtrace_map_t* Backtrace::FindMap(uintptr_t pc) {
Christopher Ferris46756822014-01-14 20:16:30 -0800130 return map_->Find(pc);
131}
132
Christopher Ferris17e91d42013-10-21 13:30:52 -0700133//-------------------------------------------------------------------------
134// BacktraceCurrent functions.
135//-------------------------------------------------------------------------
Christopher Ferris98464972014-01-06 19:16:33 -0800136BacktraceCurrent::BacktraceCurrent(
Christopher Ferris46756822014-01-14 20:16:30 -0800137 BacktraceImpl* impl, BacktraceMap* map) : Backtrace(impl, getpid(), map) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700138}
139
140BacktraceCurrent::~BacktraceCurrent() {
141}
142
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400143bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700144 if (!VerifyReadWordArgs(ptr, out_value)) {
145 return false;
146 }
147
Christopher Ferris46756822014-01-14 20:16:30 -0800148 const backtrace_map_t* map = FindMap(ptr);
149 if (map && map->flags & PROT_READ) {
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400150 *out_value = *reinterpret_cast<word_t*>(ptr);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700151 return true;
152 } else {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700153 BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400154 *out_value = static_cast<word_t>(-1);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700155 return false;
156 }
157}
158
159//-------------------------------------------------------------------------
160// BacktracePtrace functions.
161//-------------------------------------------------------------------------
Christopher Ferris98464972014-01-06 19:16:33 -0800162BacktracePtrace::BacktracePtrace(
Christopher Ferris46756822014-01-14 20:16:30 -0800163 BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map)
164 : Backtrace(impl, pid, map) {
165 tid_ = tid;
Christopher Ferris17e91d42013-10-21 13:30:52 -0700166}
167
168BacktracePtrace::~BacktracePtrace() {
169}
170
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400171bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
Christopher Ferris17e91d42013-10-21 13:30:52 -0700172 if (!VerifyReadWordArgs(ptr, out_value)) {
173 return false;
174 }
175
176#if defined(__APPLE__)
Christopher Ferris8ed46272013-10-29 15:44:25 -0700177 BACK_LOGW("MacOS does not support reading from another pid.");
Christopher Ferris17e91d42013-10-21 13:30:52 -0700178 return false;
179#else
180 // ptrace() returns -1 and sets errno when the operation fails.
181 // To disambiguate -1 from a valid result, we clear errno beforehand.
182 errno = 0;
183 *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
Pavel Chupinc6c194c2013-11-21 23:17:20 +0400184 if (*out_value == static_cast<word_t>(-1) && errno) {
Christopher Ferris8ed46272013-10-29 15:44:25 -0700185 BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
186 reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
Christopher Ferris17e91d42013-10-21 13:30:52 -0700187 return false;
188 }
189 return true;
190#endif
191}
192
Christopher Ferris46756822014-01-14 20:16:30 -0800193Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
Christopher Ferriscbfc7302013-11-05 11:04:12 -0800194 if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) {
Christopher Ferrisbc12d632013-11-12 10:54:16 -0800195 if (tid == BACKTRACE_CURRENT_THREAD || tid == gettid()) {
Christopher Ferris46756822014-01-14 20:16:30 -0800196 return CreateCurrentObj(map);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700197 } else {
Christopher Ferris46756822014-01-14 20:16:30 -0800198 return CreateThreadObj(tid, map);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700199 }
Christopher Ferrisbc12d632013-11-12 10:54:16 -0800200 } else if (tid == BACKTRACE_CURRENT_THREAD) {
Christopher Ferris46756822014-01-14 20:16:30 -0800201 return CreatePtraceObj(pid, pid, map);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700202 } else {
Christopher Ferris46756822014-01-14 20:16:30 -0800203 return CreatePtraceObj(pid, tid, map);
Christopher Ferris17e91d42013-10-21 13:30:52 -0700204 }
205}