blob: d91b1db8432989a9429e7d4ee98840a5f457dc4b [file] [log] [blame] [edit]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/ipc/unwinder_support.h"
#include "src/developer/debug/ipc/records.h"
#include "src/developer/debug/shared/arch.h"
#include "src/developer/debug/shared/register_info.h"
#include "src/lib/unwinder/unwind.h"
namespace debug_ipc {
namespace {
StackFrame::Trust ConvertTrust(unwinder::Frame::Trust unwinder_trust) {
switch (unwinder_trust) {
case unwinder::Frame::Trust::kScan:
return StackFrame::Trust::kScan;
case unwinder::Frame::Trust::kSCS:
return StackFrame::Trust::kSCS;
case unwinder::Frame::Trust::kSigReturn:
return StackFrame::Trust::kSigReturn;
case unwinder::Frame::Trust::kFP:
return StackFrame::Trust::kFP;
case unwinder::Frame::Trust::kPLT:
return StackFrame::Trust::kPLT;
case unwinder::Frame::Trust::kArmEhAbi:
return StackFrame::Trust::kArmEhAbi;
case unwinder::Frame::Trust::kCFI:
return StackFrame::Trust::kCFI;
case unwinder::Frame::Trust::kContext:
return StackFrame::Trust::kContext;
default:
return StackFrame::Trust::kUnknown;
}
}
} // namespace
unwinder::Registers ConvertRegisters(debug::Arch arch,
const std::vector<debug::RegisterValue>& regs) {
std::optional<unwinder::Registers> res = std::nullopt;
switch (arch) {
case debug::Arch::kX64:
res = unwinder::Registers(unwinder::Registers::Arch::kX64);
// The first 4 registers are out-of-order.
res->Set(unwinder::RegisterID::kX64_rax, static_cast<uint64_t>((regs)[0].GetValue()));
res->Set(unwinder::RegisterID::kX64_rbx, static_cast<uint64_t>((regs)[1].GetValue()));
res->Set(unwinder::RegisterID::kX64_rcx, static_cast<uint64_t>((regs)[2].GetValue()));
res->Set(unwinder::RegisterID::kX64_rdx, static_cast<uint64_t>((regs)[3].GetValue()));
for (int i = 4; i < static_cast<int>(unwinder::RegisterID::kX64_last); i++) {
res->Set(static_cast<unwinder::RegisterID>(i), static_cast<uint64_t>((regs)[i].GetValue()));
}
break;
case debug::Arch::kArm64:
res = unwinder::Registers(unwinder::Registers::Arch::kArm64);
for (int i = 0; i < static_cast<int>(unwinder::RegisterID::kArm64_last); i++) {
res->Set(static_cast<unwinder::RegisterID>(i), static_cast<uint64_t>((regs)[i].GetValue()));
}
break;
case debug::Arch::kRiscv64:
FX_NOTREACHED() << "Riscv64 is not supported yet";
break;
default:
FX_NOTREACHED() << "Unknown platform";
break;
}
return *res;
}
std::vector<debug_ipc::StackFrame> ConvertFrames(const std::vector<unwinder::Frame>& frames) {
std::vector<debug_ipc::StackFrame> res;
for (const unwinder::Frame& frame : frames) {
std::vector<debug::RegisterValue> frame_regs;
uint64_t ip = 0;
uint64_t sp = 0;
frame.regs.GetSP(sp);
frame.regs.GetPC(ip);
if (!res.empty()) {
res.back().cfa = sp;
}
debug::Arch arch;
switch (frame.regs.arch()) {
case unwinder::Registers::Arch::kX64:
arch = debug::Arch::kX64;
break;
case unwinder::Registers::Arch::kArm32:
case unwinder::Registers::Arch::kArm64:
arch = debug::Arch::kArm64;
break;
case unwinder::Registers::Arch::kRiscv64:
arch = debug::Arch::kRiscv64;
break;
}
frame_regs.reserve(frame.regs.size());
for (auto& [reg_id, val] : frame.regs) {
if (auto* info = debug::DWARFToRegisterInfo(arch, static_cast<uint32_t>(reg_id))) {
frame_regs.emplace_back(info->id, val);
}
}
auto pc_is_return_address = frame.pc_is_return_address ? StackFrame::AddressType::kReturn
: StackFrame::AddressType::kExact;
res.emplace_back(ip, sp, 0, ConvertTrust(frame.trust), pc_is_return_address, frame_regs);
}
return res;
}
} // namespace debug_ipc