2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/kdbg/kdb_symbols.c
5 * PURPOSE: Getting symbol information...
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Colin Finck (colin@reactos.org)
11 /* INCLUDES *****************************************************************/
19 /* GLOBALS ******************************************************************/
21 typedef struct _IMAGE_SYMBOL_INFO_CACHE
25 UNICODE_STRING FileName
;
26 PROSSYM_INFO RosSymInfo
;
28 IMAGE_SYMBOL_INFO_CACHE
, *PIMAGE_SYMBOL_INFO_CACHE
;
30 static BOOLEAN LoadSymbols
= FALSE
;
31 static LIST_ENTRY SymbolsToLoad
;
32 static KSPIN_LOCK SymbolsToLoadLock
;
33 static KEVENT SymbolsToLoadEvent
;
35 /* FUNCTIONS ****************************************************************/
39 KdbpSymSearchModuleList(
40 IN PLIST_ENTRY current_entry
,
41 IN PLIST_ENTRY end_entry
,
45 OUT PLDR_DATA_TABLE_ENTRY
* pLdrEntry
)
47 while (current_entry
&& current_entry
!= end_entry
)
49 *pLdrEntry
= CONTAINING_RECORD(current_entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
51 if ((Address
&& Address
>= (PVOID
)(*pLdrEntry
)->DllBase
&& Address
< (PVOID
)((ULONG_PTR
)(*pLdrEntry
)->DllBase
+ (*pLdrEntry
)->SizeOfImage
)) ||
52 (Index
>= 0 && (*Count
)++ == Index
))
57 current_entry
= current_entry
->Flink
;
63 /*! \brief Find a module...
65 * \param Address If \a Address is not NULL the module containing \a Address
67 * \param Name If \a Name is not NULL the module named \a Name will be
69 * \param Index If \a Index is >= 0 the Index'th module will be returned.
70 * \param pLdrEntry Pointer to a PLDR_DATA_TABLE_ENTRY which is filled.
72 * \retval TRUE Module was found, \a pLdrEntry was filled.
73 * \retval FALSE No module was found.
77 IN PVOID Address OPTIONAL
,
78 IN INT Index OPTIONAL
,
79 OUT PLDR_DATA_TABLE_ENTRY
* pLdrEntry
)
82 PEPROCESS CurrentProcess
;
84 /* First try to look up the module in the kernel module list. */
85 KeAcquireSpinLockAtDpcLevel(&PsLoadedModuleSpinLock
);
86 if(KdbpSymSearchModuleList(PsLoadedModuleList
.Flink
,
93 KeReleaseSpinLockFromDpcLevel(&PsLoadedModuleSpinLock
);
96 KeReleaseSpinLockFromDpcLevel(&PsLoadedModuleSpinLock
);
98 /* That didn't succeed. Try the module list of the current process now. */
99 CurrentProcess
= PsGetCurrentProcess();
101 if(!CurrentProcess
|| !CurrentProcess
->Peb
|| !CurrentProcess
->Peb
->Ldr
)
104 return KdbpSymSearchModuleList(CurrentProcess
->Peb
->Ldr
->InLoadOrderModuleList
.Flink
,
105 &CurrentProcess
->Peb
->Ldr
->InLoadOrderModuleList
,
115 KdbpSymUnicodeToAnsi(IN PUNICODE_STRING Unicode
,
123 /* Set length and normalize it */
124 i
= Unicode
->Length
/ sizeof(WCHAR
);
125 i
= min(i
, Length
- 1);
127 /* Set source and destination, and copy */
128 pw
= Unicode
->Buffer
;
130 while (i
--) *p
++ = (CHAR
)*pw
++;
132 /* Null terminate and return */
137 /*! \brief Print address...
139 * Tries to lookup line number, file name and function name for the given
140 * address and prints it.
141 * If no such information is found the address is printed in the format
142 * <module: offset>, otherwise the format will be
143 * <module: offset (filename:linenumber (functionname))>
145 * \retval TRUE Module containing \a Address was found, \a Address was printed.
146 * \retval FALSE No module containing \a Address was found, nothing was printed.
153 PLDR_DATA_TABLE_ENTRY LdrEntry
;
154 ULONG_PTR RelativeAddress
;
155 BOOLEAN Printed
= FALSE
;
156 CHAR ModuleNameAnsi
[64];
158 if (!KdbpSymFindModule(Address
, -1, &LdrEntry
))
161 RelativeAddress
= (ULONG_PTR
)Address
- (ULONG_PTR
)LdrEntry
->DllBase
;
163 KdbpSymUnicodeToAnsi(&LdrEntry
->BaseDllName
,
165 sizeof(ModuleNameAnsi
));
167 if (LdrEntry
->PatchInformation
)
171 CHAR FunctionName
[256];
173 if (RosSymGetAddressInformation(LdrEntry
->PatchInformation
,
179 KdbPrintf("<%s:%x (%s:%d (%s))>",
180 ModuleNameAnsi
, RelativeAddress
,
181 FileName
, LineNumber
, FunctionName
);
188 /* Just print module & address */
189 KdbPrintf("<%s:%x>", ModuleNameAnsi
, RelativeAddress
);
195 static KSTART_ROUTINE LoadSymbolsRoutine
;
196 /*! \brief The symbol loader thread routine.
197 * This opens the image file for reading and loads the symbols
198 * section from there.
200 * \note We must do this because KdbSymProcessSymbols is
201 * called at high IRQL and we can't set the event from here
203 * \param Context Unused
205 _Use_decl_annotations_
211 UNREFERENCED_PARAMETER(Context
);
215 PLIST_ENTRY ListEntry
;
216 NTSTATUS Status
= KeWaitForSingleObject(&SymbolsToLoadEvent
, WrKernel
, KernelMode
, FALSE
, NULL
);
217 if (!NT_SUCCESS(Status
))
219 DPRINT1("KeWaitForSingleObject failed?! 0x%08x\n", Status
);
224 while ((ListEntry
= ExInterlockedRemoveHeadList(&SymbolsToLoad
, &SymbolsToLoadLock
)))
226 PLDR_DATA_TABLE_ENTRY LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderLinks
);
228 OBJECT_ATTRIBUTES Attrib
;
229 IO_STATUS_BLOCK Iosb
;
230 InitializeObjectAttributes(&Attrib
, &LdrEntry
->FullDllName
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
231 DPRINT1("Trying %wZ\n", &LdrEntry
->FullDllName
);
232 Status
= ZwOpenFile(&FileHandle
,
233 FILE_READ_ACCESS
| SYNCHRONIZE
,
237 FILE_SYNCHRONOUS_IO_NONALERT
);
238 if (!NT_SUCCESS(Status
))
240 /* Try system paths */
241 static const UNICODE_STRING System32Dir
= RTL_CONSTANT_STRING(L
"\\SystemRoot\\system32\\");
242 UNICODE_STRING ImagePath
;
243 WCHAR ImagePathBuffer
[256];
244 RtlInitEmptyUnicodeString(&ImagePath
, ImagePathBuffer
, sizeof(ImagePathBuffer
));
245 RtlCopyUnicodeString(&ImagePath
, &System32Dir
);
246 RtlAppendUnicodeStringToString(&ImagePath
, &LdrEntry
->BaseDllName
);
247 InitializeObjectAttributes(&Attrib
, &ImagePath
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
248 DPRINT1("Trying %wZ\n", &ImagePath
);
249 Status
= ZwOpenFile(&FileHandle
,
250 FILE_READ_ACCESS
| SYNCHRONIZE
,
254 FILE_SYNCHRONOUS_IO_NONALERT
);
255 if (!NT_SUCCESS(Status
))
257 static const UNICODE_STRING DriversDir
= RTL_CONSTANT_STRING(L
"\\SystemRoot\\system32\\drivers\\");
259 RtlInitEmptyUnicodeString(&ImagePath
, ImagePathBuffer
, sizeof(ImagePathBuffer
));
260 RtlCopyUnicodeString(&ImagePath
, &DriversDir
);
261 RtlAppendUnicodeStringToString(&ImagePath
, &LdrEntry
->BaseDllName
);
262 InitializeObjectAttributes(&Attrib
, &ImagePath
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
263 DPRINT1("Trying %wZ\n", &ImagePath
);
264 Status
= ZwOpenFile(&FileHandle
,
265 FILE_READ_ACCESS
| SYNCHRONIZE
,
269 FILE_SYNCHRONOUS_IO_NONALERT
);
273 if (!NT_SUCCESS(Status
))
275 DPRINT1("Failed opening file %wZ (%wZ) for reading symbols (0x%08x)\n", &LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
, Status
);
276 /* We took a ref previously */
277 MmUnloadSystemImage(LdrEntry
);
281 /* Hand it to Rossym */
282 if (!RosSymCreateFromFile(&FileHandle
, (PROSSYM_INFO
*)&LdrEntry
->PatchInformation
))
283 LdrEntry
->PatchInformation
= NULL
;
285 /* We're done for this one. */
287 MmUnloadSystemImage(LdrEntry
);
292 /*! \brief Load symbols from image mapping. If this fails,
294 * \param LdrEntry The entry to load symbols from
297 KdbSymProcessSymbols(
298 _Inout_ PLDR_DATA_TABLE_ENTRY LdrEntry
,
304 /* Check if this is unload */
307 /* Did we process it */
308 if (LdrEntry
->PatchInformation
)
310 RosSymDelete(LdrEntry
->PatchInformation
);
311 LdrEntry
->PatchInformation
= NULL
;
316 if (RosSymCreateFromMem(LdrEntry
->DllBase
, LdrEntry
->SizeOfImage
, (PROSSYM_INFO
*)&LdrEntry
->PatchInformation
))
321 /* Add a ref until we really process it */
322 LdrEntry
->LoadCount
++;
324 /* Tell our worker thread to read from it */
325 KeAcquireSpinLockAtDpcLevel(&SymbolsToLoadLock
);
326 InsertTailList(&SymbolsToLoad
, &LdrEntry
->InInitializationOrderLinks
);
327 KeReleaseSpinLockFromDpcLevel(&SymbolsToLoadLock
);
329 KeSetEvent(&SymbolsToLoadEvent
, IO_NO_INCREMENT
, FALSE
);
334 * @brief Initializes the KDB symbols implementation.
336 * @param[in] BootPhase
337 * Phase of initialization.
340 * TRUE if symbols are to be loaded at this given BootPhase; FALSE if not.
344 _In_ ULONG BootPhase
)
346 #if 1 // FIXME: This is a workaround HACK!!
347 static BOOLEAN OrigLoadSymbols
= FALSE
;
350 DPRINT("KdbSymInit() BootPhase=%d\n", BootPhase
);
358 /* By default, load symbols in DBG builds, but not in REL builds
359 or anything other than x86, because they only work on x86
360 and can cause the system to hang on x64. */
361 #if DBG && defined(_M_IX86)
367 /* Check the command line for LOADSYMBOLS, NOLOADSYMBOLS,
368 * LOADSYMBOLS={YES|NO}, NOLOADSYMBOLS={YES|NO} */
369 ASSERT(KeLoaderBlock
);
370 CommandLine
= KeLoaderBlock
->LoadOptions
;
373 /* Skip any whitespace */
374 while (isspace(*CommandLine
))
378 if (_strnicmp(CommandLine
, "LOADSYMBOLS", 11) == 0)
383 else if (_strnicmp(CommandLine
, "NOLOADSYMBOLS", 13) == 0)
390 if (*CommandLine
== '=')
393 YesNo
= toupper(*CommandLine
);
394 if (YesNo
== 'N' || YesNo
== '0')
399 LoadSymbols
= (0 < Found
);
402 /* Move on to the next option */
403 while (*CommandLine
&& !isspace(*CommandLine
))
407 #if 1 // FIXME: This is a workaround HACK!!
408 // Save the actual value of LoadSymbols but disable it for BootPhase 0.
409 OrigLoadSymbols
= LoadSymbols
;
411 return OrigLoadSymbols
;
414 else if (BootPhase
== 1)
419 PLIST_ENTRY ListEntry
;
421 #if 1 // FIXME: This is a workaround HACK!!
422 // Now, restore the actual value of LoadSymbols.
423 LoadSymbols
= OrigLoadSymbols
;
426 /* Do not continue loading symbols if we have less than 96MB of RAM */
427 if (MmNumberOfPhysicalPages
< (96 * 1024 * 1024 / PAGE_SIZE
))
430 /* Continue this phase only if we need to load symbols */
434 /* Launch our worker thread */
435 InitializeListHead(&SymbolsToLoad
);
436 KeInitializeSpinLock(&SymbolsToLoadLock
);
437 KeInitializeEvent(&SymbolsToLoadEvent
, SynchronizationEvent
, FALSE
);
439 Status
= PsCreateSystemThread(&Thread
,
444 if (!NT_SUCCESS(Status
))
446 DPRINT1("Failed starting symbols loader thread: 0x%08x\n", Status
);
451 RosSymInitKernelMode();
453 KeAcquireSpinLock(&PsLoadedModuleSpinLock
, &OldIrql
);
455 for (ListEntry
= PsLoadedModuleList
.Flink
;
456 ListEntry
!= &PsLoadedModuleList
;
457 ListEntry
= ListEntry
->Flink
)
459 PLDR_DATA_TABLE_ENTRY LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
460 KdbSymProcessSymbols(LdrEntry
, TRUE
);
463 KeReleaseSpinLock(&PsLoadedModuleSpinLock
, OldIrql
);