Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 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 "dwarf_unwind.h" |
| 18 | |
| 19 | #include <ucontext.h> |
| 20 | |
| 21 | #include <backtrace/Backtrace.h> |
Elliott Hughes | 66dd09e | 2015-12-04 14:00:57 -0800 | [diff] [blame] | 22 | #include <android-base/logging.h> |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 23 | |
| 24 | #include "thread_tree.h" |
| 25 | |
Yabin Cui | 8a52e97 | 2015-10-01 11:32:44 -0700 | [diff] [blame] | 26 | #define SetUContextReg(dst, perf_regno) \ |
| 27 | do { \ |
| 28 | uint64_t value; \ |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 29 | if (GetRegValue(regs, perf_regno, &value)) { \ |
Chih-Hung Hsieh | 2019e83 | 2016-05-18 14:36:58 -0700 | [diff] [blame] | 30 | (dst) = value; \ |
Yabin Cui | 8a52e97 | 2015-10-01 11:32:44 -0700 | [diff] [blame] | 31 | } \ |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 32 | } while (0) |
| 33 | |
| 34 | static ucontext_t BuildUContextFromRegs(const RegSet& regs __attribute__((unused))) { |
| 35 | ucontext_t ucontext; |
| 36 | memset(&ucontext, 0, sizeof(ucontext)); |
| 37 | #if defined(__i386__) |
| 38 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_GS], PERF_REG_X86_GS); |
| 39 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_FS], PERF_REG_X86_FS); |
| 40 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_ES], PERF_REG_X86_ES); |
| 41 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_DS], PERF_REG_X86_DS); |
| 42 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_EAX], PERF_REG_X86_AX); |
| 43 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_EBX], PERF_REG_X86_BX); |
| 44 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_ECX], PERF_REG_X86_CX); |
| 45 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_EDX], PERF_REG_X86_DX); |
| 46 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_ESI], PERF_REG_X86_SI); |
| 47 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_EDI], PERF_REG_X86_DI); |
| 48 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_EBP], PERF_REG_X86_BP); |
| 49 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_EIP], PERF_REG_X86_IP); |
| 50 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_ESP], PERF_REG_X86_SP); |
| 51 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_CS], PERF_REG_X86_CS); |
| 52 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_EFL], PERF_REG_X86_FLAGS); |
| 53 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_SS], PERF_REG_X86_SS); |
| 54 | #elif defined(__x86_64__) |
| 55 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_R8], PERF_REG_X86_R8); |
| 56 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_R9], PERF_REG_X86_R9); |
| 57 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_R10], PERF_REG_X86_R10); |
| 58 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_R11], PERF_REG_X86_R11); |
| 59 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_R12], PERF_REG_X86_R12); |
| 60 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_R13], PERF_REG_X86_R13); |
| 61 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_R14], PERF_REG_X86_R14); |
| 62 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_R15], PERF_REG_X86_R15); |
| 63 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_RDI], PERF_REG_X86_DI); |
| 64 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_RSI], PERF_REG_X86_SI); |
| 65 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_RBP], PERF_REG_X86_BP); |
| 66 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_RBX], PERF_REG_X86_BX); |
| 67 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_RDX], PERF_REG_X86_DX); |
| 68 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_RAX], PERF_REG_X86_AX); |
| 69 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_RCX], PERF_REG_X86_CX); |
| 70 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_RSP], PERF_REG_X86_SP); |
| 71 | SetUContextReg(ucontext.uc_mcontext.gregs[REG_RIP], PERF_REG_X86_IP); |
| 72 | #elif defined(__aarch64__) |
| 73 | for (size_t i = PERF_REG_ARM64_X0; i < PERF_REG_ARM64_MAX; ++i) { |
| 74 | SetUContextReg(ucontext.uc_mcontext.regs[i], i); |
| 75 | } |
| 76 | #elif defined(__arm__) |
| 77 | SetUContextReg(ucontext.uc_mcontext.arm_r0, PERF_REG_ARM_R0); |
| 78 | SetUContextReg(ucontext.uc_mcontext.arm_r1, PERF_REG_ARM_R1); |
| 79 | SetUContextReg(ucontext.uc_mcontext.arm_r2, PERF_REG_ARM_R2); |
| 80 | SetUContextReg(ucontext.uc_mcontext.arm_r3, PERF_REG_ARM_R3); |
| 81 | SetUContextReg(ucontext.uc_mcontext.arm_r4, PERF_REG_ARM_R4); |
| 82 | SetUContextReg(ucontext.uc_mcontext.arm_r5, PERF_REG_ARM_R5); |
| 83 | SetUContextReg(ucontext.uc_mcontext.arm_r6, PERF_REG_ARM_R6); |
| 84 | SetUContextReg(ucontext.uc_mcontext.arm_r7, PERF_REG_ARM_R7); |
| 85 | SetUContextReg(ucontext.uc_mcontext.arm_r8, PERF_REG_ARM_R8); |
| 86 | SetUContextReg(ucontext.uc_mcontext.arm_r9, PERF_REG_ARM_R9); |
| 87 | SetUContextReg(ucontext.uc_mcontext.arm_r10, PERF_REG_ARM_R10); |
| 88 | SetUContextReg(ucontext.uc_mcontext.arm_fp, PERF_REG_ARM_FP); |
| 89 | SetUContextReg(ucontext.uc_mcontext.arm_ip, PERF_REG_ARM_IP); |
| 90 | SetUContextReg(ucontext.uc_mcontext.arm_sp, PERF_REG_ARM_SP); |
| 91 | SetUContextReg(ucontext.uc_mcontext.arm_lr, PERF_REG_ARM_LR); |
| 92 | SetUContextReg(ucontext.uc_mcontext.arm_pc, PERF_REG_ARM_PC); |
| 93 | #endif |
| 94 | return ucontext; |
| 95 | } |
| 96 | |
Yabin Cui | 417df29 | 2016-11-16 12:26:13 -0800 | [diff] [blame] | 97 | std::vector<uint64_t> UnwindCallChain(int abi, const ThreadEntry& thread, |
Yabin Cui | cf31e9d | 2016-07-14 14:29:33 -0700 | [diff] [blame] | 98 | const RegSet& regs, const char* stack, |
| 99 | size_t stack_size, bool strict_arch_check) { |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 100 | std::vector<uint64_t> result; |
Yabin Cui | 417df29 | 2016-11-16 12:26:13 -0800 | [diff] [blame] | 101 | ArchType arch = (abi != PERF_SAMPLE_REGS_ABI_32) ? |
| 102 | ScopedCurrentArch::GetCurrentArch() : |
| 103 | ScopedCurrentArch::GetCurrentArch32(); |
Yabin Cui | 4b6720d | 2016-03-31 14:39:19 -0700 | [diff] [blame] | 104 | if (!IsArchTheSame(arch, GetBuildArch(), strict_arch_check)) { |
Yabin Cui | 257d5e6 | 2016-03-30 16:21:47 -0700 | [diff] [blame] | 105 | LOG(FATAL) << "simpleperf is built in arch " << GetArchString(GetBuildArch()) |
Yabin Cui | 4b6720d | 2016-03-31 14:39:19 -0700 | [diff] [blame] | 106 | << ", and can't do stack unwinding for arch " << GetArchString(arch); |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 107 | return result; |
| 108 | } |
| 109 | uint64_t sp_reg_value; |
Yabin Cui | 4846089 | 2016-03-18 12:30:31 -0700 | [diff] [blame] | 110 | if (!GetSpRegValue(regs, arch, &sp_reg_value)) { |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 111 | LOG(ERROR) << "can't get sp reg value"; |
| 112 | return result; |
| 113 | } |
| 114 | uint64_t stack_addr = sp_reg_value; |
| 115 | |
Yabin Cui | aa0dd19 | 2016-12-15 11:24:03 -0800 | [diff] [blame] | 116 | std::vector<backtrace_map_t> bt_maps(thread.maps->size()); |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 117 | size_t map_index = 0; |
Yabin Cui | aa0dd19 | 2016-12-15 11:24:03 -0800 | [diff] [blame] | 118 | for (auto& map : *thread.maps) { |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 119 | backtrace_map_t& bt_map = bt_maps[map_index++]; |
| 120 | bt_map.start = map->start_addr; |
| 121 | bt_map.end = map->start_addr + map->len; |
| 122 | bt_map.offset = map->pgoff; |
Yabin Cui | eec606c | 2016-07-07 13:53:33 -0700 | [diff] [blame] | 123 | bt_map.name = map->dso->GetDebugFilePath(); |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 124 | } |
| 125 | std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(thread.pid, bt_maps)); |
| 126 | |
| 127 | backtrace_stackinfo_t stack_info; |
| 128 | stack_info.start = stack_addr; |
Yabin Cui | cf31e9d | 2016-07-14 14:29:33 -0700 | [diff] [blame] | 129 | stack_info.end = stack_addr + stack_size; |
| 130 | stack_info.data = reinterpret_cast<const uint8_t*>(stack); |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 131 | |
| 132 | std::unique_ptr<Backtrace> backtrace( |
| 133 | Backtrace::CreateOffline(thread.pid, thread.tid, backtrace_map.get(), stack_info, true)); |
| 134 | ucontext_t ucontext = BuildUContextFromRegs(regs); |
| 135 | if (backtrace->Unwind(0, &ucontext)) { |
| 136 | for (auto it = backtrace->begin(); it != backtrace->end(); ++it) { |
Yabin Cui | 8ce6814 | 2016-08-05 11:27:42 -0700 | [diff] [blame] | 137 | // Unwinding in arm architecture can return 0 pc address. |
| 138 | if (it->pc == 0) { |
| 139 | break; |
| 140 | } |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 141 | result.push_back(it->pc); |
| 142 | } |
| 143 | } |
| 144 | return result; |
| 145 | } |