mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-21 10:19:04 +02:00
Remove function in the disassembly merged the function into the previous one, so its code showed up again under that name. Both now just remove it. The symbol list's selection color was translucent blue on the list box's blue background, so it gets the opaque one. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
249 lines
7.0 KiB
C++
249 lines
7.0 KiB
C++
#pragma once
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <set>
|
|
#include <algorithm>
|
|
|
|
#include "ext/imgui/imgui.h"
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/Math/geom2d.h"
|
|
|
|
#include "Core/Debugger/DisassemblyManager.h"
|
|
#include "Core/MIPS/MIPSDebugInterface.h"
|
|
|
|
struct ImConfig;
|
|
struct ImControl;
|
|
|
|
class MIPSState;
|
|
|
|
// Corresponds to CtrlDisAsmView
|
|
// TODO: Fold out common code.
|
|
class ImDisasmView {
|
|
public:
|
|
ImDisasmView();
|
|
|
|
// Public variables bounds to imgui checkboxes
|
|
bool followPC_ = true;
|
|
|
|
void Draw(ImDrawList *drawList, ImControl &control);
|
|
|
|
void PopupMenu(MIPSState *mips, ImControl &control);
|
|
void NotifyStep();
|
|
|
|
void ScrollRelative(int amount);
|
|
|
|
void onChar(int c);
|
|
void onMouseDown(float x, float y, int button);
|
|
void onMouseUp(float x, float y, int button);
|
|
void onMouseMove(float x, float y, int button);
|
|
void scrollAddressIntoView();
|
|
bool curAddressIsVisible();
|
|
void ScanVisibleFunctions();
|
|
void clearFunctions() { g_disassemblyManager.clear(); };
|
|
|
|
void getOpcodeText(u32 address, char *dest, int bufsize, bool insertSymbols);
|
|
u32 yToAddress(float y);
|
|
|
|
void setDebugger(MIPSDebugInterface *deb) {
|
|
if (debugger_ != deb) {
|
|
debugger_ = deb;
|
|
curAddress_ = debugger_->GetPC();
|
|
g_disassemblyManager.setCpu(deb);
|
|
}
|
|
}
|
|
|
|
MIPSDebugInterface *getDebugger() {
|
|
return debugger_;
|
|
}
|
|
|
|
void scrollStepping(u32 newPc);
|
|
|
|
void gotoAddr(unsigned int addr) {
|
|
if (positionLocked_ != 0)
|
|
return;
|
|
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart_, visibleRows_);
|
|
u32 newAddress = g_disassemblyManager.getStartAddress(addr);
|
|
|
|
if (newAddress < windowStart_ || newAddress >= windowEnd) {
|
|
windowStart_ = g_disassemblyManager.getNthPreviousAddress(newAddress, visibleRows_ / 2);
|
|
}
|
|
|
|
setCurAddress(newAddress);
|
|
ScanVisibleFunctions();
|
|
}
|
|
void GotoPC() {
|
|
gotoAddr(debugger_->GetPC());
|
|
}
|
|
void GotoRA() {
|
|
gotoAddr(debugger_->GetRA());
|
|
}
|
|
u32 getSelection() {
|
|
return curAddress_;
|
|
}
|
|
void setShowMode(bool s) {
|
|
showHex_ = s;
|
|
}
|
|
// Removes the function symbol and its name, leaving the code without a function (handy for
|
|
// testing stack walks without symbols).
|
|
void RemoveFunction(u32 funcStart);
|
|
void toggleBreakpoint(bool toggleEnabled = false);
|
|
void editBreakpoint(ImConfig &cfg);
|
|
|
|
void setCurAddress(u32 newAddress, bool extend = false) {
|
|
newAddress = g_disassemblyManager.getStartAddress(newAddress);
|
|
const u32 after = g_disassemblyManager.getNthNextAddress(newAddress, 1);
|
|
curAddress_ = newAddress;
|
|
selectRangeStart_ = extend ? std::min(selectRangeStart_, newAddress) : newAddress;
|
|
selectRangeEnd_ = extend ? std::max(selectRangeEnd_, after) : after;
|
|
updateStatusBarText();
|
|
}
|
|
|
|
void LockPosition() {
|
|
positionLocked_++;
|
|
}
|
|
void UnlockPosition() {
|
|
positionLocked_--;
|
|
_assert_(positionLocked_ >= 0);
|
|
}
|
|
void Search(std::string_view needle);
|
|
void SearchNext(bool forward);
|
|
|
|
// Check these every frame!
|
|
const std::string &StatusBarText() const {
|
|
return statusBarText_;
|
|
}
|
|
bool SymbolMapReloaded() {
|
|
bool retval = mapReloaded_;
|
|
mapReloaded_ = false;
|
|
return retval;
|
|
}
|
|
// The function start "Select in symbol list" was picked for, if it was since the last call.
|
|
bool TakeSymbolListRequest(u32 *funcStart) {
|
|
if (symbolListRequest_ == 0xFFFFFFFF) {
|
|
return false;
|
|
}
|
|
*funcStart = symbolListRequest_;
|
|
symbolListRequest_ = 0xFFFFFFFF;
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
enum class CopyInstructionsMode {
|
|
OPCODES,
|
|
DISASM,
|
|
ADDRESSES,
|
|
};
|
|
|
|
void ProcessKeyboardShortcuts(bool focused);
|
|
// Plants the one-shot "run to cursor" breakpoint and resumes. With nextFrame, hits are ignored
|
|
// until the next vblank, so the rest of the current frame is skipped over.
|
|
void RunToAddress(u32 address, bool nextFrame);
|
|
// Requests the assemble popup - the actual input happens in PopupMenu(), since ImGui popups
|
|
// can only be opened and drawn from inside the frame that owns them.
|
|
void assembleOpcode(u32 address, std::string_view defaultText, bool selectAll = false);
|
|
// Same, prefilled with the instruction that's already there, selected so typing replaces it.
|
|
void assembleCurrentOpcode(u32 address);
|
|
// Applies what was typed into that popup. Returns false and fills in assembleError_ if it
|
|
// couldn't be assembled, so the popup can stay open and show why.
|
|
bool applyAssembly(u32 address, std::string_view op);
|
|
std::string disassembleRange(u32 start, u32 size);
|
|
void disassembleToFile();
|
|
void FollowBranch();
|
|
void calculatePixelPositions();
|
|
bool getDisasmAddressText(u32 address, char *dest, size_t bufSize, bool abbreviateLabels, bool showData);
|
|
void updateStatusBarText();
|
|
void drawBranchLine(ImDrawList *list, Bounds rc, std::map<u32, float> &addressPositions, const BranchLine &line);
|
|
void CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructionsMode mode);
|
|
std::set<std::string> getSelectedLineArguments();
|
|
void drawArguments(ImDrawList *list, Bounds rc, const DisassemblyLineInfo &line, float x, float y, ImColor textColor, const std::set<std::string> ¤tArguments);
|
|
|
|
u32 curAddress_ = 0;
|
|
u32 selectRangeStart_ = 0;
|
|
u32 selectRangeEnd_ = 0;
|
|
float rowHeight_ = 0.f;
|
|
float charWidth_ = 0.f;
|
|
|
|
bool bpPopup_ = false;
|
|
bool hasFocus_ = true;
|
|
bool showHex_ = false;
|
|
|
|
MIPSDebugInterface *debugger_ = nullptr;
|
|
|
|
u32 windowStart_ = 0;
|
|
int visibleRows_ = 1;
|
|
bool displaySymbols_ = true;
|
|
|
|
struct {
|
|
int addressStart;
|
|
int opcodeStart;
|
|
int argumentsStart;
|
|
int arrowsStart;
|
|
} pixelPositions_{};
|
|
|
|
std::vector<u32> jumpStack_;
|
|
|
|
std::string searchQuery_;
|
|
int matchAddress_;
|
|
bool searching_ = false;
|
|
bool keyTaken = false;
|
|
bool mapReloaded_ = false;
|
|
u32 symbolListRequest_ = 0xFFFFFFFF;
|
|
|
|
int positionLocked_ = 0;
|
|
|
|
std::string statusBarText_;
|
|
u32 funcBegin_ = 0;
|
|
char funcNameTemp_[128]{};
|
|
|
|
bool assemblePopup_ = false;
|
|
u32 assembleAddress_ = 0;
|
|
char assembleTemp_[256]{};
|
|
bool assembleSelectAll_ = false;
|
|
std::string assembleError_;
|
|
};
|
|
|
|
// Corresponds to the CDisasm dialog
|
|
class ImDisasmWindow {
|
|
public:
|
|
void Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImControl &control, CoreState coreState);
|
|
ImDisasmView &View() {
|
|
return disasmView_;
|
|
}
|
|
void NotifyStep() {
|
|
disasmView_.NotifyStep();
|
|
}
|
|
const char *Title() const {
|
|
return "CPU Debugger";
|
|
}
|
|
|
|
private:
|
|
// We just keep the state directly in the window. Can refactor later.
|
|
|
|
enum {
|
|
INVALID_ADDR = 0xFFFFFFFF,
|
|
};
|
|
|
|
u32 gotoAddr_ = 0x08800000;
|
|
|
|
// Symbol cache. Rebuilt whenever the symbol map's version no longer matches the one the
|
|
// cache was built from - that covers the map being replaced wholesale when a game boots or
|
|
// exits, not just edits made from here.
|
|
std::vector<SymbolEntry> symCache_;
|
|
uint32_t symCacheVersion_ = 0;
|
|
int selectedSymbol_ = -1;
|
|
char selectedSymbolName_[128];
|
|
|
|
// Filter over symCache_. Held as indices into it rather than a filtered copy, so
|
|
// selectedSymbol_ keeps meaning the same thing whether or not a filter is active.
|
|
char symFilter_[64]{};
|
|
std::vector<int> symMatches_;
|
|
bool symMatchesDirty_ = true;
|
|
// Set when the selection was moved from outside the list, so it scrolls there.
|
|
bool scrollToSelectedSymbol_ = false;
|
|
|
|
ImDisasmView disasmView_;
|
|
char searchTerm_[64]{};
|
|
};
|