Files
kaizen/src/frontend/Debugger.cpp
2025-07-31 17:25:22 +02:00

192 lines
5.6 KiB
C++

#include <Debugger.hpp>
#include <imgui.h>
#include <execution>
void BreakpointFunc(s64 addr, s64 startAddr, Disassembler::DisassemblyResult&) {
n64::Core& core = n64::Core::GetInstance();
bool isBroken = core.breakpoints.contains(addr + 4);
ImGui::PushStyleColor(ImGuiCol_CheckMark, 0xff0000ff);
ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, 0);
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, 0x800000ff);
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 0.5f);
if(ImGui::Checkbox(std::format("##toggleBreakpoint{}", (addr - startAddr) / 4).c_str(), &isBroken)) {
core.ToggleBreakpoint(addr + 4);
}
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
void AddressFunc(s64, s64, Disassembler::DisassemblyResult& disasm) {
if(!disasm.success) {
ImGui::TextColored(ImColor(0xffeaefb6), "????????????????");
return;
}
ImGui::TextColored(ImColor(0xffeaefb6), "%s", std::format("{:016X}:", disasm.address).c_str());
}
void InstructionFunc(s64, s64, Disassembler::DisassemblyResult& disasm) {
if(!disasm.success) {
ImGui::TextColored(ImColor(0xffcbf1ae), "Disassembly unsuccessful...");
return;
}
ImGui::TextColored(ImColor(0xffcbf1ae), "%s", std::format("{} ", disasm.mnemonic).c_str());
ImGui::SameLine(0, 0);
for(int i = 0; i < 3; i++) {
if(disasm.ops[i].str.empty())
continue;
if(i >= 2) {
ImGui::TextColored(ImColor(disasm.ops[i].color), "%s", disasm.ops[i].str.c_str());
ImGui::SameLine(0, 0);
continue;
}
std::string op_str = disasm.ops[i].str;
if(!disasm.ops[i+1].str.empty())
op_str += ", ";
ImGui::TextColored(ImColor(disasm.ops[i].color), "%s", op_str.c_str());
ImGui::SameLine(0, 0);
}
}
void CommentFunc(s64, s64, Disassembler::DisassemblyResult& disasm) {
n64::Core& core = n64::Core::GetInstance();
n64::Mem& mem = core.cpu->GetMem();
n64::Registers& regs = core.cpu->GetRegs();
if(!disasm.success) {
ImGui::TextColored(ImColor(0xff71efe5), "");
return;
}
ImGui::TextColored(ImColor(0xff71efe5), "%s", std::format("{}", disasm.GetFormattedComment()).c_str());
u64 vaddr = disasm.GetResolvedAddressFromComment();
if(vaddr == 0xFFFF'FFFF'FFFF'FFFFull)
return;
if(!ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_ForTooltip))
return;
if(!ImGui::BeginTooltip())
return;
ImGui::Text("%s", std::format("Memory contents @ 0x{:016X}", vaddr).c_str());
if(!ImGui::BeginTable("##memoryContents", 16))
return;
for(u32 col = 0; col < 16; col++)
ImGui::TableSetupColumn(std::format("##hexCol{}", col).c_str());
ImGui::TableHeadersRow();
for(u32 row = 0; row < 16; row++) {
ImGui::TableNextRow();
for(u32 col = 0; col < 16; col+=4) {
u32 paddr;
if(!regs.cop0.MapVAddr(n64::Cop0::LOAD, vaddr+row*0x10+col, paddr))
continue;
u32 val = mem.Read<u32>(paddr);
ImGui::TableSetColumnIndex(col+0);
ImGui::Text("%02X", (val >> 24) & 0xff);
ImGui::TableSetColumnIndex(col+1);
ImGui::Text("%02X", (val >> 16) & 0xff);
ImGui::TableSetColumnIndex(col+2);
ImGui::Text("%02X", (val >> 8) & 0xff);
ImGui::TableSetColumnIndex(col+3);
ImGui::Text("%02X", (val >> 0) & 0xff);
}
}
ImGui::EndTable();
ImGui::EndTooltip();
}
bool Debugger::render() {
n64::Core& core = n64::Core::GetInstance();
n64::Registers& regs = core.cpu->GetRegs();
if(!enabled)
return false;
static s64 startAddr = 0xFFFF'FFFF'8000'0000;
int step = 4, stepFast = 256;
static bool followPC = true;
if(!ImGui::Begin("Debugger", &enabled))
return false;
ImGui::BeginDisabled(followPC);
ImGui::InputScalar("Address", ImGuiDataType_S64, (void*)&startAddr, (void*)&step, (void*)&stepFast, "%016lX", ImGuiInputTextFlags_CharsHexadecimal);
ImGui::EndDisabled();
ImGui::Text("Follow program counter:");
ImGui::SameLine(0,0);
ImGui::Checkbox("##followPC", &followPC);
ImGui::SameLine(0,0);
ImGui::Text("Add a breakpoint");
ImGui::SameLine(0,0);
if(followPC)
startAddr = regs.pc - 256; // TODO: arbitrary???
if(ImGui::Button(core.breakpoints.contains(startAddr) ? "-" : "+")) {
core.ToggleBreakpoint(startAddr);
}
if(!ImGui::BeginTable("Disassembly", columns.size(), ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody))
return false;
for(int i = 0; i < columns.size(); i++)
ImGui::TableSetupColumn(columns[i].name);
ImGui::TableHeadersRow();
for(u64 addr = startAddr; addr < startAddr + MAX_LINES_OF_DISASM * sizeof(u32); addr += sizeof(u32)) {
auto disasm = Disassembler::GetInstance().Disassemble(addr);
auto addrIsCurrent = addr == regs.nextPC;
auto addrIsBreakpoint = core.breakpoints.contains(addr);
ImColor colorChoice = ImGui::GetStyle().Colors[ImGuiCol_TableRowBg];
ImColor colorChoiceAlt = ImGui::GetStyle().Colors[ImGuiCol_TableRowBgAlt];
if(addrIsCurrent) {
colorChoice = 0x80e27fbc;
colorChoiceAlt = 0x80e27fbc;
}
if(addrIsBreakpoint) {
colorChoice = 0x800000ff;
colorChoiceAlt = 0x800000ff;
}
ImGui::PushStyleColor(ImGuiCol_TableRowBg, colorChoice.Value);
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, colorChoiceAlt.Value);
ImGui::TableNextRow();
for(int i = 0; i < columns.size(); i++) {
ImGui::TableSetColumnIndex(i);
columns[i].func(addr, startAddr, disasm);
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
ImGui::EndTable();
ImGui::End();
return true;
}