[Debugger] Add events.ongprvalue to JS API
This commit is contained in:
parent
aa1ace5746
commit
1b34937307
|
@ -39,6 +39,51 @@ const _regNums = {
|
|||
f28: 28, f29: 29, f30: 30, f31: 31
|
||||
}
|
||||
|
||||
const _gprNames = [
|
||||
'r0', 'at', 'v0', 'v1', 'a0', 'a1', 'a2', 'a3',
|
||||
't0', 't1', 't2', 't3', 't4', 't5', 't6', 't7',
|
||||
's0', 's1', 's2', 's3', 's4', 's5', 's6', 's7',
|
||||
't8', 't9', 'k0', 'k1', 'gp', 'sp', 'fp', 'ra'
|
||||
]
|
||||
|
||||
const GPR_R0 = (1 << 0)
|
||||
const GPR_AT = (1 << 1)
|
||||
const GPR_V0 = (1 << 2)
|
||||
const GPR_V1 = (1 << 3)
|
||||
const GPR_A0 = (1 << 4)
|
||||
const GPR_A1 = (1 << 5)
|
||||
const GPR_A2 = (1 << 6)
|
||||
const GPR_A3 = (1 << 7)
|
||||
const GPR_T0 = (1 << 8)
|
||||
const GPR_T1 = (1 << 9)
|
||||
const GPR_T2 = (1 << 10)
|
||||
const GPR_T3 = (1 << 11)
|
||||
const GPR_T4 = (1 << 12)
|
||||
const GPR_T5 = (1 << 13)
|
||||
const GPR_T6 = (1 << 14)
|
||||
const GPR_T7 = (1 << 15)
|
||||
const GPR_S0 = (1 << 16)
|
||||
const GPR_S1 = (1 << 17)
|
||||
const GPR_S2 = (1 << 18)
|
||||
const GPR_S3 = (1 << 19)
|
||||
const GPR_S4 = (1 << 20)
|
||||
const GPR_S5 = (1 << 21)
|
||||
const GPR_S6 = (1 << 22)
|
||||
const GPR_S7 = (1 << 23)
|
||||
const GPR_T8 = (1 << 24)
|
||||
const GPR_T9 = (1 << 25)
|
||||
const GPR_K0 = (1 << 26)
|
||||
const GPR_K1 = (1 << 27)
|
||||
const GPR_GP = (1 << 28)
|
||||
const GPR_SP = (1 << 29)
|
||||
const GPR_FP = (1 << 30)
|
||||
const GPR_RA = (1 << 31) >>> 0
|
||||
|
||||
const GPR_ANY_ARG = (GPR_A0 | GPR_A1 | GPR_A2 | GPR_A3)
|
||||
const GPR_ANY_TEMP = (GPR_T0 | GPR_T1 | GPR_T2 | GPR_T3 | GPR_T4 | GPR_T5 | GPR_T6 | GPR_T7 | GPR_T8 | GPR_T9)
|
||||
const GPR_ANY_SAVE = (GPR_S0 | GPR_S1 | GPR_S2 | GPR_S3 | GPR_S4 | GPR_S5 | GPR_S6 | GPR_S7)
|
||||
const GPR_ANY = (GPR_R0 | GPR_AT | GPR_V0 | GPR_V1 | GPR_ANY_ARG | GPR_ANY_TEMP | GPR_ANY_SAVE | GPR_K0 | GPR_K1 | GPR_GP | GPR_SP | GPR_FP | GPR_RA) >>> 0
|
||||
|
||||
function AddressRange(start, end)
|
||||
{
|
||||
this.start = start >>> 0
|
||||
|
@ -56,6 +101,17 @@ const ADDR_ANY_RDRAM_UNC = new AddressRange(0xA0000000, 0xA0800000)
|
|||
const ADDR_ANY_CART_ROM = new AddressRange(0x90000000, 0x96000000)
|
||||
const ADDR_ANY_CART_ROM_UNC = new AddressRange(0xB0000000, 0xB6000000)
|
||||
|
||||
const asm = {
|
||||
gprname: function(num)
|
||||
{
|
||||
if(num in _gprNames)
|
||||
{
|
||||
return _gprNames[num]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
const fs = {
|
||||
open: function(path, mode)
|
||||
{
|
||||
|
@ -331,7 +387,25 @@ const events = (function()
|
|||
}
|
||||
|
||||
this._stashCallback(callback);
|
||||
return _native.addCallback('onopcode', callback, start, end, value, mask)
|
||||
return _native.addCallback('opcode', callback, start, end, value, mask)
|
||||
},
|
||||
ongprvalue: function(addr, registers, value, callback)
|
||||
{
|
||||
var start = 0;
|
||||
var end = 0;
|
||||
|
||||
if(typeof(addr) == "object")
|
||||
{
|
||||
start = addr.start;
|
||||
end = addr.end;
|
||||
}
|
||||
else if(typeof(addr) == "number")
|
||||
{
|
||||
start = addr;
|
||||
}
|
||||
|
||||
this._stashCallback(callback);
|
||||
return _native.addCallback('gprvalue', callback, start, end, registers, value)
|
||||
},
|
||||
onread: function(addr, callback)
|
||||
{
|
||||
|
@ -754,7 +828,6 @@ function alert(text, caption){
|
|||
_native.msgBox(text, caption)
|
||||
}
|
||||
|
||||
|
||||
function Socket(fd)
|
||||
{
|
||||
var connected = false;
|
||||
|
|
|
@ -576,8 +576,9 @@ void CDebuggerUI::CPUStepStarted()
|
|||
uint32_t PROGRAM_COUNTER = g_Reg->m_PROGRAM_COUNTER;
|
||||
uint32_t JumpToLocation = R4300iOp::m_JumpToLocation;
|
||||
|
||||
m_ScriptSystem->HookCPUExec()->InvokeByParamInRange(PROGRAM_COUNTER);
|
||||
m_ScriptSystem->HookCPUExecOpcode()->InvokeByParamInRangeWithMaskedValue(PROGRAM_COUNTER, R4300iOp::m_Opcode.Hex);
|
||||
m_ScriptSystem->HookCPUExec()->InvokeByAddressInRange(PROGRAM_COUNTER);
|
||||
m_ScriptSystem->HookCPUExecOpcode()->InvokeByAddressInRange_MaskedOpcode(PROGRAM_COUNTER, R4300iOp::m_Opcode.Hex);
|
||||
m_ScriptSystem->HookCPUGPRValue()->InvokeByAddressInRange_GPRValue(PROGRAM_COUNTER);
|
||||
|
||||
// Memory breakpoints
|
||||
|
||||
|
@ -589,11 +590,11 @@ void CDebuggerUI::CPUStepStarted()
|
|||
|
||||
if (opInfo.IsLoadCommand()) // Read instructions
|
||||
{
|
||||
m_ScriptSystem->HookCPURead()->InvokeByParamInRange(memoryAddress);
|
||||
m_ScriptSystem->HookCPURead()->InvokeByAddressInRange(memoryAddress);
|
||||
}
|
||||
else // Write instructions
|
||||
{
|
||||
m_ScriptSystem->HookCPUWrite()->InvokeByParamInRange(memoryAddress);
|
||||
m_ScriptSystem->HookCPUWrite()->InvokeByAddressInRange(memoryAddress);
|
||||
|
||||
// Catch cart -> rdram dma
|
||||
if (memoryAddress == 0xA460000C) // PI_WR_LEN_REG
|
||||
|
|
|
@ -46,35 +46,65 @@ void CScriptHook::InvokeByParam(uint32_t param)
|
|||
}
|
||||
}
|
||||
|
||||
void CScriptHook::InvokeByParamInRange(uint32_t param)
|
||||
void CScriptHook::InvokeByAddressInRange(uint32_t address)
|
||||
{
|
||||
int nCallbacks = m_Callbacks.size();
|
||||
for (int i = 0; i < nCallbacks; i++)
|
||||
{
|
||||
if (param == m_Callbacks[i].param || (param >= m_Callbacks[i].param && param < m_Callbacks[i].param2))
|
||||
if (address == m_Callbacks[i].param || (address >= m_Callbacks[i].param && address < m_Callbacks[i].param2))
|
||||
{
|
||||
m_Callbacks[i].scriptInstance->Invoke(m_Callbacks[i].heapptr, param);
|
||||
m_Callbacks[i].scriptInstance->Invoke(m_Callbacks[i].heapptr, address);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptHook::InvokeByParamInRangeWithMaskedValue(uint32_t param, uint32_t value)
|
||||
void CScriptHook::InvokeByAddressInRange_MaskedOpcode(uint32_t pc, uint32_t opcode)
|
||||
{
|
||||
int nCallbacks = m_Callbacks.size();
|
||||
for (int i = 0; i < nCallbacks; i++)
|
||||
{
|
||||
if (param == m_Callbacks[i].param || (param >= m_Callbacks[i].param && param < m_Callbacks[i].param2))
|
||||
if (pc == m_Callbacks[i].param || (pc >= m_Callbacks[i].param && pc < m_Callbacks[i].param2))
|
||||
{
|
||||
if ((m_Callbacks[i].param3 & m_Callbacks[i].param4) == (value & m_Callbacks[i].param4))
|
||||
if ((m_Callbacks[i].param3 & m_Callbacks[i].param4) == (opcode & m_Callbacks[i].param4))
|
||||
{
|
||||
m_Callbacks[i].scriptInstance->Invoke(m_Callbacks[i].heapptr, param);
|
||||
m_Callbacks[i].scriptInstance->Invoke(m_Callbacks[i].heapptr, pc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptHook::InvokeByAddressInRange_GPRValue(uint32_t pc)
|
||||
{
|
||||
int nCallbacks = m_Callbacks.size();
|
||||
|
||||
for (int i = 0; i < nCallbacks; i++)
|
||||
{
|
||||
uint32_t startAddress = m_Callbacks[i].param;
|
||||
uint32_t endAddress = m_Callbacks[i].param2;
|
||||
uint32_t registers = m_Callbacks[i].param3;
|
||||
uint32_t value = m_Callbacks[i].param4;
|
||||
|
||||
if (!(pc == startAddress || (pc >= startAddress && pc < endAddress)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int nReg = 0; nReg < 32; nReg++)
|
||||
{
|
||||
if (registers & (1 << nReg))
|
||||
{
|
||||
if (value == g_Reg->m_GPR[nReg].UW[0])
|
||||
{
|
||||
m_Callbacks[i].scriptInstance->Invoke2(m_Callbacks[i].heapptr, pc, nReg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptHook::InvokeAll()
|
||||
{
|
||||
int nCallbacks = m_Callbacks.size();
|
||||
|
|
|
@ -33,9 +33,10 @@ public:
|
|||
void InvokeById(int callbackId);
|
||||
void InvokeByParam(uint32_t param);
|
||||
/* invoke if param >= cb.param && param < cb.param2*/
|
||||
void InvokeByParamInRange(uint32_t param);
|
||||
void InvokeByAddressInRange(uint32_t address);
|
||||
/* invoke if param >= cb.param && param < cb.param2 && (value & cb.param4) == cb.param3 */
|
||||
void InvokeByParamInRangeWithMaskedValue(uint32_t param, uint32_t value);
|
||||
void InvokeByAddressInRange_MaskedOpcode(uint32_t pc, uint32_t value);
|
||||
void InvokeByAddressInRange_GPRValue(uint32_t pc);
|
||||
void RemoveById(int callbackId);
|
||||
void RemoveByParam(uint32_t tag);
|
||||
void RemoveByInstance(CScriptInstance* scriptInstance);
|
||||
|
|
|
@ -577,6 +577,26 @@ void CScriptInstance::Invoke(void* heapptr, uint32_t param)
|
|||
LeaveCriticalSection(&m_CriticalSection);
|
||||
}
|
||||
|
||||
void CScriptInstance::Invoke2(void* heapptr, uint32_t param, uint32_t param2)
|
||||
{
|
||||
EnterCriticalSection(&m_CriticalSection);
|
||||
duk_push_heapptr(m_Ctx, heapptr);
|
||||
duk_push_uint(m_Ctx, param);
|
||||
duk_push_uint(m_Ctx, param2);
|
||||
|
||||
duk_int_t status = duk_pcall(m_Ctx, 2);
|
||||
|
||||
if (status != DUK_EXEC_SUCCESS)
|
||||
{
|
||||
const char* errorText = duk_safe_to_string(m_Ctx, -1);
|
||||
m_Debugger->Debug_LogScriptsWindow(errorText);
|
||||
m_Debugger->Debug_LogScriptsWindow("\r\n");
|
||||
}
|
||||
|
||||
duk_pop(m_Ctx);
|
||||
LeaveCriticalSection(&m_CriticalSection);
|
||||
}
|
||||
|
||||
void CScriptInstance::QueueAPC(PAPCFUNC userProc, ULONG_PTR param)
|
||||
{
|
||||
if (m_hThread != NULL)
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
void Start(char* path);
|
||||
void ForceStop();
|
||||
void Invoke(void* heapptr, uint32_t param = 0);
|
||||
void Invoke2(void* heapptr, uint32_t param = 0, uint32_t param2 = 0);
|
||||
INSTANCE_STATE GetState();
|
||||
|
||||
friend class PendingEval;
|
||||
|
|
|
@ -28,12 +28,14 @@ CScriptSystem::CScriptSystem(CDebuggerUI* debugger)
|
|||
m_HookCPUExecOpcode = new CScriptHook(this);
|
||||
m_HookCPURead = new CScriptHook(this);
|
||||
m_HookCPUWrite = new CScriptHook(this);
|
||||
m_HookCPUGPRValue = new CScriptHook(this);
|
||||
m_HookFrameDrawn = new CScriptHook(this);
|
||||
|
||||
RegisterHook("exec", m_HookCPUExec);
|
||||
RegisterHook("read", m_HookCPURead);
|
||||
RegisterHook("write", m_HookCPUWrite);
|
||||
RegisterHook("onopcode", m_HookCPUExecOpcode);
|
||||
RegisterHook("opcode", m_HookCPUExecOpcode);
|
||||
RegisterHook("gprvalue", m_HookCPUGPRValue);
|
||||
RegisterHook("draw", m_HookFrameDrawn);
|
||||
|
||||
HMODULE hInst = GetModuleHandle(NULL);
|
||||
|
|
|
@ -55,7 +55,7 @@ private:
|
|||
CScriptHook* m_HookCPURead;
|
||||
CScriptHook* m_HookCPUWrite;
|
||||
CScriptHook* m_HookCPUExecOpcode;
|
||||
|
||||
CScriptHook* m_HookCPUGPRValue;
|
||||
CScriptHook* m_HookFrameDrawn;
|
||||
|
||||
void RegisterHook(const char* hookId, CScriptHook* cbList); // associate string id with callback list
|
||||
|
@ -126,6 +126,11 @@ public:
|
|||
return m_HookCPUExecOpcode;
|
||||
}
|
||||
|
||||
CScriptHook* HookCPUGPRValue()
|
||||
{
|
||||
return m_HookCPUGPRValue;
|
||||
}
|
||||
|
||||
CScriptHook* HookFrameDrawn()
|
||||
{
|
||||
return m_HookFrameDrawn;
|
||||
|
|
54
apidoc.htm
54
apidoc.htm
|
@ -98,6 +98,7 @@ span.tag2 {
|
|||
<a href="#rom">rom</a><br>
|
||||
<a href="#events">events</a><br>
|
||||
<a href="#debug">debug</a><br>
|
||||
<a href="#asm">asm</a><br>
|
||||
<a href="#console">console</a><br>
|
||||
<a href="#fs">fs</a><br>
|
||||
<a href="#fs.Stats">fs.Stats</a><br>
|
||||
|
@ -336,7 +337,7 @@ events.onwrite(ADDR_ANY_CART_ROM_UNC, function(addr)
|
|||
<span class="tag">interpreter mode only</span>
|
||||
<div class="propertyname">events.onopcode(address, opcode, callback)</div>
|
||||
<div class="propertydesc">
|
||||
Adds a CPU executions callback for a virtual address or <a href="#AddressRange">AddressRange</a> and returns a callback ID.
|
||||
Adds a CPU execution callback for a virtual address or <a href="#AddressRange">AddressRange</a> and returns a callback ID.
|
||||
<span class="snip">callback</span> will be invoked at the beginning of a CPU step if the program counter is at <span class="snip">address</span> and <span class="snip">opcode</span> is equal to the opcode to be executed.
|
||||
<span class="snip">callback</span> receives the program counter address at which the event is fired.
|
||||
<pre class="example">
|
||||
|
@ -354,7 +355,7 @@ events.onopcode(ADDR_ANY, JR_RA, function(pc)
|
|||
<span class="tag">interpreter mode only</span>
|
||||
<div class="propertyname">events.onopcode(address, opcode, mask, callback)</div>
|
||||
<div class="propertydesc">
|
||||
Adds a CPU executions callback for a virtual address or <a href="#AddressRange">AddressRange</a> and returns a callback ID.
|
||||
Adds a CPU execution callback for a virtual address or <a href="#AddressRange">AddressRange</a> and returns a callback ID.
|
||||
<span class="snip">callback</span> will be invoked at the beginning of a CPU step if the program counter is at <span class="snip">address</span> and <span class="snip">opcode</span> is equal to the opcode to be executed ANDed with <span class="snip">mask</span>.
|
||||
<span class="snip">callback</span> receives the program counter address at which the event is fired.
|
||||
<pre class="example">
|
||||
|
@ -379,6 +380,42 @@ events.onopcode(ADDR_ANY, JAL, NO_TARGET, function(pc)
|
|||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="property">
|
||||
<span class="tag2">emulation thread</span>
|
||||
<span class="tag">interpreter mode only</span>
|
||||
<div class="propertyname">events.ongprvalue(address, registers, value, callback)</div>
|
||||
<div class="propertydesc">
|
||||
Adds a CPU execution callback for a virtual address or <a href="#AddressRange">AddressRange</a> and returns a callback ID.
|
||||
<span class="snip">callback</span> will be invoked at the beginning of a CPU step if the program counter is at <span class="snip">address</span> and the lower 32 bits of the general purpose registers specified by <span class="snip">registers</span> are equal to <span class="snip">value</span>.
|
||||
<span class="snip">callback</span> receives the program counter address at which the event is fired, and the index of the first register that contains the value.
|
||||
<pre class="example">
|
||||
events.ongprvalue(ADDR_ANY, GPR_ANY, 0x49533634, function(pc, reg)
|
||||
{
|
||||
// log pc whenever any general purpose register contains 0x49533634
|
||||
console.log(pc.hex(), asm.gprname(reg))
|
||||
})
|
||||
</pre>
|
||||
<pre class="example">
|
||||
events.ongprvalue(ADDR_ANY, GPR_A0 | GPR_A1, 0x00001234, function(pc, reg)
|
||||
{
|
||||
// log pc whenever A0 or A1 contains 0x00001234
|
||||
console.log(pc.hex(), asm.gprname(reg))
|
||||
})
|
||||
</pre>
|
||||
Valid registers:
|
||||
<pre style="font-size: 13px;">
|
||||
GPR_R0 GPR_AT GPR_V0 GPR_V1 GPR_A0 GPR_A1 GPR_A2 GPR_A3
|
||||
GPR_T0 GPR_T1 GPR_T2 GPR_T3 GPR_T4 GPR_T5 GPR_T6 GPR_T7
|
||||
GPR_S0 GPR_S1 GPR_S2 GPR_S3 GPR_S4 GPR_S5 GPR_S6 GPR_S7
|
||||
GPR_T8 GPR_T9 GPR_K0 GPR_K1 GPR_GP GPR_SP GPR_FP GPR_RA
|
||||
|
||||
GPR_ANY_ARG -- Any of the 'A' registers
|
||||
GPR_ANY_TEMP -- Any of the 'T' registers
|
||||
GPR_ANY_SAVE -- Any of the 'S' registers
|
||||
GPR_ANY -- Any register
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="property">
|
||||
<span class="tag2">emulation thread</span>
|
||||
<div class="propertyname">events.ondraw(callback)</div>
|
||||
|
@ -437,6 +474,19 @@ events.onexec(0x802CB1C0, function()
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel" id="asm">
|
||||
<div class="classname">asm</div>
|
||||
<div class="property">
|
||||
<div class="propertyname">asm.gprname(regIndex)</div>
|
||||
<div class="propertydesc">
|
||||
Returns the name of the general purpose register specified by <span class="snip">regIndex</span>.
|
||||
<pre class="example">
|
||||
asm.gprname(4) // 'a0'
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel" id="fs">
|
||||
<div class="classname">fs</div>
|
||||
<div class="property">
|
||||
|
|
Loading…
Reference in New Issue