MiQueryVirtualMemory(): created because ZwQueryVirtualMemory() didn't work for me, added cases for memory area types that I needed to walk stack traces.

Stack traces now use MiQueryVirtualMemory to make sure they never step outside the allocated stack they started in ( this prevents page faults at high irql ) - for some reason this patch eliminates the NtW32Callback() crash everybody is seeing with GDI_DEBUG enabled, tho I don't understand why.

svn path=/trunk/; revision=12286
This commit is contained in:
Royce Mitchell III 2004-12-22 05:17:44 +00:00
parent 5dcad29338
commit 4cf6b9f489
3 changed files with 191 additions and 54 deletions

View file

@ -37,4 +37,12 @@ MiLockVirtualMemory(HANDLE ProcessHandle,
PMmProbeAndLockPages pMmProbeAndLockPages,
PExFreePool pExFreePool);
NTSTATUS FASTCALL
MiQueryVirtualMemory (IN HANDLE ProcessHandle,
IN PVOID Address,
IN CINT VirtualMemoryInformationClass,
OUT PVOID VirtualMemoryInformation,
IN ULONG Length,
OUT PULONG ResultLength);
#endif /* __NTOSKRNL_INCLUDE_INTERNAL_TEST_H */

View file

@ -630,16 +630,38 @@ KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
VOID
KeDumpStackFrames(PULONG Frame)
{
PULONG StackBase, StackEnd;
MEMORY_BASIC_INFORMATION mbi;
ULONG ResultLength = sizeof(mbi);
NTSTATUS Status;
DbgPrint("Frames: ");
_SEH_TRY
{
while ( MmIsAddressValid(Frame) )
Status = MiQueryVirtualMemory (
(HANDLE)-1,
Frame,
MemoryBasicInformation,
&mbi,
sizeof(mbi),
&ResultLength );
if ( !NT_SUCCESS(Status) )
{
DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
return;
}
StackBase = Frame;
StackEnd = mbi.BaseAddress + mbi.RegionSize;
while ( Frame >= StackBase && Frame < StackEnd )
{
ULONG Addr = Frame[1];
if (!KeRosPrintAddress((PVOID)Addr))
DbgPrint("<%X>", Addr);
if ( Addr == 0 || Addr == 0xDEADBEEF )
break;
StackBase = Frame;
Frame = (PULONG)Frame[0];
DbgPrint(" ");
}
@ -655,6 +677,10 @@ VOID STDCALL
KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
{
ULONG i=0;
PULONG StackBase, StackEnd;
MEMORY_BASIC_INFORMATION mbi;
ULONG ResultLength = sizeof(mbi);
NTSTATUS Status;
DbgPrint("Frames: ");
_SEH_TRY
@ -668,13 +694,31 @@ KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
#endif
//Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
}
while ( MmIsAddressValid(Frame) && i++ < FrameCount )
Status = MiQueryVirtualMemory (
(HANDLE)-1,
Frame,
MemoryBasicInformation,
&mbi,
sizeof(mbi),
&ResultLength );
if ( !NT_SUCCESS(Status) )
{
DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
return;
}
StackBase = Frame;
StackEnd = mbi.BaseAddress + mbi.RegionSize;
while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
{
ULONG Addr = Frame[1];
if (!KeRosPrintAddress((PVOID)Addr))
DbgPrint("<%X>", Addr);
if ( Addr == 0 || Addr == 0xDEADBEEF )
break;
StackBase = Frame;
Frame = (PULONG)Frame[0];
DbgPrint(" ");
}
@ -690,7 +734,11 @@ ULONG STDCALL
KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
{
ULONG Count = 0;
PULONG Frame;
PULONG StackBase, StackEnd, Frame;
MEMORY_BASIC_INFORMATION mbi;
ULONG ResultLength = sizeof(mbi);
NTSTATUS Status;
_SEH_TRY
{
#if defined __GNUC__
@ -698,9 +746,27 @@ KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
#elif defined(_MSC_VER)
__asm mov [Frame], ebp
#endif
while ( Count < FrameCount )
Status = MiQueryVirtualMemory (
(HANDLE)-1,
Frame,
MemoryBasicInformation,
&mbi,
sizeof(mbi),
&ResultLength );
if ( !NT_SUCCESS(Status) )
{
DPRINT1("Can't get stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
return 0;
}
StackBase = Frame;
StackEnd = mbi.BaseAddress + mbi.RegionSize;
while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
{
Frames[Count++] = Frame[1];
StackBase = Frame;
Frame = (PULONG)Frame[0];
}
}

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: virtual.c,v 1.85 2004/11/13 22:27:16 hbirr Exp $
/* $Id: virtual.c,v 1.86 2004/12/22 05:17:44 royce Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/virtual.c
@ -41,12 +41,12 @@ NtFlushVirtualMemory(IN HANDLE ProcessHandle,
/*
* FUNCTION: Flushes virtual memory to file
* ARGUMENTS:
* ProcessHandle = Points to the process that allocated the virtual
* ProcessHandle = Points to the process that allocated the virtual
* memory
* BaseAddress = Points to the memory address
* NumberOfBytesToFlush = Limits the range to flush,
* NumberOfBytesFlushed = Actual number of bytes flushed
* RETURNS: Status
* RETURNS: Status
*/
{
UNIMPLEMENTED;
@ -125,43 +125,18 @@ NtLockVirtualMemory(HANDLE ProcessHandle,
}
/* (tMk 2004.II.4)
* FUNCTION:
* Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
*
*/
NTSTATUS STDCALL
NtQueryVirtualMemory (IN HANDLE ProcessHandle,
NTSTATUS FASTCALL
MiQueryVirtualMemory (IN HANDLE ProcessHandle,
IN PVOID Address,
IN CINT VirtualMemoryInformationClass,
OUT PVOID VirtualMemoryInformation,
IN ULONG Length,
OUT PULONG UnsafeResultLength)
OUT PULONG ResultLength)
{
NTSTATUS Status;
PEPROCESS Process;
MEMORY_AREA* MemoryArea;
ULONG ResultLength = 0;
PMADDRESS_SPACE AddressSpace;
KPROCESSOR_MODE PrevMode;
union
{
MEMORY_BASIC_INFORMATION BasicInfo;
}
VirtualMemoryInfo;
DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
"VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
"Length %lu ResultLength %x)\n",ProcessHandle,Address,
VirtualMemoryInformationClass,VirtualMemoryInformation,
Length,ResultLength);
PrevMode = ExGetPreviousMode();
if (PrevMode == UserMode && Address >= (PVOID)KERNEL_BASE)
{
return STATUS_INVALID_PARAMETER;
}
if (Address < (PVOID)KERNEL_BASE)
{
@ -190,14 +165,15 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
{
case MemoryBasicInformation:
{
PMEMORY_BASIC_INFORMATION Info = &VirtualMemoryInfo.BasicInfo;
PMEMORY_BASIC_INFORMATION Info =
(PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
if (Length != sizeof(MEMORY_BASIC_INFORMATION))
{
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_INFO_LENGTH_MISMATCH);
}
if (MemoryArea == NULL)
{
Info->Type = 0;
@ -208,19 +184,19 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
Info->AllocationBase = NULL;
Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
Status = STATUS_SUCCESS;
ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
}
else
else
{
switch(MemoryArea->Type)
{
case MEMORY_AREA_VIRTUAL_MEMORY:
Status = MmQueryAnonMem(MemoryArea, Address, Info,
&ResultLength);
ResultLength);
break;
case MEMORY_AREA_SECTION_VIEW:
Status = MmQuerySectionView(MemoryArea, Address, Info,
&ResultLength);
ResultLength);
break;
case MEMORY_AREA_NO_ACCESS:
Info->Type = 0;
@ -231,7 +207,7 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
Info->AllocationBase = MemoryArea->BaseAddress;
Info->RegionSize = MemoryArea->Length;
Status = STATUS_SUCCESS;
ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
break;
case MEMORY_AREA_SHARED_DATA:
Info->Type = 0;
@ -242,11 +218,52 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
Info->AllocationBase = MemoryArea->BaseAddress;
Info->RegionSize = MemoryArea->Length;
Status = STATUS_SUCCESS;
ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
break;
case MEMORY_AREA_SYSTEM:
{
static int warned = 0;
if ( !warned )
{
DPRINT1("FIXME: MEMORY_AREA_SYSTEM case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
warned = 1;
}
}
/* FIXME - don't have a clue if this is right, but it's better than nothing */
Info->Type = 0;
Info->State = MEM_COMMIT;
Info->Protect = MemoryArea->Attributes;
Info->AllocationProtect = MemoryArea->Attributes;
Info->BaseAddress = MemoryArea->BaseAddress;
Info->AllocationBase = MemoryArea->BaseAddress;
Info->RegionSize = MemoryArea->Length;
Status = STATUS_SUCCESS;
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
break;
case MEMORY_AREA_KERNEL_STACK:
{
static int warned = 0;
if ( !warned )
{
DPRINT1("FIXME: MEMORY_AREA_KERNEL_STACK case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
warned = 1;
}
}
/* FIXME - don't have a clue if this is right, but it's better than nothing */
Info->Type = 0;
Info->State = MEM_COMMIT;
Info->Protect = MemoryArea->Attributes;
Info->AllocationProtect = MemoryArea->Attributes;
Info->BaseAddress = MemoryArea->BaseAddress;
Info->AllocationBase = MemoryArea->BaseAddress;
Info->RegionSize = MemoryArea->Length;
Status = STATUS_SUCCESS;
*ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
break;
default:
DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
Status = STATUS_UNSUCCESSFUL;
ResultLength = 0;
*ResultLength = 0;
}
}
break;
@ -255,7 +272,7 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
default:
{
Status = STATUS_INVALID_INFO_CLASS;
ResultLength = 0;
*ResultLength = 0;
break;
}
}
@ -266,6 +283,52 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
ObDereferenceObject(Process);
}
return Status;
}
/* (tMk 2004.II.4)
* FUNCTION:
* Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
*
*/
NTSTATUS STDCALL
NtQueryVirtualMemory (IN HANDLE ProcessHandle,
IN PVOID Address,
IN CINT VirtualMemoryInformationClass,
OUT PVOID VirtualMemoryInformation,
IN ULONG Length,
OUT PULONG UnsafeResultLength)
{
NTSTATUS Status;
ULONG ResultLength = 0;
KPROCESSOR_MODE PrevMode;
union
{
MEMORY_BASIC_INFORMATION BasicInfo;
}
VirtualMemoryInfo;
DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
"VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
"Length %lu ResultLength %x)\n",ProcessHandle,Address,
VirtualMemoryInformationClass,VirtualMemoryInformation,
Length,ResultLength);
PrevMode = ExGetPreviousMode();
if (PrevMode == UserMode && Address >= (PVOID)KERNEL_BASE)
{
DPRINT1("Invalid parameter\n");
return STATUS_INVALID_PARAMETER;
}
Status = MiQueryVirtualMemory ( ProcessHandle,
Address,
VirtualMemoryInformationClass,
&VirtualMemoryInfo,
Length,
&ResultLength );
if (NT_SUCCESS(Status) && ResultLength > 0)
{
Status = MmCopyToCaller(VirtualMemoryInformation, &VirtualMemoryInfo, ResultLength);
@ -274,7 +337,7 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
ResultLength = 0;
}
}
if (UnsafeResultLength != NULL)
{
MmCopyToCaller(UnsafeResultLength, &ResultLength, sizeof(ULONG));
@ -284,7 +347,7 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
/* (tMk 2004.II.5)
* FUNCTION:
* FUNCTION:
* Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
*
*/
@ -310,13 +373,13 @@ NtProtectVirtualMemory(IN HANDLE ProcessHandle,
if (!NT_SUCCESS(Status))
return Status;
// (tMk 2004.II.5) in Microsoft SDK I read:
// (tMk 2004.II.5) in Microsoft SDK I read:
// 'if this parameter is NULL or does not point to a valid variable, the function fails'
if(UnsafeOldAccessProtection == NULL)
if(UnsafeOldAccessProtection == NULL)
{
return(STATUS_INVALID_PARAMETER);
}
NumberOfBytesToProtect =
PAGE_ROUND_UP(BaseAddress + NumberOfBytesToProtect) -
PAGE_ROUND_DOWN(BaseAddress);
@ -372,7 +435,7 @@ NtProtectVirtualMemory(IN HANDLE ProcessHandle,
/* (tMk 2004.II.05)
* FUNCTION:
* FUNCTION:
* Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
*
* NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
@ -416,7 +479,7 @@ NtReadVirtualMemory(IN HANDLE ProcessHandle,
Mdl = MmCreateMdl(NULL,
Buffer,
NumberOfBytesToRead);
if(Mdl == NULL)
if(Mdl == NULL)
{
ObDereferenceObject(Process);
return(STATUS_NO_MEMORY);
@ -482,7 +545,7 @@ NtUnlockVirtualMemory(HANDLE ProcessHandle,
Mdl = MmCreateMdl(NULL,
BaseAddress,
NumberOfBytesToUnlock);
if(Mdl == NULL)
if(Mdl == NULL)
{
ObDereferenceObject(Process);
return(STATUS_NO_MEMORY);
@ -506,7 +569,7 @@ NtUnlockVirtualMemory(HANDLE ProcessHandle,
/* (tMk 2004.II.05)
* FUNCTION:
* Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
*
*
* NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
*/
NTSTATUS STDCALL