Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion api/debuggerapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 8 additions & 3 deletions api/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


Expand Down
2 changes: 1 addition & 1 deletion api/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
24 changes: 19 additions & 5 deletions core/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
{
Expand All @@ -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<uint64_t>::max() && endTime.step == std::numeric_limits<uint64_t>::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);
Expand All @@ -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;
Expand Down Expand Up @@ -3309,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;
}
Expand Down
2 changes: 1 addition & 1 deletion core/debuggercontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions core/ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
83 changes: 75 additions & 8 deletions ui/ttdanalysisdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ TTDAnalysisWorker::TTDAnalysisWorker(DbgRef<DebuggerController> controller, TTDA
{
}

TTDAnalysisWorker::TTDAnalysisWorker(DbgRef<DebuggerController> 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<DebuggerController> 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)
{
}

Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -197,16 +199,34 @@ 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);
m_endAddressEdit->setEnabled(checked);
});

mainLayout->addWidget(rangeGroup);
mainLayout->addWidget(timeGroup);

// Cache settings
QGroupBox* cacheGroup = new QGroupBox("Cache Settings");
Expand Down Expand Up @@ -379,16 +399,63 @@ 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())
{
QMessageBox::warning(this, "Invalid Range", "Please enter both start and end addresses for range analysis");
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<uint64_t>::max(),std::numeric_limits<uint64_t>::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);

Expand All @@ -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
{
Expand Down
8 changes: 7 additions & 1 deletion ui/ttdanalysisdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class TTDAnalysisWorker : public QThread

public:
TTDAnalysisWorker(DbgRef<DebuggerController> controller, TTDAnalysisType type, QObject* parent = nullptr);
TTDAnalysisWorker(DbgRef<DebuggerController> controller, TTDAnalysisType type, uint64_t startAddress, uint64_t endAddress, QObject* parent = nullptr);
TTDAnalysisWorker(DbgRef<DebuggerController> controller, TTDAnalysisType type, uint64_t startAddress, uint64_t endAddress, TTDPosition startTime, TTDPosition endTime, QObject* parent = nullptr);

protected:
void run() override;
Expand All @@ -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
Expand Down Expand Up @@ -136,6 +138,10 @@ private slots:
QLineEdit* m_startAddressEdit;
QLineEdit* m_endAddressEdit;

// Time controls
QLineEdit* m_startTimeEdit;
QLineEdit* m_endTimeEdit;

// Analysis data
QList<TTDAnalysisResult> m_analysisResults;
TTDAnalysisWorker* m_currentWorker;
Expand Down
4 changes: 2 additions & 2 deletions ui/ttdcoveragerenderlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void TTDCoverageRenderLayer::ApplyToBlock(Ref<BasicBlock> block, std::vector<Dis
line.highlight.r = 0;
line.highlight.g = 0;
line.highlight.b = 0;
line.highlight.alpha = 64; // Light highlight
line.highlight.alpha = 170; // Light highlight
}
}
}
Expand Down Expand Up @@ -94,7 +94,7 @@ void TTDCoverageRenderLayer::ApplyToHighLevelILBody(Ref<Function> 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
}
}
}