https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8521f6d7b5849d3b07b6032f616d9fb48b8bc7ef

commit 8521f6d7b5849d3b07b6032f616d9fb48b8bc7ef
Author:     Timo Kreuzer <[email protected]>
AuthorDate: Fri Jun 10 18:44:51 2022 +0200
Commit:     Timo Kreuzer <[email protected]>
CommitDate: Sat Jun 25 21:45:47 2022 +0200

    [RTL] Implement dynamic function tables for x64
---
 dll/ntdll/CMakeLists.txt     |   2 +-
 dll/ntdll/def/ntdll.spec     |   2 +-
 ntoskrnl/rtl/libsupp.c       |  17 +++
 sdk/lib/rtl/CMakeLists.txt   |   1 +
 sdk/lib/rtl/amd64/dynfntbl.c | 326 +++++++++++++++++++++++++++++++++++++++++++
 sdk/lib/rtl/amd64/unwind.c   |  45 ++----
 6 files changed, 355 insertions(+), 38 deletions(-)

diff --git a/dll/ntdll/CMakeLists.txt b/dll/ntdll/CMakeLists.txt
index be810e324f8..fbcd5272eb1 100644
--- a/dll/ntdll/CMakeLists.txt
+++ b/dll/ntdll/CMakeLists.txt
@@ -60,7 +60,7 @@ set_module_type(ntdll win32dll ENTRYPOINT 0)
 set_subsystem(ntdll console)
 ################# END  HACK #################
 
-target_link_libraries(ntdll rtl ntdllsys libcntpr uuid ${PSEH_LIB})
+target_link_libraries(ntdll rtl rtl_vista ntdllsys libcntpr uuid ${PSEH_LIB})
 
 if (STACK_PROTECTOR)
     target_sources(ntdll PRIVATE $<TARGET_OBJECTS:gcc_ssp_nt>)
diff --git a/dll/ntdll/def/ntdll.spec b/dll/ntdll/def/ntdll.spec
index 57ba0653d7c..80d27637413 100644
--- a/dll/ntdll/def/ntdll.spec
+++ b/dll/ntdll/def/ntdll.spec
@@ -881,7 +881,7 @@
 @ stdcall RtlGetFrame()
 @ stdcall RtlGetFullPathName_U(wstr long ptr ptr)
 @ stdcall RtlGetFullPathName_UstrEx(ptr ptr ptr ptr ptr ptr ptr ptr)
-@ stub -version=0x600+ -arch=x86_64 RtlGetFunctionTableListHead
+@ stdcall -arch=x86_64 RtlGetFunctionTableListHead()
 @ stdcall RtlGetGroupSecurityDescriptor(ptr ptr ptr)
 @ stub -version=0x600+ RtlGetIntegerAtom
 @ stdcall RtlGetLastNtStatus()
diff --git a/ntoskrnl/rtl/libsupp.c b/ntoskrnl/rtl/libsupp.c
index e8d7b68df88..173944a0573 100644
--- a/ntoskrnl/rtl/libsupp.c
+++ b/ntoskrnl/rtl/libsupp.c
@@ -823,4 +823,21 @@ RtlCallVectoredContinueHandlers(_In_ PEXCEPTION_RECORD 
ExceptionRecord,
     return;
 }
 
+#ifdef _M_AMD64
+
+typedef PVOID PRUNTIME_FUNCTION, PUNWIND_HISTORY_TABLE;
+
+PRUNTIME_FUNCTION
+NTAPI
+RtlpLookupDynamicFunctionEntry(
+    _In_ DWORD64 ControlPc,
+    _Out_ PDWORD64 ImageBase,
+    _In_ PUNWIND_HISTORY_TABLE HistoryTable)
+{
+    /* No support for dynamic function tables in the kernel */
+    return NULL;
+}
+
+#endif
+
 /* EOF */
diff --git a/sdk/lib/rtl/CMakeLists.txt b/sdk/lib/rtl/CMakeLists.txt
index a8d2fdbe348..8550fe9fb8e 100644
--- a/sdk/lib/rtl/CMakeLists.txt
+++ b/sdk/lib/rtl/CMakeLists.txt
@@ -94,6 +94,7 @@ elseif(ARCH STREQUAL "amd64")
     list(APPEND SOURCE
         bitmap64.c
         byteswap.c
+        amd64/dynfntbl.c
         amd64/except.c
         amd64/unwind.c
         amd64/stubs.c
diff --git a/sdk/lib/rtl/amd64/dynfntbl.c b/sdk/lib/rtl/amd64/dynfntbl.c
new file mode 100644
index 00000000000..67c76e7f640
--- /dev/null
+++ b/sdk/lib/rtl/amd64/dynfntbl.c
@@ -0,0 +1,326 @@
+/*
+ * PROJECT:     ReactOS RTL
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Dynamic function table support routines
+ * COPYRIGHT:   Copyright 2022 Timo Kreuzer ([email protected])
+ */
+
+#include <rtl.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#define TAG_RTLDYNFNTBL 'tfDP'
+
+typedef
+_Function_class_(GET_RUNTIME_FUNCTION_CALLBACK)
+PRUNTIME_FUNCTION
+GET_RUNTIME_FUNCTION_CALLBACK(
+    _In_ DWORD64 ControlPc,
+    _In_opt_ PVOID Context);
+typedef GET_RUNTIME_FUNCTION_CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK;
+
+typedef
+_Function_class_(OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)
+DWORD
+OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK(
+    _In_ HANDLE Process,
+    _In_ PVOID TableAddress,
+    _Out_ PDWORD Entries,
+    _Out_ PRUNTIME_FUNCTION* Functions);
+typedef OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK 
*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK;
+
+typedef enum _FUNCTION_TABLE_TYPE
+{
+    RF_SORTED = 0x0,
+    RF_UNSORTED = 0x1,
+    RF_CALLBACK = 0x2,
+    RF_KERNEL_DYNAMIC = 0x3,
+} FUNCTION_TABLE_TYPE;
+
+typedef struct _DYNAMIC_FUNCTION_TABLE
+{
+    LIST_ENTRY ListEntry;
+    PRUNTIME_FUNCTION FunctionTable;
+    LARGE_INTEGER TimeStamp;
+    ULONG64 MinimumAddress;
+    ULONG64 MaximumAddress;
+    ULONG64 BaseAddress;
+    PGET_RUNTIME_FUNCTION_CALLBACK Callback;
+    PVOID Context;
+    PWCHAR OutOfProcessCallbackDll;
+    FUNCTION_TABLE_TYPE Type;
+    ULONG EntryCount;
+#if (NTDDI_VERSION <= NTDDI_WIN10)
+    // FIXME: RTL_BALANCED_NODE is defined in ntdef.h, it's impossible to get 
included here due to precompiled header
+    //RTL_BALANCED_NODE TreeNode;
+#else
+    //RTL_BALANCED_NODE TreeNodeMin;
+    //RTL_BALANCED_NODE TreeNodeMax;
+#endif
+} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE;
+
+RTL_SRWLOCK RtlpDynamicFunctionTableLock = { 0 };
+LIST_ENTRY RtlpDynamicFunctionTableList = { &RtlpDynamicFunctionTableList, 
&RtlpDynamicFunctionTableList };
+
+static __inline
+VOID
+AcquireDynamicFunctionTableLockExclusive()
+{
+    RtlAcquireSRWLockExclusive(&RtlpDynamicFunctionTableLock);
+}
+
+static __inline
+VOID
+ReleaseDynamicFunctionTableLockExclusive()
+{
+    RtlReleaseSRWLockExclusive(&RtlpDynamicFunctionTableLock);
+}
+
+static __inline
+VOID
+AcquireDynamicFunctionTableLockShared()
+{
+    RtlAcquireSRWLockShared(&RtlpDynamicFunctionTableLock);
+}
+
+static __inline
+VOID
+ReleaseDynamicFunctionTableLockShared()
+{
+    RtlReleaseSRWLockShared(&RtlpDynamicFunctionTableLock);
+}
+
+/*
+ * 
https://docs.microsoft.com/en-us/windows/win32/devnotes/rtlgetfunctiontablelisthead
 
+ */
+PLIST_ENTRY
+NTAPI
+RtlGetFunctionTableListHead(void)
+{
+    return &RtlpDynamicFunctionTableList;
+}
+
+static
+VOID
+RtlpInsertDynamicFunctionTable(PDYNAMIC_FUNCTION_TABLE DynamicTable)
+{
+    //LARGE_INTEGER TimeStamp;
+
+    AcquireDynamicFunctionTableLockExclusive();
+
+    /* Insert it into the list */
+    InsertTailList(&RtlpDynamicFunctionTableList, &DynamicTable->ListEntry);
+
+    // TODO: insert into RB-trees
+
+    ReleaseDynamicFunctionTableLockExclusive();
+}
+
+BOOLEAN
+NTAPI
+RtlAddFunctionTable(
+    _In_ PRUNTIME_FUNCTION FunctionTable,
+    _In_ DWORD EntryCount,
+    _In_ DWORD64 BaseAddress)
+{
+    PDYNAMIC_FUNCTION_TABLE dynamicTable;
+    ULONG i;
+
+    /* Allocate a dynamic function table */
+    dynamicTable = RtlpAllocateMemory(sizeof(*dynamicTable), TAG_RTLDYNFNTBL);
+    if (dynamicTable == NULL)
+    {
+        DPRINT1("Failed to allocate dynamic function table\n");
+        return FALSE;
+    }
+
+    /* Initialize fields */
+    dynamicTable->FunctionTable = FunctionTable;
+    dynamicTable->EntryCount = EntryCount;
+    dynamicTable->BaseAddress = BaseAddress;
+    dynamicTable->Callback = NULL;
+    dynamicTable->Context = NULL;
+    dynamicTable->Type = RF_UNSORTED;
+
+    /* Loop all entries to find the margins */
+    dynamicTable->MinimumAddress = ULONG64_MAX;
+    dynamicTable->MaximumAddress = 0;
+    for (i = 0; i < EntryCount; i++)
+    {
+        dynamicTable->MinimumAddress = min(dynamicTable->MinimumAddress,
+                                           FunctionTable[i].BeginAddress);
+        dynamicTable->MaximumAddress = max(dynamicTable->MaximumAddress,
+                                           FunctionTable[i].EndAddress);
+    }
+
+    /* Insert the table into the list */
+    RtlpInsertDynamicFunctionTable(dynamicTable);
+
+    return TRUE;
+}
+
+BOOLEAN
+NTAPI
+RtlInstallFunctionTableCallback(
+    _In_ DWORD64 TableIdentifier,
+    _In_ DWORD64 BaseAddress,
+    _In_ DWORD Length,
+    _In_ PGET_RUNTIME_FUNCTION_CALLBACK Callback,
+    _In_ PVOID Context,
+    _In_opt_z_ PCWSTR OutOfProcessCallbackDll)
+{
+    PDYNAMIC_FUNCTION_TABLE dynamicTable;
+    SIZE_T stringLength, allocationSize;
+
+    /* Make sure the identifier is valid */
+    if ((TableIdentifier & 3) != 3)
+    {
+        return FALSE;
+    }
+
+    /* Check if we have a DLL name */
+    if (OutOfProcessCallbackDll != NULL)
+    {
+        stringLength = wcslen(OutOfProcessCallbackDll) + 1;
+    }
+    else
+    {
+        stringLength = 0;
+    }
+
+    /* Calculate required size */
+    allocationSize = sizeof(DYNAMIC_FUNCTION_TABLE) + stringLength * 
sizeof(WCHAR);
+
+    /* Allocate a dynamic function table */
+    dynamicTable = RtlpAllocateMemory(allocationSize, TAG_RTLDYNFNTBL);
+    if (dynamicTable == NULL)
+    {
+        DPRINT1("Failed to allocate dynamic function table\n");
+        return FALSE;
+    }
+
+    /* Initialize fields */
+    dynamicTable->FunctionTable = (PRUNTIME_FUNCTION)TableIdentifier;
+    dynamicTable->EntryCount = 0;
+    dynamicTable->BaseAddress = BaseAddress;
+    dynamicTable->Callback = Callback;
+    dynamicTable->Context = Context;
+    dynamicTable->Type = RF_CALLBACK;
+    dynamicTable->MinimumAddress = BaseAddress;
+    dynamicTable->MaximumAddress = BaseAddress + Length;
+
+    /* If we have a DLL name, copy that, too */
+    if (OutOfProcessCallbackDll != NULL)
+    {
+        dynamicTable->OutOfProcessCallbackDll = (PWCHAR)(dynamicTable + 1);
+        RtlCopyMemory(dynamicTable->OutOfProcessCallbackDll,
+                      OutOfProcessCallbackDll,
+                      stringLength * sizeof(WCHAR));
+    }
+    else
+    {
+        dynamicTable->OutOfProcessCallbackDll = NULL;
+    }
+
+    /* Insert the table into the list */
+    RtlpInsertDynamicFunctionTable(dynamicTable);
+
+    return TRUE;
+}
+
+BOOLEAN
+NTAPI
+RtlDeleteFunctionTable(
+    _In_ PRUNTIME_FUNCTION FunctionTable)
+{
+    PLIST_ENTRY listLink;
+    PDYNAMIC_FUNCTION_TABLE dynamicTable;
+    BOOL removed = FALSE;
+
+    AcquireDynamicFunctionTableLockExclusive();
+
+    /* Loop all tables to find the one to delete */
+    for (listLink = RtlpDynamicFunctionTableList.Flink;
+         listLink != &RtlpDynamicFunctionTableList;
+         listLink = listLink->Flink)
+    {
+        dynamicTable = CONTAINING_RECORD(listLink, DYNAMIC_FUNCTION_TABLE, 
ListEntry);
+
+        if (dynamicTable->FunctionTable == FunctionTable)
+        {
+            RemoveEntryList(&dynamicTable->ListEntry);
+            removed = TRUE;
+            break;
+        }
+    }
+
+    ReleaseDynamicFunctionTableLockExclusive();
+
+    /* If we were successful, free the memory */
+    if (removed)
+    {
+        RtlpFreeMemory(dynamicTable, TAG_RTLDYNFNTBL);
+    }
+
+    return removed;
+}
+
+PRUNTIME_FUNCTION
+NTAPI
+RtlpLookupDynamicFunctionEntry(
+    _In_ DWORD64 ControlPc,
+    _Out_ PDWORD64 ImageBase,
+    _In_ PUNWIND_HISTORY_TABLE HistoryTable)
+{
+    PLIST_ENTRY listLink;
+    PDYNAMIC_FUNCTION_TABLE dynamicTable;
+    PRUNTIME_FUNCTION functionTable, foundEntry = NULL;
+    PGET_RUNTIME_FUNCTION_CALLBACK callback;
+    ULONG i;
+
+    AcquireDynamicFunctionTableLockShared();
+
+    /* Loop all tables to find the one matching ControlPc */
+    for (listLink = RtlpDynamicFunctionTableList.Flink;
+         listLink != &RtlpDynamicFunctionTableList;
+         listLink = listLink->Flink)
+    {
+        dynamicTable = CONTAINING_RECORD(listLink, DYNAMIC_FUNCTION_TABLE, 
ListEntry);
+
+        if ((ControlPc >= dynamicTable->MinimumAddress) &&
+            (ControlPc < dynamicTable->MaximumAddress))
+        {
+            /* Check if there is a callback */
+            callback = dynamicTable->Callback;
+            if (callback != NULL)
+            {
+                PVOID context = dynamicTable->Context;
+
+                *ImageBase = dynamicTable->BaseAddress;
+                ReleaseDynamicFunctionTableLockShared();
+                return callback(ControlPc, context);
+            }
+
+            /* Loop all entries in the function table */
+            functionTable = dynamicTable->FunctionTable;
+            for (i = 0; i < dynamicTable->EntryCount; i++)
+            {
+                /* Check if this entry contains the address */
+                if ((ControlPc >= functionTable[i].BeginAddress) &&
+                    (ControlPc < functionTable[i].EndAddress))
+                {
+                    foundEntry = &functionTable[i];
+                    *ImageBase = dynamicTable->BaseAddress;
+                    goto Exit;
+                }
+            }
+        }
+    }
+
+Exit:
+
+    ReleaseDynamicFunctionTableLockShared();
+
+    return foundEntry;
+}
diff --git a/sdk/lib/rtl/amd64/unwind.c b/sdk/lib/rtl/amd64/unwind.c
index 4fe42801281..49e3740bec4 100644
--- a/sdk/lib/rtl/amd64/unwind.c
+++ b/sdk/lib/rtl/amd64/unwind.c
@@ -107,6 +107,13 @@ RtlLookupFunctionTable(
     return Table;
 }
 
+PRUNTIME_FUNCTION
+NTAPI
+RtlpLookupDynamicFunctionEntry(
+    _In_ DWORD64 ControlPc,
+    _Out_ PDWORD64 ImageBase,
+    _In_ PUNWIND_HISTORY_TABLE HistoryTable);
+
 /*! RtlLookupFunctionEntry
  * \brief Locates the RUNTIME_FUNCTION entry corresponding to a code address.
  * \ref http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx
@@ -126,10 +133,10 @@ RtlLookupFunctionEntry(
     /* Find the corresponding table */
     FunctionTable = RtlLookupFunctionTable(ControlPc, ImageBase, &TableLength);
 
-    /* Fail, if no table is found */
+    /* If no table is found, try dynamic function tables */
     if (!FunctionTable)
     {
-        return NULL;
+        return RtlpLookupDynamicFunctionEntry(ControlPc, ImageBase, 
HistoryTable);
     }
 
     /* Use relative virtual address */
@@ -164,40 +171,6 @@ RtlLookupFunctionEntry(
     return NULL;
 }
 
-BOOLEAN
-NTAPI
-RtlAddFunctionTable(
-    IN PRUNTIME_FUNCTION FunctionTable,
-    IN DWORD EntryCount,
-    IN DWORD64 BaseAddress)
-{
-    UNIMPLEMENTED;
-    return FALSE;
-}
-
-BOOLEAN
-NTAPI
-RtlDeleteFunctionTable(
-    IN PRUNTIME_FUNCTION FunctionTable)
-{
-    UNIMPLEMENTED;
-    return FALSE;
-}
-
-BOOLEAN
-NTAPI
-RtlInstallFunctionTableCallback(
-    IN DWORD64 TableIdentifier,
-    IN DWORD64 BaseAddress,
-    IN DWORD Length,
-    IN PGET_RUNTIME_FUNCTION_CALLBACK Callback,
-    IN PVOID Context,
-    IN PCWSTR OutOfProcessCallbackDll)
-{
-    UNIMPLEMENTED;
-    return FALSE;
-}
-
 static
 __inline
 ULONG

Reply via email to