2025-05-13 19:45:22 +03:00

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