summaryrefslogtreecommitdiffstats
path: root/private/ntos/ke/ppc/dmpstate.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/ke/ppc/dmpstate.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/ke/ppc/dmpstate.c')
-rw-r--r--private/ntos/ke/ppc/dmpstate.c797
1 files changed, 797 insertions, 0 deletions
diff --git a/private/ntos/ke/ppc/dmpstate.c b/private/ntos/ke/ppc/dmpstate.c
new file mode 100644
index 000000000..335d5078a
--- /dev/null
+++ b/private/ntos/ke/ppc/dmpstate.c
@@ -0,0 +1,797 @@
+/*++
+
+Copyright (c) 1993 IBM and Microsoft Corporation
+
+Module Name:
+
+ dmpstate.c
+
+Abstract:
+
+ This module implements the architecture specific routine that dumps
+ the machine state when a bug check occurs and no debugger is hooked
+ to the system. It is assumed that it is called from bug check.
+
+Author:
+
+ Chuck Bauman 19-Sep-1993
+
+Environment:
+
+ Kernel mode.
+
+Revision History:
+
+ Based on Dave Cutler's MIPS implemenation
+
+ Tom Wood (twood) 19-Aug-1994
+ Update to use RtlVirtualUnwind even when there isn't a function table
+ entry. Add stack limit parameters to RtlVirtualUnwind.
+
+ Changed KiLookupFunctionEntry to deal with the indirect entries.
+
+--*/
+
+#include "ki.h"
+
+//
+// Define forward referenced prototypes.
+//
+
+VOID
+KiDisplayString (
+ IN ULONG Column,
+ IN ULONG Row,
+ IN PCHAR Buffer
+ );
+
+PRUNTIME_FUNCTION
+KiLookupFunctionEntry (
+ IN ULONG ControlPc
+ );
+
+PVOID
+KiPcToFileHeader(
+ IN PVOID PcValue,
+ OUT PVOID *BaseOfImage,
+ OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry
+ );
+
+//
+// Define external data.
+//
+
+extern LIST_ENTRY PsLoadedModuleList;
+
+VOID
+KeDumpMachineState (
+ IN PKPROCESSOR_STATE ProcessorState,
+ IN PCHAR Buffer,
+ IN PULONG BugCheckParameters,
+ IN ULONG NumberOfParameters,
+ IN PKE_BUGCHECK_UNICODE_TO_ANSI UnicodeToAnsiRoutine
+ )
+
+/*++
+
+Routine Description:
+
+ This function formats and displays the machine state at the time of the
+ to bug check.
+
+Arguments:
+
+ ProcessorState - Supplies a pointer to a processor state record.
+
+ Buffer - Supplies a pointer to a buffer to be used to output machine
+ state information.
+
+ BugCheckParameters - Supplies a pointer to an array of additional
+ bug check information.
+
+ NumberOfParameters - Suppiles the size of the bug check parameters
+ array.
+
+ UnicodeToAnsiRoutine - Supplies a pointer to a routine to convert Unicode strings
+ to Ansi strings without touching paged translation tables.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PCONTEXT ContextRecord;
+ ULONG ControlPc;
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ ULONG DisplayColumn;
+ ULONG DisplayHeight;
+ ULONG DisplayRow;
+ ULONG DisplayWidth;
+ UNICODE_STRING DllName;
+ ULONG EstablisherFrame;
+ PRUNTIME_FUNCTION FunctionEntry;
+ PVOID ImageBase;
+ ULONG Index;
+ BOOLEAN InFunction;
+ ULONG LastStack;
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY NextEntry;
+ ULONG NextPc;
+ ULONG StackLimit;
+ UCHAR AnsiBuffer[ 32 ];
+ ULONG DateStamp;
+
+ //
+ // Call the HAL to force all external interrupts to be disabled
+ // at the interrupt controller. PowerPC optimization does not
+ // do this when raising to high level.
+ //
+ for (Index = 0; Index < MAXIMUM_VECTOR; Index++) {
+ HalDisableSystemInterrupt(Index, HIGH_LEVEL);
+ }
+
+ //
+ // Query display parameters.
+ //
+
+ HalQueryDisplayParameters(&DisplayWidth,
+ &DisplayHeight,
+ &DisplayColumn,
+ &DisplayRow);
+
+ //
+ // Display any addresses that fall within the range of any module in
+ // the loaded module list.
+ //
+
+ for (Index = 0; Index < NumberOfParameters; Index += 1) {
+ ImageBase = KiPcToFileHeader((PVOID)*BugCheckParameters,
+ &ImageBase,
+ &DataTableEntry);
+
+ if (ImageBase != NULL) {
+ sprintf(Buffer,
+ "*** %08lX has base at %08lX - %s\n",
+ *BugCheckParameters,
+ ImageBase,
+ (*UnicodeToAnsiRoutine)( &DataTableEntry->BaseDllName, AnsiBuffer, sizeof( AnsiBuffer )));
+
+ HalDisplayString(Buffer);
+ }
+
+ BugCheckParameters += 1;
+ }
+
+ //
+ // Virtually unwind to the caller of bug check.
+ //
+
+ ContextRecord = &ProcessorState->ContextFrame;
+ LastStack = ContextRecord->Gpr1;
+ ControlPc = ContextRecord->Lr - 4;
+ NextPc = ControlPc;
+ FunctionEntry = KiLookupFunctionEntry(ControlPc);
+ if (FunctionEntry != NULL) {
+ NextPc = RtlVirtualUnwind(ControlPc,
+ FunctionEntry,
+ ContextRecord,
+ &InFunction,
+ &EstablisherFrame,
+ NULL,
+ 0,
+ 0xffffffff);
+ }
+
+ //
+ // At this point the context record contains the machine state at the
+ // call to bug check.
+ //
+ // Put out the machine state at the time of the bugcheck.
+ //
+
+ sprintf(Buffer,
+ "\n Machine State at Call to Bug Check IAR:%08lX MSR:%08lX\n",
+ ContextRecord->Lr,
+ ContextRecord->Msr);
+
+ HalDisplayString(Buffer);
+
+ //
+ // Format and output the integer registers.
+ //
+
+ sprintf(Buffer,
+ " R0:%8lX R1:%8lX R2:%8lX R3:%8lX R4:%8lX R5:%8lX\n",
+ ContextRecord->Gpr0,
+ ContextRecord->Gpr1,
+ ContextRecord->Gpr2,
+ ContextRecord->Gpr3,
+ ContextRecord->Gpr4,
+ ContextRecord->Gpr5);
+
+ HalDisplayString(Buffer);
+
+ sprintf(Buffer,
+ " R6:%8lX R7:%8lX R8:%8lX R9:%8lX R10:%8lX R11:%8lX\n",
+ ContextRecord->Gpr6,
+ ContextRecord->Gpr7,
+ ContextRecord->Gpr8,
+ ContextRecord->Gpr9,
+ ContextRecord->Gpr10,
+ ContextRecord->Gpr11);
+
+ HalDisplayString(Buffer);
+
+ sprintf(Buffer,
+ "R12:%8lX R13:%8lX R14:%8lX R15:%8lX R16:%8lX R17:%8lX\n",
+ ContextRecord->Gpr12,
+ ContextRecord->Gpr13,
+ ContextRecord->Gpr14,
+ ContextRecord->Gpr15,
+ ContextRecord->Gpr16,
+ ContextRecord->Gpr17);
+
+ HalDisplayString(Buffer);
+
+ sprintf(Buffer,
+ "R18:%8lX R19:%8lX R20:%8lX R21:%8lX R22:%8lX R23:%8lX\n",
+ ContextRecord->Gpr18,
+ ContextRecord->Gpr19,
+ ContextRecord->Gpr20,
+ ContextRecord->Gpr21,
+ ContextRecord->Gpr22,
+ ContextRecord->Gpr23);
+
+ HalDisplayString(Buffer);
+
+ sprintf(Buffer,
+ "R24:%8lX R25:%8lX R26:%8lX R27:%8lX R28:%8lX R29:%8lX\n",
+ ContextRecord->Gpr24,
+ ContextRecord->Gpr25,
+ ContextRecord->Gpr26,
+ ContextRecord->Gpr27,
+ ContextRecord->Gpr28,
+ ContextRecord->Gpr29);
+
+ HalDisplayString(Buffer);
+
+ sprintf(Buffer,
+ "R30:%8lX R31:%8lX CR:%8lX CTR:%8lX XER:%8lX\n",
+ ContextRecord->Gpr30,
+ ContextRecord->Gpr31,
+ ContextRecord->Cr,
+ ContextRecord->Ctr,
+ ContextRecord->Xer);
+
+ HalDisplayString(Buffer);
+
+#if 0
+
+ //
+ // I'd much rather see a longer stack trace and skip the floating
+ // point stuff when the system crashes. plj
+ //
+
+ //
+ // Format and output the floating registers.
+ //
+ DumpFloat = (PULONG)(&ContextRecord->Fpr0);
+ sprintf(Buffer,
+ " F0- F3:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n",
+ *(DumpFloat+1),
+ *DumpFloat,
+ *(DumpFloat+3),
+ *(DumpFloat+2),
+ *(DumpFloat+5),
+ *(DumpFloat+4),
+ *(DumpFloat+7),
+ *(DumpFloat+6));
+
+ HalDisplayString(Buffer);
+
+ DumpFloat = (PULONG)(&ContextRecord->Fpr4);
+ sprintf(Buffer,
+ " F4- F7:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n",
+ *(DumpFloat+1),
+ *DumpFloat,
+ *(DumpFloat+3),
+ *(DumpFloat+2),
+ *(DumpFloat+5),
+ *(DumpFloat+4),
+ *(DumpFloat+7),
+ *(DumpFloat+6));
+
+ HalDisplayString(Buffer);
+
+ DumpFloat = (PULONG)(&ContextRecord->Fpr8);
+ sprintf(Buffer,
+ " F8-F11:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n",
+ *(DumpFloat+1),
+ *DumpFloat,
+ *(DumpFloat+3),
+ *(DumpFloat+2),
+ *(DumpFloat+5),
+ *(DumpFloat+4),
+ *(DumpFloat+7),
+ *(DumpFloat+6));
+
+ HalDisplayString(Buffer);
+
+ DumpFloat = (PULONG)(&ContextRecord->Fpr12);
+ sprintf(Buffer,
+ "F12-F15:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n",
+ *(DumpFloat+1),
+ *DumpFloat,
+ *(DumpFloat+3),
+ *(DumpFloat+2),
+ *(DumpFloat+5),
+ *(DumpFloat+4),
+ *(DumpFloat+7),
+ *(DumpFloat+6));
+
+ HalDisplayString(Buffer);
+
+ DumpFloat = (PULONG)(&ContextRecord->Fpr16);
+ sprintf(Buffer,
+ "F16-F19:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n",
+ *(DumpFloat+1),
+ *DumpFloat,
+ *(DumpFloat+3),
+ *(DumpFloat+2),
+ *(DumpFloat+5),
+ *(DumpFloat+4),
+ *(DumpFloat+7),
+ *(DumpFloat+6));
+
+ HalDisplayString(Buffer);
+
+ DumpFloat = (PULONG)(&ContextRecord->Fpr20);
+ sprintf(Buffer,
+ "F20-F23:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n",
+ *(DumpFloat+1),
+ *DumpFloat,
+ *(DumpFloat+3),
+ *(DumpFloat+2),
+ *(DumpFloat+5),
+ *(DumpFloat+4),
+ *(DumpFloat+7),
+ *(DumpFloat+6));
+
+ HalDisplayString(Buffer);
+
+ DumpFloat = (PULONG)(&ContextRecord->Fpr24);
+ sprintf(Buffer,
+ "F24-F27:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n",
+ *(DumpFloat+1),
+ *DumpFloat,
+ *(DumpFloat+3),
+ *(DumpFloat+2),
+ *(DumpFloat+5),
+ *(DumpFloat+4),
+ *(DumpFloat+7),
+ *(DumpFloat+6));
+
+ HalDisplayString(Buffer);
+
+ DumpFloat = (PULONG)(&ContextRecord->Fpr28);
+ sprintf(Buffer,
+ "F28-F31:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n",
+ *(DumpFloat+1),
+ *DumpFloat,
+ *(DumpFloat+3),
+ *(DumpFloat+2),
+ *(DumpFloat+5),
+ *(DumpFloat+4),
+ *(DumpFloat+7),
+ *(DumpFloat+6));
+
+ HalDisplayString(Buffer);
+
+
+ DumpFloat = (PULONG)(&ContextRecord->Fpscr);
+ sprintf(Buffer,
+ " FPSCR:%08lX%08lX\n",
+ *(DumpFloat+1),
+ *DumpFloat);
+
+ HalDisplayString(Buffer);
+
+#define STAKWALK 4
+#else
+#define STAKWALK 8
+#endif
+
+ //
+ // Output short stack back trace with base address.
+ //
+
+ DllName.Length = 0;
+ DllName.Buffer = L"";
+ if (FunctionEntry != NULL) {
+ StackLimit = (ULONG)KeGetCurrentThread()->KernelStack;
+ HalDisplayString("Callee-Sp Return-Ra Dll Base - Name\n");
+ for (Index = 0; Index < STAKWALK; Index += 1) {
+ ImageBase = KiPcToFileHeader((PVOID)ControlPc,
+ &ImageBase,
+ &DataTableEntry);
+
+ sprintf(Buffer,
+ " %08lX %08lX : %08lX - %s\n",
+ ContextRecord->Gpr1,
+ NextPc + 4,
+ ImageBase,
+ (*UnicodeToAnsiRoutine)( (ImageBase != NULL) ? &DataTableEntry->BaseDllName : &DllName,
+ AnsiBuffer, sizeof( AnsiBuffer )));
+
+ HalDisplayString(Buffer);
+
+ if ((NextPc != ControlPc) || (ContextRecord->Gpr1 != LastStack)) {
+ ControlPc = NextPc;
+ LastStack = ContextRecord->Gpr1;
+ FunctionEntry = KiLookupFunctionEntry(ControlPc);
+ if ((FunctionEntry != NULL) && (LastStack < StackLimit)) {
+ NextPc = RtlVirtualUnwind(ControlPc,
+ FunctionEntry,
+ ContextRecord,
+ &InFunction,
+ &EstablisherFrame,
+ NULL,
+ 0,
+ 0xffffffff);
+ } else {
+ NextPc = ContextRecord->Lr;
+ }
+
+ } else {
+ break;
+ }
+ }
+ }
+
+ //
+ // Output the build number and other useful information.
+ //
+
+ sprintf(Buffer,
+ "\nIRQL : %d, DPC Active : %s, SYSVER 0x%08x\n",
+ KeGetCurrentIrql(),
+ KeIsExecutingDpc() ? "TRUE" : "FALSE",
+ NtBuildNumber);
+
+ HalDisplayString(Buffer);
+
+ //
+ // Output the processor id and the primary cache sizes.
+ //
+
+ sprintf(Buffer,
+ "Processor Id: %d.%d, Icache: %d, Dcache: %d",
+ PCR->ProcessorVersion,
+ PCR->ProcessorRevision,
+ PCR->FirstLevelIcacheSize,
+ PCR->FirstLevelDcacheSize);
+
+ HalDisplayString(Buffer);
+
+ //
+ // If the display width is greater than 80 + 24 (the size of a DLL
+ // name and base address), then display all the modules loaded in
+ // the system.
+ //
+
+ HalQueryDisplayParameters(&DisplayWidth,
+ &DisplayHeight,
+ &DisplayColumn,
+ &DisplayRow);
+
+ if (DisplayWidth > (80 + 24)) {
+ HalDisplayString("\n");
+ if (KeLoaderBlock != NULL) {
+ ModuleListHead = &KeLoaderBlock->LoadOrderListHead;
+
+ } else {
+ ModuleListHead = &PsLoadedModuleList;
+ }
+
+ //
+ // Output display headers.
+ //
+
+ Index = 1;
+ KiDisplayString(80, Index, "Dll Base DateStmp - Name");
+ NextEntry = ModuleListHead->Flink;
+ if (NextEntry != NULL) {
+
+ //
+ // Scan the list of loaded modules and display their base
+ // address and name.
+ //
+
+ while (NextEntry != ModuleListHead) {
+ Index += 1;
+ DataTableEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ if (MmDbgReadCheck(DataTableEntry->DllBase) != NULL) {
+ PIMAGE_NT_HEADERS NtHeaders;
+
+ NtHeaders = RtlImageNtHeader(DataTableEntry->DllBase);
+ DateStamp = NtHeaders->FileHeader.TimeDateStamp;
+
+ } else {
+ DateStamp = 0;
+ }
+ sprintf(Buffer,
+ "%08lX %08lx - %s",
+ DataTableEntry->DllBase,
+ DateStamp,
+ (*UnicodeToAnsiRoutine)( &DataTableEntry->BaseDllName, AnsiBuffer, sizeof( AnsiBuffer )));
+
+ KiDisplayString(80, Index, Buffer);
+ NextEntry = NextEntry->Flink;
+ if (Index > DisplayHeight) {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Reset the current display position.
+ //
+
+ HalSetDisplayParameters(DisplayColumn, DisplayRow);
+
+ //
+ // The system has crashed, if we are running without the Kernel
+ // debugger attached, attach it now.
+ //
+
+ KdInitSystem(NULL, FALSE);
+
+ return;
+}
+
+VOID
+KiDisplayString (
+ IN ULONG Column,
+ IN ULONG Row,
+ IN PCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This function display a string starting at the specified column and row
+ position on the screen.
+
+Arguments:
+
+ Column - Supplies the starting column of where the string is displayed.
+
+ Row - Supplies the starting row of where the string is displayed.
+
+ Bufer - Supplies a pointer to the string that is displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Position the cursor and display the string.
+ //
+
+ HalSetDisplayParameters(Column, Row);
+ HalDisplayString(Buffer);
+ return;
+}
+
+PRUNTIME_FUNCTION
+KiLookupFunctionEntry (
+ IN ULONG ControlPc
+ )
+
+/*++
+
+Routine Description:
+
+ This function searches the currently active function tables for an entry
+ that corresponds to the specified PC value.
+
+Arguments:
+
+ ControlPc - Supplies the address of an instruction within the specified
+ function.
+
+Return Value:
+
+ If there is no entry in the function table for the specified PC, then
+ NULL is returned. Otherwise, the address of the function table entry
+ that corresponds to the specified PC is returned.
+
+--*/
+
+{
+
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ PRUNTIME_FUNCTION FunctionEntry;
+ PRUNTIME_FUNCTION FunctionTable;
+ ULONG SizeOfExceptionTable;
+ LONG High;
+ PVOID ImageBase;
+ LONG Low;
+ LONG Middle;
+
+ //
+ // Search for the image that includes the specified PC value.
+ //
+
+ ImageBase = KiPcToFileHeader((PVOID)ControlPc,
+ &ImageBase,
+ &DataTableEntry);
+
+ //
+ // If an image is found that includes the specified PC, then locate the
+ // function table for the image.
+ //
+
+ if (ImageBase != NULL) {
+ FunctionTable = (PRUNTIME_FUNCTION)RtlImageDirectoryEntryToData(
+ ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION,
+ &SizeOfExceptionTable);
+
+ //
+ // If a function table is located, then search the function table
+ // for a function table entry for the specified PC.
+ //
+
+ if (FunctionTable != NULL) {
+
+ //
+ // Initialize search indicies.
+ //
+
+ Low = 0;
+ High = (SizeOfExceptionTable / sizeof(RUNTIME_FUNCTION)) - 1;
+
+ //
+ // Perform binary search on the function table for a function table
+ // entry that subsumes the specified PC.
+ //
+
+ while (High >= Low) {
+
+ //
+ // Compute next probe index and test entry. If the specified PC
+ // is greater than of equal to the beginning address and less
+ // than the ending address of the function table entry, then
+ // return the address of the function table entry. Otherwise,
+ // continue the search.
+ //
+
+ Middle = (Low + High) >> 1;
+ FunctionEntry = &FunctionTable[Middle];
+ if (ControlPc < FunctionEntry->BeginAddress) {
+ High = Middle - 1;
+
+ } else if (ControlPc >= FunctionEntry->EndAddress) {
+ Low = Middle + 1;
+
+ } else {
+
+ //
+ // The capability exists for more than one function entry
+ // to map to the same function. This permits a function to
+ // have (within reason) discontiguous code segment(s). If
+ // PrologEndAddress is out of range, it is re-interpreted
+ // as a pointer to the primary function table entry for
+ // that function. The out of range test takes into account
+ // the redundant encoding of millicode and glue code.
+ //
+
+ if (((FunctionEntry->PrologEndAddress < FunctionEntry->BeginAddress) ||
+ (FunctionEntry->PrologEndAddress >= FunctionEntry->EndAddress)) &&
+ (FunctionEntry->PrologEndAddress & 3) == 0) {
+ FunctionEntry = (PRUNTIME_FUNCTION)FunctionEntry->PrologEndAddress;
+ }
+
+ return FunctionEntry;
+ }
+ }
+ }
+ }
+
+ //
+ // A function table entry for the specified PC was not found.
+ //
+
+ return NULL;
+}
+
+PVOID
+KiPcToFileHeader(
+ IN PVOID PcValue,
+ OUT PVOID *BaseOfImage,
+ OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the base of an image that contains the
+ specified PcValue. An image contains the PcValue if the PcValue
+ is within the ImageBase, and the ImageBase plus the size of the
+ virtual image.
+
+Arguments:
+
+ PcValue - Supplies a PcValue.
+
+ BaseOfImage - Returns the base address for the image containing the
+ PcValue. This value must be added to any relative addresses in
+ the headers to locate portions of the image.
+
+ DataTableEntry - Suppies a pointer to a variable that receives the
+ address of the data table entry that describes the image.
+
+Return Value:
+
+ NULL - No image was found that contains the PcValue.
+
+ NON-NULL - Returns the base address of the image that contain the
+ PcValue.
+
+--*/
+
+{
+
+ PLIST_ENTRY ModuleListHead;
+ PLDR_DATA_TABLE_ENTRY Entry;
+ PLIST_ENTRY Next;
+ ULONG Bounds;
+ PVOID ReturnBase, Base;
+
+ //
+ // If the module list has been initialized, then scan the list to
+ // locate the appropriate entry.
+ //
+
+ if (KeLoaderBlock != NULL) {
+ ModuleListHead = &KeLoaderBlock->LoadOrderListHead;
+
+ } else {
+ ModuleListHead = &PsLoadedModuleList;
+ }
+
+ ReturnBase = NULL;
+ Next = ModuleListHead->Flink;
+ if (Next != NULL) {
+ while (Next != ModuleListHead) {
+ Entry = CONTAINING_RECORD(Next,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ Next = Next->Flink;
+ Base = Entry->DllBase;
+ Bounds = (ULONG)Base + Entry->SizeOfImage;
+ if ((ULONG)PcValue >= (ULONG)Base && (ULONG)PcValue < Bounds) {
+ *DataTableEntry = Entry;
+ ReturnBase = Base;
+ break;
+ }
+ }
+ }
+
+ *BaseOfImage = ReturnBase;
+ return ReturnBase;
+}