mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-05-29 00:21:34 +08:00
ImDebugger: Add initial implementation of a watch window
This commit is contained in:
@@ -1002,6 +1002,7 @@
|
||||
<ClInclude Include="AVIDump.h" />
|
||||
<ClInclude Include="ConfigValues.h" />
|
||||
<ClInclude Include="Debugger\MemBlockInfo.h" />
|
||||
<ClInclude Include="Debugger\Watch.h" />
|
||||
<ClInclude Include="Debugger\WebSocket.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\BreakpointSubscriber.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\ClientConfigSubscriber.h" />
|
||||
|
||||
@@ -2241,6 +2241,9 @@
|
||||
<ClInclude Include="..\ext\loongarch-disasm.h">
|
||||
<Filter>Ext</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\Watch.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE.TXT" />
|
||||
@@ -2269,4 +2272,4 @@
|
||||
<Filter>Ext</Filter>
|
||||
</Text>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
32
Core/Debugger/Watch.h
Normal file
32
Core/Debugger/Watch.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "Common/Math/expression_parser.h"
|
||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||
|
||||
enum class WatchFormat {
|
||||
HEX,
|
||||
INT,
|
||||
FLOAT,
|
||||
STR,
|
||||
};
|
||||
|
||||
struct WatchInfo {
|
||||
WatchInfo() = default;
|
||||
WatchInfo(const std::string &name, const std::string &expr, MIPSDebugInterface *debug, WatchFormat format = WatchFormat::HEX)
|
||||
: name(name), originalExpression(expr), format(format) {
|
||||
initExpression(debug, expr.c_str(), expression);
|
||||
}
|
||||
void SetExpression(const std::string &expr, MIPSDebugInterface *debug) {
|
||||
originalExpression = expr;
|
||||
initExpression(debug, expr.c_str(), expression);
|
||||
}
|
||||
std::string name;
|
||||
std::string originalExpression;
|
||||
PostfixExpression expression;
|
||||
WatchFormat format = WatchFormat::HEX;
|
||||
uint32_t currentValue = 0;
|
||||
uint32_t lastValue = 0;
|
||||
int steppingCounter = -1;
|
||||
bool evaluateFailed = false;
|
||||
};
|
||||
@@ -1817,6 +1817,87 @@ static void DrawSymbols(const MIPSDebugInterface *debug, ImConfig &cfg, ImContro
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
ImWatchWindow::ImWatchWindow() {}
|
||||
|
||||
void ImWatchWindow::Draw(ImConfig &cfg, ImControl &control, MIPSDebugInterface *mipsDebug) {
|
||||
if (!ImGui::Begin("Watch", &cfg.atracToolOpen) || !g_symbolMap) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
// Refresh watches
|
||||
int steppingCounter = Core_GetSteppingCounter();
|
||||
int changes = false;
|
||||
for (auto &watch : watches_) {
|
||||
if (watch.steppingCounter != steppingCounter) {
|
||||
watch.lastValue = watch.currentValue;
|
||||
watch.steppingCounter = steppingCounter;
|
||||
}
|
||||
|
||||
uint32_t prevValue = watch.currentValue;
|
||||
watch.evaluateFailed = !parseExpression(mipsDebug, watch.expression, watch.currentValue);
|
||||
}
|
||||
|
||||
if (ImGui::Button("Add Watch")) {
|
||||
watches_.push_back(WatchInfo("untitled", "[0x88000000]", mipsDebug));
|
||||
}
|
||||
|
||||
if (ImGui::BeginTable("watches", 4, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH)) {
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("Expression", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed);
|
||||
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (int i = 0; i < (int)watches_.size(); i++) {
|
||||
auto &watch = watches_[i];
|
||||
ImGui::PushID(i);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(watch.name.c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(watch.originalExpression.c_str());
|
||||
ImGui::TableNextColumn();
|
||||
if (watch.evaluateFailed) {
|
||||
ImGui::TextUnformatted("(Error)");
|
||||
} else {
|
||||
const uint32_t value = watch.currentValue;
|
||||
float valuef = 0.0f;
|
||||
switch (watch.format) {
|
||||
case WatchFormat::HEX:
|
||||
ImGui::Text("%08x", value);
|
||||
break;
|
||||
case WatchFormat::INT:
|
||||
ImGui::Text("%d", value);
|
||||
break;
|
||||
case WatchFormat::FLOAT:
|
||||
memcpy(&valuef, &value, sizeof(valuef));
|
||||
ImGui::Text("%f", value);
|
||||
break;
|
||||
case WatchFormat::STR:
|
||||
if (Memory::IsValidAddress(value)) {
|
||||
uint32_t len = Memory::ValidSize(value, 255);
|
||||
ImGui::Text("%.*s", len, Memory::GetCharPointer(value));
|
||||
} else {
|
||||
ImGui::Text("%08x", value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::SmallButton("X")) {
|
||||
watches_.erase(watches_.begin() + i);
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ImAtracToolWindow::Load() {
|
||||
if (File::ReadBinaryFileToString(Path(atracPath_), &data_)) {
|
||||
track_.reset(new Track());
|
||||
@@ -2052,6 +2133,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
|
||||
ImGui::MenuItem("VFPU regs", nullptr, &cfg_.vfpuOpen);
|
||||
ImGui::MenuItem("Callstacks", nullptr, &cfg_.callstackOpen);
|
||||
ImGui::MenuItem("Breakpoints", nullptr, &cfg_.breakpointsOpen);
|
||||
ImGui::MenuItem("Watch", nullptr, &cfg_.watchOpen);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Symbols")) {
|
||||
@@ -2305,6 +2387,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
|
||||
memDumpWindow_.Draw(cfg_, mipsDebug);
|
||||
}
|
||||
|
||||
if (cfg_.watchOpen) {
|
||||
watchWindow_.Draw(cfg_, control, mipsDebug);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (cfg_.memViewOpen[i]) {
|
||||
mem_[i].Draw(mipsDebug, cfg_, control, i);
|
||||
@@ -2475,6 +2561,8 @@ void ImConfig::SyncConfig(IniFile *ini, bool save) {
|
||||
sync.Sync("logConfigOpen", &logConfigOpen, false);
|
||||
sync.Sync("luaConsoleOpen", &luaConsoleOpen, false);
|
||||
sync.Sync("utilityModulesOpen", &utilityModulesOpen, false);
|
||||
sync.Sync("memDumpOpen", &memDumpOpen, false);
|
||||
sync.Sync("watchOpen", &watchOpen, false);
|
||||
sync.Sync("atracToolOpen", &atracToolOpen, false);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char name[64];
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "Core/Debugger/DisassemblyManager.h"
|
||||
#include "Core/Debugger/DebugInterface.h"
|
||||
#include "Core/Debugger/Watch.h"
|
||||
|
||||
#include "UI/ImDebugger/ImDisasmView.h"
|
||||
#include "UI/ImDebugger/ImMemView.h"
|
||||
@@ -133,6 +134,17 @@ public:
|
||||
std::unique_ptr<Track> track_;
|
||||
std::string error_;
|
||||
std::string data_;
|
||||
|
||||
int editingWatchIndex_ = -1;
|
||||
int editingColumn_ = 0;
|
||||
};
|
||||
|
||||
class ImWatchWindow {
|
||||
public:
|
||||
ImWatchWindow();
|
||||
void Draw(ImConfig &cfg, ImControl &control, MIPSDebugInterface *mipsDebug);
|
||||
private:
|
||||
std::vector<WatchInfo> watches_;
|
||||
};
|
||||
|
||||
enum class ImCmd {
|
||||
@@ -186,6 +198,7 @@ private:
|
||||
ImStructViewer structViewer_;
|
||||
ImGePixelViewerWindow pixelViewer_;
|
||||
ImMemDumpWindow memDumpWindow_;
|
||||
ImWatchWindow watchWindow_;
|
||||
ImAtracToolWindow atracToolWindow_;
|
||||
ImConsole luaConsole_;
|
||||
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Core/Debugger/DebugInterface.h"
|
||||
#include "../../Core/HLE/sceKernelThread.h"
|
||||
#include "../../Core/Debugger/Breakpoints.h"
|
||||
#include "../../Core/Debugger/SymbolMap.h"
|
||||
#include "../../Core/MIPS/MIPSStackWalk.h"
|
||||
#include "Core/Debugger/DebugInterface.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/Debugger/Breakpoints.h"
|
||||
#include "Core/Debugger/SymbolMap.h"
|
||||
#include "Core/Debugger/Watch.h"
|
||||
#include "Core/MIPS/MIPSStackWalk.h"
|
||||
#include "Windows/W32Util/Misc.h"
|
||||
|
||||
enum class WatchFormat {
|
||||
HEX,
|
||||
INT,
|
||||
FLOAT,
|
||||
STR,
|
||||
};
|
||||
|
||||
class CtrlThreadList: public GenericListControl
|
||||
{
|
||||
public:
|
||||
@@ -111,16 +105,6 @@ private:
|
||||
void DeleteWatch(int pos);
|
||||
bool HasWatchChanged(int pos);
|
||||
|
||||
struct WatchInfo {
|
||||
std::string name;
|
||||
std::string originalExpression;
|
||||
PostfixExpression expression;
|
||||
WatchFormat format = WatchFormat::HEX;
|
||||
uint32_t currentValue = 0;
|
||||
uint32_t lastValue = 0;
|
||||
int steppingCounter = -1;
|
||||
bool evaluateFailed = false;
|
||||
};
|
||||
std::vector<WatchInfo> watches_;
|
||||
DebugInterface *cpu_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user