HyperDbg Debugger
Loading...
Searching...
No Matches
lbr.cpp File Reference

!lbr command More...

#include "pch.h"

Functions

VOID CommandLbrHelp ()
 help of the !lbr command
BOOLEAN CommandLbrSendRequest (HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
 Send LBR requests.
BOOLEAN HyperDbgPerformLbrOperation (HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
 Request to perform an LBR operation.
BOOLEAN CommandLbrParseSimpleOperation (vector< CommandToken > CommandTokens, HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
 Parses simple (no-argument) LBR operations: enable, disable, flush.
BOOLEAN CommandLbrValidateCallStackFilterOptions (HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
 Check validity of the filter options in case of call_stack mode.
BOOLEAN CommandLbrParseFilterOperation (vector< CommandToken > CommandTokens, HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
 Parses the LBR filter operation and accumulates filter option flags.
VOID CommandLbrShowSuccessMessage (const HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
 Displays the success message appropriate for the completed LBR operation.
VOID CommandLbr (vector< CommandToken > CommandTokens, string Command)
 !lbr command handler

Variables

HANDLE g_DeviceHandle
 Holds the global handle of device which is used to send the request to the kernel by IOCTL, this handle is not used for IRP Pending of message tracing this handle is used in KD VMM.
BOOLEAN g_IsHyperTraceModuleLoaded
 shows whether the HyperTrace module is loaded or not

Detailed Description

!lbr command

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.19
Date
2026-04-05

Function Documentation

◆ CommandLbr()

VOID CommandLbr ( vector< CommandToken > CommandTokens,
string Command )

!lbr command handler

Parameters
CommandTokens
Command
Returns
VOID
330{
331 HYPERTRACE_LBR_OPERATION_PACKETS LbrRequest = {0};
332 BOOLEAN ParseResult = FALSE;
333
334 if (CommandTokens.size() == 1)
335 {
336 ShowMessages("incorrect use of the '%s'\n\n",
337 GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str());
339 return;
340 }
341
342 //
343 // Dispatch to the appropriate parser based on the subcommand
344 //
345 if (CompareLowerCaseStrings(CommandTokens.at(1), "enable") ||
346 CompareLowerCaseStrings(CommandTokens.at(1), "disable") ||
347 CompareLowerCaseStrings(CommandTokens.at(1), "flush"))
348 {
349 ParseResult = CommandLbrParseSimpleOperation(CommandTokens, &LbrRequest);
350 }
351 else if (CompareLowerCaseStrings(CommandTokens.at(1), "filter"))
352 {
353 ParseResult = CommandLbrParseFilterOperation(CommandTokens, &LbrRequest);
354 }
355 else
356 {
357 ParseResult = FALSE;
358 }
359
360 if (!ParseResult)
361 {
362 ShowMessages("incorrect use of the '%s'\n\n",
363 GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str());
365 return;
366 }
367
368 //
369 // Check if the HyperTrace module is loaded, as it is required for LBR operations
370 //
372
373 //
374 // Send the LBR operation request
375 //
376 if (CommandLbrSendRequest(&LbrRequest))
377 {
378 CommandLbrShowSuccessMessage(&LbrRequest);
379 }
380 else
381 {
382 ShowErrorMessage(LbrRequest.KernelStatus);
383 }
384}
UCHAR BOOLEAN
Definition BasicTypes.h:35
#define FALSE
Definition BasicTypes.h:113
struct _HYPERTRACE_LBR_OPERATION_PACKETS HYPERTRACE_LBR_OPERATION_PACKETS
The structure of HyperTrace LBR result packet in HyperDbg.
std::string GetCaseSensitiveStringFromCommandToken(CommandToken TargetToken)
Get case sensitive string from command token.
Definition common.cpp:467
BOOLEAN CompareLowerCaseStrings(CommandToken TargetToken, const CHAR *StringToCompare)
Compare lower case strings.
Definition common.cpp:503
BOOLEAN ShowErrorMessage(UINT32 Error)
shows the error message
Definition debugger.cpp:40
BOOLEAN CommandLbrSendRequest(HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
Send LBR requests.
Definition lbr.cpp:79
BOOLEAN CommandLbrParseSimpleOperation(vector< CommandToken > CommandTokens, HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
Parses simple (no-argument) LBR operations: enable, disable, flush.
Definition lbr.cpp:138
VOID CommandLbrHelp()
help of the !lbr command
Definition lbr.cpp:26
BOOLEAN CommandLbrParseFilterOperation(vector< CommandToken > CommandTokens, HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
Parses the LBR filter operation and accumulates filter option flags.
Definition lbr.cpp:200
VOID CommandLbrShowSuccessMessage(const HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
Displays the success message appropriate for the completed LBR operation.
Definition lbr.cpp:298
#define ASSERT_MESSAGE_HYPERTRACE_NOT_LOADED
Definition common.h:33
#define AssertShowMessageReturnStmt(expr1, expr2, message1, message2, rc)
Definition common.h:59
#define AssertReturn
Definition common.h:19
#define ASSERT_MESSAGE_DRIVER_NOT_LOADED
Definition common.h:27
HANDLE g_DeviceHandle
Holds the global handle of device which is used to send the request to the kernel by IOCTL,...
Definition globals.h:481
BOOLEAN g_IsHyperTraceModuleLoaded
shows whether the HyperTrace module is loaded or not
Definition lbrdump.cpp:19
UINT32 KernelStatus
Definition RequestStructures.h:1305

◆ CommandLbrHelp()

VOID CommandLbrHelp ( )

help of the !lbr command

Returns
VOID
27{
28 ShowMessages("!lbr : performs operation for Last Branch Record (LBR).\n");
29 ShowMessages("for dumping LBR entries, you can use the '!lbrdump' command\n");
30
31 ShowMessages("syntax : \t!lbr [Function (string)]\n");
32 ShowMessages("syntax : \t!lbr [filter FilterOptions (string)]\n");
33
34 ShowMessages("\n");
35 ShowMessages("\t\te.g : !lbr enable\n");
36 ShowMessages("\t\te.g : !lbr disable\n");
37 ShowMessages("\t\te.g : !lbr flush\n");
38
39 ShowMessages("\n");
40 ShowMessages("\t\te.g : !lbr filter\n");
41 ShowMessages("\t\te.g : !lbr filter kernel jcc ind_jmp rel_jmp far\n");
42 ShowMessages("\t\te.g : !lbr filter kernel jcc return ind_jmp rel_jmp far\n");
43 ShowMessages("\t\te.g : !lbr filter kernel jcc ind_jmp rel_jmp\n");
44 ShowMessages("\t\te.g : !lbr filter user rel_call ind_call return far\n");
45 ShowMessages("\t\te.g : !lbr filter call_stack user\n");
46 ShowMessages("\t\te.g : !lbr filter call_stack kernel\n");
47
48 ShowMessages("\nlist of filter options: \n");
49 ShowMessages("\t kernel: do not capture at ring0\n");
50 ShowMessages("\t user: do not capture at ring > 0\n");
51 ShowMessages("\t jcc: do not capture conditional branches\n");
52 ShowMessages("\t rel_call: do not capture relative calls\n");
53 ShowMessages("\t ind_call: do not capture indirect calls\n");
54 ShowMessages("\t return: do not capture near returns\n");
55 ShowMessages("\t ind_jmp: do not capture indirect jumps\n");
56 ShowMessages("\t rel_jmp: do not capture relative jumps\n");
57 ShowMessages("\t far: do not capture far branches (only in legacy LBR. check docs for details)\n");
58 ShowMessages("\t other_branches: do not capture jmp/call ptr*, jmp/call m*, ret (0c8h), sys*, interrupts,\n");
59 ShowMessages("\t exceptions (other than debug exceptions), iret, int3, intn, into, tsx abort\n");
60 ShowMessages("\t eenter, eresume, eexit, aex, init, sipi, rsm (only in ARCH LBR. check docs for details)\n");
61 ShowMessages("\t call_stack: enable LBR stack to use LIFO filtering to capture call stack profile\n");
62 ShowMessages("\t not available on CPUs older than Haswell. for this item you can only specify the 'user'\n");
63 ShowMessages("\t or the 'kernel'. it prevents all types of branches except calls and rets\n");
64 ShowMessages("\t (no option): capture everything (default option)\n");
65
66 ShowMessages("\nnote 1: LBR is usually not supported (or is emulated) in nested virtualization (VM) environments\n");
67 ShowMessages("note 2: LBR will be disabled if there is a debug-break (#DB) condition, such as the trap flags or\n");
68 ShowMessages(" hardware debug registers (to learn how to mitigate this, check the documentation)\n");
69}

◆ CommandLbrParseFilterOperation()

BOOLEAN CommandLbrParseFilterOperation ( vector< CommandToken > CommandTokens,
HYPERTRACE_LBR_OPERATION_PACKETS * LbrRequest )

Parses the LBR filter operation and accumulates filter option flags.

Parameters
CommandTokens
LbrRequest
Returns
BOOLEAN TRUE if parsed successfully
201{
203 LbrRequest->LbrFilterOptions = 0; // no options = capture everything
204
205 for (SIZE_T i = 2; i < CommandTokens.size(); i++)
206 {
207 if (CompareLowerCaseStrings(CommandTokens.at(i), "kernel"))
208 {
209 LbrRequest->LbrFilterOptions |= LBR_KERNEL;
210 }
211 else if (CompareLowerCaseStrings(CommandTokens.at(i), "user"))
212 {
213 LbrRequest->LbrFilterOptions |= LBR_USER;
214 }
215 else if (CompareLowerCaseStrings(CommandTokens.at(i), "jcc"))
216 {
217 LbrRequest->LbrFilterOptions |= LBR_JCC;
218 }
219 else if (CompareLowerCaseStrings(CommandTokens.at(i), "rel_call"))
220 {
221 LbrRequest->LbrFilterOptions |= LBR_REL_CALL;
222 }
223 else if (CompareLowerCaseStrings(CommandTokens.at(i), "ind_call"))
224 {
225 LbrRequest->LbrFilterOptions |= LBR_IND_CALL;
226 }
227 else if (CompareLowerCaseStrings(CommandTokens.at(i), "return"))
228 {
229 LbrRequest->LbrFilterOptions |= LBR_RETURN;
230 }
231 else if (CompareLowerCaseStrings(CommandTokens.at(i), "ind_jmp"))
232 {
233 LbrRequest->LbrFilterOptions |= LBR_IND_JMP;
234 }
235 else if (CompareLowerCaseStrings(CommandTokens.at(i), "rel_jmp"))
236 {
237 LbrRequest->LbrFilterOptions |= LBR_REL_JMP;
238 }
239 else if (CompareLowerCaseStrings(CommandTokens.at(i), "far") ||
240 CompareLowerCaseStrings(CommandTokens.at(i), "other_branch") ||
241 CompareLowerCaseStrings(CommandTokens.at(i), "other_branches"))
242 {
244 }
245 else if (CompareLowerCaseStrings(CommandTokens.at(i), "call_stack"))
246 {
247 LbrRequest->LbrFilterOptions |= LBR_CALL_STACK;
248 }
249 else
250 {
251 ShowMessages("unknown filter option '%s'\n\n",
252 GetCaseSensitiveStringFromCommandToken(CommandTokens.at(i)).c_str());
253 return FALSE;
254 }
255 }
256
257 //
258 // Call-stack mode should be used with branch type enabling configured to capture only CALLs (NEAR_REL_CALL and
259 // NEAR_IND_CALL) and RETs (NEAR_RET). When configured in this manner, the LBR array emulates a call stack,
260 // where CALLs are "pushed" and RETs "pop" them off the stack. If other branch types (JCC, NEAR_*_JMP, or
261 // OTHER_BRANCH) are enabled for recording with call-stack mode, LBR behavior may be undefined, so we will
262 // mask out any branch type filters that are not CALLs or RETs when call-stack mode is requested to ensure
263 // we are correctly emulating a call stack and avoiding undefined behavior
264 //
265
266 //
267 // If it is call_stack then we only keep the user and kernel bit and filter all branch types
268 // except calls and rets to ensure we are only capturing call stack profile
269 //
270 if (LbrRequest->LbrFilterOptions & LBR_CALL_STACK)
271 {
272 //
273 // Validate the filter options in case of call_stack mode
274 //
276 {
277 return FALSE;
278 }
279
280 //
281 // Preserve only the user/kernel privilege bits from the original options,
282 // then apply the mandatory call stack base flags
283 //
285 }
286
287 return TRUE;
288}
#define TRUE
Definition BasicTypes.h:114
#define LBR_FAR_OTHER_BRANCHES
Definition LbrDefinitions.h:58
#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_RETURN
Definition LbrDefinitions.h:55
#define LBR_IND_CALL
Definition LbrDefinitions.h:54
#define LBR_REL_JMP
Definition LbrDefinitions.h:57
#define LBR_USER
Definition LbrDefinitions.h:51
#define LBR_JCC
Definition LbrDefinitions.h:52
#define LBR_IND_JMP
Definition LbrDefinitions.h:56
#define LBR_KERNEL
Definition LbrDefinitions.h:50
#define LBR_REL_CALL
Definition LbrDefinitions.h:53
@ HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_FILTER
Definition RequestStructures.h:1290
BOOLEAN CommandLbrValidateCallStackFilterOptions(HYPERTRACE_LBR_OPERATION_PACKETS *LbrRequest)
Check validity of the filter options in case of call_stack mode.
Definition lbr.cpp:172
UINT32 LbrFilterOptions
Definition RequestStructures.h:1304
HYPERTRACE_LBR_OPERATION_REQUEST_TYPE LbrOperationType
Definition RequestStructures.h:1303

◆ CommandLbrParseSimpleOperation()

BOOLEAN CommandLbrParseSimpleOperation ( vector< CommandToken > CommandTokens,
HYPERTRACE_LBR_OPERATION_PACKETS * LbrRequest )

Parses simple (no-argument) LBR operations: enable, disable, flush.

Parameters
CommandTokens
LbrRequest
Returns
BOOLEAN TRUE if parsed successfully
139{
140 if (CommandTokens.size() != 2)
141 {
142 return FALSE;
143 }
144
145 if (CompareLowerCaseStrings(CommandTokens.at(1), "enable"))
146 {
148 }
149 else if (CompareLowerCaseStrings(CommandTokens.at(1), "disable"))
150 {
152 }
153 else if (CompareLowerCaseStrings(CommandTokens.at(1), "flush"))
154 {
156 }
157 else
158 {
159 return FALSE;
160 }
161
162 return TRUE;
163}
@ HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_FLUSH
Definition RequestStructures.h:1288
@ HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_DISABLE
Definition RequestStructures.h:1287
@ HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_ENABLE
Definition RequestStructures.h:1286

◆ CommandLbrSendRequest()

BOOLEAN CommandLbrSendRequest ( HYPERTRACE_LBR_OPERATION_PACKETS * LbrRequest)

Send LBR requests.

Parameters
LbrRequest
Returns
VOID
80{
81 BOOL Status;
82 ULONG ReturnedLength;
83
85
86 //
87 // Send IOCTL
88 //
89 Status = DeviceIoControl(
90 g_DeviceHandle, // Handle to device
91 IOCTL_PERFORM_HYPERTRACE_LBR_OPERATION, // IO Control Code (IOCTL)
92 LbrRequest, // Input Buffer to driver.
93 SIZEOF_HYPERTRACE_LBR_OPERATION_PACKETS, // Input buffer length
94 LbrRequest, // Output Buffer from driver.
95 SIZEOF_HYPERTRACE_LBR_OPERATION_PACKETS, // Length of output buffer in bytes.
96 &ReturnedLength, // Bytes placed in buffer.
97 NULL // synchronous call
98 );
99
100 if (!Status)
101 {
102 ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
103
104 return FALSE;
105 }
106
108 {
109 return TRUE;
110 }
111 else
112 {
113 return FALSE;
114 }
115}
int BOOL
Definition BasicTypes.h:25
unsigned long ULONG
Definition BasicTypes.h:31
#define DEBUGGER_OPERATION_WAS_SUCCESSFUL
General value to indicate that the operation or request was successful.
Definition ErrorCodes.h:23
#define IOCTL_PERFORM_HYPERTRACE_LBR_OPERATION
ioctl, to perform HyperTrace LBR operations
Definition Ioctls.h:407
#define SIZEOF_HYPERTRACE_LBR_OPERATION_PACKETS
Debugger size of HYPERTRACE_LBR_OPERATION_PACKETS.
Definition RequestStructures.h:1313
#define AssertReturnFalse
Definition common.h:21

◆ CommandLbrShowSuccessMessage()

VOID CommandLbrShowSuccessMessage ( const HYPERTRACE_LBR_OPERATION_PACKETS * LbrRequest)

Displays the success message appropriate for the completed LBR operation.

Parameters
LbrRequest
Returns
VOID
299{
300 switch (LbrRequest->LbrOperationType)
301 {
303 ShowMessages("LBR enabled successfully\n");
304 break;
306 ShowMessages("LBR disabled successfully\n");
307 break;
309 ShowMessages("LBR branches are flushed\n");
310 break;
312 ShowMessages("LBR filter options are updated successfully\n");
313 break;
314 default:
315 ShowMessages("unknown LBR operation type\n");
316 break;
317 }
318}

◆ CommandLbrValidateCallStackFilterOptions()

BOOLEAN CommandLbrValidateCallStackFilterOptions ( HYPERTRACE_LBR_OPERATION_PACKETS * LbrRequest)

Check validity of the filter options in case of call_stack mode.

Parameters
LbrRequest
Returns
BOOLEAN TRUE if the filter options are valid in case of call_stack mode
173{
174 if (LbrRequest->LbrFilterOptions & LBR_CALL_STACK)
175 {
176 //
177 // Call-stack mode should be used with branch type enabling configured to capture only CALLs (NEAR_REL_CALL and
178 // NEAR_IND_CALL) and RETs (NEAR_RET). if the user specifed LBR_REL_CALL | LBR_IND_CALL | LBR_RETURN then
179 // it is invalid
180 //
181 if ((LbrRequest->LbrFilterOptions & (LBR_REL_CALL | LBR_IND_CALL | LBR_RETURN)))
182 {
183 ShowMessages("err, invalid filter options for 'call_stack' mode. when the 'call_stack' is enabled,"
184 " 'rel_call', 'ind_call', and 'return' could not be specified as filter options\n\n");
185 return FALSE;
186 }
187 }
188 return TRUE;
189}

◆ HyperDbgPerformLbrOperation()

BOOLEAN HyperDbgPerformLbrOperation ( HYPERTRACE_LBR_OPERATION_PACKETS * LbrRequest)

Request to perform an LBR operation.

Parameters
LbrRequest
Returns
BOOLEAN
126{
127 return CommandLbrSendRequest(LbrRequest);
128}

Variable Documentation

◆ g_DeviceHandle

HANDLE g_DeviceHandle
extern

Holds the global handle of device which is used to send the request to the kernel by IOCTL, this handle is not used for IRP Pending of message tracing this handle is used in KD VMM.

◆ g_IsHyperTraceModuleLoaded

BOOLEAN g_IsHyperTraceModuleLoaded
extern

shows whether the HyperTrace module is loaded or not