HyperDbg Debugger
Loading...
Searching...
No Matches
Lbr.c File Reference

Last Branch Record (LBR) tracing implementation for HyperTrace module. More...

#include "pch.h"

Functions

BOOLEAN LbrCheckAndReadArchitecturalLbrDetails ()
 Check if the current CPU supports architectural LBR.
BOOLEAN LbrCheckAndReadLegacyLbrDetails ()
 Check if the current CPU supports LBR by examining the CPU family and model and looking up the corresponding LBR capacity.
VOID LbrAdjustArchBasedFilteringCompatibility (IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
 Check and adjust compatibility of LBR filterings for ARCH based LBR.
VOID LbrBuildArchBasedFilterOptions (UINT64 FilterOptions, IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
 Convert a filter options bitmask into IA32_LBR_CTL format for architectural LBR.
VOID LbrSetLbrSelectFilter (UINT64 FilterOptions)
 Set the LBR select filter MSR (MSR_LEGACY_LBR_SELECT) for legacy LBR, dispatching via VMCALL when in VMX non-root mode.
VOID LbrClearHardwareState ()
 Zero out the LBR hardware state (TOS and all from/to MSR pairs).
VOID LbrEnableArchBased (IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
 Enable LBR collection on architectural (ARCH) based LBR.
VOID LbrEnableLegacyBased (ULONGLONG *DbgCtlMsr)
 Enable LBR collection on legacy based LBR.
VOID LbrStartOnNativeMode (IA32_LBR_CTL_REGISTER Ia32LbrCtl)
 Start LBR collection when running natively (outside any hypervisor environment).
VOID LbrGetValuesOnVmxRootMode (ULONGLONG *DbgCtlMsr, IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
 Read current LBR control register values while in VMX root-mode.
VOID LbrGetValuesOnVmxNonRootMode (ULONGLONG *DbgCtlMsr, IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
 Read current LBR control register values while in VMX non-root mode (via VMCALL).
VOID LbrDisableArchBased (IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
 Disable LBR collection on architectural (ARCH) based LBR.
VOID LbrDisableLegacyBased (ULONGLONG *DbgCtlMsr)
 Disable LBR collection on legacy based LBR.
VOID LbrSetValuesOnVmxRootMode (ULONGLONG DbgCtlMsr, IA32_LBR_CTL_REGISTER Ia32LbrCtl)
 Write back modified LBR control register values while in VMX root-mode.
VOID LbrSetValuesOnVmxNonRootMode (ULONGLONG DbgCtlMsr, IA32_LBR_CTL_REGISTER Ia32LbrCtl)
 Write back modified LBR control register values while in VMX non-root mode (via VMCALL).
VOID LbrStopOnNativeMode ()
 Stop LBR collection when running natively (outside any hypervisor environment).
VOID LbrResetArchControlOnVmxRootMode ()
 Zero the ARCH LBR control register while in VMX root-mode.
VOID LbrResetArchControlOnVmxNonRootMode ()
 Zero the ARCH LBR control register while in VMX non-root mode (via VMCALL).
VOID LbrResetControlRegisters ()
 Reset the LBR control registers to zero, covering both ARCH and legacy LBR across all execution environments (native, VMX root-mode, VMX non-root mode).
VOID LbrAdjustFilterOptionsForCallStack (UINT64 *FilterOptions)
 Adjust filter options for call stack.
VOID LbrAdjustFilterOptions (UINT64 FilterOptions, IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
 Adjust filter options.
BOOLEAN LbrCheckArchBased (IA32_LBR_CTL_REGISTER Ia32LbrCtl)
 Check if architectural LBR is enabled based on the IA32_LBR_CTL register value.
BOOLEAN LbrCheckLegacyBased (ULONGLONG DbgCtlMsr)
 Check if legacy LBR is enabled based on the IA32_DEBUGCTL MSR value.
BOOLEAN LbrCheckOnVmxRootMode ()
 Check if LBR is enabled while in VMX root-mode.
BOOLEAN LbrCheckOnNativeOrVmxNonRootMode ()
 Check if LBR is enabled while in native mode or VMX non-root mode.
BOOLEAN LbrCheck ()
 Check if LBR is enabled or not.
BOOLEAN LbrStart (UINT64 FilterOptions)
 Start collecting LBR branches.
VOID LbrStop ()
 Stop collecting LBR branches.
VOID LbrFlush ()
 Flush LBR MSRs by disabling LBR and clearing all LBR entries.
VOID LbrFilter (UINT64 FilterOptions)
 Filter LBR branches based on the provided options.
VOID LbrSave ()
 Save LBR branches.
VOID LbrGetArchBranchType (UINT32 BrType, CHAR *BrTypeName)
 Get the branch type name based on the LBR branch type value (only applicable for architectural LBR).
VOID LbrPrint ()
 Print collected LBR branches.

Variables

CPU_LBR_MAP CPU_LBR_MAPS []
 The global variable to hold the mapping of CPU model to its LBR capacity.

Detailed Description

Last Branch Record (LBR) tracing implementation for HyperTrace module.

Author
Hari Mishal (harim.nosp@m.isha.nosp@m.l6@gm.nosp@m.ail..nosp@m.com)

Modified from LIBIHT project (Thomasaon Zhao et al) with Windows style updates.

Version
0.18
Date
2025-12-02

Function Documentation

◆ LbrAdjustArchBasedFilteringCompatibility()

VOID LbrAdjustArchBasedFilteringCompatibility ( IA32_LBR_CTL_REGISTER * Ia32LbrCtl)

Check and adjust compatibility of LBR filterings for ARCH based LBR.

Returns
VOID
212{
213 //
214 // Check capabilities and apply necessary adjustments based on CPU support
215 //
216 if (!g_Cpuid28Leafs.Ebx.LbrCpl)
217 {
218 //
219 // If CPL filtering is not supported
220 // we cannot filter kernel vs user mode branches, so we clear those filter bits to avoid confusion
221 //
222 Ia32LbrCtl->Bits.OS = 0;
223 Ia32LbrCtl->Bits.USR = 0;
224 }
225
226 if (!g_Cpuid28Leafs.Ebx.LbrFilter)
227 {
228 //
229 // If branch filtering is not supported, we cannot filter by branch type, so we clear all the specific branch type filter bits
230 //
231 Ia32LbrCtl->Bits.JCC = 0;
232 Ia32LbrCtl->Bits.NearRelJmp = 0;
233 Ia32LbrCtl->Bits.NearIndJmp = 0;
234 Ia32LbrCtl->Bits.NearRelCall = 0;
235 Ia32LbrCtl->Bits.NearIndCall = 0;
236 Ia32LbrCtl->Bits.NearRet = 0;
237 Ia32LbrCtl->Bits.OtherBranch = 0;
238 }
239
240 if (!g_Cpuid28Leafs.Ebx.LbrCallStack)
241 {
242 //
243 // If call-stack mode is not supported, we cannot filter by call stack, so we clear that filter bit
244 //
245 Ia32LbrCtl->Bits.CallStack = 0;
246 }
247}
CPUID28_LEAFS g_Cpuid28Leafs
The global variable to hold CPUID leaf 0x28 information (Architectural LBR Enumeration Leaf).
Definition GlobalVariables.h:66
ULONG64 OtherBranch
Definition Lbr.h:133
ULONG64 NearRet
Definition Lbr.h:132
ULONG64 NearRelCall
Definition Lbr.h:130
ULONG64 NearIndJmp
Definition Lbr.h:129
ULONG64 NearRelJmp
Definition Lbr.h:128
struct _IA32_LBR_CTL_REGISTER::@162044327322241346347142010232260066304104061355 Bits
ULONG64 OS
Definition Lbr.h:123
ULONG64 USR
Definition Lbr.h:124
ULONG64 CallStack
Definition Lbr.h:125
ULONG64 NearIndCall
Definition Lbr.h:131
ULONG64 JCC
Definition Lbr.h:127

◆ LbrAdjustFilterOptions()

VOID LbrAdjustFilterOptions ( UINT64 FilterOptions,
IA32_LBR_CTL_REGISTER * Ia32LbrCtl )

Adjust filter options.

Parameters
FilterOptionsA bitmask of filter options
Ia32LbrCtlPointer to the IA32_LBR_CTL_REGISTER to adjust based on the filter options and CPU capabilities
Returns
VOID
771{
772 //
773 // Adjust filter options in case of call_stack
774 //
776
777 //
778 // Save the LBR filter options to a global variable for later use
779 //
780 g_LbrFilterOptions = FilterOptions;
781
782 //
783 // For architectural LBR, convert filter options into IA32_LBR_CTL bit fields
784 //
786 {
787 LbrBuildArchBasedFilterOptions(FilterOptions, Ia32LbrCtl);
788 }
789
790 //
791 // For legacy LBR, write the raw filter options to MSR_LEGACY_LBR_SELECT
792 // Architectural LBR encodes its filters in IA32_LBR_CTL and does not use this MSR
793 //
795 {
796 LbrSetLbrSelectFilter(FilterOptions);
797 }
798}
VOID LbrBuildArchBasedFilterOptions(UINT64 FilterOptions, IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
Convert a filter options bitmask into IA32_LBR_CTL format for architectural LBR.
Definition Lbr.c:257
VOID LbrSetLbrSelectFilter(UINT64 FilterOptions)
Set the LBR select filter MSR (MSR_LEGACY_LBR_SELECT) for legacy LBR, dispatching via VMCALL when in ...
Definition Lbr.c:344
VOID LbrAdjustFilterOptionsForCallStack(UINT64 *FilterOptions)
Adjust filter options for call stack.
Definition Lbr.c:736
BOOLEAN g_ArchBasedLastBranchRecord
The flag indicating whether the architectural LBR is supported by the CPU or not if false it means th...
Definition GlobalVariables.h:42
UINT64 g_LbrFilterOptions
The global variable to hold the current LBR filter options bitmask (for both architectural and legacy...
Definition GlobalVariables.h:72

◆ LbrAdjustFilterOptionsForCallStack()

VOID LbrAdjustFilterOptionsForCallStack ( UINT64 * FilterOptions)

Adjust filter options for call stack.

Parameters
FilterOptionsA bitmask of filter options
Returns
VOID
737{
738 //
739 // Call-stack mode should be used with branch type enabling configured to capture only CALLs (NEAR_REL_CALL and
740 // NEAR_IND_CALL) and RETs (NEAR_RET). When configured in this manner, the LBR array emulates a call stack,
741 // where CALLs are "pushed" and RETs "pop" them off the stack. If other branch types (JCC, NEAR_*_JMP, or
742 // OTHER_BRANCH) are enabled for recording with call-stack mode, LBR behavior may be undefined, so we will
743 // mask out any branch type filters that are not CALLs or RETs when call-stack mode is requested to ensure
744 // we are correctly emulating a call stack and avoiding undefined behavior
745 //
746
747 //
748 // If it is call_stack then we only keep the user and kernel bit and filter all branch types
749 // except calls and rets to ensure we are only capturing call stack profile
750 //
751 if (*FilterOptions & LBR_CALL_STACK)
752 {
753 //
754 // Preserve only the user/kernel privilege bits from the original options,
755 // then apply the mandatory call stack base flags
756 //
757 *FilterOptions = LBR_CALL_STACK_BASE_FLAGS | (*FilterOptions & (LBR_KERNEL | LBR_USER));
758 }
759}
#define LBR_CALL_STACK
Definition LbrDefinitions.h:59
#define LBR_CALL_STACK_BASE_FLAGS
For call-stack mode, only CALLs and RETs should be captured Capturing other branch types may lead to ...
Definition LbrDefinitions.h:65
#define LBR_USER
Definition LbrDefinitions.h:51
#define LBR_KERNEL
Definition LbrDefinitions.h:50

◆ LbrBuildArchBasedFilterOptions()

VOID LbrBuildArchBasedFilterOptions ( UINT64 FilterOptions,
IA32_LBR_CTL_REGISTER * Ia32LbrCtl )

Convert a filter options bitmask into IA32_LBR_CTL format for architectural LBR.

Parameters
FilterOptionsA bitmask of filter options (e.g., LBR_KERNEL, LBR_USER, LBR_JCC, etc.)
Ia32LbrCtlPointer to the IA32_LBR_CTL_REGISTER to populate with the converted filter bits
Returns
VOID
258{
259 //
260 // By default, we are enabling all of them
261 //
262 Ia32LbrCtl->Bits.OS = 1;
263 Ia32LbrCtl->Bits.USR = 1;
264 Ia32LbrCtl->Bits.JCC = 1;
265 Ia32LbrCtl->Bits.NearRelCall = 1;
266 Ia32LbrCtl->Bits.NearIndCall = 1;
267 Ia32LbrCtl->Bits.NearRet = 1;
268 Ia32LbrCtl->Bits.NearIndJmp = 1;
269 Ia32LbrCtl->Bits.NearRelJmp = 1;
270 Ia32LbrCtl->Bits.OtherBranch = 1;
271 Ia32LbrCtl->Bits.CallStack = 1;
272
273 //
274 // Perform filtering the results
275 //
276 if (FilterOptions & LBR_KERNEL)
277 {
278 Ia32LbrCtl->Bits.OS = 0;
279 }
280
281 if (FilterOptions & LBR_USER)
282 {
283 Ia32LbrCtl->Bits.USR = 0;
284 }
285
286 if (FilterOptions & LBR_JCC)
287 {
288 Ia32LbrCtl->Bits.JCC = 0;
289 }
290
291 if (FilterOptions & LBR_REL_CALL)
292 {
293 Ia32LbrCtl->Bits.NearRelCall = 0;
294 }
295
296 if (FilterOptions & LBR_IND_CALL)
297 {
298 Ia32LbrCtl->Bits.NearIndCall = 0;
299 }
300
301 if (FilterOptions & LBR_RETURN)
302 {
303 Ia32LbrCtl->Bits.NearRet = 0;
304 }
305
306 if (FilterOptions & LBR_IND_JMP)
307 {
308 Ia32LbrCtl->Bits.NearIndJmp = 0;
309 }
310
311 if (FilterOptions & LBR_REL_JMP)
312 {
313 Ia32LbrCtl->Bits.NearRelJmp = 0;
314 }
315
316 if (FilterOptions & LBR_FAR_OTHER_BRANCHES)
317 {
318 Ia32LbrCtl->Bits.OtherBranch = 0;
319 }
320
321 if (FilterOptions & LBR_CALL_STACK)
322 {
323 Ia32LbrCtl->Bits.CallStack = 0;
324 }
325
326 //
327 // Adjust LBR fitlering options based on the CPU capabilities to ensure we are not setting unsupported filter bits
328 //
330}
VOID LbrAdjustArchBasedFilteringCompatibility(IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
Check and adjust compatibility of LBR filterings for ARCH based LBR.
Definition Lbr.c:211
#define LBR_FAR_OTHER_BRANCHES
Definition LbrDefinitions.h:58
#define LBR_RETURN
Definition LbrDefinitions.h:55
#define LBR_IND_CALL
Definition LbrDefinitions.h:54
#define LBR_REL_JMP
Definition LbrDefinitions.h:57
#define LBR_JCC
Definition LbrDefinitions.h:52
#define LBR_IND_JMP
Definition LbrDefinitions.h:56
#define LBR_REL_CALL
Definition LbrDefinitions.h:53

◆ LbrCheck()

BOOLEAN LbrCheck ( )

Check if LBR is enabled or not.

Returns
BOOLEAN
877{
878 BOOLEAN IsOnVmxRootMode = FALSE;
879
881 {
882 IsOnVmxRootMode = g_Callbacks.VmFuncVmxGetCurrentExecutionMode();
883 }
884
885 if (IsOnVmxRootMode)
886 {
887 return LbrCheckOnVmxRootMode();
888 }
889 else
890 {
892 }
893}
BOOLEAN LbrCheckOnNativeOrVmxNonRootMode()
Check if LBR is enabled while in native mode or VMX non-root mode.
Definition Lbr.c:853
BOOLEAN LbrCheckOnVmxRootMode()
Check if LBR is enabled while in VMX root-mode.
Definition Lbr.c:830
UCHAR BOOLEAN
Definition BasicTypes.h:35
#define FALSE
Definition BasicTypes.h:113
HYPEREVADE_CALLBACKS g_Callbacks
List of callbacks.
Definition Transparency.h:23
BOOLEAN g_RunningOnHypervisorEnvironment
The flag indicating whether the initialization is being done for hypervisor environment or not.
Definition GlobalVariables.h:35

◆ LbrCheckAndReadArchitecturalLbrDetails()

BOOLEAN LbrCheckAndReadArchitecturalLbrDetails ( )

Check if the current CPU supports architectural LBR.

Returns
BOOLEAN
87{
88 ULONG a, b, c, d;
89
90 CPUID_EAX_07 Edx07 = {0};
91
92 CPUID28_EAX Eax1c = {0};
93 CPUID28_EBX Ebx1c = {0};
94 CPUID28_ECX Ecx1c = {0};
95
96 //
97 // Check for Architectural LBR support
98 //
99 //
100 xcpuidex(CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, 0x00, &a, &b, &c, &d);
101
102 Edx07.Edx.AsUInt = d;
103
104 //
105 // CPUID.07H.00H:EDX[19] == 1 means arch LBR is supported
106 //
107 if (Edx07.Edx.AsUInt & (1 << 19))
108 {
110 }
111 else
112 {
113 //
114 // Architectural LBR is not supported by the CPU
115 //
117
118 return FALSE;
119 }
120
121 //
122 // Being here means the CPU supports architectural LBR, we can read the LBR capabilities from CPUID 0x1c leaf
123 //
125
126 //
127 // Assign LBR leafs to structure for easier access
128 //
129 Eax1c.AsUInt = a;
130 Ebx1c.AsUInt = b;
131 Ecx1c.AsUInt = c;
132
133 //
134 // Store the CPUID.1CH leaf information in a global structure for later use
135 //
136 g_Cpuid28Leafs.Eax = Eax1c;
137 g_Cpuid28Leafs.Ebx = Ebx1c;
138 g_Cpuid28Leafs.Ecx = Ecx1c;
139 g_Cpuid28Leafs.Edx = d;
140
141 //
142 // Read LBR capacity from CPUID.1CH.00H:EAX[7:0]
143 // Based on Intel SDM: For each bit n set in this field, the IA32_LBR_DEPTH.DEPTH value 8 * (n + 1) is supported
144 //
145 if (Eax1c.LbrDepthMask)
146 {
147 //
148 // Get the highest set bit in LbrDepthMask to determine the maximum supported LBR depth
149 //
150 ULONG HighestSetBit = 0;
151 for (ULONG i = 0; i < 8; i++)
152 {
153 if (Eax1c.LbrDepthMask & (1 << i))
154 {
155 HighestSetBit = i;
156 }
157 }
158 g_LbrCapacity = 8 * (HighestSetBit + 1);
159 }
160 else
161 {
162 //
163 // If LbrDepthMask is 0, it means the CPU supports architectural LBR but does not specify the depth, we can assume a default value (e.g., 16 or 32) or treat it as unsupported
164 //
165 g_LbrCapacity = MAXIMUM_LBR_CAPACITY; // Assuming a default capacity of MAXIMUM_LBR_CAPACITY if not specified
166 }
167
168 return TRUE;
169}
#define CPUID_ARCH_LAST_BRANCH_RECORD_INFORMATION
Definition Lbr.h:36
union _CPUID28_EBX CPUID28_EBX
union _CPUID28_ECX CPUID28_ECX
union _CPUID28_EAX CPUID28_EAX
#define xcpuidex(code, subleaf, a, b, c, d)
Definition TraceApi.h:39
#define TRUE
Definition BasicTypes.h:114
unsigned long ULONG
Definition BasicTypes.h:31
#define MAXIMUM_LBR_CAPACITY
Maximum LBR capacity that is supported by processors.
Definition LbrDefinitions.h:27
ULONGLONG g_LbrCapacity
The global variable to hold the LBR capacity of the current CPU.
Definition GlobalVariables.h:60
UINT32 AsUInt
Definition Lbr.h:64
UINT32 LbrDepthMask
Definition Lbr.h:57
UINT32 AsUInt
Definition Lbr.h:79
UINT32 AsUInt
Definition Lbr.h:94

◆ LbrCheckAndReadLegacyLbrDetails()

BOOLEAN LbrCheckAndReadLegacyLbrDetails ( )

Check if the current CPU supports LBR by examining the CPU family and model and looking up the corresponding LBR capacity.

Returns
BOOLEAN
178{
179 ULONG a, b, c, d;
180 ULONG Family, Model;
181 ULONGLONG i;
182
183 xcpuid(1, &a, &b, &c, &d);
184
185 Family = ((a >> 8) & 0xF) + ((a >> 20) & 0xFF);
186 Model = ((a >> 4) & 0xF) | ((a >> 12) & 0xF0);
187
188 for (i = 0; i < sizeof(CPU_LBR_MAPS) / sizeof(CPU_LBR_MAPS[0]); ++i)
189 {
190 if (Model == CPU_LBR_MAPS[i].Model)
191 {
192 g_LbrCapacity = CPU_LBR_MAPS[i].LbrCapacity;
193 break;
194 }
195 }
196
197 if (g_LbrCapacity == 0)
198 {
199 return FALSE;
200 }
201
202 return TRUE;
203}
CPU_LBR_MAP CPU_LBR_MAPS[]
The global variable to hold the mapping of CPU model to its LBR capacity.
Definition Lbr.c:21
#define xcpuid(code, a, b, c, d)
Definition TraceApi.h:29

◆ LbrCheckArchBased()

BOOLEAN LbrCheckArchBased ( IA32_LBR_CTL_REGISTER Ia32LbrCtl)

Check if architectural LBR is enabled based on the IA32_LBR_CTL register value.

Parameters
Ia32LbrCtlThe IA32_LBR_CTL register value to inspect
Returns
BOOLEAN
808{
809 return Ia32LbrCtl.Bits.LBREn ? TRUE : FALSE;
810}
ULONG64 LBREn
Definition Lbr.h:122

◆ LbrCheckLegacyBased()

BOOLEAN LbrCheckLegacyBased ( ULONGLONG DbgCtlMsr)

Check if legacy LBR is enabled based on the IA32_DEBUGCTL MSR value.

Parameters
DbgCtlMsrThe IA32_DEBUGCTL MSR value to inspect
Returns
BOOLEAN
820{
821 return (DbgCtlMsr & IA32_DEBUGCTL_LBR_FLAG) ? TRUE : FALSE;
822}

◆ LbrCheckOnNativeOrVmxNonRootMode()

BOOLEAN LbrCheckOnNativeOrVmxNonRootMode ( )

Check if LBR is enabled while in native mode or VMX non-root mode.

Returns
BOOLEAN
854{
855 ULONGLONG DbgCtlMsr = 0;
856 IA32_LBR_CTL_REGISTER Ia32LbrCtl = {0};
857
859 {
860 xrdmsr(IA32_LBR_CTL, &Ia32LbrCtl.AsUInt);
861 return LbrCheckArchBased(Ia32LbrCtl);
862 }
863 else
864 {
865 xrdmsr(IA32_DEBUGCTL, &DbgCtlMsr);
866 return LbrCheckLegacyBased(DbgCtlMsr);
867 }
868}
BOOLEAN LbrCheckLegacyBased(ULONGLONG DbgCtlMsr)
Check if legacy LBR is enabled based on the IA32_DEBUGCTL MSR value.
Definition Lbr.c:819
BOOLEAN LbrCheckArchBased(IA32_LBR_CTL_REGISTER Ia32LbrCtl)
Check if architectural LBR is enabled based on the IA32_LBR_CTL register value.
Definition Lbr.c:807
union _IA32_LBR_CTL_REGISTER IA32_LBR_CTL_REGISTER
The structure to hold the IA32_LBR_CTL MSR, which is used to enable and configure the LBR feature.
#define IA32_LBR_CTL
Definition Lbr.h:43
#define xrdmsr(msr, pval)
Definition TraceApi.h:25
ULONG64 AsUInt
Definition Lbr.h:118

◆ LbrCheckOnVmxRootMode()

BOOLEAN LbrCheckOnVmxRootMode ( )

Check if LBR is enabled while in VMX root-mode.

Returns
BOOLEAN
831{
832 ULONGLONG DbgCtlMsr = 0;
833 IA32_LBR_CTL_REGISTER Ia32LbrCtl = {0};
834
836 {
837 Ia32LbrCtl.AsUInt = g_Callbacks.VmFuncGetGuestIa32LbrCtl();
838 return LbrCheckArchBased(Ia32LbrCtl);
839 }
840 else
841 {
842 DbgCtlMsr = g_Callbacks.VmFuncGetDebugctl();
843 return LbrCheckLegacyBased(DbgCtlMsr);
844 }
845}

◆ LbrClearHardwareState()

VOID LbrClearHardwareState ( )

Zero out the LBR hardware state (TOS and all from/to MSR pairs).

For architectural LBR the TOS index is not maintained by software and the CPU shifts entries automatically, so MSR_LBR_TOS is skipped in that case.

Returns
VOID
387{
388 //
389 // For architectural LBR, the TOS is not used; the CPU shifts LBR entries automatically
390 // and does not update the TOS index
391 //
393 {
395 }
396
397 //
398 // Clearing LBR TO and FROM MSRs
399 //
400 for (ULONG i = 0; i < (ULONG)g_LbrCapacity; i++)
401 {
403 {
405 xwrmsr(IA32_LBR_0_TO_IP + i, 0);
406 }
407 else
408 {
411 }
412 }
413}
#define IA32_LBR_0_FROM_IP
Definition Lbr.h:32
#define IA32_LBR_0_TO_IP
Definition Lbr.h:33
#define MSR_LASTBRANCH_0_FROM_IP
Definition Lbr.h:24
#define MSR_LBR_TOS
Definition Lbr.h:23
#define MSR_LASTBRANCH_0_TO_IP
Definition Lbr.h:25
#define xwrmsr(msr, val)
Definition TraceApi.h:26

◆ LbrDisableArchBased()

VOID LbrDisableArchBased ( IA32_LBR_CTL_REGISTER * Ia32LbrCtl)

Disable LBR collection on architectural (ARCH) based LBR.

Parameters
Ia32LbrCtlPointer to the IA32_LBR_CTL register whose LBREn bit will be cleared
Returns
VOID
531{
532 Ia32LbrCtl->Bits.LBREn = 0;
533}

◆ LbrDisableLegacyBased()

VOID LbrDisableLegacyBased ( ULONGLONG * DbgCtlMsr)

Disable LBR collection on legacy based LBR.

Parameters
DbgCtlMsrPointer to the IA32_DEBUGCTL MSR value whose LBR flag will be cleared
Returns
VOID
543{
544 *DbgCtlMsr &= ~IA32_DEBUGCTL_LBR_FLAG;
545}

◆ LbrEnableArchBased()

VOID LbrEnableArchBased ( IA32_LBR_CTL_REGISTER * Ia32LbrCtl)

Enable LBR collection on architectural (ARCH) based LBR.

Parameters
Ia32LbrCtlPointer to the IA32_LBR_CTL_REGISTER whose LBREn bit will be set
Returns
VOID
423{
424 Ia32LbrCtl->Bits.LBREn = 1;
425}

◆ LbrEnableLegacyBased()

VOID LbrEnableLegacyBased ( ULONGLONG * DbgCtlMsr)

Enable LBR collection on legacy based LBR.

Parameters
DbgCtlMsrPointer to the IA32_DEBUGCTL MSR value to be modified
Returns
VOID
435{
436 //
437 // Enable LBR and CLEAR 'Freeze LBRs on PMI' (Bit 11)
438 // If Bit 11 is set, the LBR stops recording as soon as a single PMI interrupt fires
439 //
440 *DbgCtlMsr |= IA32_DEBUGCTL_LBR_FLAG; // Bit 0 = 1
441 *DbgCtlMsr &= ~(1ULL << IA32_DEBUGCTL_FREEZE_LBRS_ON_PMI_BIT); // Bit 11 = 0
442}

◆ LbrFilter()

VOID LbrFilter ( UINT64 FilterOptions)

Filter LBR branches based on the provided options.

Parameters
FilterOptionsA bitmask of filter options to apply to the LBR branches
Returns
VOID
1071{
1072 // LogInfo("Updating LBR filter options: 0x%llx\n", FilterOptions);
1073
1074 //
1075 // First, we flush the LBR to clear out any existing entries that may not meet the new filter criteria
1076 //
1077 LbrFlush();
1078
1079 //
1080 // Then we apply the new filter options and re-enable LBR with the updated filter settings
1081 //
1082 LbrStart(FilterOptions);
1083}
VOID LbrFlush()
Flush LBR MSRs by disabling LBR and clearing all LBR entries.
Definition Lbr.c:1041
BOOLEAN LbrStart(UINT64 FilterOptions)
Start collecting LBR branches.
Definition Lbr.c:903

◆ LbrFlush()

VOID LbrFlush ( )

Flush LBR MSRs by disabling LBR and clearing all LBR entries.

Returns
VOID
1042{
1043 // LogInfo("Flush LBR on cpu core: %d\n", KeGetCurrentProcessorNumberEx(NULL));
1044
1045 //
1046 // Stop LBR collection and save any remaining entries
1047 //
1048 LbrStop();
1049
1050 //
1051 // Reset the LBR control registers to zero:
1052 // - ARCH LBR: zeroes IA32_LBR_CTL entirely (clears filters and disables collection)
1053 // - Legacy LBR: zeroes MSR_LEGACY_LBR_SELECT (resets branch filter to capture-all)
1054 //
1056
1057 //
1058 // Clear all remaining hardware state (TOS for legacy LBR, and all from/to MSR pairs)
1059 //
1061}
VOID LbrStop()
Stop collecting LBR branches.
Definition Lbr.c:983
VOID LbrClearHardwareState()
Zero out the LBR hardware state (TOS and all from/to MSR pairs).
Definition Lbr.c:386
VOID LbrResetControlRegisters()
Reset the LBR control registers to zero, covering both ARCH and legacy LBR across all execution envir...
Definition Lbr.c:673

◆ LbrGetArchBranchType()

VOID LbrGetArchBranchType ( UINT32 BrType,
CHAR * BrTypeName )

Get the branch type name based on the LBR branch type value (only applicable for architectural LBR).

THIS FUNCTION IS ALSO IMPLEMENTED IN THE USER MODE

Parameters
BrTypeThe raw branch type value from the LBR info MSR
BrTypeNameA character buffer to receive the branch type name string
Returns
VOID
1149{
1150 if (BrType == LBR_BR_TYPE_COND)
1151 {
1152 strncpy(BrTypeName, "COND ", LBR_BR_TYPE_NAME_MAX_LEN);
1153 }
1154 else if (BrType == LBR_BR_TYPE_JMP_INDIRECT)
1155 {
1156 strncpy(BrTypeName, "JMP Indirect ", LBR_BR_TYPE_NAME_MAX_LEN);
1157 }
1158 else if (BrType == LBR_BR_TYPE_JMP_DIRECT)
1159 {
1160 strncpy(BrTypeName, "JMP Direct ", LBR_BR_TYPE_NAME_MAX_LEN);
1161 }
1162 else if (BrType == LBR_BR_TYPE_CALL_INDIRECT)
1163 {
1164 strncpy(BrTypeName, "CALL Indirect", LBR_BR_TYPE_NAME_MAX_LEN);
1165 }
1166 else if (BrType == LBR_BR_TYPE_CALL_DIRECT)
1167 {
1168 strncpy(BrTypeName, "CALL Direct ", LBR_BR_TYPE_NAME_MAX_LEN);
1169 }
1170 else if (BrType == LBR_BR_TYPE_RET)
1171 {
1172 strncpy(BrTypeName, "RET ", LBR_BR_TYPE_NAME_MAX_LEN);
1173 }
1174 else if (BrType >= LBR_BR_TYPE_RESERVED_MIN && BrType <= LBR_BR_TYPE_RESERVED_MAX)
1175 {
1176 strncpy(BrTypeName, "Reserved ", LBR_BR_TYPE_NAME_MAX_LEN);
1177 }
1178 else if (BrType >= LBR_BR_TYPE_OTHER_MIN && BrType <= LBR_BR_TYPE_OTHER_MAX)
1179 {
1180 strncpy(BrTypeName, "Other Branch ", LBR_BR_TYPE_NAME_MAX_LEN);
1181 }
1182 else
1183 {
1184 strncpy(BrTypeName, "Unknown ", LBR_BR_TYPE_NAME_MAX_LEN);
1185 }
1186}
#define LBR_BR_TYPE_JMP_DIRECT
Definition LbrDefinitions.h:72
#define LBR_BR_TYPE_OTHER_MIN
Definition LbrDefinitions.h:78
#define LBR_BR_TYPE_CALL_DIRECT
Definition LbrDefinitions.h:74
#define LBR_BR_TYPE_OTHER_MAX
Definition LbrDefinitions.h:79
#define LBR_BR_TYPE_RESERVED_MIN
Definition LbrDefinitions.h:76
#define LBR_BR_TYPE_COND
Branch Type Encodings (Only on Architectural LBR, not available in Legacy LBR).
Definition LbrDefinitions.h:70
#define LBR_BR_TYPE_CALL_INDIRECT
Definition LbrDefinitions.h:73
#define LBR_BR_TYPE_RESERVED_MAX
Definition LbrDefinitions.h:77
#define LBR_BR_TYPE_JMP_INDIRECT
Definition LbrDefinitions.h:71
#define LBR_BR_TYPE_RET
Definition LbrDefinitions.h:75
#define LBR_BR_TYPE_NAME_MAX_LEN
Definition LbrDefinitions.h:81

◆ LbrGetValuesOnVmxNonRootMode()

VOID LbrGetValuesOnVmxNonRootMode ( ULONGLONG * DbgCtlMsr,
IA32_LBR_CTL_REGISTER * Ia32LbrCtl )

Read current LBR control register values while in VMX non-root mode (via VMCALL).

Parameters
DbgCtlMsrPointer to receive the IA32_DEBUGCTL MSR value (legacy LBR)
Ia32LbrCtlPointer to receive the IA32_LBR_CTL register value (arch LBR)
Returns
VOID
506{
508 {
509 //
510 // It is not on VMX-root mode, so we need to perform a VMCALL to get the IA32_LBR_CTL value on the target core
511 //
512 Ia32LbrCtl->AsUInt = g_Callbacks.VmFuncGetGuestIa32LbrCtlVmcallOnTargetCore();
513 }
514 else
515 {
516 //
517 // It is not on VMX-root mode, so we need to perform a VMCALL to get the IA32_DEBUGCTL MSR value on the target core
518 //
519 *DbgCtlMsr = g_Callbacks.VmFuncGetDebugctlVmcallOnTargetCore();
520 }
521}

◆ LbrGetValuesOnVmxRootMode()

VOID LbrGetValuesOnVmxRootMode ( ULONGLONG * DbgCtlMsr,
IA32_LBR_CTL_REGISTER * Ia32LbrCtl )

Read current LBR control register values while in VMX root-mode.

Parameters
DbgCtlMsrPointer to receive the IA32_DEBUGCTL MSR value (legacy LBR)
Ia32LbrCtlPointer to receive the IA32_LBR_CTL register value (arch LBR)
Returns
VOID
480{
482 {
483 //
484 // It is on VMX-root mode, run it directly to get the IA32_LBR_CTL value in VMCS
485 //
486 Ia32LbrCtl->AsUInt = g_Callbacks.VmFuncGetGuestIa32LbrCtl();
487 }
488 else
489 {
490 //
491 // It is on VMX-root mode, run it directly to get the IA32_DEBUGCTL MSR value in VMCS
492 //
493 *DbgCtlMsr = g_Callbacks.VmFuncGetDebugctl();
494 }
495}

◆ LbrPrint()

VOID LbrPrint ( )

Print collected LBR branches.

Returns
VOID
1195{
1196 ULONG CurrentIdx;
1197 LBR_STACK_ENTRY * State;
1198 UINT32 CurrentCore = 0;
1199 CHAR BrTypeName[LBR_BR_TYPE_NAME_MAX_LEN] = {0};
1200 UINT32 BrType = 0;
1201 //
1202 // Get the current core id
1203 //
1204 CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
1205
1206 //
1207 // Get the current processor LBR stack
1208 //
1209 State = &g_LbrStateList[CurrentCore];
1210
1211 Log("LBR Chronological Trace on core : 0x%x\n\n", CurrentCore);
1212
1213 for (ULONG i = 1; i <= g_LbrCapacity; i++)
1214 {
1216 {
1217 //
1218 // In ARCH LBR, there is not TOS index and everything is in order
1219 //
1220 CurrentIdx = i - 1;
1221 }
1222 else
1223 {
1224 CurrentIdx = (ULONG)(State->Tos + i) % (ULONG)g_LbrCapacity;
1225 }
1226
1227 if (State->BranchEntry[CurrentIdx].From == 0)
1228 {
1229 continue;
1230 }
1231
1233 {
1234 BrType = (UINT32)State->LastBranchInfo[CurrentIdx].BrType_OnlyArchLbr;
1235
1236 //
1237 // Get the branch type name for better readability when printing
1238 //
1239 LbrGetArchBranchType(BrType, BrTypeName);
1240
1241 //
1242 // Architectural LBR
1243 //
1244 Log("\t [%2u] Branch Mispredicted: %s, Branch type: %s, Cycle Count (Decimal): %04d (is valid? %s) - From: %016llx To: %016llx\n",
1245 CurrentIdx,
1246 State->LastBranchInfo[CurrentIdx].Mispred ? "true " : "false",
1247 BrTypeName,
1248 State->LastBranchInfo[CurrentIdx].CycleCount,
1249 State->LastBranchInfo[CurrentIdx].CycCntValid_OnlyArchLbr ? "true " : "false",
1250 State->BranchEntry[CurrentIdx].From,
1251 State->BranchEntry[CurrentIdx].To);
1252 }
1253 else
1254 {
1255 //
1256 // Legacy LBR
1257 //
1258 Log("\t [%2u] Branch Mispredicted: %s, Cycle Count (Decimal): %04d - From: %016llx To: %016llx\n",
1259 CurrentIdx,
1260 State->LastBranchInfo[CurrentIdx].Mispred ? "true " : "false",
1261 State->LastBranchInfo[CurrentIdx].CycleCount,
1262 State->BranchEntry[CurrentIdx].From,
1263 State->BranchEntry[CurrentIdx].To);
1264 }
1265 }
1266}
VOID LbrGetArchBranchType(UINT32 BrType, CHAR *BrTypeName)
Get the branch type name based on the LBR branch type value (only applicable for architectural LBR).
Definition Lbr.c:1148
unsigned int UINT32
Definition BasicTypes.h:54
char CHAR
Definition BasicTypes.h:33
struct _LBR_STACK_ENTRY LBR_STACK_ENTRY
The structure to hold the LBR stack for a single processor core, including the branch entries and the...
#define Log(format,...)
Log without any prefix.
Definition HyperDbgHyperLogIntrinsics.h:129
LBR_STACK_ENTRY * g_LbrStateList
This will be a dynamically allocated array to hold LBR states for each core.
Definition GlobalVariables.h:54
ULONGLONG From
Definition LbrDefinitions.h:156
ULONGLONG To
Definition LbrDefinitions.h:157
MSR_LBR_INFO LastBranchInfo[MAXIMUM_LBR_CAPACITY]
Definition LbrDefinitions.h:168
UINT8 Tos
Definition LbrDefinitions.h:169
LBR_BRANCH_ENTRY BranchEntry[MAXIMUM_LBR_CAPACITY]
Definition LbrDefinitions.h:167
UINT64 Mispred
Definition LbrDefinitions.h:141
UINT64 BrType_OnlyArchLbr
Definition LbrDefinitions.h:113
UINT64 CycCntValid_OnlyArchLbr
Definition LbrDefinitions.h:116
UINT64 CycleCount
Definition LbrDefinitions.h:95

◆ LbrResetArchControlOnVmxNonRootMode()

VOID LbrResetArchControlOnVmxNonRootMode ( )

Zero the ARCH LBR control register while in VMX non-root mode (via VMCALL).

Setting IA32_LBR_CTL to 0 simultaneously clears all filter bits and disables collection (LBREn = 0), which is the correct flush state.

Returns
VOID
652{
653 //
654 // It is not on VMX-root mode, perform a VMCALL to set the entire IA32_LBR_CTL to 0 on the target core
655 // (this also disables LBR since LBREn is cleared)
656 //
657 g_Callbacks.VmFuncSetGuestIa32LbrCtlVmcallOnTargetCore(0);
658}

◆ LbrResetArchControlOnVmxRootMode()

VOID LbrResetArchControlOnVmxRootMode ( )

Zero the ARCH LBR control register while in VMX root-mode.

Setting IA32_LBR_CTL to 0 simultaneously clears all filter bits and disables collection (LBREn = 0), which is the correct flush state.

Returns
VOID
634{
635 //
636 // It is on VMX-root mode, set the entire IA32_LBR_CTL to 0 directly in VMCS
637 // (this also disables LBR since LBREn is cleared)
638 //
639 g_Callbacks.VmFuncSetGuestIa32LbrCtl(0);
640}

◆ LbrResetControlRegisters()

VOID LbrResetControlRegisters ( )

Reset the LBR control registers to zero, covering both ARCH and legacy LBR across all execution environments (native, VMX root-mode, VMX non-root mode).

For architectural LBR, IA32_LBR_CTL is zeroed entirely (clearing filter bits and disabling collection in one write). For legacy LBR, MSR_LEGACY_LBR_SELECT is zeroed to reset the branch filter to its default capture-all state. Note: Even though MSR_LEGACY_LBR_SELECT is a plain MSR (not a VMCS field), it must be written from VMX-root mode for the change to take effect.

Returns
VOID
674{
675 BOOLEAN IsOnVmxRootMode;
676
678 {
679 IsOnVmxRootMode = g_Callbacks.VmFuncVmxGetCurrentExecutionMode();
680
681 //
682 // If we don't set it on VMX-root mode, the LBR MSRs won't work based on our tests
683 // even though it is just a plain MSR (and not a VMCS field)
684 //
685 if (IsOnVmxRootMode)
686 {
688 {
690 }
691 else
692 {
693 //
694 // Reuse LbrSetLbrSelectFilter: writing 0 resets MSR_LEGACY_LBR_SELECT to
695 // its default state (capture all branch types) from VMX-root mode
696 //
697 g_Callbacks.VmFuncSetLbrSelect(0);
698 }
699 }
700 else
701 {
703 {
705 }
706 else
707 {
708 //
709 // Reuse LbrSetLbrSelectFilter: writing 0 resets MSR_LEGACY_LBR_SELECT to
710 // its default state (capture all branch types) via VMCALL on the target core
711 //
712 g_Callbacks.VmFuncSetLbrSelectVmcallOnTargetCore(0);
713 }
714 }
715 }
716 else
717 {
719 {
721 }
722 else
723 {
725 }
726 }
727}
VOID LbrResetArchControlOnVmxNonRootMode()
Zero the ARCH LBR control register while in VMX non-root mode (via VMCALL).
Definition Lbr.c:651
VOID LbrResetArchControlOnVmxRootMode()
Zero the ARCH LBR control register while in VMX root-mode.
Definition Lbr.c:633
#define MSR_LEGACY_LBR_SELECT
MSR address of LBR_SELECT, which is used to configure the LBR filtering options.
Definition LbrDefinitions.h:21

◆ LbrSave()

VOID LbrSave ( )

Save LBR branches.

Returns
VOID
1092{
1093 UINT64 LbrTos;
1094 LBR_STACK_ENTRY * State;
1095 UINT32 CurrentCore = 0;
1096
1097 //
1098 // Get the current core id
1099 //
1100 CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
1101
1102 //
1103 // Get the current processor LBR stack
1104 //
1105 State = &g_LbrStateList[CurrentCore];
1106
1107 //
1108 // Read and store the current TOS index to know where the most recent branch is stored
1109 // Note that there is no TOS index in ARCH LBR since everything is in order
1110 //
1112 {
1113 xrdmsr(MSR_LBR_TOS, &LbrTos);
1114 State->Tos = (UINT8)LbrTos;
1115 }
1116
1117 //
1118 // Dump LBR entries into the current core's state structure
1119 //
1120 for (ULONG i = 0; i < (ULONG)g_LbrCapacity; i++)
1121 {
1123 {
1124 xrdmsr(IA32_LBR_0_FROM_IP + i, &State->BranchEntry[i].From);
1125 xrdmsr(IA32_LBR_0_TO_IP + i, &State->BranchEntry[i].To);
1127 }
1128 else
1129 {
1133 }
1134 }
1135}
#define MSR_LASTBRANCH_INFO_0
Definition Lbr.h:26
#define IA32_LBR_0_INFO
Definition Lbr.h:34
unsigned char UINT8
Definition BasicTypes.h:52
UINT64 AsUInt
Definition LbrDefinitions.h:143

◆ LbrSetLbrSelectFilter()

VOID LbrSetLbrSelectFilter ( UINT64 FilterOptions)

Set the LBR select filter MSR (MSR_LEGACY_LBR_SELECT) for legacy LBR, dispatching via VMCALL when in VMX non-root mode.

This function is only relevant for legacy LBR. Architectural LBR encodes filter options directly in IA32_LBR_CTL and does not use MSR_LEGACY_LBR_SELECT. Note: Even though MSR_LEGACY_LBR_SELECT is a plain MSR (not a VMCS field), it must be set from VMX-root mode for the LBR MSRs to work correctly.

Parameters
FilterOptionsThe raw filter options bitmask to write into MSR_LEGACY_LBR_SELECT
Returns
VOID
345{
346 BOOLEAN IsOnVmxRootMode;
347
349 {
350 IsOnVmxRootMode = g_Callbacks.VmFuncVmxGetCurrentExecutionMode();
351
352 //
353 // If we don't set it on VMX-root mode, the LBR MSRs won't work based on our tests
354 // even though it is just a plain MSR (and not a VMCS field)
355 //
356 if (IsOnVmxRootMode)
357 {
358 //
359 // It is on VMX-root mode, run it directly to set the MSR_LEGACY_LBR_SELECT MSR value
360 //
361 g_Callbacks.VmFuncSetLbrSelect(FilterOptions);
362 }
363 else
364 {
365 //
366 // It is not on VMX-root mode, so we need to perform a VMCALL to set the MSR_LEGACY_LBR_SELECT MSR value on the target core
367 //
368 g_Callbacks.VmFuncSetLbrSelectVmcallOnTargetCore(FilterOptions);
369 }
370 }
371 else
372 {
373 xwrmsr(MSR_LEGACY_LBR_SELECT, FilterOptions);
374 }
375}

◆ LbrSetValuesOnVmxNonRootMode()

VOID LbrSetValuesOnVmxNonRootMode ( ULONGLONG DbgCtlMsr,
IA32_LBR_CTL_REGISTER Ia32LbrCtl )

Write back modified LBR control register values while in VMX non-root mode (via VMCALL).

Parameters
DbgCtlMsrThe updated IA32_DEBUGCTL MSR value to apply (legacy LBR)
Ia32LbrCtlThe updated IA32_LBR_CTL register value to apply (arch LBR)
Returns
VOID
582{
584 {
585 //
586 // It is not on VMX-root mode, so we need to perform a VMCALL to set the IA32_LBR_CTL value on the target core
587 //
588 g_Callbacks.VmFuncSetGuestIa32LbrCtlVmcallOnTargetCore(Ia32LbrCtl.AsUInt);
589 }
590 else
591 {
592 //
593 // It is not on VMX-root mode, so we need to perform a VMCALL to set the IA32_DEBUGCTL MSR value on the target core
594 //
595 g_Callbacks.VmFuncSetDebugctlVmcallOnTargetCore(DbgCtlMsr);
596 }
597}

◆ LbrSetValuesOnVmxRootMode()

VOID LbrSetValuesOnVmxRootMode ( ULONGLONG DbgCtlMsr,
IA32_LBR_CTL_REGISTER Ia32LbrCtl )

Write back modified LBR control register values while in VMX root-mode.

Parameters
DbgCtlMsrThe updated IA32_DEBUGCTL MSR value to apply (legacy LBR)
Ia32LbrCtlThe updated IA32_LBR_CTL register value to apply (arch LBR)
Returns
VOID
556{
558 {
559 //
560 // It is on VMX-root mode, run it directly to set the IA32_LBR_CTL value in VMCS
561 //
562 g_Callbacks.VmFuncSetGuestIa32LbrCtl(Ia32LbrCtl.AsUInt);
563 }
564 else
565 {
566 //
567 // It is on VMX-root mode, run it directly to set the IA32_DEBUGCTL MSR value in VMCS
568 //
569 g_Callbacks.VmFuncSetDebugctl(DbgCtlMsr);
570 }
571}

◆ LbrStart()

BOOLEAN LbrStart ( UINT64 FilterOptions)

Start collecting LBR branches.

Parameters
FilterOptionsA bitmask of filter options to apply to the LBR branches (e.g., filtering by branch type, privilege level, etc.)
Returns
BOOLEAN
904{
905 BOOLEAN IsOnVmxRootMode;
906 IA32_LBR_CTL_REGISTER Ia32LbrCtl = {0};
907 ULONGLONG DbgCtlMsr = 0;
908
909 if (g_LbrCapacity == 0)
910 {
911 LogInfo("Err, LBR aborting, CPU model not supported\n");
912 return FALSE;
913 }
914
915 //
916 // Adjust and set filter options
917 //
918 LbrAdjustFilterOptions(FilterOptions, &Ia32LbrCtl);
919
920 //
921 // Clear hardware state before enabling LBR
922 //
924
926 {
927 IsOnVmxRootMode = g_Callbacks.VmFuncVmxGetCurrentExecutionMode();
928
929 //
930 // DEBUGCTL is not involved in ARCH LBR - it has its own dedicated control register
931 // So for ARCH LBR we skip reading the previous value and build the register from scratch (replacing it)
932 //
934 {
935 if (IsOnVmxRootMode)
936 {
937 LbrGetValuesOnVmxRootMode(&DbgCtlMsr, &Ia32LbrCtl);
938 }
939 else
940 {
941 LbrGetValuesOnVmxNonRootMode(&DbgCtlMsr, &Ia32LbrCtl);
942 }
943 }
944
945 //
946 // Apply the appropriate bit to enable LBR based on whether it is architectural LBR or legacy LBR
947 //
949 {
950 LbrEnableArchBased(&Ia32LbrCtl);
951 }
952 else
953 {
954 LbrEnableLegacyBased(&DbgCtlMsr);
955 }
956
957 //
958 // Write the updated LBR control register values back based on the current VMX execution mode
959 //
960 if (IsOnVmxRootMode)
961 {
962 LbrSetValuesOnVmxRootMode(DbgCtlMsr, Ia32LbrCtl);
963 }
964 else
965 {
966 LbrSetValuesOnVmxNonRootMode(DbgCtlMsr, Ia32LbrCtl);
967 }
968 }
969 else
970 {
971 LbrStartOnNativeMode(Ia32LbrCtl);
972 }
973
974 return TRUE;
975}
VOID LbrGetValuesOnVmxNonRootMode(ULONGLONG *DbgCtlMsr, IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
Read current LBR control register values while in VMX non-root mode (via VMCALL).
Definition Lbr.c:505
VOID LbrStartOnNativeMode(IA32_LBR_CTL_REGISTER Ia32LbrCtl)
Start LBR collection when running natively (outside any hypervisor environment).
Definition Lbr.c:451
VOID LbrAdjustFilterOptions(UINT64 FilterOptions, IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
Adjust filter options.
Definition Lbr.c:770
VOID LbrEnableArchBased(IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
Enable LBR collection on architectural (ARCH) based LBR.
Definition Lbr.c:422
VOID LbrSetValuesOnVmxRootMode(ULONGLONG DbgCtlMsr, IA32_LBR_CTL_REGISTER Ia32LbrCtl)
Write back modified LBR control register values while in VMX root-mode.
Definition Lbr.c:555
VOID LbrSetValuesOnVmxNonRootMode(ULONGLONG DbgCtlMsr, IA32_LBR_CTL_REGISTER Ia32LbrCtl)
Write back modified LBR control register values while in VMX non-root mode (via VMCALL).
Definition Lbr.c:581
VOID LbrGetValuesOnVmxRootMode(ULONGLONG *DbgCtlMsr, IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
Read current LBR control register values while in VMX root-mode.
Definition Lbr.c:479
VOID LbrEnableLegacyBased(ULONGLONG *DbgCtlMsr)
Enable LBR collection on legacy based LBR.
Definition Lbr.c:434
#define LogInfo(format,...)
Define log variables.
Definition HyperDbgHyperLogIntrinsics.h:71

◆ LbrStartOnNativeMode()

VOID LbrStartOnNativeMode ( IA32_LBR_CTL_REGISTER Ia32LbrCtl)

Start LBR collection when running natively (outside any hypervisor environment).

Parameters
Ia32LbrCtlThe pre-built IA32_LBR_CTL_REGISTER value carrying the filter bits (arch LBR)
Returns
VOID
452{
453 ULONGLONG DbgCtlMsr = 0;
454
456 {
457 //
458 // No need to read the existing control since we are replacing it entirely for ARCH LBR
459 //
460 LbrEnableArchBased(&Ia32LbrCtl);
461 xwrmsr(IA32_LBR_CTL, Ia32LbrCtl.AsUInt);
462 }
463 else
464 {
465 xrdmsr(IA32_DEBUGCTL, &DbgCtlMsr);
466 LbrEnableLegacyBased(&DbgCtlMsr);
467 xwrmsr(IA32_DEBUGCTL, DbgCtlMsr);
468 }
469}

◆ LbrStop()

VOID LbrStop ( )

Stop collecting LBR branches.

Returns
VOID
984{
985 BOOLEAN IsOnVmxRootMode;
986 ULONGLONG DbgCtlMsr = NULL64_ZERO;
987 IA32_LBR_CTL_REGISTER Ia32LbrCtl = {0};
988
990 {
991 IsOnVmxRootMode = g_Callbacks.VmFuncVmxGetCurrentExecutionMode();
992
993 //
994 // Read the current LBR control register values based on the current VMX execution mode
995 //
996 if (IsOnVmxRootMode)
997 {
998 LbrGetValuesOnVmxRootMode(&DbgCtlMsr, &Ia32LbrCtl);
999 }
1000 else
1001 {
1002 LbrGetValuesOnVmxNonRootMode(&DbgCtlMsr, &Ia32LbrCtl);
1003 }
1004
1005 //
1006 // Apply the appropriate bit to disable LBR based on whether it is architectural LBR or legacy LBR
1007 //
1009 {
1010 LbrDisableArchBased(&Ia32LbrCtl);
1011 }
1012 else
1013 {
1014 LbrDisableLegacyBased(&DbgCtlMsr);
1015 }
1016
1017 //
1018 // Write the updated LBR control register values back based on the current VMX execution mode
1019 //
1020 if (IsOnVmxRootMode)
1021 {
1022 LbrSetValuesOnVmxRootMode(DbgCtlMsr, Ia32LbrCtl);
1023 }
1024 else
1025 {
1026 LbrSetValuesOnVmxNonRootMode(DbgCtlMsr, Ia32LbrCtl);
1027 }
1028 }
1029 else
1030 {
1032 }
1033}
VOID LbrDisableArchBased(IA32_LBR_CTL_REGISTER *Ia32LbrCtl)
Disable LBR collection on architectural (ARCH) based LBR.
Definition Lbr.c:530
VOID LbrStopOnNativeMode()
Stop LBR collection when running natively (outside any hypervisor environment).
Definition Lbr.c:605
VOID LbrDisableLegacyBased(ULONGLONG *DbgCtlMsr)
Disable LBR collection on legacy based LBR.
Definition Lbr.c:542
#define NULL64_ZERO
Definition BasicTypes.h:111

◆ LbrStopOnNativeMode()

VOID LbrStopOnNativeMode ( )

Stop LBR collection when running natively (outside any hypervisor environment).

Returns
VOID
606{
607 ULONGLONG DbgCtlMsr = NULL64_ZERO;
608 IA32_LBR_CTL_REGISTER Ia32LbrCtl = {0};
609
611 {
612 xrdmsr(IA32_LBR_CTL, &Ia32LbrCtl.AsUInt);
613 LbrDisableArchBased(&Ia32LbrCtl);
614 xwrmsr(IA32_LBR_CTL, Ia32LbrCtl);
615 }
616 else
617 {
618 xrdmsr(IA32_DEBUGCTL, &DbgCtlMsr);
619 LbrDisableLegacyBased(&DbgCtlMsr);
620 xwrmsr(IA32_DEBUGCTL, DbgCtlMsr);
621 }
622}

Variable Documentation

◆ CPU_LBR_MAPS

CPU_LBR_MAP CPU_LBR_MAPS[]

The global variable to hold the mapping of CPU model to its LBR capacity.

21 {
22 {0x5c, 32},
23 {0x5f, 32},
24 {0x4e, 32},
25 {0x5e, 32},
26 {0x8e, 32},
27 {0x9e, 32},
28 {0x55, 32},
29 {0x66, 32},
30 {0x7a, 32},
31 {0x67, 32},
32 {0x6a, 32},
33 {0x6c, 32},
34 {0x7d, 32},
35 {0x7e, 32},
36 {0x8c, 32},
37 {0x8d, 32},
38 {0xa5, 32},
39 {0xa6, 32},
40 {0xa7, 32},
41 {0xa8, 32},
42 {0x86, 32},
43 {0x8a, 32},
44 {0x96, 32},
45 {0x9c, 32},
46 {0x3d, 16},
47 {0x47, 16},
48 {0x4f, 16},
49 {0x56, 16},
50 {0x3c, 16},
51 {0x45, 16},
52 {0x46, 16},
53 {0x3f, 16},
54 {0x2a, 16},
55 {0x2d, 16},
56 {0x3a, 16},
57 {0x3e, 16},
58 {0x1a, 16},
59 {0x1e, 16},
60 {0x1f, 16},
61 {0x2e, 16},
62 {0x25, 16},
63 {0x2c, 16},
64 {0x2f, 16},
65 {0x17, 4},
66 {0x1d, 4},
67 {0x0f, 4},
68 {0x37, 8},
69 {0x4a, 8},
70 {0x4c, 8},
71 {0x4d, 8},
72 {0x5a, 8},
73 {0x5d, 8},
74 {0x1c, 8},
75 {0x26, 8},
76 {0x27, 8},
77 {0x35, 8},
78 {0x36, 8}};