547 lines
12 KiB
C
547 lines
12 KiB
C
#ifndef _PH_PHSUP_H
|
|
#define _PH_PHSUP_H
|
|
|
|
// This header file provides some useful definitions specific to phlib.
|
|
|
|
#include <intrin.h>
|
|
#include <wchar.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
// Memory
|
|
|
|
#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset)))
|
|
#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset)))
|
|
#define ALIGN_UP_BY(Address, Align) (((ULONG_PTR)(Address) + (Align) - 1) & ~((Align) - 1))
|
|
#define ALIGN_UP_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_UP_BY(Pointer, Align))
|
|
#define ALIGN_UP(Address, Type) ALIGN_UP_BY(Address, sizeof(Type))
|
|
#define ALIGN_UP_POINTER(Pointer, Type) ((PVOID)ALIGN_UP(Pointer, Type))
|
|
|
|
#define PAGE_SIZE 0x1000
|
|
|
|
#define PH_LARGE_BUFFER_SIZE (256 * 1024 * 1024)
|
|
|
|
// Exceptions
|
|
|
|
#define PhRaiseStatus(Status) RtlRaiseStatus(Status)
|
|
|
|
#define SIMPLE_EXCEPTION_FILTER(Condition) \
|
|
((Condition) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
|
|
|
|
// Compiler
|
|
|
|
#ifdef DEBUG
|
|
#define ASSUME_ASSERT(Expression) assert(Expression)
|
|
#define ASSUME_NO_DEFAULT assert(FALSE)
|
|
#else
|
|
#define ASSUME_ASSERT(Expression) __assume(Expression)
|
|
#define ASSUME_NO_DEFAULT __assume(FALSE)
|
|
#endif
|
|
|
|
// Time
|
|
|
|
#define PH_TICKS_PER_NS ((LONG64)1 * 10)
|
|
#define PH_TICKS_PER_MS (PH_TICKS_PER_NS * 1000)
|
|
#define PH_TICKS_PER_SEC (PH_TICKS_PER_MS * 1000)
|
|
#define PH_TICKS_PER_MIN (PH_TICKS_PER_SEC * 60)
|
|
#define PH_TICKS_PER_HOUR (PH_TICKS_PER_MIN * 60)
|
|
#define PH_TICKS_PER_DAY (PH_TICKS_PER_HOUR * 24)
|
|
|
|
#define PH_TICKS_PARTIAL_MS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MS) % 1000)
|
|
#define PH_TICKS_PARTIAL_SEC(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_SEC) % 60)
|
|
#define PH_TICKS_PARTIAL_MIN(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_MIN) % 60)
|
|
#define PH_TICKS_PARTIAL_HOURS(Ticks) (((ULONG64)(Ticks) / PH_TICKS_PER_HOUR) % 24)
|
|
#define PH_TICKS_PARTIAL_DAYS(Ticks) ((ULONG64)(Ticks) / PH_TICKS_PER_DAY)
|
|
|
|
#define PH_TIMEOUT_MS PH_TICKS_PER_MS
|
|
#define PH_TIMEOUT_SEC PH_TICKS_PER_SEC
|
|
|
|
// Annotations
|
|
|
|
/**
|
|
* Indicates that a function assumes the specified number of references are available for the
|
|
* object.
|
|
*
|
|
* \remarks Usually functions reference objects if they store them for later usage; this annotation
|
|
* specifies that the caller must supply these extra references itself. In effect these references
|
|
* are "transferred" to the function and must not be used. E.g. if you create an object and
|
|
* immediately call a function with _Assume_refs_(1), you may no longer use the object since that
|
|
* one reference you held is no longer yours.
|
|
*/
|
|
#define _Assume_refs_(count)
|
|
|
|
#define _Callback_
|
|
|
|
/**
|
|
* Indicates that a function may raise a software exception.
|
|
*
|
|
* \remarks Do not use this annotation for temporary usages of exceptions, e.g. unimplemented
|
|
* functions.
|
|
*/
|
|
#define _May_raise_
|
|
|
|
/**
|
|
* Indicates that a function requires the specified value to be aligned at the specified number of
|
|
* bytes.
|
|
*/
|
|
#define _Needs_align_(align)
|
|
|
|
// Casts
|
|
|
|
// Zero extension and sign extension macros
|
|
#define C_1uTo2(x) ((unsigned short)(unsigned char)(x))
|
|
#define C_1sTo2(x) ((unsigned short)(signed char)(x))
|
|
#define C_1uTo4(x) ((unsigned int)(unsigned char)(x))
|
|
#define C_1sTo4(x) ((unsigned int)(signed char)(x))
|
|
#define C_2uTo4(x) ((unsigned int)(unsigned short)(x))
|
|
#define C_2sTo4(x) ((unsigned int)(signed short)(x))
|
|
#define C_4uTo8(x) ((unsigned __int64)(unsigned int)(x))
|
|
#define C_4sTo8(x) ((unsigned __int64)(signed int)(x))
|
|
|
|
// Sorting
|
|
|
|
typedef enum _PH_SORT_ORDER
|
|
{
|
|
NoSortOrder = 0,
|
|
AscendingSortOrder,
|
|
DescendingSortOrder
|
|
} PH_SORT_ORDER, *PPH_SORT_ORDER;
|
|
|
|
FORCEINLINE LONG PhModifySort(
|
|
_In_ LONG Result,
|
|
_In_ PH_SORT_ORDER Order
|
|
)
|
|
{
|
|
if (Order == AscendingSortOrder)
|
|
return Result;
|
|
else if (Order == DescendingSortOrder)
|
|
return -Result;
|
|
else
|
|
return Result;
|
|
}
|
|
|
|
#define PH_BUILTIN_COMPARE(value1, value2) \
|
|
if (value1 > value2) \
|
|
return 1; \
|
|
else if (value1 < value2) \
|
|
return -1; \
|
|
\
|
|
return 0
|
|
|
|
FORCEINLINE int charcmp(
|
|
_In_ signed char value1,
|
|
_In_ signed char value2
|
|
)
|
|
{
|
|
return C_1sTo4(value1 - value2);
|
|
}
|
|
|
|
FORCEINLINE int ucharcmp(
|
|
_In_ unsigned char value1,
|
|
_In_ unsigned char value2
|
|
)
|
|
{
|
|
PH_BUILTIN_COMPARE(value1, value2);
|
|
}
|
|
|
|
FORCEINLINE int shortcmp(
|
|
_In_ signed short value1,
|
|
_In_ signed short value2
|
|
)
|
|
{
|
|
return C_2sTo4(value1 - value2);
|
|
}
|
|
|
|
FORCEINLINE int ushortcmp(
|
|
_In_ unsigned short value1,
|
|
_In_ unsigned short value2
|
|
)
|
|
{
|
|
PH_BUILTIN_COMPARE(value1, value2);
|
|
}
|
|
|
|
FORCEINLINE int intcmp(
|
|
_In_ int value1,
|
|
_In_ int value2
|
|
)
|
|
{
|
|
return value1 - value2;
|
|
}
|
|
|
|
FORCEINLINE int uintcmp(
|
|
_In_ unsigned int value1,
|
|
_In_ unsigned int value2
|
|
)
|
|
{
|
|
PH_BUILTIN_COMPARE(value1, value2);
|
|
}
|
|
|
|
FORCEINLINE int int64cmp(
|
|
_In_ __int64 value1,
|
|
_In_ __int64 value2
|
|
)
|
|
{
|
|
PH_BUILTIN_COMPARE(value1, value2);
|
|
}
|
|
|
|
FORCEINLINE int uint64cmp(
|
|
_In_ unsigned __int64 value1,
|
|
_In_ unsigned __int64 value2
|
|
)
|
|
{
|
|
PH_BUILTIN_COMPARE(value1, value2);
|
|
}
|
|
|
|
FORCEINLINE int intptrcmp(
|
|
_In_ LONG_PTR value1,
|
|
_In_ LONG_PTR value2
|
|
)
|
|
{
|
|
PH_BUILTIN_COMPARE(value1, value2);
|
|
}
|
|
|
|
FORCEINLINE int uintptrcmp(
|
|
_In_ ULONG_PTR value1,
|
|
_In_ ULONG_PTR value2
|
|
)
|
|
{
|
|
PH_BUILTIN_COMPARE(value1, value2);
|
|
}
|
|
|
|
FORCEINLINE int singlecmp(
|
|
_In_ float value1,
|
|
_In_ float value2
|
|
)
|
|
{
|
|
PH_BUILTIN_COMPARE(value1, value2);
|
|
}
|
|
|
|
FORCEINLINE int doublecmp(
|
|
_In_ double value1,
|
|
_In_ double value2
|
|
)
|
|
{
|
|
PH_BUILTIN_COMPARE(value1, value2);
|
|
}
|
|
|
|
FORCEINLINE int wcsicmp2(
|
|
_In_opt_ PWSTR Value1,
|
|
_In_opt_ PWSTR Value2
|
|
)
|
|
{
|
|
if (Value1 && Value2)
|
|
return _wcsicmp(Value1, Value2);
|
|
else if (!Value1)
|
|
return !Value2 ? 0 : -1;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
typedef int (__cdecl *PC_COMPARE_FUNCTION)(void *, const void *, const void *);
|
|
|
|
// Synchronization
|
|
|
|
#ifndef _WIN64
|
|
|
|
#ifndef _InterlockedCompareExchangePointer
|
|
void *_InterlockedCompareExchangePointer(
|
|
void *volatile *Destination,
|
|
void *Exchange,
|
|
void *Comparand
|
|
);
|
|
#endif
|
|
|
|
#if (_MSC_VER < 1900)
|
|
#ifndef _InterlockedExchangePointer
|
|
FORCEINLINE void *_InterlockedExchangePointer(
|
|
void *volatile *Destination,
|
|
void *Exchange
|
|
)
|
|
{
|
|
return (PVOID)_InterlockedExchange(
|
|
(PLONG_PTR)Destination,
|
|
(LONG_PTR)Exchange
|
|
);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#endif
|
|
|
|
FORCEINLINE LONG_PTR _InterlockedExchangeAddPointer(
|
|
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend,
|
|
_In_ LONG_PTR Value
|
|
)
|
|
{
|
|
#ifdef _WIN64
|
|
return (LONG_PTR)_InterlockedExchangeAdd64((PLONG64)Addend, (LONG64)Value);
|
|
#else
|
|
return (LONG_PTR)_InterlockedExchangeAdd((PLONG)Addend, (LONG)Value);
|
|
#endif
|
|
}
|
|
|
|
FORCEINLINE LONG_PTR _InterlockedIncrementPointer(
|
|
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend
|
|
)
|
|
{
|
|
#ifdef _WIN64
|
|
return (LONG_PTR)_InterlockedIncrement64((PLONG64)Addend);
|
|
#else
|
|
return (LONG_PTR)_InterlockedIncrement((PLONG)Addend);
|
|
#endif
|
|
}
|
|
|
|
FORCEINLINE LONG_PTR _InterlockedDecrementPointer(
|
|
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Addend
|
|
)
|
|
{
|
|
#ifdef _WIN64
|
|
return (LONG_PTR)_InterlockedDecrement64((PLONG64)Addend);
|
|
#else
|
|
return (LONG_PTR)_InterlockedDecrement((PLONG)Addend);
|
|
#endif
|
|
}
|
|
|
|
FORCEINLINE BOOLEAN _InterlockedBitTestAndResetPointer(
|
|
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Base,
|
|
_In_ LONG_PTR Bit
|
|
)
|
|
{
|
|
#ifdef _WIN64
|
|
return _interlockedbittestandreset64((PLONG64)Base, (LONG64)Bit);
|
|
#else
|
|
return _interlockedbittestandreset((PLONG)Base, (LONG)Bit);
|
|
#endif
|
|
}
|
|
|
|
FORCEINLINE BOOLEAN _InterlockedBitTestAndSetPointer(
|
|
_Inout_ _Interlocked_operand_ LONG_PTR volatile *Base,
|
|
_In_ LONG_PTR Bit
|
|
)
|
|
{
|
|
#ifdef _WIN64
|
|
return _interlockedbittestandset64((PLONG64)Base, (LONG64)Bit);
|
|
#else
|
|
return _interlockedbittestandset((PLONG)Base, (LONG)Bit);
|
|
#endif
|
|
}
|
|
|
|
FORCEINLINE BOOLEAN _InterlockedIncrementNoZero(
|
|
_Inout_ _Interlocked_operand_ LONG volatile *Addend
|
|
)
|
|
{
|
|
LONG value;
|
|
LONG newValue;
|
|
|
|
value = *Addend;
|
|
|
|
while (TRUE)
|
|
{
|
|
if (value == 0)
|
|
return FALSE;
|
|
|
|
if ((newValue = _InterlockedCompareExchange(
|
|
Addend,
|
|
value + 1,
|
|
value
|
|
)) == value)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
value = newValue;
|
|
}
|
|
}
|
|
|
|
FORCEINLINE BOOLEAN _InterlockedIncrementPositive(
|
|
_Inout_ _Interlocked_operand_ LONG volatile *Addend
|
|
)
|
|
{
|
|
LONG value;
|
|
LONG newValue;
|
|
|
|
value = *Addend;
|
|
|
|
while (TRUE)
|
|
{
|
|
if (value <= 0)
|
|
return FALSE;
|
|
|
|
if ((newValue = _InterlockedCompareExchange(
|
|
Addend,
|
|
value + 1,
|
|
value
|
|
)) == value)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
value = newValue;
|
|
}
|
|
}
|
|
|
|
// Strings
|
|
|
|
#define PH_INT32_STR_LEN 12
|
|
#define PH_INT32_STR_LEN_1 (PH_INT32_STR_LEN + 1)
|
|
|
|
#define PH_INT64_STR_LEN 50
|
|
#define PH_INT64_STR_LEN_1 (PH_INT64_STR_LEN + 1)
|
|
|
|
#define PH_PTR_STR_LEN 24
|
|
#define PH_PTR_STR_LEN_1 (PH_PTR_STR_LEN + 1)
|
|
|
|
FORCEINLINE VOID PhPrintInt32(
|
|
_Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination,
|
|
_In_ LONG Int32
|
|
)
|
|
{
|
|
_ltow(Int32, Destination, 10);
|
|
}
|
|
|
|
FORCEINLINE VOID PhPrintUInt32(
|
|
_Out_writes_(PH_INT32_STR_LEN_1) PWSTR Destination,
|
|
_In_ ULONG UInt32
|
|
)
|
|
{
|
|
_ultow(UInt32, Destination, 10);
|
|
}
|
|
|
|
FORCEINLINE VOID PhPrintInt64(
|
|
_Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination,
|
|
_In_ LONG64 Int64
|
|
)
|
|
{
|
|
_i64tow(Int64, Destination, 10);
|
|
}
|
|
|
|
FORCEINLINE VOID PhPrintUInt64(
|
|
_Out_writes_(PH_INT64_STR_LEN_1) PWSTR Destination,
|
|
_In_ ULONG64 UInt64
|
|
)
|
|
{
|
|
_ui64tow(UInt64, Destination, 10);
|
|
}
|
|
|
|
FORCEINLINE VOID PhPrintPointer(
|
|
_Out_writes_(PH_PTR_STR_LEN_1) PWSTR Destination,
|
|
_In_ PVOID Pointer
|
|
)
|
|
{
|
|
Destination[0] = '0';
|
|
Destination[1] = 'x';
|
|
#ifdef _WIN64
|
|
_ui64tow((ULONG64)Pointer, &Destination[2], 16);
|
|
#else
|
|
_ultow((ULONG)Pointer, &Destination[2], 16);
|
|
#endif
|
|
}
|
|
|
|
// Misc.
|
|
|
|
FORCEINLINE ULONG PhCountBits(
|
|
_In_ ULONG Value
|
|
)
|
|
{
|
|
ULONG count = 0;
|
|
|
|
while (Value)
|
|
{
|
|
count++;
|
|
Value &= Value - 1;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
FORCEINLINE ULONG PhRoundNumber(
|
|
_In_ ULONG Value,
|
|
_In_ ULONG Granularity
|
|
)
|
|
{
|
|
return (Value + Granularity / 2) / Granularity * Granularity;
|
|
}
|
|
|
|
FORCEINLINE ULONG PhMultiplyDivide(
|
|
_In_ ULONG Number,
|
|
_In_ ULONG Numerator,
|
|
_In_ ULONG Denominator
|
|
)
|
|
{
|
|
return (ULONG)(((ULONG64)Number * (ULONG64)Numerator + Denominator / 2) / (ULONG64)Denominator);
|
|
}
|
|
|
|
FORCEINLINE LONG PhMultiplyDivideSigned(
|
|
_In_ LONG Number,
|
|
_In_ ULONG Numerator,
|
|
_In_ ULONG Denominator
|
|
)
|
|
{
|
|
if (Number >= 0)
|
|
return PhMultiplyDivide(Number, Numerator, Denominator);
|
|
else
|
|
return -(LONG)PhMultiplyDivide(-Number, Numerator, Denominator);
|
|
}
|
|
|
|
FORCEINLINE VOID PhProbeAddress(
|
|
_In_ PVOID UserAddress,
|
|
_In_ SIZE_T UserLength,
|
|
_In_ PVOID BufferAddress,
|
|
_In_ SIZE_T BufferLength,
|
|
_In_ ULONG Alignment
|
|
)
|
|
{
|
|
if (UserLength != 0)
|
|
{
|
|
if (((ULONG_PTR)UserAddress & (Alignment - 1)) != 0)
|
|
PhRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
|
|
|
|
if (
|
|
((ULONG_PTR)UserAddress + UserLength < (ULONG_PTR)UserAddress) ||
|
|
((ULONG_PTR)UserAddress < (ULONG_PTR)BufferAddress) ||
|
|
((ULONG_PTR)UserAddress + UserLength > (ULONG_PTR)BufferAddress + BufferLength)
|
|
)
|
|
PhRaiseStatus(STATUS_ACCESS_VIOLATION);
|
|
}
|
|
}
|
|
|
|
FORCEINLINE PLARGE_INTEGER PhTimeoutFromMilliseconds(
|
|
_Out_ PLARGE_INTEGER Timeout,
|
|
_In_ ULONG Milliseconds
|
|
)
|
|
{
|
|
if (Milliseconds == INFINITE)
|
|
return NULL;
|
|
|
|
Timeout->QuadPart = -(LONGLONG)UInt32x32To64(Milliseconds, PH_TIMEOUT_MS);
|
|
|
|
return Timeout;
|
|
}
|
|
|
|
FORCEINLINE NTSTATUS PhGetLastWin32ErrorAsNtStatus()
|
|
{
|
|
ULONG win32Result;
|
|
|
|
// This is needed because NTSTATUS_FROM_WIN32 uses the argument multiple times.
|
|
win32Result = GetLastError();
|
|
|
|
return NTSTATUS_FROM_WIN32(win32Result);
|
|
}
|
|
|
|
FORCEINLINE PVOID PhGetModuleProcAddress(
|
|
_In_ PWSTR ModuleName,
|
|
_In_ PSTR ProcName
|
|
)
|
|
{
|
|
HMODULE module;
|
|
|
|
module = GetModuleHandle(ModuleName);
|
|
|
|
if (module)
|
|
return GetProcAddress(module, ProcName);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|