blob: ee701afa0873f5efb27e743f2f4e8395ad599e43 [file] [log] [blame]
// Copyright 2018 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/third_party/libunwindstack/fuchsia/RegsFuchsia.h"
#include <zircon/syscalls.h>
#include <zircon/syscalls/debug.h>
#include "unwindstack/Elf.h"
#include "unwindstack/MachineX86_64.h"
#include "unwindstack/Memory.h"
namespace unwindstack {
namespace {
constexpr uint16_t kUnwindStackRegCount = X86_64_REG_LAST;
} // namespace
RegsFuchsia::RegsFuchsia()
: RegsImpl<uint64_t>(kUnwindStackRegCount,
Location(LOCATION_SP_OFFSET, -8)) {}
RegsFuchsia::~RegsFuchsia() = default;
ArchEnum RegsFuchsia::Arch() { return ARCH_X86_64; }
void RegsFuchsia::Set(const zx_thread_state_general_regs& input) {
regs_.resize(kUnwindStackRegCount);
regs_[X86_64_REG_RAX] = input.rax;
regs_[X86_64_REG_RBX] = input.rbx;
regs_[X86_64_REG_RCX] = input.rcx;
regs_[X86_64_REG_RDX] = input.rdx;
regs_[X86_64_REG_RSI] = input.rsi;
regs_[X86_64_REG_RDI] = input.rdi;
regs_[X86_64_REG_RBP] = input.rbp;
regs_[X86_64_REG_RSP] = input.rsp;
regs_[X86_64_REG_R8] = input.r8;
regs_[X86_64_REG_R9] = input.r9;
regs_[X86_64_REG_R10] = input.r10;
regs_[X86_64_REG_R11] = input.r11;
regs_[X86_64_REG_R12] = input.r12;
regs_[X86_64_REG_R13] = input.r13;
regs_[X86_64_REG_R14] = input.r14;
regs_[X86_64_REG_R15] = input.r15;
regs_[X86_64_REG_RIP] = input.rip;
}
zx_status_t RegsFuchsia::Read(zx_handle_t thread) {
zx_thread_state_general_regs thread_regs;
zx_status_t status = zx_thread_read_state(
thread, ZX_THREAD_STATE_GENERAL_REGS, &thread_regs, sizeof(thread_regs));
if (status != ZX_OK)
return status;
Set(thread_regs);
return ZX_OK;
}
uint64_t RegsFuchsia::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
// Android uses this to "fix" the IP (source of the call instead of the
// return address). But we expect no adjustment.
return 0;
}
bool RegsFuchsia::SetPcFromReturnAddress(Memory* process_memory) {
// Attempt to get the return address from the top of the stack.
uint64_t new_pc;
if (!process_memory->ReadFully(regs_[X86_64_REG_SP], &new_pc,
sizeof(new_pc)) ||
new_pc == regs_[X86_64_REG_PC]) {
return false;
}
regs_[X86_64_REG_PC] = new_pc;
return true;
}
bool RegsFuchsia::StepIfSignalHandler(uint64_t rel_pc, Elf* elf,
Memory* process_memory) {
// TODO(brettw) Figure out if we need to implement this.
return false;
}
void RegsFuchsia::IterateRegisters(
std::function<void(const char*, uint64_t)> fn) {
fn("rax", regs_[X86_64_REG_RAX]);
fn("rbx", regs_[X86_64_REG_RBX]);
fn("rcx", regs_[X86_64_REG_RCX]);
fn("rdx", regs_[X86_64_REG_RDX]);
fn("r8", regs_[X86_64_REG_R8]);
fn("r9", regs_[X86_64_REG_R9]);
fn("r10", regs_[X86_64_REG_R10]);
fn("r11", regs_[X86_64_REG_R11]);
fn("r12", regs_[X86_64_REG_R12]);
fn("r13", regs_[X86_64_REG_R13]);
fn("r14", regs_[X86_64_REG_R14]);
fn("r15", regs_[X86_64_REG_R15]);
fn("rdi", regs_[X86_64_REG_RDI]);
fn("rsi", regs_[X86_64_REG_RSI]);
fn("rbp", regs_[X86_64_REG_RBP]);
fn("rsp", regs_[X86_64_REG_RSP]);
fn("rip", regs_[X86_64_REG_RIP]);
}
uint64_t RegsFuchsia::pc() { return regs_[X86_64_REG_PC]; }
uint64_t RegsFuchsia::sp() { return regs_[X86_64_REG_SP]; }
void RegsFuchsia::set_pc(uint64_t pc) { regs_[X86_64_REG_PC] = pc; }
void RegsFuchsia::set_sp(uint64_t sp) { regs_[X86_64_REG_SP] = sp; }
Regs* RegsFuchsia::Clone() { return new RegsFuchsia(*this); }
} // namespace unwindstack