blob: ff3c1fe10036cb24af5781e53080a096cd2d2cd2 [file] [log] [blame]
/*
* 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 <ucontext.h>
#include <backtrace/Backtrace.h>
#include <android-base/logging.h>
#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<uint64_t> UnwindCallChain(ArchType arch, const ThreadEntry& thread,
const RegSet& regs, const std::vector<char>& stack,
bool strict_arch_check) {
std::vector<uint64_t> result;
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<backtrace_map_t> 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->GetAccessiblePath();
}
std::unique_ptr<BacktraceMap> 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<const uint8_t*>(stack.data());
std::unique_ptr<Backtrace> 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) {
result.push_back(it->pc);
}
}
return result;
}