1
0
Fork 0

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:
Duncan Ogilvie 2016-05-22 17:34:01 +02:00
commit c1f505b46e
15 changed files with 1110 additions and 211 deletions

View File

@ -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);

View File

@ -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++;
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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
{

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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);
}