Implement basic support for per-breakpoint log files
This commit is contained in:
parent
1342a9f449
commit
db264d18d5
|
@ -510,6 +510,21 @@ bool BpSetCommandCondition(duint Address, BP_TYPE Type, const char* Condition)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BpSetLogFile(duint Address, BP_TYPE Type, const char* LogFile)
|
||||
{
|
||||
ASSERT_DEBUGGING("Command function call");
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Set breakpoint hit command
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
|
||||
bpInfo->logFile = LogFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BpSetFastResume(duint Address, BP_TYPE Type, bool fastResume)
|
||||
{
|
||||
ASSERT_DEBUGGING("Command function call");
|
||||
|
@ -843,6 +858,7 @@ void BpCacheSave(JSON Root)
|
|||
json_object_set_new(jsonObj, "logCondition", json_string(breakpoint.logCondition));
|
||||
json_object_set_new(jsonObj, "commandText", json_string(breakpoint.commandText));
|
||||
json_object_set_new(jsonObj, "commandCondition", json_string(breakpoint.commandCondition));
|
||||
json_object_set_new(jsonObj, "logFile", json_string(breakpoint.logFile));
|
||||
json_object_set_new(jsonObj, "fastResume", json_boolean(breakpoint.fastResume));
|
||||
json_object_set_new(jsonObj, "silent", json_boolean(breakpoint.silent));
|
||||
json_array_append_new(jsonBreakpoints, jsonObj);
|
||||
|
@ -908,6 +924,7 @@ void BpCacheLoad(JSON Root, bool migrateCommandCondition)
|
|||
loadStringValue(value, breakpoint.logCondition, "logCondition");
|
||||
loadStringValue(value, breakpoint.commandText, "commandText");
|
||||
loadStringValue(value, breakpoint.commandCondition, "commandCondition");
|
||||
loadStringValue(value, breakpoint.logFile, "logFile");
|
||||
|
||||
// On 2023-06-10 the default of the command condition was changed from $breakpointcondition to 1
|
||||
// If we detect an older database, try to preserve the old behavior.
|
||||
|
|
|
@ -38,6 +38,7 @@ struct BREAKPOINT
|
|||
std::string logCondition; // condition to log
|
||||
std::string commandText; // script command to execute.
|
||||
std::string commandCondition; // condition to execute the command
|
||||
std::string logFile; // file path to log to
|
||||
uint32 hitcount; // hit counter
|
||||
bool fastResume; // if true, debugger resumes without any GUI/Script/Plugin interaction.
|
||||
duint memsize; // memory breakpoint size (not implemented)
|
||||
|
@ -62,6 +63,7 @@ bool BpSetLogText(duint Address, BP_TYPE Type, const char* Log);
|
|||
bool BpSetLogCondition(duint Address, BP_TYPE Type, const char* Condition);
|
||||
bool BpSetCommandText(duint Address, BP_TYPE Type, const char* Cmd);
|
||||
bool BpSetCommandCondition(duint Address, BP_TYPE Type, const char* Condition);
|
||||
bool BpSetLogFile(duint Address, BP_TYPE Type, const char* LogFile);
|
||||
bool BpSetFastResume(duint Address, BP_TYPE Type, bool fastResume);
|
||||
bool BpSetSingleshoot(duint Address, BP_TYPE Type, bool singleshoot);
|
||||
bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module, duint base = 0);
|
||||
|
|
|
@ -59,6 +59,11 @@ static bool cbDebugSetBPXCommandConditionCommon(BP_TYPE Type, int argc, char* ar
|
|||
return cbDebugSetBPXTextCommon(Type, argc, argv, String(GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "command condition"))), BpSetCommandCondition);
|
||||
}
|
||||
|
||||
static bool cbDebugSetBPXLogFileCommon(BP_TYPE Type, int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXTextCommon(Type, argc, argv, String(GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "log file"))), BpSetLogFile);
|
||||
}
|
||||
|
||||
static bool cbDebugSetBPXFastResumeCommon(BP_TYPE Type, int argc, char* argv[])
|
||||
{
|
||||
BREAKPOINT bp;
|
||||
|
@ -208,6 +213,11 @@ bool cbDebugSetBPXCommandCondition(int argc, char* argv[])
|
|||
return cbDebugSetBPXCommandConditionCommon(BPNORMAL, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXLogFile(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXLogFileCommon(BPNORMAL, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXFastResume(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXFastResumeCommon(BPNORMAL, argc, argv);
|
||||
|
@ -263,6 +273,11 @@ bool cbDebugSetBPXHardwareCommandCondition(int argc, char* argv[])
|
|||
return cbDebugSetBPXCommandConditionCommon(BPHARDWARE, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXHardwareLogFile(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXLogFileCommon(BPHARDWARE, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXHardwareFastResume(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXFastResumeCommon(BPHARDWARE, argc, argv);
|
||||
|
@ -318,6 +333,11 @@ bool cbDebugSetBPXMemoryCommandCondition(int argc, char* argv[])
|
|||
return cbDebugSetBPXCommandConditionCommon(BPMEMORY, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXMemoryLogFile(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXLogFileCommon(BPMEMORY, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXMemoryFastResume(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXFastResumeCommon(BPMEMORY, argc, argv);
|
||||
|
@ -373,6 +393,11 @@ bool cbDebugSetBPXDLLCommandCondition(int argc, char* argv[])
|
|||
return cbDebugSetBPXCommandConditionCommon(BPDLL, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXDLLLogFile(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXLogFileCommon(BPDLL, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXDLLFastResume(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXFastResumeCommon(BPDLL, argc, argv);
|
||||
|
@ -428,6 +453,11 @@ bool cbDebugSetBPXExceptionCommandCondition(int argc, char* argv[])
|
|||
return cbDebugSetBPXCommandConditionCommon(BPEXCEPTION, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXExceptionLogFile(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXLogFileCommon(BPEXCEPTION, argc, argv);
|
||||
}
|
||||
|
||||
bool cbDebugSetBPXExceptionFastResume(int argc, char* argv[])
|
||||
{
|
||||
return cbDebugSetBPXFastResumeCommon(BPEXCEPTION, argc, argv);
|
||||
|
|
|
@ -8,6 +8,7 @@ bool cbDebugSetBPXLog(int argc, char* argv[]);
|
|||
bool cbDebugSetBPXLogCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXCommand(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXCommandCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXLogFile(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXFastResume(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXSingleshoot(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXSilent(int argc, char* argv[]);
|
||||
|
@ -20,6 +21,7 @@ bool cbDebugSetBPXHardwareLog(int argc, char* argv[]);
|
|||
bool cbDebugSetBPXHardwareLogCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXHardwareCommand(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXHardwareCommandCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXHardwareLogFile(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXHardwareFastResume(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXHardwareSingleshoot(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXHardwareSilent(int argc, char* argv[]);
|
||||
|
@ -32,6 +34,7 @@ bool cbDebugSetBPXMemoryLog(int argc, char* argv[]);
|
|||
bool cbDebugSetBPXMemoryLogCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXMemoryCommand(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXMemoryCommandCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXMemoryLogFile(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXMemoryFastResume(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXMemorySingleshoot(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXMemorySilent(int argc, char* argv[]);
|
||||
|
@ -44,6 +47,7 @@ bool cbDebugSetBPXDLLLog(int argc, char* argv[]);
|
|||
bool cbDebugSetBPXDLLLogCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXDLLCommand(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXDLLCommandCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXDLLLogFile(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXDLLFastResume(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXDLLSingleshoot(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXDLLSilent(int argc, char* argv[]);
|
||||
|
@ -56,6 +60,7 @@ bool cbDebugSetBPXExceptionLog(int argc, char* argv[]);
|
|||
bool cbDebugSetBPXExceptionLogCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXExceptionCommand(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXExceptionCommandCondition(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXExceptionLogFile(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXExceptionFastResume(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXExceptionSingleshoot(int argc, char* argv[]);
|
||||
bool cbDebugSetBPXExceptionSilent(int argc, char* argv[]);
|
||||
|
|
|
@ -102,6 +102,44 @@ static TITANCBSTEP gStepIntoPartyCallback;
|
|||
HANDLE hDebugLoopThread = nullptr;
|
||||
DWORD dwDebugFlags = 0;
|
||||
|
||||
struct BreakpointLogFile
|
||||
{
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
bool needsFlush = false;
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, BreakpointLogFile> gBreakpointLogFiles;
|
||||
|
||||
static BreakpointLogFile & dbgOpenBreakpointLogFile(const std::string & logFile)
|
||||
{
|
||||
// TODO: convert filename to lower case?
|
||||
|
||||
auto itr = gBreakpointLogFiles.find(logFile);
|
||||
if(itr != gBreakpointLogFiles.end())
|
||||
return itr->second;
|
||||
|
||||
auto hFile = CreateFileW(
|
||||
StringUtils::Utf8ToUtf16(logFile).c_str(),
|
||||
FILE_APPEND_DATA | FILE_GENERIC_READ, FILE_SHARE_READ,
|
||||
nullptr,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
nullptr
|
||||
);
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
SetFilePointer(hFile, 0, nullptr, FILE_END);
|
||||
BreakpointLogFile newFile;
|
||||
newFile.hFile = hFile;
|
||||
return gBreakpointLogFiles.emplace(logFile, newFile).first->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
static BreakpointLogFile invalidLogFile;
|
||||
return invalidLogFile;
|
||||
}
|
||||
}
|
||||
|
||||
static duint dbgcleartracestate()
|
||||
{
|
||||
auto steps = traceState.StepCount();
|
||||
|
@ -279,6 +317,15 @@ void cbDebuggerPaused()
|
|||
}
|
||||
// Watchdog
|
||||
cbCheckWatchdog(0, nullptr);
|
||||
// Flush breakpoint logs
|
||||
for(auto & itr : gBreakpointLogFiles)
|
||||
{
|
||||
if(itr.second.needsFlush)
|
||||
{
|
||||
FlushFileBuffers(itr.second.hFile);
|
||||
itr.second.needsFlush = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dbginit()
|
||||
|
@ -949,9 +996,34 @@ static void cbGenericBreakpoint(BP_TYPE bptype, const void* ExceptionAddress = n
|
|||
// Update breakpoint view
|
||||
DebugUpdateBreakpointsViewAsync();
|
||||
|
||||
DWORD logFileError = ERROR_SUCCESS;
|
||||
if(!bp.logText.empty() && logCondition == 1) //log
|
||||
{
|
||||
dprintf_untranslated("%s\n", stringformatinline(bp.logText).c_str());
|
||||
auto formattedText = stringformatinline(bp.logText);
|
||||
if(!bp.logFile.empty())
|
||||
{
|
||||
auto logFile = dbgOpenBreakpointLogFile(bp.logFile);
|
||||
if(logFile.hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Pause and display the error
|
||||
breakCondition = 1;
|
||||
logFileError = GetLastError();
|
||||
|
||||
// Show the log in the regular log tab
|
||||
dprintf_untranslated("%s\n", formattedText.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
formattedText += "\n";
|
||||
DWORD written = 0;
|
||||
WriteFile(logFile.hFile, formattedText.c_str(), (DWORD)formattedText.length(), &written, nullptr);
|
||||
logFile.needsFlush = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf_untranslated("%s\n", formattedText.c_str());
|
||||
}
|
||||
}
|
||||
if(!bp.commandText.empty() && commandCondition) //command
|
||||
{
|
||||
|
@ -980,6 +1052,13 @@ static void cbGenericBreakpoint(BP_TYPE bptype, const void* ExceptionAddress = n
|
|||
else //resume immediately
|
||||
unlock(WAITID_RUN);
|
||||
|
||||
// Make sure the log file error is displayed last
|
||||
if(logFileError != ERROR_SUCCESS)
|
||||
{
|
||||
String error = stringformatinline(StringUtils::sprintf("{winerror@%x}", GetLastError()));
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to open breakpoint log: %s (%s)\n"), bp.logFile.c_str(), error.c_str());
|
||||
}
|
||||
|
||||
//wait until the user resumes
|
||||
wait(WAITID_RUN);
|
||||
}
|
||||
|
@ -2955,6 +3034,13 @@ static void debugLoopFunction(INIT_STRUCT* init)
|
|||
DeleteFileW(gDllLoader.c_str());
|
||||
gDllLoader.clear();
|
||||
}
|
||||
|
||||
// Close the breakpoint log files
|
||||
for(const auto & itr : gBreakpointLogFiles)
|
||||
{
|
||||
CloseHandle(itr.second.hFile);
|
||||
}
|
||||
gBreakpointLogFiles.clear();
|
||||
}
|
||||
|
||||
void dbgsetdebuggeeinitscript(const char* fileName)
|
||||
|
|
|
@ -182,6 +182,7 @@ static void registercommands()
|
|||
dbgcmdnew("SetBreakpointLogCondition,bplogcondition", cbDebugSetBPXLogCondition, true); //set breakpoint logCondition
|
||||
dbgcmdnew("SetBreakpointCommand", cbDebugSetBPXCommand, true); //set breakpoint command on hit
|
||||
dbgcmdnew("SetBreakpointCommandCondition", cbDebugSetBPXCommandCondition, true); //set breakpoint commandCondition
|
||||
dbgcmdnew("SetBreakpointLogFile", cbDebugSetBPXLogFile, true); //set breakpoint logFile
|
||||
dbgcmdnew("SetBreakpointFastResume", cbDebugSetBPXFastResume, true); //set breakpoint fast resume
|
||||
dbgcmdnew("SetBreakpointSingleshoot", cbDebugSetBPXSingleshoot, true); //set breakpoint singleshoot
|
||||
dbgcmdnew("SetBreakpointSilent", cbDebugSetBPXSilent, true); //set breakpoint fast resume
|
||||
|
@ -194,6 +195,7 @@ static void registercommands()
|
|||
dbgcmdnew("SetHardwareBreakpointLogCondition,bphwlogcondition", cbDebugSetBPXHardwareLogCondition, true); //set breakpoint logText
|
||||
dbgcmdnew("SetHardwareBreakpointCommand", cbDebugSetBPXHardwareCommand, true); //set breakpoint command on hit
|
||||
dbgcmdnew("SetHardwareBreakpointCommandCondition", cbDebugSetBPXHardwareCommandCondition, true); //set breakpoint commandCondition
|
||||
dbgcmdnew("SetHardwareBreakpointLogFile", cbDebugSetBPXHardwareLogFile, true); //set breakpoint logFile
|
||||
dbgcmdnew("SetHardwareBreakpointFastResume", cbDebugSetBPXHardwareFastResume, true); //set breakpoint fast resume
|
||||
dbgcmdnew("SetHardwareBreakpointSingleshoot", cbDebugSetBPXHardwareSingleshoot, true); //set breakpoint singleshoot
|
||||
dbgcmdnew("SetHardwareBreakpointSilent", cbDebugSetBPXHardwareSilent, true); //set breakpoint fast resume
|
||||
|
@ -206,6 +208,7 @@ static void registercommands()
|
|||
dbgcmdnew("SetMemoryBreakpointLogCondition,bpmlogcondition", cbDebugSetBPXMemoryLogCondition, true); //set breakpoint logCondition
|
||||
dbgcmdnew("SetMemoryBreakpointCommand", cbDebugSetBPXMemoryCommand, true); //set breakpoint command on hit
|
||||
dbgcmdnew("SetMemoryBreakpointCommandCondition", cbDebugSetBPXMemoryCommandCondition, true); //set breakpoint commandCondition
|
||||
dbgcmdnew("SetMemoryBreakpointLogFile", cbDebugSetBPXMemoryLogFile, true); //set breakpoint logFile
|
||||
dbgcmdnew("SetMemoryBreakpointFastResume", cbDebugSetBPXMemoryFastResume, true); //set breakpoint fast resume
|
||||
dbgcmdnew("SetMemoryBreakpointSingleshoot", cbDebugSetBPXMemorySingleshoot, true); //set breakpoint singleshoot
|
||||
dbgcmdnew("SetMemoryBreakpointSilent", cbDebugSetBPXMemorySilent, true); //set breakpoint fast resume
|
||||
|
@ -218,6 +221,7 @@ static void registercommands()
|
|||
dbgcmdnew("SetLibrarianBreakpointLogCondition", cbDebugSetBPXDLLLogCondition, true); //set breakpoint logCondition
|
||||
dbgcmdnew("SetLibrarianBreakpointCommand", cbDebugSetBPXDLLCommand, true); //set breakpoint command on hit
|
||||
dbgcmdnew("SetLibrarianBreakpointCommandCondition", cbDebugSetBPXDLLCommandCondition, true); //set breakpoint commandCondition
|
||||
dbgcmdnew("SetLibrarianBreakpointLogFile", cbDebugSetBPXDLLLogFile, true); //set breakpoint logFile
|
||||
dbgcmdnew("SetLibrarianBreakpointFastResume", cbDebugSetBPXDLLFastResume, true); //set breakpoint fast resume
|
||||
dbgcmdnew("SetLibrarianBreakpointSingleshoot", cbDebugSetBPXDLLSingleshoot, true); //set breakpoint singleshoot
|
||||
dbgcmdnew("SetLibrarianBreakpointSilent", cbDebugSetBPXDLLSilent, true); //set breakpoint fast resume
|
||||
|
@ -230,6 +234,7 @@ static void registercommands()
|
|||
dbgcmdnew("SetExceptionBreakpointLogCondition", cbDebugSetBPXExceptionLogCondition, true); //set breakpoint logCondition
|
||||
dbgcmdnew("SetExceptionBreakpointCommand", cbDebugSetBPXExceptionCommand, true); //set breakpoint command on hit
|
||||
dbgcmdnew("SetExceptionBreakpointCommandCondition", cbDebugSetBPXExceptionCommandCondition, true); //set breakpoint commandCondition
|
||||
dbgcmdnew("SetExceptionBreakpointLogFile", cbDebugSetBPXExceptionLogFile, true); //set breakpoint logFile
|
||||
dbgcmdnew("SetExceptionBreakpointFastResume", cbDebugSetBPXExceptionFastResume, true); //set breakpoint fast resume
|
||||
dbgcmdnew("SetExceptionBreakpointSingleshoot", cbDebugSetBPXExceptionSingleshoot, true); //set breakpoint singleshoot
|
||||
dbgcmdnew("SetExceptionBreakpointSilent", cbDebugSetBPXExceptionSilent, true); //set breakpoint fast resume
|
||||
|
|
Loading…
Reference in New Issue