1/* 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 <ucontext.h> 23#include <unistd.h> 24 25#include <string> 26 27#include <backtrace/Backtrace.h> 28#include <backtrace/BacktraceMap.h> 29 30#include "BacktraceImpl.h" 31#include "BacktraceLog.h" 32#include "thread_utils.h" 33 34//------------------------------------------------------------------------- 35// Backtrace functions. 36//------------------------------------------------------------------------- 37Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map) 38 : pid_(pid), tid_(-1), map_(map), map_shared_(true), impl_(impl) { 39 impl_->SetParent(this); 40 41 if (map_ == NULL) { 42 map_ = BacktraceMap::Create(pid); 43 map_shared_ = false; 44 } 45} 46 47Backtrace::~Backtrace() { 48 if (impl_) { 49 delete impl_; 50 impl_ = NULL; 51 } 52 53 if (map_ && !map_shared_) { 54 delete map_; 55 map_ = NULL; 56 } 57} 58 59bool Backtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { 60 return impl_->Unwind(num_ignore_frames, ucontext); 61} 62 63extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len, 64 int* status); 65 66std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) { 67 std::string func_name = impl_->GetFunctionNameRaw(pc, offset); 68 if (!func_name.empty()) { 69#if defined(__APPLE__) 70 // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7. 71 if (func_name[0] != '_') { 72 return func_name; 73 } 74#endif 75 char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0); 76 if (name) { 77 func_name = name; 78 free(name); 79 } 80 } 81 return func_name; 82} 83 84bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) { 85 if (ptr & (sizeof(word_t)-1)) { 86 BACK_LOGW("invalid pointer %p", (void*)ptr); 87 *out_value = (word_t)-1; 88 return false; 89 } 90 return true; 91} 92 93std::string Backtrace::FormatFrameData(size_t frame_num) { 94 if (frame_num >= frames_.size()) { 95 return ""; 96 } 97 return FormatFrameData(&frames_[frame_num]); 98} 99 100std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) { 101 const char* map_name; 102 if (frame->map && !frame->map->name.empty()) { 103 map_name = frame->map->name.c_str(); 104 } else { 105 map_name = "<unknown>"; 106 } 107 108 uintptr_t relative_pc; 109 if (frame->map) { 110 relative_pc = frame->pc - frame->map->start; 111 } else { 112 relative_pc = frame->pc; 113 } 114 115 char buf[512]; 116 if (!frame->func_name.empty() && frame->func_offset) { 117 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")", 118 frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name, 119 frame->func_name.c_str(), frame->func_offset); 120 } else if (!frame->func_name.empty()) { 121 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame->num, 122 (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name.c_str()); 123 } else { 124 snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame->num, 125 (int)sizeof(uintptr_t)*2, relative_pc, map_name); 126 } 127 128 return buf; 129} 130 131const backtrace_map_t* Backtrace::FindMap(uintptr_t pc) { 132 return map_->Find(pc); 133} 134 135//------------------------------------------------------------------------- 136// BacktraceCurrent functions. 137//------------------------------------------------------------------------- 138BacktraceCurrent::BacktraceCurrent( 139 BacktraceImpl* impl, BacktraceMap* map) : Backtrace(impl, getpid(), map) { 140} 141 142BacktraceCurrent::~BacktraceCurrent() { 143} 144 145bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) { 146 if (!VerifyReadWordArgs(ptr, out_value)) { 147 return false; 148 } 149 150 const backtrace_map_t* map = FindMap(ptr); 151 if (map && map->flags & PROT_READ) { 152 *out_value = *reinterpret_cast<word_t*>(ptr); 153 return true; 154 } else { 155 BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr)); 156 *out_value = static_cast<word_t>(-1); 157 return false; 158 } 159} 160 161//------------------------------------------------------------------------- 162// BacktracePtrace functions. 163//------------------------------------------------------------------------- 164BacktracePtrace::BacktracePtrace( 165 BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map) 166 : Backtrace(impl, pid, map) { 167 tid_ = tid; 168} 169 170BacktracePtrace::~BacktracePtrace() { 171} 172 173bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) { 174 if (!VerifyReadWordArgs(ptr, out_value)) { 175 return false; 176 } 177 178#if defined(__APPLE__) 179 BACK_LOGW("MacOS does not support reading from another pid."); 180 return false; 181#else 182 // ptrace() returns -1 and sets errno when the operation fails. 183 // To disambiguate -1 from a valid result, we clear errno beforehand. 184 errno = 0; 185 *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL); 186 if (*out_value == static_cast<word_t>(-1) && errno) { 187 BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s", 188 reinterpret_cast<void*>(ptr), Tid(), strerror(errno)); 189 return false; 190 } 191 return true; 192#endif 193} 194 195Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) { 196 if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) { 197 if (tid == BACKTRACE_CURRENT_THREAD || tid == gettid()) { 198 return CreateCurrentObj(map); 199 } else { 200 return CreateThreadObj(tid, map); 201 } 202 } else if (tid == BACKTRACE_CURRENT_THREAD) { 203 return CreatePtraceObj(pid, pid, map); 204 } else { 205 return CreatePtraceObj(pid, tid, map); 206 } 207} 208