Initial work for comment detail in debugger

This commit is contained in:
irisz64
2025-07-31 14:42:43 +02:00
parent cad486e1b9
commit 1d117bf96b
4 changed files with 212 additions and 128 deletions

View File

@@ -1,99 +1,9 @@
#include <Disassembler.hpp>
#include <Core.hpp>
#include <optional>
Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 address, const u32 instruction) const {
cs_insn *insn;
const auto bytes = Util::IntegralToBuffer(std::byteswap(instruction));
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
if (count <= 0)
return {};
DisassemblyResult result{true, std::format("0x{:016X}:\t{}\t{}", insn[0].address, insn[0].mnemonic, insn[0].op_str)};
cs_free(insn, count);
return result;
}
[[nodiscard]] Disassembler::DisassemblyResult Disassembler::Disassemble(const u32 address) const {
n64::Core& core = n64::Core::GetInstance();
n64::Mem& mem = core.cpu->GetMem();
u32 paddr;
if(!core.cpu->GetRegs().cop0.MapVAddr(n64::Cop0::TLBAccessType::LOAD, address, paddr))
return DisassemblyResult{false, ""};
u32 instruction = mem.Read<u32>(paddr);
return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction);
}
Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 address, const u32 instruction) const {
cs_insn *insn;
const auto bytes = Util::IntegralToBuffer(std::byteswap(instruction));
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
if (count <= 0)
return {};
DisassemblyResult result{true};
result.address = insn[0].address;
result.mnemonic = insn[0].mnemonic;
result.full += std::format("0x{:016X}", result.address) + ":\t";
result.full += result.mnemonic + "\t";
result.comment = "// ";
const cs_detail *details = insn[0].detail;
auto formatOperand = [&](const cs_mips_op &operand) {
switch (operand.type) {
case MIPS_OP_IMM:
return DisassemblyResult::Operand{
0xffcbf1ae,
std::format("#{:X}", operand.is_unsigned ? operand.uimm : operand.imm)
};
case MIPS_OP_MEM:
return DisassemblyResult::Operand{
0xffaef1c3,
std::format("{}(0x{:X})", cs_reg_name(handle, operand.mem.base), operand.mem.disp)
};
case MIPS_OP_REG:
return DisassemblyResult::Operand{
0xffaef1eb,
std::format("{}", cs_reg_name(handle, operand.reg))
};
default:
return DisassemblyResult::Operand { 0xff808080, "" };
}
};
auto formatComment = [&](const cs_mips_op &operand) -> std::string {
switch (operand.type) {
case MIPS_OP_IMM:
return std::format("#{:X}", operand.is_unsigned ? operand.uimm : operand.imm);
case MIPS_OP_MEM:
return std::format("{}(0x{:X})", CapstoneToRegValue(operand.mem.base), operand.mem.disp);
case MIPS_OP_REG:
return std::format("{}", CapstoneToRegValue(operand.reg));
default:
return "! Unknown !";
}
};
for (u8 i = 0; i < details->mips.op_count && i < 3; i++) {
result.ops[i] = formatOperand(details->mips.operands[i]);
result.comment += formatComment(details->mips.operands[i]) + " ";
result.full += result.ops[i].str + "\t";
}
result.full += result.comment;
cs_free(insn, count);
return result;
}
std::string Disassembler::CapstoneToRegValue(mips_reg reg) const {
template <>
std::optional<u64> Disassembler::CapstoneToRegValue(mips_reg reg) const {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
u64 val = 0;
switch(reg) {
@@ -191,8 +101,109 @@ std::string Disassembler::CapstoneToRegValue(mips_reg reg) const {
val = regs.Read<u64>(31);
break;
default:
return "! Unknown !";
return {};
}
return std::format("{} (= 0x{:016X})", cs_reg_name(handle, reg), val);
return val;
}
template <>
std::string Disassembler::CapstoneToRegValue(mips_reg reg) const {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
auto val = CapstoneToRegValue<std::optional<u64>>(reg);
return std::format("{}", val.has_value() ? std::format("{} (= 0x{:016X})", cs_reg_name(handle, reg), val.value()) : "! Unknown !");
}
Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 address, const u32 instruction) const {
cs_insn *insn;
const auto bytes = Util::IntegralToBuffer(std::byteswap(instruction));
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
if (count <= 0)
return {};
DisassemblyResult result{true, std::format("0x{:016X}:\t{}\t{}", insn[0].address, insn[0].mnemonic, insn[0].op_str)};
cs_free(insn, count);
return result;
}
[[nodiscard]] Disassembler::DisassemblyResult Disassembler::Disassemble(const u32 address) const {
n64::Core& core = n64::Core::GetInstance();
n64::Mem& mem = core.cpu->GetMem();
u32 paddr;
if(!core.cpu->GetRegs().cop0.MapVAddr(n64::Cop0::TLBAccessType::LOAD, address, paddr))
return DisassemblyResult{false, ""};
u32 instruction = mem.Read<u32>(paddr);
return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction);
}
Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 address, const u32 instruction) const {
n64::Core& core = n64::Core::GetInstance();
cs_insn *insn;
const auto bytes = Util::IntegralToBuffer(std::byteswap(instruction));
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
if (count <= 0)
return {};
DisassemblyResult result{true};
result.address = insn[0].address;
result.mnemonic = insn[0].mnemonic;
result.full += std::format("0x{:016X}", result.address) + ":\t";
result.full += result.mnemonic + "\t";
const cs_detail *details = insn[0].detail;
auto formatOperand = [&](const cs_mips_op &operand) {
switch (operand.type) {
case MIPS_OP_IMM:
return DisassemblyResult::Operand{
0xffcbf1ae,
std::format("#{:X}", operand.is_unsigned ? operand.uimm : operand.imm)
};
case MIPS_OP_MEM:
return DisassemblyResult::Operand{
0xffaef1c3,
std::format("{}(0x{:X})", cs_reg_name(handle, operand.mem.base), operand.mem.disp)
};
case MIPS_OP_REG:
return DisassemblyResult::Operand{
0xffaef1eb,
std::format("{}", cs_reg_name(handle, operand.reg))
};
default:
return DisassemblyResult::Operand { 0xff808080, "" };
}
};
auto formatComment = [&](const cs_mips_op &operand) -> CommentPart {
switch (operand.type) {
case MIPS_OP_IMM:
return {std::format("#{:X}, ", operand.is_unsigned ? operand.uimm : operand.imm)};
case MIPS_OP_MEM:
return {
std::format("{}(0x{:X}), ", CapstoneToRegValue<std::string>(operand.mem.base), operand.mem.disp),
CapstoneToRegValue<std::optional<u64>>(operand.mem.base).value() + (s16)operand.mem.disp,
};
case MIPS_OP_REG:
return {std::format("{}, ", CapstoneToRegValue<std::string>(operand.reg))};
default:
return {"! Unknown !"};
}
};
for (u8 i = 0; i < details->mips.op_count && i < 3; i++) {
result.ops[i] = formatOperand(details->mips.operands[i]);
result.comment[i] = formatComment(details->mips.operands[i]);
result.full += result.ops[i].str + "\t";
}
cs_free(insn, count);
return result;
}

View File

@@ -5,6 +5,11 @@
#include <array>
struct Disassembler {
struct CommentPart {
std::string str;
u64 resolvedAddr = 0xFFFF'FFFF'FFFF'FFFFull;
};
struct DisassemblyResult {
bool success = false;
std::string full;
@@ -15,7 +20,23 @@ struct Disassembler {
std::string str;
};
std::array<Operand, 3> ops{};
std::string comment;
std::array<CommentPart, 3> comment{};
std::string GetFormattedComment() {
std::string res{};
for(auto& [str, _] : comment) {
res += str;
}
return res;
}
u64 GetResolvedAddressFromComment() {
auto it = std::ranges::find_if(comment, [](auto& part) {
return part.resolvedAddr != 0xFFFF'FFFF'FFFF'FFFFull;
});
if(it == comment.end()) return 0xFFFF'FFFF'FFFF'FFFFull;
return it->resolvedAddr;
}
};
~Disassembler() { cs_close(&handle); }
@@ -24,13 +45,13 @@ struct Disassembler {
static Disassembler ret(rsp);
return ret;
}
[[nodiscard]] DisassemblyResult Disassemble(const u32 address) const;
[[nodiscard]] DisassemblyResult DisassembleDetailed(u32 address, u32 instruction) const;
[[nodiscard]] DisassemblyResult DisassembleSimple(u32 address, u32 instruction) const;
private:
std::string CapstoneToRegValue(mips_reg reg) const;
template <typename T>
T CapstoneToRegValue(mips_reg reg) const;
explicit Disassembler(const bool rsp) : rsp(rsp) {
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN), &handle) !=
CS_ERR_OK) {