SDK documentation

Disclaimer

Everything I document here is what it should work like. My code is not perfect, so if you're stuck with something, feel free to ping me.

Intro

Software Development Kit for the PulseDbg hypervisor is a package that allows you to work with a PulseDbg debuggee directly. Using the SDK you can implement a debugger, introspection tool, IDA shim - anything you like. The basic idea is the same - you have a target system running under the hypervisor, and a hypervisor client which is your application.

Overview

PulseSDK currently has the following directory layout:

PulseEng stands for Pulse Engine. It is a library that implements the communication layer with the PulseDbg hypervisor. It uses a custom binary protocol which is very boring. The protocol is not a secret, I just change it all the time. I do not promise backward or forward compatibility of the protocol. Use the current PulseEng version with the current PulseDbg host version in order to make sure that it works correctly.

PulseSDK also has a libpulseeng.so library compiled for Linux. I'm not a Linux guy, I'm still learning. I have no idea if it is compatible with your distro. All I can tell is I built it on my Ubuntu 24.04.

Header files

The main header for the SDK is "ps.h". Including this header is enough to use PulseSDK in your application. It includes the following headers:

Transport usage

The life cycle of a transport is:

Engine usage

Engine requests

The way the debugging session works is there is a communication between a debugger and a debuggee via some transport. Transports have different properties (like maximum transfer unit or latency), which leads to inevitable delays when performing any debugging action. It is also true that transports can be somewhat unstable, so there is a built-in logic inside the engine about how to handle packet losses. The request timeout that you can set via EngSetRequestTimeout is a total timeout for your request. Still, if an engine thinks that there was a packet drop, it will issue several retransmission attempts. The retransmission will happen shortly, i.e. request timeout value divided by a number of maximum retransmission count. So, there is a balance between the wait length and a retransmission opportunity: if you set this timeout to a small value, it might happen that retransmission will never have a chance to receive a valid reply. Therefore, if you want to adjust this value, please play with it first and see how it behaves.

Pulse API

First of all, when the target is running, it has a certain polling rate (configurable with PulseConfig utility). So keep in mind that there will be a longer delay (or even timeout fails) when calling Ps* functions with a running target. It is not prohibited to call target command functions on a running target, but several calls (like setting a breakpoint) are not SMP-safe. Freezing the target execution guarantees SMP-safety and also gives you the shortest possible delay of a function call. Second, the hypervisor natively works with physical addresses, so you'll have to get used a little to this fact. I'd recommend reviewing x86 architecture basics.

Request API

Request API provides more control over the transport request lifecyclt. It echoes Pulse API functions. Request API operates with requests. The lifecycle of the request is the following:

Transport functions

PULSE_STATUS TransportCreate(PPS_TRANSPORT *pTransport, PS_TRANSPORT_TYPE TransportType);
PULSE_STATUS TransportEnumerateInterfaces(PPS_TRANSPORT pTransport);
PULSE_STATUS TransportGetInterfaceCount(PPS_TRANSPORT pTransport, uint32_t *pInterfaceCount);
PULSE_STATUS TransportGetInterfaceName(PPS_TRANSPORT pTransport, uint32_t InterfaceIndex, char *pcInterfaceNameBuffer, uint32_t *pcbBufSize);
PULSE_STATUS TransportSetInterfaceName(PPS_TRANSPORT pTransport, char *lpcInterfaceName);
PULSE_STATUS TransportSetInterfaceIndex(PPS_TRANSPORT pTransport, uint32_t InterfaceIndex);
PULSE_STATUS TransportSetRawDataCallback(PPS_TRANSPORT pTransport, lpfnRawDataCallback RawDataCallback, uintptr_t Context);
PULSE_STATUS TransportDestroy(PPS_TRANSPORT pTransport);

Engine functions

PULSE_STATUS EngCreateEngine(PPS_ENGINE *ppEngine);
PULSE_STATUS EngAssignTransport(PPS_ENGINE pEngine, PPS_TRANSPORT pTransport);
PULSE_STATUS EngSetRequestTimeout(PPS_ENGINE pEngine, uint32_t Timeout);
PULSE_STATUS EngSetRequestRetryCount(PPS_ENGINE pEngine, uint32_t RetryCount);
PULSE_STATUS EngStart(PPS_ENGINE pEngine);
PULSE_STATUS EngStop(PPS_ENGINE pEngine);
PULSE_STATUS EngDestroyEngine(PPS_ENGINE pEngine);

Pulse API


PULSE_STATUS PsSetEventCallback(PPS_ENGINE pEngine, lpfnEventCallback EventCallback, uintptr_t Context);

PULSE_STATUS PsPing(PPS_ENGINE pEngine);
PULSE_STATUS PsGo(PPS_ENGINE pEngine);
PULSE_STATUS PsBreakIn(PPS_ENGINE pEngine);
PULSE_STATUS PsStep(PPS_ENGINE pEngine, uint8_t SuppressInterrupts);
PULSE_STATUS PsSwitchCpu(PPS_ENGINE pEngine, uint64_t TargetCpuIndex);
PULSE_STATUS PsReboot(PPS_ENGINE pEngine);

PULSE_STATUS PsReadVirtualMemory(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsWriteVirtualMemory(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, void* pBuffer, uint64_t cbToWrite, uint64_t* pcbWritten);
PULSE_STATUS PsReadLinearMemory(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint64_t Address, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsWriteLinearMemory(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint64_t Address, void* pBuffer, uint64_t cbToWrite, uint64_t* pcbWritten);
PULSE_STATUS PsReadPhysicalMemory(PPS_ENGINE pEngine, uint64_t Address, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsWritePhysicalMemory(PPS_ENGINE pEngine, uint64_t Address, void* pBuffer, uint64_t cbToWrite, uint64_t* pcbWritten);

PULSE_STATUS PsGetContext(PPS_ENGINE pEngine, PPS_CTX pContext, uint64_t RegMask, PS_CPU_MODE *pCpuMode);
PULSE_STATUS PsSetContext(PPS_ENGINE pEngine, PPS_CTX pContext, uint64_t RegMask);
PULSE_STATUS PsGetExtendedContext(PPS_ENGINE pEngine, PPS_CTX_EXT pContextExt, uint8_t ExtRegSetIndex, uint64_t *pExtRegMask);
PULSE_STATUS PsSetExtendedContext(PPS_ENGINE pEngine, PPS_CTX_EXT pContextExt, uint8_t ExtRegSetIndex, uint64_t *pExtRegMask);

PULSE_STATUS PsReadIo(PPS_ENGINE pEngine, uint16_t Port, uint16_t AccessSize, void *pBuffer, uint32_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsWriteIo(PPS_ENGINE pEngine, uint16_t Port, uint16_t AccessSize, void *pBuffer, uint32_t cbToWrite, uint64_t *pcbWritten);

PULSE_STATUS PsGetStateInfo(PPS_ENGINE pEngine, PPS_STATE_INFO pStateInfo);
PULSE_STATUS PsGetCpuInfo(PPS_ENGINE pEngine, uint8_t *pActiveCpu, uint8_t *pCpuCount);
PULSE_STATUS PsCpuId(PPS_ENGINE pEngine, uint32_t Leaf, uint32_t Subleaf, PPS_CPUID_DATA pCpuIdData);

PULSE_STATUS PsReadMsr(PPS_ENGINE pEngine, uint32_t MsrNumber, uint64_t *pMsrValue);
PULSE_STATUS PsWriteMsr(PPS_ENGINE pEngine, uint32_t MsrNumber, uint64_t MsrValue);

PULSE_STATUS PsSearchVirtualMemory(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint16_t Selector, uint64_t StartOffset, uint64_t EndOffset, void* pPattern, uint32_t PatternSize, uint32_t SearchStep, uint8_t IgnoreGaps, uint64_t *pResult);
PULSE_STATUS PsSearchLinearMemory(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint64_t StartAddress, uint64_t EndAddress, void* pPattern, uint32_t PatternSize, uint32_t SearchStep, uint8_t IgnoreGaps, uint64_t *pResult);
PULSE_STATUS PsSearchPhysicalMemory(PPS_ENGINE pEngine, uint64_t StartAddress, uint64_t EndAddress, void* pPattern, uint32_t PatternSize, uint32_t SearchStep, uint8_t IgnoreGaps, uint64_t *pResult);

PULSE_STATUS PsWalkPageVirtual(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint16_t Selector, uint64_t Offset, PPS_PAGE_WALK_INFO pPageWalkInfo);
PULSE_STATUS PsWalkPageLinear(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint64_t Address, PPS_PAGE_WALK_INFO pPageWalkInfo);

PULSE_STATUS PsVirtualToPhysical(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint16_t Selector, uint64_t Offset, uint64_t *pPhysicalAddress);
PULSE_STATUS PsLinearToPhysical(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint64_t Address, uint64_t *pPhysicalAddress);

PULSE_STATUS PsSetBreakPoint(PPS_ENGINE pEngine, uint64_t PhysicalAddress, uint16_t *pBreakPointId);
PULSE_STATUS PsRemoveBreakPoint(PPS_ENGINE pEngine, uint16_t BreakPointId);
PULSE_STATUS PsClearBreakPoints(PPS_ENGINE pEngine);

PULSE_STATUS PsGetBreakPointInfo(PPS_ENGINE pEngine, PPS_BREAK_POINT_INFO pBreakPointInfoArray, uint16_t StartBreakPointId, uint16_t *pCount, uint16_t *pTotalCount);
PULSE_STATUS PsGetBreakPointFilterInfo(PPS_ENGINE pEngine, PPS_BREAK_POINT_FILTER_INFO pBreakPointFilterInfoArray, uint16_t BreakPointId, uint16_t FiltersSkipCount, uint16_t *pCount);

PULSE_STATUS PsAddBreakPointFilter(PPS_ENGINE pEngine, uint16_t BreakPointId, PPS_BREAK_POINT_FILTER_PARAMS pBreakPointFilterParams, uint16_t *pBreakPointFilerId);
PULSE_STATUS PsRemoveBreakPointFilter(PPS_ENGINE pEngine, uint16_t BreakPointId, uint16_t BreakPointFilterId);
PULSE_STATUS PsClearBreakPointFilters(PPS_ENGINE pEngine, uint16_t BreakPointId);

PULSE_STATUS PsReadMmioVirtual(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsWriteMmioVirtual(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToWrite, uint64_t* pcbWritten);
PULSE_STATUS PsReadMmioLinear(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint64_t Address, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsWriteMmioLinear(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint64_t Address, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToWrite, uint64_t* pcbWritten);
PULSE_STATUS PsReadMmioPhysical(PPS_ENGINE pEngine, uint64_t Address, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsWriteMmioPhysical(PPS_ENGINE pEngine, uint64_t Address, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToWrite, uint64_t* pcbWritten);

PULSE_STATUS PsComputeSha1Virtual(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, uint32_t cbToRead, PPS_SHA1_HASH pSha1Hash, uint32_t *pcbRead);
PULSE_STATUS PsComputeSha1Linear(PPS_ENGINE pEngine, uint64_t PageTableAddress, uint64_t Address, uint32_t cbToRead, PPS_SHA1_HASH pSha1Hash, uint32_t *pcbRead);
PULSE_STATUS PsComputeSha1Physical(PPS_ENGINE pEngine, uint64_t Address, uint32_t cbToRead, PPS_SHA1_HASH pSha1Hash, uint32_t *pcbRead);

Pulse request API


PULSE_STATUS PsRequestCreate(PPS_ENGINE pEngine, PPS_REQUEST *ppRequest);
PULSE_STATUS PsRequestCreateBatch(PPS_ENGINE pEngine, PPS_REQUEST *ppRequest);
PULSE_STATUS PsRequestSubmit(PPS_REQUEST pRequest);
PULSE_STATUS PsRequestExecute(PPS_REQUEST pRequest); // Synchronous execution
PULSE_STATUS PsRequestWait(PPS_REQUEST pRequest, uint32_t Timeout);
PULSE_STATUS PsRequestGetStatus(PPS_REQUEST pRequest);
PULSE_STATUS PsRequestReset(PPS_REQUEST pRequest);
PULSE_STATUS PsRequestDestroy(PPS_REQUEST pRequest);

PULSE_STATUS PsRequestPing(PPS_REQUEST pRequest);
PULSE_STATUS PsRequestGo(PPS_REQUEST pRequest);
PULSE_STATUS PsRequestBreakIn(PPS_REQUEST pRequest);
PULSE_STATUS PsRequestStep(PPS_REQUEST pRequest, uint8_t SuppressInterrupts);
PULSE_STATUS PsRequestSwitchCpu(PPS_REQUEST pRequest, uint64_t TargetCpuIndex);
PULSE_STATUS PsRequestReboot(PPS_REQUEST pRequest);

PULSE_STATUS PsRequestReadVirtualMemory(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsRequestWriteVirtualMemory(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, void* pBuffer, uint64_t cbToWrite, uint64_t *pcbWritten);
PULSE_STATUS PsRequestReadLinearMemory(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint64_t Address, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsRequestWriteLinearMemory(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint64_t Address, void* pBuffer, uint64_t cbToWrite, uint64_t *pcbWritten);
PULSE_STATUS PsRequestReadPhysicalMemory(PPS_REQUEST pRequest, uint64_t Address, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsRequestWritePhysicalMemory(PPS_REQUEST pRequest, uint64_t Address, void* pBuffer, uint64_t cbToWrite, uint64_t *pcbWritten);

PULSE_STATUS PsRequestGetContext(PPS_REQUEST pRequest, PPS_CTX pContext, uint64_t RegMask, PS_CPU_MODE *pCpuMode);
PULSE_STATUS PsRequestSetContext(PPS_REQUEST pRequest, PPS_CTX pContext, uint64_t RegMask);
PULSE_STATUS PsRequestGetExtendedContext(PPS_REQUEST pRequest, PPS_CTX_EXT pContextExt, uint8_t ExtRegSetIndex, uint64_t *pExtRegMask);
PULSE_STATUS PsRequestSetExtendedContext(PPS_REQUEST pRequest, PPS_CTX_EXT pContextExt, uint8_t ExtRegSetIndex, uint64_t *pExtRegMask);

PULSE_STATUS PsRequestReadIo(PPS_REQUEST pRequest, uint16_t Port, uint16_t AccessSize, void *pBuffer, uint32_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsRequestWriteIo(PPS_REQUEST pRequest, uint16_t Port, uint16_t AccessSize, void *pBuffer, uint32_t cbToWrite, uint64_t *pcbWritten);

PULSE_STATUS PsRequestGetStateInfo(PPS_REQUEST pRequest, PPS_STATE_INFO pStateInfo);
PULSE_STATUS PsRequestGetCpuInfo(PPS_REQUEST pRequest, uint8_t *pActiveCpu, uint8_t *pCpuCount);
PULSE_STATUS PsRequestCpuId(PPS_REQUEST pRequest, uint32_t Leaf, uint32_t Subleaf, PPS_CPUID_DATA pCpuIdData);

PULSE_STATUS PsRequestReadMsr(PPS_REQUEST pRequest, uint32_t MsrNumber, uint64_t *pMsrValue);
PULSE_STATUS PsRequestWriteMsr(PPS_REQUEST pRequest, uint32_t MsrNumber, uint64_t MsrValue);

PULSE_STATUS PsRequestSearchVirtualMemory(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint16_t Selector, uint64_t StartOffset, uint64_t EndOffset, void* pPattern, uint32_t PatternSize, uint32_t SearchStep, uint8_t IgnoreGaps, uint64_t *pResult);
PULSE_STATUS PsRequestSearchLinearMemory(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint64_t StartAddress, uint64_t EndAddress, void* pPattern, uint32_t PatternSize, uint32_t SearchStep, uint8_t IgnoreGaps, uint64_t *pResult);
PULSE_STATUS PsRequestSearchPhysicalMemory(PPS_REQUEST pRequest, uint64_t StartAddress, uint64_t EndAddress, void* pPattern, uint32_t PatternSize, uint32_t SearchStep, uint8_t IgnoreGaps, uint64_t *pResult);

PULSE_STATUS PsRequestWalkPageVirtual(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint16_t Selector, uint64_t Offset, PPS_PAGE_WALK_INFO pPageWalkInfo);
PULSE_STATUS PsRequestWalkPageLinear(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint64_t Address, PPS_PAGE_WALK_INFO pPageWalkInfo);

PULSE_STATUS PsRequestVirtualToPhysical(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint16_t Selector, uint64_t Offset, uint64_t *pPhysicalAddress);
PULSE_STATUS PsRequestLinearToPhysical(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint64_t Address, uint64_t *pPhysicalAddress);

PULSE_STATUS PsRequestSetBreakPoint(PPS_REQUEST pRequest, uint64_t PhysicalAddress, uint16_t *pBreakPointId);
PULSE_STATUS PsRequestRemoveBreakPoint(PPS_REQUEST pRequest, uint16_t BreakPointId);
PULSE_STATUS PsRequestClearBreakPoints(PPS_REQUEST pRequest);

PULSE_STATUS PsRequestAddBreakPointFilter(PPS_REQUEST pRequest, uint16_t BreakPointId, PPS_BREAK_POINT_FILTER_PARAMS pBreakPointFilterParams, uint16_t *pBreakPointFilterId);
PULSE_STATUS PsRequestRemoveBreakPointFilter(PPS_REQUEST pRequest, uint16_t BreakPointId, uint16_t BreakPointFilterId);
PULSE_STATUS PsRequestClearBreakPointFilters(PPS_REQUEST pRequest, uint16_t BreakPointId);

PULSE_STATUS PsRequestGetBreakPointInfo(PPS_REQUEST pRequest, PPS_BREAK_POINT_INFO pBreakPointInfoArray, uint16_t StartBreakPointId, uint16_t *pCount, uint16_t *pTotalCount);
PULSE_STATUS PsRequestGetBreakPointFilterInfo(PPS_REQUEST pRequest, PPS_BREAK_POINT_FILTER_INFO pBreakPointFilterInfoArray, uint16_t BreakPointId, uint16_t FiltersSkipCount, uint16_t *pCount);

PULSE_STATUS PsRequestReadMmioVirtual(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsRequestWriteMmioVirtual(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToWrite, uint64_t* pcbWritten);
PULSE_STATUS PsRequestReadMmioLinear(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint64_t Address, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsRequestWriteMmioLinear(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint64_t Address, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToWrite, uint64_t* pcbWritten);
PULSE_STATUS PsRequestReadMmioPhysical(PPS_REQUEST pRequest, uint64_t Address, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToRead, uint64_t *pcbRead);
PULSE_STATUS PsRequestWriteMmioPhysical(PPS_REQUEST pRequest, uint64_t Address, uint8_t AccessSize, PS_CACHE_TYPE *pCacheType, void* pBuffer, uint64_t cbToWrite, uint64_t* pcbWritten);

PULSE_STATUS PsRequestComputeSha1Virtual(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint16_t SelectorValue, uint64_t Offset, uint32_t cbToRead, PPS_SHA1_HASH pSha1Hash, uint32_t *pcbRead);
PULSE_STATUS PsRequestComputeSha1Linear(PPS_REQUEST pRequest, uint64_t PageTableAddress, uint64_t Address, uint32_t cbToRead, PPS_SHA1_HASH pSha1Hash, uint32_t *pcbRead);
PULSE_STATUS PsRequestComputeSha1Physical(PPS_REQUEST pRequest, uint64_t Address, uint32_t cbToRead, PPS_SHA1_HASH pSha1Hash, uint32_t *pcbRead);

uint64_t PsRequestGetMaxReadVirtualMemoryBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxWriteVirtualMemoryBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxReadLinearMemoryBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxWriteLinearMemoryBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxReadPhysicalMemoryBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxWritePhysicalMemoryBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxReadIoBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxWriteIoBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxSearchPatternSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxReadMmioVirtualBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxWriteMmioVirtualBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxReadMmioLinearBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxWriteMmioLinearBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxReadMmioPhysicalBufferSize(PPS_REQUEST pRequest);
uint64_t PsRequestGetMaxWriteMmioPhysicalBufferSize(PPS_REQUEST pRequest);