blob: a60d7c29bdc1cd492dce32075360a8794e9a4a3a [file] [log] [blame]
// Copyright 2016 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 "registers_amd64.h"
#include "registers.h"
#include <cinttypes>
#include <cstring>
#include <zircon/syscalls.h>
#include <zircon/syscalls/debug.h>
#include "lib/fxl/logging.h"
#include "lib/fxl/strings/string_printf.h"
#include "garnet/lib/debugger_utils/util.h"
#include "arch_x86.h"
#include "thread.h"
namespace inferior_control {
int GetPCRegisterNumber() { return static_cast<int>(Amd64Register::RIP); }
int GetFPRegisterNumber() { return static_cast<int>(Amd64Register::RBP); }
int GetSPRegisterNumber() { return static_cast<int>(Amd64Register::RSP); }
namespace {
// Includes all registers if |register_number| is -1.
// TODO: Here as elsewhere: more regsets.
std::string GetRegisterAsStringHelper(const zx_thread_state_general_regs& gregs,
int regno) {
FXL_DCHECK(regno >= -1 &&
regno < static_cast<int>(Amd64Register::NUM_REGISTERS));
// Based on the value of |regno|, we either need to fit in all
// registers or just a single one.
const size_t kDataSize = regno < 0 ? sizeof(gregs) : sizeof(uint64_t);
const uint8_t* greg_bytes = reinterpret_cast<const uint8_t*>(&gregs);
greg_bytes += regno < 0 ? 0 : regno * sizeof(uint64_t);
return debugger_utils::EncodeByteArrayString(greg_bytes, kDataSize);
}
class RegistersAmd64 final : public Registers {
public:
RegistersAmd64(Thread* thread) : Registers(thread) {
memset(&gregs_, 0, sizeof(gregs_));
}
~RegistersAmd64() = default;
bool IsSupported() override { return true; }
bool RefreshRegset(int regset) override {
FXL_DCHECK(regset == 0);
return RefreshRegsetHelper(regset, &gregs_, sizeof(gregs_));
}
bool WriteRegset(int regset) override {
FXL_DCHECK(regset == 0);
return WriteRegsetHelper(regset, &gregs_, sizeof(gregs_));
}
std::string GetRegsetAsString(int regset) override {
FXL_DCHECK(regset == 0);
return GetRegisterAsStringHelper(gregs_, -1);
}
bool SetRegsetFromString(int regset, const fxl::StringView& value) override {
FXL_DCHECK(regset == 0);
return SetRegsetFromStringHelper(regset, &gregs_, sizeof(gregs_), value);
}
std::string GetRegisterAsString(int regno) override {
if (regno < 0 || regno >= static_cast<int>(Amd64Register::NUM_REGISTERS)) {
FXL_LOG(ERROR) << "Bad register number: " << regno;
return "";
}
return GetRegisterAsStringHelper(gregs_, regno);
}
bool GetRegister(int regno, void* buffer, size_t buf_size) override {
if (regno < 0 || regno >= static_cast<int>(Amd64Register::NUM_REGISTERS)) {
FXL_LOG(ERROR) << "Bad register_number: " << regno;
return false;
}
if (buf_size != sizeof(uint64_t)) {
FXL_LOG(ERROR) << "Bad buffer size: " << buf_size;
return false;
}
auto greg_bytes = reinterpret_cast<const uint8_t*>(&gregs_);
greg_bytes += regno * sizeof(uint64_t);
std::memcpy(buffer, greg_bytes, buf_size);
FXL_VLOG(1) << "Get register " << regno << " = "
<< debugger_utils::EncodeByteArrayString(greg_bytes, buf_size);
return true;
}
bool SetRegister(int regno, const void* value, size_t value_size) override {
if (regno < 0 || regno >= static_cast<int>(Amd64Register::NUM_REGISTERS)) {
FXL_LOG(ERROR) << "Invalid x86_64 register number: " << regno;
return false;
}
// On x86_64 all general register values are 64-bit.
if (value_size != sizeof(uint64_t)) {
FXL_LOG(ERROR) << "Invalid x86_64 register value size: " << value_size;
return false;
}
auto greg_bytes = reinterpret_cast<uint8_t*>(&gregs_);
greg_bytes += regno * sizeof(uint64_t);
std::memcpy(greg_bytes, value, value_size);
FXL_VLOG(1) << "Set register " << regno << " = "
<< debugger_utils::EncodeByteArrayString(greg_bytes,
value_size);
return true;
}
bool SetSingleStep(bool enable) override {
if (enable)
gregs_.rflags |= X86_EFLAGS_TF_MASK;
else
gregs_.rflags &= ~static_cast<uint64_t>(X86_EFLAGS_TF_MASK);
FXL_VLOG(2) << "rflags.TF set to " << enable;
return true;
}
std::string GetFormattedRegset(int regset) override {
if (regset != 0)
return fxl::StringPrintf("Invalid regset %d\n", regset);
return FormatGeneralRegisters();
}
private:
std::string FormatGeneralRegisters() {
std::string result;
result += fxl::StringPrintf(" CS: %#18llx RIP: %#18" PRIx64
" EFL: %#18" PRIx64 "\n",
0ull, gregs_.rip, gregs_.rflags);
result += fxl::StringPrintf(" RAX: %#18" PRIx64 " RBX: %#18" PRIx64
" RCX: %#18" PRIx64 " RDX: %#18" PRIx64 "\n",
gregs_.rax, gregs_.rbx, gregs_.rcx, gregs_.rdx);
result += fxl::StringPrintf(" RSI: %#18" PRIx64 " RDI: %#18" PRIx64
" RBP: %#18" PRIx64 " RSP: %#18" PRIx64 "\n",
gregs_.rsi, gregs_.rdi, gregs_.rbp, gregs_.rsp);
result += fxl::StringPrintf(" R8: %#18" PRIx64 " R9: %#18" PRIx64
" R10: %#18" PRIx64 " R11: %#18" PRIx64 "\n",
gregs_.r8, gregs_.r9, gregs_.r10, gregs_.r11);
result += fxl::StringPrintf(" R12: %#18" PRIx64 " R13: %#18" PRIx64
" R14: %#18" PRIx64 " R15: %#18" PRIx64 "\n",
gregs_.r12, gregs_.r13, gregs_.r14, gregs_.r15);
return result;
}
zx_thread_state_general_regs gregs_;
};
} // namespace
// static
std::unique_ptr<Registers> Registers::Create(Thread* thread) {
return std::unique_ptr<Registers>(new RegistersAmd64(thread));
}
// static
std::string Registers::GetUninitializedGeneralRegistersAsString() {
return std::string(sizeof(zx_thread_state_general_regs) * 2, '0');
}
// static
size_t Registers::GetRegisterSize() { return sizeof(uint64_t); }
} // namespace inferior_control