blob: b4481cce9748f83fea220f9952c5b6de742c6a66 [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
Christopher Ferris5f118512017-09-01 11:17:16 -070044static std::string GetFunctionName(BacktraceMap* back_map, uintptr_t pc, uintptr_t* offset) {
Christopher Ferris6f3981c2017-07-27 09:29:18 -070045 *offset = 0;
46 unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
47
48 // Get the map for this
49 unwindstack::MapInfo* map_info = maps->Find(pc);
50 if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
51 return "";
52 }
53
Christopher Ferris5f118512017-09-01 11:17:16 -070054 UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
55 unwindstack::Elf* elf = map_info->GetElf(stack_map->process_memory(), true);
Christopher Ferris6f3981c2017-07-27 09:29:18 -070056
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
Christopher Ferrisb9de87f2017-09-20 13:37:24 -070071static void SetFrameInfo(unwindstack::Regs* regs, unwindstack::MapInfo* map_info,
72 uint64_t adjusted_rel_pc, backtrace_frame_data_t* frame) {
73 // This will point to the adjusted absolute pc. regs->pc() is
74 // unaltered.
75 frame->pc = map_info->start + adjusted_rel_pc;
76 frame->sp = regs->sp();
77 frame->rel_pc = adjusted_rel_pc;
78 frame->stack_size = 0;
79
80 frame->map.start = map_info->start;
81 frame->map.end = map_info->end;
82 frame->map.offset = map_info->offset;
83 frame->map.flags = map_info->flags;
84 frame->map.name = map_info->name;
85
86 unwindstack::Elf* elf = map_info->elf;
87 frame->map.load_bias = elf->GetLoadBias();
88 uint64_t func_offset = 0;
89 if (elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) {
90 frame->func_name = demangle(frame->func_name.c_str());
91 } else {
92 frame->func_name = "";
93 }
94 frame->func_offset = func_offset;
95}
96
Christopher Ferris5f118512017-09-01 11:17:16 -070097static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
98 std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
99 UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
100 unwindstack::Maps* maps = stack_map->stack_maps();
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700101 bool adjust_rel_pc = false;
102 size_t num_frames = 0;
103 frames->clear();
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700104 bool return_address_attempted = false;
105 auto process_memory = stack_map->process_memory();
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700106 while (num_frames < MAX_BACKTRACE_FRAMES) {
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700107 unwindstack::MapInfo* map_info = maps->Find(regs->pc());
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700108 bool stepped;
109 bool in_device_map = false;
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700110 if (map_info == nullptr) {
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700111 stepped = false;
112 if (num_ignore_frames == 0) {
113 frames->resize(num_frames + 1);
114 backtrace_frame_data_t* frame = &frames->at(num_frames);
115 frame->pc = regs->pc();
116 frame->sp = regs->sp();
117 frame->rel_pc = frame->pc;
118 num_frames++;
Christopher Ferris04fdec02017-08-11 15:17:46 -0700119 } else {
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700120 num_ignore_frames--;
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700121 }
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700122 } else {
123 unwindstack::Elf* elf = map_info->GetElf(process_memory, true);
124 uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
125
126 if (frames->size() != 0 || !IsUnwindLibrary(map_info->name)) {
127 if (num_ignore_frames == 0) {
128 uint64_t adjusted_rel_pc = rel_pc;
129 if (adjust_rel_pc) {
130 adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
131 }
132
133 frames->resize(num_frames + 1);
134 backtrace_frame_data_t* frame = &frames->at(num_frames);
135 frame->num = num_frames;
136 SetFrameInfo(regs, map_info, adjusted_rel_pc, frame);
137
138 if (num_frames > 0) {
139 // Set the stack size for the previous frame.
140 backtrace_frame_data_t* prev = &frames->at(num_frames - 1);
141 prev->stack_size = frame->sp - prev->sp;
142 }
143 num_frames++;
144 } else {
145 num_ignore_frames--;
146 }
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700147 }
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700148
149 if (map_info->flags & PROT_DEVICE_MAP) {
150 // Do not stop here, fall through in case we are
151 // in the speculative unwind path and need to remove
152 // some of the speculative frames.
153 stepped = false;
154 in_device_map = true;
155 } else {
156 unwindstack::MapInfo* sp_info = maps->Find(regs->sp());
157 if (sp_info->flags & PROT_DEVICE_MAP) {
158 // Do not stop here, fall through in case we are
159 // in the speculative unwind path and need to remove
160 // some of the speculative frames.
161 stepped = false;
162 in_device_map = true;
163 } else {
164 bool finished;
165 stepped = elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get(), &finished);
166 if (stepped && finished) {
167 break;
168 }
169 }
170 }
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700171 }
172 adjust_rel_pc = true;
173
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700174 if (!stepped) {
175 if (return_address_attempted) {
176 // Remove the speculative frame.
177 if (frames->size() > 0) {
178 frames->pop_back();
179 }
180 break;
181 } else if (in_device_map) {
182 // Do not attempt any other unwinding, pc or sp is in a device
183 // map.
184 break;
185 } else {
186 // Stepping didn't work, try this secondary method.
187 if (!regs->SetPcFromReturnAddress(process_memory.get())) {
188 break;
189 }
190 return_address_attempted = true;
191 }
192 } else {
193 return_address_attempted = false;
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700194 }
195 }
196
197 return true;
198}
199
200UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
Christopher Ferris5f118512017-09-01 11:17:16 -0700201 : BacktraceCurrent(pid, tid, map) {}
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700202
203std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
Christopher Ferris5f118512017-09-01 11:17:16 -0700204 return ::GetFunctionName(GetMap(), pc, offset);
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700205}
206
207bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
208 std::unique_ptr<unwindstack::Regs> regs;
209 if (ucontext == nullptr) {
210 regs.reset(unwindstack::Regs::CreateFromLocal());
211 // Fill in the registers from this function. Do it here to avoid
212 // one extra function call appearing in the unwind.
213 unwindstack::RegsGetLocal(regs.get());
214 } else {
Josh Gao0953ecd2017-08-25 13:55:06 -0700215 regs.reset(
216 unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), ucontext));
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700217 }
218
219 error_ = BACKTRACE_UNWIND_NO_ERROR;
Christopher Ferris5f118512017-09-01 11:17:16 -0700220 return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700221}
222
223UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
Christopher Ferris5f118512017-09-01 11:17:16 -0700224 : BacktracePtrace(pid, tid, map) {}
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700225
226std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
Christopher Ferris5f118512017-09-01 11:17:16 -0700227 return ::GetFunctionName(GetMap(), pc, offset);
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700228}
229
230bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
231 std::unique_ptr<unwindstack::Regs> regs;
232 if (context == nullptr) {
Josh Gao0953ecd2017-08-25 13:55:06 -0700233 regs.reset(unwindstack::Regs::RemoteGet(Tid()));
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700234 } else {
Josh Gao0953ecd2017-08-25 13:55:06 -0700235 regs.reset(
236 unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), context));
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700237 }
238
239 error_ = BACKTRACE_UNWIND_NO_ERROR;
Christopher Ferris5f118512017-09-01 11:17:16 -0700240 return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
Christopher Ferris6f3981c2017-07-27 09:29:18 -0700241}
242
243Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
244 if (pid == BACKTRACE_CURRENT_PROCESS) {
245 pid = getpid();
246 if (tid == BACKTRACE_CURRENT_THREAD) {
247 tid = gettid();
248 }
249 } else if (tid == BACKTRACE_CURRENT_THREAD) {
250 tid = pid;
251 }
252
253 if (map == nullptr) {
254// This would cause the wrong type of map object to be created, so disallow.
255#if defined(__ANDROID__)
256 __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
257 "Backtrace::CreateNew() must be called with a real map pointer.");
258#else
259 BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
260 abort();
261#endif
262 }
263
264 if (pid == getpid()) {
265 return new UnwindStackCurrent(pid, tid, map);
266 } else {
267 return new UnwindStackPtrace(pid, tid, map);
268 }
269}