mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-12 02:29:28 +00:00
644 lines
17 KiB
C
644 lines
17 KiB
C
/**
|
|
* @file PtApi.c
|
|
* @author Masoud Rahimi Jafari (Masoodrahimy1379@gmail.com)
|
|
* @brief Tracing routines for HyperTrace module (Intel Processor Trace)
|
|
* @details
|
|
* @version 0.19
|
|
* @date 2026-04-29
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*/
|
|
#include "pch.h"
|
|
|
|
/**
|
|
* @brief Translate a user-mode HYPERTRACE_PT_OPERATION_PACKETS into a
|
|
* kernel-side PT_TRACE_CONFIG, falling back to defaults when the
|
|
* caller left fields zero (e.g. a bare `!pt filter`).
|
|
*
|
|
* The returned config is value-typed; HyperTracePtFilter's slow
|
|
* path copies it into every per-CPU slot via
|
|
* HyperTracePtSeedConfigOnAllCpus.
|
|
* @return VOID
|
|
*/
|
|
static VOID
|
|
HyperTracePtBuildConfig(const HYPERTRACE_PT_OPERATION_PACKETS * Req,
|
|
PT_TRACE_CONFIG * OutCfg)
|
|
{
|
|
UINT32 Copy;
|
|
|
|
//
|
|
// Start from defaults; only the fields the user can drive are then
|
|
// overridden.
|
|
//
|
|
PtEngineInitDefaultConfig(OutCfg);
|
|
|
|
//
|
|
// If the request specifies neither user nor kernel, default to both
|
|
// (matches LBR behaviour when filter is empty).
|
|
//
|
|
if (Req->FilterOptions.TraceUser || Req->FilterOptions.TraceKernel)
|
|
{
|
|
OutCfg->TraceUser = (Req->FilterOptions.TraceUser != 0) ? TRUE : FALSE;
|
|
OutCfg->TraceKernel = (Req->FilterOptions.TraceKernel != 0) ? TRUE : FALSE;
|
|
}
|
|
|
|
OutCfg->TargetCr3 = Req->EnableOptions.Cr3;
|
|
|
|
if (Req->BufferSize != 0)
|
|
{
|
|
OutCfg->BufferSize = Req->BufferSize;
|
|
}
|
|
|
|
OutCfg->NumAddrRanges = Req->FilterOptions.NumAddrRanges;
|
|
if (OutCfg->NumAddrRanges > PT_MAX_ADDR_RANGES)
|
|
OutCfg->NumAddrRanges = PT_MAX_ADDR_RANGES;
|
|
|
|
for (Copy = 0; Copy < OutCfg->NumAddrRanges; Copy++)
|
|
{
|
|
OutCfg->AddrRanges[Copy] = Req->FilterOptions.AddrRanges[Copy];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Push a fully-formed PT_TRACE_CONFIG into every active per-CPU
|
|
* slot. Used by the Enable path so PtAllocateAllCpuBuffers picks up
|
|
* the right BufferSize on every core. Runs at PASSIVE_LEVEL —
|
|
* does NOT start or stop tracing (callers handle that via DPC)
|
|
* @return VOID
|
|
*/
|
|
static VOID
|
|
HyperTracePtSeedConfigOnAllCpus(const PT_TRACE_CONFIG * Cfg)
|
|
{
|
|
UINT32 ProcessorsCount;
|
|
UINT32 i;
|
|
|
|
if (g_PtStateList == NULL || Cfg == NULL)
|
|
return;
|
|
|
|
ProcessorsCount = KeQueryActiveProcessorCount(0);
|
|
|
|
for (i = 0; i < ProcessorsCount; i++)
|
|
{
|
|
g_PtStateList[i].Config = *Cfg;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Enable PT tracing for HyperTrace
|
|
*
|
|
* @param PtOperationRequest Pointer to the HyperTrace PT operation request packet
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtEnable(HYPERTRACE_PT_OPERATION_PACKETS * PtOperationRequest)
|
|
{
|
|
//
|
|
// Check if PT is already enabled or not
|
|
//
|
|
if (g_ProcessorTraceEnabled)
|
|
{
|
|
PtOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_ALREADY_ENABLED;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check PT support on CPU
|
|
//
|
|
if (!PtCheck())
|
|
{
|
|
PtOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_NOT_SUPPORTED;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Allocate per-CPU ToPA / output / overflow buffers at PASSIVE_LEVEL
|
|
// (the contiguous-memory allocator cannot run from a DPC).
|
|
// PtAllocateAllCpuBuffers reads Cpu->Config.BufferSize, which was set
|
|
// either at module init (default 2MB) or by a prior !pt filter — so
|
|
// any pre-enable filter settings are preserved here.
|
|
//
|
|
if (!PtAllocateAllCpuBuffers())
|
|
{
|
|
//
|
|
// Roll back any partial allocations so we don't leak on next try.
|
|
//
|
|
PtFreeAllCpuBuffers();
|
|
PtOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_NOT_SUPPORTED;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Broadcast enabling PT on all cores
|
|
//
|
|
BroadcastEnablePtOnAllCores();
|
|
|
|
//
|
|
// Set the flag to indicate that PT tracing is enabled
|
|
//
|
|
g_ProcessorTraceEnabled = TRUE;
|
|
|
|
//
|
|
// Set successful status
|
|
//
|
|
PtOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable PT tracing for HyperTrace
|
|
*
|
|
* @param PtOperationRequest Pointer to the HyperTrace PT operation request packet
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtDisable(HYPERTRACE_PT_OPERATION_PACKETS * PtOperationRequest)
|
|
{
|
|
//
|
|
// Check if PT is already disabled or not
|
|
//
|
|
if (!g_ProcessorTraceEnabled)
|
|
{
|
|
if (PtOperationRequest != NULL)
|
|
{
|
|
PtOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_ALREADY_DISABLED;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Disabling PT
|
|
//
|
|
g_ProcessorTraceEnabled = FALSE;
|
|
|
|
//
|
|
// Broadcast disabling PT on all cores (DPC stops tracing per-core)
|
|
//
|
|
BroadcastDisablePtOnAllCores();
|
|
|
|
//
|
|
// Free per-CPU buffers at PASSIVE_LEVEL after the broadcast has stopped
|
|
// tracing on every core.
|
|
//
|
|
PtFreeAllCpuBuffers();
|
|
|
|
//
|
|
// Set successful status
|
|
//
|
|
if (PtOperationRequest != NULL)
|
|
{
|
|
PtOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Pause PT tracing on every core. Buffers stay allocated and the
|
|
* per-CPU CTL is preserved, so HyperTracePtResume can restart the
|
|
* trace exactly where it stopped.
|
|
*
|
|
* @param HyperTraceOperationRequest
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtPause(HYPERTRACE_PT_OPERATION_PACKETS * HyperTraceOperationRequest)
|
|
{
|
|
if (!g_ProcessorTraceEnabled)
|
|
{
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_ALREADY_DISABLED;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BroadcastPausePtOnAllCores();
|
|
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Resume PT tracing on every core after a prior HyperTracePtPause.
|
|
*
|
|
* @param HyperTraceOperationRequest
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtResume(HYPERTRACE_PT_OPERATION_PACKETS * HyperTraceOperationRequest)
|
|
{
|
|
if (!g_ProcessorTraceEnabled)
|
|
{
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_ALREADY_DISABLED;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BroadcastResumePtOnAllCores();
|
|
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Snapshot the current PT output position on every core and write
|
|
* the per-CPU byte counts into HyperTraceOperationRequest->BytesPerCpu.
|
|
* The returned counts are the decode window — bytes [0, BytesPerCpu[i])
|
|
* in CPU i's user mapping currently hold valid trace data.
|
|
*
|
|
* @param HyperTraceOperationRequest
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtSize(HYPERTRACE_PT_OPERATION_PACKETS * HyperTraceOperationRequest)
|
|
{
|
|
UINT32 ProcessorsCount;
|
|
|
|
if (!g_ProcessorTraceEnabled)
|
|
{
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_ALREADY_DISABLED;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if (HyperTraceOperationRequest == NULL)
|
|
return FALSE;
|
|
|
|
ProcessorsCount = KeQueryActiveProcessorCount(0);
|
|
|
|
if (ProcessorsCount > PT_MAX_CPUS_FOR_MMAP)
|
|
ProcessorsCount = PT_MAX_CPUS_FOR_MMAP;
|
|
|
|
RtlZeroMemory(HyperTraceOperationRequest->BytesPerCpu,
|
|
sizeof(HyperTraceOperationRequest->BytesPerCpu));
|
|
|
|
BroadcastSizePtOnAllCores(HyperTraceOperationRequest->BytesPerCpu);
|
|
|
|
HyperTraceOperationRequest->NumCpus = ProcessorsCount;
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Dump PT trace state for HyperTrace
|
|
*
|
|
* @param HyperTraceOperationRequest
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtDump(HYPERTRACE_PT_OPERATION_PACKETS * HyperTraceOperationRequest)
|
|
{
|
|
if (!g_ProcessorTraceEnabled)
|
|
{
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_ALREADY_DISABLED;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
LogInfo("Dumping PT trace summary...\n");
|
|
|
|
BroadcastDumpPtOnAllCores();
|
|
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Flush PT trace state on all cores (free buffers)
|
|
*
|
|
* @param HyperTraceOperationRequest
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtFlush(HYPERTRACE_PT_OPERATION_PACKETS * HyperTraceOperationRequest)
|
|
{
|
|
if (!g_ProcessorTraceEnabled)
|
|
{
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_ALREADY_DISABLED;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Stop tracing on all cores via DPC (so MSRs are quiesced)
|
|
//
|
|
BroadcastFlushPtOnAllCores();
|
|
|
|
//
|
|
// Then free contiguous buffers at PASSIVE_LEVEL
|
|
//
|
|
PtFreeAllCpuBuffers();
|
|
|
|
//
|
|
// Reallocate buffers so subsequent !pt save / !pt dump / !pt enable
|
|
// continue to work — Flush in LBR keeps tracing alive, so we mirror
|
|
// that by leaving PT primed for the next !pt enable.
|
|
//
|
|
if (!PtAllocateAllCpuBuffers())
|
|
{
|
|
PtFreeAllCpuBuffers();
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_PT_NOT_SUPPORTED;
|
|
}
|
|
g_ProcessorTraceEnabled = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Resume tracing on all cores
|
|
//
|
|
BroadcastEnablePtOnAllCores();
|
|
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Apply a new PT trace configuration (TraceUser / TraceKernel /
|
|
* TargetCr3 / BufferSize / NumAddrRanges + AddrRanges) on all cores.
|
|
*
|
|
* Mirrors HyperTraceLbrUpdateFilterOptions / LbrFilter:
|
|
*
|
|
* - If PT is currently enabled, stop tracing on all cores, free
|
|
* and reallocate buffers (because BufferSize may have changed),
|
|
* push the new config into every per-CPU slot, and resume
|
|
* tracing on all cores.
|
|
* - If PT is currently disabled, only update the per-CPU config
|
|
* so that the next `!pt enable` picks it up.
|
|
*
|
|
* Must be called at IRQL == PASSIVE_LEVEL because of the
|
|
* contiguous-memory allocator.
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtFilter(HYPERTRACE_PT_OPERATION_PACKETS * Req)
|
|
{
|
|
PT_APPLY_CORE_FILTER_REQUEST ApplyCoreFilterReq = {0};
|
|
BOOLEAN WasEnabled = g_ProcessorTraceEnabled;
|
|
BOOLEAN BufferChanged = FALSE;
|
|
UINT64 ExistingSize = 0;
|
|
|
|
//
|
|
// Copy the user-mode request into a kernel-mode PT_APPLY_CORE_FILTER_REQUEST
|
|
//
|
|
memcpy(&ApplyCoreFilterReq.FilterOptions, &Req->FilterOptions, sizeof(PT_FILTER_OPTIONS));
|
|
memcpy(&ApplyCoreFilterReq.EnableOptions, &Req->EnableOptions, sizeof(PT_ENABLE_OPTIONS));
|
|
ApplyCoreFilterReq.BufferSize = Req->BufferSize;
|
|
|
|
//
|
|
// Translate the user-mode packet into PT_FILTER_OPTIONS - the narrow
|
|
// surface PtFilter operates on. Default to user+kernel when the
|
|
// caller specified neither (matches LBR's empty-filter behaviour).
|
|
//
|
|
if (Req->FilterOptions.TraceUser || Req->FilterOptions.TraceKernel)
|
|
{
|
|
ApplyCoreFilterReq.FilterOptions.TraceUser = (Req->FilterOptions.TraceUser != 0) ? TRUE : FALSE;
|
|
ApplyCoreFilterReq.FilterOptions.TraceKernel = (Req->FilterOptions.TraceKernel != 0) ? TRUE : FALSE;
|
|
}
|
|
else
|
|
{
|
|
ApplyCoreFilterReq.FilterOptions.TraceUser = TRUE;
|
|
ApplyCoreFilterReq.FilterOptions.TraceKernel = TRUE;
|
|
}
|
|
|
|
if (Req->FilterOptions.NumAddrRanges > PT_MAX_ADDR_RANGES)
|
|
ApplyCoreFilterReq.FilterOptions.NumAddrRanges = PT_MAX_ADDR_RANGES;
|
|
|
|
//
|
|
// Decide between fast (filter-only) and slow (buffer-resize) paths.
|
|
//
|
|
if (g_PtStateList != NULL)
|
|
{
|
|
ExistingSize = g_PtStateList[0].Config.BufferSize;
|
|
}
|
|
|
|
if (ApplyCoreFilterReq.BufferSize != 0 && ApplyCoreFilterReq.BufferSize != ExistingSize)
|
|
{
|
|
BufferChanged = TRUE;
|
|
}
|
|
|
|
if (!WasEnabled || BufferChanged)
|
|
{
|
|
//
|
|
// Slow path — PT is off and/or BufferSize changed. We have to
|
|
// free + reallocate per-CPU buffers at PASSIVE_LEVEL, so we
|
|
// can't go through DPC for the config seeding either.
|
|
//
|
|
PT_TRACE_CONFIG Cfg;
|
|
|
|
if (WasEnabled)
|
|
{
|
|
BroadcastFlushPtOnAllCores();
|
|
PtFreeAllCpuBuffers();
|
|
}
|
|
|
|
//
|
|
// Build a full PT_TRACE_CONFIG (defaults + the user-tunable
|
|
// fields from the request) and seed it on every CPU so the next
|
|
// PtAllocateAllCpuBuffers picks up the right BufferSize and
|
|
// PtEngineStart programs the right RTIT_CTL bits.
|
|
//
|
|
HyperTracePtBuildConfig(Req, &Cfg);
|
|
HyperTracePtSeedConfigOnAllCpus(&Cfg);
|
|
|
|
if (WasEnabled)
|
|
{
|
|
if (!PtAllocateAllCpuBuffers())
|
|
{
|
|
PtFreeAllCpuBuffers();
|
|
g_ProcessorTraceEnabled = FALSE;
|
|
if (Req != NULL)
|
|
{
|
|
Req->KernelStatus = DEBUGGER_ERROR_PT_NOT_SUPPORTED;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BroadcastEnablePtOnAllCores();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Fast filter-only path: PT is running and BufferSize is
|
|
// unchanged. Force FilterOptions.BufferSize=0 so PtFilter on each core
|
|
// keeps the buffer that's already allocated, then broadcast.
|
|
//
|
|
ApplyCoreFilterReq.BufferSize = 0;
|
|
BroadcastFilterPtOnAllCores(&ApplyCoreFilterReq);
|
|
}
|
|
|
|
if (Req != NULL)
|
|
{
|
|
Req->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Map every per-CPU PT main output + overflow buffer into the
|
|
* calling user-mode process. See HYPERTRACE_PT_MMAP_PACKETS for
|
|
* the full lifetime / single-process contract.
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtMmap(HYPERTRACE_PT_MMAP_PACKETS * Req)
|
|
{
|
|
if (Req == NULL)
|
|
return FALSE;
|
|
|
|
Req->NumCpus = 0;
|
|
|
|
if (!g_HyperTraceCallbacksInitialized)
|
|
{
|
|
Req->KernelStatus = DEBUGGER_ERROR_HYPERTRACE_NOT_INITIALIZED;
|
|
return FALSE;
|
|
}
|
|
|
|
if (!g_ProcessorTraceEnabled)
|
|
{
|
|
Req->KernelStatus = DEBUGGER_ERROR_PT_ALREADY_DISABLED;
|
|
return FALSE;
|
|
}
|
|
|
|
if (PtMmapAllCpuBuffersToUser(Req->Cpus, PT_MAX_CPUS_FOR_MMAP, &Req->NumCpus) != 0)
|
|
{
|
|
Req->KernelStatus = DEBUGGER_ERROR_PT_NOT_SUPPORTED;
|
|
return FALSE;
|
|
}
|
|
|
|
Req->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Perform actions related to HyperTrace PT
|
|
*
|
|
* @param PtOperationRequest
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePtPerformOperation(HYPERTRACE_PT_OPERATION_PACKETS * PtOperationRequest)
|
|
{
|
|
BOOLEAN Status = TRUE;
|
|
|
|
//
|
|
// Check if the hypertrace module is initialized before performing any operation
|
|
//
|
|
if (!g_HyperTraceCallbacksInitialized)
|
|
{
|
|
PtOperationRequest->KernelStatus = DEBUGGER_ERROR_HYPERTRACE_NOT_INITIALIZED;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Perform the requested operation
|
|
//
|
|
switch (PtOperationRequest->PtOperationType)
|
|
{
|
|
case HYPERTRACE_PT_OPERATION_REQUEST_TYPE_ENABLE:
|
|
|
|
LogInfo("HyperTrace: Enabling PT tracing...\n");
|
|
|
|
HyperTracePtEnable(PtOperationRequest);
|
|
|
|
break;
|
|
|
|
case HYPERTRACE_PT_OPERATION_REQUEST_TYPE_DISABLE:
|
|
|
|
LogInfo("HyperTrace: Disabling PT tracing...\n");
|
|
|
|
HyperTracePtDisable(PtOperationRequest);
|
|
|
|
break;
|
|
|
|
case HYPERTRACE_PT_OPERATION_REQUEST_TYPE_PAUSE:
|
|
|
|
LogInfo("HyperTrace: Pausing PT tracing...\n");
|
|
|
|
HyperTracePtPause(PtOperationRequest);
|
|
|
|
break;
|
|
|
|
case HYPERTRACE_PT_OPERATION_REQUEST_TYPE_RESUME:
|
|
|
|
LogInfo("HyperTrace: Resuming PT tracing...\n");
|
|
|
|
HyperTracePtResume(PtOperationRequest);
|
|
|
|
break;
|
|
|
|
case HYPERTRACE_PT_OPERATION_REQUEST_TYPE_SIZE:
|
|
|
|
LogInfo("HyperTrace: Snapshotting PT buffer sizes...\n");
|
|
|
|
HyperTracePtSize(PtOperationRequest);
|
|
|
|
break;
|
|
|
|
case HYPERTRACE_PT_OPERATION_REQUEST_TYPE_DUMP:
|
|
|
|
LogInfo("HyperTrace: Showing PT tracing...\n");
|
|
|
|
HyperTracePtDump(PtOperationRequest);
|
|
|
|
break;
|
|
|
|
case HYPERTRACE_PT_OPERATION_REQUEST_TYPE_FLUSH:
|
|
|
|
LogInfo("HyperTrace: Flushing PT tracing...\n");
|
|
|
|
HyperTracePtFlush(PtOperationRequest);
|
|
|
|
break;
|
|
|
|
case HYPERTRACE_PT_OPERATION_REQUEST_TYPE_FILTER:
|
|
|
|
LogInfo("HyperTrace: Updating PT filter / config...\n");
|
|
|
|
HyperTracePtFilter(PtOperationRequest);
|
|
|
|
break;
|
|
|
|
default:
|
|
Status = FALSE;
|
|
PtOperationRequest->KernelStatus = DEBUGGER_ERROR_INVALID_HYPERTRACE_OPERATION_TYPE;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|