Skip to content
Open
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
17 changes: 17 additions & 0 deletions docs/guide/dbgeng-ttd.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-

Binary Ninja's TTD integration includes powerful analysis widgets that leverage WinDbg's TTD.Calls and TTD.Memory queries to help you understand program behavior during the recorded trace.

### TTD Navigation Widget

Stepping to the next or previous access of a register or a piece of memory is by far the most common TTD operation, so it is available directly underneath the control buttons in the debugger sidebar. The widget only appears during a TTD session and is hidden otherwise.

- The `Target` field is what the navigation walks through. Unless pinned, it tracks the code view:
- Put the cursor on a register token (e.g. `rax`) and the target becomes that register, which takes priority over the address the cursor is on
- Select a range of bytes and the target becomes that address range
- Otherwise the target is the address the cursor is on
- You can also type a target in yourself. Address ranges are written as `start..end` (`start - end` works too), and a single address covers one byte. Both ends accept the same expressions as the rest of Binary Ninja, so symbol names work.
- `R`, `W` and `X` choose which kinds of memory access to stop on. They do not apply to a register target, since TTD reports register value changes without an access type, and are disabled in that case.
- The arrow buttons time-travel to the closest matching access in that direction, and a status line appears underneath reporting where the trace landed.
- The button carrying the TTD Memory sidebar's icon lists *every* access to the target instead of stepping to one, by handing the query to the [TTD Memory widget](#ttd-memory-widget) and opening it. This is the same as the `TTD Memory Access` context menu items, and is likewise memory-only.

`Pin` freezes the target where it is. Time travelling moves the code view, so an unpinned target becomes whatever the trace landed on; pinning is what lets repeated navigation keep walking the same register or address range. Typing your own target pins it for you, since otherwise the next click in the code view would overwrite what you typed.

This is the same functionality as the `TTD Memory Access (Next/Prev)` and `Go to Next/Previous Register Write` context menu items described below, so use whichever is more convenient.

### TTD Calls Widget

The TTD Calls widget allows you to query and analyze function call events from your TTD trace. This is equivalent to WinDbg's `dx @$cursession.TTD.Calls()` functionality but integrated directly into Binary Ninja.
Expand Down
26 changes: 24 additions & 2 deletions ui/debuggerwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ DebuggerWidget::DebuggerWidget(const QString& name, ViewFrame* view, BinaryViewR
m_splitter->setChildrenCollapsible(true);

m_controlsWidget = new DebugControlsWidget(this, "Controls", data);
m_ttdNavigationWidget = new TTDNavigationWidget(this, data);

// The controls and the TTD navigation widget form a single pane of the splitter so that the
// navigation widget always sits directly underneath the control buttons. The pane hugs its
// contents the way the bare toolbar used to, rather than growing into the space the tabs
// below should be getting.
QWidget* controlsContainer = new QWidget(this);
controlsContainer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
QVBoxLayout* controlsLayout = new QVBoxLayout(controlsContainer);
controlsLayout->setContentsMargins(0, 0, 0, 0);
controlsLayout->setSpacing(0);
controlsLayout->addWidget(m_controlsWidget);
controlsLayout->addWidget(m_ttdNavigationWidget);

m_tabs = new QTabWidget(this);

Expand All @@ -80,8 +93,10 @@ DebuggerWidget::DebuggerWidget(const QString& name, ViewFrame* view, BinaryViewR
m_tabs->addTab(m_registersWidget, "Registers");
m_tabs->addTab(m_breakpointsWidget, "Breakpoints");

m_splitter->addWidget(m_controlsWidget);
m_splitter->addWidget(controlsContainer);
m_splitter->addWidget(m_tabs);
m_splitter->setStretchFactor(0, 0);
m_splitter->setStretchFactor(1, 1);

layout->addWidget(m_splitter);
setLayout(layout);
Expand All @@ -101,6 +116,12 @@ void DebuggerWidget::notifyFontChanged()
}


void DebuggerWidget::notifyViewLocationChanged(View* view, const ViewLocation& viewLocation)
{
m_ttdNavigationWidget->updateTargetFromView(view);
}


void DebuggerWidget::updateContent()
{
m_registersWidget->updateContent();
Expand All @@ -110,7 +131,8 @@ void DebuggerWidget::updateContent()
void DebuggerWidget::uiEventHandler(const DebuggerEvent& event)
{
m_controlsWidget->updateButtons();

m_ttdNavigationWidget->updateState();

// Enable adapter selector only when not connected
DebugAdapterConnectionStatus connection = m_controller->GetConnectionStatus();
if (m_adapterSelector->count() > 0 && m_adapterSelector->currentText() != "(No available debug adapter)")
Expand Down
3 changes: 3 additions & 0 deletions ui/debuggerwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ limitations under the License.
#include "registerswidget.h"
#include "moduleswidget.h"
#include "controlswidget.h"
#include "ttdnavigationwidget.h"
#include "ui.h"
#include "debuggerapi.h"

Expand All @@ -50,6 +51,7 @@ class DebuggerWidget : public SidebarWidget
QTabWidget* m_tabs;

DebugControlsWidget* m_controlsWidget;
TTDNavigationWidget* m_ttdNavigationWidget;
DebugRegistersContainer* m_registersWidget;
DebugBreakpointsWidget* m_breakpointsWidget;

Expand All @@ -58,6 +60,7 @@ class DebuggerWidget : public SidebarWidget
//void shouldBeVisible()

virtual void notifyFontChanged() override;
virtual void notifyViewLocationChanged(View* view, const ViewLocation& viewLocation) override;

private slots:
void uiEventHandler(const DebuggerEvent& event);
Expand Down
Loading