Skip to content

Commit 378eaa0

Browse files
authored
Implement TTD.Events API and UI widget for time travel debugging events (#862)
1 parent 2146eaf commit 378eaa0

19 files changed

Lines changed: 3084 additions & 10 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,4 @@ api/python/__pycache__
6969
# TTD files
7070
*.run
7171
*.idx
72+
*.bndb

api/debuggerapi.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ limitations under the License.
1919
#include "binaryninjaapi.h"
2020
#include "ffi.h"
2121
#include "../vendor/intx/intx.hpp"
22+
#include <optional>
2223

2324
using namespace BinaryNinja;
2425

@@ -517,6 +518,78 @@ namespace BinaryNinjaDebuggerAPI {
517518
TTDCallEvent() : threadId(0), uniqueThreadId(0), functionAddress(0), returnAddress(0), returnValue(0), hasReturnValue(false) {}
518519
};
519520

521+
// TTD Event Types - bitfield flags for filtering events
522+
enum TTDEventType
523+
{
524+
TTDEventNone = 0,
525+
TTDEventThreadCreated = 1,
526+
TTDEventThreadTerminated = 2,
527+
TTDEventModuleLoaded = 4,
528+
TTDEventModuleUnloaded = 8,
529+
TTDEventException = 16,
530+
TTDEventAll = TTDEventThreadCreated | TTDEventThreadTerminated | TTDEventModuleLoaded | TTDEventModuleUnloaded | TTDEventException
531+
};
532+
533+
// TTD Module - information about modules that were loaded/unloaded during trace
534+
struct TTDModule
535+
{
536+
std::string name; // Name and path of the module
537+
uint64_t address; // Address where the module was loaded
538+
uint64_t size; // Size of the module in bytes
539+
uint32_t checksum; // Checksum of the module
540+
uint32_t timestamp; // Timestamp of the module
541+
542+
TTDModule() : address(0), size(0), checksum(0), timestamp(0) {}
543+
};
544+
545+
// TTD Thread - information about threads and their lifetime during trace
546+
struct TTDThread
547+
{
548+
uint32_t uniqueId; // Unique ID for the thread across the trace
549+
uint32_t id; // TID of the thread
550+
TTDPosition lifetimeStart; // Lifetime start position
551+
TTDPosition lifetimeEnd; // Lifetime end position
552+
TTDPosition activeTimeStart; // Active time start position
553+
TTDPosition activeTimeEnd; // Active time end position
554+
555+
TTDThread() : uniqueId(0), id(0) {}
556+
};
557+
558+
// TTD Exception Types
559+
enum TTDExceptionType
560+
{
561+
TTDExceptionSoftware,
562+
TTDExceptionHardware
563+
};
564+
565+
// TTD Exception - information about exceptions that occurred during trace
566+
struct TTDException
567+
{
568+
TTDExceptionType type; // Type of exception (Software/Hardware)
569+
uint64_t programCounter; // Instruction where exception was thrown
570+
uint32_t code; // Exception code
571+
uint32_t flags; // Exception flags
572+
uint64_t recordAddress; // Where in memory the exception record is found
573+
TTDPosition position; // Position where exception occurred
574+
575+
TTDException() : type(TTDExceptionSoftware), programCounter(0), code(0), flags(0), recordAddress(0) {}
576+
};
577+
578+
// TTD Event - represents important events that happened during trace
579+
struct TTDEvent
580+
{
581+
TTDEventType type; // Type of event
582+
TTDPosition position; // Position where event occurred
583+
584+
// Optional child objects - existence depends on event type
585+
std::optional<TTDModule> module; // For ModuleLoaded/ModuleUnloaded events
586+
std::optional<TTDThread> thread; // For ThreadCreated/ThreadTerminated events
587+
std::optional<TTDException> exception; // For Exception events
588+
589+
TTDEvent() : type(TTDEventThreadCreated) {}
590+
TTDEvent(TTDEventType eventType) : type(eventType) {}
591+
};
592+
520593

521594
typedef BNDebugAdapterConnectionStatus DebugAdapterConnectionStatus;
522595
typedef BNDebugAdapterTargetStatus DebugAdapterTargetStatus;
@@ -687,6 +760,8 @@ namespace BinaryNinjaDebuggerAPI {
687760
// TTD Memory Analysis Methods
688761
std::vector<TTDMemoryEvent> GetTTDMemoryAccessForAddress(uint64_t address, uint64_t size, TTDMemoryAccessType accessType = TTDMemoryRead);
689762
std::vector<TTDCallEvent> GetTTDCallsForSymbols(const std::string& symbols, uint64_t startReturnAddress = 0, uint64_t endReturnAddress = 0);
763+
std::vector<TTDEvent> GetTTDEvents(TTDEventType eventType);
764+
std::vector<TTDEvent> GetAllTTDEvents();
690765
TTDPosition GetCurrentTTDPosition();
691766
bool SetTTDPosition(const TTDPosition& position);
692767

api/debuggercontroller.cpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,145 @@ std::vector<TTDCallEvent> DebuggerController::GetTTDCallsForSymbols(const std::s
10631063
}
10641064

10651065

1066+
std::vector<TTDEvent> DebuggerController::GetTTDEvents(TTDEventType eventType)
1067+
{
1068+
std::vector<TTDEvent> result;
1069+
1070+
size_t count = 0;
1071+
BNDebuggerTTDEvent* events = BNDebuggerGetTTDEvents(m_object,
1072+
static_cast<BNDebuggerTTDEventType>(eventType), &count);
1073+
1074+
if (events && count > 0)
1075+
{
1076+
result.reserve(count);
1077+
for (size_t i = 0; i < count; i++)
1078+
{
1079+
TTDEvent event;
1080+
event.type = static_cast<TTDEventType>(events[i].type);
1081+
event.position.sequence = events[i].position.sequence;
1082+
event.position.step = events[i].position.step;
1083+
1084+
// Copy optional module details
1085+
if (events[i].module)
1086+
{
1087+
TTDModule module;
1088+
module.name = events[i].module->name ? std::string(events[i].module->name) : "";
1089+
module.address = events[i].module->address;
1090+
module.size = events[i].module->size;
1091+
module.checksum = events[i].module->checksum;
1092+
module.timestamp = events[i].module->timestamp;
1093+
event.module = module;
1094+
}
1095+
1096+
// Copy optional thread details
1097+
if (events[i].thread)
1098+
{
1099+
TTDThread thread;
1100+
thread.uniqueId = events[i].thread->uniqueId;
1101+
thread.id = events[i].thread->id;
1102+
thread.lifetimeStart.sequence = events[i].thread->lifetimeStart.sequence;
1103+
thread.lifetimeStart.step = events[i].thread->lifetimeStart.step;
1104+
thread.lifetimeEnd.sequence = events[i].thread->lifetimeEnd.sequence;
1105+
thread.lifetimeEnd.step = events[i].thread->lifetimeEnd.step;
1106+
thread.activeTimeStart.sequence = events[i].thread->activeTimeStart.sequence;
1107+
thread.activeTimeStart.step = events[i].thread->activeTimeStart.step;
1108+
thread.activeTimeEnd.sequence = events[i].thread->activeTimeEnd.sequence;
1109+
thread.activeTimeEnd.step = events[i].thread->activeTimeEnd.step;
1110+
event.thread = thread;
1111+
}
1112+
1113+
// Copy optional exception details
1114+
if (events[i].exception)
1115+
{
1116+
TTDException exception;
1117+
exception.type = static_cast<TTDExceptionType>(events[i].exception->type);
1118+
exception.programCounter = events[i].exception->programCounter;
1119+
exception.code = events[i].exception->code;
1120+
exception.flags = events[i].exception->flags;
1121+
exception.recordAddress = events[i].exception->recordAddress;
1122+
exception.position.sequence = events[i].exception->position.sequence;
1123+
exception.position.step = events[i].exception->position.step;
1124+
event.exception = exception;
1125+
}
1126+
1127+
result.push_back(event);
1128+
}
1129+
BNDebuggerFreeTTDEvents(events, count);
1130+
}
1131+
1132+
return result;
1133+
}
1134+
1135+
1136+
std::vector<TTDEvent> DebuggerController::GetAllTTDEvents()
1137+
{
1138+
std::vector<TTDEvent> result;
1139+
1140+
size_t count = 0;
1141+
BNDebuggerTTDEvent* events = BNDebuggerGetAllTTDEvents(m_object, &count);
1142+
1143+
if (events && count > 0)
1144+
{
1145+
result.reserve(count);
1146+
for (size_t i = 0; i < count; i++)
1147+
{
1148+
TTDEvent event;
1149+
event.type = static_cast<TTDEventType>(events[i].type);
1150+
event.position.sequence = events[i].position.sequence;
1151+
event.position.step = events[i].position.step;
1152+
1153+
// Copy optional module details
1154+
if (events[i].module)
1155+
{
1156+
TTDModule module;
1157+
module.name = events[i].module->name ? std::string(events[i].module->name) : "";
1158+
module.address = events[i].module->address;
1159+
module.size = events[i].module->size;
1160+
module.checksum = events[i].module->checksum;
1161+
module.timestamp = events[i].module->timestamp;
1162+
event.module = module;
1163+
}
1164+
1165+
// Copy optional thread details
1166+
if (events[i].thread)
1167+
{
1168+
TTDThread thread;
1169+
thread.uniqueId = events[i].thread->uniqueId;
1170+
thread.id = events[i].thread->id;
1171+
thread.lifetimeStart.sequence = events[i].thread->lifetimeStart.sequence;
1172+
thread.lifetimeStart.step = events[i].thread->lifetimeStart.step;
1173+
thread.lifetimeEnd.sequence = events[i].thread->lifetimeEnd.sequence;
1174+
thread.lifetimeEnd.step = events[i].thread->lifetimeEnd.step;
1175+
thread.activeTimeStart.sequence = events[i].thread->activeTimeStart.sequence;
1176+
thread.activeTimeStart.step = events[i].thread->activeTimeStart.step;
1177+
thread.activeTimeEnd.sequence = events[i].thread->activeTimeEnd.sequence;
1178+
thread.activeTimeEnd.step = events[i].thread->activeTimeEnd.step;
1179+
event.thread = thread;
1180+
}
1181+
1182+
// Copy optional exception details
1183+
if (events[i].exception)
1184+
{
1185+
TTDException exception;
1186+
exception.type = static_cast<TTDExceptionType>(events[i].exception->type);
1187+
exception.programCounter = events[i].exception->programCounter;
1188+
exception.code = events[i].exception->code;
1189+
exception.flags = events[i].exception->flags;
1190+
exception.recordAddress = events[i].exception->recordAddress;
1191+
exception.position.sequence = events[i].exception->position.sequence;
1192+
exception.position.step = events[i].exception->position.step;
1193+
event.exception = exception;
1194+
}
1195+
1196+
result.push_back(event);
1197+
}
1198+
BNDebuggerFreeTTDEvents(events, count);
1199+
}
1200+
1201+
return result;
1202+
}
1203+
1204+
10661205
bool DebuggerController::IsInstructionExecuted(uint64_t address)
10671206
{
10681207
return BNDebuggerIsInstructionExecuted(m_object, address);

api/ffi.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,69 @@ extern "C"
339339
BNDebuggerTTDPosition timeEnd; // Position when call ended
340340
} BNDebuggerTTDCallEvent;
341341

342+
// TTD Event Types - bitfield flags for filtering events
343+
typedef enum BNDebuggerTTDEventType
344+
{
345+
BNDebuggerTTDEventNone = 0,
346+
BNDebuggerTTDEventThreadCreated = 1,
347+
BNDebuggerTTDEventThreadTerminated = 2,
348+
BNDebuggerTTDEventModuleLoaded = 4,
349+
BNDebuggerTTDEventModuleUnloaded = 8,
350+
BNDebuggerTTDEventException = 16,
351+
BNDebuggerTTDEventAll = BNDebuggerTTDEventThreadCreated | BNDebuggerTTDEventThreadTerminated | BNDebuggerTTDEventModuleLoaded | BNDebuggerTTDEventModuleUnloaded | BNDebuggerTTDEventException
352+
} BNDebuggerTTDEventType;
353+
354+
// TTD Module
355+
typedef struct BNDebuggerTTDModule
356+
{
357+
char* name; // Name and path of the module
358+
uint64_t address; // Address where the module was loaded
359+
uint64_t size; // Size of the module in bytes
360+
uint32_t checksum; // Checksum of the module
361+
uint32_t timestamp; // Timestamp of the module
362+
} BNDebuggerTTDModule;
363+
364+
// TTD Thread
365+
typedef struct BNDebuggerTTDThread
366+
{
367+
uint32_t uniqueId; // Unique ID for the thread across the trace
368+
uint32_t id; // TID of the thread
369+
BNDebuggerTTDPosition lifetimeStart; // Lifetime start position
370+
BNDebuggerTTDPosition lifetimeEnd; // Lifetime end position
371+
BNDebuggerTTDPosition activeTimeStart; // Active time start position
372+
BNDebuggerTTDPosition activeTimeEnd; // Active time end position
373+
} BNDebuggerTTDThread;
374+
375+
// TTD Exception Types
376+
typedef enum BNDebuggerTTDExceptionType
377+
{
378+
BNDebuggerTTDExceptionSoftware,
379+
BNDebuggerTTDExceptionHardware
380+
} BNDebuggerTTDExceptionType;
381+
382+
// TTD Exception
383+
typedef struct BNDebuggerTTDException
384+
{
385+
BNDebuggerTTDExceptionType type; // Type of exception (Software/Hardware)
386+
uint64_t programCounter; // Instruction where exception was thrown
387+
uint32_t code; // Exception code
388+
uint32_t flags; // Exception flags
389+
uint64_t recordAddress; // Where in memory the exception record is found
390+
BNDebuggerTTDPosition position; // Position where exception occurred
391+
} BNDebuggerTTDException;
392+
393+
// TTD Event
394+
typedef struct BNDebuggerTTDEvent
395+
{
396+
BNDebuggerTTDEventType type; // Type of event
397+
BNDebuggerTTDPosition position; // Position where event occurred
398+
399+
// Optional child objects - existence depends on event type
400+
BNDebuggerTTDModule* module; // For ModuleLoaded/ModuleUnloaded events (NULL if not present)
401+
BNDebuggerTTDThread* thread; // For ThreadCreated/ThreadTerminated events (NULL if not present)
402+
BNDebuggerTTDException* exception; // For Exception events (NULL if not present)
403+
} BNDebuggerTTDEvent;
404+
342405

343406
// This should really be a union, but gcc complains...
344407
typedef struct BNDebuggerEventData
@@ -555,10 +618,14 @@ extern "C"
555618
uint64_t address, uint64_t size, BNDebuggerTTDMemoryAccessType accessType, size_t* count);
556619
DEBUGGER_FFI_API BNDebuggerTTDCallEvent* BNDebuggerGetTTDCallsForSymbols(BNDebuggerController* controller,
557620
const char* symbols, uint64_t startReturnAddress, uint64_t endReturnAddress, size_t* count);
621+
DEBUGGER_FFI_API BNDebuggerTTDEvent* BNDebuggerGetTTDEvents(BNDebuggerController* controller,
622+
BNDebuggerTTDEventType eventType, size_t* count);
623+
DEBUGGER_FFI_API BNDebuggerTTDEvent* BNDebuggerGetAllTTDEvents(BNDebuggerController* controller, size_t* count);
558624
DEBUGGER_FFI_API BNDebuggerTTDPosition BNDebuggerGetCurrentTTDPosition(BNDebuggerController* controller);
559625
DEBUGGER_FFI_API bool BNDebuggerSetTTDPosition(BNDebuggerController* controller, BNDebuggerTTDPosition position);
560626
DEBUGGER_FFI_API void BNDebuggerFreeTTDMemoryEvents(BNDebuggerTTDMemoryEvent* events, size_t count);
561627
DEBUGGER_FFI_API void BNDebuggerFreeTTDCallEvents(BNDebuggerTTDCallEvent* events, size_t count);
628+
DEBUGGER_FFI_API void BNDebuggerFreeTTDEvents(BNDebuggerTTDEvent* events, size_t count);
562629

563630
// TTD Code Coverage Analysis Functions
564631
DEBUGGER_FFI_API bool BNDebuggerIsInstructionExecuted(BNDebuggerController* controller, uint64_t address);

0 commit comments

Comments
 (0)