Merge pull request #651 from torusrxxx/development
Conditional breakpoint This will make a lot of people happy, thanks a lot!
This commit is contained in:
commit
c1f505b46e
|
@ -61,6 +61,8 @@ BRIDGE_IMPEXP int BridgeGetDbgVersion();
|
|||
#define MAX_MODULE_SIZE 256
|
||||
#define MAX_IMPORT_SIZE 65536
|
||||
#define MAX_BREAKPOINT_SIZE 256
|
||||
#define MAX_CONDITIONAL_EXPR_SIZE 256
|
||||
#define MAX_CONDITIONAL_LOG_SIZE 256
|
||||
#define MAX_SCRIPT_LINE_SIZE 2048
|
||||
#define MAX_THREAD_NAME_SIZE 256
|
||||
#define MAX_STRING_SIZE 512
|
||||
|
@ -321,6 +323,12 @@ typedef struct
|
|||
char name[MAX_BREAKPOINT_SIZE];
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
unsigned short slot;
|
||||
// extended part
|
||||
unsigned int hitCount;
|
||||
bool fastResume;
|
||||
char condition[MAX_CONDITIONAL_EXPR_SIZE];
|
||||
char log[MAX_CONDITIONAL_LOG_SIZE];
|
||||
char hitCmd[MAX_CONDITIONAL_EXPR_SIZE];
|
||||
} BRIDGEBP;
|
||||
|
||||
typedef struct
|
||||
|
@ -844,7 +852,7 @@ typedef struct
|
|||
} SCRIPTTYPEINFO;
|
||||
|
||||
//GUI functions
|
||||
// TODO: Most of these functions are not unicode-aware. Rewrite them.
|
||||
//code page is utf8
|
||||
BRIDGE_IMPEXP void GuiDisasmAt(duint addr, duint cip);
|
||||
BRIDGE_IMPEXP void GuiSetDebugState(DBGSTATE state);
|
||||
BRIDGE_IMPEXP void GuiAddLogMessage(const char* msg);
|
||||
|
|
|
@ -568,64 +568,27 @@ extern "C" DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* bpmap)
|
|||
int retcount = 0;
|
||||
std::vector<BRIDGEBP> bridgeList;
|
||||
BRIDGEBP curBp;
|
||||
BP_TYPE currentBpType;
|
||||
switch(type)
|
||||
{
|
||||
case bp_normal:
|
||||
currentBpType = BPNORMAL;
|
||||
break;
|
||||
case bp_hardware:
|
||||
currentBpType = BPHARDWARE;
|
||||
break;
|
||||
case bp_memory:
|
||||
currentBpType = BPMEMORY;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
unsigned short slot = 0;
|
||||
for(int i = 0; i < bpcount; i++)
|
||||
{
|
||||
memset(&curBp, 0, sizeof(BRIDGEBP));
|
||||
switch(type)
|
||||
{
|
||||
case bp_none: //all types
|
||||
break;
|
||||
case bp_normal: //normal
|
||||
if(list[i].type != BPNORMAL)
|
||||
continue;
|
||||
break;
|
||||
case bp_hardware: //hardware
|
||||
if(list[i].type != BPHARDWARE)
|
||||
continue;
|
||||
break;
|
||||
case bp_memory: //memory
|
||||
if(list[i].type != BPMEMORY)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
switch(list[i].type)
|
||||
{
|
||||
case BPNORMAL:
|
||||
curBp.type = bp_normal;
|
||||
break;
|
||||
case BPHARDWARE:
|
||||
curBp.type = bp_hardware;
|
||||
break;
|
||||
case BPMEMORY:
|
||||
curBp.type = bp_memory;
|
||||
break;
|
||||
}
|
||||
switch(((DWORD)list[i].titantype) >> 8)
|
||||
{
|
||||
case UE_DR0:
|
||||
slot = 0;
|
||||
break;
|
||||
case UE_DR1:
|
||||
slot = 1;
|
||||
break;
|
||||
case UE_DR2:
|
||||
slot = 2;
|
||||
break;
|
||||
case UE_DR3:
|
||||
slot = 3;
|
||||
break;
|
||||
}
|
||||
curBp.addr = list[i].addr;
|
||||
curBp.enabled = list[i].enabled;
|
||||
curBp.active = list[i].active;
|
||||
strcpy_s(curBp.mod, list[i].mod);
|
||||
strcpy_s(curBp.name, list[i].name);
|
||||
curBp.singleshoot = list[i].singleshoot;
|
||||
curBp.slot = slot;
|
||||
|
||||
if(list[i].type != currentBpType)
|
||||
continue;
|
||||
BpToBridge(&list[i], &curBp);
|
||||
bridgeList.push_back(curBp);
|
||||
retcount++;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
#include "module.h"
|
||||
#include "value.h"
|
||||
#include "debugger.h"
|
||||
|
||||
typedef std::pair<BP_TYPE, duint> BreakpointKey;
|
||||
std::map<BreakpointKey, BREAKPOINT> breakpoints;
|
||||
|
@ -121,7 +123,7 @@ bool BpGet(duint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp)
|
|||
for(auto & i : breakpoints)
|
||||
{
|
||||
// Do the names match?
|
||||
if(strcmp(Name, i.second.name) != 0)
|
||||
if(_stricmp(Name, i.second.name) != 0)
|
||||
continue;
|
||||
|
||||
// Fill out the optional user buffer
|
||||
|
@ -139,6 +141,17 @@ bool BpGet(duint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool BpGetAny(BP_TYPE Type, const char* Name, BREAKPOINT* Bp)
|
||||
{
|
||||
if(BpGet(0, Type, Name, Bp))
|
||||
return true;
|
||||
duint addr;
|
||||
if(valfromstring(Name, &addr))
|
||||
if(BpGet(addr, Type, 0, Bp))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BpDelete(duint Address, BP_TYPE Type)
|
||||
{
|
||||
ASSERT_DEBUGGING("Command function call");
|
||||
|
@ -204,6 +217,66 @@ bool BpSetTitanType(duint Address, BP_TYPE Type, int TitanType)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BpSetCondition(duint Address, BP_TYPE Type, const char* Condition)
|
||||
{
|
||||
ASSERT_DEBUGGING("Command function call");
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Set breakpoint condition
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
|
||||
strcpy_s(bpInfo->condition, Condition);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BpSetLogText(duint Address, BP_TYPE Type, const char* Log)
|
||||
{
|
||||
ASSERT_DEBUGGING("Command function call");
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Set breakpoint log
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
|
||||
strcpy_s(bpInfo->logText, MAX_CONDITIONAL_LOG_SIZE, Log);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BpSetHitCommand(duint Address, BP_TYPE Type, const char* Cmd)
|
||||
{
|
||||
ASSERT_DEBUGGING("Command function call");
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Set breakpoint hit command
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
|
||||
strcpy_s(bpInfo->hitcmd, MAX_CONDITIONAL_EXPR_SIZE, Cmd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BpSetFastResume(duint Address, BP_TYPE Type, bool fastResume)
|
||||
{
|
||||
ASSERT_DEBUGGING("Command function call");
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Set breakpoint fast resume
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
|
||||
bpInfo->fastResume = fastResume;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module)
|
||||
{
|
||||
ASSERT_DEBUGGING("Export call");
|
||||
|
@ -270,6 +343,32 @@ int BpGetCount(BP_TYPE Type, bool EnabledOnly)
|
|||
return count;
|
||||
}
|
||||
|
||||
|
||||
uint32 BpGetHitCount(duint Address, BP_TYPE Type)
|
||||
{
|
||||
SHARED_ACQUIRE(LockBreakpoints);
|
||||
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
|
||||
return bpInfo->hitcount;
|
||||
}
|
||||
|
||||
bool BpResetHitCount(duint Address, BP_TYPE Type, uint32 newHitCount)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
|
||||
bpInfo->hitcount = newHitCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp)
|
||||
{
|
||||
//
|
||||
|
@ -282,11 +381,16 @@ void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp)
|
|||
memset(BridgeBp, 0, sizeof(BRIDGEBP));
|
||||
strcpy_s(BridgeBp->mod, Bp->mod);
|
||||
strcpy_s(BridgeBp->name, Bp->name);
|
||||
strcpy_s(BridgeBp->condition, Bp->condition);
|
||||
strcpy_s(BridgeBp->log, Bp->logText);
|
||||
strcpy_s(BridgeBp->hitCmd, Bp->hitcmd);
|
||||
|
||||
BridgeBp->active = Bp->active;
|
||||
BridgeBp->addr = Bp->addr;
|
||||
BridgeBp->enabled = Bp->enabled;
|
||||
BridgeBp->singleshoot = Bp->singleshoot;
|
||||
BridgeBp->fastResume = Bp->fastResume;
|
||||
BridgeBp->hitCount = Bp->hitcount;
|
||||
|
||||
switch(Bp->type)
|
||||
{
|
||||
|
@ -295,6 +399,21 @@ void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp)
|
|||
break;
|
||||
case BPHARDWARE:
|
||||
BridgeBp->type = bp_hardware;
|
||||
switch(((DWORD)Bp->titantype) >> 8)
|
||||
{
|
||||
case UE_DR0:
|
||||
BridgeBp->slot = 0;
|
||||
break;
|
||||
case UE_DR1:
|
||||
BridgeBp->slot = 1;
|
||||
break;
|
||||
case UE_DR2:
|
||||
BridgeBp->slot = 2;
|
||||
break;
|
||||
case UE_DR3:
|
||||
BridgeBp->slot = 3;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BPMEMORY:
|
||||
BridgeBp->type = bp_memory;
|
||||
|
@ -333,6 +452,10 @@ void BpCacheSave(JSON Root)
|
|||
json_object_set_new(jsonObj, "titantype", json_hex(breakpoint.titantype));
|
||||
json_object_set_new(jsonObj, "name", json_string(breakpoint.name));
|
||||
json_object_set_new(jsonObj, "module", json_string(breakpoint.mod));
|
||||
json_object_set_new(jsonObj, "condition", json_string(breakpoint.condition));
|
||||
json_object_set_new(jsonObj, "log", json_string(breakpoint.logText));
|
||||
json_object_set_new(jsonObj, "hitcommand", json_string(breakpoint.hitcmd));
|
||||
json_object_set_new(jsonObj, "fastresume", json_boolean(true));
|
||||
json_array_append_new(jsonBreakpoints, jsonObj);
|
||||
}
|
||||
|
||||
|
@ -372,15 +495,33 @@ void BpCacheLoad(JSON Root)
|
|||
breakpoint.titantype = (DWORD)json_hex_value(json_object_get(value, "titantype"));
|
||||
|
||||
// Name
|
||||
const char* name = json_string_value(json_object_get(value, "name"));
|
||||
if(name)
|
||||
strcpy_s(breakpoint.name, name);
|
||||
const char* text = json_string_value(json_object_get(value, "name"));
|
||||
if(text)
|
||||
strcpy_s(breakpoint.name, text);
|
||||
|
||||
// Module
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(breakpoint.mod, mod);
|
||||
|
||||
// Condition
|
||||
text = json_string_value(json_object_get(value, "condition"));
|
||||
if(text)
|
||||
strcpy_s(breakpoint.condition, text);
|
||||
|
||||
// Log string
|
||||
text = json_string_value(json_object_get(value, "log"));
|
||||
if(text)
|
||||
strcpy_s(breakpoint.logText, text);
|
||||
|
||||
// Hit command
|
||||
text = json_string_value(json_object_get(value, "hitcommand"));
|
||||
if(text)
|
||||
strcpy_s(breakpoint.hitcmd, text);
|
||||
|
||||
// Fast resume
|
||||
breakpoint.fastResume = json_boolean_value(json_object_get(value, "fastresume"));
|
||||
|
||||
// Build the hash map key: MOD_HASH + ADDRESS
|
||||
duint key = ModHashFromName(breakpoint.mod) + breakpoint.addr;
|
||||
breakpoints.insert(std::make_pair(BreakpointKey(breakpoint.type, key), breakpoint));
|
||||
|
@ -391,4 +532,4 @@ void BpClear()
|
|||
{
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
breakpoints.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,11 @@ struct BREAKPOINT
|
|||
DWORD titantype;
|
||||
char name[MAX_BREAKPOINT_SIZE];
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
char condition[MAX_CONDITIONAL_EXPR_SIZE]; // condition to stop. If true, debugger halts.
|
||||
char logText[MAX_CONDITIONAL_LOG_SIZE]; // text to log.
|
||||
char hitcmd[MAX_CONDITIONAL_EXPR_SIZE]; // script command to execute.
|
||||
uint32 hitcount; // hit counter
|
||||
bool fastResume; // if true, debugger resumes without any GUI/Script/Plugin interaction.
|
||||
};
|
||||
|
||||
// Breakpoint enumeration callback
|
||||
|
@ -37,16 +42,23 @@ BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, duint Address);
|
|||
int BpGetList(std::vector<BREAKPOINT>* List);
|
||||
bool BpNew(duint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name);
|
||||
bool BpGet(duint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp);
|
||||
bool BpGetAny(BP_TYPE Type, const char* Name, BREAKPOINT* Bp);
|
||||
bool BpDelete(duint Address, BP_TYPE Type);
|
||||
bool BpEnable(duint Address, BP_TYPE Type, bool Enable);
|
||||
bool BpSetName(duint Address, BP_TYPE Type, const char* Name);
|
||||
bool BpSetTitanType(duint Address, BP_TYPE Type, int TitanType);
|
||||
bool BpSetCondition(duint Address, BP_TYPE Type, const char* Condition);
|
||||
bool BpSetLogText(duint Address, BP_TYPE Type, const char* Log);
|
||||
bool BpSetHitCommand(duint Address, BP_TYPE Type, const char* Cmd);
|
||||
bool BpSetFastResume(duint Address, BP_TYPE Type, bool fastResume);
|
||||
bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module);
|
||||
bool BpEnumAll(BPENUMCALLBACK EnumCallback);
|
||||
int BpGetCount(BP_TYPE Type, bool EnabledOnly = false);
|
||||
uint32 BpGetHitCount(duint Address, BP_TYPE Type);
|
||||
bool BpResetHitCount(duint Address, BP_TYPE Type, uint32 newHitCount);
|
||||
void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp);
|
||||
void BpCacheSave(JSON Root);
|
||||
void BpCacheLoad(JSON Root);
|
||||
void BpClear();
|
||||
|
||||
#endif // _BREAKPOINT_H
|
||||
#endif // _BREAKPOINT_H
|
||||
|
|
|
@ -269,192 +269,285 @@ void DebugUpdateStack(duint dumpAddr, duint csp, bool forceDump)
|
|||
GuiStackDumpAt(dumpAddr, csp);
|
||||
}
|
||||
|
||||
void BreakpointProlog(duint condition, BREAKPOINT& bp, PLUG_CB_BREAKPOINT& bpInfo)
|
||||
{
|
||||
// update GUI
|
||||
if(condition != 0)
|
||||
{
|
||||
GuiSetDebugState(paused);
|
||||
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
|
||||
}
|
||||
// plugin interaction
|
||||
lock(WAITID_RUN);
|
||||
PLUG_CB_PAUSEDEBUG pauseInfo;
|
||||
memset(&pauseInfo, 0, sizeof(pauseInfo));
|
||||
plugincbcall(CB_PAUSEDEBUG, &pauseInfo);
|
||||
plugincbcall(CB_BREAKPOINT, &bpInfo);
|
||||
// conditional
|
||||
if(bp.logText[0] != 0)
|
||||
{
|
||||
char logText2[MAX_CONDITIONAL_LOG_SIZE + 1];
|
||||
memcpy(logText2, bp.logText, MAX_CONDITIONAL_LOG_SIZE);
|
||||
strcat_s(logText2, "\n");
|
||||
GuiAddLogMessage(logText2);
|
||||
}
|
||||
if(bp.hitcmd[0] != 0 && condition != 0)
|
||||
{
|
||||
DbgCmdExec(bp.hitcmd);
|
||||
}
|
||||
if(condition == 0)
|
||||
{
|
||||
unlock(WAITID_RUN);
|
||||
SetForegroundWindow(GuiGetWindowHandle());
|
||||
bSkipExceptions = false;
|
||||
}
|
||||
//lock
|
||||
wait(WAITID_RUN);
|
||||
}
|
||||
|
||||
void cbUserBreakpoint()
|
||||
{
|
||||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
BREAKPOINT* bpPtr;
|
||||
BREAKPOINT bp;
|
||||
BRIDGEBP pluginBp;
|
||||
PLUG_CB_BREAKPOINT bpInfo;
|
||||
bpInfo.breakpoint = 0;
|
||||
if(!BpGet(GetContextDataEx(hActiveThread, UE_CIP), BPNORMAL, 0, &bp) && bp.enabled)
|
||||
ULONG_PTR CIP;
|
||||
duint condition = 1;
|
||||
memset(&bpInfo, 0, sizeof(bpInfo));
|
||||
CIP = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
bpPtr = BpInfoFromAddr(BPNORMAL, CIP);
|
||||
if(!(bpPtr && bpPtr->enabled))
|
||||
dputs("Breakpoint reached not in list!");
|
||||
else
|
||||
{
|
||||
const char* bptype = "INT3";
|
||||
int titantype = bp.titantype;
|
||||
if((titantype & UE_BREAKPOINT_TYPE_UD2) == UE_BREAKPOINT_TYPE_UD2)
|
||||
bptype = "UD2";
|
||||
else if((titantype & UE_BREAKPOINT_TYPE_LONG_INT3) == UE_BREAKPOINT_TYPE_LONG_INT3)
|
||||
bptype = "LONG INT3";
|
||||
const char* symbolicname = SymGetSymbolicName(bp.addr);
|
||||
if(symbolicname)
|
||||
// increment hit count
|
||||
InterlockedIncrement(&bpPtr->hitcount);
|
||||
// condition eval
|
||||
bp = *bpPtr;
|
||||
bp.addr += ModBaseFromAddr(CIP);
|
||||
//setBpActive(bp);
|
||||
|
||||
//if(bp.type == BPHARDWARE) //TODO: properly implement this (check debug registers)
|
||||
// bp.active = true;
|
||||
//else
|
||||
bp.active = MemIsValidReadPtr(bp.addr);
|
||||
|
||||
if(bpPtr->condition[0] != 0)
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("%s breakpoint \"%s\" at %s (" fhex ")!\n", bptype, bp.name, symbolicname, bp.addr);
|
||||
if(*(uint16*)bp.condition == 0x30) // short curcit for condition "0"
|
||||
condition = 0;
|
||||
else
|
||||
dprintf("%s breakpoint at %s (" fhex ")!\n", bptype, symbolicname, bp.addr);
|
||||
valfromstring(bp.condition, &condition); // if this fails, condition remains 1
|
||||
if(bp.fastResume && condition == 0) // fast resume : ignore GUI/Script/Plugin/Singleshoot/Other
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(bp.logText[0] == 0 && condition != 0)
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("%s breakpoint \"%s\" at " fhex "!\n", bptype, bp.name, bp.addr);
|
||||
int titantype = bp.titantype;
|
||||
if((titantype & UE_BREAKPOINT_TYPE_UD2) == UE_BREAKPOINT_TYPE_UD2)
|
||||
bptype = "UD2";
|
||||
else if((titantype & UE_BREAKPOINT_TYPE_LONG_INT3) == UE_BREAKPOINT_TYPE_LONG_INT3)
|
||||
bptype = "LONG INT3";
|
||||
const char* symbolicname = SymGetSymbolicName(bp.addr);
|
||||
if(symbolicname)
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("%s breakpoint \"%s\" at %s (" fhex ")!\n", bptype, bp.name, symbolicname, bp.addr);
|
||||
else
|
||||
dprintf("%s breakpoint at %s (" fhex ")!\n", bptype, symbolicname, bp.addr);
|
||||
}
|
||||
else
|
||||
dprintf("%s breakpoint at " fhex "!\n", bptype, bp.addr);
|
||||
}
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("%s breakpoint \"%s\" at " fhex "!\n", bptype, bp.name, bp.addr);
|
||||
else
|
||||
dprintf("%s breakpoint at " fhex "!\n", bptype, bp.addr);
|
||||
}
|
||||
} // else: BreakpointProlog outputs the log.
|
||||
if(bp.singleshoot)
|
||||
BpDelete(bp.addr, BPNORMAL);
|
||||
BpToBridge(&bp, &pluginBp);
|
||||
bpInfo.breakpoint = &pluginBp;
|
||||
}
|
||||
GuiSetDebugState(paused);
|
||||
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
|
||||
//lock
|
||||
lock(WAITID_RUN);
|
||||
SetForegroundWindow(GuiGetWindowHandle());
|
||||
bSkipExceptions = false;
|
||||
PLUG_CB_PAUSEDEBUG pauseInfo;
|
||||
pauseInfo.reserved = 0;
|
||||
plugincbcall(CB_PAUSEDEBUG, &pauseInfo);
|
||||
plugincbcall(CB_BREAKPOINT, &bpInfo);
|
||||
wait(WAITID_RUN);
|
||||
BreakpointProlog(condition, bp, bpInfo);
|
||||
}
|
||||
|
||||
void cbHardwareBreakpoint(void* ExceptionAddress)
|
||||
{
|
||||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
duint cip = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
BREAKPOINT* bpPtr;
|
||||
BREAKPOINT bp;
|
||||
BRIDGEBP pluginBp;
|
||||
PLUG_CB_BREAKPOINT bpInfo;
|
||||
bpInfo.breakpoint = 0;
|
||||
if(!BpGet((duint)ExceptionAddress, BPHARDWARE, 0, &bp))
|
||||
ULONG_PTR CIP;
|
||||
duint condition = 1;
|
||||
memset(&bpInfo, 0, sizeof(bpInfo));
|
||||
CIP = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
bpPtr = BpInfoFromAddr(BPHARDWARE, (duint)ExceptionAddress);
|
||||
if(!(bpPtr && bpPtr->enabled))
|
||||
dputs("Hardware breakpoint reached not in list!");
|
||||
else
|
||||
{
|
||||
const char* bpsize = "";
|
||||
switch(TITANGETSIZE(bp.titantype)) //size
|
||||
// increment hit count
|
||||
InterlockedIncrement(&bpPtr->hitcount);
|
||||
// condition eval
|
||||
bp = *bpPtr;
|
||||
bp.addr += ModBaseFromAddr(CIP);
|
||||
//setBpActive(bp);
|
||||
|
||||
//if(bp.type == BPHARDWARE) //TODO: properly implement this (check debug registers)
|
||||
bp.active = true;
|
||||
//else
|
||||
// bp.active = MemIsValidReadPtr(bp.addr);
|
||||
|
||||
if(bpPtr->condition[0] != 0)
|
||||
{
|
||||
case UE_HARDWARE_SIZE_1:
|
||||
bpsize = "byte, ";
|
||||
break;
|
||||
case UE_HARDWARE_SIZE_2:
|
||||
bpsize = "word, ";
|
||||
break;
|
||||
case UE_HARDWARE_SIZE_4:
|
||||
bpsize = "dword, ";
|
||||
break;
|
||||
if(*(uint16*)bp.condition == 0x30) // short curcit for condition "0"
|
||||
condition = 0;
|
||||
else
|
||||
valfromstring(bp.condition, &condition); // if this fails, condition remains 1
|
||||
if(bp.fastResume && condition == 0) // fast resume : ignore GUI/Script/Plugin/Singleshoot/Other
|
||||
return;
|
||||
}
|
||||
if(bp.logText[0] == 0 && condition != 0)
|
||||
{
|
||||
switch (TITANGETSIZE(bp.titantype)) //size
|
||||
{
|
||||
case UE_HARDWARE_SIZE_1:
|
||||
bpsize = "byte, ";
|
||||
break;
|
||||
case UE_HARDWARE_SIZE_2:
|
||||
bpsize = "word, ";
|
||||
break;
|
||||
case UE_HARDWARE_SIZE_4:
|
||||
bpsize = "dword, ";
|
||||
break;
|
||||
#ifdef _WIN64
|
||||
case UE_HARDWARE_SIZE_8:
|
||||
bpsize = "qword, ";
|
||||
break;
|
||||
case UE_HARDWARE_SIZE_8:
|
||||
bpsize = "qword, ";
|
||||
break;
|
||||
#endif //_WIN64
|
||||
}
|
||||
const char* bptype = "";
|
||||
switch(TITANGETTYPE(bp.titantype)) //type
|
||||
{
|
||||
case UE_HARDWARE_EXECUTE:
|
||||
bptype = "execute";
|
||||
bpsize = "";
|
||||
break;
|
||||
case UE_HARDWARE_READWRITE:
|
||||
bptype = "read/write";
|
||||
break;
|
||||
case UE_HARDWARE_WRITE:
|
||||
bptype = "write";
|
||||
break;
|
||||
}
|
||||
const char* symbolicname = SymGetSymbolicName(bp.addr);
|
||||
if(symbolicname)
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("Hardware breakpoint (%s%s) \"%s\" at %s (" fhex ")!\n", bpsize, bptype, bp.name, symbolicname, bp.addr);
|
||||
}
|
||||
const char* bptype = "";
|
||||
switch (TITANGETTYPE(bp.titantype)) //type
|
||||
{
|
||||
case UE_HARDWARE_EXECUTE:
|
||||
bptype = "execute";
|
||||
bpsize = "";
|
||||
break;
|
||||
case UE_HARDWARE_READWRITE:
|
||||
bptype = "read/write";
|
||||
break;
|
||||
case UE_HARDWARE_WRITE:
|
||||
bptype = "write";
|
||||
break;
|
||||
}
|
||||
const char* symbolicname = SymGetSymbolicName(bp.addr);
|
||||
if(symbolicname)
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("Hardware breakpoint (%s%s) \"%s\" at %s (" fhex ")!\n", bpsize, bptype, bp.name, symbolicname, bp.addr);
|
||||
else
|
||||
dprintf("Hardware breakpoint (%s%s) at %s (" fhex ")!\n", bpsize, bptype, symbolicname, bp.addr);
|
||||
}
|
||||
else
|
||||
dprintf("Hardware breakpoint (%s%s) at %s (" fhex ")!\n", bpsize, bptype, symbolicname, bp.addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("Hardware breakpoint (%s%s) \"%s\" at " fhex "!\n", bpsize, bptype, bp.name, bp.addr);
|
||||
else
|
||||
dprintf("Hardware breakpoint (%s%s) at " fhex "!\n", bpsize, bptype, bp.addr);
|
||||
}
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("Hardware breakpoint (%s%s) \"%s\" at " fhex "!\n", bpsize, bptype, bp.name, bp.addr);
|
||||
else
|
||||
dprintf("Hardware breakpoint (%s%s) at " fhex "!\n", bpsize, bptype, bp.addr);
|
||||
}
|
||||
} // else: BreakpointProlog outputs the log.
|
||||
if(bp.singleshoot)
|
||||
BpDelete(bp.addr, BPHARDWARE);
|
||||
BpToBridge(&bp, &pluginBp);
|
||||
bpInfo.breakpoint = &pluginBp;
|
||||
}
|
||||
GuiSetDebugState(paused);
|
||||
DebugUpdateGui(cip, true);
|
||||
//lock
|
||||
lock(WAITID_RUN);
|
||||
SetForegroundWindow(GuiGetWindowHandle());
|
||||
bSkipExceptions = false;
|
||||
PLUG_CB_PAUSEDEBUG pauseInfo;
|
||||
pauseInfo.reserved = 0;
|
||||
plugincbcall(CB_PAUSEDEBUG, &pauseInfo);
|
||||
plugincbcall(CB_BREAKPOINT, &bpInfo);
|
||||
wait(WAITID_RUN);
|
||||
BreakpointProlog(condition, bp, bpInfo);
|
||||
}
|
||||
|
||||
void cbMemoryBreakpoint(void* ExceptionAddress)
|
||||
{
|
||||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
duint cip = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
duint size;
|
||||
duint base = MemFindBaseAddr((duint)ExceptionAddress, &size, true);
|
||||
BREAKPOINT* bpPtr;
|
||||
BREAKPOINT bp;
|
||||
BRIDGEBP pluginBp;
|
||||
PLUG_CB_BREAKPOINT bpInfo;
|
||||
bpInfo.breakpoint = 0;
|
||||
if(!BpGet(base, BPMEMORY, 0, &bp))
|
||||
duint size;
|
||||
duint base = MemFindBaseAddr((duint)ExceptionAddress, &size, true);
|
||||
ULONG_PTR CIP;
|
||||
duint condition = 1;
|
||||
memset(&bpInfo, 0, sizeof(bpInfo));
|
||||
CIP = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
bpPtr = BpInfoFromAddr(BPMEMORY, base);
|
||||
if(!(bpPtr && bpPtr->enabled))
|
||||
dputs("Memory breakpoint reached not in list!");
|
||||
else
|
||||
{
|
||||
const char* bptype = "";
|
||||
switch(bp.titantype)
|
||||
// increment hit count
|
||||
InterlockedIncrement(&bpPtr->hitcount);
|
||||
// condition eval
|
||||
bp = *bpPtr;
|
||||
bp.addr += ModBaseFromAddr(CIP);
|
||||
//setBpActive(bp);
|
||||
|
||||
//if(bp.type == BPHARDWARE) //TODO: properly implement this (check debug registers)
|
||||
// bp.active = true;
|
||||
//else
|
||||
bp.active = MemIsValidReadPtr(bp.addr);
|
||||
|
||||
if(bpPtr->condition[0] != 0)
|
||||
{
|
||||
case UE_MEMORY_READ:
|
||||
bptype = " (read)";
|
||||
break;
|
||||
case UE_MEMORY_WRITE:
|
||||
bptype = " (write)";
|
||||
break;
|
||||
case UE_MEMORY_EXECUTE:
|
||||
bptype = " (execute)";
|
||||
break;
|
||||
case UE_MEMORY:
|
||||
bptype = " (read/write/execute)";
|
||||
break;
|
||||
}
|
||||
const char* symbolicname = SymGetSymbolicName(bp.addr);
|
||||
if(symbolicname)
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("Memory breakpoint%s \"%s\" at %s (" fhex ", " fhex ")!\n", bptype, bp.name, symbolicname, bp.addr, ExceptionAddress);
|
||||
if(*(uint16*)bp.condition == 0x30) // short curcit for condition "0"
|
||||
condition = 0;
|
||||
else
|
||||
dprintf("Memory breakpoint%s at %s (" fhex ", " fhex ")!\n", bptype, symbolicname, bp.addr, ExceptionAddress);
|
||||
valfromstring(bp.condition, &condition); // if this fails, condition remains 1
|
||||
if(bp.fastResume && condition == 0) // fast resume : ignore GUI/Script/Plugin/Singleshoot/Other
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(bp.logText[0] == 0 && condition!=0)
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("Memory breakpoint%s \"%s\" at " fhex " (" fhex ")!\n", bptype, bp.name, bp.addr, ExceptionAddress);
|
||||
const char* bptype = "";
|
||||
switch (bp.titantype)
|
||||
{
|
||||
case UE_MEMORY_READ:
|
||||
bptype = " (read)";
|
||||
break;
|
||||
case UE_MEMORY_WRITE:
|
||||
bptype = " (write)";
|
||||
break;
|
||||
case UE_MEMORY_EXECUTE:
|
||||
bptype = " (execute)";
|
||||
break;
|
||||
case UE_MEMORY:
|
||||
bptype = " (read/write/execute)";
|
||||
break;
|
||||
}
|
||||
const char* symbolicname = SymGetSymbolicName(bp.addr);
|
||||
if(symbolicname)
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("Memory breakpoint%s \"%s\" at %s (" fhex ", " fhex ")!\n", bptype, bp.name, symbolicname, bp.addr, ExceptionAddress);
|
||||
else
|
||||
dprintf("Memory breakpoint%s at %s (" fhex ", " fhex ")!\n", bptype, symbolicname, bp.addr, ExceptionAddress);
|
||||
}
|
||||
else
|
||||
dprintf("Memory breakpoint%s at " fhex " (" fhex ")!\n", bptype, bp.addr, ExceptionAddress);
|
||||
}
|
||||
{
|
||||
if(*bp.name)
|
||||
dprintf("Memory breakpoint%s \"%s\" at " fhex " (" fhex ")!\n", bptype, bp.name, bp.addr, ExceptionAddress);
|
||||
else
|
||||
dprintf("Memory breakpoint%s at " fhex " (" fhex ")!\n", bptype, bp.addr, ExceptionAddress);
|
||||
}
|
||||
} // else: BreakpointProlog outputs the log.
|
||||
BpToBridge(&bp, &pluginBp);
|
||||
bpInfo.breakpoint = &pluginBp;
|
||||
}
|
||||
if(bp.singleshoot)
|
||||
BpDelete(bp.addr, BPMEMORY); //delete from breakpoint list
|
||||
GuiSetDebugState(paused);
|
||||
DebugUpdateGui(cip, true);
|
||||
//lock
|
||||
lock(WAITID_RUN);
|
||||
SetForegroundWindow(GuiGetWindowHandle());
|
||||
bSkipExceptions = false;
|
||||
PLUG_CB_PAUSEDEBUG pauseInfo;
|
||||
pauseInfo.reserved = 0;
|
||||
plugincbcall(CB_PAUSEDEBUG, &pauseInfo);
|
||||
plugincbcall(CB_BREAKPOINT, &bpInfo);
|
||||
wait(WAITID_RUN);
|
||||
BreakpointProlog(condition, bp, bpInfo);
|
||||
}
|
||||
|
||||
void cbLibrarianBreakpoint(void* lpData)
|
||||
|
|
|
@ -115,4 +115,7 @@ extern char szSymbolCachePath[MAX_PATH];
|
|||
extern bool bUndecorateSymbolNames;
|
||||
extern bool bEnableSourceDebugging;
|
||||
|
||||
//private
|
||||
void BreakpointProlog(duint condition, BREAKPOINT& bp, PLUG_CB_BREAKPOINT& bpInfo);
|
||||
|
||||
#endif // _DEBUGGER_H
|
||||
|
|
|
@ -445,6 +445,352 @@ CMDRESULT cbDebugDisableBPX(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
CMDRESULT cbDebugSetBPXConditionCommon(BP_TYPE Type, int argc, char* argv[])
|
||||
{
|
||||
BREAKPOINT bp;
|
||||
if(argc < 2)
|
||||
{
|
||||
dprintf("not enough arguments!\n");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
else if(argc == 2)
|
||||
{
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
if(!BpSetCondition(bp.addr, Type, ""))
|
||||
{
|
||||
dprintf("Can't set condition on breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
BpSetCondition(bp.addr, Type, argv[2]);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXLogCommon(BP_TYPE Type, int argc, char* argv[])
|
||||
{
|
||||
BREAKPOINT bp;
|
||||
if(argc < 2)
|
||||
{
|
||||
dprintf("not enough arguments!\n");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
else if(argc == 2)
|
||||
{
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
if(!(BpSetLogText(bp.addr, Type, "")))
|
||||
{
|
||||
dprintf("Can't set logging text on breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
BpSetLogText(bp.addr, Type, argv[2]);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXCommandCommon(BP_TYPE Type, int argc, char* argv[])
|
||||
{
|
||||
BREAKPOINT bp;
|
||||
if(argc < 2)
|
||||
{
|
||||
dprintf("not enough arguments!\n");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
else if(argc == 2)
|
||||
{
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
if(!BpSetHitCommand(bp.addr, Type, ""))
|
||||
{
|
||||
dprintf("Can't set command on hit on breakpoint \"%s\"", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
if(!(BpSetHitCommand(bp.addr, Type, argv[2])))
|
||||
{
|
||||
dprintf("Can't set command on hit on breakpoint \"%s\"", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugGetBPXHitCountCommon(BP_TYPE Type, int argc, char* argv[])
|
||||
{
|
||||
BREAKPOINT bp;
|
||||
if(argc < 2)
|
||||
{
|
||||
dprintf("not enough arguments!\n");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
else if(argc == 2)
|
||||
{
|
||||
duint result;
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
//result = BpGetHitCount(bp.addr, bp.type);
|
||||
result = bp.hitcount; // improving performance
|
||||
varset("$result", result, false);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("Too much arguments!\n");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugResetBPXHitCountCommon(BP_TYPE Type, int argc, char* argv[])
|
||||
{
|
||||
BREAKPOINT bp;
|
||||
if(argc < 2)
|
||||
{
|
||||
dprintf("not enough arguments!\n");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
else if(argc == 2)
|
||||
{
|
||||
duint result;
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
result = BpResetHitCount(bp.addr, bp.type, 0);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
duint value;
|
||||
if(!(valfromstring(argv[2], &value)))
|
||||
{
|
||||
dprintf("Invalid expression \"%1\"", argv[2]);
|
||||
}
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
if(!(BpResetHitCount(bp.addr, Type, (uint32)value)))
|
||||
{
|
||||
dprintf("Can't set command on hit on breakpoint \"%s\"", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CMDRESULT cbDebugSetBPXFastResumeCommon(BP_TYPE Type, int argc, char* argv[]){
|
||||
BREAKPOINT bp;
|
||||
if(argc < 2)
|
||||
{
|
||||
dprintf("not enough arguments!\n");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
else if(argc == 2)
|
||||
{
|
||||
duint value;
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
if(!valfromstring(argv[2], &value))
|
||||
{
|
||||
dprintf("Invalid expression \"%1\"", argv[2]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!(BpSetFastResume(bp.addr, Type, true)))
|
||||
{
|
||||
dprintf("Can't set fast resume on breakpoint \"%1\"", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
duint result;
|
||||
if(!(valfromstring(argv[2], &result)))
|
||||
{
|
||||
dprintf("Invalid expression \"%1\"", argv[2]);
|
||||
}
|
||||
if(BpGetAny(Type, argv[1], &bp))
|
||||
{
|
||||
if(!(BpSetFastResume(bp.addr, Type, result != 0)))
|
||||
{
|
||||
dprintf("Can't set fast resume on breakpoint \"%1\"", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXCondition(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXConditionCommon(BPNORMAL, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXLog(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXLogCommon(BPNORMAL, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXCommand(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXCommandCommon(BPNORMAL, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXFastResume(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXFastResumeCommon(BPNORMAL, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugResetBPXHitCount(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugResetBPXHitCountCommon(BPNORMAL, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugGetBPXHitCount(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugGetBPXHitCountCommon(BPNORMAL, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXHardwareCondition(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXConditionCommon(BPHARDWARE, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXHardwareLog(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXLogCommon(BPHARDWARE, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXHardwareCommand(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXCommandCommon(BPHARDWARE, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXHardwareFastResume(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXFastResumeCommon(BPHARDWARE, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugResetBPXHardwareHitCount(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugResetBPXHitCountCommon(BPHARDWARE, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugGetBPXHardwareHitCount(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugGetBPXHitCountCommon(BPHARDWARE, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXMemoryCondition(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXConditionCommon(BPMEMORY, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXMemoryLog(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXLogCommon(BPMEMORY, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXMemoryCommand(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXCommandCommon(BPMEMORY, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugResetBPXMemoryHitCount(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXFastResumeCommon(BPMEMORY, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetBPXMemoryFastResume(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugResetBPXHitCountCommon(BPMEMORY, argc, argv);
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugGetBPXMemoryHitCount(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugGetBPXHitCountCommon(BPMEMORY, argc, argv);
|
||||
}
|
||||
CMDRESULT cbDebugSetHardwareBreakpoint(int argc, char* argv[])
|
||||
{
|
||||
if(argc < 2)
|
||||
|
@ -2151,4 +2497,4 @@ CMDRESULT cbDebugSetfreezestack(int argc, char* argv[])
|
|||
dbgsetfreezestack(freeze);
|
||||
dprintf("Stack is now %s\n", freeze ? "freezed" : "unfreezed");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,32 @@ CMDRESULT cbDebugSetBPX(int argc, char* argv[]);
|
|||
CMDRESULT cbDebugDeleteBPX(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugEnableBPX(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugDisableBPX(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXCondition(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXLog(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXCommand(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugGetBPXHitCount(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXFastResume(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugResetBPXHitCount(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetHardwareBreakpoint(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugDeleteHardwareBreakpoint(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugEnableHardwareBreakpoint(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugDisableHardwareBreakpoint(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXHardwareCondition(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXHardwareLog(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXHardwareCommand(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugGetBPXHardwareHitCount(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXHardwareFastResume(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugResetBPXHardwareHitCount(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetMemoryBpx(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugDeleteMemoryBreakpoint(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugEnableMemoryBreakpoint(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugDisableMemoryBreakpoint(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXMemoryCondition(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXMemoryLog(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXMemoryCommand(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugGetBPXMemoryHitCount(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetBPXMemoryFastResume(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugResetBPXMemoryHitCount(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugBplist(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugStepInto(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugeStepInto(int argc, char* argv[]);
|
||||
|
@ -69,4 +87,4 @@ CMDRESULT cbDebugSetfreezestack(int argc, char* argv[]);
|
|||
//misc
|
||||
void showcommandlineerror(cmdline_error_t* cmdline_error);
|
||||
|
||||
#endif //_DEBUGGER_COMMANDS_H
|
||||
#endif //_DEBUGGER_COMMANDS_H
|
||||
|
|
|
@ -1683,7 +1683,7 @@ bool valfromstring_noexpr(const char* string, duint* value, bool silent, bool ba
|
|||
/**
|
||||
\brief Gets a value from a string. This function can parse expressions, memory locations, registers, flags, API names, labels, symbols and variables.
|
||||
\param string The string to parse.
|
||||
\param [out] value The value of the expression. This value cannot be null.
|
||||
\param [out] value The value of the expression. This value cannot be null. When the expression is invalid, value is not changed.
|
||||
\param silent true to not output anything to the console.
|
||||
\param baseonly true to skip parsing API names, labels, symbols and variables (basic expressions only).
|
||||
\param [out] value_size This function can output the value size parsed (for example memory location size or register size). Can be null.
|
||||
|
|
|
@ -124,6 +124,24 @@ static void registercommands()
|
|||
dbgcmdnew("DeleteMemoryBPX\1membpc\1bpmc", cbDebugDeleteMemoryBreakpoint, true); //delete memory breakpoint
|
||||
dbgcmdnew("EnableMemoryBreakpoint\1membpe\1bpme", cbDebugEnableMemoryBreakpoint, true); //enable memory breakpoint
|
||||
dbgcmdnew("DisableMemoryBreakpoint\1membpd\1bpmd", cbDebugDisableMemoryBreakpoint, true); //enable memory breakpoint
|
||||
dbgcmdnew("SetBreakpointCondition\1bpcond", cbDebugSetBPXCondition, true); //set breakpoint condition
|
||||
dbgcmdnew("SetBreakpointLog\1bplog", cbDebugSetBPXLog, true); //set breakpoint log
|
||||
dbgcmdnew("SetBreakpointCommand", cbDebugSetBPXCommand, true); //set breakpoint command on hit
|
||||
dbgcmdnew("SetBreakpointFastResume", cbDebugSetBPXFastResume, true); //set breakpoint fast resume
|
||||
dbgcmdnew("GetBreakpointHitCount", cbDebugGetBPXHitCount, true); //get breakpoint hit count
|
||||
dbgcmdnew("ResetBreakpointHitCount", cbDebugResetBPXHitCount, true); //reset breakpoint hit count
|
||||
dbgcmdnew("SetHardwareBreakpointCondition\1bphwcond", cbDebugSetBPXHardwareCondition, true); //set breakpoint condition
|
||||
dbgcmdnew("SetHardwareBreakpointLog\1bphwlog", cbDebugSetBPXHardwareLog, true); //set breakpoint log
|
||||
dbgcmdnew("SetHardwareBreakpointCommand", cbDebugSetBPXHardwareCommand, true); //set breakpoint command on hit
|
||||
dbgcmdnew("SetHardwareBreakpointFastResume", cbDebugSetBPXHardwareFastResume, true); //set breakpoint fast resume
|
||||
dbgcmdnew("GetHardwareBreakpointHitCount", cbDebugGetBPXHardwareHitCount, true); //get breakpoint hit count
|
||||
dbgcmdnew("ResetHardwareBreakpointHitCount", cbDebugResetBPXHardwareHitCount, true); //reset breakpoint hit count
|
||||
dbgcmdnew("SetMemoryBreakpointCondition\1bpmcond", cbDebugSetBPXMemoryCondition, true); //set breakpoint condition
|
||||
dbgcmdnew("SetMemoryBreakpointLog\1bpmlog", cbDebugSetBPXMemoryLog, true); //set breakpoint log
|
||||
dbgcmdnew("SetMemoryBreakpointCommand", cbDebugSetBPXMemoryCommand, true); //set breakpoint command on hit
|
||||
dbgcmdnew("SetMemoryBreakpointFastResume", cbDebugSetBPXMemoryFastResume, true); //set breakpoint fast resume
|
||||
dbgcmdnew("SetMemoryGetBreakpointHitCount", cbDebugGetBPXMemoryHitCount, true); //get breakpoint hit count
|
||||
dbgcmdnew("ResetMemoryBreakpointHitCount", cbDebugResetBPXMemoryHitCount, true); //reset breakpoint hit count
|
||||
|
||||
//variables
|
||||
dbgcmdnew("varnew\1var", cbInstrVar, false); //make a variable arg1:name,[arg2:value]
|
||||
|
@ -500,7 +518,7 @@ extern "C" DLL_EXPORT void _dbg_dbgexitsignal()
|
|||
if(memleaks())
|
||||
dprintf("%d memory leak(s) found!\n", memleaks());
|
||||
else
|
||||
DeleteFileA(alloctrace);
|
||||
DeleteFileW(StringUtils::Utf8ToUtf16(alloctrace).c_str());
|
||||
dputs("Cleaning up wait objects...");
|
||||
waitdeinitialize();
|
||||
dputs("Cleaning up debugger threads...");
|
||||
|
@ -529,4 +547,4 @@ extern "C" DLL_EXPORT bool _dbg_dbgcmddirectexec(const char* cmd)
|
|||
bool dbgisstopped()
|
||||
{
|
||||
return bIsStopped;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -304,7 +304,8 @@ bool CapstoneTokenizer::tokenizeMnemonic()
|
|||
type = TokenType::MnemonicNop;
|
||||
else if(_cp.IsInt3())
|
||||
type = TokenType::MnemonicInt3;
|
||||
else if(_cp.InGroup(CS_GRP_PRIVILEGE) || _cp.InGroup(CS_GRP_IRET) || _cp.InGroup(CS_GRP_INVALID))
|
||||
else if(_cp.InGroup(CS_GRP_PRIVILEGE) || _cp.InGroup(CS_GRP_IRET) || _cp.InGroup(CS_GRP_INVALID)
|
||||
|| id == X86_INS_RDTSC || id == X86_INS_SYSCALL || id == X86_INS_SYSENTER || id == X86_INS_CPUID || id == X86_INS_RDRAND || id == X86_INS_RDTSCP)
|
||||
type = TokenType::MnemonicUnusual;
|
||||
else
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Configuration.h"
|
||||
#include "Bridge.h"
|
||||
#include "Breakpoints.h"
|
||||
#include "LineEditDialog.h"
|
||||
|
||||
BreakpointsView::BreakpointsView(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
|
@ -13,6 +14,11 @@ BreakpointsView::BreakpointsView(QWidget* parent) : QWidget(parent)
|
|||
mSoftBPTable->addColumnAt(8 + wCharWidth * 32, tr("Name"), false);
|
||||
mSoftBPTable->addColumnAt(8 + wCharWidth * 32, tr("Module/Label"), false);
|
||||
mSoftBPTable->addColumnAt(8 + wCharWidth * 8, tr("State"), false);
|
||||
mSoftBPTable->addColumnAt(8 + wCharWidth * 10, tr("Hit count"), false);
|
||||
mSoftBPTable->addColumnAt(8 + wCharWidth * 32, tr("Log text"), false);
|
||||
mSoftBPTable->addColumnAt(8 + wCharWidth * 32, tr("Condition"), false);
|
||||
mSoftBPTable->addColumnAt(8 + wCharWidth * 2, tr("Fast resume"), false);
|
||||
mSoftBPTable->addColumnAt(8 + wCharWidth * 16, tr("Command on hit"), false);
|
||||
mSoftBPTable->addColumnAt(wCharWidth * 10, tr("Comment"), false);
|
||||
|
||||
// Hardware
|
||||
|
@ -22,6 +28,11 @@ BreakpointsView::BreakpointsView(QWidget* parent) : QWidget(parent)
|
|||
mHardBPTable->addColumnAt(8 + wCharWidth * 32, tr("Name"), false);
|
||||
mHardBPTable->addColumnAt(8 + wCharWidth * 32, tr("Module/Label"), false);
|
||||
mHardBPTable->addColumnAt(8 + wCharWidth * 8, tr("State"), false);
|
||||
mHardBPTable->addColumnAt(8 + wCharWidth * 10, tr("Hit count"), false);
|
||||
mHardBPTable->addColumnAt(8 + wCharWidth * 32, tr("Log text"), false);
|
||||
mHardBPTable->addColumnAt(8 + wCharWidth * 32, tr("Condition"), false);
|
||||
mHardBPTable->addColumnAt(8 + wCharWidth * 2, tr("Fast resume"), false);
|
||||
mHardBPTable->addColumnAt(8 + wCharWidth * 16, tr("Command on hit"), false);
|
||||
mHardBPTable->addColumnAt(wCharWidth * 10, tr("Comment"), false);
|
||||
|
||||
// Memory
|
||||
|
@ -31,6 +42,11 @@ BreakpointsView::BreakpointsView(QWidget* parent) : QWidget(parent)
|
|||
mMemBPTable->addColumnAt(8 + wCharWidth * 32, tr("Name"), false);
|
||||
mMemBPTable->addColumnAt(8 + wCharWidth * 32, tr("Module/Label"), false);
|
||||
mMemBPTable->addColumnAt(8 + wCharWidth * 8, tr("State"), false);
|
||||
mMemBPTable->addColumnAt(8 + wCharWidth * 10, tr("Hit count"), false);
|
||||
mMemBPTable->addColumnAt(8 + wCharWidth * 32, tr("Log text"), false);
|
||||
mMemBPTable->addColumnAt(8 + wCharWidth * 32, tr("Condition"), false);
|
||||
mMemBPTable->addColumnAt(8 + wCharWidth * 2, tr("Fast resume"), false);
|
||||
mMemBPTable->addColumnAt(8 + wCharWidth * 16, tr("Command on hit"), false);
|
||||
mMemBPTable->addColumnAt(wCharWidth * 10, tr("Comment"), false);
|
||||
|
||||
// Splitter
|
||||
|
@ -48,6 +64,7 @@ BreakpointsView::BreakpointsView(QWidget* parent) : QWidget(parent)
|
|||
this->setLayout(mVertLayout);
|
||||
|
||||
// Create the action list for the right click context menu
|
||||
setupCondBPRightClickContextMenu();
|
||||
setupHardBPRightClickContextMenu();
|
||||
setupSoftBPRightClickContextMenu();
|
||||
setupMemBPRightClickContextMenu();
|
||||
|
@ -98,16 +115,23 @@ void BreakpointsView::reloadData()
|
|||
else
|
||||
mHardBPTable->setCellContent(wI, 3, tr("Disabled"));
|
||||
|
||||
char comment[MAX_COMMENT_SIZE] = "";
|
||||
if(DbgGetCommentAt(wBPList.bp[wI].addr, comment))
|
||||
mHardBPTable->setCellContent(wI, 4, QString("%1").arg(wBPList.bp[wI].hitCount));
|
||||
mHardBPTable->setCellContent(wI, 5, QString().fromUtf8(wBPList.bp[wI].log));
|
||||
mHardBPTable->setCellContent(wI, 6, QString().fromUtf8(wBPList.bp[wI].condition));
|
||||
mHardBPTable->setCellContent(wI, 7, wBPList.bp[wI].fastResume ? "X" : "");
|
||||
mHardBPTable->setCellContent(wI, 8, QString().fromUtf8(wBPList.bp[wI].hitCmd));
|
||||
|
||||
char text[MAX_COMMENT_SIZE] = "";
|
||||
if(DbgGetCommentAt(wBPList.bp[wI].addr, text))
|
||||
{
|
||||
if(comment[0] == '\1') //automatic comment
|
||||
mHardBPTable->setCellContent(wI, 4, QString(comment + 1));
|
||||
if(text[0] == '\1') //automatic comment
|
||||
mHardBPTable->setCellContent(wI, 9, QString(text + 1));
|
||||
else
|
||||
mHardBPTable->setCellContent(wI, 4, comment);
|
||||
mHardBPTable->setCellContent(wI, 9, QString().fromUtf8(text));
|
||||
}
|
||||
else
|
||||
mHardBPTable->setCellContent(wI, 4, "");
|
||||
mHardBPTable->setCellContent(wI, 9, "");
|
||||
|
||||
}
|
||||
mHardBPTable->reloadData();
|
||||
if(wBPList.count)
|
||||
|
@ -137,16 +161,22 @@ void BreakpointsView::reloadData()
|
|||
else
|
||||
mSoftBPTable->setCellContent(wI, 3, tr("Disabled"));
|
||||
|
||||
mSoftBPTable->setCellContent(wI, 4, QString("%1").arg(wBPList.bp[wI].hitCount));
|
||||
mSoftBPTable->setCellContent(wI, 5, QString().fromUtf8(wBPList.bp[wI].log));
|
||||
mSoftBPTable->setCellContent(wI, 6, QString().fromUtf8(wBPList.bp[wI].condition));
|
||||
mSoftBPTable->setCellContent(wI, 7, wBPList.bp[wI].fastResume ? "X" : "");
|
||||
mSoftBPTable->setCellContent(wI, 8, QString().fromUtf8(wBPList.bp[wI].hitCmd));
|
||||
|
||||
char comment[MAX_COMMENT_SIZE] = "";
|
||||
if(DbgGetCommentAt(wBPList.bp[wI].addr, comment))
|
||||
{
|
||||
if(comment[0] == '\1') //automatic comment
|
||||
mSoftBPTable->setCellContent(wI, 4, QString(comment + 1));
|
||||
mSoftBPTable->setCellContent(wI, 9, QString(comment + 1));
|
||||
else
|
||||
mSoftBPTable->setCellContent(wI, 4, comment);
|
||||
mSoftBPTable->setCellContent(wI, 9, QString().fromUtf8(comment));
|
||||
}
|
||||
else
|
||||
mSoftBPTable->setCellContent(wI, 4, "");
|
||||
mSoftBPTable->setCellContent(wI, 9, "");
|
||||
}
|
||||
mSoftBPTable->reloadData();
|
||||
if(wBPList.count)
|
||||
|
@ -176,16 +206,22 @@ void BreakpointsView::reloadData()
|
|||
else
|
||||
mMemBPTable->setCellContent(wI, 3, tr("Disabled"));
|
||||
|
||||
mMemBPTable->setCellContent(wI, 4, QString("%1").arg(wBPList.bp[wI].hitCount));
|
||||
mMemBPTable->setCellContent(wI, 5, QString().fromUtf8(wBPList.bp[wI].log));
|
||||
mMemBPTable->setCellContent(wI, 6, QString().fromUtf8(wBPList.bp[wI].condition));
|
||||
mMemBPTable->setCellContent(wI, 7, wBPList.bp[wI].fastResume ? "X" : "");
|
||||
mMemBPTable->setCellContent(wI, 8, QString().fromUtf8(wBPList.bp[wI].hitCmd));
|
||||
|
||||
char comment[MAX_COMMENT_SIZE] = "";
|
||||
if(DbgGetCommentAt(wBPList.bp[wI].addr, comment))
|
||||
{
|
||||
if(comment[0] == '\1') //automatic comment
|
||||
mMemBPTable->setCellContent(wI, 4, QString(comment + 1));
|
||||
mMemBPTable->setCellContent(wI, 9, QString(comment + 1));
|
||||
else
|
||||
mMemBPTable->setCellContent(wI, 4, comment);
|
||||
mMemBPTable->setCellContent(wI, 9, QString().fromUtf8(comment));
|
||||
}
|
||||
else
|
||||
mMemBPTable->setCellContent(wI, 4, "");
|
||||
mMemBPTable->setCellContent(wI, 9, "");
|
||||
}
|
||||
mMemBPTable->reloadData();
|
||||
|
||||
|
@ -214,6 +250,11 @@ void BreakpointsView::setupHardBPRightClickContextMenu()
|
|||
mHardBPEnableDisableAction->setShortcutContext(Qt::WidgetShortcut);
|
||||
mHardBPTable->addAction(mHardBPEnableDisableAction);
|
||||
connect(mHardBPEnableDisableAction, SIGNAL(triggered()), this, SLOT(enableDisableHardBPActionSlot()));
|
||||
|
||||
// Reset hit count
|
||||
mHardBPResetHitCountAction = new QAction(tr("Reset hit count"), this);
|
||||
mHardBPTable->addAction(mHardBPResetHitCountAction);
|
||||
connect(mHardBPResetHitCountAction, SIGNAL(triggered()), this, SLOT(resetHardwareHitCountSlot()));
|
||||
}
|
||||
|
||||
void BreakpointsView::refreshShortcutsSlot()
|
||||
|
@ -268,6 +309,11 @@ void BreakpointsView::hardwareBPContextMenuSlot(const QPoint & pos)
|
|||
if(wBPList.count)
|
||||
BridgeFree(wBPList.bp);
|
||||
|
||||
// Conditional
|
||||
CurrentType = 2;
|
||||
wMenu->addMenu(mConditionalBreakpointMenu);
|
||||
wMenu->addAction(mHardBPResetHitCountAction);
|
||||
|
||||
// Separator
|
||||
wMenu->addSeparator();
|
||||
|
||||
|
@ -314,6 +360,13 @@ void BreakpointsView::doubleClickHardwareSlot()
|
|||
emit showCpu();
|
||||
}
|
||||
|
||||
void BreakpointsView::resetHardwareHitCountSlot()
|
||||
{
|
||||
StdTable* table = mHardBPTable;
|
||||
QString addrText = table->getCellContent(table->getInitialSelection(), 0);
|
||||
DbgCmdExecDirect(QString("ResetHardwareBreakpointHitCount " + addrText).toUtf8().constData());
|
||||
reloadData();
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Software Context Menu Management
|
||||
|
@ -336,6 +389,11 @@ void BreakpointsView::setupSoftBPRightClickContextMenu()
|
|||
mSoftBPTable->addAction(mSoftBPEnableDisableAction);
|
||||
connect(mSoftBPEnableDisableAction, SIGNAL(triggered()), this, SLOT(enableDisableSoftBPActionSlot()));
|
||||
|
||||
// Reset hit count
|
||||
mSoftBPResetHitCountAction = new QAction(tr("Reset hit count"), this);
|
||||
mSoftBPTable->addAction(mSoftBPResetHitCountAction);
|
||||
connect(mSoftBPResetHitCountAction, SIGNAL(triggered()), this, SLOT(resetSoftwareHitCountSlot()));
|
||||
|
||||
// Enable All
|
||||
mSoftBPEnableAllAction = new QAction(tr("Enable All"), this);
|
||||
mSoftBPTable->addAction(mSoftBPEnableAllAction);
|
||||
|
@ -387,6 +445,11 @@ void BreakpointsView::softwareBPContextMenuSlot(const QPoint & pos)
|
|||
if(wBPList.count)
|
||||
BridgeFree(wBPList.bp);
|
||||
|
||||
// Conditional
|
||||
CurrentType = 1;
|
||||
wMenu->addMenu(mConditionalBreakpointMenu);
|
||||
wMenu->addAction(mSoftBPResetHitCountAction);
|
||||
|
||||
// Separator
|
||||
wMenu->addSeparator();
|
||||
|
||||
|
@ -449,6 +512,13 @@ void BreakpointsView::doubleClickSoftwareSlot()
|
|||
emit showCpu();
|
||||
}
|
||||
|
||||
void BreakpointsView::resetSoftwareHitCountSlot()
|
||||
{
|
||||
StdTable* table = mSoftBPTable;
|
||||
QString addrText = table->getCellContent(table->getInitialSelection(), 0);
|
||||
DbgCmdExecDirect(QString("ResetSoftwareBreakpointHitCount " + addrText).toUtf8().constData());
|
||||
reloadData();
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Memory Context Menu Management
|
||||
|
@ -470,6 +540,11 @@ void BreakpointsView::setupMemBPRightClickContextMenu()
|
|||
mMemBPEnableDisableAction->setShortcutContext(Qt::WidgetShortcut);
|
||||
mMemBPTable->addAction(mMemBPEnableDisableAction);
|
||||
connect(mMemBPEnableDisableAction, SIGNAL(triggered()), this, SLOT(enableDisableMemBPActionSlot()));
|
||||
|
||||
// Reset hit count
|
||||
mMemBPResetHitCountAction = new QAction(tr("Reset hit count"), this);
|
||||
mMemBPTable->addAction(mMemBPResetHitCountAction);
|
||||
connect(mMemBPResetHitCountAction, SIGNAL(triggered()), this, SLOT(resetMemoryHitCountSlot()));
|
||||
}
|
||||
|
||||
void BreakpointsView::memoryBPContextMenuSlot(const QPoint & pos)
|
||||
|
@ -512,6 +587,11 @@ void BreakpointsView::memoryBPContextMenuSlot(const QPoint & pos)
|
|||
if(wBPList.count)
|
||||
BridgeFree(wBPList.bp);
|
||||
|
||||
// Conditional
|
||||
CurrentType = 3;
|
||||
wMenu->addMenu(mConditionalBreakpointMenu);
|
||||
wMenu->addAction(mMemBPResetHitCountAction);
|
||||
|
||||
// Separator
|
||||
wMenu->addSeparator();
|
||||
|
||||
|
@ -557,3 +637,200 @@ void BreakpointsView::doubleClickMemorySlot()
|
|||
DbgCmdExecDirect(QString("disasm " + addrText).toUtf8().constData());
|
||||
emit showCpu();
|
||||
}
|
||||
|
||||
void BreakpointsView::resetMemoryHitCountSlot()
|
||||
{
|
||||
StdTable* table = mMemBPTable;
|
||||
QString addrText = table->getCellContent(table->getInitialSelection(), 0);
|
||||
DbgCmdExecDirect(QString("ResetMemoryBreakpointHitCount " + addrText).toUtf8().constData());
|
||||
reloadData();
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
Conditional Breakpoint Context Menu Management (Sub-menu only)
|
||||
************************************************************************************/
|
||||
|
||||
void BreakpointsView::setupCondBPRightClickContextMenu()
|
||||
{
|
||||
mConditionalBreakpointMenu = new QMenu(tr("&Conditional/Logging"), this);
|
||||
|
||||
mConditionalSetCondition = new QAction(tr("&Condition..."), this);
|
||||
connect(mConditionalSetCondition, SIGNAL(triggered()), this, SLOT(setConditionSlot()));
|
||||
mConditionalBreakpointMenu->addAction(mConditionalSetCondition);
|
||||
|
||||
mConditionalSetFastResume = new QAction(tr("&Fast Resume"), this);
|
||||
connect(mConditionalSetFastResume, SIGNAL(triggered()), this, SLOT(setFastResumeSlot()));
|
||||
mConditionalBreakpointMenu->addAction(mConditionalSetFastResume);
|
||||
|
||||
mConditionalSetLog = new QAction(tr("&Log on hit..."), this);
|
||||
connect(mConditionalSetLog, SIGNAL(triggered()), this, SLOT(setLogSlot()));
|
||||
mConditionalBreakpointMenu->addAction(mConditionalSetLog);
|
||||
|
||||
mConditionalSetCmd = new QAction(tr("&Run command on hit..."), this);
|
||||
connect(mConditionalSetCmd, SIGNAL(triggered()), this, SLOT(setCmdSlot()));
|
||||
mConditionalBreakpointMenu->addAction(mConditionalSetCmd);
|
||||
}
|
||||
|
||||
void BreakpointsView::setConditionSlot()
|
||||
{
|
||||
QString addrText;
|
||||
QString currentText;
|
||||
LineEditDialog mLineEdit(this);
|
||||
switch(CurrentType)
|
||||
{
|
||||
case 1:
|
||||
addrText = mSoftBPTable->getCellContent(mSoftBPTable->getInitialSelection(), 0);
|
||||
currentText = mSoftBPTable->getCellContent(mSoftBPTable->getInitialSelection(), 6);
|
||||
break;
|
||||
case 2:
|
||||
addrText = mHardBPTable->getCellContent(mHardBPTable->getInitialSelection(), 0);
|
||||
currentText = mHardBPTable->getCellContent(mHardBPTable->getInitialSelection(), 6);
|
||||
break;
|
||||
case 3:
|
||||
addrText = mMemBPTable->getCellContent(mMemBPTable->getInitialSelection(), 0);
|
||||
currentText = mMemBPTable->getCellContent(mMemBPTable->getInitialSelection(), 6);
|
||||
break;
|
||||
default:
|
||||
__debugbreak();
|
||||
}
|
||||
mLineEdit.setText(currentText);
|
||||
mLineEdit.setWindowTitle(tr("Set break condition on ") + addrText);
|
||||
if(mLineEdit.exec() != QDialog::Accepted)
|
||||
return;
|
||||
currentText = mLineEdit.editText;
|
||||
switch(CurrentType)
|
||||
{
|
||||
case 1:
|
||||
DbgCmdExecDirect(QString("bpcond " + addrText + " , \"" + currentText + "\"").toUtf8().constData());
|
||||
break;
|
||||
case 2:
|
||||
DbgCmdExecDirect(QString("bphwcond " + addrText + " , \"" + currentText + "\"").toUtf8().constData());
|
||||
break;
|
||||
case 3:
|
||||
DbgCmdExecDirect(QString("bpmcond " + addrText + " , \"" + currentText + "\"").toUtf8().constData());
|
||||
break;
|
||||
}
|
||||
reloadData();
|
||||
}
|
||||
|
||||
void BreakpointsView::setLogSlot()
|
||||
{
|
||||
QString addrText;
|
||||
QString currentText;
|
||||
LineEditDialog mLineEdit(this);
|
||||
switch(CurrentType)
|
||||
{
|
||||
case 1:
|
||||
addrText = mSoftBPTable->getCellContent(mSoftBPTable->getInitialSelection(), 0);
|
||||
currentText = mSoftBPTable->getCellContent(mSoftBPTable->getInitialSelection(), 5);
|
||||
break;
|
||||
case 2:
|
||||
addrText = mHardBPTable->getCellContent(mHardBPTable->getInitialSelection(), 0);
|
||||
currentText = mHardBPTable->getCellContent(mHardBPTable->getInitialSelection(), 5);
|
||||
break;
|
||||
case 3:
|
||||
addrText = mMemBPTable->getCellContent(mMemBPTable->getInitialSelection(), 0);
|
||||
currentText = mMemBPTable->getCellContent(mMemBPTable->getInitialSelection(), 5);
|
||||
break;
|
||||
default:
|
||||
__debugbreak();
|
||||
}
|
||||
mLineEdit.setText(currentText);
|
||||
mLineEdit.setWindowTitle(tr("Set log string on ") + addrText);
|
||||
if(mLineEdit.exec() != QDialog::Accepted)
|
||||
return;
|
||||
currentText = mLineEdit.editText;
|
||||
switch(CurrentType)
|
||||
{
|
||||
case 1:
|
||||
DbgCmdExecDirect(QString("bplog " + addrText + " , \"" + currentText + "\"").toUtf8().constData());
|
||||
break;
|
||||
case 2:
|
||||
DbgCmdExecDirect(QString("bphwlog " + addrText + " , \"" + currentText + "\"").toUtf8().constData());
|
||||
break;
|
||||
case 3:
|
||||
DbgCmdExecDirect(QString("bpmlog " + addrText + " , \"" + currentText + "\"").toUtf8().constData());
|
||||
break;
|
||||
}
|
||||
reloadData();
|
||||
}
|
||||
|
||||
void BreakpointsView::setCmdSlot()
|
||||
{
|
||||
QString addrText;
|
||||
QString currentText;
|
||||
LineEditDialog mLineEdit(this);
|
||||
switch(CurrentType)
|
||||
{
|
||||
case 1:
|
||||
addrText = mSoftBPTable->getCellContent(mSoftBPTable->getInitialSelection(), 0);
|
||||
currentText = mSoftBPTable->getCellContent(mSoftBPTable->getInitialSelection(), 8);
|
||||
break;
|
||||
case 2:
|
||||
addrText = mHardBPTable->getCellContent(mHardBPTable->getInitialSelection(), 0);
|
||||
currentText = mHardBPTable->getCellContent(mHardBPTable->getInitialSelection(), 8);
|
||||
break;
|
||||
case 3:
|
||||
addrText = mMemBPTable->getCellContent(mMemBPTable->getInitialSelection(), 0);
|
||||
currentText = mMemBPTable->getCellContent(mMemBPTable->getInitialSelection(), 8);
|
||||
break;
|
||||
default:
|
||||
__debugbreak();
|
||||
}
|
||||
mLineEdit.setText(currentText);
|
||||
mLineEdit.setWindowTitle(tr("Set command to execute when hitting on ") + addrText);
|
||||
if(mLineEdit.exec() != QDialog::Accepted)
|
||||
return;
|
||||
currentText = mLineEdit.editText;
|
||||
switch(CurrentType)
|
||||
{
|
||||
case 1:
|
||||
DbgCmdExecDirect(QString("SetBreakpointCommand " + addrText + " , \"" + currentText + "\"").toUtf8().constData());
|
||||
break;
|
||||
case 2:
|
||||
DbgCmdExecDirect(QString("SetHardwareBreakpointCommand " + addrText + " , \"" + currentText + "\"").toUtf8().constData());
|
||||
break;
|
||||
case 3:
|
||||
DbgCmdExecDirect(QString("SetMemoryBreakpointCommand " + addrText + " , \"" + currentText + "\"").toUtf8().constData());
|
||||
break;
|
||||
}
|
||||
reloadData();
|
||||
}
|
||||
|
||||
void BreakpointsView::setFastResumeSlot()
|
||||
{
|
||||
QString addrText;
|
||||
QString currentText;
|
||||
switch(CurrentType)
|
||||
{
|
||||
case 1:
|
||||
addrText = mSoftBPTable->getCellContent(mSoftBPTable->getInitialSelection(), 0);
|
||||
currentText = mSoftBPTable->getCellContent(mSoftBPTable->getInitialSelection(), 7);
|
||||
break;
|
||||
case 2:
|
||||
addrText = mHardBPTable->getCellContent(mHardBPTable->getInitialSelection(), 0);
|
||||
currentText = mHardBPTable->getCellContent(mHardBPTable->getInitialSelection(), 7);
|
||||
break;
|
||||
case 3:
|
||||
addrText = mMemBPTable->getCellContent(mMemBPTable->getInitialSelection(), 0);
|
||||
currentText = mMemBPTable->getCellContent(mMemBPTable->getInitialSelection(), 7);
|
||||
break;
|
||||
default:
|
||||
__debugbreak();
|
||||
}
|
||||
currentText = currentText == "X" ? "0" : "1";
|
||||
switch(CurrentType)
|
||||
{
|
||||
case 1:
|
||||
DbgCmdExecDirect(QString("SetBreakpointFastResume " + addrText + " , " + currentText).toUtf8().constData());
|
||||
break;
|
||||
case 2:
|
||||
DbgCmdExecDirect(QString("SetHardwareBreakpointFastResume " + addrText + " , " + currentText).toUtf8().constData());
|
||||
break;
|
||||
case 3:
|
||||
DbgCmdExecDirect(QString("SetMemoryBreakpointFastResume " + addrText + " , " + currentText).toUtf8().constData());
|
||||
break;
|
||||
}
|
||||
reloadData();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ public:
|
|||
void setupHardBPRightClickContextMenu();
|
||||
void setupSoftBPRightClickContextMenu();
|
||||
void setupMemBPRightClickContextMenu();
|
||||
void setupCondBPRightClickContextMenu();
|
||||
|
||||
signals:
|
||||
void showCpu();
|
||||
|
@ -28,6 +29,7 @@ public slots:
|
|||
void removeAllHardBPActionSlot();
|
||||
void enableDisableHardBPActionSlot();
|
||||
void doubleClickHardwareSlot();
|
||||
void resetHardwareHitCountSlot();
|
||||
|
||||
// Software
|
||||
void softwareBPContextMenuSlot(const QPoint & pos);
|
||||
|
@ -37,6 +39,7 @@ public slots:
|
|||
void enableAllSoftBPActionSlot();
|
||||
void disableAllSoftBPActionSlot();
|
||||
void doubleClickSoftwareSlot();
|
||||
void resetSoftwareHitCountSlot();
|
||||
|
||||
// Memory
|
||||
void memoryBPContextMenuSlot(const QPoint & pos);
|
||||
|
@ -44,6 +47,13 @@ public slots:
|
|||
void removeAllMemBPActionSlot();
|
||||
void enableDisableMemBPActionSlot();
|
||||
void doubleClickMemorySlot();
|
||||
void resetMemoryHitCountSlot();
|
||||
|
||||
// Conditional
|
||||
void setLogSlot();
|
||||
void setCmdSlot();
|
||||
void setFastResumeSlot();
|
||||
void setConditionSlot();
|
||||
|
||||
private:
|
||||
QVBoxLayout* mVertLayout;
|
||||
|
@ -51,11 +61,19 @@ private:
|
|||
StdTable* mHardBPTable;
|
||||
StdTable* mSoftBPTable;
|
||||
StdTable* mMemBPTable;
|
||||
QMenu* mConditionalBreakpointMenu;
|
||||
// Conditional BP Context Menu
|
||||
int CurrentType;
|
||||
QAction* mConditionalSetCondition;
|
||||
QAction* mConditionalSetFastResume;
|
||||
QAction* mConditionalSetLog;
|
||||
QAction* mConditionalSetCmd;
|
||||
|
||||
// Hardware BP Context Menu
|
||||
QAction* mHardBPRemoveAction;
|
||||
QAction* mHardBPRemoveAllAction;
|
||||
QAction* mHardBPEnableDisableAction;
|
||||
QAction* mHardBPResetHitCountAction;
|
||||
|
||||
// Software BP Context Menu
|
||||
QAction* mSoftBPRemoveAction;
|
||||
|
@ -63,11 +81,13 @@ private:
|
|||
QAction* mSoftBPEnableDisableAction;
|
||||
QAction* mSoftBPEnableAllAction;
|
||||
QAction* mSoftBPDisableAllAction;
|
||||
QAction* mSoftBPResetHitCountAction;
|
||||
|
||||
// Memory BP Context Menu
|
||||
QAction* mMemBPRemoveAction;
|
||||
QAction* mMemBPRemoveAllAction;
|
||||
QAction* mMemBPEnableDisableAction;
|
||||
QAction* mMemBPResetHitCountAction;
|
||||
};
|
||||
|
||||
#endif // BREAKPOINTSVIEW_H
|
||||
|
|
|
@ -802,12 +802,12 @@ void CPUDump::setLabelSlot()
|
|||
char label_text[MAX_COMMENT_SIZE] = "";
|
||||
if(DbgGetLabelAt((duint)wVA, SEG_DEFAULT, label_text))
|
||||
mLineEdit.setText(QString(label_text));
|
||||
mLineEdit.setWindowTitle("Add label at " + addr_text);
|
||||
mLineEdit.setWindowTitle(tr("Add label at ") + addr_text);
|
||||
if(mLineEdit.exec() != QDialog::Accepted)
|
||||
return;
|
||||
if(!DbgSetLabelAt(wVA, mLineEdit.editText.toUtf8().constData()))
|
||||
{
|
||||
QMessageBox msg(QMessageBox::Critical, "Error!", "DbgSetLabelAt failed!");
|
||||
QMessageBox msg(QMessageBox::Critical, tr("Error!"), tr("DbgSetLabelAt failed!"));
|
||||
msg.setWindowIcon(QIcon(":/icons/images/compile-error.png"));
|
||||
msg.setParent(this, Qt::Dialog);
|
||||
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
|
@ -1698,4 +1698,3 @@ void CPUDump::gotoPrevSlot()
|
|||
historyPrev();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ void PageMemoryRights::on_btnSetrights_clicked()
|
|||
emit refreshMemoryMap();
|
||||
|
||||
if(one_right_changed)
|
||||
ui->LnEdStatus->setText("Pages Rights Changed to: " + rights);
|
||||
ui->LnEdStatus->setText(tr("Pages Rights Changed to: ") + rights);
|
||||
else
|
||||
ui->LnEdStatus->setText("Error setting rights, read the MSDN to learn the valid rights of: " + pagetype);
|
||||
ui->LnEdStatus->setText(tr("Error setting rights, read the MSDN to learn the valid rights of: ") + pagetype);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue