Big refactor to improve the tracing experience
- "Trace record" has been renamed to "Trace coverage" - "Run trace" has been renamed to "Trace recording" - You can now start recording directly from the trace dialog
This commit is contained in:
parent
cb7e6ea892
commit
3361b2dfc2
|
@ -247,7 +247,7 @@ static void HandleZydisOperand(const Zydis & cp, int opindex, DISASM_ARGTYPE* ar
|
|||
|
||||
void TraceRecordManager::TraceExecuteRecord(const Zydis & newInstruction)
|
||||
{
|
||||
if(!isRunTraceEnabled())
|
||||
if(!isTraceRecordingEnabled())
|
||||
return;
|
||||
unsigned char WriteBuffer[3072];
|
||||
unsigned char* WriteBufferPtr = WriteBuffer;
|
||||
|
@ -419,7 +419,7 @@ void TraceRecordManager::TraceExecuteRecord(const Zydis & newInstruction)
|
|||
{
|
||||
CloseHandle(rtFile);
|
||||
String error = stringformatinline(StringUtils::sprintf("{winerror@%d}", GetLastError()));
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Run trace has stopped unexpectedly because WriteFile() failed. GetLastError() = %s.\r\n"), error.c_str());
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Trace recording has stopped unexpectedly because WriteFile() failed. GetLastError() = %s.\r\n"), error.c_str());
|
||||
rtEnabled = false;
|
||||
}
|
||||
}
|
||||
|
@ -486,12 +486,12 @@ void TraceRecordManager::increaseInstructionCounter()
|
|||
InterlockedIncrement((volatile long*)&instructionCounter);
|
||||
}
|
||||
|
||||
bool TraceRecordManager::enableRunTrace(bool enabled, const char* fileName)
|
||||
bool TraceRecordManager::enableTraceRecording(bool enabled, const char* fileName)
|
||||
{
|
||||
if(enabled)
|
||||
{
|
||||
if(rtEnabled)
|
||||
enableRunTrace(false, NULL); //re-enable run trace
|
||||
enableTraceRecording(false, NULL); //re-enable run trace
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
rtFile = CreateFileW(StringUtils::Utf8ToUtf16(fileName).c_str(), FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
@ -529,7 +529,7 @@ bool TraceRecordManager::enableRunTrace(bool enabled, const char* fileName)
|
|||
CloseHandle(rtFile);
|
||||
json_free(headerinfo);
|
||||
json_decref(root);
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Run trace failed to start because file header cannot be written."));
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Trace recording failed to start because the file header cannot be written."));
|
||||
return false;
|
||||
}
|
||||
WriteFile(rtFile, headerinfo, (DWORD)headerinfosize, &written, nullptr);
|
||||
|
@ -538,7 +538,7 @@ bool TraceRecordManager::enableRunTrace(bool enabled, const char* fileName)
|
|||
if(written < headerinfosize) //disk-full?
|
||||
{
|
||||
CloseHandle(rtFile);
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Run trace failed to start because file header cannot be written."));
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Trace recording failed to start because the file header cannot be written."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -549,7 +549,7 @@ bool TraceRecordManager::enableRunTrace(bool enabled, const char* fileName)
|
|||
rtNeedThreadId = true;
|
||||
for(size_t i = 0; i < _countof(rtOldContextChanged); i++)
|
||||
rtOldContextChanged[i] = true;
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Run trace started. File: %s\r\n"), fileName);
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Started trace recording to file: %s\r\n"), fileName);
|
||||
Zydis cp;
|
||||
unsigned char instr[MAX_DISASM_BUFFER];
|
||||
auto cip = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
|
@ -564,7 +564,7 @@ bool TraceRecordManager::enableRunTrace(bool enabled, const char* fileName)
|
|||
else
|
||||
{
|
||||
String error = stringformatinline(StringUtils::sprintf("{winerror@%d}", GetLastError()));
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Cannot create run trace file. GetLastError() = %s.\r\n"), error.c_str());
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Cannot create trace recording file. GetLastError() = %s.\r\n"), error.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -575,7 +575,7 @@ bool TraceRecordManager::enableRunTrace(bool enabled, const char* fileName)
|
|||
CloseHandle(rtFile);
|
||||
rtPrevInstAvailable = false;
|
||||
rtEnabled = false;
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Run trace stopped."));
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Trace recording stopped."));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -700,12 +700,12 @@ unsigned int TraceRecordManager::getModuleIndex(const String & moduleName)
|
|||
}
|
||||
}
|
||||
|
||||
bool TraceRecordManager::isRunTraceEnabled()
|
||||
bool TraceRecordManager::isTraceRecordingEnabled()
|
||||
{
|
||||
return rtEnabled;
|
||||
}
|
||||
|
||||
void _dbg_dbgtraceexecute(duint CIP)
|
||||
void dbgtraceexecute(duint CIP)
|
||||
{
|
||||
if(TraceRecord.getTraceRecordType(CIP) != TraceRecordManager::TraceRecordType::TraceRecordNone)
|
||||
{
|
||||
|
@ -714,7 +714,7 @@ void _dbg_dbgtraceexecute(duint CIP)
|
|||
if(MemRead(CIP, data, MAX_DISASM_BUFFER))
|
||||
{
|
||||
instruction.DisassembleSafe(CIP, data, MAX_DISASM_BUFFER);
|
||||
if(TraceRecord.isRunTraceEnabled())
|
||||
if(TraceRecord.isTraceRecordingEnabled())
|
||||
{
|
||||
TraceRecord.TraceExecute(CIP, instruction.Size());
|
||||
TraceRecord.TraceExecuteRecord(instruction);
|
||||
|
@ -727,7 +727,7 @@ void _dbg_dbgtraceexecute(duint CIP)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(TraceRecord.isRunTraceEnabled())
|
||||
if(TraceRecord.isTraceRecordingEnabled())
|
||||
{
|
||||
Zydis instruction;
|
||||
unsigned char data[MAX_DISASM_BUFFER];
|
||||
|
@ -740,34 +740,3 @@ void _dbg_dbgtraceexecute(duint CIP)
|
|||
}
|
||||
TraceRecord.increaseInstructionCounter();
|
||||
}
|
||||
|
||||
unsigned int _dbg_dbggetTraceRecordHitCount(duint address)
|
||||
{
|
||||
return TraceRecord.getHitCount(address);
|
||||
}
|
||||
|
||||
TRACERECORDBYTETYPE _dbg_dbggetTraceRecordByteType(duint address)
|
||||
{
|
||||
return (TRACERECORDBYTETYPE)TraceRecord.getByteType(address);
|
||||
}
|
||||
|
||||
bool _dbg_dbgsetTraceRecordType(duint pageAddress, TRACERECORDTYPE type)
|
||||
{
|
||||
return TraceRecord.setTraceRecordType(pageAddress, (TraceRecordManager::TraceRecordType)type);
|
||||
}
|
||||
|
||||
TRACERECORDTYPE _dbg_dbggetTraceRecordType(duint pageAddress)
|
||||
{
|
||||
return (TRACERECORDTYPE)TraceRecord.getTraceRecordType(pageAddress);
|
||||
}
|
||||
|
||||
// When disabled, file name is not relevant and can be NULL
|
||||
bool _dbg_dbgenableRunTrace(bool enabled, const char* fileName)
|
||||
{
|
||||
return TraceRecord.enableRunTrace(enabled, fileName);
|
||||
}
|
||||
|
||||
bool _dbg_dbgisRunTraceEnabled()
|
||||
{
|
||||
return TraceRecord.isRunTraceEnabled();
|
||||
}
|
||||
|
|
|
@ -60,8 +60,8 @@ public:
|
|||
TraceRecordByteType getByteType(duint address);
|
||||
void increaseInstructionCounter();
|
||||
|
||||
bool isRunTraceEnabled();
|
||||
bool enableRunTrace(bool enabled, const char* fileName);
|
||||
bool isTraceRecordingEnabled();
|
||||
bool enableTraceRecording(bool enabled, const char* fileName);
|
||||
|
||||
void saveToDb(JSON root);
|
||||
void loadFromDb(JSON root);
|
||||
|
@ -113,14 +113,6 @@ private:
|
|||
};
|
||||
|
||||
extern TraceRecordManager TraceRecord;
|
||||
void _dbg_dbgtraceexecute(duint CIP);
|
||||
|
||||
//exported to bridge
|
||||
unsigned int _dbg_dbggetTraceRecordHitCount(duint address);
|
||||
TRACERECORDBYTETYPE _dbg_dbggetTraceRecordByteType(duint address);
|
||||
bool _dbg_dbgsetTraceRecordType(duint pageAddress, TRACERECORDTYPE type);
|
||||
TRACERECORDTYPE _dbg_dbggetTraceRecordType(duint pageAddress);
|
||||
bool _dbg_dbgenableRunTrace(bool enabled, const char* fileName);
|
||||
bool _dbg_dbgisRunTraceEnabled();
|
||||
void dbgtraceexecute(duint CIP);
|
||||
|
||||
#endif // TRACERECORD_H
|
||||
|
|
|
@ -174,7 +174,7 @@ static bool _getjit(char* jit, bool jit64)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool _getprocesslist(DBGPROCESSINFO** entries, int* count)
|
||||
static bool _getprocesslist(DBGPROCESSINFO** entries, int* count)
|
||||
{
|
||||
std::vector<PROCESSENTRY32> infoList;
|
||||
std::vector<std::string> commandList;
|
||||
|
@ -440,7 +440,7 @@ static int SymAutoComplete(const char* Search, char** Buffer, int MaxSymbols)
|
|||
return count;
|
||||
}
|
||||
|
||||
MODULESYMBOLSTATUS _modsymbolstatus(duint base)
|
||||
static MODULESYMBOLSTATUS _modsymbolstatus(duint base)
|
||||
{
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
auto modInfo = ModInfoFromAddr(base);
|
||||
|
@ -463,6 +463,36 @@ static void _refreshmodulelist()
|
|||
SymUpdateModuleList();
|
||||
}
|
||||
|
||||
static unsigned int _getTraceRecordHitCount(duint address)
|
||||
{
|
||||
return TraceRecord.getHitCount(address);
|
||||
}
|
||||
|
||||
static TRACERECORDBYTETYPE _getTraceRecordByteType(duint address)
|
||||
{
|
||||
return (TRACERECORDBYTETYPE)TraceRecord.getByteType(address);
|
||||
}
|
||||
|
||||
static bool _setTraceRecordType(duint pageAddress, TRACERECORDTYPE type)
|
||||
{
|
||||
return TraceRecord.setTraceRecordType(pageAddress, (TraceRecordManager::TraceRecordType)type);
|
||||
}
|
||||
|
||||
static TRACERECORDTYPE _getTraceRecordType(duint pageAddress)
|
||||
{
|
||||
return (TRACERECORDTYPE)TraceRecord.getTraceRecordType(pageAddress);
|
||||
}
|
||||
|
||||
static bool _enableTraceRecording(bool enabled, const char* fileName)
|
||||
{
|
||||
return TraceRecord.enableTraceRecording(enabled, fileName);
|
||||
}
|
||||
|
||||
static bool _isTraceRecordingEnabled()
|
||||
{
|
||||
return TraceRecord.isTraceRecordingEnabled();
|
||||
}
|
||||
|
||||
void dbgfunctionsinit()
|
||||
{
|
||||
_dbgfunctions.AssembleAtEx = _assembleatex;
|
||||
|
@ -508,10 +538,10 @@ void dbgfunctionsinit()
|
|||
_dbgfunctions.GetBridgeBp = _getbridgebp;
|
||||
_dbgfunctions.StringFormatInline = _stringformatinline;
|
||||
_dbgfunctions.GetMnemonicBrief = _getmnemonicbrief;
|
||||
_dbgfunctions.GetTraceRecordHitCount = _dbg_dbggetTraceRecordHitCount;
|
||||
_dbgfunctions.GetTraceRecordByteType = _dbg_dbggetTraceRecordByteType;
|
||||
_dbgfunctions.SetTraceRecordType = _dbg_dbgsetTraceRecordType;
|
||||
_dbgfunctions.GetTraceRecordType = _dbg_dbggetTraceRecordType;
|
||||
_dbgfunctions.GetTraceRecordHitCount = _getTraceRecordHitCount;
|
||||
_dbgfunctions.GetTraceRecordByteType = _getTraceRecordByteType;
|
||||
_dbgfunctions.SetTraceRecordType = _setTraceRecordType;
|
||||
_dbgfunctions.GetTraceRecordType = _getTraceRecordType;
|
||||
_dbgfunctions.EnumHandles = _enumhandles;
|
||||
_dbgfunctions.GetHandleName = _gethandlename;
|
||||
_dbgfunctions.EnumTcpConnections = _enumtcpconnections;
|
||||
|
|
|
@ -110,7 +110,7 @@ SCRIPT_EXPORT bool Script::Register::Set(Script::Register::RegisterEnum reg, dui
|
|||
if(reg == ArchValue(EIP, RIP) || reg == CIP)
|
||||
{
|
||||
auto cip = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
_dbg_dbgtraceexecute(cip);
|
||||
dbgtraceexecute(cip);
|
||||
DebugUpdateGuiAsync(cip, false); //update disassembly + register view
|
||||
}
|
||||
else if(reg == ArchValue(ESP, RSP) || reg == SP || reg == CSP) //update stack
|
||||
|
|
|
@ -500,6 +500,6 @@ bool cbInstrTraceexecute(int argc, char* argv[])
|
|||
duint addr;
|
||||
if(!valfromstring(argv[1], &addr, false))
|
||||
return false;
|
||||
_dbg_dbgtraceexecute(addr);
|
||||
dbgtraceexecute(addr);
|
||||
return true;
|
||||
}
|
|
@ -480,7 +480,7 @@ bool cbDebugSkip(int argc, char* argv[])
|
|||
{
|
||||
disasmfast(cip, &basicinfo);
|
||||
cip += basicinfo.size;
|
||||
_dbg_dbgtraceexecute(cip);
|
||||
dbgtraceexecute(cip);
|
||||
}
|
||||
SetContextDataEx(hActiveThread, UE_CIP, cip);
|
||||
DebugUpdateGuiAsync(cip, false); //update GUI
|
||||
|
|
|
@ -171,14 +171,14 @@ bool cbDebugTraceSetLogFile(int argc, char* argv[])
|
|||
return dbgsettracelogfile(fileName);
|
||||
}
|
||||
|
||||
bool cbDebugStartRunTrace(int argc, char* argv[])
|
||||
bool cbDebugStartTraceRecording(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 2))
|
||||
return false;
|
||||
return _dbg_dbgenableRunTrace(true, argv[1]);
|
||||
return TraceRecord.enableTraceRecording(true, argv[1]);
|
||||
}
|
||||
|
||||
bool cbDebugStopRunTrace(int argc, char* argv[])
|
||||
bool cbDebugStopTraceRecording(int argc, char* argv[])
|
||||
{
|
||||
return _dbg_dbgenableRunTrace(false, nullptr);
|
||||
return TraceRecord.enableTraceRecording(false, nullptr);
|
||||
}
|
|
@ -14,5 +14,5 @@ bool cbDebugTraceSetLog(int argc, char* argv[]);
|
|||
bool cbDebugTraceSetCommand(int argc, char* argv[]);
|
||||
bool cbDebugTraceSetSwitchCondition(int argc, char* argv[]);
|
||||
bool cbDebugTraceSetLogFile(int argc, char* argv[]);
|
||||
bool cbDebugStartRunTrace(int argc, char* argv[]);
|
||||
bool cbDebugStopRunTrace(int argc, char* argv[]);
|
||||
bool cbDebugStartTraceRecording(int argc, char* argv[]);
|
||||
bool cbDebugStopTraceRecording(int argc, char* argv[]);
|
|
@ -746,7 +746,7 @@ void cbPauseBreakpoint()
|
|||
DebugUpdateGuiSetStateAsync(CIP, true);
|
||||
_dbg_animatestop(); // Stop animating when paused
|
||||
// Trace record
|
||||
_dbg_dbgtraceexecute(CIP);
|
||||
dbgtraceexecute(CIP);
|
||||
//lock
|
||||
lock(WAITID_RUN);
|
||||
// Plugin callback
|
||||
|
@ -925,7 +925,7 @@ static void cbGenericBreakpoint(BP_TYPE bptype, void* ExceptionAddress = nullptr
|
|||
plugincbcall(CB_BREAKPOINT, &bpInfo);
|
||||
|
||||
// Trace record
|
||||
_dbg_dbgtraceexecute(CIP);
|
||||
dbgtraceexecute(CIP);
|
||||
|
||||
// Watchdog
|
||||
cbCheckWatchdog(0, nullptr);
|
||||
|
@ -994,7 +994,7 @@ void cbRunToUserCodeBreakpoint(void* ExceptionAddress)
|
|||
// lock
|
||||
lock(WAITID_RUN);
|
||||
// Trace record
|
||||
_dbg_dbgtraceexecute(CIP);
|
||||
dbgtraceexecute(CIP);
|
||||
// Update GUI
|
||||
DebugUpdateGuiSetStateAsync(GetContextDataEx(hActiveThread, UE_CIP), true);
|
||||
// Plugin callback
|
||||
|
@ -1191,7 +1191,7 @@ void cbStep()
|
|||
{
|
||||
DebugUpdateGuiSetStateAsync(CIP, true);
|
||||
// Trace record
|
||||
_dbg_dbgtraceexecute(CIP);
|
||||
dbgtraceexecute(CIP);
|
||||
// Plugin interaction
|
||||
PLUG_CB_STEPPED stepInfo;
|
||||
stepInfo.reserved = 0;
|
||||
|
@ -1207,7 +1207,7 @@ void cbStep()
|
|||
}
|
||||
else
|
||||
{
|
||||
_dbg_dbgtraceexecute(CIP);
|
||||
dbgtraceexecute(CIP);
|
||||
(bRepeatIn ? StepIntoWow64 : StepOverWrapper)((void*)cbStep);
|
||||
}
|
||||
}
|
||||
|
@ -1220,7 +1220,7 @@ static void cbRtrFinalStep(bool checkRepeat = false)
|
|||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
duint CIP = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
// Trace record
|
||||
_dbg_dbgtraceexecute(CIP);
|
||||
dbgtraceexecute(CIP);
|
||||
DebugUpdateGuiSetStateAsync(CIP, true);
|
||||
//lock
|
||||
lock(WAITID_RUN);
|
||||
|
@ -1243,7 +1243,7 @@ void cbRtrStep()
|
|||
duint cip = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
|
||||
MemRead(cip, data, sizeof(data));
|
||||
_dbg_dbgtraceexecute(cip);
|
||||
dbgtraceexecute(cip);
|
||||
if(mRtrPreviousCSP <= csp) //"Run until return" should break only if RSP is bigger than or equal to current value
|
||||
{
|
||||
if(data[0] == 0xC3 || data[0] == 0xC2) //retn instruction
|
||||
|
@ -1342,7 +1342,7 @@ static void cbTraceUniversalConditionalStep(duint cip, bool bStepInto, void(*cal
|
|||
}
|
||||
else //continue tracing
|
||||
{
|
||||
_dbg_dbgtraceexecute(cip);
|
||||
dbgtraceexecute(cip);
|
||||
if(switchCondition) //switch (invert) the step type once
|
||||
bStepInto = !bStepInto;
|
||||
(bStepInto ? StepIntoWow64 : StepOverWrapper)((void*)callback);
|
||||
|
@ -2903,7 +2903,7 @@ static void debugLoopFunction(INIT_STRUCT* init)
|
|||
ThreadClear();
|
||||
WatchClear();
|
||||
TraceRecord.clear();
|
||||
_dbg_dbgenableRunTrace(false, nullptr); //Stop run trace
|
||||
TraceRecord.enableTraceRecording(false, nullptr); // Stop trace recording
|
||||
GuiSetDebugState(stopped);
|
||||
GuiUpdateAllViews();
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Debugging stopped!"));
|
||||
|
|
|
@ -116,7 +116,7 @@ void ExpressionFunctions::Init()
|
|||
//Trace record
|
||||
RegisterEasy("tr.enabled", trenabled);
|
||||
RegisterEasy("tr.hitcount,tr.count", trhitcount);
|
||||
RegisterEasy("tr.runtraceenabled", trisruntraceenabled);
|
||||
RegisterEasy("tr.isrecording,tr.runtraceenabled", trisrecording);
|
||||
|
||||
//Byte/Word/Dword/Qword/Pointer
|
||||
RegisterEasy("ReadByte,Byte,byte", readbyte);
|
||||
|
|
|
@ -436,9 +436,9 @@ namespace Exprfunc
|
|||
return trenabled(addr) ? TraceRecord.getHitCount(addr) : 0;
|
||||
}
|
||||
|
||||
duint trisruntraceenabled()
|
||||
duint trisrecording()
|
||||
{
|
||||
return _dbg_dbgisRunTraceEnabled() ? 1 : 0;
|
||||
return TraceRecord.isTraceRecordingEnabled() ? 1 : 0;
|
||||
}
|
||||
|
||||
duint gettickcount()
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace Exprfunc
|
|||
|
||||
duint trenabled(duint addr);
|
||||
duint trhitcount(duint addr);
|
||||
duint trisruntraceenabled();
|
||||
duint trisrecording();
|
||||
duint gettickcount();
|
||||
|
||||
duint readbyte(duint addr);
|
||||
|
|
|
@ -2619,7 +2619,7 @@ bool valtostring(const char* string, duint value, bool silent)
|
|||
if(strstr(regName(), "ip"))
|
||||
{
|
||||
auto cip = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
_dbg_dbgtraceexecute(cip);
|
||||
dbgtraceexecute(cip);
|
||||
DebugUpdateGuiAsync(cip, false); //update disassembly + register view
|
||||
}
|
||||
else if(strstr(regName(), "sp")) //update stack
|
||||
|
|
|
@ -211,18 +211,18 @@ static void registercommands()
|
|||
//tracing
|
||||
dbgcmdnew("TraceIntoConditional,ticnd", cbDebugTraceIntoConditional, true); //Trace into conditional
|
||||
dbgcmdnew("TraceOverConditional,tocnd", cbDebugTraceOverConditional, true); //Trace over conditional
|
||||
dbgcmdnew("TraceIntoBeyondTraceRecord,tibt", cbDebugTraceIntoBeyondTraceRecord, true); //Trace into beyond trace record
|
||||
dbgcmdnew("TraceOverBeyondTraceRecord,tobt", cbDebugTraceOverBeyondTraceRecord, true); //Trace over beyond trace record
|
||||
dbgcmdnew("TraceIntoIntoTraceRecord,tiit", cbDebugTraceIntoIntoTraceRecord, true); //Trace into into trace record
|
||||
dbgcmdnew("TraceOverIntoTraceRecord,toit", cbDebugTraceOverIntoTraceRecord, true); //Trace over into trace record
|
||||
dbgcmdnew("TraceIntoBeyondTraceCoverage,TraceIntoBeyondTraceRecord,tibt", cbDebugTraceIntoBeyondTraceRecord, true); //Trace into beyond trace record
|
||||
dbgcmdnew("TraceOverBeyondTraceCoverage,TraceOverBeyondTraceRecord,tobt", cbDebugTraceOverBeyondTraceRecord, true); //Trace over beyond trace record
|
||||
dbgcmdnew("TraceIntoIntoTraceCoverage,TraceIntoIntoTraceRecord,tiit", cbDebugTraceIntoIntoTraceRecord, true); //Trace into into trace record
|
||||
dbgcmdnew("TraceOverIntoTraceCoverage,TraceOverIntoTraceRecord,toit", cbDebugTraceOverIntoTraceRecord, true); //Trace over into trace record
|
||||
dbgcmdnew("RunToParty", cbDebugRunToParty, true); //Run to code in a party
|
||||
dbgcmdnew("RunToUserCode,rtu", cbDebugRunToUserCode, true); //Run to user code
|
||||
dbgcmdnew("TraceSetLog,SetTraceLog", cbDebugTraceSetLog, true); //Set trace log text + condition
|
||||
dbgcmdnew("TraceSetCommand,SetTraceCommand", cbDebugTraceSetCommand, true); //Set trace command text + condition
|
||||
dbgcmdnew("TraceSetSwitchCondition,SetTraceSwitchCondition", cbDebugTraceSetSwitchCondition, true); //Set trace switch condition
|
||||
dbgcmdnew("TraceSetLogFile,SetTraceLogFile", cbDebugTraceSetLogFile, true); //Set trace log file
|
||||
dbgcmdnew("StartRunTrace,opentrace", cbDebugStartRunTrace, true); //start run trace (Ollyscript command "opentrace" "opens run trace window")
|
||||
dbgcmdnew("StopRunTrace,tc", cbDebugStopRunTrace, true); //stop run trace (and Ollyscript command)
|
||||
dbgcmdnew("StartTraceRecording,StartRunTrace,opentrace", cbDebugStartTraceRecording, true); //start run trace (Ollyscript command "opentrace" "opens run trace window")
|
||||
dbgcmdnew("StopTraceRecording,StopRunTrace,tc", cbDebugStopTraceRecording, true); //stop run trace (and Ollyscript command)
|
||||
|
||||
//thread control
|
||||
dbgcmdnew("createthread,threadcreate,newthread,threadnew", cbDebugCreatethread, true); //create thread
|
||||
|
|
|
@ -14,7 +14,17 @@ BrowseDialog::BrowseDialog(QWidget* parent, const QString & title, const QString
|
|||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::MSWindowsFixedSizeDialogHint);
|
||||
setWindowTitle(title);
|
||||
ui->label->setText(text);
|
||||
ui->lineEdit->setText(defaultPath);
|
||||
auto nativePath = QDir::toNativeSeparators(defaultPath);
|
||||
ui->lineEdit->setText(nativePath);
|
||||
// Select the filename when saving
|
||||
auto lastSlashIdx = nativePath.lastIndexOf(QDir::separator());
|
||||
if(save && !QFileInfo(nativePath).isDir() && lastSlashIdx != -1)
|
||||
{
|
||||
auto periodIdx = nativePath.lastIndexOf('.');
|
||||
if(periodIdx == -1)
|
||||
periodIdx = nativePath.length();
|
||||
ui->lineEdit->setSelection(lastSlashIdx + 1, periodIdx - lastSlashIdx - 1);
|
||||
}
|
||||
QCompleter* completer = new QCompleter(ui->lineEdit);
|
||||
completer->setModel(new QDirModel(completer));
|
||||
ui->lineEdit->setCompleter(completer);
|
||||
|
|
|
@ -12,7 +12,7 @@ class BrowseDialog : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BrowseDialog(QWidget* parent, const QString & title, const QString & text, const QString & filter, const QString & defaultPath, bool save);
|
||||
BrowseDialog(QWidget* parent, const QString & title, const QString & text, const QString & filter, const QString & defaultPath, bool save);
|
||||
~BrowseDialog();
|
||||
|
||||
QString path;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "MemoryPage.h"
|
||||
#include "CommonActions.h"
|
||||
#include "BrowseDialog.h"
|
||||
#include "Tracer/TraceBrowser.h"
|
||||
|
||||
CPUDisassembly::CPUDisassembly(QWidget* parent, bool isMain) : Disassembly(parent, isMain)
|
||||
{
|
||||
|
@ -389,27 +390,33 @@ void CPUDisassembly::setupRightClickContextMenu()
|
|||
mMenuBuilder->addMenu(makeMenu(DIcon("label"), tr("Label")), labelMenu);
|
||||
mCommonActions->build(mMenuBuilder, CommonActions::ActionComment | CommonActions::ActionBookmark);
|
||||
|
||||
QAction* traceRecordDisable = makeAction(DIcon("close-all-tabs"), tr("Disable"), SLOT(ActionTraceRecordDisableSlot()));
|
||||
QAction* traceRecordEnableBit = makeAction(DIcon("bit"), tr("Bit"), SLOT(ActionTraceRecordBitSlot()));
|
||||
QAction* traceRecordEnableByte = makeAction(DIcon("byte"), tr("Byte"), SLOT(ActionTraceRecordByteSlot()));
|
||||
QAction* traceRecordEnableWord = makeAction(DIcon("word"), tr("Word"), SLOT(ActionTraceRecordWordSlot()));
|
||||
QAction* traceRecordToggleRunTrace = makeShortcutAction(tr("Start Run Trace"), SLOT(ActionTraceRecordToggleRunTraceSlot()), "ActionToggleRunTrace");
|
||||
mMenuBuilder->addMenu(makeMenu(DIcon("trace"), tr("Trace record")), [ = ](QMenu * menu)
|
||||
QAction* traceCoverageDisable = makeAction(DIcon("close-all-tabs"), tr("Disable"), SLOT(traceCoverageDisableSlot()));
|
||||
QAction* traceCoverageEnableBit = makeAction(DIcon("bit"), tr("Bit"), SLOT(traceCoverageBitSlot()));
|
||||
QAction* traceCoverageEnableByte = makeAction(DIcon("byte"), tr("Byte"), SLOT(traceCoverageByteSlot()));
|
||||
QAction* traceCoverageEnableWord = makeAction(DIcon("word"), tr("Word"), SLOT(traceCoverageWordSlot()));
|
||||
QAction* traceCoverageToggleTraceRecording = makeShortcutAction(DIcon("control-record"), tr("Start trace recording"), SLOT(traceCoverageToggleTraceRecordingSlot()), "ActionToggleRunTrace");
|
||||
mMenuBuilder->addMenu(makeMenu(DIcon("trace"), tr("Trace coverage")), [ = ](QMenu * menu)
|
||||
{
|
||||
if(DbgFunctions()->GetTraceRecordType(rvaToVa(getInitialSelection())) == TRACERECORDTYPE::TraceRecordNone)
|
||||
{
|
||||
menu->addAction(traceRecordEnableBit);
|
||||
menu->addAction(traceRecordEnableByte);
|
||||
menu->addAction(traceRecordEnableWord);
|
||||
menu->addAction(traceCoverageEnableBit);
|
||||
menu->addAction(traceCoverageEnableByte);
|
||||
menu->addAction(traceCoverageEnableWord);
|
||||
}
|
||||
else
|
||||
menu->addAction(traceRecordDisable);
|
||||
menu->addAction(traceCoverageDisable);
|
||||
menu->addSeparator();
|
||||
if(DbgValFromString("tr.runtraceenabled()") == 1)
|
||||
traceRecordToggleRunTrace->setText(tr("Stop Run Trace"));
|
||||
if(TraceBrowser::isRecording())
|
||||
{
|
||||
traceCoverageToggleTraceRecording->setText(tr("Stop trace recording"));
|
||||
traceCoverageToggleTraceRecording->setIcon(DIcon("control-stop"));
|
||||
}
|
||||
else
|
||||
traceRecordToggleRunTrace->setText(tr("Start Run Trace"));
|
||||
menu->addAction(traceRecordToggleRunTrace);
|
||||
{
|
||||
traceCoverageToggleTraceRecording->setText(tr("Start trace recording"));
|
||||
traceCoverageToggleTraceRecording->setIcon(DIcon("control-record"));
|
||||
}
|
||||
menu->addAction(traceCoverageToggleTraceRecording);
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -1876,7 +1883,7 @@ void CPUDisassembly::labelHelpSlot()
|
|||
}
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordBitSlot()
|
||||
void CPUDisassembly::traceCoverageBitSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
@ -1886,14 +1893,14 @@ void CPUDisassembly::ActionTraceRecordBitSlot()
|
|||
{
|
||||
if(!(DbgFunctions()->SetTraceRecordType(i, TRACERECORDTYPE::TraceRecordBitExec)))
|
||||
{
|
||||
GuiAddLogMessage(tr("Failed to set trace record.\n").toUtf8().constData());
|
||||
GuiAddLogMessage(tr("Failed to enable trace coverage for page %1.\n").arg(ToPtrString(i)).toUtf8().constData());
|
||||
break;
|
||||
}
|
||||
}
|
||||
DbgCmdExec("traceexecute cip");
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordByteSlot()
|
||||
void CPUDisassembly::traceCoverageByteSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
@ -1903,14 +1910,14 @@ void CPUDisassembly::ActionTraceRecordByteSlot()
|
|||
{
|
||||
if(!(DbgFunctions()->SetTraceRecordType(i, TRACERECORDTYPE::TraceRecordByteWithExecTypeAndCounter)))
|
||||
{
|
||||
GuiAddLogMessage(tr("Failed to set trace record.\n").toUtf8().constData());
|
||||
GuiAddLogMessage(tr("Failed to enable trace coverage for page %1.\n").arg(ToPtrString(i)).toUtf8().constData());
|
||||
break;
|
||||
}
|
||||
}
|
||||
DbgCmdExec("traceexecute cip");
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordWordSlot()
|
||||
void CPUDisassembly::traceCoverageWordSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
@ -1920,14 +1927,14 @@ void CPUDisassembly::ActionTraceRecordWordSlot()
|
|||
{
|
||||
if(!(DbgFunctions()->SetTraceRecordType(i, TRACERECORDTYPE::TraceRecordWordWithExecTypeAndCounter)))
|
||||
{
|
||||
GuiAddLogMessage(tr("Failed to set trace record.\n").toUtf8().constData());
|
||||
GuiAddLogMessage(tr("Failed to enable trace coverage for page %1.\n").arg(ToPtrString(i)).toUtf8().constData());
|
||||
break;
|
||||
}
|
||||
}
|
||||
DbgCmdExec("traceexecute cip");
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordDisableSlot()
|
||||
void CPUDisassembly::traceCoverageDisableSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
@ -1937,7 +1944,7 @@ void CPUDisassembly::ActionTraceRecordDisableSlot()
|
|||
{
|
||||
if(!(DbgFunctions()->SetTraceRecordType(i, TRACERECORDTYPE::TraceRecordNone)))
|
||||
{
|
||||
GuiAddLogMessage(tr("Failed to set trace record.\n").toUtf8().constData());
|
||||
GuiAddLogMessage(tr("Failed to disable trace coverage for page %1.\n").arg(ToPtrString(i)).toUtf8().constData());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2045,31 +2052,7 @@ void CPUDisassembly::downloadCurrentSymbolsSlot()
|
|||
DbgCmdExec(QString("symdownload \"%0\"").arg(module));
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordToggleRunTraceSlot()
|
||||
void CPUDisassembly::traceCoverageToggleTraceRecordingSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
if(DbgValFromString("tr.runtraceenabled()") == 1)
|
||||
DbgCmdExec("StopRunTrace");
|
||||
else
|
||||
{
|
||||
QString defaultFileName;
|
||||
char moduleName[MAX_MODULE_SIZE];
|
||||
QDateTime currentTime = QDateTime::currentDateTime();
|
||||
duint defaultModule = DbgValFromString("mod.main()");
|
||||
if(DbgFunctions()->ModNameFromAddr(defaultModule, moduleName, false))
|
||||
{
|
||||
defaultFileName = QString::fromUtf8(moduleName);
|
||||
}
|
||||
defaultFileName += "-" + QLocale(QString(currentLocale)).toString(currentTime.date()) + " " + currentTime.time().toString("hh-mm-ss") + ArchValue(".trace32", ".trace64");
|
||||
BrowseDialog browse(this, tr("Select stored file"), tr("Store run trace to the following file"),
|
||||
tr("Run trace files (*.%1);;All files (*.*)").arg(ArchValue("trace32", "trace64")), QCoreApplication::applicationDirPath() + QDir::separator() + "db" + QDir::separator() + defaultFileName, true);
|
||||
if(browse.exec() == QDialog::Accepted)
|
||||
{
|
||||
if(browse.path.contains(QChar('"')) || browse.path.contains(QChar('\'')))
|
||||
SimpleErrorBox(this, tr("Error"), tr("File name contains invalid character."));
|
||||
else
|
||||
DbgCmdExec(QString("StartRunTrace \"%1\"").arg(browse.path));
|
||||
}
|
||||
}
|
||||
TraceBrowser::toggleTraceRecording(this);
|
||||
}
|
||||
|
|
|
@ -89,11 +89,11 @@ public slots:
|
|||
void openSourceSlot();
|
||||
void mnemonicHelpSlot();
|
||||
void mnemonicBriefSlot();
|
||||
void ActionTraceRecordBitSlot();
|
||||
void ActionTraceRecordByteSlot();
|
||||
void ActionTraceRecordWordSlot();
|
||||
void ActionTraceRecordDisableSlot();
|
||||
void ActionTraceRecordToggleRunTraceSlot();
|
||||
void traceCoverageBitSlot();
|
||||
void traceCoverageByteSlot();
|
||||
void traceCoverageWordSlot();
|
||||
void traceCoverageDisableSlot();
|
||||
void traceCoverageToggleTraceRecordingSlot();
|
||||
void displayWarningSlot(QString title, QString text);
|
||||
void labelHelpSlot();
|
||||
void analyzeSingleFunctionSlot();
|
||||
|
|
|
@ -320,7 +320,7 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
connect(ui->actionFunctions, SIGNAL(triggered()), this, SLOT(displayFunctions()));
|
||||
connect(ui->actionCallStack, SIGNAL(triggered()), this, SLOT(displayCallstack()));
|
||||
connect(ui->actionSEHChain, SIGNAL(triggered()), this, SLOT(displaySEHChain()));
|
||||
connect(ui->actionTrace, SIGNAL(triggered()), this, SLOT(displayRunTrace()));
|
||||
connect(ui->actionTrace, SIGNAL(triggered()), this, SLOT(displayTraceWidget()));
|
||||
connect(ui->actionDonate, SIGNAL(triggered()), this, SLOT(donate()));
|
||||
connect(ui->actionReportBug, SIGNAL(triggered()), this, SLOT(reportBug()));
|
||||
connect(ui->actionBlog, SIGNAL(triggered()), this, SLOT(blog()));
|
||||
|
@ -1104,22 +1104,22 @@ void MainWindow::setFocusToCommandBar()
|
|||
|
||||
void MainWindow::execTRBit()
|
||||
{
|
||||
mCpuWidget->getDisasmWidget()->ActionTraceRecordBitSlot();
|
||||
mCpuWidget->getDisasmWidget()->traceCoverageBitSlot();
|
||||
}
|
||||
|
||||
void MainWindow::execTRByte()
|
||||
{
|
||||
mCpuWidget->getDisasmWidget()->ActionTraceRecordByteSlot();
|
||||
mCpuWidget->getDisasmWidget()->traceCoverageByteSlot();
|
||||
}
|
||||
|
||||
void MainWindow::execTRWord()
|
||||
{
|
||||
mCpuWidget->getDisasmWidget()->ActionTraceRecordWordSlot();
|
||||
mCpuWidget->getDisasmWidget()->traceCoverageWordSlot();
|
||||
}
|
||||
|
||||
void MainWindow::execTRNone()
|
||||
{
|
||||
mCpuWidget->getDisasmWidget()->ActionTraceRecordDisableSlot();
|
||||
mCpuWidget->getDisasmWidget()->traceCoverageDisableSlot();
|
||||
}
|
||||
|
||||
void MainWindow::execTicnd()
|
||||
|
@ -1813,7 +1813,7 @@ void MainWindow::displaySEHChain()
|
|||
showQWidgetTab(mSEHChainView);
|
||||
}
|
||||
|
||||
void MainWindow::displayRunTrace()
|
||||
void MainWindow::displayTraceWidget()
|
||||
{
|
||||
showQWidgetTab(mTraceWidget);
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ public slots:
|
|||
void displayThreadsWidget();
|
||||
void displayVariables();
|
||||
void displayGraphWidget();
|
||||
void displayRunTrace();
|
||||
void displayTraceWidget();
|
||||
void openSettings();
|
||||
void openAppearance();
|
||||
void openCalculator();
|
||||
|
|
|
@ -204,7 +204,7 @@
|
|||
</property>
|
||||
<widget class="QMenu" name="menuTrace_record">
|
||||
<property name="title">
|
||||
<string>Trace record</string>
|
||||
<string>Trace &coverage</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="trace" resource="../../resource.qrc">
|
||||
|
@ -1035,7 +1035,7 @@
|
|||
<string>Bit</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Enable trace record with 1 bit per byte to record whether the code has been executed.</string>
|
||||
<string>Enable trace coverage with 1 bit (whether an instruction was executed or not)</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTRByte">
|
||||
|
@ -1047,7 +1047,7 @@
|
|||
<string>Byte</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Enable trace record with 1 byte per byte to record how many times the code has been executed.</string>
|
||||
<string>Enable trace coverage with 1 byte to record how many times an instruction has been executed.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTRWord">
|
||||
|
@ -1059,7 +1059,7 @@
|
|||
<string>Word</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Enable trace record with 2 bytes per byte to record how many times the code has been executed.</string>
|
||||
<string>Enable trace coverage with 1 word to record how many times an instruction has been executed.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTRTIBT">
|
||||
|
@ -1068,10 +1068,10 @@
|
|||
<normaloff>:/Default/icons/traceinto.png</normaloff>:/Default/icons/traceinto.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trace into beyond trace record</string>
|
||||
<string>Step into until reaching uncovered code</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Trace into until the current instruction was not executed before. Equivalent command "tibt"</string>
|
||||
<string>Step into until reaching an instruction that was not covered before. Equivalent command "tibt"</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTRTOBT">
|
||||
|
@ -1080,10 +1080,10 @@
|
|||
<normaloff>:/Default/icons/traceover.png</normaloff>:/Default/icons/traceover.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trace over beyond trace record</string>
|
||||
<string>Step over until reaching uncovered code</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Trace over until the current instruction was not executed before. Equivalent command "tobt"</string>
|
||||
<string>Step over until reaching an instruction that was not covered before. Equivalent command "tobt"</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTRTIIT">
|
||||
|
@ -1092,10 +1092,10 @@
|
|||
<normaloff>:/Default/icons/arrow-step-into.png</normaloff>:/Default/icons/arrow-step-into.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trace into into trace record</string>
|
||||
<string>Step into until reaching covered code</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Trace into until the current instruction was executed before. Equivalent command "tiit"</string>
|
||||
<string>Step into until reaching an instruction that has been covered before. Equivalent command "tiit"</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTRTOIT">
|
||||
|
@ -1104,10 +1104,10 @@
|
|||
<normaloff>:/Default/icons/arrow-step-over.png</normaloff>:/Default/icons/arrow-step-over.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trace over into trace record</string>
|
||||
<string>Step over until reaching covered code</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Trace over until the current instruction was executed before. Equivalent command "toit"</string>
|
||||
<string>Step over until reaching an instruction that has been covered before. Equivalent command "toit"</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTRNone">
|
||||
|
@ -1116,10 +1116,10 @@
|
|||
<normaloff>:/Default/icons/close-all-tabs.png</normaloff>:/Default/icons/close-all-tabs.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
<string>Disable</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Disable trace record</string>
|
||||
<string>Disable trace coverage</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRtu">
|
||||
|
|
|
@ -607,10 +607,10 @@ void MemoryMapView::dumpMemory()
|
|||
end = base + size;
|
||||
}
|
||||
|
||||
char modname[MAX_MODULE_SIZE] = "";
|
||||
if(!DbgFunctions()->ModNameFromAddr(DbgEval("mod.main()"), modname, false))
|
||||
*modname = '\0';
|
||||
QString defaultFile = QString("%1/%2%3.bin").arg(QDir::currentPath(), *modname ? modname + QString("_") : "", getCellContent(getInitialSelection(), 0));
|
||||
auto modname = mainModuleName();
|
||||
if(!modname.isEmpty())
|
||||
modname += '_';
|
||||
QString defaultFile = QString("%1/%2%3.bin").arg(QDir::currentPath(), modname, getCellContent(getInitialSelection(), 0));
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save Memory Region"), defaultFile, tr("Binary files (*.bin);;All files (*.*)"));
|
||||
|
||||
if(fileName.length())
|
||||
|
@ -622,11 +622,11 @@ void MemoryMapView::dumpMemory()
|
|||
|
||||
void MemoryMapView::loadMemory()
|
||||
{
|
||||
char modname[MAX_MODULE_SIZE] = "";
|
||||
if(!DbgFunctions()->ModNameFromAddr(DbgEval("mod.main()"), modname, false))
|
||||
*modname = '\0';
|
||||
auto modname = mainModuleName();
|
||||
if(!modname.isEmpty())
|
||||
modname += '_';
|
||||
auto addr = getCellContent(getInitialSelection(), 0);
|
||||
QString defaultFile = QString("%1/%2%3.bin").arg(QDir::currentPath(), *modname ? modname + QString("_") : "", addr);
|
||||
QString defaultFile = QString("%1/%2%3.bin").arg(QDir::currentPath(), modname, addr);
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Load Memory Region"), defaultFile, tr("Binary files (*.bin);;All files (*.*)"));
|
||||
|
||||
if(fileName.length())
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <QMessageBox>
|
||||
#include "BrowseDialog.h"
|
||||
#include "MiscUtil.h"
|
||||
#include "Tracer/TraceBrowser.h"
|
||||
|
||||
SimpleTraceDialog::SimpleTraceDialog(QWidget* parent) :
|
||||
QDialog(parent),
|
||||
|
@ -52,6 +53,16 @@ void SimpleTraceDialog::on_btnOk_clicked()
|
|||
if(msgyn.exec() == QMessageBox::No)
|
||||
return;
|
||||
}
|
||||
if(ui->chkRecordTrace->isChecked())
|
||||
{
|
||||
if(!TraceBrowser::toggleTraceRecording(this))
|
||||
{
|
||||
ui->chkRecordTrace->setChecked(false);
|
||||
SimpleWarningBox(this, tr("Error"), tr("Trace recording was requested, but not enabled."));
|
||||
return;
|
||||
}
|
||||
ui->chkRecordTrace->setChecked(false);
|
||||
}
|
||||
auto logText = ui->editLogText->addHistoryClear();
|
||||
auto logCondition = ui->editLogCondition->addHistoryClear();
|
||||
if(!DbgCmdExecDirect(QString("TraceSetLog \"%1\", \"%2\"").arg(escapeText(logText), escapeText(logCondition)).toUtf8().constData()))
|
||||
|
@ -89,9 +100,33 @@ void SimpleTraceDialog::on_btnOk_clicked()
|
|||
|
||||
void SimpleTraceDialog::on_btnLogFile_clicked()
|
||||
{
|
||||
BrowseDialog browse(this, tr("Trace log file"), tr("Enter the path to the log file."), tr("Log Files (*.txt *.log);;All Files (*.*)"), QCoreApplication::applicationDirPath(), true);
|
||||
BrowseDialog browse(
|
||||
this,
|
||||
tr("Trace log file"),
|
||||
tr("Enter the path to the log file."),
|
||||
tr("Log Files (*.txt *.log);;All Files (*.*)"),
|
||||
getDbPath(mainModuleName() + ".log", true),
|
||||
true
|
||||
);
|
||||
if(browse.exec() == QDialog::Accepted)
|
||||
mLogFile = browse.path;
|
||||
else
|
||||
mLogFile.clear();
|
||||
}
|
||||
|
||||
int SimpleTraceDialog::exec()
|
||||
{
|
||||
if(TraceBrowser::isRecording())
|
||||
{
|
||||
ui->chkRecordTrace->setEnabled(false);
|
||||
ui->chkRecordTrace->setChecked(true);
|
||||
ui->chkRecordTrace->setToolTip(tr("Trace recording already started"));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->chkRecordTrace->setEnabled(true);
|
||||
ui->chkRecordTrace->setChecked(false);
|
||||
ui->chkRecordTrace->setToolTip("");
|
||||
}
|
||||
return QDialog::exec();
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@ private slots:
|
|||
void on_btnOk_clicked();
|
||||
void on_btnLogFile_clicked();
|
||||
|
||||
public slots:
|
||||
int exec() override;
|
||||
|
||||
private:
|
||||
Ui::SimpleTraceDialog* ui;
|
||||
QString mTraceCommand;
|
||||
|
|
|
@ -65,6 +65,13 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkRecordTrace">
|
||||
<property name="text">
|
||||
<string>&Record trace</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnLogFile">
|
||||
<property name="text">
|
||||
|
@ -195,6 +202,7 @@
|
|||
<tabstop>editCommandCondition</tabstop>
|
||||
<tabstop>spinMaxTraceCount</tabstop>
|
||||
<tabstop>editSwitchCondition</tabstop>
|
||||
<tabstop>chkRecordTrace</tabstop>
|
||||
<tabstop>btnLogFile</tabstop>
|
||||
<tabstop>btnOk</tabstop>
|
||||
<tabstop>btnCancel</tabstop>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "ui_SystemBreakpointScriptDialog.h"
|
||||
#include "Bridge.h"
|
||||
#include "Configuration.h"
|
||||
#include "MiscUtil.h"
|
||||
#include <QDirModel>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
|
@ -33,12 +34,7 @@ SystemBreakpointScriptDialog::SystemBreakpointScriptDialog(QWidget* parent) :
|
|||
|
||||
if(DbgIsDebugging())
|
||||
{
|
||||
char moduleName[MAX_MODULE_SIZE];
|
||||
if(DbgFunctions()->ModNameFromAddr(DbgValFromString("mod.main()"), moduleName, true))
|
||||
{
|
||||
ui->groupBoxDebuggee->setTitle(tr("2. System breakpoint script for %1").arg(moduleName));
|
||||
}
|
||||
|
||||
ui->groupBoxDebuggee->setTitle(tr("2. System breakpoint script for %1").arg(mainModuleName(true)));
|
||||
ui->lineEditDebuggee->setText(DbgFunctions()->DbgGetDebuggeeInitScript());
|
||||
}
|
||||
else
|
||||
|
@ -122,14 +118,7 @@ void SystemBreakpointScriptDialog::on_openDebuggee_clicked()
|
|||
if(msgyn.exec() == QMessageBox::Yes)
|
||||
{
|
||||
// The new script is at db dir
|
||||
QString defaultFileName;
|
||||
char moduleName[MAX_MODULE_SIZE];
|
||||
if(DbgFunctions()->ModNameFromAddr(DbgValFromString("mod.main()"), moduleName, false))
|
||||
{
|
||||
defaultFileName = QString::fromUtf8(moduleName);
|
||||
}
|
||||
defaultFileName = defaultFileName + ".autorun.txt";
|
||||
defaultFileName = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + QDir::separator() + "db" + QDir::separator() + defaultFileName);
|
||||
auto defaultFileName = getDbPath(mainModuleName() + ".autorun.txt");
|
||||
// Create it
|
||||
if(!QFile::exists(defaultFileName))
|
||||
{
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include "Imports.h"
|
||||
#include <QString>
|
||||
|
||||
void DbgCmdExec(const QString & cmd)
|
||||
bool DbgCmdExec(const QString & cmd)
|
||||
{
|
||||
DbgCmdExec(cmd.toUtf8().constData());
|
||||
return DbgCmdExec(cmd.toUtf8().constData());
|
||||
}
|
||||
|
||||
bool DbgCmdExecDirect(const QString & cmd)
|
||||
|
|
|
@ -13,5 +13,5 @@
|
|||
// Convenience overloads
|
||||
class QString;
|
||||
|
||||
void DbgCmdExec(const QString & cmd);
|
||||
bool DbgCmdExec(const QString & cmd);
|
||||
bool DbgCmdExecDirect(const QString & cmd);
|
||||
|
|
|
@ -67,6 +67,41 @@ bool TraceBrowser::isFileOpened() const
|
|||
return mTraceFile && mTraceFile->Progress() == 100 && mTraceFile->Length() > 0;
|
||||
}
|
||||
|
||||
bool TraceBrowser::isRecording()
|
||||
{
|
||||
return DbgEval("tr.isrecording()") != 0;
|
||||
}
|
||||
|
||||
bool TraceBrowser::toggleTraceRecording(QWidget* parent)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
if(isRecording())
|
||||
{
|
||||
return DbgCmdExecDirect("StopTraceRecording");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto extension = ArchValue(".trace32", ".trace64");
|
||||
BrowseDialog browse(
|
||||
parent,
|
||||
tr("Start trace recording"),
|
||||
tr("Trace recording file"),
|
||||
tr("Trace recordings (*.%1);;All files (*.*)").arg(extension),
|
||||
getDbPath(mainModuleName() + extension, true),
|
||||
true
|
||||
);
|
||||
if(browse.exec() == QDialog::Accepted)
|
||||
{
|
||||
if(browse.path.contains(QChar('"')) || browse.path.contains(QChar('\'')))
|
||||
SimpleErrorBox(parent, tr("Error"), tr("File name contains invalid character."));
|
||||
else
|
||||
return DbgCmdExecDirect(QString("StartTraceRecording \"%1\"").arg(browse.path));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString TraceBrowser::getAddrText(dsint cur_addr, char label[MAX_LABEL_SIZE], bool getLabel)
|
||||
{
|
||||
QString addrText = "";
|
||||
|
@ -784,8 +819,9 @@ void TraceBrowser::prepareData()
|
|||
{
|
||||
if(mTraceFile->Progress() == 100)
|
||||
{
|
||||
if(mTraceFile->Length() < getTableOffset() + viewables)
|
||||
lines = mTraceFile->Length() - getTableOffset();
|
||||
duint tableOffset = getTableOffset();
|
||||
if(mTraceFile->Length() < tableOffset + viewables)
|
||||
lines = mTraceFile->Length() - tableOffset;
|
||||
else
|
||||
lines = viewables;
|
||||
}
|
||||
|
@ -803,15 +839,21 @@ void TraceBrowser::setupRightClickContextMenu()
|
|||
else
|
||||
return mTraceFile->Registers(getInitialSelection()).regcontext.cip;
|
||||
});
|
||||
QAction* toggleRunTrace = makeShortcutAction(DIcon("trace"), tr("Start Run Trace"), SLOT(toggleRunTraceSlot()), "ActionToggleRunTrace");
|
||||
mMenuBuilder->addAction(toggleRunTrace, [toggleRunTrace](QMenu*)
|
||||
QAction* toggleTraceRecording = makeShortcutAction(DIcon("control-record"), tr("Start recording"), SLOT(toggleTraceRecordingSlot()), "ActionToggleRunTrace");
|
||||
mMenuBuilder->addAction(toggleTraceRecording, [toggleTraceRecording](QMenu*)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
if(DbgValFromString("tr.runtraceenabled()") == 1)
|
||||
toggleRunTrace->setText(tr("Stop Run Trace"));
|
||||
if(isRecording())
|
||||
{
|
||||
toggleTraceRecording->setText(tr("Stop recording"));
|
||||
toggleTraceRecording->setIcon(DIcon("control-stop"));
|
||||
}
|
||||
else
|
||||
toggleRunTrace->setText(tr("Start Run Trace"));
|
||||
{
|
||||
toggleTraceRecording->setText(tr("Start recording"));
|
||||
toggleTraceRecording->setIcon(DIcon("control-record"));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
auto mTraceFileIsNull = [this](QMenu*)
|
||||
|
@ -830,11 +872,11 @@ void TraceBrowser::setupRightClickContextMenu()
|
|||
else
|
||||
return false;
|
||||
});
|
||||
mMenuBuilder->addAction(makeAction(DIcon("fatal-error"), tr("Close"), SLOT(closeFileSlot())), [this](QMenu*)
|
||||
mMenuBuilder->addAction(makeAction(DIcon("close"), tr("Close recording"), SLOT(closeFileSlot())), [this](QMenu*)
|
||||
{
|
||||
return mTraceFile != nullptr;
|
||||
});
|
||||
mMenuBuilder->addAction(makeAction(DIcon("fatal-error"), tr("Close and delete"), SLOT(closeDeleteSlot())), [this](QMenu*)
|
||||
mMenuBuilder->addAction(makeAction(DIcon("delete"), tr("Delete recording"), SLOT(closeDeleteSlot())), [this](QMenu*)
|
||||
{
|
||||
return mTraceFile != nullptr;
|
||||
});
|
||||
|
@ -1257,7 +1299,14 @@ void TraceBrowser::updateColors()
|
|||
|
||||
void TraceBrowser::openFileSlot()
|
||||
{
|
||||
BrowseDialog browse(this, tr("Open run trace file"), tr("Open trace file"), tr("Run trace files (*.%1);;All files (*.*)").arg(ArchValue("trace32", "trace64")), QApplication::applicationDirPath() + QDir::separator() + "db", false);
|
||||
BrowseDialog browse(
|
||||
this,
|
||||
tr("Open trace recording"),
|
||||
tr("Trace recording"),
|
||||
tr("Trace recordings (*.%1);;All files (*.*)").arg(ArchValue("trace32", "trace64")),
|
||||
getDbPath(),
|
||||
false
|
||||
);
|
||||
if(browse.exec() != QDialog::Accepted)
|
||||
return;
|
||||
emit openSlot(browse.path);
|
||||
|
@ -1276,39 +1325,15 @@ void TraceBrowser::openSlot(const QString & fileName)
|
|||
mTraceFile->Open(fileName);
|
||||
}
|
||||
|
||||
void TraceBrowser::toggleRunTraceSlot()
|
||||
void TraceBrowser::toggleTraceRecordingSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
if(DbgValFromString("tr.runtraceenabled()") == 1)
|
||||
DbgCmdExec("StopRunTrace");
|
||||
else
|
||||
{
|
||||
QString defaultFileName;
|
||||
char moduleName[MAX_MODULE_SIZE];
|
||||
QDateTime currentTime = QDateTime::currentDateTime();
|
||||
duint defaultModule = DbgValFromString("mod.main()");
|
||||
if(DbgFunctions()->ModNameFromAddr(defaultModule, moduleName, false))
|
||||
{
|
||||
defaultFileName = QString::fromUtf8(moduleName);
|
||||
}
|
||||
defaultFileName += "-" + QLocale(QString(currentLocale)).toString(currentTime.date()) + " " + currentTime.time().toString("hh-mm-ss") + ArchValue(".trace32", ".trace64");
|
||||
BrowseDialog browse(this, tr("Select stored file"), tr("Store run trace to the following file"),
|
||||
tr("Run trace files (*.%1);;All files (*.*)").arg(ArchValue("trace32", "trace64")), QCoreApplication::applicationDirPath() + QDir::separator() + "db" + QDir::separator() + defaultFileName, true);
|
||||
if(browse.exec() == QDialog::Accepted)
|
||||
{
|
||||
if(browse.path.contains(QChar('"')) || browse.path.contains(QChar('\'')))
|
||||
SimpleErrorBox(this, tr("Error"), tr("File name contains invalid character."));
|
||||
else
|
||||
DbgCmdExec(QString("StartRunTrace \"%1\"").arg(browse.path));
|
||||
}
|
||||
}
|
||||
toggleTraceRecording(this);
|
||||
}
|
||||
|
||||
void TraceBrowser::closeFileSlot()
|
||||
{
|
||||
if(DbgValFromString("tr.runtraceenabled()") == 1)
|
||||
DbgCmdExec("StopRunTrace");
|
||||
if(isRecording())
|
||||
DbgCmdExecDirect("StopTraceRecording");
|
||||
mTraceFile->Close();
|
||||
delete mTraceFile;
|
||||
mTraceFile = nullptr;
|
||||
|
@ -1317,11 +1342,11 @@ void TraceBrowser::closeFileSlot()
|
|||
|
||||
void TraceBrowser::closeDeleteSlot()
|
||||
{
|
||||
QMessageBox msgbox(QMessageBox::Critical, tr("Close and delete"), tr("Are you really going to delete this file?"), QMessageBox::Yes | QMessageBox::Cancel, this);
|
||||
QMessageBox msgbox(QMessageBox::Critical, tr("Delete recording"), tr("Are you sure you want to delete this recording?"), QMessageBox::Yes | QMessageBox::No, this);
|
||||
if(msgbox.exec() == QMessageBox::Yes)
|
||||
{
|
||||
if(DbgValFromString("tr.runtraceenabled()") == 1)
|
||||
DbgCmdExecDirect("StopRunTrace");
|
||||
if(isRecording())
|
||||
DbgCmdExecDirect("StopTraceRecording");
|
||||
mTraceFile->Delete();
|
||||
delete mTraceFile;
|
||||
mTraceFile = nullptr;
|
||||
|
@ -1333,7 +1358,7 @@ void TraceBrowser::parseFinishedSlot()
|
|||
{
|
||||
if(mTraceFile->isError())
|
||||
{
|
||||
SimpleErrorBox(this, tr("Error"), tr("Error when opening run trace file"));
|
||||
SimpleErrorBox(this, tr("Error"), tr("Error when opening trace recording"));
|
||||
delete mTraceFile;
|
||||
mTraceFile = nullptr;
|
||||
setRowCount(0);
|
||||
|
@ -1829,7 +1854,7 @@ void TraceBrowser::updateSlot()
|
|||
{
|
||||
if(mTraceFile && mTraceFile->Progress() == 100) // && this->isVisible()
|
||||
{
|
||||
if(DbgValFromString("tr.runtraceenabled()") == 1)
|
||||
if(isRecording())
|
||||
{
|
||||
mTraceFile->purgeLastPage();
|
||||
setRowCount(mTraceFile->Length());
|
||||
|
|
|
@ -31,6 +31,9 @@ public:
|
|||
bool isFileOpened() const;
|
||||
TraceFileReader* getTraceFile() { return mTraceFile; }
|
||||
|
||||
static bool isRecording();
|
||||
static bool toggleTraceRecording(QWidget* parent);
|
||||
|
||||
private:
|
||||
enum TableColumnIndex
|
||||
{
|
||||
|
@ -151,7 +154,7 @@ signals:
|
|||
public slots:
|
||||
void openFileSlot();
|
||||
void openSlot(const QString & fileName);
|
||||
void toggleRunTraceSlot();
|
||||
void toggleTraceRecordingSlot();
|
||||
void closeFileSlot();
|
||||
void closeDeleteSlot();
|
||||
void parseFinishedSlot();
|
||||
|
|
|
@ -448,16 +448,16 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
defaultShortcuts.insert("DebugCommand", Shortcut({tr("Debug"), tr("Command")}, "Ctrl+Return", true));
|
||||
defaultShortcuts.insert("DebugTraceIntoConditional", Shortcut({tr("Debug"), tr("Trace into...")}, "Ctrl+Alt+F7", true));
|
||||
defaultShortcuts.insert("DebugTraceOverConditional", Shortcut({tr("Debug"), tr("Trace over...")}, "Ctrl+Alt+F8", true));
|
||||
defaultShortcuts.insert("DebugEnableTraceRecordBit", Shortcut({tr("Debug"), tr("Trace Record"), tr("Bit")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceRecordNone", Shortcut({tr("Debug"), tr("Trace Record"), tr("None")}, "", true));
|
||||
defaultShortcuts.insert("DebugEnableTraceRecordBit", Shortcut({tr("Debug"), tr("Trace coverage"), tr("Bit")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceRecordNone", Shortcut({tr("Debug"), tr("Trace coverage"), tr("None")}, "", true));
|
||||
defaultShortcuts.insert("DebugInstrUndo", Shortcut({tr("Debug"), tr("Undo instruction")}, "Alt+U", true));
|
||||
defaultShortcuts.insert("DebugAnimateInto", Shortcut({tr("Debug"), tr("Animate into")}, "Ctrl+F7", true));
|
||||
defaultShortcuts.insert("DebugAnimateOver", Shortcut({tr("Debug"), tr("Animate over")}, "Ctrl+F8", true));
|
||||
defaultShortcuts.insert("DebugAnimateCommand", Shortcut({tr("Debug"), tr("Animate command")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceIntoIntoTracerecord", Shortcut({tr("Debug"), tr("Trace into into trace record")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceOverIntoTracerecord", Shortcut({tr("Debug"), tr("Trace over into trace record")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceIntoBeyondTracerecord", Shortcut({tr("Debug"), tr("Trace into beyond trace record")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceOverBeyondTracerecord", Shortcut({tr("Debug"), tr("Trace over beyond trace record")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceIntoIntoTracerecord", Shortcut({tr("Debug"), tr("Step into until reaching uncovered code")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceOverIntoTracerecord", Shortcut({tr("Debug"), tr("Step over until reaching uncovered code")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceIntoBeyondTracerecord", Shortcut({tr("Debug"), tr("Step into until reaching covered code")}, "", true));
|
||||
defaultShortcuts.insert("DebugTraceOverBeyondTracerecord", Shortcut({tr("Debug"), tr("Step over until reaching covered code")}, "", true));
|
||||
|
||||
defaultShortcuts.insert("PluginsScylla", Shortcut({tr("Plugins"), tr("Scylla")}, "Ctrl+I", true));
|
||||
|
||||
|
@ -623,7 +623,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
defaultShortcuts.insert("ActionModifyValue", Shortcut({tr("Actions"), tr("Modify value")}, "Space"));
|
||||
defaultShortcuts.insert("ActionWatchDwordQword", Shortcut({tr("Actions"), tr("Watch DWORD/QWORD")}));
|
||||
defaultShortcuts.insert("ActionCopyFileOffset", Shortcut({tr("Actions"), tr("Copy File Offset")}));
|
||||
defaultShortcuts.insert("ActionToggleRunTrace", Shortcut({tr("Actions"), tr("Start or Stop Run Trace")}));
|
||||
defaultShortcuts.insert("ActionToggleRunTrace", Shortcut({tr("Actions"), tr("Start/Stop trace recording")}));
|
||||
|
||||
defaultShortcuts.insert("ActionCopyCroppedTable", Shortcut({tr("Actions"), tr("Copy -> Cropped Table")}));
|
||||
defaultShortcuts.insert("ActionCopyTable", Shortcut({tr("Actions"), tr("Copy -> Table")}));
|
||||
|
|
|
@ -176,7 +176,14 @@ QIcon getFileIcon(QString file)
|
|||
//Export table in CSV. TODO: Display a dialog where the user choose what column to export and in which encoding
|
||||
bool ExportCSV(dsint rows, dsint columns, std::vector<QString> headers, std::function<QString(dsint, dsint)> getCellContent)
|
||||
{
|
||||
BrowseDialog browse(nullptr, QApplication::translate("ExportCSV", "Export data in CSV format"), QApplication::translate("ExportCSV", "Enter the CSV file name to export"), QApplication::translate("ExportCSV", "CSV files (*.csv);;All files (*.*)"), QApplication::applicationDirPath() + QDir::separator() + "db", true);
|
||||
BrowseDialog browse(
|
||||
nullptr,
|
||||
QApplication::translate("ExportCSV", "Export data in CSV format"),
|
||||
QApplication::translate("ExportCSV", "Enter the CSV file name to export"),
|
||||
QApplication::translate("ExportCSV", "CSV files (*.csv);;All files (*.*)"),
|
||||
getDbPath("export.csv", true),
|
||||
true
|
||||
);
|
||||
browse.setWindowIcon(DIcon("database-export"));
|
||||
if(browse.exec() == QDialog::Accepted)
|
||||
{
|
||||
|
@ -342,3 +349,44 @@ QIcon DIconHelper(QString name)
|
|||
}
|
||||
return QIcon::fromTheme(name);
|
||||
}
|
||||
|
||||
QString getDbPath(const QString & filename, bool addDateTimeSuffix)
|
||||
{
|
||||
auto path = QString("%1/db").arg(QCoreApplication::applicationDirPath());
|
||||
if(!filename.isEmpty())
|
||||
{
|
||||
path += '/';
|
||||
path += filename;
|
||||
// Add a date suffix before the extension
|
||||
if(addDateTimeSuffix)
|
||||
{
|
||||
auto extensionIdx = path.lastIndexOf('.');
|
||||
if(extensionIdx == -1)
|
||||
{
|
||||
extensionIdx = path.length();
|
||||
}
|
||||
auto now = QDateTime::currentDateTime();
|
||||
auto suffix = QString().sprintf("-%04d%02d%02d-%02d%02d%02d",
|
||||
now.date().year(),
|
||||
now.date().month(),
|
||||
now.date().day(),
|
||||
now.time().hour(),
|
||||
now.time().minute(),
|
||||
now.time().second()
|
||||
);
|
||||
path.insert(extensionIdx, suffix);
|
||||
}
|
||||
}
|
||||
return QDir::toNativeSeparators(path);
|
||||
}
|
||||
|
||||
QString mainModuleName(bool extension)
|
||||
{
|
||||
auto base = DbgEval("mod.main()");
|
||||
char name[MAX_MODULE_SIZE] = "";
|
||||
if(base && DbgFunctions()->ModNameFromAddr(base, name, extension))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
|
|
@ -22,5 +22,7 @@ bool isEaster();
|
|||
bool isSeasonal();
|
||||
QIcon getFileIcon(QString file);
|
||||
QIcon DIconHelper(QString name);
|
||||
QString getDbPath(const QString & filename = QString(), bool addDateTimeSuffix = false);
|
||||
QString mainModuleName(bool extension = false);
|
||||
|
||||
#define DIcon(name) [](QString arg) { static QIcon icon(DIconHelper(std::move(arg))); return icon; }(name)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 588 B |
Binary file not shown.
After Width: | Height: | Size: 529 B |
Binary file not shown.
After Width: | Height: | Size: 699 B |
|
@ -316,6 +316,9 @@
|
|||
<file>icons/crash_dump.png</file>
|
||||
<file>icons/exclamation.png</file>
|
||||
<file>index.theme</file>
|
||||
<file>icons/control-record.png</file>
|
||||
<file>icons/delete.png</file>
|
||||
<file>icons/close.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/css">
|
||||
<file>default.css</file>
|
||||
|
|
Loading…
Reference in New Issue