Made unit tests for and fixed all functions from rtlsupportapi.h

pull/83/head
David Hall 2019-07-11 14:52:17 -06:00
parent c05c582a90
commit db7652bc21
4 changed files with 393 additions and 93 deletions

View File

@ -1,6 +1,5 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Vanara.PInvoke
{
@ -8,121 +7,196 @@ namespace Vanara.PInvoke
{
/// <summary>Adds a dynamic function table to the dynamic function table list.</summary>
/// <param name="FunctionTable">
/// A pointer to an array of function entries. For a definition of the <c>PRUNTIME_FUNCTION</c> type, see WinNT.h. For more information on runtime
/// function entries, see the calling convention documentation for the processor.
/// A pointer to an array of function entries. For a definition of the <c>PRUNTIME_FUNCTION</c> type, see rtlsupportapi.h. For more
/// information on runtime function entries, see the calling convention documentation for the processor.
/// </param>
/// <param name="EntryCount">The number of entries in the FunctionTable array.</param>
/// <param name="BaseAddress">The base address to use when computing full virtual addresses from relative virtual addresses of function table entries.</param>
/// <param name="TargetGp">
/// <para>The target global pointer. This is part of the Intel IPF calling convention. It is a pointer to a data area in an image.</para>
/// <para>This parameter does not exist on x64.</para>
/// <param name="BaseAddress">
/// The base address to use when computing full virtual addresses from relative virtual addresses of function table entries.
/// </param>
/// <returns>If the function succeeds, the return value is <c>TRUE</c>. Otherwise, the return value is <c>FALSE</c>.</returns>
// BOOLEAN WINAPI RtlAddFunctionTable( _In_ PRUNTIME_FUNCTION FunctionTable, _In_ DWORD EntryCount, _In_ DWORD64 BaseAddress, _In_ ULONGLONG TargetGp);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680588(v=vs.85).aspx
/// <remarks>
/// <para>
/// Function tables are used on 64-bit Windows to determine how to unwind or walk the stack. These tables are usually generated by
/// the compiler and stored as part of the image. However, applications must provide the function table for dynamically generated
/// code. For more information about function tables, see the architecture guide for your system.
/// </para>
/// <para>
/// This function is useful for code that is generated from a template or generated only once during the life of the process. For
/// more dynamically generated code, use the RtlInstallFunctionTableCallback function.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtladdfunctiontable NTSYSAPI BOOLEAN RtlAddFunctionTable(
// PRUNTIME_FUNCTION FunctionTable, DWORD EntryCount, DWORD64 BaseAddress );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinNT.h", MSDNShortId = "ms680588")]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "4717f29e-c5f8-4b02-a7c8-edd065f1c793")]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool RtlAddFunctionTable(IntPtr FunctionTable, uint EntryCount, ulong BaseAddress, ulong TargetGp);
public static extern bool RtlAddFunctionTable([In] IMAGE_RUNTIME_FUNCTION_ENTRY[] FunctionTable, uint EntryCount, ulong BaseAddress);
/// <summary>Retrieves a context record in the context of the caller.</summary>
/// <param name="ContextRecord">A pointer to a <c>CONTEXT</c> structure.</param>
/// <param name="ContextRecord">A pointer to a CONTEXT structure.</param>
/// <returns>This function does not return a value.</returns>
// VOID WINAPI RtlCaptureContext( _Out_ PCONTEXT ContextRecord); https://msdn.microsoft.com/en-us/library/windows/desktop/ms680591(v=vs.85).aspx
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlcapturecontext NTSYSAPI VOID RtlCaptureContext( PCONTEXT
// ContextRecord );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinNT.h", MSDNShortId = "ms680591")]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "e2ce0cde-43ab-4681-be66-bd7509fd6ca2")]
public static extern void RtlCaptureContext(ref CONTEXT ContextRecord);
/// <summary>Removes a dynamic function table from the dynamic function table list.</summary><param name="FunctionTable">A pointer to an array of function entries that were previously passed to <c>RtlAddFunctionTable</c> or an identifier previously passed to <c>RtlInstallFunctionTableCallback</c>. For a definition of the <c>PRUNTIME_FUNCTION</c> type, see WinNT.h.</param><returns>If the function succeeds, the return value is <c>TRUE</c>. Otherwise, the return value is <c>FALSE</c>.</returns>
// BOOLEAN WINAPI RtlDeleteFunctionTable( _In_ PRUNTIME_FUNCTION FunctionTable);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680593(v=vs.85).aspx
/// <summary>Retrieves a context record in the context of the caller.</summary>
/// <param name="contextFlags">
/// The context flags to specify what aspects of the context to capture. See <see cref="CONTEXT_FLAG"/> for pre-configured values.
/// </param>
/// <returns>The captured <c>CONTEXT</c> structure.</returns>
[PInvokeData("rtlsupportapi.h", MSDNShortId = "e2ce0cde-43ab-4681-be66-bd7509fd6ca2")]
public static CONTEXT RtlCaptureContext(uint contextFlags = uint.MaxValue)
{
if (contextFlags == uint.MaxValue) contextFlags = CONTEXT_FLAG.CONTEXT_ALL;
var ctx = new CONTEXT { ContextFlags = contextFlags };
RtlCaptureContext(ref ctx);
return ctx;
}
/// <summary>Removes a dynamic function table from the dynamic function table list.</summary>
/// <param name="FunctionTable">
/// A pointer to an array of function entries that were previously passed to RtlAddFunctionTable or an identifier previously passed
/// to RtlInstallFunctionTableCallback. For a definition of the <c>PRUNTIME_FUNCTION</c> type, see rtlsupportapi.h.
/// </param>
/// <returns>If the function succeeds, the return value is <c>TRUE</c>. Otherwise, the return value is <c>FALSE</c>.</returns>
/// <remarks>
/// Function tables are used on 64-bit Windows to determine how to unwind or walk the stack. These tables are usually generated by
/// the compiler and stored as part of the image. However, applications must provide the function table for dynamically generated
/// code. For more information about function tables, see the architecture guide for your system.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtldeletefunctiontable NTSYSAPI BOOLEAN RtlDeleteFunctionTable(
// PRUNTIME_FUNCTION FunctionTable );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinNT.h", MSDNShortId = "ms680593")]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "42bc3d83-8053-40e9-b153-f68733d0cb2b")]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool RtlDeleteFunctionTable(IntPtr FunctionTable);
public static extern bool RtlDeleteFunctionTable([In] IMAGE_RUNTIME_FUNCTION_ENTRY[] FunctionTable);
/// <summary>Adds a dynamic function table to the dynamic function table list.</summary><param name="TableIdentifier">The identifier for the dynamic function table callback. The two low-order bits must be set. For example, BaseAddress|0x3.</param><param name="BaseAddress">The base address of the region of memory managed by the callback function.</param><param name="Length">The size of the region of memory managed by the callback function, in bytes.</param><param name="Callback">A pointer to the callback function that is called to retrieve the function table entries for the functions in the specified region of memory. For a definition of the <c>PGET_RUNTIME_FUNCTION_CALLBACK</c> type, see WinNT.h.</param><param name="Context">A pointer to the user-defined data to be passed to the callback function.</param><param name="OutOfProcessCallbackDll"><para>An optional pointer to a string that specifies the path of a DLL that provides function table entries that are outside the process.</para><para>When a debugger unwinds to a function in the range of addresses managed by the callback function, it loads this DLL and calls the <c>OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME</c> function, whose type is <c>POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK</c>. For more information, see the definitions of these items in WinNT.h.</para></param><returns>If the function succeeds, the return value is <c>TRUE</c>. If the function fails, the return value is <c>FALSE</c>.</returns>
// BOOLEAN WINAPI RtlInstallFunctionTableCallback( _In_ DWORD64 TableIdentifier, _In_ DWORD64 BaseAddress, _In_ DWORD Length, _In_ PGET_RUNTIME_FUNCTION_CALLBACK Callback, _In_ PVOID Context, _In_ PCWSTR OutOfProcessCallbackDll);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680595(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)]
[PInvokeData("WinNT.h", MSDNShortId = "ms680595")]
/// <summary>Removes a dynamic function table from the dynamic function table list.</summary>
/// <param name="FunctionTable">
/// A pointer to an array of function entries that were previously passed to RtlAddFunctionTable or an identifier previously passed
/// to RtlInstallFunctionTableCallback. For a definition of the <c>PRUNTIME_FUNCTION</c> type, see rtlsupportapi.h.
/// </param>
/// <returns>If the function succeeds, the return value is <c>TRUE</c>. Otherwise, the return value is <c>FALSE</c>.</returns>
/// <remarks>
/// Function tables are used on 64-bit Windows to determine how to unwind or walk the stack. These tables are usually generated by
/// the compiler and stored as part of the image. However, applications must provide the function table for dynamically generated
/// code. For more information about function tables, see the architecture guide for your system.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtldeletefunctiontable NTSYSAPI BOOLEAN RtlDeleteFunctionTable(
// PRUNTIME_FUNCTION FunctionTable );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "42bc3d83-8053-40e9-b153-f68733d0cb2b")]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool RtlInstallFunctionTableCallback(ulong TableIdentifier, ulong BaseAddress, uint Length, PGET_RUNTIME_FUNCTION_CALLBACK Callback, IntPtr Context, [Optional] string OutOfProcessCallbackDll);
public static extern bool RtlDeleteFunctionTable([In] ulong FunctionTable);
/// <summary>Retrieves the function table entries for the functions in the specified region of memory.</summary>
/// <param name="ControlPc">The control address.</param>
/// <param name="Context">A pointer to the user-defined data to be passed from the function call.</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
[PInvokeData("WinNT.h")]
public delegate IntPtr PGET_RUNTIME_FUNCTION_CALLBACK(uint ControlPc, IntPtr Context);
/// <summary>Adds a dynamic function table to the dynamic function table list.</summary>
/// <param name="TableIdentifier">
/// The identifier for the dynamic function table callback. The two low-order bits must be set. For example, BaseAddress|0x3.
/// </param>
/// <param name="BaseAddress">The base address of the region of memory managed by the callback function.</param>
/// <param name="Length">The size of the region of memory managed by the callback function, in bytes.</param>
/// <param name="Callback">
/// A pointer to the callback function that is called to retrieve the function table entries for the functions in the specified
/// region of memory. For a definition of the <c>PGET_RUNTIME_FUNCTION_CALLBACK</c> type, see rtlsupportapi.h.
/// </param>
/// <param name="Context">A pointer to the user-defined data to be passed to the callback function.</param>
/// <param name="OutOfProcessCallbackDll">
/// <para>
/// An optional pointer to a string that specifies the path of a DLL that provides function table entries that are outside the process.
/// </para>
/// <para>
/// When a debugger unwinds to a function in the range of addresses managed by the callback function, it loads this DLL and calls the
/// <c>OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME</c> function, whose type is <c>POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK</c>.
/// For more information, see the definitions of these items in rtlsupportapi.h.
/// </para>
/// </param>
/// <returns>If the function succeeds, the return value is <c>TRUE</c>. If the function fails, the return value is <c>FALSE</c>.</returns>
/// <remarks>
/// <para>
/// Function tables are used on 64-bit Windows to determine how to unwind or walk the stack. These tables are usually generated by
/// the compiler and stored as part of the image. However, applications must provide the function table for dynamically generated
/// code. For more information about function tables, see the architecture guide for your system.
/// </para>
/// <para>
/// This function is useful for very dynamic code. The application specifies the memory range for the generated code, but does not
/// need to generate a table until it is needed by an unwind request. At that time, the system calls the callback function with the
/// Context and the control address. The callback function must return the runtime function entry for the specified address. Be sure
/// to avoid creating a deadlock between the callback function and the code generator.
/// </para>
/// <para>
/// For code that is generated from a template or generated only once during the life of the process, use the RtlAddFunctionTable function.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlinstallfunctiontablecallback NTSYSAPI BOOLEAN
// RtlInstallFunctionTableCallback( DWORD64 TableIdentifier, DWORD64 BaseAddress, DWORD Length, PGET_RUNTIME_FUNCTION_CALLBACK
// Callback, PVOID Context, PCWSTR OutOfProcessCallbackDll );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "63b35b17-0b0e-46ed-9dbf-98290ab08bd1")]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool RtlInstallFunctionTableCallback(ulong TableIdentifier, ulong BaseAddress, uint Length, PGET_RUNTIME_FUNCTION_CALLBACK Callback, IntPtr Context = default, [MarshalAs(UnmanagedType.LPWStr)] string OutOfProcessCallbackDll = null);
/// <summary>Searches the active function tables for an entry that corresponds to the specified PC value.</summary>
/// <param name="ControlPc">The virtual address of an instruction bundle within the function.</param>
/// <param name="ImageBase">The base address of module to which the function belongs.</param>
/// <param name="TargetGp">
/// <param name="HistoryTable">
/// <para>The global pointer value of the module.</para>
/// <para>This parameter has a different declaration on x64 and ARM systems. For more information, see x64 Definition and ARM Definition.</para>
/// </param>
/// <returns>
/// If there is no entry in the function table for the specified PC, the function returns <c>NULL</c>. Otherwise, the function returns the address of the
/// function table entry that corresponds to the specified PC.
/// If there is no entry in the function table for the specified PC, the function returns <c>NULL</c>. Otherwise, the function
/// returns the address of the function table entry that corresponds to the specified PC.
/// </returns>
// PVOID WINAPI RtlLookupFunctionEntry( _In_ ULONGLONG ControlPc, _Out_ PULONGLONG ImageBase, _Out_ PULONGLONG TargetGp);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680597(v=vs.85).aspx
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtllookupfunctionentry NTSYSAPI PRUNTIME_FUNCTION
// RtlLookupFunctionEntry( DWORD64 ControlPc, PDWORD64 ImageBase, PUNWIND_HISTORY_TABLE HistoryTable );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinNT.h", MSDNShortId = "ms680597")]
public static extern IntPtr RtlLookupFunctionEntry(ulong ControlPc, out ulong ImageBase, out ulong TargetGp);
/// <summary>Moves a block of memory from one location to another.</summary>
/// <param name="Destination">A pointer to the starting address of the move destination.</param>
/// <param name="Source">A pointer to the starting address of the block of memory to be moved.</param>
/// <param name="Length">The size of the block of memory to move, in bytes.</param>
/// <returns>This function has no return value.</returns>
// void MoveMemory( _In_ PVOID Destination, _In_ const VOID *Source, _In_ SIZE_T Length);
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366788(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = false, EntryPoint = "RtlMoveMemory")]
[PInvokeData("WinBase.h", MSDNShortId = "aa366788")]
public static extern void MoveMemory(IntPtr Destination, IntPtr Source, SizeT Length);
[PInvokeData("rtlsupportapi.h", MSDNShortId = "624b97fb-0453-4f47-b6bd-92aa14705e78")]
public static extern IntPtr RtlLookupFunctionEntry(ulong ControlPc, out ulong ImageBase, out UNWIND_HISTORY_TABLE HistoryTable);
/// <summary>Retrieves the base address of the image that contains the specified PC value.</summary>
/// <param name="PcValue">
/// The PC value. The function searches all modules mapped into the address space of the calling process for a module that contains this value.
/// The PC value. The function searches all modules mapped into the address space of the calling process for a module that contains
/// this value.
/// </param>
/// <param name="BaseOfImage">
/// The base address of the image containing the PC value. This value must be added to any relative addresses in the headers to locate the image.
/// The base address of the image containing the PC value. This value must be added to any relative addresses in the headers to
/// locate the image.
/// </param>
/// <returns>
/// <para>If the PC value is found, the function returns the base address of the image that contains the PC value.</para>
/// <para>If no image contains the PC value, the function returns <c>NULL</c>.</para>
/// </returns>
// PVOID WINAPI RtlPcToFileHeader( _In_ PVOID PcValue, _Out_ PVOID *BaseOfImage);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680603(v=vs.85).aspx
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlpctofileheader NTSYSAPI PVOID RtlPcToFileHeader( PVOID
// PcValue, PVOID *BaseOfImage );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinNT.h", MSDNShortId = "ms680603")]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "690c9f20-d471-49c9-a40c-28926f03acac")]
public static extern IntPtr RtlPcToFileHeader(IntPtr PcValue, out IntPtr BaseOfImage);
/// <summary>Restores the context of the caller to the specified context record.</summary>
/// <param name="ContextRecord">A pointer to a <c>CONTEXT</c> structure.</param>
/// <param name="ContextRecord">A pointer to a CONTEXT structure.</param>
/// <param name="ExceptionRecord">
/// <para>A pointer to an <c>EXCEPTION_RECORD</c> structure. This parameter is optional and should typically be <c>NULL</c>.</para>
/// <para>A pointer to an EXCEPTION_RECORD structure. This parameter is optional and should typically be <c>NULL</c>.</para>
/// <para>
/// An exception record is used primarily with long jump and C++ catch-throw support. If the <c>ExceptionCode</c> member is STATUS_LONGJUMP, the
/// <c>ExceptionInformation</c> member contains a pointer to a jump buffer. <c>RtlRestoreContext</c> will copy the non-volatile state from the jump
/// buffer in to the context record before the context record is restored.
/// An exception record is used primarily with long jump and C++ catch-throw support. If the <c>ExceptionCode</c> member is
/// STATUS_LONGJUMP, the <c>ExceptionInformation</c> member contains a pointer to a jump buffer. <c>RtlRestoreContext</c> will copy
/// the non-volatile state from the jump buffer in to the context record before the context record is restored.
/// </para>
/// <para>
/// If the <c>ExceptionCode</c> member is STATUS_UNWIND_CONSOLIDATE, the <c>ExceptionInformation</c> member contains a pointer to a callback function,
/// such as a catch handler. <c>RtlRestoreContext</c> consolidates the call frames between its frame and the frame specified in the context record before
/// calling the callback function. This hides frames from any exception handling that might occur in the callback function. The difference between this
/// and a typical unwind is that the data on the stack is still present, so frame data such as a throw object is still available. The callback function
/// returns a new program counter to update in the context record, which is then used in a normal restore context.
/// If the <c>ExceptionCode</c> member is STATUS_UNWIND_CONSOLIDATE, the <c>ExceptionInformation</c> member contains a pointer to a
/// callback function, such as a catch handler. <c>RtlRestoreContext</c> consolidates the call frames between its frame and the frame
/// specified in the context record before calling the callback function. This hides frames from any exception handling that might
/// occur in the callback function. The difference between this and a typical unwind is that the data on the stack is still present,
/// so frame data such as a throw object is still available. The callback function returns a new program counter to update in the
/// context record, which is then used in a normal restore context.
/// </para>
/// </param>
/// <returns>This function does not return a value.</returns>
// VOID WINAPI RtlRestoreContext( _In_ PCONTEXT ContextRecord, _In_ PEXCEPTION_RECORD ExceptionRecord); https://msdn.microsoft.com/en-us/library/windows/desktop/ms680605(v=vs.85).aspx
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlrestorecontext NTSYSAPI VOID RtlRestoreContext( PCONTEXT
// ContextRecord, _EXCEPTION_RECORD *ExceptionRecord );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinNT.h", MSDNShortId = "ms680605")]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "f5304d17-bc67-4e0f-a535-efca4e65c74c")]
public static extern void RtlRestoreContext(ref CONTEXT ContextRecord, ref EXCEPTION_RECORD ExceptionRecord);
/// <summary>Initiates an unwind of procedure call frames.</summary>
@ -130,31 +204,66 @@ namespace Vanara.PInvoke
/// A pointer to the call frame that is the target of the unwind. If this parameter is <c>NULL</c>, the function performs an exit unwind.
/// </param>
/// <param name="TargetIp">The continuation address of the unwind. This parameter is ignored if TargetFrame is <c>NULL</c>.</param>
/// <param name="ExceptionRecord">A pointer to an <c>EXCEPTION_RECORD</c> structure.</param>
/// <param name="ExceptionRecord">A pointer to an EXCEPTION_RECORD structure.</param>
/// <param name="ReturnValue">A value to be placed in the integer function return register before continuing execution.</param>
/// <returns>This function does not return a value.</returns>
// void WINAPI RtlUnwind( _In_opt_ PVOID TargetFrame, _In_opt_ PVOID TargetIp, _In_opt_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID ReturnValue); https://msdn.microsoft.com/en-us/library/windows/desktop/ms680609(v=vs.85).aspx
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlunwind NTSYSAPI VOID RtlUnwind( PVOID TargetFrame, PVOID
// TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinNT.h", MSDNShortId = "ms680609")]
public static extern void RtlUnwind(IntPtr TargetFrame, IntPtr TargetIp, ref EXCEPTION_RECORD ExceptionRecord, IntPtr ReturnValue);
[PInvokeData("rtlsupportapi.h", MSDNShortId = "254b2547-9d3d-468f-a360-20a12e9dd82e")]
public static extern void RtlUnwind([In, Optional] IntPtr TargetFrame, [In, Optional] IntPtr TargetIp, in EXCEPTION_RECORD ExceptionRecord, IntPtr ReturnValue);
/// <summary>Initiates an unwind of procedure call frames.</summary>
/// <param name="TargetFrame">
/// A pointer to the call frame that is the target of the unwind. If this parameter is <c>NULL</c>, the function performs an exit unwind.
/// </param>
/// <param name="TargetIp">The continuation address of the unwind. This parameter is ignored if TargetFrame is <c>NULL</c>.</param>
/// <param name="ExceptionRecord">A pointer to an <c>EXCEPTION_RECORD</c> structure.</param>
/// <param name="ExceptionRecord">A pointer to an EXCEPTION_RECORD structure.</param>
/// <param name="ReturnValue">A value to be placed in the integer function return register before continuing execution.</param>
/// <param name="OriginalContext">A pointer to a <c>CONTEXT</c> structure that stores context during the unwind operation.</param>
/// <returns>This function does not return a value.</returns>
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlunwind NTSYSAPI VOID RtlUnwind( PVOID TargetFrame, PVOID
// TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "254b2547-9d3d-468f-a360-20a12e9dd82e")]
public static extern void RtlUnwind([In, Optional] IntPtr TargetFrame, [In, Optional] IntPtr TargetIp, [In, Optional] IntPtr ExceptionRecord, IntPtr ReturnValue);
/// <summary>Initiates an unwind of procedure call frames.</summary>
/// <param name="TargetFrame">
/// A pointer to the call frame that is the target of the unwind. If this parameter is <c>NULL</c>, the function performs an exit unwind.
/// </param>
/// <param name="TargetIp">The continuation address of the unwind. This parameter is ignored if TargetFrame is <c>NULL</c>.</param>
/// <param name="ExceptionRecord">A pointer to an EXCEPTION_RECORD structure.</param>
/// <param name="ReturnValue">A value to be placed in the integer function return register before continuing execution.</param>
/// <param name="ContextRecord">A pointer to a CONTEXT structure that stores context during the unwind operation.</param>
/// <param name="HistoryTable">
/// A pointer to the unwind history table. This structure is processor specific. For definitions of this structure, see Winternl.h.
/// </param>
/// <returns>This function does not return a value.</returns>
// void WINAPI RtlUnwindEx( _In_opt_ PVOID TargetFrame, _In_opt_ PVOID TargetIp, _In_opt_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID ReturnValue, _In_
// PCONTEXT OriginalContext, _In_opt_ PUNWIND_HISTORY_TABLE HistoryTable); https://msdn.microsoft.com/en-us/library/windows/desktop/ms680615(v=vs.85).aspx
/// <remarks>The <c>FRAME_POINTERS</c> structure is defined as follows:</remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlunwindex NTSYSAPI VOID RtlUnwindEx( PVOID TargetFrame, PVOID
// TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinNT.h", MSDNShortId = "ms680615")]
public static extern void RtlUnwindEx(IntPtr TargetFrame, IntPtr TargetIp, ref EXCEPTION_RECORD ExceptionRecord, IntPtr ReturnValue, ref CONTEXT OriginalContext, IntPtr HistoryTable);
[PInvokeData("rtlsupportapi.h", MSDNShortId = "3d2d8778-311e-4cc1-b280-4f83ab457755")]
public static extern void RtlUnwindEx([In, Optional] IntPtr TargetFrame, [In, Optional] IntPtr TargetIp, in EXCEPTION_RECORD ExceptionRecord, IntPtr ReturnValue, in CONTEXT OriginalContext, in UNWIND_HISTORY_TABLE HistoryTable);
/// <summary>Initiates an unwind of procedure call frames.</summary>
/// <param name="TargetFrame">
/// A pointer to the call frame that is the target of the unwind. If this parameter is <c>NULL</c>, the function performs an exit unwind.
/// </param>
/// <param name="TargetIp">The continuation address of the unwind. This parameter is ignored if TargetFrame is <c>NULL</c>.</param>
/// <param name="ExceptionRecord">A pointer to an EXCEPTION_RECORD structure.</param>
/// <param name="ReturnValue">A value to be placed in the integer function return register before continuing execution.</param>
/// <param name="ContextRecord">A pointer to a CONTEXT structure that stores context during the unwind operation.</param>
/// <param name="HistoryTable">
/// A pointer to the unwind history table. This structure is processor specific. For definitions of this structure, see Winternl.h.
/// </param>
/// <returns>This function does not return a value.</returns>
/// <remarks>The <c>FRAME_POINTERS</c> structure is defined as follows:</remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlunwindex NTSYSAPI VOID RtlUnwindEx( PVOID TargetFrame, PVOID
// TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "3d2d8778-311e-4cc1-b280-4f83ab457755")]
public static extern void RtlUnwindEx([In, Optional] IntPtr TargetFrame, [In, Optional] IntPtr TargetIp, [In, Optional] IntPtr ExceptionRecord, IntPtr ReturnValue, in CONTEXT OriginalContext, [In, Optional] IntPtr HistoryTable);
/*
public static extern void RtlCaptureStackBackTrace();
@ -194,29 +303,30 @@ namespace Vanara.PInvoke
/// <param name="ImageBase">The base address of the module to which the function belongs.</param>
/// <param name="ControlPC">The virtual address where control left the specified function.</param>
/// <param name="FunctionEntry">
/// The address of the function table entry for the specified function. To obtain the function table entry, call the <c>RtlLookupFunctionEntry</c> function.
/// The address of the function table entry for the specified function. To obtain the function table entry, call the
/// <c>RtlLookupFunctionEntry</c> function.
/// </param>
/// <param name="ContextRecord">A pointer to a <c>CONTEXT</c> structure that represents the context of the previous frame.</param>
/// <param name="InFunction">
/// <para>
/// The location of the PC. If this parameter is 0, the PC is in the prologue, epilogue, or a null frame region of the function. If this parameter is 1,
/// the PC is in the body of the function.
/// The location of the PC. If this parameter is 0, the PC is in the prologue, epilogue, or a null frame region of the function. If
/// this parameter is 1, the PC is in the body of the function.
/// </para>
/// <para>This parameter is not present on x64.</para>
/// </param>
/// <param name="EstablisherFrame">
/// <para>
/// A pointer to a <c>FRAME_POINTERS</c> structure that receives the establisher frame pointer value. The real frame pointer is defined only if
/// InFunction is 1.
/// A pointer to a <c>FRAME_POINTERS</c> structure that receives the establisher frame pointer value. The real frame pointer is
/// defined only if InFunction is 1.
/// </para>
/// <para>This parameter is of type <c>PULONG64</c> on x64.</para>
/// </param>
/// <param name="ContextPointers">An optional pointer to a context pointers structure.</param>
/// <returns>This function returns a pointer to an EXCEPTION_ROUTINE callback function.</returns>
// PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( _In_ HandlerType, _In_ ImageBase, _In_ ControlPC, _In_ FunctionEntry, _Inout_ ContextRecord, _Out_ InFunction, _Out_ EstablisherFrame, _Inout_opt_ ContextPointers);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680617(v=vs.85).aspx
// PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind( _In_ HandlerType, _In_ ImageBase, _In_ ControlPC, _In_ FunctionEntry, _Inout_
// ContextRecord, _Out_ InFunction, _Out_ EstablisherFrame, _Inout_opt_ ContextPointers); https://msdn.microsoft.com/en-us/library/windows/desktop/ms680617(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = false, EntryPoint = "RtlVirtualUnwind")]
[PInvokeData("WinNT.h", MSDNShortId = "ms680617")]
[PInvokeData("rtlsupportapi.h", MSDNShortId = "ms680617")]
public static extern EXCEPTION_ROUTINE RtlVirtualUnwindX64(UNW_FLAGS HandlerType, UIntPtr ImageBase, UIntPtr ControlPC, IntPtr FunctionEntry, ref CONTEXT ContextRecord, out IntPtr HandlerData, out ulong EstablisherFrame, IntPtr ContextPointers);
/// <summary>The handler type.</summary>
@ -237,13 +347,5 @@ namespace Vanara.PInvoke
public delegate EXCEPTION_DISPOSITION EXCEPTION_ROUTINE(ref EXCEPTION_RECORD ExceptionRecord, IntPtr EstablisherFrame, ref CONTEXT ContextRecord, IntPtr DispatcherContext);
*/
/// <summary>The RtlZeroMemory routine fills a block of memory with zeros, given a pointer to the block and the length, in bytes, to be filled.</summary>
/// <param name="Destination">A pointer to the memory block to be filled with zeros.</param>
/// <param name="Length">The number of bytes to fill with zeros.</param>
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-rtlzeromemory
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinNT.h")]
public static extern void RtlZeroMemory(IntPtr Destination, SizeT Length);
}
}

View File

@ -6,6 +6,20 @@ namespace Vanara.PInvoke
{
public static partial class Kernel32
{
public const string OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME = "OutOfProcessFunctionTableCallback";
/// <summary>Retrieves the function table entries for the functions in the specified region of memory.</summary>
/// <param name="ControlPc">The control address.</param>
/// <param name="Context">A pointer to the user-defined data to be passed from the function call.</param>
/// <returns>Pointer to a <see cref="IMAGE_RUNTIME_FUNCTION_ENTRY"/> structure.</returns>
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
[PInvokeData("WinNT.h")]
public delegate IntPtr PGET_RUNTIME_FUNCTION_CALLBACK(IntPtr ControlPc, IntPtr Context);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
[PInvokeData("WinNT.h")]
public delegate uint POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK(HPROCESS Process, IntPtr TableAddress, out uint Entries, [Out] IMAGE_RUNTIME_FUNCTION_ENTRY[] Functions);
/// <summary>
/// <para>
/// An application-defined function previously registered with the AddSecureMemoryCacheCallback function that is called when a
@ -322,6 +336,44 @@ namespace Vanara.PInvoke
VER_PRODUCT_TYPE = 0x0000080,
}
/// <summary>
/// Copies the contents of a source memory block to a destination memory block, and supports overlapping source and destination
/// memory blocks.
/// </summary>
/// <param name="Destination">A pointer to the destination memory block to copy the bytes to.</param>
/// <param name="Source">A pointer to the source memory block to copy the bytes from.</param>
/// <param name="Length">The number of bytes to copy from the source to the destination.</param>
/// <returns>None</returns>
/// <remarks>
/// <para>
/// The source memory block, which is defined by Source and Length, can overlap the destination memory block, which is defined by
/// Destination and Length.
/// </para>
/// <para>
/// The <c>RtlCopyMemory</c> routine runs faster than <c>RtlMoveMemory</c>, but <c>RtlCopyMemory</c> requires that the source and
/// destination memory blocks do not overlap.
/// </para>
/// <para>
/// Callers of <c>RtlMoveMemory</c> can be running at any IRQL if the source and destination memory blocks are in nonpaged system
/// memory. Otherwise, the caller must be running at IRQL &lt;= APC_LEVEL.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/devnotes/rtlmovememory VOID RtlMoveMemory( _Out_ VOID UNALIGNED *Destination, _In_
// const VOID UNALIGNED *Source, _In_ SIZE_T Length );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("winnt.h", MSDNShortId = "D374F14D-24C7-4771-AD40-3AC37E7A2D2F")]
public static extern void RtlMoveMemory([In] IntPtr Destination, [In] IntPtr Source, [In] SizeT Length);
/// <summary>
/// The RtlZeroMemory routine fills a block of memory with zeros, given a pointer to the block and the length, in bytes, to be filled.
/// </summary>
/// <param name="Destination">A pointer to the memory block to be filled with zeros.</param>
/// <param name="Length">The number of bytes to fill with zeros.</param>
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-rtlzeromemory
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("winnt.h")]
public static extern void RtlZeroMemory(IntPtr Destination, SizeT Length);
/// <summary>Contains the hardware counter value.</summary>
// typedef struct _HARDWARE_COUNTER_DATA { HARDWARE_COUNTER_TYPE Type; DWORD Reserved; DWORD64 Value;} HARDWARE_COUNTER_DATA,
// *PHARDWARE_COUNTER_DATA; https://msdn.microsoft.com/en-us/library/windows/desktop/dd796394(v=vs.85).aspx
@ -341,6 +393,23 @@ namespace Vanara.PInvoke
public ulong Value;
}
/// <summary>Represents an entry in the function table on 64-bit Windows.</summary>
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-runtime_function
// typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { DWORD BeginAddress; DWORD EndAddress; union { DWORD UnwindInfoAddress; DWORD UnwindData; } DUMMYUNIONNAME; } RUNTIME_FUNCTION, *PRUNTIME_FUNCTION, _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;
[PInvokeData("winnt.h", MSDNShortId = "9ed16f9a-3403-4ba9-9968-f51f6788a1f8")]
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_RUNTIME_FUNCTION_ENTRY
{
/// <summary>The address of the start of the function.</summary>
public uint BeginAddress;
/// <summary>The address of the end of the function.</summary>
public uint EndAddress;
/// <summary>The address of the unwind information for the function.</summary>
public uint UnwindInfoAddress;
}
/// <summary>Contains the thread profiling and hardware counter data that you requested.</summary>
// typedef struct _PERFORMANCE_DATA { WORD Size; BYTE Version; BYTE HwCountersCount; DWORD ContextSwitchCount; DWORD64
// WaitReasonBitMap; DWORD64 CycleTime; DWORD RetryCount; DWORD Reserved; HARDWARE_COUNTER_DATA HwCounters[MAX_HW_COUNTERS];}
@ -437,6 +506,29 @@ namespace Vanara.PInvoke
public IntPtr UmsCompletionList;
}
[PInvokeData("winnt.h")]
[StructLayout(LayoutKind.Sequential)]
public struct UNWIND_HISTORY_TABLE_ENTRY
{
public ulong ImageBase;
public IMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry;
}
[PInvokeData("winnt.h")]
[StructLayout(LayoutKind.Sequential)]
public struct UNWIND_HISTORY_TABLE
{
public uint Count;
public byte LocalHint;
public byte GlobalHint;
public byte Search;
public byte Once;
public ulong LowAddress;
public ulong HighAddress;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public UNWIND_HISTORY_TABLE_ENTRY[] Entry;
}
/// <summary>
/// <para>Represents a context frame on WOW64. Refer to the header file WinNT.h for the definition of this structure.</para>
/// </summary>

View File

@ -48,6 +48,7 @@
<Compile Include="AppModelTests.cs" />
<Compile Include="InterlockedApiTests.cs" />
<Compile Include="InteropServices\SafeLocalHandleTests.cs" />
<Compile Include="RtlSupportApiTests.cs" />
<Compile Include="RealtimeApiSetTests.cs" />
<Compile Include="PsApiTests.cs" />
<Compile Include="ProfileApiTests.cs" />

View File

@ -0,0 +1,105 @@
using NUnit.Framework;
using System;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.Extensions;
using Vanara.InteropServices;
using static Vanara.PInvoke.AdvApi32;
using static Vanara.PInvoke.Kernel32;
namespace Vanara.PInvoke.Tests
{
[TestFixture]
public class RtlSupportApiTests
{
[Test]
public void RtlAddDeleteFunctionTableTest()
{
using (var mem = new SafeHGlobalHandle(4096))
{
var funcs = new[] { new IMAGE_RUNTIME_FUNCTION_ENTRY { BeginAddress = 0, EndAddress = 4096, UnwindInfoAddress = 2048 } };
var baseAddr = (ulong)((IntPtr)mem).ToInt64();
Assert.That(RtlAddFunctionTable(funcs, 1, baseAddr), ResultIs.Successful);
try
{
var retAddr = RtlLookupFunctionEntry(baseAddr, out var img, out var hist);
Assert.That(retAddr, Is.EqualTo(IntPtr.Zero));
}
finally
{
Assert.That(RtlDeleteFunctionTable(funcs), ResultIs.Successful);
}
}
}
[Test]
public void RtlCaptureContextTest()
{
var ctx = RtlCaptureContext();
Assert.That(ctx.ContextFlags, Is.EqualTo(CONTEXT_FLAG.CONTEXT_ALL));
}
[Test]
public void RtlInstallFunctionTableCallbackTest()
{
IntPtr pEntry = default;
using (SafeHGlobalHandle mem = new SafeHGlobalHandle(4096), entry = SafeHGlobalHandle.CreateFromStructure(new IMAGE_RUNTIME_FUNCTION_ENTRY { BeginAddress = 0, EndAddress = 4096, UnwindInfoAddress = 2048 }))
{
var baseAddr = (ulong)((IntPtr)mem).ToInt64();
pEntry = (IntPtr)entry;
var id = baseAddr | 0x3;
Assert.That(RtlInstallFunctionTableCallback(id, baseAddr, 4096, callbk), ResultIs.Successful);
Assert.That(RtlDeleteFunctionTable(id), ResultIs.Successful);
}
IntPtr callbk(IntPtr ControlPc, IntPtr Context) => pEntry;
}
[Test]
public void RtlPcToFileHeaderTest()
{
Assert.That(() => RtlPcToFileHeader(IntPtr.Zero, out var p), Throws.Nothing);
// TODO - Too undocumented to implement.
}
[Test]
public void RtlRestoreContextTest()
{
var ctx = default(CONTEXT);
var exc = default(EXCEPTION_RECORD);
Assert.That(() => RtlRestoreContext(ref ctx, ref exc), Throws.Nothing);
// TODO - Too undocumented to implement.
}
[Test]
public void RtlUnwindTest()
{
Assert.Fail("Too undocumented to implement.");
Assert.That(() => RtlUnwind(default, default, IntPtr.Zero, default), Throws.Nothing);
}
[Test]
public void RtlUnwindExTest()
{
Assert.Fail("Too undocumented to implement.");
Assert.That(() => RtlUnwindEx(default, default, IntPtr.Zero, default, default, default), Throws.Nothing);
}
[Test]
public void RtlMoveMemoryTest()
{
using (SafeHGlobalHandle src = new SafeHGlobalHandle(1024), dest = new SafeHGlobalHandle(1024))
{
src.Fill(7, 512);
Assert.That(() => RtlMoveMemory((IntPtr)dest, (IntPtr)src, 768), Throws.Nothing);
Assert.That(Marshal.ReadByte(((IntPtr)dest).Offset(256)), Is.EqualTo(7));
Assert.That(Marshal.ReadByte(((IntPtr)dest).Offset(896)), Is.EqualTo(0));
Assert.That(() => RtlZeroMemory((IntPtr)dest, 128), Throws.Nothing);
Assert.That(Marshal.ReadByte(((IntPtr)dest).Offset(64)), Is.EqualTo(0));
Assert.That(Marshal.ReadByte(((IntPtr)dest).Offset(256)), Is.EqualTo(7));
}
}
}
}