For the complete documentation index, see llms.txt. This page is also available as Markdown.

!lbr (tracing branches using Last Branch Record)

Description of '!lbr' command in HyperDbg.

Command

!lbr

Syntax

!lbr [Function (string)]

!lbr [filter FilterOptions (string)]

Description

Performs operations for Last Branch Record (LBR), including enabling, disabling, flushing, and configuring filters.

To use this command, the trace module should be loaded using the load command (load trace).

To dump the LBR entries after enabling them, use the '!lbrdump' command.

Parameters

[Function (string)]

The target functionality. Can be one of the following values:

Function
Description

enable

Enable the Last Branch Record

disable

Disable the Last Branch Record

flush

Flush (clear) the Last Branch Record

filter

Configure the LBR filter options

[FilterOptions (string)] (optional)

One or more filter options to configure which branch types are not captured. If no option is specified, everything is captured (default). Can be a combination of the following values:

Option
Description

kernel

Do not capture at ring 0

user

Do not capture at ring > 0

jcc

Do not capture conditional branches

rel_call

Do not capture relative calls

ind_call

Do not capture indirect calls

return

Do not capture near returns

ind_jmp

Do not capture indirect jumps

rel_jmp

Do not capture relative jumps

far

Do not capture far branches (only in legacy LBR)

other_branches

Do not capture jmp/call ptr*, jmp/call m*, ret (0c8h), sys*, interrupts, exceptions (other than debug exceptions), iret, int3, intn, into, tsx abort, eenter, eresume, eexit, aex, init, sipi, rsm (only in ARCH LBR)

call_stack

Enable LBR stack to use LIFO filtering to capture call stack profile. Not available on CPUs older than Haswell. For this option, you can only additionally specify user or kernel. It prevents all types of branches except calls and returns

Examples

The following command enables the Last Branch Record.

The following command disables the Last Branch Record.

The following command flushes (clears) the Last Branch Record.

The following command applies the default LBR configuration in which all types of branches are shown or in other words, it just resets the filter options to include all branches.

The following command configures the LBR filter to not capture kernel-mode conditional branches, indirect jumps, relative jumps, and far branches.

The following command configures the LBR filter to not capture kernel-mode conditional branches, near returns, indirect jumps, relative jumps, and far branches.

The following command configures the LBR filter to not capture kernel-mode conditional branches, indirect jumps, and relative jumps.

The following command configures the LBR filter to not capture user-mode relative calls, indirect calls, near returns, and far branches.

The following command enables the call stack profile mode for user-mode branches.

The following command enables the call stack profile mode for kernel-mode branches.

SDK

None

Remarks

Starting from v0.19, this command was added to the HyperDbg debugger.

Check requirements to know the differences between Legacy LBRs and Architectural (ARCH)-based LBRs.

Virtual machines (nested virtualization environments) usually do not support or emulate LBR. As a result, you need a physical (bare-metal) machine to use this command.

Some filter options (e.g., far) are only available in Legacy LBR, while others (e.g., other_branches) are only available in ARCH LBR.

The LBR is a ring buffer that records control flow transitions, but its limited depth can be a problem when profiling code that makes many small helper (leaf) function calls, such as in C++. These short calls fill up the buffer quickly and push out the more important call stack context before it can be examined. The call_stack mode solves this by applying LIFO (last-in, first-out) filtering: calls are recorded normally, but when a RET is executed, the matching CALL entry is removed from the buffer. This effectively cancels out leaf function call/return pairs, keeping the buffer focused on the main execution path rather than short-lived helper calls.

When using the call_stack option, it is recommended to also specify either user or kernel to restrict profiling to the desired privilege level. Note that call_stack removes all branch types from the LBR except CALL and RET instructions; all other branch types (conditional jumps, indirect jumps, etc.) are not captured.

On a machine that supports Architectural LBR, there is additional information available for each branch entry, such as the branch type and whether the cycle count is valid. See the '!lbrdump' command for an example of these differences.

If you want to prevent LBR from being masked and disabled by the processor automatically (e.g., by a #DB), and you are using the VMM module, you can use the '!exception' command to intercept Debug Breaks (#DB). Simply intercepting them is sufficient as the CPU will not mask LBR again. For example, the following event command prevents LBR from being disabled:

This command will continue the debuggee for some time (in Debugger Mode). This means that you lose the current context (registers & memory) after executing this command.

Requirements

Intel processors support two LBR implementations. Legacy LBR uses model-specific registers (MSRs) and is available on processors up to and including the 11th generation. Architectural LBR (ARCH LBR) was introduced starting from the 12th generation and exposes LBR as a standardized set of architectural registers. Depending on the generation of your processor, you have different features in LBR.

The call_stack option is not available on processors older than Haswell (4th generation).

lbr_save

lbr_print

lbr_check

lbr_restore

lbr_restore_by_filter

!lbrdump (dump Last Branch Record entries)

Last updated