/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "dwarf_unwind.h" #include #include #include #include "thread_tree.h" #define SetUContextReg(dst, perf_regno) \ do { \ uint64_t value; \ if (GetRegValue(regs, perf_regno, &value)) { \ (dst) = value; \ } \ } while (0) static ucontext_t BuildUContextFromRegs(const RegSet& regs __attribute__((unused))) { ucontext_t ucontext; memset(&ucontext, 0, sizeof(ucontext)); #if defined(__i386__) SetUContextReg(ucontext.uc_mcontext.gregs[REG_GS], PERF_REG_X86_GS); SetUContextReg(ucontext.uc_mcontext.gregs[REG_FS], PERF_REG_X86_FS); SetUContextReg(ucontext.uc_mcontext.gregs[REG_ES], PERF_REG_X86_ES); SetUContextReg(ucontext.uc_mcontext.gregs[REG_DS], PERF_REG_X86_DS); SetUContextReg(ucontext.uc_mcontext.gregs[REG_EAX], PERF_REG_X86_AX); SetUContextReg(ucontext.uc_mcontext.gregs[REG_EBX], PERF_REG_X86_BX); SetUContextReg(ucontext.uc_mcontext.gregs[REG_ECX], PERF_REG_X86_CX); SetUContextReg(ucontext.uc_mcontext.gregs[REG_EDX], PERF_REG_X86_DX); SetUContextReg(ucontext.uc_mcontext.gregs[REG_ESI], PERF_REG_X86_SI); SetUContextReg(ucontext.uc_mcontext.gregs[REG_EDI], PERF_REG_X86_DI); SetUContextReg(ucontext.uc_mcontext.gregs[REG_EBP], PERF_REG_X86_BP); SetUContextReg(ucontext.uc_mcontext.gregs[REG_EIP], PERF_REG_X86_IP); SetUContextReg(ucontext.uc_mcontext.gregs[REG_ESP], PERF_REG_X86_SP); SetUContextReg(ucontext.uc_mcontext.gregs[REG_CS], PERF_REG_X86_CS); SetUContextReg(ucontext.uc_mcontext.gregs[REG_EFL], PERF_REG_X86_FLAGS); SetUContextReg(ucontext.uc_mcontext.gregs[REG_SS], PERF_REG_X86_SS); #elif defined(__x86_64__) SetUContextReg(ucontext.uc_mcontext.gregs[REG_R8], PERF_REG_X86_R8); SetUContextReg(ucontext.uc_mcontext.gregs[REG_R9], PERF_REG_X86_R9); SetUContextReg(ucontext.uc_mcontext.gregs[REG_R10], PERF_REG_X86_R10); SetUContextReg(ucontext.uc_mcontext.gregs[REG_R11], PERF_REG_X86_R11); SetUContextReg(ucontext.uc_mcontext.gregs[REG_R12], PERF_REG_X86_R12); SetUContextReg(ucontext.uc_mcontext.gregs[REG_R13], PERF_REG_X86_R13); SetUContextReg(ucontext.uc_mcontext.gregs[REG_R14], PERF_REG_X86_R14); SetUContextReg(ucontext.uc_mcontext.gregs[REG_R15], PERF_REG_X86_R15); SetUContextReg(ucontext.uc_mcontext.gregs[REG_RDI], PERF_REG_X86_DI); SetUContextReg(ucontext.uc_mcontext.gregs[REG_RSI], PERF_REG_X86_SI); SetUContextReg(ucontext.uc_mcontext.gregs[REG_RBP], PERF_REG_X86_BP); SetUContextReg(ucontext.uc_mcontext.gregs[REG_RBX], PERF_REG_X86_BX); SetUContextReg(ucontext.uc_mcontext.gregs[REG_RDX], PERF_REG_X86_DX); SetUContextReg(ucontext.uc_mcontext.gregs[REG_RAX], PERF_REG_X86_AX); SetUContextReg(ucontext.uc_mcontext.gregs[REG_RCX], PERF_REG_X86_CX); SetUContextReg(ucontext.uc_mcontext.gregs[REG_RSP], PERF_REG_X86_SP); SetUContextReg(ucontext.uc_mcontext.gregs[REG_RIP], PERF_REG_X86_IP); #elif defined(__aarch64__) for (size_t i = PERF_REG_ARM64_X0; i < PERF_REG_ARM64_MAX; ++i) { SetUContextReg(ucontext.uc_mcontext.regs[i], i); } #elif defined(__arm__) SetUContextReg(ucontext.uc_mcontext.arm_r0, PERF_REG_ARM_R0); SetUContextReg(ucontext.uc_mcontext.arm_r1, PERF_REG_ARM_R1); SetUContextReg(ucontext.uc_mcontext.arm_r2, PERF_REG_ARM_R2); SetUContextReg(ucontext.uc_mcontext.arm_r3, PERF_REG_ARM_R3); SetUContextReg(ucontext.uc_mcontext.arm_r4, PERF_REG_ARM_R4); SetUContextReg(ucontext.uc_mcontext.arm_r5, PERF_REG_ARM_R5); SetUContextReg(ucontext.uc_mcontext.arm_r6, PERF_REG_ARM_R6); SetUContextReg(ucontext.uc_mcontext.arm_r7, PERF_REG_ARM_R7); SetUContextReg(ucontext.uc_mcontext.arm_r8, PERF_REG_ARM_R8); SetUContextReg(ucontext.uc_mcontext.arm_r9, PERF_REG_ARM_R9); SetUContextReg(ucontext.uc_mcontext.arm_r10, PERF_REG_ARM_R10); SetUContextReg(ucontext.uc_mcontext.arm_fp, PERF_REG_ARM_FP); SetUContextReg(ucontext.uc_mcontext.arm_ip, PERF_REG_ARM_IP); SetUContextReg(ucontext.uc_mcontext.arm_sp, PERF_REG_ARM_SP); SetUContextReg(ucontext.uc_mcontext.arm_lr, PERF_REG_ARM_LR); SetUContextReg(ucontext.uc_mcontext.arm_pc, PERF_REG_ARM_PC); #endif return ucontext; } std::vector UnwindCallChain(int abi, const ThreadEntry& thread, const RegSet& regs, const char* stack, size_t stack_size, bool strict_arch_check) { std::vector result; ArchType arch = (abi != PERF_SAMPLE_REGS_ABI_32) ? ScopedCurrentArch::GetCurrentArch() : ScopedCurrentArch::GetCurrentArch32(); if (!IsArchTheSame(arch, GetBuildArch(), strict_arch_check)) { LOG(FATAL) << "simpleperf is built in arch " << GetArchString(GetBuildArch()) << ", and can't do stack unwinding for arch " << GetArchString(arch); return result; } uint64_t sp_reg_value; if (!GetSpRegValue(regs, arch, &sp_reg_value)) { LOG(ERROR) << "can't get sp reg value"; return result; } uint64_t stack_addr = sp_reg_value; std::vector bt_maps(thread.maps->size()); size_t map_index = 0; for (auto& map : *thread.maps) { backtrace_map_t& bt_map = bt_maps[map_index++]; bt_map.start = map->start_addr; bt_map.end = map->start_addr + map->len; bt_map.offset = map->pgoff; bt_map.name = map->dso->GetDebugFilePath(); } std::unique_ptr backtrace_map(BacktraceMap::Create(thread.pid, bt_maps)); backtrace_stackinfo_t stack_info; stack_info.start = stack_addr; stack_info.end = stack_addr + stack_size; stack_info.data = reinterpret_cast(stack); std::unique_ptr backtrace( Backtrace::CreateOffline(thread.pid, thread.tid, backtrace_map.get(), stack_info, true)); ucontext_t ucontext = BuildUContextFromRegs(regs); if (backtrace->Unwind(0, &ucontext)) { for (auto it = backtrace->begin(); it != backtrace->end(); ++it) { // Unwinding in arm architecture can return 0 pc address. if (it->pc == 0) { break; } result.push_back(it->pc); } } return result; }