mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
GE Debugger: Allow expressions for goto address.
This commit is contained in:
parent
542e7aa555
commit
f595299fe5
4 changed files with 251 additions and 10 deletions
|
@ -580,8 +580,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool parseExpression(char* exp, IExpressionFunctions* funcs, uint32_t& dest)
|
||||
{
|
||||
bool parseExpression(const char *exp, IExpressionFunctions *funcs, uint32_t &dest) {
|
||||
PostfixExpression postfix;
|
||||
if (initPostfixExpression(exp,funcs,postfix) == false) return false;
|
||||
return parsePostfixExpression(postfix,funcs,dest);
|
||||
|
|
|
@ -15,7 +15,234 @@
|
|||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "GPUDebugInterface.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Common/Math/expression_parser.h"
|
||||
#include "Core/Debugger/SymbolMap.h"
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
#include "GPU/Debugger/GECommandTable.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
enum class GEReferenceIndex : uint32_t {
|
||||
VADDR = 0x100,
|
||||
IADDR,
|
||||
OFFSET,
|
||||
PC,
|
||||
STALL,
|
||||
BFLAG,
|
||||
|
||||
BONE_MATRIX = 0x200,
|
||||
WORLD_MATRIX = 0x260,
|
||||
VIEW_MATRIX = 0x26C,
|
||||
PROJ_MATRIX = 0x278,
|
||||
TGEN_MATRIX = 0x288,
|
||||
MATRIX_END = 0x294,
|
||||
};
|
||||
ENUM_CLASS_BITOPS(GEReferenceIndex);
|
||||
|
||||
struct ReferenceName {
|
||||
GEReferenceIndex index;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static constexpr ReferenceName referenceNames[] = {
|
||||
{ GEReferenceIndex::VADDR, "vaddr" },
|
||||
{ GEReferenceIndex::IADDR, "iaddr" },
|
||||
{ GEReferenceIndex::OFFSET, "offset" },
|
||||
{ GEReferenceIndex::PC, "pc" },
|
||||
{ GEReferenceIndex::STALL, "stall" },
|
||||
{ GEReferenceIndex::BFLAG, "bflag" },
|
||||
{ GEReferenceIndex::BFLAG, "boundflag" },
|
||||
};
|
||||
|
||||
class GEExpressionFunctions : public IExpressionFunctions {
|
||||
public:
|
||||
GEExpressionFunctions(GPUDebugInterface *gpu) : gpu_(gpu) {}
|
||||
|
||||
bool parseReference(char *str, uint32_t &referenceIndex) override;
|
||||
bool parseSymbol(char *str, uint32_t &symbolValue) override;
|
||||
uint32_t getReferenceValue(uint32_t referenceIndex) override;
|
||||
ExpressionType getReferenceType(uint32_t referenceIndex) override;
|
||||
bool getMemoryValue(uint32_t address, int size, uint32_t &dest, char *error) override;
|
||||
|
||||
private:
|
||||
GPUDebugInterface *gpu_;
|
||||
};
|
||||
|
||||
bool GEExpressionFunctions::parseReference(char *str, uint32_t &referenceIndex) {
|
||||
// TODO: Support formats and a form of fields (i.e. vtype.throughmode.)
|
||||
// For now, let's just support the register bits directly.
|
||||
GECmdInfo info;
|
||||
if (GECmdInfoByName(str, info)) {
|
||||
referenceIndex = info.reg;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Also allow non-register references.
|
||||
for (const auto &entry : referenceNames) {
|
||||
if (strcasecmp(str, entry.name) == 0) {
|
||||
referenceIndex = (uint32_t)entry.index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// And matrix data. Maybe should allow column/row specification.
|
||||
int subindex = -1;
|
||||
int len = -1;
|
||||
|
||||
if (sscanf(str, "bone%i%n", &subindex, &len) == 1) {
|
||||
if (len == strlen(str) && subindex < 96) {
|
||||
referenceIndex = (uint32_t)GEReferenceIndex::BONE_MATRIX + subindex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (sscanf(str, "world%i%n", &subindex, &len) == 1) {
|
||||
if (len == strlen(str) && subindex < 12) {
|
||||
referenceIndex = (uint32_t)GEReferenceIndex::WORLD_MATRIX + subindex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (sscanf(str, "view%i%n", &subindex, &len) == 1) {
|
||||
if (len == strlen(str) && subindex < 12) {
|
||||
referenceIndex = (uint32_t)GEReferenceIndex::VIEW_MATRIX + subindex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (sscanf(str, "proj%i%n", &subindex, &len) == 1) {
|
||||
if (len == strlen(str) && subindex < 16) {
|
||||
referenceIndex = (uint32_t)GEReferenceIndex::PROJ_MATRIX + subindex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (sscanf(str, "tgen%i%n", &subindex, &len) == 1 || sscanf(str, "texgen%i%n", &subindex, &len) == 1) {
|
||||
if (len == strlen(str) && subindex < 12) {
|
||||
referenceIndex = (uint32_t)GEReferenceIndex::TGEN_MATRIX + subindex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GEExpressionFunctions::parseSymbol(char *str, uint32_t &symbolValue) {
|
||||
// Mainly useful for checking memory addresses.
|
||||
return g_symbolMap->GetLabelValue(str, symbolValue);
|
||||
}
|
||||
|
||||
uint32_t GEExpressionFunctions::getReferenceValue(uint32_t referenceIndex) {
|
||||
if (referenceIndex < 0x100) {
|
||||
uint32_t value = gpu_->GetGState().cmdmem[referenceIndex];
|
||||
// TODO: Later, support float values and similar.
|
||||
return value & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
// We return the matrix value as float bits, which gets interpreted correctly in the parser.
|
||||
if (referenceIndex >= (uint32_t)GEReferenceIndex::BONE_MATRIX && referenceIndex < (uint32_t)GEReferenceIndex::MATRIX_END) {
|
||||
GPUgstate state = gpu_->GetGState();
|
||||
float value;
|
||||
if (referenceIndex >= (uint32_t)GEReferenceIndex::TGEN_MATRIX) {
|
||||
value = state.tgenMatrix[referenceIndex - (uint32_t)GEReferenceIndex::TGEN_MATRIX];
|
||||
} else if (referenceIndex >= (uint32_t)GEReferenceIndex::PROJ_MATRIX) {
|
||||
value = state.projMatrix[referenceIndex - (uint32_t)GEReferenceIndex::PROJ_MATRIX];
|
||||
} else if (referenceIndex >= (uint32_t)GEReferenceIndex::VIEW_MATRIX) {
|
||||
value = state.viewMatrix[referenceIndex - (uint32_t)GEReferenceIndex::VIEW_MATRIX];
|
||||
} else if (referenceIndex >= (uint32_t)GEReferenceIndex::WORLD_MATRIX) {
|
||||
value = state.worldMatrix[referenceIndex - (uint32_t)GEReferenceIndex::WORLD_MATRIX];
|
||||
} else {
|
||||
value = state.boneMatrix[referenceIndex - (uint32_t)GEReferenceIndex::BONE_MATRIX];
|
||||
}
|
||||
|
||||
uint32_t result;
|
||||
memcpy(&result, &value, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
GEReferenceIndex ref = (GEReferenceIndex)referenceIndex;
|
||||
DisplayList list;
|
||||
switch (ref) {
|
||||
case GEReferenceIndex::VADDR:
|
||||
return gpu_->GetVertexAddress();
|
||||
case GEReferenceIndex::IADDR:
|
||||
return gpu_->GetIndexAddress();
|
||||
case GEReferenceIndex::OFFSET:
|
||||
// TODO: Should use an interface method, probably.
|
||||
return gstate_c.offsetAddr;
|
||||
case GEReferenceIndex::PC:
|
||||
if (gpu_->GetCurrentDisplayList(list)) {
|
||||
return list.pc;
|
||||
}
|
||||
return 0;
|
||||
case GEReferenceIndex::STALL:
|
||||
if (gpu_->GetCurrentDisplayList(list)) {
|
||||
return list.stall;
|
||||
}
|
||||
return 0;
|
||||
case GEReferenceIndex::BFLAG:
|
||||
if (gpu_->GetCurrentDisplayList(list)) {
|
||||
return list.bboxResult ? 1 : 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case GEReferenceIndex::BONE_MATRIX:
|
||||
case GEReferenceIndex::WORLD_MATRIX:
|
||||
case GEReferenceIndex::VIEW_MATRIX:
|
||||
case GEReferenceIndex::PROJ_MATRIX:
|
||||
case GEReferenceIndex::TGEN_MATRIX:
|
||||
case GEReferenceIndex::MATRIX_END:
|
||||
// Shouldn't have gotten here.
|
||||
break;
|
||||
}
|
||||
|
||||
_assert_msg_(false, "Invalid reference index");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExpressionType GEExpressionFunctions::getReferenceType(uint32_t referenceIndex) {
|
||||
if (referenceIndex < 0x100) {
|
||||
// TODO: Later, support float values and similar.
|
||||
return EXPR_TYPE_UINT;
|
||||
}
|
||||
|
||||
if (referenceIndex >= (uint32_t)GEReferenceIndex::BONE_MATRIX && referenceIndex < (uint32_t)GEReferenceIndex::MATRIX_END)
|
||||
return EXPR_TYPE_FLOAT;
|
||||
return EXPR_TYPE_UINT;
|
||||
}
|
||||
|
||||
bool GEExpressionFunctions::getMemoryValue(uint32_t address, int size, uint32_t &dest, char *error) {
|
||||
if (!Memory::IsValidRange(address, size)) {
|
||||
sprintf(error, "Invalid address or size %08x + %d", address, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
dest = Memory::Read_U8(address);
|
||||
return true;
|
||||
case 2:
|
||||
dest = Memory::Read_U16(address);
|
||||
return true;
|
||||
case 4:
|
||||
dest = Memory::Read_U32(address);
|
||||
return true;
|
||||
}
|
||||
|
||||
sprintf(error, "Unexpected memory access size %d", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GPUDebugInitExpression(GPUDebugInterface *g, const char *str, PostfixExpression &exp) {
|
||||
GEExpressionFunctions funcs(g);
|
||||
return initPostfixExpression(str, &funcs, exp);
|
||||
}
|
||||
|
||||
bool GPUDebugExecExpression(GPUDebugInterface *g, PostfixExpression &exp, uint32_t &result) {
|
||||
GEExpressionFunctions funcs(g);
|
||||
return parsePostfixExpression(exp, &funcs, result);
|
||||
}
|
||||
|
||||
bool GPUDebugExecExpression(GPUDebugInterface *g, const char *str, uint32_t &result) {
|
||||
GEExpressionFunctions funcs(g);
|
||||
return parseExpression(str, &funcs, result);
|
||||
}
|
||||
|
||||
void GPUDebugBuffer::Allocate(u32 stride, u32 height, GEBufferFormat fmt, bool flipped, bool reversed) {
|
||||
GPUDebugBufferFormat actualFmt = GPUDebugBufferFormat(fmt);
|
||||
|
|
|
@ -20,9 +20,10 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "Common/Math/expression_parser.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "GPU/GPU.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "Core/MemMap.h"
|
||||
|
||||
struct GPUDebugOp {
|
||||
u32 pc;
|
||||
|
@ -251,3 +252,7 @@ public:
|
|||
// get content of specific framebuffer / texture?
|
||||
// vertex / texture decoding?
|
||||
};
|
||||
|
||||
bool GPUDebugInitExpression(GPUDebugInterface *g, const char *str, PostfixExpression &exp);
|
||||
bool GPUDebugExecExpression(GPUDebugInterface *g, PostfixExpression &exp, uint32_t &result);
|
||||
bool GPUDebugExecExpression(GPUDebugInterface *g, const char *str, uint32_t &result);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include <algorithm>
|
||||
#include <tchar.h>
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/System/Display.h"
|
||||
#include "Windows/GEDebugger/CtrlDisplayListView.h"
|
||||
#include "Windows/GEDebugger/GEDebugger.h"
|
||||
|
@ -369,15 +371,23 @@ void CtrlDisplayListView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
|
|||
break;
|
||||
case ID_GEDBG_GOTOADDR:
|
||||
{
|
||||
u32 newAddress = curAddress;
|
||||
if (!InputBox_GetHex(GetModuleHandle(NULL), wnd, L"Address", curAddress, newAddress)) {
|
||||
std::string expression = StringFromFormat("%08x", curAddress);
|
||||
if (!InputBox_GetString(GetModuleHandle(NULL), wnd, L"Address", expression, expression, true)) {
|
||||
break;
|
||||
}
|
||||
if (Memory::IsValidAddress(newAddress)) {
|
||||
setCurAddress(newAddress);
|
||||
scrollAddressIntoView();
|
||||
redraw();
|
||||
uint32_t newAddress = curAddress;
|
||||
if (!GPUDebugExecExpression(gpuDebug, expression.c_str(), newAddress)) {
|
||||
MessageBox(wnd, ConvertUTF8ToWString(getExpressionError()).c_str(), L"Invalid expression", MB_OK | MB_ICONEXCLAMATION);
|
||||
break;
|
||||
}
|
||||
if (!Memory::IsValidAddress(newAddress)) {
|
||||
MessageBox(wnd, L"Address not in valid memory", L"Invalid address", MB_OK | MB_ICONEXCLAMATION);
|
||||
break;
|
||||
}
|
||||
|
||||
setCurAddress(newAddress);
|
||||
scrollAddressIntoView();
|
||||
redraw();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue