From e784a382e4e647badb490cf0cad52705a864bd69 Mon Sep 17 00:00:00 2001 From: Nicole <41876584+NicoleFaye@users.noreply.github.com> Date: Sun, 18 Jan 2026 19:41:33 -0800 Subject: [PATCH 1/5] Add Time Range Filter option for ttd code coverage analysis --- api/debuggerapi.h | 2 +- api/debuggercontroller.cpp | 11 +++-- api/ffi.h | 2 +- core/debuggercontroller.cpp | 22 ++++++++-- core/debuggercontroller.h | 2 +- core/ffi.cpp | 6 ++- ui/ttdanalysisdialog.cpp | 83 +++++++++++++++++++++++++++++++---- ui/ttdanalysisdialog.h | 8 +++- ui/ttdcoveragerenderlayer.cpp | 4 +- 9 files changed, 117 insertions(+), 23 deletions(-) diff --git a/api/debuggerapi.h b/api/debuggerapi.h index ebfdde5a..4f1b5496 100644 --- a/api/debuggerapi.h +++ b/api/debuggerapi.h @@ -807,7 +807,7 @@ namespace BinaryNinjaDebuggerAPI { // TTD Code Coverage Analysis Methods bool IsInstructionExecuted(uint64_t address); - bool RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t endAddress); + bool RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t endAddress, TTDPosition startTime, TTDPosition endTime); size_t GetExecutedInstructionCount() const; bool SaveCodeCoverageToFile(const std::string& filePath) const; bool LoadCodeCoverageFromFile(const std::string& filePath); diff --git a/api/debuggercontroller.cpp b/api/debuggercontroller.cpp index d4c5173b..809adcf6 100644 --- a/api/debuggercontroller.cpp +++ b/api/debuggercontroller.cpp @@ -1325,9 +1325,14 @@ bool DebuggerController::IsInstructionExecuted(uint64_t address) } -bool DebuggerController::RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t endAddress) -{ - return BNDebuggerRunCodeCoverageAnalysisRange(m_object, startAddress, endAddress); +bool DebuggerController::RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t endAddress, TTDPosition startTime, TTDPosition endTime) +{ + BNDebuggerTTDPosition startPos, endPos; + startPos.sequence = startTime.sequence; + startPos.step = startTime.step; + endPos.sequence = endTime.sequence; + endPos.step = endTime.step; + return BNDebuggerRunCodeCoverageAnalysisRange(m_object, startAddress, endAddress, startPos, endPos); } diff --git a/api/ffi.h b/api/ffi.h index ebc23813..516e111d 100644 --- a/api/ffi.h +++ b/api/ffi.h @@ -678,7 +678,7 @@ extern "C" // TTD Code Coverage Analysis Functions DEBUGGER_FFI_API bool BNDebuggerIsInstructionExecuted(BNDebuggerController* controller, uint64_t address); - DEBUGGER_FFI_API bool BNDebuggerRunCodeCoverageAnalysisRange(BNDebuggerController* controller, uint64_t startAddress, uint64_t endAddress); + DEBUGGER_FFI_API bool BNDebuggerRunCodeCoverageAnalysisRange(BNDebuggerController* controller, uint64_t startAddress, uint64_t endAddress, BNDebuggerTTDPosition startTime, BNDebuggerTTDPosition endTime); DEBUGGER_FFI_API size_t BNDebuggerGetExecutedInstructionCount(BNDebuggerController* controller); DEBUGGER_FFI_API bool BNDebuggerSaveCodeCoverageToFile(BNDebuggerController* controller, const char* filePath); DEBUGGER_FFI_API bool BNDebuggerLoadCodeCoverageFromFile(BNDebuggerController* controller, const char* filePath); diff --git a/core/debuggercontroller.cpp b/core/debuggercontroller.cpp index a51e0d3a..7558e99d 100644 --- a/core/debuggercontroller.cpp +++ b/core/debuggercontroller.cpp @@ -3227,7 +3227,7 @@ bool DebuggerController::IsInstructionExecuted(uint64_t address) } -bool DebuggerController::RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t endAddress) +bool DebuggerController::RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t endAddress, TTDPosition startTime, TTDPosition endTime) { if (!m_state->IsConnected() || !IsTTD()) { @@ -3245,7 +3245,18 @@ bool DebuggerController::RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t m_executedInstructions.clear(); m_codeCoverageAnalysisRun = false; - LogInfo("Starting TTD code coverage analysis for range 0x%" PRIX64 " - 0x%" PRIX64 "...", startAddress, endAddress); + LogInfo("Starting TTD code coverage analysis."); + LogInfo("\tAddress range: 0x%" PRIX64 " - 0x%" PRIX64, startAddress, endAddress); + //log time range + bool endTimeIsMax = endTime.sequence== std::numeric_limits::max() && endTime.step == std::numeric_limits::max(); + if(endTimeIsMax) + { + LogInfo("\tTime range: %" PRIX64 ":%" PRIX64 " - end of trace", startTime.sequence, startTime.step); + } + else{ + LogInfo("\tTime range: %" PRIX64 ":%" PRIX64 " - %" PRIX64 ":%" PRIX64, startTime.sequence, startTime.step, + endTime.sequence, endTime.step); + } // Query TTD for execute access covering the specified range auto events = GetTTDMemoryAccessForAddress(startAddress, endAddress, TTDMemoryExecute); @@ -3257,13 +3268,16 @@ bool DebuggerController::RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t // Add all executed instruction addresses within the range if (event.instructionAddress >= startAddress && event.instructionAddress <= endAddress) { - m_executedInstructions.insert(event.instructionAddress); + if ((event.timeStart.step >= startTime.step || event.timeStart.sequence >= startTime.sequence) && (event.timeStart.sequence <= endTime.sequence || event.timeStart.step <= endTime.step)) + { + m_executedInstructions.insert(event.instructionAddress); + } } } } m_codeCoverageAnalysisRun = true; - LogInfo("TTD code coverage analysis completed for range. Found 0x%" PRIu64 "executed instructions.", + LogInfo("TTD code coverage analysis completed for ranges. Found %" PRIu64 " executed instructions.", (uint64_t)m_executedInstructions.size()); return true; diff --git a/core/debuggercontroller.h b/core/debuggercontroller.h index 1014bb97..6a44bb1f 100644 --- a/core/debuggercontroller.h +++ b/core/debuggercontroller.h @@ -397,7 +397,7 @@ namespace BinaryNinjaDebugger { // TTD Code Coverage Analysis Methods bool IsInstructionExecuted(uint64_t address); - bool RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t endAddress); + bool RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t endAddress, TTDPosition startTime, TTDPosition endTime); size_t GetExecutedInstructionCount() const; bool SaveCodeCoverageToFile(const std::string& filePath) const; bool LoadCodeCoverageFromFile(const std::string& filePath); diff --git a/core/ffi.cpp b/core/ffi.cpp index 5f51c8cb..f03b1b6a 100644 --- a/core/ffi.cpp +++ b/core/ffi.cpp @@ -1246,9 +1246,11 @@ bool BNDebuggerIsInstructionExecuted(BNDebuggerController* controller, uint64_t return controller->object->IsInstructionExecuted(address); } -bool BNDebuggerRunCodeCoverageAnalysisRange(BNDebuggerController* controller, uint64_t startAddress, uint64_t endAddress) +bool BNDebuggerRunCodeCoverageAnalysisRange(BNDebuggerController* controller, uint64_t startAddress, uint64_t endAddress, BNDebuggerTTDPosition startTime, BNDebuggerTTDPosition endTime) { - return controller->object->RunCodeCoverageAnalysis(startAddress, endAddress); + TTDPosition startPos(startTime.sequence, startTime.step); + TTDPosition endPos(endTime.sequence, endTime.step); + return controller->object->RunCodeCoverageAnalysis(startAddress, endAddress, startPos, endPos); } size_t BNDebuggerGetExecutedInstructionCount(BNDebuggerController* controller) diff --git a/ui/ttdanalysisdialog.cpp b/ui/ttdanalysisdialog.cpp index 2aa84b44..8a198893 100644 --- a/ui/ttdanalysisdialog.cpp +++ b/ui/ttdanalysisdialog.cpp @@ -27,8 +27,8 @@ TTDAnalysisWorker::TTDAnalysisWorker(DbgRef controller, TTDA { } -TTDAnalysisWorker::TTDAnalysisWorker(DbgRef controller, TTDAnalysisType type, uint64_t startAddress, uint64_t endAddress, QObject* parent) - : QThread(parent), m_controller(controller), m_analysisType(type), m_useRange(true), m_startAddress(startAddress), m_endAddress(endAddress) +TTDAnalysisWorker::TTDAnalysisWorker(DbgRef controller, TTDAnalysisType type, uint64_t startAddress, uint64_t endAddress, TTDPosition startTime, TTDPosition endTime, QObject* parent) + : QThread(parent), m_controller(controller), m_analysisType(type), m_useRange(true), m_startAddress(startAddress), m_endAddress(endAddress), m_startTime(startTime), m_endTime(endTime) { } @@ -58,14 +58,16 @@ void TTDAnalysisWorker::run() emit analysisProgress(30, "Running code coverage analysis..."); if (m_useRange) { - success = m_controller->RunCodeCoverageAnalysis(m_startAddress, m_endAddress); + success = m_controller->RunCodeCoverageAnalysis(m_startAddress, m_endAddress, m_startTime, m_endTime); if (success) { resultCount = m_controller->GetExecutedInstructionCount(); - message = QString("Range-based code coverage analysis completed successfully. Found %1 executed instructions in range 0x%2 - 0x%3.") + message = QString("Range-based code coverage analysis completed successfully. Found %1 executed instructions in address range 0x%2 - 0x%3 and time range (%4,%5) - (%6,%7).") .arg(resultCount) .arg(m_startAddress, 0, 16) - .arg(m_endAddress, 0, 16); + .arg(m_endAddress, 0, 16) + .arg(m_startTime.sequence).arg(m_startTime.step) + .arg(m_endTime.sequence).arg(m_endTime.step); } else { @@ -197,9 +199,26 @@ void TTDAnalysisDialog::setupUI() m_endAddressEdit->setText(QString("0x") + QString::number(m_data->GetImageBase() + 0x7000, 16)); m_endAddressEdit->setEnabled(true); rangeControlsLayout->addWidget(m_endAddressEdit); - rangeLayout->addLayout(rangeControlsLayout); + // Time settings + QGroupBox* timeGroup = new QGroupBox("Time Range (Optional)"); + QVBoxLayout* timeLayout = new QVBoxLayout(timeGroup); + + QHBoxLayout* timeControlsLayout = new QHBoxLayout(); + timeControlsLayout->addWidget(new QLabel("Start Time:")); + m_startTimeEdit = new QLineEdit(); + //set text to starting position + m_startTimeEdit->setEnabled(true); + timeControlsLayout->addWidget(m_startTimeEdit); + + timeControlsLayout->addWidget(new QLabel("End Time:")); + m_endTimeEdit = new QLineEdit(); + //set text to ending position + m_endTimeEdit->setEnabled(true); + timeControlsLayout->addWidget(m_endTimeEdit); + timeLayout->addLayout(timeControlsLayout); + // Connect range checkbox to enable/disable range controls connect(m_useRangeCheckBox, &QCheckBox::toggled, [this](bool checked) { m_startAddressEdit->setEnabled(checked); @@ -207,6 +226,7 @@ void TTDAnalysisDialog::setupUI() }); mainLayout->addWidget(rangeGroup); + mainLayout->addWidget(timeGroup); // Cache settings QGroupBox* cacheGroup = new QGroupBox("Cache Settings"); @@ -379,9 +399,12 @@ void TTDAnalysisDialog::onRunAnalysis() if (m_useRangeCheckBox->isChecked()) { // Validate range inputs - bool startOk, endOk; + bool startOk, endOk, startTimeOk, endTimeOk; QString startText = m_startAddressEdit->text().trimmed(); QString endText = m_endAddressEdit->text().trimmed(); + QString startTimeText = m_startTimeEdit->text().trimmed(); + QString endTimeText = m_endTimeEdit->text().trimmed(); + TTDPosition startTime, endTime; if (startText.isEmpty() || endText.isEmpty()) { @@ -389,6 +412,50 @@ void TTDAnalysisDialog::onRunAnalysis() return; } + if (startTimeText.isEmpty()) + { + startTime = TTDPosition(0, 0); + }else{ + QStringList startTimeParts = startTimeText.split(u':'); + if (startTimeParts.size() != 2) + { + QMessageBox::warning(this, "Invalid Time", "Start time must be in the format 'sequence:step'"); + return; + } + bool seqOk, stepOk; + uint64_t sequence = startTimeParts[0].toULongLong(&seqOk, 16); + uint64_t step = startTimeParts[1].toULongLong(&stepOk, 16); + if (!seqOk || !stepOk) + { + QMessageBox::warning(this, "Invalid Time", "Start time contains invalid numbers"); + return; + } + startTime = TTDPosition(sequence, step); + } + + if (endTimeText.isEmpty()) + { + endTime = TTDPosition(std::numeric_limits::max(),std::numeric_limits::max()); + } + else + { + QStringList endTimeParts = endTimeText.split(u':'); + if (endTimeParts.size() != 2) + { + QMessageBox::warning(this, "Invalid Time", "End time must be in the format 'sequence:step'"); + return; + } + bool seqOk, stepOk; + uint64_t sequence = endTimeParts[0].toULongLong(&seqOk, 16); + uint64_t step = endTimeParts[1].toULongLong(&stepOk, 16); + if (!seqOk || !stepOk) + { + QMessageBox::warning(this, "Invalid Time", "End time contains invalid numbers"); + return; + } + endTime = TTDPosition(sequence, step); + } + uint64_t startAddress = startText.toULongLong(&startOk, 0); // Auto-detect base (0x for hex) uint64_t endAddress = endText.toULongLong(&endOk, 0); @@ -405,7 +472,7 @@ void TTDAnalysisDialog::onRunAnalysis() } // Start range-based analysis in worker thread - m_currentWorker = new TTDAnalysisWorker(m_controller, analysisType, startAddress, endAddress, this); + m_currentWorker = new TTDAnalysisWorker(m_controller, analysisType, startAddress, endAddress, startTime, endTime, this); } else { diff --git a/ui/ttdanalysisdialog.h b/ui/ttdanalysisdialog.h index ff43e052..2d6347dc 100644 --- a/ui/ttdanalysisdialog.h +++ b/ui/ttdanalysisdialog.h @@ -70,7 +70,7 @@ class TTDAnalysisWorker : public QThread public: TTDAnalysisWorker(DbgRef controller, TTDAnalysisType type, QObject* parent = nullptr); - TTDAnalysisWorker(DbgRef controller, TTDAnalysisType type, uint64_t startAddress, uint64_t endAddress, QObject* parent = nullptr); + TTDAnalysisWorker(DbgRef controller, TTDAnalysisType type, uint64_t startAddress, uint64_t endAddress, TTDPosition startTime, TTDPosition endTime, QObject* parent = nullptr); protected: void run() override; @@ -85,6 +85,8 @@ class TTDAnalysisWorker : public QThread bool m_useRange; uint64_t m_startAddress; uint64_t m_endAddress; + TTDPosition m_startTime; + TTDPosition m_endTime; }; class TTDAnalysisDialog : public QDialog @@ -136,6 +138,10 @@ private slots: QLineEdit* m_startAddressEdit; QLineEdit* m_endAddressEdit; + // Time controls + QLineEdit* m_startTimeEdit; + QLineEdit* m_endTimeEdit; + // Analysis data QList m_analysisResults; TTDAnalysisWorker* m_currentWorker; diff --git a/ui/ttdcoveragerenderlayer.cpp b/ui/ttdcoveragerenderlayer.cpp index ad45fef1..055dbebe 100644 --- a/ui/ttdcoveragerenderlayer.cpp +++ b/ui/ttdcoveragerenderlayer.cpp @@ -56,7 +56,7 @@ void TTDCoverageRenderLayer::ApplyToBlock(Ref block, std::vector function, std: line.highlight.r = 0; line.highlight.g = 0; line.highlight.b = 0; - line.highlight.alpha = 64; // Light highlight + line.highlight.alpha = 170; // Light highlight } } } \ No newline at end of file From 7ba3c1a4b38d5449e015fba73f77938dbf1ef63a Mon Sep 17 00:00:00 2001 From: Nicole <41876584+NicoleFaye@users.noreply.github.com> Date: Sun, 18 Jan 2026 20:14:04 -0800 Subject: [PATCH 2/5] Added visual studio build related files to gitignore --- .gitignore | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.gitignore b/.gitignore index c1525a49..94512ee0 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,19 @@ api/python/__pycache__ *.bndb /.claude/ + +# visual studio related build files +*.vcxproj* +*.cmake +*.recipe +*.tlog +*.stamp +*.depend +**/CMakeFiles +/out +/ui/debuggerui_autogen +**/RelWithDebInfo +CMakeCache.txt +*.sln +api/python/binaryninjacore.dll +/core/api/vendor From ec363e4a9afbca116b589e8910b82c1b7c0deb80 Mon Sep 17 00:00:00 2001 From: Nicole <41876584+NicoleFaye@users.noreply.github.com> Date: Sun, 18 Jan 2026 20:19:07 -0800 Subject: [PATCH 3/5] Fix Info message showing in error stream --- core/debuggercontroller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/debuggercontroller.cpp b/core/debuggercontroller.cpp index 7558e99d..d5f2e0bf 100644 --- a/core/debuggercontroller.cpp +++ b/core/debuggercontroller.cpp @@ -3323,7 +3323,7 @@ bool DebuggerController::SaveCodeCoverageToFile(const std::string& filePath) con } file.close(); - LogError("%s", fmt::format("Saved {} executed instruction addresses to {}", count, filePath.c_str()).c_str()); + LogInfo("%s", fmt::format("Saved {} executed instruction addresses to {}", count, filePath.c_str()).c_str()); return true; } From e4364382ecc213eb81e7073c01f3e5425aa30e32 Mon Sep 17 00:00:00 2001 From: Nicole <41876584+NicoleFaye@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:17:55 -0800 Subject: [PATCH 4/5] add method to query memory accress for a time range in ttd --- api/debuggerapi.h | 1 + api/debuggercontroller.cpp | 37 ++++++++++++++++++++ api/ffi.h | 3 ++ core/adapters/dbgengttdadapter.cpp | 56 ++++++++++++++++++++++++++++++ core/adapters/dbgengttdadapter.h | 4 +++ core/debugadapter.cpp | 6 ++++ core/debugadapter.h | 1 + core/debuggercontroller.cpp | 18 ++++++++++ core/debuggercontroller.h | 1 + core/ffi.cpp | 38 ++++++++++++++++++++ 10 files changed, 165 insertions(+) diff --git a/api/debuggerapi.h b/api/debuggerapi.h index 4f1b5496..8d38c6a7 100644 --- a/api/debuggerapi.h +++ b/api/debuggerapi.h @@ -799,6 +799,7 @@ namespace BinaryNinjaDebuggerAPI { // TTD Memory Analysis Methods std::vector GetTTDMemoryAccessForAddress(uint64_t address, uint64_t endAddress, TTDMemoryAccessType accessType = TTDMemoryRead); + std::vector GetTTDMemoryAccessForPositionRange(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, const TTDPosition startTime, const TTDPosition endTime); std::vector GetTTDCallsForSymbols(const std::string& symbols, uint64_t startReturnAddress = 0, uint64_t endReturnAddress = 0); std::vector GetTTDEvents(TTDEventType eventType); std::vector GetAllTTDEvents(); diff --git a/api/debuggercontroller.cpp b/api/debuggercontroller.cpp index 809adcf6..0623b463 100644 --- a/api/debuggercontroller.cpp +++ b/api/debuggercontroller.cpp @@ -1078,6 +1078,43 @@ bool DebuggerController::IsTTD() return BNDebuggerIsTTD(m_object); } +std::vector DebuggerController::GetTTDMemoryAccessForPositionRange(uint64_t address, uint64_t endAddress, TTDMemoryAccessType accessType, const TTDPosition startTime, const TTDPosition endTime) +{ + std::vector result; + + BNDebuggerTTDMemoryAccessType type = static_cast(accessType); + BNDebuggerTTDPosition bnStartTime = {startTime.sequence, startTime.step}; + BNDebuggerTTDPosition bnEndTime = {endTime.sequence, endTime.step}; + + size_t count = 0; + BNDebuggerTTDMemoryEvent* events = BNDebuggerGetTTDMemoryAccessForPositionRange(m_object, address, endAddress, type, bnStartTime, bnEndTime, &count); + + if (events && count > 0) + { + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + TTDMemoryEvent event; + event.eventType = events[i].eventType ? std::string(events[i].eventType) : ""; + event.threadId = events[i].threadId; + event.uniqueThreadId = events[i].uniqueThreadId; + event.timeStart.sequence = events[i].timeStart.sequence; + event.timeStart.step = events[i].timeStart.step; + event.timeEnd.sequence = events[i].timeEnd.sequence; + event.timeEnd.step = events[i].timeEnd.step; + event.accessType = static_cast(events[i].accessType); + event.address = events[i].address; + event.size = events[i].size; + event.memoryAddress = events[i].memoryAddress; + event.instructionAddress = events[i].instructionAddress; + event.value = events[i].value; + result.push_back(event); + } + BNDebuggerFreeTTDMemoryEvents(events, count); + } + + return result; +} std::vector DebuggerController::GetTTDMemoryAccessForAddress(uint64_t address, uint64_t endAddress, TTDMemoryAccessType accessType) { diff --git a/api/ffi.h b/api/ffi.h index 516e111d..b95d874c 100644 --- a/api/ffi.h +++ b/api/ffi.h @@ -665,6 +665,9 @@ extern "C" // TTD Memory Analysis Functions DEBUGGER_FFI_API BNDebuggerTTDMemoryEvent* BNDebuggerGetTTDMemoryAccessForAddress(BNDebuggerController* controller, uint64_t address, uint64_t endAddress, BNDebuggerTTDMemoryAccessType accessType, size_t* count); + DEBUGGER_FFI_API BNDebuggerTTDMemoryEvent* BNDebuggerGetTTDMemoryAccessForPositionRange(BNDebuggerController* controller, + uint64_t address, uint64_t endAddress, BNDebuggerTTDMemoryAccessType accessType ,BNDebuggerTTDPosition startPosition, BNDebuggerTTDPosition endPosition, + size_t* count); DEBUGGER_FFI_API BNDebuggerTTDCallEvent* BNDebuggerGetTTDCallsForSymbols(BNDebuggerController* controller, const char* symbols, uint64_t startReturnAddress, uint64_t endReturnAddress, size_t* count); DEBUGGER_FFI_API BNDebuggerTTDEvent* BNDebuggerGetTTDEvents(BNDebuggerController* controller, diff --git a/core/adapters/dbgengttdadapter.cpp b/core/adapters/dbgengttdadapter.cpp index 317855cf..b48bb5c9 100644 --- a/core/adapters/dbgengttdadapter.cpp +++ b/core/adapters/dbgengttdadapter.cpp @@ -403,6 +403,18 @@ std::vector DbgEngTTDAdapter::GetTTDMemoryAccessForAddress(uint6 return events; } +std::vector DbgEngTTDAdapter::GetTTDMemoryAccessForPositionRange(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, const TTDPosition startTime, const TTDPosition endTime) +{ + std::vector events; + + if (!QueryMemoryAccessByAddressAndPositionRange(startAddress, endAddress, accessType, startTime, endTime, events)) + { + LogError("Failed to query TTD memory access events for address range 0x%llx-0x%llx", startAddress, endAddress); + } + + return events; +} + TTDPosition DbgEngTTDAdapter::GetCurrentTTDPosition() { TTDPosition position; @@ -563,6 +575,50 @@ bool DbgEngTTDAdapter::QueryMemoryAccessByAddress(uint64_t startAddress, uint64_ } } +bool DbgEngTTDAdapter::QueryMemoryAccessByAddressAndPositionRange(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, TTDPosition startTime, TTDPosition endTime, std::vector& events) +{ + if (!m_debugControl) + { + LogError("Debug control interface not available"); + return false; + } + + try + { + // Build the access type string for TTD memory queries - combine flags as needed + std::string accessTypeStr; + if (accessType & TTDMemoryRead) accessTypeStr += "r"; + if (accessType & TTDMemoryWrite) accessTypeStr += "w"; + if (accessType & TTDMemoryExecute) accessTypeStr += "e"; + + if (accessTypeStr.empty()) + { + LogError("Invalid access type specified"); + return false; + } + + // Create the actual TTD memory query expression + std::string expression = fmt::format("@$cursession.TTD.MemoryForPositionRange(0x{:x},0x{:x},\"{}\",\"{:x}:{:x}\",\"{:x}:{:x}\")", startAddress, endAddress, accessTypeStr, startTime.sequence,startTime.step, endTime.sequence, endTime.step); + + LogInfo("Executing TTD memory query: %s", expression.c_str()); + + // Execute the query and parse results + if (!ParseTTDMemoryObjects(expression, accessType, events)) + { + LogError("Failed to parse TTD memory objects from query"); + return false; + } + + LogInfo("Successfully retrieved %zu TTD memory events", events.size()); + return true; + } + catch (const std::exception& e) + { + LogError("Exception in QueryMemoryAccessByAddress: %s", e.what()); + return false; + } +} + void DbgEngTTDAdapter::GenerateDefaultAdapterSettings(BinaryView* data) { diff --git a/core/adapters/dbgengttdadapter.h b/core/adapters/dbgengttdadapter.h index c740d473..0921f4ab 100644 --- a/core/adapters/dbgengttdadapter.h +++ b/core/adapters/dbgengttdadapter.h @@ -48,6 +48,9 @@ namespace BinaryNinjaDebugger { // TTD Memory Analysis Methods std::vector GetTTDMemoryAccessForAddress(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType = TTDMemoryRead) override; + std::vector GetTTDMemoryAccessForPositionRange(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, TTDPosition startTime, TTDPosition endTime) override; + + // TTD Position Methods TTDPosition GetCurrentTTDPosition() override; bool SetTTDPosition(const TTDPosition& position) override; @@ -64,6 +67,7 @@ namespace BinaryNinjaDebugger { private: // Helper methods for TTD memory analysis bool QueryMemoryAccessByAddress(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, std::vector& events); + bool QueryMemoryAccessByAddressAndPositionRange(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, TTDPosition startTime, TTDPosition endTime, std::vector& events); // Helper methods for TTD calls analysis bool QueryCallsForSymbols(const std::vector& symbols, uint64_t startReturnAddress, uint64_t endReturnAddress, std::vector& events); diff --git a/core/debugadapter.cpp b/core/debugadapter.cpp index 048e402d..4740c7e8 100644 --- a/core/debugadapter.cpp +++ b/core/debugadapter.cpp @@ -219,6 +219,12 @@ std::vector DebugAdapter::GetTTDMemoryAccessForAddress(uint64_t return {}; } +std::vector DebugAdapter::GetTTDMemoryAccessForPositionRange(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, const TTDPosition startTime, const TTDPosition endTime) +{ + // Default implementation returns empty results for adapters that don't support TTD + return {}; +} + std::vector DebugAdapter::GetTTDCallsForSymbols(const std::string& symbols, uint64_t startReturnAddress, uint64_t endReturnAddress) { diff --git a/core/debugadapter.h b/core/debugadapter.h index f733014f..b59a0d25 100644 --- a/core/debugadapter.h +++ b/core/debugadapter.h @@ -390,6 +390,7 @@ namespace BinaryNinjaDebugger { // TTD (Time Travel Debugging) methods - default implementations return empty results virtual std::vector GetTTDMemoryAccessForAddress(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType = TTDMemoryRead); + virtual std::vector GetTTDMemoryAccessForPositionRange(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, const TTDPosition startTime, const TTDPosition endTime); virtual std::vector GetTTDCallsForSymbols(const std::string& symbols, uint64_t startReturnAddress = 0, uint64_t endReturnAddress = 0); virtual std::vector GetTTDEvents(TTDEventType eventType); virtual std::vector GetAllTTDEvents(); diff --git a/core/debuggercontroller.cpp b/core/debuggercontroller.cpp index d5f2e0bf..4c0ac1fa 100644 --- a/core/debuggercontroller.cpp +++ b/core/debuggercontroller.cpp @@ -3134,6 +3134,24 @@ std::vector DebuggerController::GetTTDMemoryAccessForAddress(uin return events; } +std::vector DebuggerController::GetTTDMemoryAccessForPositionRange(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, const TTDPosition startTime, const TTDPosition endTime) +{ + std::vector events; + + if (!m_state->IsConnected() || !IsTTD()) + { + LogError("Current adapter does not support TTD"); + return events; + } + + if (m_adapter) + { + events = m_adapter->GetTTDMemoryAccessForPositionRange(startAddress, endAddress, accessType, startTime, endTime); + } + + return events; +} + std::vector DebuggerController::GetTTDCallsForSymbols(const std::string& symbols, uint64_t startReturnAddress, uint64_t endReturnAddress) { std::vector events; diff --git a/core/debuggercontroller.h b/core/debuggercontroller.h index 6a44bb1f..108cc6f8 100644 --- a/core/debuggercontroller.h +++ b/core/debuggercontroller.h @@ -389,6 +389,7 @@ namespace BinaryNinjaDebugger { // TTD Memory Analysis Methods std::vector GetTTDMemoryAccessForAddress(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType = TTDMemoryRead); + std::vector GetTTDMemoryAccessForPositionRange(uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, const TTDPosition startTime, const TTDPosition endTime); std::vector GetTTDCallsForSymbols(const std::string& symbols, uint64_t startReturnAddress = 0, uint64_t endReturnAddress = 0); std::vector GetTTDEvents(TTDEventType eventType); std::vector GetAllTTDEvents(); diff --git a/core/ffi.cpp b/core/ffi.cpp index f03b1b6a..18ef0a5d 100644 --- a/core/ffi.cpp +++ b/core/ffi.cpp @@ -1226,6 +1226,44 @@ BNDebuggerTTDMemoryEvent* BNDebuggerGetTTDMemoryAccessForAddress(BNDebuggerContr return result; } +BNDebuggerTTDMemoryEvent* BNDebuggerGetTTDMemoryAccessForPositionRange(BNDebuggerController* controller, + uint64_t address, uint64_t endAddress, BNDebuggerTTDMemoryAccessType accessType, BNDebuggerTTDPosition startTime, BNDebuggerTTDPosition endTime, size_t* count) +{ + if (!count) + return nullptr; + + *count = 0; + + TTDMemoryAccessType type = static_cast(accessType); + TTDPosition startPos(startTime.sequence, startTime.step); + TTDPosition endPos(endTime.sequence, endTime.step); + auto events = controller->object->GetTTDMemoryAccessForPositionRange(address, endAddress, type, startPos, endPos); + if (events.empty()) + return nullptr; + + *count = events.size(); + auto result = new BNDebuggerTTDMemoryEvent[events.size()]; + + for (size_t i = 0; i < events.size(); i++) + { + result[i].eventType = BNAllocString(events[i].eventType.c_str()); + result[i].threadId = events[i].threadId; + result[i].uniqueThreadId = events[i].uniqueThreadId; + result[i].timeStart.sequence = events[i].timeStart.sequence; + result[i].timeStart.step = events[i].timeStart.step; + result[i].timeEnd.sequence = events[i].timeEnd.sequence; + result[i].timeEnd.step = events[i].timeEnd.step; + result[i].address = events[i].address; + result[i].size = events[i].size; + result[i].memoryAddress = events[i].memoryAddress; + result[i].instructionAddress = events[i].instructionAddress; + result[i].value = events[i].value; + result[i].accessType = static_cast(events[i].accessType); + } + + return result; +} + BNDebuggerTTDPosition BNDebuggerGetCurrentTTDPosition(BNDebuggerController* controller) { auto position = controller->object->GetCurrentTTDPosition(); From 3ee3bca5f373c3d20d112bd9dffac27400346fd4 Mon Sep 17 00:00:00 2001 From: Nicole <41876584+NicoleFaye@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:18:50 -0800 Subject: [PATCH 5/5] use time based memory access query instead of filtering --- core/debuggercontroller.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/debuggercontroller.cpp b/core/debuggercontroller.cpp index 4c0ac1fa..2ae479ac 100644 --- a/core/debuggercontroller.cpp +++ b/core/debuggercontroller.cpp @@ -3277,8 +3277,8 @@ bool DebuggerController::RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t } // Query TTD for execute access covering the specified range - auto events = GetTTDMemoryAccessForAddress(startAddress, endAddress, TTDMemoryExecute); - + auto events = GetTTDMemoryAccessForPositionRange(startAddress, endAddress, TTDMemoryExecute, startTime, endTime); + for (const auto& event : events) { if (event.accessType == TTDMemoryExecute) @@ -3286,10 +3286,8 @@ bool DebuggerController::RunCodeCoverageAnalysis(uint64_t startAddress, uint64_t // Add all executed instruction addresses within the range if (event.instructionAddress >= startAddress && event.instructionAddress <= endAddress) { - if ((event.timeStart.step >= startTime.step || event.timeStart.sequence >= startTime.sequence) && (event.timeStart.sequence <= endTime.sequence || event.timeStart.step <= endTime.step)) - { - m_executedInstructions.insert(event.instructionAddress); - } + // Check if the event is within the specified time range + m_executedInstructions.insert(event.instructionAddress); } } }