blob: 3b2f38e08ab1d4250746b761e2208567b1b44e82 [file] [log] [blame]
Christopher Ferris6f3981c2017-07-27 09:29:18 -07001/*
2 * Copyright (C) 2017 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 _GNU_SOURCE 1
18#include <assert.h>
19#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22#include <ucontext.h>
23
24#include <memory>
25#include <string>
26
27#if !defined(__ANDROID__)
28#include <cutils/threads.h>
29#endif
30
31#include <backtrace/Backtrace.h>
Christopher Ferris04fdec02017-08-11 15:17:46 -070032#include <demangle.h>
Christopher Ferris6f3981c2017-07-27 09:29:18 -070033#include <unwindstack/Elf.h>
34#include <unwindstack/MapInfo.h>
35#include <unwindstack/Maps.h>
36#include <unwindstack/Memory.h>
37#include <unwindstack/Regs.h>
38#include <unwindstack/RegsGetLocal.h>
39
40#include "BacktraceLog.h"
41#include "UnwindStack.h"
42#include "UnwindStackMap.h"
43
44static std::string GetFunctionName(pid_t pid, BacktraceMap* back_map, uintptr_t pc,
45 uintptr_t* offset) {
46 *offset = 0;
47 unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
48
49 // Get the map for this
50 unwindstack::MapInfo* map_info = maps->Find(pc);
51 if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
52 return "";
53 }
54
55 unwindstack::Elf* elf = map_info->GetElf(pid, true);
56
57 std::string name;
58 uint64_t func_offset;
59 if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
60 return "";
61 }
62 *offset = func_offset;
63 return name;
64}
65
66static bool IsUnwindLibrary(const std::string& map_name) {
67 const std::string library(basename(map_name.c_str()));
68 return library == "libunwindstack.so" || library == "libbacktrace.so";
69}
70
71static bool Unwind(pid_t pid, unwindstack::Memory* memory, unwindstack::Regs* regs,
72 BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames,
73 size_t num_ignore_frames) {
74 unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
75 bool adjust_rel_pc = false;
76 size_t num_frames = 0;
77 frames->clear();
78 while (num_frames < MAX_BACKTRACE_FRAMES) {
79 if (regs->pc() == 0) {
80 break;
81 }
82 unwindstack::MapInfo* map_info = maps->Find(regs->pc());
83 if (map_info == nullptr) {
84 break;
85 }
86
87 unwindstack::Elf* elf = map_info->GetElf(pid, true);
Christopher Ferris3b4b0752017-08-09 11:16:03 -070088 uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
Christopher Ferris6f3981c2017-07-27 09:29:18 -070089
90 bool skip_frame = num_frames == 0 && IsUnwindLibrary(map_info->name);
91 if (num_ignore_frames == 0 && !skip_frame) {
92 uint64_t adjusted_rel_pc = rel_pc;
Christopher Ferris3b4b0752017-08-09 11:16:03 -070093 if (adjust_rel_pc) {
Christopher Ferris6f3981c2017-07-27 09:29:18 -070094 adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
95 }
96 frames->resize(num_frames + 1);
97 backtrace_frame_data_t* frame = &frames->at(num_frames);
98 frame->num = num_frames;
Christopher Ferris3b4b0752017-08-09 11:16:03 -070099 // This will point to the adjusted absolute pc. regs->pc() is
100 // unaltered.
101 frame->pc = map_info->start + adjusted_rel_pc;
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700102 frame->sp = regs->sp();
103 frame->rel_pc = adjusted_rel_pc;
104 frame->stack_size = 0;
105
106 frame->map.start = map_info->start;
107 frame->map.end = map_info->end;
108 frame->map.offset = map_info->offset;
109 frame->map.load_bias = elf->GetLoadBias();
110 frame->map.flags = map_info->flags;
111 frame->map.name = map_info->name;
112
113 uint64_t func_offset = 0;
Christopher Ferris04fdec02017-08-11 15:17:46 -0700114 if (elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) {
115 frame->func_name = demangle(frame->func_name.c_str());
116 } else {
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700117 frame->func_name = "";
118 }
119 frame->func_offset = func_offset;
120 if (num_frames > 0) {
121 // Set the stack size for the previous frame.
122 backtrace_frame_data_t* prev = &frames->at(num_frames - 1);
123 prev->stack_size = frame->sp - prev->sp;
124 }
125 num_frames++;
126 } else if (!skip_frame && num_ignore_frames > 0) {
127 num_ignore_frames--;
128 }
129 adjust_rel_pc = true;
130
131 // Do not unwind through a device map.
132 if (map_info->flags & PROT_DEVICE_MAP) {
133 break;
134 }
135 unwindstack::MapInfo* sp_info = maps->Find(regs->sp());
136 if (sp_info->flags & PROT_DEVICE_MAP) {
137 break;
138 }
139
140 if (!elf->Step(rel_pc + map_info->elf_offset, regs, memory)) {
141 break;
142 }
143 }
144
145 return true;
146}
147
148UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
149 : BacktraceCurrent(pid, tid, map), memory_(new unwindstack::MemoryLocal) {}
150
151std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
152 return ::GetFunctionName(Pid(), GetMap(), pc, offset);
153}
154
155bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
156 std::unique_ptr<unwindstack::Regs> regs;
157 if (ucontext == nullptr) {
158 regs.reset(unwindstack::Regs::CreateFromLocal());
159 // Fill in the registers from this function. Do it here to avoid
160 // one extra function call appearing in the unwind.
161 unwindstack::RegsGetLocal(regs.get());
162 } else {
Josh Gao0953ecd2017-08-25 13:55:06 -0700163 regs.reset(
164 unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), ucontext));
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700165 }
166
167 error_ = BACKTRACE_UNWIND_NO_ERROR;
168 return ::Unwind(getpid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
169}
170
171UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
172 : BacktracePtrace(pid, tid, map), memory_(new unwindstack::MemoryRemote(pid)) {}
173
174std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
175 return ::GetFunctionName(Pid(), GetMap(), pc, offset);
176}
177
178bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
179 std::unique_ptr<unwindstack::Regs> regs;
180 if (context == nullptr) {
Josh Gao0953ecd2017-08-25 13:55:06 -0700181 regs.reset(unwindstack::Regs::RemoteGet(Tid()));
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700182 } else {
Josh Gao0953ecd2017-08-25 13:55:06 -0700183 regs.reset(
184 unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), context));
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700185 }
186
187 error_ = BACKTRACE_UNWIND_NO_ERROR;
188 return ::Unwind(Pid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
189}
190
191Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
192 if (pid == BACKTRACE_CURRENT_PROCESS) {
193 pid = getpid();
194 if (tid == BACKTRACE_CURRENT_THREAD) {
195 tid = gettid();
196 }
197 } else if (tid == BACKTRACE_CURRENT_THREAD) {
198 tid = pid;
199 }
200
201 if (map == nullptr) {
202// This would cause the wrong type of map object to be created, so disallow.
203#if defined(__ANDROID__)
204 __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
205 "Backtrace::CreateNew() must be called with a real map pointer.");
206#else
207 BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
208 abort();
209#endif
210 }
211
212 if (pid == getpid()) {
213 return new UnwindStackCurrent(pid, tid, map);
214 } else {
215 return new UnwindStackPtrace(pid, tid, map);
216 }
217}