diff --git a/src/bridge/bridgemain.h b/src/bridge/bridgemain.h index 7a76cca4..78e28391 100644 --- a/src/bridge/bridgemain.h +++ b/src/bridge/bridgemain.h @@ -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); diff --git a/src/dbg/_exports.cpp b/src/dbg/_exports.cpp index 6edc5061..fb6d07c8 100644 --- a/src/dbg/_exports.cpp +++ b/src/dbg/_exports.cpp @@ -568,64 +568,27 @@ extern "C" DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* bpmap) int retcount = 0; std::vector 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++; } diff --git a/src/dbg/breakpoint.cpp b/src/dbg/breakpoint.cpp index 5c40c54c..4bc4ca04 100644 --- a/src/dbg/breakpoint.cpp +++ b/src/dbg/breakpoint.cpp @@ -8,6 +8,8 @@ #include "memory.h" #include "threading.h" #include "module.h" +#include "value.h" +#include "debugger.h" typedef std::pair BreakpointKey; std::map 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(); -} \ No newline at end of file +} diff --git a/src/dbg/breakpoint.h b/src/dbg/breakpoint.h index 4a16d0b7..2b20b8cc 100644 --- a/src/dbg/breakpoint.h +++ b/src/dbg/breakpoint.h @@ -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* 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 \ No newline at end of file +#endif // _BREAKPOINT_H diff --git a/src/dbg/debugger.cpp b/src/dbg/debugger.cpp index eacf6256..72d500cf 100644 --- a/src/dbg/debugger.cpp +++ b/src/dbg/debugger.cpp @@ -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) diff --git a/src/dbg/debugger.h b/src/dbg/debugger.h index 24ef03c6..0cf43d70 100644 --- a/src/dbg/debugger.h +++ b/src/dbg/debugger.h @@ -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 diff --git a/src/dbg/debugger_commands.cpp b/src/dbg/debugger_commands.cpp index f8068cb9..b4697815 100644 --- a/src/dbg/debugger_commands.cpp +++ b/src/dbg/debugger_commands.cpp @@ -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; -} \ No newline at end of file +} diff --git a/src/dbg/debugger_commands.h b/src/dbg/debugger_commands.h index eabe2ae1..07a8df6e 100644 --- a/src/dbg/debugger_commands.h +++ b/src/dbg/debugger_commands.h @@ -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 \ No newline at end of file +#endif //_DEBUGGER_COMMANDS_H diff --git a/src/dbg/value.cpp b/src/dbg/value.cpp index 00a49235..c451a2e3 100644 --- a/src/dbg/value.cpp +++ b/src/dbg/value.cpp @@ -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. diff --git a/src/dbg/x64_dbg.cpp b/src/dbg/x64_dbg.cpp index e9251ca7..99aef2a1 100644 --- a/src/dbg/x64_dbg.cpp +++ b/src/dbg/x64_dbg.cpp @@ -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; -} \ No newline at end of file +} diff --git a/src/gui/Src/Disassembler/capstone_gui.cpp b/src/gui/Src/Disassembler/capstone_gui.cpp index 75f27960..13e52a2c 100644 --- a/src/gui/Src/Disassembler/capstone_gui.cpp +++ b/src/gui/Src/Disassembler/capstone_gui.cpp @@ -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 { diff --git a/src/gui/Src/Gui/BreakpointsView.cpp b/src/gui/Src/Gui/BreakpointsView.cpp index 6f582528..67e8fa3f 100644 --- a/src/gui/Src/Gui/BreakpointsView.cpp +++ b/src/gui/Src/Gui/BreakpointsView.cpp @@ -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(); +} diff --git a/src/gui/Src/Gui/BreakpointsView.h b/src/gui/Src/Gui/BreakpointsView.h index 827f42a4..a125327b 100644 --- a/src/gui/Src/Gui/BreakpointsView.h +++ b/src/gui/Src/Gui/BreakpointsView.h @@ -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 diff --git a/src/gui/Src/Gui/CPUDump.cpp b/src/gui/Src/Gui/CPUDump.cpp index 5b8c4d77..fbcacbd1 100644 --- a/src/gui/Src/Gui/CPUDump.cpp +++ b/src/gui/Src/Gui/CPUDump.cpp @@ -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(); } - diff --git a/src/gui/Src/Gui/PageMemoryRights.cpp b/src/gui/Src/Gui/PageMemoryRights.cpp index 7ce4ed06..4677f81a 100644 --- a/src/gui/Src/Gui/PageMemoryRights.cpp +++ b/src/gui/Src/Gui/PageMemoryRights.cpp @@ -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); }