From 651e5336b465af11ac892f2f3ea3577665307819 Mon Sep 17 00:00:00 2001 From: Crementif <26669564+Crementif@users.noreply.github.com> Date: Thu, 3 Aug 2023 06:45:11 -0700 Subject: [PATCH] debugger: Add logging breakpoint + misc fixes (#927) --- src/Cafe/HW/Espresso/Debugger/Debugger.cpp | 83 ++++++++++---- src/Cafe/HW/Espresso/Debugger/Debugger.h | 6 +- src/gui/debugger/BreakpointWindow.cpp | 107 ++++++++++++------ src/gui/debugger/BreakpointWindow.h | 3 +- src/gui/debugger/DebuggerWindow2.cpp | 11 +- src/gui/debugger/DisasmCtrl.cpp | 51 ++++----- src/gui/debugger/DumpCtrl.cpp | 60 ++++------ .../DebugPPCThreadsWindow.cpp | 4 +- 8 files changed, 193 insertions(+), 132 deletions(-) diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp index b6417080..0883c436 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp @@ -1,5 +1,6 @@ #include "gui/guiWrapper.h" #include "Debugger.h" +#include "Cafe/OS/RPL/rpl_structs.h" #include "Cemu/PPCAssembler/ppcAssembler.h" #include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h" #include "Cemu/ExpressionParser/ExpressionParser.h" @@ -74,7 +75,7 @@ uint32 debugger_getAddressOriginalOpcode(uint32 address) auto bpItr = debugger_getFirstBP(address); while (bpItr) { - if (bpItr->bpType == DEBUGGER_BP_T_NORMAL || bpItr->bpType == DEBUGGER_BP_T_ONE_SHOT) + if (bpItr->isExecuteBP()) return bpItr->originalOpcodeValue; bpItr = bpItr->next; } @@ -121,32 +122,23 @@ void debugger_updateExecutionBreakpoint(uint32 address, bool forceRestore) } } -void debugger_createExecuteBreakpoint(uint32 address) +void debugger_createCodeBreakpoint(uint32 address, uint8 bpType) { // check if breakpoint already exists auto existingBP = debugger_getFirstBP(address); - if (existingBP && debuggerBPChain_hasType(existingBP, DEBUGGER_BP_T_NORMAL)) + if (existingBP && debuggerBPChain_hasType(existingBP, bpType)) return; // breakpoint already exists // get original opcode at address uint32 originalOpcode = debugger_getAddressOriginalOpcode(address); // init breakpoint object - DebuggerBreakpoint* bp = new DebuggerBreakpoint(address, originalOpcode, DEBUGGER_BP_T_NORMAL, true); + DebuggerBreakpoint* bp = new DebuggerBreakpoint(address, originalOpcode, bpType, true); debuggerBPChain_add(address, bp); debugger_updateExecutionBreakpoint(address); } -void debugger_createSingleShotExecuteBreakpoint(uint32 address) +void debugger_createExecuteBreakpoint(uint32 address) { - // check if breakpoint already exists - auto existingBP = debugger_getFirstBP(address); - if (existingBP && debuggerBPChain_hasType(existingBP, DEBUGGER_BP_T_ONE_SHOT)) - return; // breakpoint already exists - // get original opcode at address - uint32 originalOpcode = debugger_getAddressOriginalOpcode(address); - // init breakpoint object - DebuggerBreakpoint* bp = new DebuggerBreakpoint(address, originalOpcode, DEBUGGER_BP_T_ONE_SHOT, true); - debuggerBPChain_add(address, bp); - debugger_updateExecutionBreakpoint(address); + debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL); } namespace coreinit @@ -218,7 +210,7 @@ void debugger_handleSingleStepException(uint64 dr6) } if (catchBP) { - debugger_createSingleShotExecuteBreakpoint(ppcInterpreterCurrentInstance->instructionPointer + 4); + debugger_createCodeBreakpoint(ppcInterpreterCurrentInstance->instructionPointer + 4, DEBUGGER_BP_T_ONE_SHOT); } } @@ -250,7 +242,7 @@ void debugger_handleEntryBreakpoint(uint32 address) if (!debuggerState.breakOnEntry) return; - debugger_createExecuteBreakpoint(address); + debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL); } void debugger_deleteBreakpoint(DebuggerBreakpoint* bp) @@ -298,10 +290,12 @@ void debugger_toggleExecuteBreakpoint(uint32 address) { // delete existing breakpoint debugger_deleteBreakpoint(existingBP); - return; } - // create new - debugger_createExecuteBreakpoint(address); + else + { + // create new breakpoint + debugger_createExecuteBreakpoint(address); + } } void debugger_forceBreak() @@ -327,7 +321,7 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b { if (bpItr == bp) { - if (bpItr->bpType == DEBUGGER_BP_T_NORMAL) + if (bpItr->bpType == DEBUGGER_BP_T_NORMAL || bpItr->bpType == DEBUGGER_BP_T_LOGGING) { bp->enabled = state; debugger_updateExecutionBreakpoint(address); @@ -486,7 +480,7 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU) return false; } // create one-shot breakpoint at next instruction - debugger_createSingleShotExecuteBreakpoint(initialIP +4); + debugger_createCodeBreakpoint(initialIP + 4, DEBUGGER_BP_T_ONE_SHOT); // step over current instruction (to avoid breakpoint) debugger_stepInto(hCPU); debuggerWindow_moveIP(); @@ -506,8 +500,39 @@ void debugger_createPPCStateSnapshot(PPCInterpreter_t* hCPU) debuggerState.debugSession.ppcSnapshot.cr[i] = hCPU->cr[i]; } +void DebugLogStackTrace(OSThread_t* thread, MPTR sp); + void debugger_enterTW(PPCInterpreter_t* hCPU) { + // handle logging points + DebuggerBreakpoint* bp = debugger_getFirstBP(hCPU->instructionPointer); + bool shouldBreak = debuggerBPChain_hasType(bp, DEBUGGER_BP_T_NORMAL) || debuggerBPChain_hasType(bp, DEBUGGER_BP_T_ONE_SHOT); + while (bp) + { + if (bp->bpType == DEBUGGER_BP_T_LOGGING && bp->enabled) + { + std::wstring logName = !bp->comment.empty() ? L"Breakpoint '"+bp->comment+L"'" : fmt::format(L"Breakpoint at 0x{:08X} (no comment)", bp->address); + std::wstring logContext = fmt::format(L"Thread: {:08x} LR: 0x{:08x}", coreinitThread_getCurrentThreadMPTRDepr(hCPU), hCPU->spr.LR, cemuLog_advancedPPCLoggingEnabled() ? L" Stack Trace:" : L""); + cemuLog_log(LogType::Force, L"[Debugger] {} was executed! {}", logName, logContext); + if (cemuLog_advancedPPCLoggingEnabled()) + DebugLogStackTrace(coreinitThread_getCurrentThreadDepr(hCPU), hCPU->gpr[1]); + break; + } + bp = bp->next; + } + + // return early if it's only a non-pausing logging breakpoint to prevent a modified debugger state and GUI updates + if (!shouldBreak) + { + uint32 backupIP = debuggerState.debugSession.instructionPointer; + debuggerState.debugSession.instructionPointer = hCPU->instructionPointer; + debugger_stepInto(hCPU, false); + PPCInterpreterSlim_executeInstruction(hCPU); + debuggerState.debugSession.instructionPointer = backupIP; + return; + } + + // handle breakpoints debuggerState.debugSession.isTrapped = true; debuggerState.debugSession.debuggedThreadMPTR = coreinitThread_getCurrentThreadMPTRDepr(hCPU); debuggerState.debugSession.instructionPointer = hCPU->instructionPointer; @@ -579,6 +604,20 @@ void debugger_shouldBreak(PPCInterpreter_t* hCPU) void debugger_addParserSymbols(class ExpressionParser& ep) { + const auto module_count = RPLLoader_GetModuleCount(); + const auto module_list = RPLLoader_GetModuleList(); + + std::vector module_tmp(module_count); + for (int i = 0; i < module_count; i++) + { + const auto module = module_list[i]; + if (module) + { + module_tmp[i] = (double)module->regionMappingBase_text.GetMPTR(); + ep.AddConstant(module->moduleName2, module_tmp[i]); + } + } + for (sint32 i = 0; i < 32; i++) ep.AddConstant(fmt::format("r{}", i), debuggerState.debugSession.ppcSnapshot.gpr[i]); } \ No newline at end of file diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.h b/src/Cafe/HW/Espresso/Debugger/Debugger.h index 08cbd90a..717df28a 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.h +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.h @@ -7,6 +7,7 @@ #define DEBUGGER_BP_T_ONE_SHOT 1 // normal breakpoint, deletes itself after trigger (used for stepping) #define DEBUGGER_BP_T_MEMORY_READ 2 // memory breakpoint #define DEBUGGER_BP_T_MEMORY_WRITE 3 // memory breakpoint +#define DEBUGGER_BP_T_LOGGING 4 // logging breakpoint, prints the breakpoint comment and stack trace whenever hit #define DEBUGGER_BP_T_GDBSTUB 1 // breakpoint created by GDBStub #define DEBUGGER_BP_T_DEBUGGER 2 // breakpoint created by Cemu's debugger @@ -42,7 +43,7 @@ struct DebuggerBreakpoint bool isExecuteBP() const { - return bpType == DEBUGGER_BP_T_NORMAL || bpType == DEBUGGER_BP_T_ONE_SHOT; + return bpType == DEBUGGER_BP_T_NORMAL || bpType == DEBUGGER_BP_T_LOGGING || bpType == DEBUGGER_BP_T_ONE_SHOT; } bool isMemBP() const @@ -98,8 +99,9 @@ extern debuggerState_t debuggerState; // new API DebuggerBreakpoint* debugger_getFirstBP(uint32 address); -void debugger_toggleExecuteBreakpoint(uint32 address); // create/remove execute breakpoint +void debugger_createCodeBreakpoint(uint32 address, uint8 bpType); void debugger_createExecuteBreakpoint(uint32 address); +void debugger_toggleExecuteBreakpoint(uint32 address); // create/remove execute breakpoint void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* bp); void debugger_createMemoryBreakpoint(uint32 address, bool onRead, bool onWrite); diff --git a/src/gui/debugger/BreakpointWindow.cpp b/src/gui/debugger/BreakpointWindow.cpp index ecb77428..63b92626 100644 --- a/src/gui/debugger/BreakpointWindow.cpp +++ b/src/gui/debugger/BreakpointWindow.cpp @@ -11,9 +11,11 @@ enum { - MENU_ID_CREATE_MEM_BP_READ = 1, + MENU_ID_CREATE_CODE_BP_EXECUTION = 1, + MENU_ID_CREATE_CODE_BP_LOGGING, + MENU_ID_CREATE_MEM_BP_READ, MENU_ID_CREATE_MEM_BP_WRITE, - + MENU_ID_DELETE_BP, }; enum ItemColumns @@ -118,6 +120,8 @@ void BreakpointWindow::OnUpdateView() const char* typeName = "UKN"; if (bp->bpType == DEBUGGER_BP_T_NORMAL) typeName = "X"; + else if (bp->bpType == DEBUGGER_BP_T_LOGGING) + typeName = "LOG"; else if (bp->bpType == DEBUGGER_BP_T_ONE_SHOT) typeName = "XS"; else if (bp->bpType == DEBUGGER_BP_T_MEMORY_READ) @@ -211,31 +215,56 @@ void BreakpointWindow::OnLeftDClick(wxMouseEvent& event) void BreakpointWindow::OnRightDown(wxMouseEvent& event) { - wxMenu menu; + const auto position = event.GetPosition(); + const sint32 index = (position.y / m_breakpoints->GetCharHeight()) - 2; + if (index < 0 || index >= m_breakpoints->GetItemCount()) + { + wxMenu menu; + menu.Append(MENU_ID_CREATE_CODE_BP_EXECUTION, _("Create execution breakpoint")); + menu.Append(MENU_ID_CREATE_CODE_BP_LOGGING, _("Create logging breakpoint")); + menu.Append(MENU_ID_CREATE_MEM_BP_READ, _("Create memory breakpoint (read)")); + menu.Append(MENU_ID_CREATE_MEM_BP_WRITE, _("Create memory breakpoint (write)")); - menu.Append(MENU_ID_CREATE_MEM_BP_READ, _("Create memory breakpoint (read)")); - menu.Append(MENU_ID_CREATE_MEM_BP_WRITE, _("Create memory breakpoint (write)")); + menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(BreakpointWindow::OnContextMenuClick), nullptr, this); + PopupMenu(&menu); + } + else + { + m_breakpoints->SetItemState(index, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED); + m_breakpoints->SetItemState(index, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); - menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(BreakpointWindow::OnContextMenuClick), nullptr, this); - PopupMenu(&menu); + wxMenu menu; + menu.Append(MENU_ID_DELETE_BP, _("Delete breakpoint")); + + menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(BreakpointWindow::OnContextMenuClickSelected), nullptr, this); + PopupMenu(&menu); + } +} + +void BreakpointWindow::OnContextMenuClickSelected(wxCommandEvent& evt) +{ + if (evt.GetId() == MENU_ID_DELETE_BP) + { + long sel = m_breakpoints->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (sel != -1) + { + if (sel >= debuggerState.breakpoints.size()) + return; + + auto it = debuggerState.breakpoints.begin(); + std::advance(it, sel); + + debugger_deleteBreakpoint(*it); + + wxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE); + wxPostEvent(this->m_parent, evt); + } + } } void BreakpointWindow::OnContextMenuClick(wxCommandEvent& evt) { - switch (evt.GetId()) - { - case MENU_ID_CREATE_MEM_BP_READ: - MemoryBreakpointDialog(false); - return; - case MENU_ID_CREATE_MEM_BP_WRITE: - MemoryBreakpointDialog(true); - return; - } -} - -void BreakpointWindow::MemoryBreakpointDialog(bool isWrite) -{ - wxTextEntryDialog goto_dialog(this, _("Enter a memory address"), _("Memory breakpoint"), wxEmptyString); + wxTextEntryDialog goto_dialog(this, _("Enter a memory address"), _("Set breakpoint"), wxEmptyString); if (goto_dialog.ShowModal() == wxID_OK) { ExpressionParser parser; @@ -243,22 +272,34 @@ void BreakpointWindow::MemoryBreakpointDialog(bool isWrite) auto value = goto_dialog.GetValue().ToStdString(); std::transform(value.begin(), value.end(), value.begin(), tolower); - + uint32_t newBreakpointAddress = 0; try { debugger_addParserSymbols(parser); - const auto result = (uint32)parser.Evaluate(value); - debug_printf("goto eval result: %x\n", result); - - debugger_createMemoryBreakpoint(result, isWrite == false, isWrite == true); - this->OnUpdateView(); + newBreakpointAddress = parser.IsConstantExpression("0x"+value) ? (uint32)parser.Evaluate("0x"+value) : (uint32)parser.Evaluate(value); } - catch (const std::exception& e) + catch (const std::exception& ex) { - //ctx.errorHandler.printError(nullptr, -1, fmt::format("Unexpected error in expression \"{}\"", expressionString)); - //return EXPRESSION_RESOLVE_RESULT::EXPRESSION_ERROR; - wxMessageBox(e.what(), "Invalid expression"); + wxMessageBox(ex.what(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this); + return; } - + + switch (evt.GetId()) + { + case MENU_ID_CREATE_CODE_BP_EXECUTION: + debugger_createCodeBreakpoint(newBreakpointAddress, DEBUGGER_BP_T_NORMAL); + break; + case MENU_ID_CREATE_CODE_BP_LOGGING: + debugger_createCodeBreakpoint(newBreakpointAddress, DEBUGGER_BP_T_LOGGING); + break; + case MENU_ID_CREATE_MEM_BP_READ: + debugger_createMemoryBreakpoint(newBreakpointAddress, true, false); + break; + case MENU_ID_CREATE_MEM_BP_WRITE: + debugger_createMemoryBreakpoint(newBreakpointAddress, false, true); + break; + } + + this->OnUpdateView(); } -} \ No newline at end of file +} diff --git a/src/gui/debugger/BreakpointWindow.h b/src/gui/debugger/BreakpointWindow.h index 4851cb52..ac132950 100644 --- a/src/gui/debugger/BreakpointWindow.h +++ b/src/gui/debugger/BreakpointWindow.h @@ -19,8 +19,7 @@ private: void OnRightDown(wxMouseEvent& event); void OnContextMenuClick(wxCommandEvent& evt); - - void MemoryBreakpointDialog(bool isWrite); + void OnContextMenuClickSelected(wxCommandEvent& evt); wxCheckedListCtrl* m_breakpoints; }; \ No newline at end of file diff --git a/src/gui/debugger/DebuggerWindow2.cpp b/src/gui/debugger/DebuggerWindow2.cpp index f8c5c931..969e40bd 100644 --- a/src/gui/debugger/DebuggerWindow2.cpp +++ b/src/gui/debugger/DebuggerWindow2.cpp @@ -118,7 +118,7 @@ void DebuggerModuleStorage::Load(XMLConfigParser& parser) const auto comment = element.get("Comment", ""); // calculate absolute address - uint32 module_base_address = (type == DEBUGGER_BP_T_NORMAL ? this->rpl_module->regionMappingBase_text.GetMPTR() : this->rpl_module->regionMappingBase_data); + uint32 module_base_address = (type == DEBUGGER_BP_T_NORMAL || type == DEBUGGER_BP_T_LOGGING) ? this->rpl_module->regionMappingBase_text.GetMPTR() : this->rpl_module->regionMappingBase_data; uint32 address = module_base_address + relative_address; // don't change anything if there's already a breakpoint @@ -127,7 +127,9 @@ void DebuggerModuleStorage::Load(XMLConfigParser& parser) // register breakpoints in debugger if (type == DEBUGGER_BP_T_NORMAL) - debugger_createExecuteBreakpoint(address); + debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL); + else if (type == DEBUGGER_BP_T_LOGGING) + debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_LOGGING); else if (type == DEBUGGER_BP_T_MEMORY_READ) debugger_createMemoryBreakpoint(address, true, false); else if (type == DEBUGGER_BP_T_MEMORY_WRITE) @@ -173,7 +175,7 @@ void DebuggerModuleStorage::Save(XMLConfigParser& parser) // check whether the breakpoint is part of the current module being saved RPLModule* address_module; - if (bp->bpType == DEBUGGER_BP_T_NORMAL) address_module = RPLLoader_FindModuleByCodeAddr(bp->address); + if (bp->bpType == DEBUGGER_BP_T_NORMAL || bp->bpType == DEBUGGER_BP_T_LOGGING) address_module = RPLLoader_FindModuleByCodeAddr(bp->address); else if (bp->isMemBP()) address_module = RPLLoader_FindModuleByDataAddr(bp->address); else continue; @@ -259,7 +261,7 @@ void DebuggerWindow2::LoadModuleStorage(const RPLModule* module) bool already_loaded = std::any_of(m_modules_storage.begin(), m_modules_storage.end(), [path](const std::unique_ptr& debug) { return debug->GetFilename() == path; }); if (!path.empty() && !already_loaded) { - m_modules_storage.emplace_back(std::move(new XMLDebuggerModuleConfig(path, { module->moduleName2, module->patchCRC, module, false }))); + m_modules_storage.emplace_back(new XMLDebuggerModuleConfig(path, { module->moduleName2, module->patchCRC, module, false }))->Load(); } } @@ -522,6 +524,7 @@ void DebuggerWindow2::OnToolClicked(wxCommandEvent& event) void DebuggerWindow2::OnBreakpointChange(wxCommandEvent& event) { m_breakpoint_window->OnUpdateView(); + m_disasm_ctrl->RefreshControl(); UpdateModuleLabel(); } diff --git a/src/gui/debugger/DisasmCtrl.cpp b/src/gui/debugger/DisasmCtrl.cpp index dededf2c..21f6fc1d 100644 --- a/src/gui/debugger/DisasmCtrl.cpp +++ b/src/gui/debugger/DisasmCtrl.cpp @@ -147,7 +147,7 @@ void DisasmCtrl::DrawDisassemblyLine(wxDC& dc, const wxPoint& linePosition, MPTR else if (is_active_bp) background_colour = wxColour(0xFF80A0FF); else if (bp != nullptr) - background_colour = wxColour(0xFF8080FF); + background_colour = wxColour(bp->bpType == DEBUGGER_BP_T_NORMAL ? 0xFF8080FF : 0x80FFFFFF); else if(virtualAddress == m_lastGotoTarget) background_colour = wxColour(0xFFE0E0E0); else @@ -540,8 +540,6 @@ void DisasmCtrl::OnKeyPressed(sint32 key_code, const wxPoint& position) { debugger_toggleExecuteBreakpoint(*optVirtualAddress); - RefreshControl(); - wxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE); wxPostEvent(this->m_parent, evt); } @@ -767,40 +765,31 @@ void DisasmCtrl::GoToAddressDialog() auto value = goto_dialog.GetValue().ToStdString(); std::transform(value.begin(), value.end(), value.begin(), tolower); - const auto module_count = RPLLoader_GetModuleCount(); - const auto module_list = RPLLoader_GetModuleList(); + debugger_addParserSymbols(parser); - std::vector module_tmp(module_count); - for (int i = 0; i < module_count; i++) + // try to parse expression as hex value first (it should interpret 1234 as 0x1234, not 1234) + if (parser.IsConstantExpression("0x"+value)) { - const auto module = module_list[i]; - if (module) - { - module_tmp[i] = (double)module->regionMappingBase_text.GetMPTR(); - parser.AddConstant(module->moduleName2, module_tmp[i]); - } - } - - double grp_tmp[32]; - PPCSnapshot& ppc_snapshot = debuggerState.debugSession.ppcSnapshot; - for (int i = 0; i < 32; i++) - { - char var_name[32]; - sprintf(var_name, "r%d", i); - grp_tmp[i] = ppc_snapshot.gpr[i]; - parser.AddConstant(var_name, grp_tmp[i]); - } - - try - { - const auto result = (uint32)parser.Evaluate(value); - debug_printf("goto eval result: %x\n", result); + const auto result = (uint32)parser.Evaluate("0x"+value); m_lastGotoTarget = result; CenterOffset(result); - debuggerWindow_updateViewThreadsafe2(); } - catch (const std::exception& ) + else if (parser.IsConstantExpression(value)) { + const auto result = (uint32)parser.Evaluate(value); + m_lastGotoTarget = result; + CenterOffset(result); + } + else + { + try + { + const auto _ = (uint32)parser.Evaluate(value); + } + catch (const std::exception& ex) + { + wxMessageBox(ex.what(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this); + } } } } \ No newline at end of file diff --git a/src/gui/debugger/DumpCtrl.cpp b/src/gui/debugger/DumpCtrl.cpp index cc1d5fee..16fdd87d 100644 --- a/src/gui/debugger/DumpCtrl.cpp +++ b/src/gui/debugger/DumpCtrl.cpp @@ -214,46 +214,36 @@ void DumpCtrl::GoToAddressDialog() wxTextEntryDialog goto_dialog(this, _("Enter a target address."), _("GoTo address"), wxEmptyString); if (goto_dialog.ShowModal() == wxID_OK) { - try + ExpressionParser parser; + + auto value = goto_dialog.GetValue().ToStdString(); + std::transform(value.begin(), value.end(), value.begin(), tolower); + + debugger_addParserSymbols(parser); + + // try to parse expression as hex value first (it should interpret 1234 as 0x1234, not 1234) + if (parser.IsConstantExpression("0x"+value)) { - ExpressionParser parser; - - auto value = goto_dialog.GetValue().ToStdString(); - std::transform(value.begin(), value.end(), value.begin(), tolower); - //parser.SetExpr(value); - - const auto module_count = RPLLoader_GetModuleCount(); - const auto module_list = RPLLoader_GetModuleList(); - - std::vector module_tmp(module_count); - for (int i = 0; i < module_count; i++) - { - const auto module = module_list[i]; - if (module) - { - module_tmp[i] = (double)module->regionMappingBase_text.GetMPTR(); - parser.AddConstant(module->moduleName2, module_tmp[i]); - } - } - - double grp_tmp[32]; - PPCSnapshot& ppc_snapshot = debuggerState.debugSession.ppcSnapshot; - for (int i = 0; i < 32; i++) - { - char var_name[32]; - sprintf(var_name, "r%d", i); - grp_tmp[i] = ppc_snapshot.gpr[i]; - parser.AddConstant(var_name, grp_tmp[i]); - } - - const auto result = (uint32)parser.Evaluate(value); - debug_printf("goto eval result: %x\n", result); + const auto result = (uint32)parser.Evaluate("0x"+value); m_lastGotoOffset = result; CenterOffset(result); } - catch (const std::exception& ex) + else if (parser.IsConstantExpression(value)) { - wxMessageBox(ex.what(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this); + const auto result = (uint32)parser.Evaluate(value); + m_lastGotoOffset = result; + CenterOffset(result); + } + else + { + try + { + const auto _ = (uint32)parser.Evaluate(value); + } + catch (const std::exception& ex) + { + wxMessageBox(ex.what(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this); + } } } } diff --git a/src/gui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp b/src/gui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp index 1cbe1f8e..b93cf94e 100644 --- a/src/gui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp +++ b/src/gui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp @@ -280,9 +280,7 @@ void DebugLogStackTrace(OSThread_t* thread, MPTR sp); void DebugPPCThreadsWindow::DumpStackTrace(OSThread_t* thread) { - cemuLog_log(LogType::Force, fmt::format("Dumping stack trace for thread {0:08x} LR: {1:08x}", - memory_getVirtualOffsetFromPointer(thread), - _swapEndianU32(thread->context.lr))); + cemuLog_log(LogType::Force, "Dumping stack trace for thread {0:08x} LR: {1:08x}", memory_getVirtualOffsetFromPointer(thread), _swapEndianU32(thread->context.lr)); DebugLogStackTrace(thread, _swapEndianU32(thread->context.gpr[1])); }