ReactOS  0.4.15-dev-5146-g069b08d
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 
15 typedef
16 _Function_class_(GET_RUNTIME_FUNCTION_CALLBACK)
18 GET_RUNTIME_FUNCTION_CALLBACK(
19  _In_ DWORD64 ControlPc,
21 typedef GET_RUNTIME_FUNCTION_CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK;
22 
23 typedef
24 _Function_class_(OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)
25 DWORD
26 OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK(
28  _In_ PVOID TableAddress,
30  _Out_ PRUNTIME_FUNCTION* Functions);
31 typedef OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK *POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK;
32 
33 typedef 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 
66 static __inline
67 VOID
69 {
71 }
72 
73 static __inline
74 VOID
76 {
78 }
79 
80 static __inline
81 VOID
83 {
85 }
86 
87 static __inline
88 VOID
90 {
92 }
93 
94 /*
95  * https://docs.microsoft.com/en-us/windows/win32/devnotes/rtlgetfunctiontablelisthead
96  */
98 NTAPI
100 {
102 }
103 
104 static
105 VOID
107 {
108  //LARGE_INTEGER TimeStamp;
109 
111 
112  /* Insert it into the list */
114 
115  // TODO: insert into RB-trees
116 
118 }
119 
120 BOOLEAN
121 NTAPI
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 
163 BOOLEAN
164 NTAPI
166  _In_ DWORD64 TableIdentifier,
168  _In_ DWORD Length,
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 
232 BOOLEAN
233 NTAPI
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 
270 NTAPI
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 
321 Exit:
322 
324 
325  return foundEntry;
326 }
FUNCTION_TABLE_TYPE
Definition: dynfntbl.c:39
LIST_ENTRY RtlpDynamicFunctionTableList
Definition: dynfntbl.c:64
FUNCTION_TABLE_TYPE Type
Definition: dynfntbl.c:52
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define max(a, b)
Definition: svc.c:63
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define _In_opt_
Definition: ms_sal.h:309
static __inline VOID AcquireDynamicFunctionTableLockExclusive()
Definition: dynfntbl.c:68
#define _In_opt_z_
Definition: ms_sal.h:314
#define _Out_
Definition: ms_sal.h:345
Definition: http.c:7251
#define TRUE
Definition: types.h:120
VOID NTAPI RtlAcquireSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:325
VOID NTAPI RtlpFreeMemory(_In_ PVOID Mem, _In_ ULONG Tag)
Definition: rtlcompat.c:45
uint16_t * PWCHAR
Definition: typedefs.h:56
#define InsertTailList(ListHead, Entry)
BOOLEAN NTAPI RtlDeleteFunctionTable(_In_ PRUNTIME_FUNCTION FunctionTable)
Definition: dynfntbl.c:234
BOOLEAN NTAPI RtlAddFunctionTable(_In_ PRUNTIME_FUNCTION FunctionTable, _In_ DWORD EntryCount, _In_ DWORD64 BaseAddress)
Definition: dynfntbl.c:122
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
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
PGET_RUNTIME_FUNCTION_CALLBACK Callback
Definition: dynfntbl.c:49
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
static __inline VOID ReleaseDynamicFunctionTableLockExclusive()
Definition: dynfntbl.c:75
#define FALSE
Definition: types.h:117
PVOID NTAPI RtlpAllocateMemory(_In_ ULONG Bytes, _In_ ULONG Tag)
Definition: rtlcompat.c:34
unsigned int BOOL
Definition: ntddk_ex.h:94
#define TAG_RTLDYNFNTBL
Definition: dynfntbl.c:13
unsigned char BOOLEAN
#define _In_
Definition: ms_sal.h:308
PRUNTIME_FUNCTION NTAPI RtlpLookupDynamicFunctionEntry(_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _In_ PUNWIND_HISTORY_TABLE HistoryTable)
Definition: dynfntbl.c:271
struct _DYNAMIC_FUNCTION_TABLE DYNAMIC_FUNCTION_TABLE
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
static VOID RtlpInsertDynamicFunctionTable(PDYNAMIC_FUNCTION_TABLE DynamicTable)
Definition: dynfntbl.c:106
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
__wchar_t WCHAR
Definition: xmlstorage.h:180
PLIST_ENTRY NTAPI RtlGetFunctionTableListHead(void)
Definition: dynfntbl.c:99
VOID NTAPI RtlAcquireSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:591
static void Exit(void)
Definition: sock.c:1331
static __inline VOID AcquireDynamicFunctionTableLockShared()
Definition: dynfntbl.c:82
unsigned long DWORD
Definition: ntddk_ex.h:95
VOID NTAPI RtlReleaseSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:526
#define ULONG64_MAX
Definition: d3dx9_private.h:34
struct _RUNTIME_FUNCTION * PRUNTIME_FUNCTION
unsigned __int64 ULONG64
Definition: imports.h:198
VOID NTAPI RtlReleaseSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock)
Definition: srw.c:710
Definition: typedefs.h:119
PRUNTIME_FUNCTION FunctionTable
Definition: dynfntbl.c:44
_In_ WDFINTERRUPT _In_ PFN_WDF_INTERRUPT_SYNCHRONIZE Callback
Definition: wdfinterrupt.h:456
LIST_ENTRY ListEntry
Definition: dynfntbl.c:43
static __inline VOID ReleaseDynamicFunctionTableLockShared()
Definition: dynfntbl.c:89
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint64_t DWORD64
Definition: typedefs.h:67
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
LIST_ENTRY Entries[5]
Definition: ExDoubleList.c:8
LARGE_INTEGER TimeStamp
Definition: dynfntbl.c:45
#define min(a, b)
Definition: monoChain.cc:55
#define NULL
Definition: types.h:112
DWORD * PDWORD
Definition: pedump.c:68
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define DPRINT1
Definition: precomp.h:8
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
struct tagContext Context
Definition: acpixf.h:1034
unsigned int ULONG
Definition: retypes.h:1
uint64_t * PDWORD64
Definition: typedefs.h:67
static WLX_DISPATCH_VERSION_1_4 FunctionTable
Definition: wlx.c:722
PWCHAR OutOfProcessCallbackDll
Definition: dynfntbl.c:51
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
static IPrintDialogCallback callback
Definition: printdlg.c:326
RTL_SRWLOCK RtlpDynamicFunctionTableLock
Definition: dynfntbl.c:63
typedef _Function_class_(GET_RUNTIME_FUNCTION_CALLBACK)
Definition: dynfntbl.c:16
struct _DYNAMIC_FUNCTION_TABLE * PDYNAMIC_FUNCTION_TABLE