ReactOS 0.4.16-dev-1946-g52006dd
dynfntbl.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS RTL
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Dynamic function table support routines
5 * COPYRIGHT: Copyright 2022-2025 Timo Kreuzer (timo.kreuzer@reactos.org)
6 */
7
8#include <rtl.h>
9
10#define NDEBUG
11#include <debug.h>
12
13#define TAG_RTLDYNFNTBL 'tfDP'
14
15typedef
16_Function_class_(GET_RUNTIME_FUNCTION_CALLBACK)
17PRUNTIME_FUNCTION
18GET_RUNTIME_FUNCTION_CALLBACK(
19 _In_ DWORD64 ControlPc,
21typedef GET_RUNTIME_FUNCTION_CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK;
22
23typedef
24_Function_class_(OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)
26OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK(
28 _In_ PVOID TableAddress,
30 _Out_ PRUNTIME_FUNCTION* Functions);
31typedef OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK *POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK;
32
33typedef enum _FUNCTION_TABLE_TYPE
34{
35 RF_SORTED = 0x0,
36 RF_UNSORTED = 0x1,
37 RF_CALLBACK = 0x2,
38 RF_KERNEL_DYNAMIC = 0x3,
40
42{
44 PRUNTIME_FUNCTION FunctionTable;
54#if (NTDDI_VERSION <= NTDDI_WIN10)
55 // FIXME: RTL_BALANCED_NODE is defined in ntdef.h, it's impossible to get included here due to precompiled header
56 //RTL_BALANCED_NODE TreeNode;
57#else
58 //RTL_BALANCED_NODE TreeNodeMin;
59 //RTL_BALANCED_NODE TreeNodeMax;
60#endif
62
65
66static __inline
67VOID
69{
71}
72
73static __inline
74VOID
76{
78}
79
80static __inline
81VOID
83{
85}
86
87static __inline
88VOID
90{
92}
93
94/*
95 * https://docs.microsoft.com/en-us/windows/win32/devnotes/rtlgetfunctiontablelisthead
96 */
100{
102}
103
104static
105VOID
107{
108 //LARGE_INTEGER TimeStamp;
109
111
112 /* Insert it into the list */
114
115 // TODO: insert into RB-trees
116
118}
119
121NTAPI
123 _In_ PRUNTIME_FUNCTION FunctionTable,
124 _In_ DWORD EntryCount,
126{
127 PDYNAMIC_FUNCTION_TABLE dynamicTable;
128 ULONG i;
129
130 /* Allocate a dynamic function table */
131 dynamicTable = RtlpAllocateMemory(sizeof(*dynamicTable), TAG_RTLDYNFNTBL);
132 if (dynamicTable == NULL)
133 {
134 DPRINT1("Failed to allocate dynamic function table\n");
135 return FALSE;
136 }
137
138 /* Initialize fields */
139 dynamicTable->FunctionTable = FunctionTable;
140 dynamicTable->EntryCount = EntryCount;
141 dynamicTable->BaseAddress = BaseAddress;
142 dynamicTable->Callback = NULL;
143 dynamicTable->Context = NULL;
144 dynamicTable->Type = RF_UNSORTED;
145
146 /* Loop all entries to find the margins */
147 dynamicTable->MinimumAddress = ULONG64_MAX;
148 dynamicTable->MaximumAddress = 0;
149 for (i = 0; i < EntryCount; i++)
150 {
151 dynamicTable->MinimumAddress = min(dynamicTable->MinimumAddress,
152 FunctionTable[i].BeginAddress);
153 dynamicTable->MaximumAddress = max(dynamicTable->MaximumAddress,
154 FunctionTable[i].EndAddress);
155 }
156
157 /* Adjust the margins to be absolute addresses */
158 dynamicTable->MinimumAddress += BaseAddress;
159 dynamicTable->MaximumAddress += BaseAddress;
160
161 /* Insert the table into the list */
162 RtlpInsertDynamicFunctionTable(dynamicTable);
163
164 return TRUE;
165}
166
168NTAPI
170 _In_ DWORD64 TableIdentifier,
175 _In_opt_z_ PCWSTR OutOfProcessCallbackDll)
176{
177 PDYNAMIC_FUNCTION_TABLE dynamicTable;
178 SIZE_T stringLength, allocationSize;
179
180 /* Make sure the identifier is valid */
181 if ((TableIdentifier & 3) != 3)
182 {
183 return FALSE;
184 }
185
186 /* Check if we have a DLL name */
187 if (OutOfProcessCallbackDll != NULL)
188 {
189 stringLength = wcslen(OutOfProcessCallbackDll) + 1;
190 }
191 else
192 {
193 stringLength = 0;
194 }
195
196 /* Calculate required size */
197 allocationSize = sizeof(DYNAMIC_FUNCTION_TABLE) + stringLength * sizeof(WCHAR);
198
199 /* Allocate a dynamic function table */
200 dynamicTable = RtlpAllocateMemory(allocationSize, TAG_RTLDYNFNTBL);
201 if (dynamicTable == NULL)
202 {
203 DPRINT1("Failed to allocate dynamic function table\n");
204 return FALSE;
205 }
206
207 /* Initialize fields */
208 dynamicTable->FunctionTable = (PRUNTIME_FUNCTION)TableIdentifier;
209 dynamicTable->EntryCount = 0;
210 dynamicTable->BaseAddress = BaseAddress;
211 dynamicTable->Callback = Callback;
212 dynamicTable->Context = Context;
213 dynamicTable->Type = RF_CALLBACK;
214 dynamicTable->MinimumAddress = BaseAddress;
215 dynamicTable->MaximumAddress = BaseAddress + Length;
216
217 /* If we have a DLL name, copy that, too */
218 if (OutOfProcessCallbackDll != NULL)
219 {
220 dynamicTable->OutOfProcessCallbackDll = (PWCHAR)(dynamicTable + 1);
222 OutOfProcessCallbackDll,
223 stringLength * sizeof(WCHAR));
224 }
225 else
226 {
227 dynamicTable->OutOfProcessCallbackDll = NULL;
228 }
229
230 /* Insert the table into the list */
231 RtlpInsertDynamicFunctionTable(dynamicTable);
232
233 return TRUE;
234}
235
237NTAPI
239 _In_ PRUNTIME_FUNCTION FunctionTable)
240{
241 PLIST_ENTRY listLink;
242 PDYNAMIC_FUNCTION_TABLE dynamicTable;
243 BOOL removed = FALSE;
244
246
247 /* Loop all tables to find the one to delete */
248 for (listLink = RtlpDynamicFunctionTableList.Flink;
249 listLink != &RtlpDynamicFunctionTableList;
250 listLink = listLink->Flink)
251 {
252 dynamicTable = CONTAINING_RECORD(listLink, DYNAMIC_FUNCTION_TABLE, ListEntry);
253
254 if (dynamicTable->FunctionTable == FunctionTable)
255 {
256 RemoveEntryList(&dynamicTable->ListEntry);
257 removed = TRUE;
258 break;
259 }
260 }
261
263
264 /* If we were successful, free the memory */
265 if (removed)
266 {
267 RtlpFreeMemory(dynamicTable, TAG_RTLDYNFNTBL);
268 }
269
270 return removed;
271}
272
273PRUNTIME_FUNCTION
274NTAPI
276 _In_ DWORD64 ControlPc,
277 _Out_ PDWORD64 ImageBase,
278 _In_ PUNWIND_HISTORY_TABLE HistoryTable)
279{
280 PLIST_ENTRY listLink;
281 PDYNAMIC_FUNCTION_TABLE dynamicTable;
282 PRUNTIME_FUNCTION functionTable, foundEntry = NULL;
284 DWORD64 ipOffset;
285 ULONG i;
286
288
289 /* Loop all tables to find the one matching ControlPc */
290 for (listLink = RtlpDynamicFunctionTableList.Flink;
291 listLink != &RtlpDynamicFunctionTableList;
292 listLink = listLink->Flink)
293 {
294 dynamicTable = CONTAINING_RECORD(listLink, DYNAMIC_FUNCTION_TABLE, ListEntry);
295
296 if ((ControlPc >= dynamicTable->MinimumAddress) &&
297 (ControlPc < dynamicTable->MaximumAddress))
298 {
299 /* Check if there is a callback */
300 callback = dynamicTable->Callback;
301 if (callback != NULL)
302 {
303 PVOID context = dynamicTable->Context;
304
305 *ImageBase = dynamicTable->BaseAddress;
307 return callback(ControlPc, context);
308 }
309
310 /* Loop all entries in the function table */
311 functionTable = dynamicTable->FunctionTable;
312 ipOffset = ControlPc - dynamicTable->BaseAddress;
313 for (i = 0; i < dynamicTable->EntryCount; i++)
314 {
315 /* Check if this entry contains the address */
316 if ((ipOffset >= functionTable[i].BeginAddress) &&
317 (ipOffset < functionTable[i].EndAddress))
318 {
319 foundEntry = &functionTable[i];
320 *ImageBase = dynamicTable->BaseAddress;
321 goto Exit;
322 }
323 }
324 }
325 }
326
327Exit:
328
330
331 return foundEntry;
332}
unsigned char BOOLEAN
#define __inline
Definition: _wctype.cpp:15
#define DPRINT1
Definition: precomp.h:8
#define ULONG64_MAX
Definition: d3dx9_private.h:34
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
struct _DYNAMIC_FUNCTION_TABLE DYNAMIC_FUNCTION_TABLE
#define TAG_RTLDYNFNTBL
Definition: dynfntbl.c:13
static __inline VOID AcquireDynamicFunctionTableLockShared()
Definition: dynfntbl.c:82
static __inline VOID ReleaseDynamicFunctionTableLockExclusive()
Definition: dynfntbl.c:75
struct _DYNAMIC_FUNCTION_TABLE * PDYNAMIC_FUNCTION_TABLE
FUNCTION_TABLE_TYPE
Definition: dynfntbl.c:39
static VOID RtlpInsertDynamicFunctionTable(PDYNAMIC_FUNCTION_TABLE DynamicTable)
Definition: dynfntbl.c:106
PRUNTIME_FUNCTION NTAPI RtlpLookupDynamicFunctionEntry(_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _In_ PUNWIND_HISTORY_TABLE HistoryTable)
Definition: dynfntbl.c:275
static __inline VOID AcquireDynamicFunctionTableLockExclusive()
Definition: dynfntbl.c:68
RTL_SRWLOCK RtlpDynamicFunctionTableLock
Definition: dynfntbl.c:63
BOOLEAN NTAPI RtlAddFunctionTable(_In_ PRUNTIME_FUNCTION FunctionTable, _In_ DWORD EntryCount, _In_ DWORD64 BaseAddress)
Definition: dynfntbl.c:122
BOOLEAN NTAPI RtlDeleteFunctionTable(_In_ PRUNTIME_FUNCTION FunctionTable)
Definition: dynfntbl.c:238
PLIST_ENTRY NTAPI RtlGetFunctionTableListHead(void)
Definition: dynfntbl.c:99
static __inline VOID ReleaseDynamicFunctionTableLockShared()
Definition: dynfntbl.c:89
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)
Definition: dynfntbl.c:169
LIST_ENTRY RtlpDynamicFunctionTableList
Definition: dynfntbl.c:64
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
unsigned __int64 ULONG64
Definition: imports.h:198
static const ENTRY Entries[]
static IPrintDialogCallback callback
Definition: printdlg.c:326
#define min(a, b)
Definition: monoChain.cc:55
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
VOID NTAPI RtlReleaseSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:710
VOID NTAPI RtlAcquireSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:591
VOID NTAPI RtlReleaseSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:526
VOID NTAPI RtlAcquireSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:325
#define _In_opt_z_
Definition: no_sal2.h:218
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define _Function_class_(n)
Definition: no_sal2.h:398
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
DWORD * PDWORD
Definition: pedump.c:68
PVOID NTAPI RtlpAllocateMemory(_In_ ULONG Bytes, _In_ ULONG Tag)
Definition: rtlcompat.c:34
VOID NTAPI RtlpFreeMemory(_In_ PVOID Mem, _In_ ULONG Tag)
Definition: rtlcompat.c:45
PRUNTIME_FUNCTION(CALLBACK * PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD_PTR, PVOID)
Definition: rtlsupportapi.h:56
static void Exit(void)
Definition: sock.c:1330
PGET_RUNTIME_FUNCTION_CALLBACK Callback
Definition: dynfntbl.c:49
PRUNTIME_FUNCTION FunctionTable
Definition: dynfntbl.c:44
LIST_ENTRY ListEntry
Definition: dynfntbl.c:43
LARGE_INTEGER TimeStamp
Definition: dynfntbl.c:45
FUNCTION_TABLE_TYPE Type
Definition: dynfntbl.c:52
PWCHAR OutOfProcessCallbackDll
Definition: dynfntbl.c:51
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: http.c:7252
#define max(a, b)
Definition: svc.c:63
uint64_t * PDWORD64
Definition: typedefs.h:67
const uint16_t * PCWSTR
Definition: typedefs.h:57
uint64_t DWORD64
Definition: typedefs.h:67
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
_In_ WDFINTERRUPT _In_ PFN_WDF_INTERRUPT_SYNCHRONIZE Callback
Definition: wdfinterrupt.h:458
static WLX_DISPATCH_VERSION_1_4 FunctionTable
Definition: wlx.c:747
__wchar_t WCHAR
Definition: xmlstorage.h:180