Skip to content

Commit 19e457d

Browse files
committed
Add support for TTD in GDB MI adapter (#1019)
1 parent 3822d2f commit 19e457d

4 files changed

Lines changed: 61 additions & 16 deletions

File tree

core/adapters/gdbmiadapter.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,27 @@ bool GdbMiAdapter::Connect(const std::string& server, uint32_t port) {
542542
}
543543
}
544544

545+
// Detect reverse debugging / TTD support by probing the remote server's qSupported capabilities.
546+
// Servers like udbserver and rr advertise ReverseContinue+ and ReverseStep+ in qSupported.
547+
m_canReverseContinue = false;
548+
m_canReverseStep = false;
549+
{
550+
std::string qSupportedResponse = InvokeBackendCommand(
551+
"maintenance packet qSupported:ReverseContinue+;ReverseStep+");
552+
if (!qSupportedResponse.empty())
553+
{
554+
if (qSupportedResponse.find("ReverseContinue+") != std::string::npos)
555+
m_canReverseContinue = true;
556+
if (qSupportedResponse.find("ReverseStep+") != std::string::npos)
557+
m_canReverseStep = true;
558+
}
559+
560+
if (m_canReverseContinue && m_canReverseStep)
561+
LogInfo("Reverse debugging support detected (TTD enabled)");
562+
else
563+
LogInfo("No reverse debugging support detected");
564+
}
565+
545566
// AFTER we are connected and stopped, populate the cache for the first time.
546567
LogInfo("Populating initial state cache...");
547568
ScheduleStateRefresh();
@@ -1031,6 +1052,30 @@ bool GdbMiAdapter::StepReturn() {
10311052
return (m_mi->SendCommand("-exec-finish").command == "running");
10321053
}
10331054

1055+
bool GdbMiAdapter::GoReverse() {
1056+
if (!m_mi || m_targetRunningAtomic || !m_canReverseContinue) return false;
1057+
1058+
return (m_mi->SendCommand("-exec-continue --reverse").command == "running");
1059+
}
1060+
1061+
bool GdbMiAdapter::StepIntoReverse() {
1062+
if (!m_mi || m_targetRunningAtomic || !m_canReverseStep) return false;
1063+
1064+
return (m_mi->SendCommand("-exec-step-instruction --reverse").command == "running");
1065+
}
1066+
1067+
bool GdbMiAdapter::StepOverReverse() {
1068+
if (!m_mi || m_targetRunningAtomic || !m_canReverseStep) return false;
1069+
1070+
return (m_mi->SendCommand("-exec-next-instruction --reverse").command == "running");
1071+
}
1072+
1073+
bool GdbMiAdapter::StepReturnReverse() {
1074+
if (!m_mi || m_targetRunningAtomic || !m_canReverseStep) return false;
1075+
1076+
return (m_mi->SendCommand("-exec-finish --reverse").command == "running");
1077+
}
1078+
10341079
uint64_t GdbMiAdapter::GetInstructionOffset() {
10351080
std::string ipRegisterName;
10361081
if ((m_remoteArch == "x86") || (m_remoteArch == "i386"))
@@ -1091,9 +1136,10 @@ std::string GdbMiAdapter::GetTargetArchitecture() { return m_remoteArch; }
10911136
bool GdbMiAdapter::SupportFeature(DebugAdapterCapacity feature) {
10921137
switch (feature) {
10931138
case DebugAdapterSupportStepOver: return true;
1139+
case DebugAdapterSupportStepOverReverse: return m_canReverseContinue && m_canReverseStep;
10941140
case DebugAdapterSupportModules: return true;
10951141
case DebugAdapterSupportThreads: return true;
1096-
case DebugAdapterSupportTTD: return false;
1142+
case DebugAdapterSupportTTD: return m_canReverseContinue && m_canReverseStep;
10971143
default: return false;
10981144
}
10991145
}

core/adapters/gdbmiadapter.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ class GdbMiAdapter : public BinaryNinjaDebugger::DebugAdapter
1414
bool m_connected = false;
1515
std::string m_remoteArch;
1616
std::vector<std::string> m_registerNames; // In GDB's order
17+
18+
// TTD / reverse debugging capability flags (set during Connect)
19+
bool m_canReverseContinue = false;
20+
bool m_canReverseStep = false;
1721
BinaryNinjaDebugger::DebugStopReason m_lastStopReason;
1822
std::atomic<bool> m_targetRunningAtomic{false};
1923
uint64_t m_exitCode = 0;
@@ -100,6 +104,11 @@ class GdbMiAdapter : public BinaryNinjaDebugger::DebugAdapter
100104
bool StepOver() override;
101105
bool StepReturn() override;
102106

107+
bool GoReverse() override;
108+
bool StepIntoReverse() override;
109+
bool StepOverReverse() override;
110+
bool StepReturnReverse() override;
111+
103112
std::uint32_t GetActivePID() override { return 0; }
104113

105114
std::string InvokeBackendCommand(const std::string& command) override;

core/debuggercontroller.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -501,10 +501,6 @@ bool DebuggerController::CreateDebugAdapter()
501501
// Binary View object
502502
m_adapter->SetController(this);
503503

504-
m_adapterSupportsStepOver = m_adapter->SupportFeature(DebugAdapterSupportStepOver);
505-
m_adapterSupportsStepOverReverse = m_adapter->SupportFeature(DebugAdapterSupportStepOverReverse);
506-
m_adapterSupportsTTD = m_adapter->SupportFeature(DebugAdapterSupportTTD);
507-
508504
ApplyBreakpoints();
509505

510506
// Forward the DebuggerEvent from the adapters to the controller
@@ -1688,7 +1684,7 @@ DebugStopReason DebuggerController::StepOverAndWaitInternal()
16881684
{
16891685
m_userRequestedBreak = false;
16901686

1691-
if (m_adapterSupportsStepOver)
1687+
if (m_adapter && m_adapter->SupportFeature(DebugAdapterSupportStepOver))
16921688
{
16931689
return ExecuteAdapterAndWait(DebugAdapterStepOver);
16941690
}
@@ -1703,7 +1699,7 @@ DebugStopReason DebuggerController::StepOverReverseAndWaitInternal()
17031699
{
17041700
m_userRequestedBreak = false;
17051701

1706-
if (m_adapterSupportsStepOverReverse)
1702+
if (m_adapter && m_adapter->SupportFeature(DebugAdapterSupportStepOverReverse))
17071703
{
17081704
return ExecuteAdapterAndWait(DebugAdapterStepOverReverse);
17091705
}
@@ -3147,7 +3143,7 @@ std::vector<TTDEvent> DebuggerController::GetAllTTDEvents()
31473143

31483144
void DebuggerController::RecordTTDPosition()
31493145
{
3150-
if (!m_adapterSupportsTTD || !m_adapter || m_suppressTTDPositionRecording)
3146+
if (!m_adapter || !m_adapter->SupportFeature(DebugAdapterSupportTTD) || m_suppressTTDPositionRecording)
31513147
return;
31523148

31533149
TTDPosition position = m_adapter->GetCurrentTTDPosition();
@@ -3199,13 +3195,13 @@ bool DebuggerController::TTDNavigateForward()
31993195

32003196
bool DebuggerController::CanTTDNavigateBack() const
32013197
{
3202-
return m_adapterSupportsTTD && m_ttdPositionHistoryIndex > 0;
3198+
return m_adapter && m_adapter->SupportFeature(DebugAdapterSupportTTD) && m_ttdPositionHistoryIndex > 0;
32033199
}
32043200

32053201

32063202
bool DebuggerController::CanTTDNavigateForward() const
32073203
{
3208-
return m_adapterSupportsTTD
3204+
return m_adapter && m_adapter->SupportFeature(DebugAdapterSupportTTD)
32093205
&& m_ttdPositionHistoryIndex >= 0
32103206
&& m_ttdPositionHistoryIndex < static_cast<int>(m_ttdPositionHistory.size()) - 1;
32113207
}

core/debuggercontroller.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,6 @@ namespace BinaryNinjaDebugger {
189189

190190
void DetectLoadedModule();
191191

192-
bool m_adapterSupportsStepOver = false;
193-
bool m_adapterSupportsStepOverReverse = false;
194-
// bool m_adapterSupportsModules = false;
195-
// bool m_adapterSupportsThreads = false;
196-
bool m_adapterSupportsTTD = false;
197-
198192
std::mutex m_eventsMutex;
199193
std::condition_variable m_cv;
200194
std::queue<std::shared_ptr<PendingEvent>> m_eventQueue;

0 commit comments

Comments
 (0)