Merge pull request #577 from HyperDbg/LBR

Lbr
This commit is contained in:
Sina Karvandi 2026-04-24 20:05:28 +02:00 committed by GitHub
commit 512e7fe290
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 1086 additions and 1488 deletions

View file

@ -45,6 +45,6 @@ object ScriptConstantTypes {
object ScriptEvalFunc {
object ScriptOperators extends ChiselEnum {
val sFuncUndefined, sFuncInc, sFuncDec, sFuncReference, sFuncOr, sFuncXor, sFuncAnd, sFuncAsr, sFuncAsl, sFuncAdd, sFuncSub, sFuncMul, sFuncDiv, sFuncMod, sFuncGt, sFuncLt, sFuncEgt, sFuncElt, sFuncEqual, sFuncNeq, sFuncJmp, sFuncJz, sFuncJnz, sFuncMov, sFuncStart_of_do_while, sFuncStart_of_do_while_commands, sFuncEnd_of_do_while, sFuncStart_of_for, sFuncFor_inc_dec, sFuncStart_of_for_ommands, sFuncEnd_of_if, sFuncIgnore_lvalue, sFuncPush, sFuncPop, sFuncCall, sFuncRet, sFuncPrint, sFuncFormats, sFuncEvent_enable, sFuncEvent_disable, sFuncEvent_clear, sFuncTest_statement, sFuncSpinlock_lock, sFuncSpinlock_unlock, sFuncEvent_sc, sFuncMicrosleep, sFuncPrintf, sFuncPause, sFuncFlush, sFuncEvent_trace_step, sFuncEvent_trace_step_in, sFuncEvent_trace_step_out, sFuncEvent_trace_instrumentation_step, sFuncEvent_trace_instrumentation_step_in, sFuncLbr_start, sFuncLbr_stop, sFuncRdtsc, sFuncRdtscp, sFuncSpinlock_lock_custom_wait, sFuncEvent_inject, sFuncPoi, sFuncDb, sFuncDd, sFuncDw, sFuncDq, sFuncNeg, sFuncHi, sFuncLow, sFuncNot, sFuncCheck_address, sFuncDisassemble_len, sFuncDisassemble_len32, sFuncDisassemble_len64, sFuncInterlocked_increment, sFuncInterlocked_decrement, sFuncPhysical_to_virtual, sFuncVirtual_to_physical, sFuncPoi_pa, sFuncHi_pa, sFuncLow_pa, sFuncDb_pa, sFuncDd_pa, sFuncDw_pa, sFuncDq_pa, sFuncEd, sFuncEb, sFuncEq, sFuncInterlocked_exchange, sFuncInterlocked_exchange_add, sFuncEb_pa, sFuncEd_pa, sFuncEq_pa, sFuncInterlocked_compare_exchange, sFuncStrlen, sFuncStrcmp, sFuncMemcmp, sFuncStrncmp, sFuncWcslen, sFuncWcscmp, sFuncEvent_inject_error_code, sFuncMemcpy, sFuncMemcpy_pa, sFuncWcsncmp = Value
val sFuncUndefined, sFuncInc, sFuncDec, sFuncReference, sFuncOr, sFuncXor, sFuncAnd, sFuncAsr, sFuncAsl, sFuncAdd, sFuncSub, sFuncMul, sFuncDiv, sFuncMod, sFuncGt, sFuncLt, sFuncEgt, sFuncElt, sFuncEqual, sFuncNeq, sFuncJmp, sFuncJz, sFuncJnz, sFuncMov, sFuncStart_of_do_while, sFuncStart_of_do_while_commands, sFuncEnd_of_do_while, sFuncStart_of_for, sFuncFor_inc_dec, sFuncStart_of_for_ommands, sFuncEnd_of_if, sFuncIgnore_lvalue, sFuncPush, sFuncPop, sFuncCall, sFuncRet, sFuncPrint, sFuncFormats, sFuncEvent_enable, sFuncEvent_disable, sFuncEvent_clear, sFuncTest_statement, sFuncSpinlock_lock, sFuncSpinlock_unlock, sFuncEvent_sc, sFuncMicrosleep, sFuncPrintf, sFuncPause, sFuncFlush, sFuncEvent_trace_step, sFuncEvent_trace_step_in, sFuncEvent_trace_step_out, sFuncEvent_trace_instrumentation_step, sFuncEvent_trace_instrumentation_step_in, sFuncRdtsc, sFuncRdtscp, sFuncLbr_save, sFuncLbr_dump, sFuncSpinlock_lock_custom_wait, sFuncEvent_inject, sFuncPoi, sFuncDb, sFuncDd, sFuncDw, sFuncDq, sFuncNeg, sFuncHi, sFuncLow, sFuncNot, sFuncCheck_address, sFuncDisassemble_len, sFuncDisassemble_len32, sFuncDisassemble_len64, sFuncInterlocked_increment, sFuncInterlocked_decrement, sFuncPhysical_to_virtual, sFuncVirtual_to_physical, sFuncPoi_pa, sFuncHi_pa, sFuncLow_pa, sFuncDb_pa, sFuncDd_pa, sFuncDw_pa, sFuncDq_pa, sFuncEd, sFuncEb, sFuncEq, sFuncInterlocked_exchange, sFuncInterlocked_exchange_add, sFuncEb_pa, sFuncEd_pa, sFuncEq_pa, sFuncInterlocked_compare_exchange, sFuncStrlen, sFuncStrcmp, sFuncMemcmp, sFuncStrncmp, sFuncWcslen, sFuncWcscmp, sFuncEvent_inject_error_code, sFuncMemcpy, sFuncMemcpy_pa, sFuncWcsncmp = Value
}
}

View file

@ -1500,8 +1500,8 @@ HvGetAndStoreDebugctl(UINT64 * StoreDebugctl)
VOID
HvSetDebugctl(UINT64 Value)
{
VmxVmwrite64(VMCS_GUEST_DEBUGCTL, Value & 0xFFFFFFFF);
VmxVmwrite64(VMCS_GUEST_DEBUGCTL_HIGH, Value >> 32);
VmxVmwrite32(VMCS_GUEST_DEBUGCTL, Value & 0xFFFFFFFF);
VmxVmwrite32(VMCS_GUEST_DEBUGCTL_HIGH, Value >> 32);
}
/**

View file

@ -1286,7 +1286,7 @@ DrvDispatchIoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
//
// Perform the HyperTrace operation
//
HyperTracePerformOperation(HyperTraceOperationRequest, FALSE);
HyperTracePerformOperation(HyperTraceOperationRequest, TRUE);
Irp->IoStatus.Information = SIZEOF_HYPERTRACE_OPERATION_PACKETS;
Status = STATUS_SUCCESS;

View file

@ -23,19 +23,9 @@
BOOLEAN
DpcRoutineEnableLbr(KDPC * Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
LBR_IOCTL_REQUEST * CurrentRequest;
ULONG CurrentCore;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(DeferredContext);
CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
//
// Get the current request (for current core)
//
CurrentRequest = &g_LbrRequestState[CurrentCore];
//
// Check if the initialization is being done for hypervisor environment or not
// If it is, then we need to perform some additional steps to enable LBR in VMX
@ -53,8 +43,7 @@ DpcRoutineEnableLbr(KDPC * Dpc, PVOID DeferredContext, PVOID SystemArgument1, PV
//
// Enable LBR on all cores from VMX-root mode by VMCALL
//
// LbrStartLbr(CurrentRequest, TRUE, TRUE);
HyperTraceExamplePerformLbrTrace(TRUE, TRUE);
LbrStartLbr(TRUE, TRUE);
//
// Wait for all DPCs to synchronize at this point
@ -81,18 +70,13 @@ DpcRoutineEnableLbr(KDPC * Dpc, PVOID DeferredContext, PVOID SystemArgument1, PV
BOOLEAN
DpcRoutineDisableLbr(KDPC * Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
LBR_IOCTL_REQUEST * CurrentRequest;
ULONG CurrentCore;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(DeferredContext);
CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
//
// Get the current request (for current core)
// Disable LBR on all cores from VMX-root mode by VMCALL
//
CurrentRequest = &g_LbrRequestState[CurrentCore];
LbrStopLbr(TRUE, TRUE);
//
// Check if the initialization is being done for hypervisor environment or not
@ -108,11 +92,6 @@ DpcRoutineDisableLbr(KDPC * Dpc, PVOID DeferredContext, PVOID SystemArgument1, P
g_Callbacks.VmFuncSetLoadDebugControlsVmcallOnTargetCore(FALSE);
}
//
// Disable LBR on all cores from VMX-root mode by VMCALL
//
LbrStopLbr(CurrentRequest, TRUE, TRUE);
//
// Wait for all DPCs to synchronize at this point
//

View file

@ -14,9 +14,7 @@
// Global Definitions //
//////////////////////////////////////////////////
ULONGLONG LbrCapacity = 0;
LIST_ENTRY LbrStateHead;
KSPIN_LOCK LbrStateLock;
ULONGLONG LbrCapacity = 0;
//
// Typical Intel LBR capacities based on CPU model
@ -82,96 +80,70 @@ CPU_LBR_MAP CPU_LBR_MAPS[] = {
{0x36, 8}};
/**
* @brief Initialize LBR state list and spinlock
*
* @param State
* @return VOID
*/
VOID
LbrInitialize()
{
InitializeListHead(&LbrStateHead);
KeInitializeSpinLock(&LbrStateLock);
}
/**
* @brief Read LBR MSRs and store the values in the provided LBR_STATE structure
*
* @param State
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
* @brief Flush LBR MSRs by disabling LBR and clearing all LBR entries
*
* @return VOID
*/
VOID
LbrGetLbr(LBR_STATE * State, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
LbrFlushLbr()
{
ULONG i;
ULONGLONG DbgCtlMsr;
KIRQL OldIrql;
if (ApplyFromVmxRootMode)
{
if (ApplyByVmcall)
{
DbgCtlMsr = g_Callbacks.VmFuncGetDebugctlVmcallOnTargetCore();
}
else
{
DbgCtlMsr = g_Callbacks.VmFuncGetDebugctl();
}
xlock_core(&OldIrql);
DbgCtlMsr &= ~DEBUGCTLMSR_LBR;
//
// Disable LBR
//
LogInfo("Flush LBR on cpu core: %d\n", xcoreid());
if (ApplyByVmcall)
{
g_Callbacks.VmFuncSetDebugctlVmcallOnTargetCore(DbgCtlMsr);
}
else
{
g_Callbacks.VmFuncSetDebugctl(DbgCtlMsr);
}
}
else
xrdmsr(MSR_IA32_DEBUGCTLMSR, &DbgCtlMsr);
DbgCtlMsr &= ~DEBUGCTLMSR_LBR;
xwrmsr(MSR_IA32_DEBUGCTLMSR, DbgCtlMsr);
//
// Flush LBR registers
//
xwrmsr(MSR_LBR_SELECT, 0);
xwrmsr(MSR_LBR_TOS, 0);
for (i = 0; i < LbrCapacity; i++)
{
xrdmsr(MSR_IA32_DEBUGCTLMSR, &DbgCtlMsr);
DbgCtlMsr &= ~DEBUGCTLMSR_LBR;
xwrmsr(MSR_IA32_DEBUGCTLMSR, DbgCtlMsr);
xwrmsr(MSR_LBR_NHM_FROM + i, 0);
xwrmsr(MSR_LBR_NHM_TO + i, 0);
}
xacquire_lock(&LbrStateLock, &OldIrql);
xrdmsr(MSR_LBR_SELECT, &State->Config.LbrSelect);
xrdmsr(MSR_LBR_TOS, &State->Data->LbrTos);
for (i = 0; i < (ULONG)LbrCapacity; i++)
{
xrdmsr(MSR_LBR_NHM_FROM + i, &State->Data->Entries[i].From);
xrdmsr(MSR_LBR_NHM_TO + i, &State->Data->Entries[i].To);
}
xrelease_lock(&LbrStateLock, &OldIrql);
xrelease_core(&OldIrql);
}
/**
* @brief Write LBR MSRs from the provided LBR_STATE structure
* @brief Start collecting LBR branches
*
* @param State
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return VOID
* @return BOOLEAN
*/
VOID
LbrPutLbr(LBR_STATE * State, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
BOOLEAN
LbrStartLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
{
if (LbrCapacity == 0)
{
LogInfo("LBR: Aborting, CPU model not supported.\n");
return FALSE;
}
ULONGLONG DbgCtlMsr;
KIRQL OldIrql;
xacquire_lock(&LbrStateLock, &OldIrql);
//
// Force the selection mask
xwrmsr(MSR_LBR_SELECT, State->Config.LbrSelect);
//
xwrmsr(MSR_LBR_SELECT, LBR_SELECT);
//
// Clear hardware state
//
xwrmsr(MSR_LBR_TOS, 0);
for (ULONG i = 0; i < (ULONG)LbrCapacity; i++)
{
@ -179,8 +151,6 @@ LbrPutLbr(LBR_STATE * State, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall
xwrmsr(MSR_LBR_NHM_TO + i, 0);
}
xrelease_lock(&LbrStateLock, &OldIrql);
if (ApplyFromVmxRootMode)
{
if (ApplyByVmcall)
@ -215,475 +185,131 @@ LbrPutLbr(LBR_STATE * State, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall
DbgCtlMsr &= ~(1ULL << 11); // Bit 11 = 0
xwrmsr(MSR_IA32_DEBUGCTLMSR, DbgCtlMsr);
}
return TRUE;
}
/**
* @brief Flush LBR MSRs by disabling LBR and clearing all LBR entries
* @brief Save LBR branches
*
* @return VOID
*/
VOID
LbrFlushLbr()
LbrSaveLbr()
{
UINT64 LbrTos;
LBR_STACK_ENTRY * State;
UINT32 CurrentCore = 0;
//
// Get the current core id
//
CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
//
// Get the current processor LBR stack
//
State = &g_LbrStateList[CurrentCore];
//
// Read and store the current TOS index to know where the most recent branch is stored
//
xrdmsr(MSR_LBR_TOS, &LbrTos);
State->Tos = (UINT32)LbrTos;
//
// Dump LBR entries into the current core's state structure
//
for (ULONG i = 0; i < (ULONG)LbrCapacity; i++)
{
xrdmsr(MSR_LBR_NHM_FROM + i, &State->BranchEntry[i].From);
xrdmsr(MSR_LBR_NHM_TO + i, &State->BranchEntry[i].To);
}
}
/**
* @brief Stop collecting LBR branches
*
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return VOID
*/
VOID
LbrStopLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
{
ULONG i;
ULONGLONG DbgCtlMsr;
KIRQL OldIrql;
xlock_core(&OldIrql);
//
// Disable LBR
//
LogInfo("LIBIHT-COM: Flush LBR on cpu core: %d\n", xcoreid());
xrdmsr(MSR_IA32_DEBUGCTLMSR, &DbgCtlMsr);
DbgCtlMsr &= ~DEBUGCTLMSR_LBR;
xwrmsr(MSR_IA32_DEBUGCTLMSR, DbgCtlMsr);
//
// Flush LBR registers
//
xwrmsr(MSR_LBR_SELECT, 0);
xwrmsr(MSR_LBR_TOS, 0);
for (i = 0; i < LbrCapacity; i++)
if (ApplyFromVmxRootMode)
{
xwrmsr(MSR_LBR_NHM_FROM + i, 0);
xwrmsr(MSR_LBR_NHM_TO + i, 0);
if (ApplyByVmcall)
{
DbgCtlMsr = g_Callbacks.VmFuncGetDebugctlVmcallOnTargetCore();
}
else
{
DbgCtlMsr = g_Callbacks.VmFuncGetDebugctl();
}
DbgCtlMsr &= ~DEBUGCTLMSR_LBR;
if (ApplyByVmcall)
{
g_Callbacks.VmFuncSetDebugctlVmcallOnTargetCore(DbgCtlMsr);
}
else
{
g_Callbacks.VmFuncSetDebugctl(DbgCtlMsr);
}
}
else
{
xrdmsr(MSR_IA32_DEBUGCTLMSR, &DbgCtlMsr);
DbgCtlMsr &= ~DEBUGCTLMSR_LBR;
xwrmsr(MSR_IA32_DEBUGCTLMSR, DbgCtlMsr);
}
xrelease_core(&OldIrql);
//
// Save the LBR entries
//
LbrSaveLbr();
}
/**
* @brief Start collecting LBR branches for a specific process and store the configuration in the global LBR state list
* @brief Dump collected LBR branches
*
* @param Request
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return BOOLEAN
* @return VOID
*/
BOOLEAN
LbrStartLbr(LBR_IOCTL_REQUEST * Request, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
VOID
LbrDumpLbr()
{
LBR_STATE * State;
if (LbrCapacity == 0)
{
LogInfo("LBR: Aborting, CPU model not supported.\n");
return FALSE;
}
State = LbrFindLbrState(Request->LbrConfig.Pid);
if (State)
{
LogInfo("LIBIHT-COM: LBR already enabled for pid %d\n",
Request->LbrConfig.Pid);
return FALSE;
}
State = LbrCreateLbrState();
if (State == NULL)
{
LogInfo("LIBIHT-COM: Create LBR state failed\n");
return FALSE;
}
ULONG CurrentIdx;
LBR_STACK_ENTRY * State;
UINT32 CurrentCore = 0;
//
// Setup config fields for LBR state
// Get the current core id
//
State->Parent = NULL;
State->Config.Pid = Request->LbrConfig.Pid ? Request->LbrConfig.Pid : xgetcurrent_pid();
State->Config.LbrSelect = Request->LbrConfig.LbrSelect ? Request->LbrConfig.LbrSelect : LBR_SELECT;
LbrInsertLbrState(State);
CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
//
// If the requesting process is the current process, trace it right away
// Get the current processor LBR stack
//
if (State->Config.Pid == xgetcurrent_pid())
{
LbrPutLbr(State, ApplyFromVmxRootMode, ApplyByVmcall);
}
return TRUE;
}
/**
* @brief Stop collecting LBR branches for a specific process and remove the corresponding LBR state from the global list
*
* @param Request
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return BOOLEAN
*/
BOOLEAN
LbrStopLbr(LBR_IOCTL_REQUEST * Request, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
{
LBR_STATE * State;
State = LbrFindLbrState(Request->LbrConfig.Pid);
if (State == NULL)
{
LogInfo("LIBIHT-COM: LBR not enabled for pid %d\n",
Request->LbrConfig.Pid);
return FALSE;
}
if (State->Config.Pid == xgetcurrent_pid())
{
LbrGetLbr(State, ApplyFromVmxRootMode, ApplyByVmcall);
}
LbrRemoveLbrState(State);
return TRUE;
}
/**
* @brief Dump LBR info for a specific process to debug logs and optionally copy the LBR data to user buffer
*
* @param Request
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return BOOLEAN
*/
BOOLEAN
LbrDumpLbr(LBR_IOCTL_REQUEST * Request, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
{
UNREFERENCED_PARAMETER(ApplyFromVmxRootMode);
UNREFERENCED_PARAMETER(ApplyByVmcall);
LBR_STATE * State = LbrFindLbrState(Request->LbrConfig.Pid);
if (State == NULL)
return FALSE;
ULONG CurrentIdx;
State = &g_LbrStateList[CurrentCore];
LogInfo("LBR Chronological Trace\n");
for (ULONG i = 1; i <= LbrCapacity; i++)
{
CurrentIdx = (ULONG)(State->Data->LbrTos + i) % (ULONG)LbrCapacity;
CurrentIdx = (ULONG)(State->Tos + i) % (ULONG)LbrCapacity;
if (State->Data->Entries[CurrentIdx].From == 0)
continue;
// if (State->BranchEntry[CurrentIdx].From == 0)
// continue;
LogInfo("[%2u] FROM: 0x%llx TO: 0x%llx\n",
CurrentIdx,
State->Data->Entries[CurrentIdx].From,
State->Data->Entries[CurrentIdx].To);
}
return TRUE;
}
/**
* @brief Update LBR configuration for a specific process and optionally refresh the LBR MSRs if the current process is the owner
*
* @param Request
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return BOOLEAN
*/
BOOLEAN
LbrConfigLbr(LBR_IOCTL_REQUEST * Request, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
{
LBR_STATE * State;
State = LbrFindLbrState(Request->LbrConfig.Pid);
if (State == NULL)
{
LogInfo("LIBIHT-COM: LBR not enabled for pid %d\n",
Request->LbrConfig.Pid);
return FALSE;
}
if (State->Config.Pid == xgetcurrent_pid())
{
LbrGetLbr(State, ApplyFromVmxRootMode, ApplyByVmcall);
State->Config.LbrSelect = Request->LbrConfig.LbrSelect;
LbrPutLbr(State, ApplyFromVmxRootMode, ApplyByVmcall);
}
else
{
State->Config.LbrSelect = Request->LbrConfig.LbrSelect;
}
return TRUE;
}
/**
* @brief Create a new LBR_STATE structure with allocated memory for LBR data and entries
*
* @return LBR_STATE*
*/
LBR_STATE *
LbrCreateLbrState()
{
LBR_STATE * State;
LBR_DATA * Data;
LBR_STACK_ENTRY * Entries;
State = xmalloc(sizeof(LBR_STATE));
if (State == NULL)
return NULL;
Data = xmalloc(sizeof(LBR_DATA));
if (Data == NULL)
{
xfree(State);
return NULL;
}
SIZE_T TotalEntrySize = (SIZE_T)sizeof(LBR_STACK_ENTRY) * LbrCapacity;
Entries = xmalloc(TotalEntrySize);
if (Entries == NULL)
{
xfree(Data);
xfree(State);
return NULL;
}
xmemset(State, sizeof(LBR_STATE));
xmemset(Data, sizeof(LBR_DATA));
xmemset(Entries, TotalEntrySize);
State->Data = Data;
Data->Entries = Entries;
return State;
}
/**
* @brief Find the LBR_STATE structure for a specific process ID from the global list
*
* @param Pid
* @return LBR_STATE*
*/
LBR_STATE *
LbrFindLbrState(ULONG Pid)
{
KIRQL OldIrql;
LBR_STATE * RetState = NULL;
PLIST_ENTRY Link;
ULONG TargetPid = (Pid == 0) ? xgetcurrent_pid() : Pid;
xacquire_lock(&LbrStateLock, &OldIrql);
for (Link = LbrStateHead.Flink; Link != &LbrStateHead; Link = Link->Flink)
{
LBR_STATE * Curr = CONTAINING_RECORD(Link, LBR_STATE, List);
if (Curr->Config.Pid == TargetPid)
{
RetState = Curr;
break;
}
}
xrelease_lock(&LbrStateLock, &OldIrql);
return RetState;
}
/**
* @brief Insert a new LBR_STATE structure into the global list with proper locking
*
* @param NewState
* @return VOID
*/
VOID
LbrInsertLbrState(LBR_STATE * NewState)
{
KIRQL OldIrql;
if (NewState == NULL)
return;
xacquire_lock(&LbrStateLock, &OldIrql);
LogInfo("LIBIHT-COM: Insert LBR state for pid %d\n", NewState->Config.Pid);
xlist_add(NewState->List, LbrStateHead);
xrelease_lock(&LbrStateLock, &OldIrql);
}
/**
* @brief Remove an existing LBR_STATE structure from the global list and free its associated memory with proper locking
*
* @param OldState
* @return VOID
*/
VOID
LbrRemoveLbrState(LBR_STATE * OldState)
{
KIRQL OldIrql;
if (OldState == NULL)
return;
xacquire_lock(&LbrStateLock, &OldIrql);
LogInfo("LIBIHT-COM: Remove LBR state for pid %d\n", OldState->Config.Pid);
xlist_del(OldState->List);
xfree(OldState->Data->Entries);
xfree(OldState->Data);
xfree(OldState);
xrelease_lock(&LbrStateLock, &OldIrql);
}
/**
* @brief Free all LBR_STATE structures in the global list and their associated memory with proper locking
*
* @return VOID
*/
VOID
LbrFreeLbrStatList()
{
KIRQL OldIrql;
LBR_STATE * CurrState;
PLIST_ENTRY CurrLink;
xacquire_lock(&LbrStateLock, &OldIrql);
CurrLink = LbrStateHead.Flink;
while (CurrLink != &LbrStateHead)
{
CurrState = CONTAINING_RECORD(CurrLink, LBR_STATE, List);
CurrLink = CurrLink->Flink;
xlist_del(CurrState->List);
xfree(CurrState->Data->Entries);
xfree(CurrState->Data);
xfree(CurrState);
}
xrelease_lock(&LbrStateLock, &OldIrql);
}
/**
* @brief Handle IOCTL requests for LBR operations by dispatching to the appropriate function based on the command
*
* @param Request
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return BOOLEAN
*/
BOOLEAN
LbrIoctlHandler(XIOCTL_REQUEST * Request, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
{
BOOLEAN Status = TRUE;
LogInfo("LIBIHT-COM: LBR ioctl command %d.\n", Request->Cmd);
switch (Request->Cmd)
{
case LIBIHT_IOCTL_ENABLE_LBR:
Status = LbrStartLbr(&Request->Body.Lbr, ApplyFromVmxRootMode, ApplyByVmcall);
break;
case LIBIHT_IOCTL_DISABLE_LBR:
Status = LbrStopLbr(&Request->Body.Lbr, ApplyFromVmxRootMode, ApplyByVmcall);
break;
case LIBIHT_IOCTL_DUMP_LBR:
Status = LbrDumpLbr(&Request->Body.Lbr, ApplyFromVmxRootMode, ApplyByVmcall);
break;
case LIBIHT_IOCTL_CONFIG_LBR:
Status = LbrConfigLbr(&Request->Body.Lbr, ApplyFromVmxRootMode, ApplyByVmcall);
break;
default:
LogInfo("LIBIHT-COM: Invalid LBR ioctl command\n");
Status = FALSE;
break;
}
return Status;
}
/**
* @brief Handle context switch events by saving the LBR state of the previous process and restoring the LBR state of the next process if they are being traced
*
* @param PrevPid
* @param NextPid
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return VOID
*/
VOID
LbrCswitchHandler(ULONG PrevPid,
ULONG NextPid,
BOOLEAN ApplyFromVmxRootMode,
BOOLEAN ApplyByVmcall)
{
LBR_STATE * PrevState;
LBR_STATE * NextState;
PrevState = LbrFindLbrState(PrevPid);
NextState = LbrFindLbrState(NextPid);
if (PrevState)
{
LogInfo("LIBIHT-COM: LBR context switch from pid %d on cpu core %d\n",
PrevState->Config.Pid,
xcoreid());
LbrGetLbr(PrevState, ApplyFromVmxRootMode, ApplyByVmcall);
}
if (NextState)
{
LogInfo("LIBIHT-COM: LBR context switch to pid %d on cpu core %d\n",
NextState->Config.Pid,
xcoreid());
LbrPutLbr(NextState, ApplyFromVmxRootMode, ApplyByVmcall);
}
}
/**
* @brief Handle new process creation events by inheriting the LBR state from the parent process if it is being traced
*
* @param ParentPid
* @param ChildPid
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return VOID
*/
VOID
LbrNewProcHandler(
ULONG ParentPid,
ULONG ChildPid,
BOOLEAN ApplyFromVmxRootMode,
BOOLEAN ApplyByVmcall)
{
LBR_STATE *ParentState, *ChildState;
KIRQL OldIrql;
ParentState = LbrFindLbrState(ParentPid);
if (ParentState == NULL)
return;
LogInfo("LIBIHT-COM: LBR new child process pid %d, parent pid %d\n",
ChildPid,
ParentPid);
ChildState = LbrCreateLbrState();
if (ChildState == NULL)
return;
xacquire_lock(&LbrStateLock, &OldIrql);
ChildState->Parent = ParentState;
ChildState->Config.Pid = ChildPid;
ChildState->Config.LbrSelect = ParentState->Config.LbrSelect;
xmemcpy(ChildState->Data,
ParentState->Data,
sizeof(LBR_DATA) + LbrCapacity * sizeof(LBR_STACK_ENTRY));
xrelease_lock(&LbrStateLock, &OldIrql);
LbrInsertLbrState(ChildState);
if (ChildPid == xgetcurrent_pid())
{
LbrPutLbr(ChildState, ApplyFromVmxRootMode, ApplyByVmcall);
State->BranchEntry[CurrentIdx].From,
State->BranchEntry[CurrentIdx].To);
}
}

View file

@ -22,22 +22,7 @@
VOID
HyperTraceExamplePerformLbrTrace(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
{
LBR_IOCTL_REQUEST Request = {0};
KAFFINITY Affinity = 1;
KeSetSystemAffinityThread(Affinity);
LbrInitialize();
if (!LbrCheck())
{
return;
}
Request.LbrConfig.Pid = 0;
Request.LbrConfig.LbrSelect = LBR_SELECT;
if (LbrStartLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall))
if (LbrStartLbr(ApplyFromVmxRootMode, ApplyByVmcall))
{
for (volatile int i = 0; i < 50; i++)
{
@ -53,20 +38,11 @@ HyperTraceExamplePerformLbrTrace(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVm
}
}
LBR_STATE * State = LbrFindLbrState(0);
if (State)
{
LbrGetLbr(State, ApplyFromVmxRootMode, ApplyByVmcall);
}
LogInfo("Dumping LBR Buffer...\n");
LbrDumpLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
LbrStopLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
LbrStopLbr(ApplyFromVmxRootMode, ApplyByVmcall);
LbrDumpLbr(); // This will print the collected LBR branches to the log
}
KeRevertToUserAffinityThread();
}
/**
@ -79,12 +55,7 @@ HyperTraceExamplePerformLbrTrace(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVm
BOOLEAN
HyperTraceStartLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
{
LBR_IOCTL_REQUEST Request = {0};
Request.LbrConfig.Pid = 0;
Request.LbrConfig.LbrSelect = LBR_SELECT;
return LbrStartLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
return LbrStartLbr(ApplyFromVmxRootMode, ApplyByVmcall);
}
/**
@ -92,27 +63,12 @@ HyperTraceStartLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
* @param ApplyFromVmxRootMode
* @param ApplyByVmcall
*
* @return BOOLEAN
* @return VOID
*/
BOOLEAN
VOID
HyperTraceStopLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
{
LBR_IOCTL_REQUEST Request = {0};
Request.LbrConfig.Pid = 0;
Request.LbrConfig.LbrSelect = LBR_SELECT;
LBR_STATE * State = LbrFindLbrState(0);
if (State)
{
LbrGetLbr(State, ApplyFromVmxRootMode, ApplyByVmcall);
}
LogInfo("Dumping LBR Buffer...\n");
LbrDumpLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
return LbrStopLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
LbrStopLbr(ApplyFromVmxRootMode, ApplyByVmcall);
}
/**
@ -129,7 +85,7 @@ BOOLEAN
HyperTraceInitCallback(HYPERTRACE_CALLBACKS * HypertraceCallbacks,
BOOLEAN InitForHypervisorEnvironment)
{
ULONG ProcessorsCount;
UINT32 ProcessorsCount = 0;
//
// Check if the LBR is supported on this CPU before initializing the hypertrace module,
@ -159,14 +115,14 @@ HyperTraceInitCallback(HYPERTRACE_CALLBACKS * HypertraceCallbacks,
RtlCopyMemory(&g_Callbacks, HypertraceCallbacks, sizeof(HYPERTRACE_CALLBACKS));
//
// Read number of cores
// Query the number of processors in the system to initialize the global LBR state list accordingly
//
ProcessorsCount = KeQueryActiveProcessorCount(0);
//
// Initialize the memory for LBR requests on all cores
// Initialize the global LBR state list to hold LBR states for each core
//
g_LbrRequestState = PlatformAllocateMemory(sizeof(LBR_IOCTL_REQUEST) * ProcessorsCount);
g_LbrStateList = (LBR_STACK_ENTRY *)xmalloc(sizeof(LBR_STACK_ENTRY) * ProcessorsCount);
//
// Set the flag to indicate whether the initialization is being done for hypervisor environment or not
@ -210,13 +166,11 @@ HyperTraceQueryStateOfLbrSaveAndLoadVmExitAndEntryControls(UINT32 CoreId)
* @return BOOLEAN
*/
BOOLEAN
HyperTraceEnableLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
BOOLEAN ApplyFromVmxRootMode)
HyperTraceEnableLbr(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
BOOLEAN ApplyFromVmxRootMode)
{
UNREFERENCED_PARAMETER(ApplyFromVmxRootMode);
ULONG ProcessorsCount;
//
// Check if LBR is already enabled or not
//
@ -244,22 +198,6 @@ HyperTraceEnableLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationReq
return FALSE;
}
//
// Enabling LBR
//
LbrInitialize();
//
// Read number of cores
//
ProcessorsCount = KeQueryActiveProcessorCount(0);
for (size_t i = 0; i < ProcessorsCount; i++)
{
g_LbrRequestState[i].LbrConfig.Pid = 0;
g_LbrRequestState[i].LbrConfig.LbrSelect = LBR_SELECT;
}
//
// Broadcast enabling LBR on all cores
//
@ -287,8 +225,8 @@ HyperTraceEnableLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationReq
* @return BOOLEAN
*/
BOOLEAN
HyperTraceDisableLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
BOOLEAN ApplyFromVmxRootMode)
HyperTraceDisableLbr(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
BOOLEAN ApplyFromVmxRootMode)
{
UNREFERENCED_PARAMETER(ApplyFromVmxRootMode);
@ -327,7 +265,7 @@ HyperTraceDisableLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRe
}
/**
* @brief Show LBR tracing for HyperTrace
* @brief Save LBR tracing for HyperTrace
*
* @param HyperTraceOperationRequest
* @param ApplyFromVmxRootMode
@ -335,13 +273,11 @@ HyperTraceDisableLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRe
* @return BOOLEAN
*/
BOOLEAN
HyperTraceShowLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
BOOLEAN ApplyFromVmxRootMode)
HyperTraceSaveLbr(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
BOOLEAN ApplyFromVmxRootMode)
{
UNREFERENCED_PARAMETER(ApplyFromVmxRootMode);
LBR_IOCTL_REQUEST * CurrentRequest;
//
// Check if LBR is already disabled or not
//
@ -355,21 +291,65 @@ HyperTraceShowLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationReque
return FALSE;
}
//
// Get the current request (for current core)
//
CurrentRequest = &g_LbrRequestState[KeGetCurrentProcessorNumberEx(NULL)];
LogInfo("Saving LBR Buffer...\n");
LBR_STATE * State = LbrFindLbrState(0);
//
// Save the LBR state
//
LbrSaveLbr();
if (State)
//
// The operation was successful
//
if (HyperTraceOperationRequest != NULL)
{
LbrGetLbr(State, TRUE, TRUE);
HyperTraceOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
}
return TRUE;
}
/**
* @brief Dump LBR tracing for HyperTrace
*
* @param HyperTraceOperationRequest
* @param ApplyFromVmxRootMode
*
* @return BOOLEAN
*/
BOOLEAN
HyperTraceDumpLbr(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
BOOLEAN ApplyFromVmxRootMode)
{
UNREFERENCED_PARAMETER(ApplyFromVmxRootMode);
//
// Check if LBR is already disabled or not
//
if (!g_LastBranchRecordEnabled)
{
if (HyperTraceOperationRequest != NULL)
{
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_LBR_ALREADY_DISABLED;
}
return FALSE;
}
LogInfo("Dumping LBR Buffer...\n");
LbrDumpLbr(CurrentRequest, TRUE, TRUE);
//
// This will print the collected LBR branches to the log
//
LbrDumpLbr();
//
// The operation was successful
//
if (HyperTraceOperationRequest != NULL)
{
HyperTraceOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
}
return TRUE;
}
@ -385,7 +365,7 @@ HyperTraceUninit()
//
// Disable LBR tracing if it is still enabled
//
HyperTraceDisableLbrTracing(NULL, FALSE);
HyperTraceDisableLbr(NULL, FALSE);
//
// Set callbacks to not initialized
@ -393,14 +373,13 @@ HyperTraceUninit()
g_HyperTraceCallbacksInitialized = FALSE;
//
// UnAllocate the state buffer
// Unallocate the global LBR state list if it is allocated
//
PlatformFreeMemory(g_LbrRequestState);
//
// Set LBR request buffer to zero
//
g_LbrRequestState = NULL64_ZERO;
if (g_LbrStateList != NULL)
{
xfree(g_LbrStateList);
g_LbrStateList = NULL;
}
}
/**
@ -435,7 +414,7 @@ HyperTracePerformOperation(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationReq
LogInfo("HyperTrace: Enabling LBR tracing...\n");
HyperTraceEnableLbrTracing(HyperTraceOperationRequest, ApplyFromVmxRootMode);
HyperTraceEnableLbr(HyperTraceOperationRequest, ApplyFromVmxRootMode);
break;
@ -443,15 +422,23 @@ HyperTracePerformOperation(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationReq
LogInfo("HyperTrace: Disabling LBR tracing...\n");
HyperTraceDisableLbrTracing(HyperTraceOperationRequest, ApplyFromVmxRootMode);
HyperTraceDisableLbr(HyperTraceOperationRequest, ApplyFromVmxRootMode);
break;
case HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_SHOW:
case HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_SAVE:
LogInfo("HyperTrace: Saving LBR tracing...\n");
HyperTraceSaveLbr(HyperTraceOperationRequest, ApplyFromVmxRootMode);
break;
case HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_DUMP:
LogInfo("HyperTrace: Showing LBR tracing...\n");
HyperTraceShowLbrTracing(HyperTraceOperationRequest, ApplyFromVmxRootMode);
HyperTraceDumpLbr(HyperTraceOperationRequest, ApplyFromVmxRootMode);
break;

View file

@ -35,7 +35,7 @@ BOOLEAN g_InitForHypervisorEnvironment;
BOOLEAN g_LastBranchRecordEnabled;
/**
* @brief Core specific state
* @brief This will be a dynamically allocated array to hold LBR states for each core
*
*/
LBR_IOCTL_REQUEST * g_LbrRequestState;
LBR_STACK_ENTRY * g_LbrStateList;

View file

@ -11,7 +11,7 @@
#pragma once
//////////////////////////////////////////////////
// Globals //
// Constants //
//////////////////////////////////////////////////
// Intel MSR Constants
@ -23,63 +23,30 @@
#define MSR_LBR_NHM_TO 0x000006C0
#define LBR_SELECT 0x00000000
/**
* @brief Maximum LBR capacity that is supported by processors
*
*/
#define MAXIMUM_LBR_CAPACITY 0x20 // 32 entries, which is the maximum supported by modern Intel CPUs
//////////////////////////////////////////////////
// Structures //
//////////////////////////////////////////////////
typedef struct _LBR_STACK_ENTRY
typedef struct _LBR_BRANCH_ENTRY
{
ULONGLONG From;
ULONGLONG To;
} LBR_BRANCH_ENTRY, PLBR_BRANCH_ENTRY;
typedef struct _LBR_STACK_ENTRY
{
LBR_BRANCH_ENTRY BranchEntry[MAXIMUM_LBR_CAPACITY];
UINT32 Tos;
} LBR_STACK_ENTRY, PLBR_STACK_ENTRY;
typedef struct _LBR_DATA
{
ULONGLONG LbrTos;
LBR_STACK_ENTRY * Entries;
} LBR_DATA, *PLBR_DATA;
typedef struct _LBR_CONFIG
{
ULONG Pid;
ULONGLONG LbrSelect;
} LBR_CONFIG, *PLBR_CONFIG;
typedef struct _LBR_STATE
{
LBR_CONFIG Config;
LBR_DATA * Data;
PVOID Parent;
LIST_ENTRY List;
} LBR_STATE, *PLBR_STATE;
typedef struct _LBR_IOCTL_REQUEST
{
LBR_CONFIG LbrConfig;
LBR_DATA * Buffer;
} LBR_IOCTL_REQUEST, *PLBR_IOCTL_REQUEST;
typedef struct _XIOCTL_REQUEST
{
ULONG Cmd;
union
{
LBR_IOCTL_REQUEST Lbr;
} Body;
} XIOCTL_REQUEST, *PXIOCTL_REQUEST;
// IOCTL Commands
#define LIBIHT_IOCTL_ENABLE_LBR 0x1
#define LIBIHT_IOCTL_DISABLE_LBR 0x2
#define LIBIHT_IOCTL_DUMP_LBR 0x3
#define LIBIHT_IOCTL_CONFIG_LBR 0x4
//////////////////////////////////////////////////
// Platform Wrappers //
//////////////////////////////////////////////////
@ -136,41 +103,20 @@ extern CPU_LBR_MAP CPU_LBR_MAPS[];
// Prototypes //
//////////////////////////////////////////////////
VOID
LbrGetLbr(LBR_STATE * State, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall);
VOID
LbrPutLbr(LBR_STATE * State, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall);
LBR_STATE *
LbrCreateLbrState();
LBR_STATE *
LbrFindLbrState(ULONG Pid);
BOOLEAN
LbrCheck();
VOID
LbrInsertLbrState(LBR_STATE * NewState);
VOID
LbrRemoveLbrState(LBR_STATE * OldState);
VOID
LbrFreeLbrStatList();
VOID
LbrInitialize();
BOOLEAN
LbrStartLbr(LBR_IOCTL_REQUEST * Request, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall);
LbrStartLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall);
BOOLEAN
LbrStopLbr(LBR_IOCTL_REQUEST * Request, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall);
VOID
LbrStopLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall);
BOOLEAN
LbrDumpLbr(LBR_IOCTL_REQUEST * Request, BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall);
VOID
LbrSaveLbr();
VOID
LbrDumpLbr();
extern ULONGLONG LbrCapacity;
extern LIST_ENTRY LbrStateHead;

View file

@ -1272,7 +1272,8 @@ typedef enum _HYPERTRACE_OPERATION_REQUEST_TYPE
{
HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_ENABLE,
HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_DISABLE,
HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_SHOW,
HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_SAVE,
HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_DUMP,
} HYPERTRACE_OPERATION_REQUEST_TYPE;

View file

@ -148,10 +148,10 @@ static const char *const SymbolTypeNames[] = {
#define FUNC_EVENT_TRACE_STEP_OUT 51
#define FUNC_EVENT_TRACE_INSTRUMENTATION_STEP 52
#define FUNC_EVENT_TRACE_INSTRUMENTATION_STEP_IN 53
#define FUNC_LBR_START 54
#define FUNC_LBR_STOP 55
#define FUNC_RDTSC 56
#define FUNC_RDTSCP 57
#define FUNC_RDTSC 54
#define FUNC_RDTSCP 55
#define FUNC_LBR_SAVE 56
#define FUNC_LBR_DUMP 57
#define FUNC_SPINLOCK_LOCK_CUSTOM_WAIT 58
#define FUNC_EVENT_INJECT 59
#define FUNC_POI 60
@ -253,10 +253,10 @@ static const char *const FunctionNames[] = {
"FUNC_EVENT_TRACE_STEP_OUT",
"FUNC_EVENT_TRACE_INSTRUMENTATION_STEP",
"FUNC_EVENT_TRACE_INSTRUMENTATION_STEP_IN",
"FUNC_LBR_START",
"FUNC_LBR_STOP",
"FUNC_RDTSC",
"FUNC_RDTSCP",
"FUNC_LBR_SAVE",
"FUNC_LBR_DUMP",
"FUNC_SPINLOCK_LOCK_CUSTOM_WAIT",
"FUNC_EVENT_INJECT",
"FUNC_POI",

View file

@ -54,10 +54,12 @@ HyperTracePerformOperation(HYPERTRACE_OPERATION_PACKETS * LbrOperationRequest,
//////////////////////////////////////////////////
IMPORT_EXPORT_HYPERTRACE BOOLEAN
HyperTraceStartLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall);
HyperTraceSaveLbr(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
BOOLEAN ApplyFromVmxRootMode);
IMPORT_EXPORT_HYPERTRACE BOOLEAN
HyperTraceStopLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall);
HyperTraceDumpLbr(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
BOOLEAN ApplyFromVmxRootMode);
IMPORT_EXPORT_HYPERTRACE BOOLEAN
HyperTraceQueryStateOfLbrSaveAndLoadVmExitAndEntryControls(UINT32 CoreId);

View file

@ -31,7 +31,8 @@ CommandLbrHelp()
ShowMessages("\n");
ShowMessages("\t\te.g : !lbr enable\n");
ShowMessages("\t\te.g : !lbr disable\n");
ShowMessages("\t\te.g : !lbr show\n");
ShowMessages("\t\te.g : !lbr save\n");
ShowMessages("\t\te.g : !lbr dump\n");
}
/**
@ -140,9 +141,13 @@ CommandLbr(vector<CommandToken> CommandTokens, string Command)
{
LbrRequest.HyperTraceOperationType = HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_DISABLE;
}
else if (CompareLowerCaseStrings(CommandTokens.at(1), "show"))
else if (CompareLowerCaseStrings(CommandTokens.at(1), "save"))
{
LbrRequest.HyperTraceOperationType = HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_SHOW;
LbrRequest.HyperTraceOperationType = HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_SAVE;
}
else if (CompareLowerCaseStrings(CommandTokens.at(1), "dump"))
{
LbrRequest.HyperTraceOperationType = HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_DUMP;
}
else
{
@ -165,7 +170,11 @@ CommandLbr(vector<CommandToken> CommandTokens, string Command)
{
ShowMessages("LBR disabled successfully\n");
}
else if (LbrRequest.HyperTraceOperationType == HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_SHOW)
else if (LbrRequest.HyperTraceOperationType == HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_SAVE)
{
ShowMessages("LBR branches are saved\n");
}
else if (LbrRequest.HyperTraceOperationType == HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_DUMP)
{
ShowMessages("LBR branches are shown\n");
}

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,19 @@
#pragma once
#ifndef PARSE_TABLE_H
#define PARSE_TABLE_H
#define RULES_COUNT 274
#define RULES_COUNT 276
#define TERMINAL_COUNT 124
#define NONETERMINAL_COUNT 63
#define START_VARIABLE "S"
#define MAX_RHS_LEN 15
#define KEYWORD_LIST_LENGTH 111
#define KEYWORD_LIST_LENGTH 113
#define OPERATORS_ONE_OPERAND_LIST_LENGTH 3
#define OPERATORS_TWO_OPERAND_LIST_LENGTH 16
#define REGISTER_MAP_LIST_LENGTH 120
#define PSEUDO_REGISTER_MAP_LIST_LENGTH 16
#define SCRIPT_VARIABLE_TYPE_LIST_LENGTH 10
#define ASSIGNMENT_OPERATOR_LIST_LENGTH 10
#define SEMANTIC_RULES_MAP_LIST_LENGTH 156
#define SEMANTIC_RULES_MAP_LIST_LENGTH 158
#define THREEOPFUNC1_LENGTH 1
#define THREEOPFUNC2_LENGTH 3
#define TWOOPFUNC1_LENGTH 8
@ -26,8 +26,8 @@
#define THREEOPFUNC4_LENGTH 1
#define ONEOPFUNC4_LENGTH 1
#define TWOOPFUNC4_LENGTH 1
#define ZEROOPFUNC1_LENGTH 9
#define ZEROOPFUNC2_LENGTH 2
#define ZEROOPFUNC1_LENGTH 7
#define ZEROOPFUNC2_LENGTH 4
#define VARARGFUNC1_LENGTH 1
extern const struct _SCRIPT_ENGINE_TOKEN Lhs[RULES_COUNT];
extern const struct _SCRIPT_ENGINE_TOKEN Rhs[RULES_COUNT][MAX_RHS_LEN];
@ -60,11 +60,11 @@ extern const SYMBOL_MAP PseudoRegisterMapList[];
extern const char* ScriptVariableTypeList[];
#define LALR_RULES_COUNT 109
#define LALR_TERMINAL_COUNT 78
#define LALR_RULES_COUNT 111
#define LALR_TERMINAL_COUNT 80
#define LALR_NONTERMINAL_COUNT 26
#define LALR_MAX_RHS_LEN 9
#define LALR_STATE_COUNT 307
#define LALR_STATE_COUNT 315
extern const struct _SCRIPT_ENGINE_TOKEN LalrLhs[RULES_COUNT];
extern const struct _SCRIPT_ENGINE_TOKEN LalrRhs[RULES_COUNT][MAX_RHS_LEN];
extern const unsigned int LalrRhsSize[RULES_COUNT];

View file

@ -1,5 +1,5 @@
# OneOpFunc1 input is a number and returns a number.
.OneOpFunc1->poi db dd dw dq neg hi low not check_address strlen wcslen disassemble_len disassemble_len32 disassemble_len64 interlocked_increment interlocked_decrement reference physical_to_virtual virtual_to_physical poi_pa hi_pa low_pa db_pa dd_pa dw_pa dq_pa
.OneOpFunc1->poi db dd dw dq neg hi low not check_address strlen wcslen disassemble_len disassemble_len32 disassemble_len64 lbr_save lbr_dump interlocked_increment interlocked_decrement reference physical_to_virtual virtual_to_physical poi_pa hi_pa low_pa db_pa dd_pa dw_pa dq_pa
# TwoOpFunc1 inputs are two numbers and returns a number.
.TwoOpFunc1->ed eb eq interlocked_exchange interlocked_exchange_add wcscmp eb_pa ed_pa eq_pa

View file

@ -35,10 +35,10 @@
# TwoOpFunc4 the two inputs are numbers or wstrings and returns a number.
.TwoOpFunc4->wcscmp
.ZeroOpFunc1->pause flush event_trace_step event_trace_step_in event_trace_step_out event_trace_instrumentation_step event_trace_instrumentation_step_in lbr_start lbr_stop
.ZeroOpFunc1->pause flush event_trace_step event_trace_step_in event_trace_step_out event_trace_instrumentation_step event_trace_instrumentation_step_in
# ZeroOpFunc2 no input and returns a number
.ZeroOpFunc2->rdtsc rdtscp
.ZeroOpFunc2->rdtsc rdtscp lbr_save lbr_dump
.VarArgFunc1->printf

View file

@ -2014,15 +2014,16 @@ ScriptEngineFunctionEventTraceStepIn()
}
/**
* @brief Implementation of lbr_start function
* @brief Implementation of lbr_save function
*
* @return VOID
* @return BOOLEAN
*/
VOID
ScriptEngineFunctionLbrStart()
BOOLEAN
ScriptEngineFunctionLbrSave()
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, it's not possible to call lbr_start function in the user-mode\n");
return FALSE;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
@ -2030,7 +2031,7 @@ ScriptEngineFunctionLbrStart()
//
// Depending if we are in VMX-root then a VMCALL is issued by default instead, otherwise the VMCALL is ignored
//
HyperTraceStartLbr(VmFuncVmxGetCurrentExecutionMode(), TRUE);
return HyperTraceSaveLbr(NULL, VmFuncVmxGetCurrentExecutionMode());
#endif // SCRIPT_ENGINE_KERNEL_MODE
}
@ -2038,13 +2039,14 @@ ScriptEngineFunctionLbrStart()
/**
* @brief Implementation of lbr_stop function
*
* @return VOID
* @return BOOLEAN
*/
VOID
ScriptEngineFunctionLbrStop()
BOOLEAN
ScriptEngineFunctionLbrDump()
{
#ifdef SCRIPT_ENGINE_USER_MODE
ShowMessages("err, it's not possible to call lbr_stop function in the user-mode\n");
return FALSE;
#endif // SCRIPT_ENGINE_USER_MODE
#ifdef SCRIPT_ENGINE_KERNEL_MODE
@ -2052,7 +2054,7 @@ ScriptEngineFunctionLbrStop()
//
// Depending if we are in VMX-root then a VMCALL is issued by default instead, otherwise the VMCALL is ignored
//
HyperTraceStopLbr(VmFuncVmxGetCurrentExecutionMode(), TRUE);
return HyperTraceDumpLbr(NULL, VmFuncVmxGetCurrentExecutionMode());
#endif // SCRIPT_ENGINE_KERNEL_MODE
}

View file

@ -736,16 +736,26 @@ ScriptEngineExecute(PGUEST_REGS GuestRegs,
GuestRegs);
break;
case FUNC_LBR_START:
case FUNC_LBR_SAVE:
ScriptEngineFunctionLbrStart();
Des = (PSYMBOL)((unsigned long long)CodeBuffer->Head +
(unsigned long long)(*Indx * sizeof(SYMBOL)));
*Indx = *Indx + 1;
DesVal = ScriptEngineFunctionLbrSave();
SetValue(GuestRegs, ScriptGeneralRegisters, Des, DesVal);
break;
case FUNC_LBR_STOP:
case FUNC_LBR_DUMP:
ScriptEngineFunctionLbrStop();
Des = (PSYMBOL)((unsigned long long)CodeBuffer->Head +
(unsigned long long)(*Indx * sizeof(SYMBOL)));
*Indx = *Indx + 1;
DesVal = ScriptEngineFunctionLbrDump();
SetValue(GuestRegs, ScriptGeneralRegisters, Des, DesVal);
break;
case FUNC_FLUSH:

View file

@ -263,11 +263,11 @@ ScriptEngineFunctionEventTraceInstrumentationStep();
VOID
ScriptEngineFunctionEventTraceStepIn();
VOID
ScriptEngineFunctionLbrStart();
BOOLEAN
ScriptEngineFunctionLbrSave();
VOID
ScriptEngineFunctionLbrStop();
BOOLEAN
ScriptEngineFunctionLbrDump();
UINT64
ScriptEngineFunctionStrcmp(const char * Address1, const char * Address2);