|
HyperDbg Debugger
|
Processor Trace (PT) tracing implementation for HyperTrace module. More...
#include "pch.h"Functions | |
| INT32 | PtEngineSizeToTopaEncoding (UINT64 SizeInBytes) |
| Convert a buffer size in bytes to the ToPA Size field encoding. Valid sizes are 4KB * 2^N for N = 0..15. | |
| INT32 | PtEngineQueryCapabilities (PT_CAPABILITIES *OutCaps) |
| Probe Intel PT capabilities via CPUID leaf 7 / leaf 0x14. | |
| VOID | PtEngineInitDefaultConfig (PT_TRACE_CONFIG *Config) |
| Initialize a PT_TRACE_CONFIG with sensible defaults. Trace user + kernel, branch + TSC packets, 2 MB output buffer. | |
| INT32 | PtEngineAllocateBuffers (PT_PER_CPU *Cpu, const PT_TRACE_CONFIG *Config) |
| Allocate the ToPA table, output buffer, and overflow zone for one per-CPU PT context, then build the ToPA entries. | |
| VOID | PtEngineFreeBuffers (PT_PER_CPU *Cpu) |
| Free all PT buffers belonging to one per-CPU context. Must not be called while State == PT_STATE_TRACING. | |
| INT32 | PtEngineStart (PT_PER_CPU *Cpu) |
| Start tracing on the CURRENT CPU using the passed PT_PER_CPU. Programs all PT MSRs and sets TraceEn=1. | |
| UINT64 | PtEngineStop (PT_PER_CPU *Cpu, PT_OUTPUT_BUFFER *Out) |
| Stop tracing on the CURRENT CPU. Reads final output position, copies trace data if requested, resets PT MSRs. | |
| INT32 | PtEnginePause (PT_PER_CPU *Cpu) |
| Pause tracing on the CURRENT CPU. Preserves buffer state. | |
| INT32 | PtEngineResume (PT_PER_CPU *Cpu) |
| Resume tracing on the CURRENT CPU after pause. | |
| BOOLEAN | PtEngineIsPtPmi () |
| Check whether the latest PMI was raised by Intel PT (IA32_PERF_GLOBAL_STATUS bit 55). | |
| UINT64 | PtEngineHandlePmi (PT_PER_CPU *Cpu, PT_OUTPUT_BUFFER *Out) |
| Handle a ToPA PMI on the CURRENT CPU. Caller is responsible for having already disabled tracing (e.g. via VMCS clear of RTIT_CTL). | |
| BOOLEAN | PtCheck () |
| Check whether Intel PT is supported on the current CPU. Mirrors LbrCheck — must be called once before any Pt* operation. | |
| BOOLEAN | PtAllocateAllCpuBuffers () |
| Allocate ToPA / output / overflow buffers for every active CPU. | |
| VOID | PtFreeAllCpuBuffers () |
| Free ToPA / output / overflow buffers for every active CPU. | |
| INT32 | PtMmapAllCpuBuffersToUser (PT_USER_BUFFER_DESC *OutDescs, UINT32 MaxDescs, UINT32 *OutNumCpus) |
| Map every per-CPU PT main output buffer and 4 KB overflow page into the current user process as a single virtually contiguous region per CPU, and fill OutDescs[i] with the base UserVa and the total Size (main + overflow) for that CPU. | |
| VOID | PtUnmapAllCpuBuffersFromUser () |
| Release every user mapping created by PtMmapAllCpuBuffersToUser. Called by PtFreeAllCpuBuffers (i.e. on PT disable / flush) so user VAs stop being usable before the backing memory is freed. Also used as a rollback path on partial mmap failure. | |
| BOOLEAN | PtStart () |
| Start PT tracing on the CURRENT CPU. Buffers must already be allocated by PtAllocateAllCpuBuffers (called at PASSIVE_LEVEL). | |
| VOID | PtStop () |
| Stop PT tracing on the CURRENT CPU. Trace data accumulated in the per-CPU output buffer is left in place; PtSize / PtDump can read it later. | |
| VOID | PtPause () |
| Pause PT tracing on the CURRENT CPU. Buffer state is preserved so a subsequent PtResume picks up where this left off. | |
| VOID | PtResume () |
| Resume PT tracing on the CURRENT CPU after a prior PtPause. | |
| UINT64 | PtSize () |
| Snapshot the current PT output position on the CURRENT CPU without disturbing tracing state. The returned value is the number of bytes of valid trace data sitting in this CPU's main + overflow buffer, i.e. the offset a decoder should stop at when reading from the user mapping. | |
| VOID | PtDump () |
| Print PT trace summary for the CURRENT CPU. | |
| VOID | PtFilter (const PT_FILTER_OPTIONS *FilterOptions) |
| LBR-style filter wrapper: refresh tracing on the CURRENT CPU with a fresh PT_FILTER_OPTIONS. | |
| VOID | PtFlush () |
| Flush PT trace state on the CURRENT CPU — disables tracing and clears the bytes-captured counter so the next PtStart begins from a fresh baseline. Buffer freeing happens at PASSIVE_LEVEL via PtFreeAllCpuBuffers; this is safe to call from a DPC. | |
Processor Trace (PT) tracing implementation for HyperTrace module.
Programs Intel PT MSRs and manages per-CPU ToPA / output buffers. The engine half (PtEngine*) deals with a single PT_PER_CPU at a time and is OS-agnostic. The HyperDbg wrappers (PtCheck, PtStart, PtStop, PtPause, PtResume, PtSize, PtDump, PtFlush) operate on the global per-CPU state list (g_PtStateList) and mirror the LBR API surface.
| BOOLEAN PtAllocateAllCpuBuffers | ( | ) |
Allocate ToPA / output / overflow buffers for every active CPU.
Must be called at IRQL == PASSIVE_LEVEL (before broadcasting the per-core enable DPC), because MmAllocateContiguousMemorySpecifyCache is paged. Idempotent: cores that already have buffers (State != DISABLED) are skipped.
| BOOLEAN PtCheck | ( | ) |
Check whether Intel PT is supported on the current CPU. Mirrors LbrCheck — must be called once before any Pt* operation.
If running under HyperDbg's hypervisor we also verify that the platform's IA32_VMX_MISC MSR advertises PT-in-VMX support, since without that bit set we may not be able to keep PT alive across VM transitions in a future VMCS-controlled implementation. This is a soft check — the current direct-MSR path still works because PT MSRs aren't trapped — but it surfaces the situation in the log.
| VOID PtDump | ( | ) |
Print PT trace summary for the CURRENT CPU.
PT packets are a compressed binary stream that requires a decoder (libipt or similar) to be human-readable, so this only emits the per-CPU statistics; bulk packet data is preserved in the output buffer for offline retrieval.
| INT32 PtEngineAllocateBuffers | ( | PT_PER_CPU * | Cpu, |
| const PT_TRACE_CONFIG * | Config ) |
Allocate the ToPA table, output buffer, and overflow zone for one per-CPU PT context, then build the ToPA entries.
ToPA layout: [0] main output buffer (Config->BufferSize), INT=1 [1] overflow page (4 KB), INT=0 [2] END, wraps back to ToPA table (circular)
| VOID PtEngineFreeBuffers | ( | PT_PER_CPU * | Cpu | ) |
Free all PT buffers belonging to one per-CPU context. Must not be called while State == PT_STATE_TRACING.
| UINT64 PtEngineHandlePmi | ( | PT_PER_CPU * | Cpu, |
| PT_OUTPUT_BUFFER * | Out ) |
Handle a ToPA PMI on the CURRENT CPU. Caller is responsible for having already disabled tracing (e.g. via VMCS clear of RTIT_CTL).
| VOID PtEngineInitDefaultConfig | ( | PT_TRACE_CONFIG * | Config | ) |
Initialize a PT_TRACE_CONFIG with sensible defaults. Trace user + kernel, branch + TSC packets, 2 MB output buffer.
| BOOLEAN PtEngineIsPtPmi | ( | ) |
Check whether the latest PMI was raised by Intel PT (IA32_PERF_GLOBAL_STATUS bit 55).
| INT32 PtEnginePause | ( | PT_PER_CPU * | Cpu | ) |
Pause tracing on the CURRENT CPU. Preserves buffer state.
| INT32 PtEngineQueryCapabilities | ( | PT_CAPABILITIES * | OutCaps | ) |
Probe Intel PT capabilities via CPUID leaf 7 / leaf 0x14.
| OutCaps | Optional. If non-NULL, populated with detailed capabilities. |
| INT32 PtEngineResume | ( | PT_PER_CPU * | Cpu | ) |
Resume tracing on the CURRENT CPU after pause.
| INT32 PtEngineSizeToTopaEncoding | ( | UINT64 | SizeInBytes | ) |
Convert a buffer size in bytes to the ToPA Size field encoding. Valid sizes are 4KB * 2^N for N = 0..15.
| SizeInBytes |
| INT32 PtEngineStart | ( | PT_PER_CPU * | Cpu | ) |
Start tracing on the CURRENT CPU using the passed PT_PER_CPU. Programs all PT MSRs and sets TraceEn=1.
Must be called from the target CPU (DPC or VMX root).
| UINT64 PtEngineStop | ( | PT_PER_CPU * | Cpu, |
| PT_OUTPUT_BUFFER * | Out ) |
Stop tracing on the CURRENT CPU. Reads final output position, copies trace data if requested, resets PT MSRs.
| VOID PtFilter | ( | const PT_FILTER_OPTIONS * | FilterOptions | ) |
LBR-style filter wrapper: refresh tracing on the CURRENT CPU with a fresh PT_FILTER_OPTIONS.
Mirrors LbrFilter — the caller hands in only the fields a user is allowed to drive (TraceUser, TraceKernel, TargetCr3, BufferSize, NumAddrRanges, AddrRanges) and PtFilter writes them into the per-CPU PT_TRACE_CONFIG one at a time. Engine-managed options (BranchEn, TscEn, MtcEn, CycEn, RetCompression, *Freq) are left alone, so a filter call can never accidentally turn off the packet types the engine relies on.
BufferSize == 0 keeps the per-CPU value already in place, so pure filter changes (privilege bits, CR3, IP ranges) skip any reallocation of the ToPA / output / overflow buffers and can run entirely from a DPC. Genuine buffer-size changes still need a PASSIVE_LEVEL caller to free + reallocate; HyperTracePtFilter handles that case before broadcasting.
| VOID PtFlush | ( | ) |
Flush PT trace state on the CURRENT CPU — disables tracing and clears the bytes-captured counter so the next PtStart begins from a fresh baseline. Buffer freeing happens at PASSIVE_LEVEL via PtFreeAllCpuBuffers; this is safe to call from a DPC.
Mirrors LbrFlush.
| VOID PtFreeAllCpuBuffers | ( | ) |
Free ToPA / output / overflow buffers for every active CPU.
Must be called at IRQL == PASSIVE_LEVEL (after broadcasting any per-core disable DPC), because MmFreeContiguousMemory is paged.
| INT32 PtMmapAllCpuBuffersToUser | ( | PT_USER_BUFFER_DESC * | OutDescs, |
| UINT32 | MaxDescs, | ||
| UINT32 * | OutNumCpus ) |
Map every per-CPU PT main output buffer and 4 KB overflow page into the current user process as a single virtually contiguous region per CPU, and fill OutDescs[i] with the base UserVa and the total Size (main + overflow) for that CPU.
PT buffers must already exist (PtAllocateAllCpuBuffers must have run, i.e. PT is enabled). Idempotent within an enable cycle: a second call returns the already-cached mappings. On any per-CPU failure the partial work is rolled back and the function returns -1.
| VOID PtPause | ( | ) |
Pause PT tracing on the CURRENT CPU. Buffer state is preserved so a subsequent PtResume picks up where this left off.
| VOID PtResume | ( | ) |
Resume PT tracing on the CURRENT CPU after a prior PtPause.
| UINT64 PtSize | ( | ) |
Snapshot the current PT output position on the CURRENT CPU without disturbing tracing state. The returned value is the number of bytes of valid trace data sitting in this CPU's main + overflow buffer, i.e. the offset a decoder should stop at when reading from the user mapping.
| BOOLEAN PtStart | ( | ) |
Start PT tracing on the CURRENT CPU. Buffers must already be allocated by PtAllocateAllCpuBuffers (called at PASSIVE_LEVEL).
Mirrors LbrStart but takes no parameters: per-CPU configuration is sourced from g_PtStateList[core].Config (defaulted at init time).
| VOID PtStop | ( | ) |
Stop PT tracing on the CURRENT CPU. Trace data accumulated in the per-CPU output buffer is left in place; PtSize / PtDump can read it later.
| VOID PtUnmapAllCpuBuffersFromUser | ( | ) |
Release every user mapping created by PtMmapAllCpuBuffersToUser. Called by PtFreeAllCpuBuffers (i.e. on PT disable / flush) so user VAs stop being usable before the backing memory is freed. Also used as a rollback path on partial mmap failure.
Always walks the full table (PtUnmapCpuRegionFromUser is NULL-safe) so rollback after a half-finished mapping still cleans up the CPUs that were mapped before the failure.