ReactOS 0.4.15-dev-8138-g1e75ea8
dynfntbl.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS RTL
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Dynamic function table support routines
5 * COPYRIGHT: Copyright 2022 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)
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{
49 PGET_RUNTIME_FUNCTION_CALLBACK Callback;
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
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 /* Insert the table into the list */
158 RtlpInsertDynamicFunctionTable(dynamicTable);
159
160 return TRUE;
161}
162
164NTAPI
166 _In_ DWORD64 TableIdentifier,
169 _In_ PGET_RUNTIME_FUNCTION_CALLBACK Callback,
171 _In_opt_z_ PCWSTR OutOfProcessCallbackDll)
172{
173 PDYNAMIC_FUNCTION_TABLE dynamicTable;
174 SIZE_T stringLength, allocationSize;
175
176 /* Make sure the identifier is valid */
177 if ((TableIdentifier & 3) != 3)
178 {
179 return FALSE;
180 }
181
182 /* Check if we have a DLL name */
183 if (OutOfProcessCallbackDll != NULL)
184 {
185 stringLength = wcslen(OutOfProcessCallbackDll) + 1;
186 }
187 else
188 {
189 stringLength = 0;
190 }
191
192 /* Calculate required size */
193 allocationSize = sizeof(DYNAMIC_FUNCTION_TABLE) + stringLength * sizeof(WCHAR);
194
195 /* Allocate a dynamic function table */
196 dynamicTable = RtlpAllocateMemory(allocationSize, TAG_RTLDYNFNTBL);
197 if (dynamicTable == NULL)
198 {
199 DPRINT1("Failed to allocate dynamic function table\n");
200 return FALSE;
201 }
202
203 /* Initialize fields */
204 dynamicTable->FunctionTable = (PRUNTIME_FUNCTION)TableIdentifier;
205 dynamicTable->EntryCount = 0;
206 dynamicTable->BaseAddress = BaseAddress;
207 dynamicTable->Callback = Callback;
208 dynamicTable->Context = Context;
209 dynamicTable->Type = RF_CALLBACK;
210 dynamicTable->MinimumAddress = BaseAddress;
211 dynamicTable->MaximumAddress = BaseAddress + Length;
212
213 /* If we have a DLL name, copy that, too */
214 if (OutOfProcessCallbackDll != NULL)
215 {
216 dynamicTable->OutOfProcessCallbackDll = (PWCHAR)(dynamicTable + 1);
218 OutOfProcessCallbackDll,
219 stringLength * sizeof(WCHAR));
220 }
221 else
222 {
223 dynamicTable->OutOfProcessCallbackDll = NULL;
224 }
225
226 /* Insert the table into the list */
227 RtlpInsertDynamicFunctionTable(dynamicTable);
228
229 return TRUE;
230}
231
233NTAPI
236{
237 PLIST_ENTRY listLink;
238 PDYNAMIC_FUNCTION_TABLE dynamicTable;
239 BOOL removed = FALSE;
240
242
243 /* Loop all tables to find the one to delete */
244 for (listLink = RtlpDynamicFunctionTableList.Flink;
245 listLink != &RtlpDynamicFunctionTableList;
246 listLink = listLink->Flink)
247 {
248 dynamicTable = CONTAINING_RECORD(listLink, DYNAMIC_FUNCTION_TABLE, ListEntry);
249
250 if (dynamicTable->FunctionTable == FunctionTable)
251 {
252 RemoveEntryList(&dynamicTable->ListEntry);
253 removed = TRUE;
254 break;
255 }
256 }
257
259
260 /* If we were successful, free the memory */
261 if (removed)
262 {
263 RtlpFreeMemory(dynamicTable, TAG_RTLDYNFNTBL);
264 }
265
266 return removed;
267}
268
270NTAPI
272 _In_ DWORD64 ControlPc,
273 _Out_ PDWORD64 ImageBase,
274 _In_ PUNWIND_HISTORY_TABLE HistoryTable)
275{
276 PLIST_ENTRY listLink;
277 PDYNAMIC_FUNCTION_TABLE dynamicTable;
278 PRUNTIME_FUNCTION functionTable, foundEntry = NULL;
279 PGET_RUNTIME_FUNCTION_CALLBACK callback;
280 ULONG i;
281
283
284 /* Loop all tables to find the one matching ControlPc */
285 for (listLink = RtlpDynamicFunctionTableList.Flink;
286 listLink != &RtlpDynamicFunctionTableList;
287 listLink = listLink->Flink)
288 {
289 dynamicTable = CONTAINING_RECORD(listLink, DYNAMIC_FUNCTION_TABLE, ListEntry);
290
291 if ((ControlPc >= dynamicTable->MinimumAddress) &&
292 (ControlPc < dynamicTable->MaximumAddress))
293 {
294 /* Check if there is a callback */
295 callback = dynamicTable->Callback;
296 if (callback != NULL)
297 {
298 PVOID context = dynamicTable->Context;
299
300 *ImageBase = dynamicTable->BaseAddress;
302 return callback(ControlPc, context);
303 }
304
305 /* Loop all entries in the function table */
306 functionTable = dynamicTable->FunctionTable;
307 for (i = 0; i < dynamicTable->EntryCount; i++)
308 {
309 /* Check if this entry contains the address */
310 if ((ControlPc >= functionTable[i].BeginAddress) &&
311 (ControlPc < functionTable[i].EndAddress))
312 {
313 foundEntry = &functionTable[i];
314 *ImageBase = dynamicTable->BaseAddress;
315 goto Exit;
316 }
317 }
318 }
319 }
320
321Exit:
322
324
325 return foundEntry;
326}
static const ENTRY Entries[]
unsigned char BOOLEAN
#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
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
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:271
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:234
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:165
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 IPrintDialogCallback callback
Definition: printdlg.c:326
#define min(a, b)
Definition: monoChain.cc:55
#define _Function_class_(x)
Definition: ms_sal.h:2946
#define _In_opt_z_
Definition: ms_sal.h:314
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
DWORD * PDWORD
Definition: pedump.c:68
struct _RUNTIME_FUNCTION * PRUNTIME_FUNCTION
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
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:722
__wchar_t WCHAR
Definition: xmlstorage.h:180