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, PMmProbeAndLockPages pMmProbeAndLockPages,
PExFreePool pExFreePool); 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 */ #endif /* __NTOSKRNL_INCLUDE_INTERNAL_TEST_H */

View file

@ -630,16 +630,38 @@ KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
VOID VOID
KeDumpStackFrames(PULONG Frame) KeDumpStackFrames(PULONG Frame)
{ {
PULONG StackBase, StackEnd;
MEMORY_BASIC_INFORMATION mbi;
ULONG ResultLength = sizeof(mbi);
NTSTATUS Status;
DbgPrint("Frames: "); DbgPrint("Frames: ");
_SEH_TRY _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]; ULONG Addr = Frame[1];
if (!KeRosPrintAddress((PVOID)Addr)) if (!KeRosPrintAddress((PVOID)Addr))
DbgPrint("<%X>", Addr); DbgPrint("<%X>", Addr);
if ( Addr == 0 || Addr == 0xDEADBEEF ) if ( Addr == 0 || Addr == 0xDEADBEEF )
break; break;
StackBase = Frame;
Frame = (PULONG)Frame[0]; Frame = (PULONG)Frame[0];
DbgPrint(" "); DbgPrint(" ");
} }
@ -655,6 +677,10 @@ VOID STDCALL
KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount ) KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
{ {
ULONG i=0; ULONG i=0;
PULONG StackBase, StackEnd;
MEMORY_BASIC_INFORMATION mbi;
ULONG ResultLength = sizeof(mbi);
NTSTATUS Status;
DbgPrint("Frames: "); DbgPrint("Frames: ");
_SEH_TRY _SEH_TRY
@ -668,13 +694,31 @@ KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
#endif #endif
//Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames //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]; ULONG Addr = Frame[1];
if (!KeRosPrintAddress((PVOID)Addr)) if (!KeRosPrintAddress((PVOID)Addr))
DbgPrint("<%X>", Addr); DbgPrint("<%X>", Addr);
if ( Addr == 0 || Addr == 0xDEADBEEF ) if ( Addr == 0 || Addr == 0xDEADBEEF )
break; break;
StackBase = Frame;
Frame = (PULONG)Frame[0]; Frame = (PULONG)Frame[0];
DbgPrint(" "); DbgPrint(" ");
} }
@ -690,7 +734,11 @@ ULONG STDCALL
KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount ) KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
{ {
ULONG Count = 0; ULONG Count = 0;
PULONG Frame; PULONG StackBase, StackEnd, Frame;
MEMORY_BASIC_INFORMATION mbi;
ULONG ResultLength = sizeof(mbi);
NTSTATUS Status;
_SEH_TRY _SEH_TRY
{ {
#if defined __GNUC__ #if defined __GNUC__
@ -698,9 +746,27 @@ KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
__asm mov [Frame], ebp __asm mov [Frame], ebp
#endif #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]; Frames[Count++] = Frame[1];
StackBase = Frame;
Frame = (PULONG)Frame[0]; Frame = (PULONG)Frame[0];
} }
} }

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/virtual.c * FILE: ntoskrnl/mm/virtual.c
@ -125,43 +125,18 @@ NtLockVirtualMemory(HANDLE ProcessHandle,
} }
/* (tMk 2004.II.4) NTSTATUS FASTCALL
* FUNCTION: MiQueryVirtualMemory (IN HANDLE ProcessHandle,
* Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
*
*/
NTSTATUS STDCALL
NtQueryVirtualMemory (IN HANDLE ProcessHandle,
IN PVOID Address, IN PVOID Address,
IN CINT VirtualMemoryInformationClass, IN CINT VirtualMemoryInformationClass,
OUT PVOID VirtualMemoryInformation, OUT PVOID VirtualMemoryInformation,
IN ULONG Length, IN ULONG Length,
OUT PULONG UnsafeResultLength) OUT PULONG ResultLength)
{ {
NTSTATUS Status; NTSTATUS Status;
PEPROCESS Process; PEPROCESS Process;
MEMORY_AREA* MemoryArea; MEMORY_AREA* MemoryArea;
ULONG ResultLength = 0;
PMADDRESS_SPACE AddressSpace; 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) if (Address < (PVOID)KERNEL_BASE)
{ {
@ -190,7 +165,8 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
{ {
case MemoryBasicInformation: case MemoryBasicInformation:
{ {
PMEMORY_BASIC_INFORMATION Info = &VirtualMemoryInfo.BasicInfo; PMEMORY_BASIC_INFORMATION Info =
(PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
if (Length != sizeof(MEMORY_BASIC_INFORMATION)) if (Length != sizeof(MEMORY_BASIC_INFORMATION))
{ {
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
@ -208,7 +184,7 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
Info->AllocationBase = NULL; Info->AllocationBase = NULL;
Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress); Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
ResultLength = sizeof(MEMORY_BASIC_INFORMATION); *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
} }
else else
{ {
@ -216,11 +192,11 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
{ {
case MEMORY_AREA_VIRTUAL_MEMORY: case MEMORY_AREA_VIRTUAL_MEMORY:
Status = MmQueryAnonMem(MemoryArea, Address, Info, Status = MmQueryAnonMem(MemoryArea, Address, Info,
&ResultLength); ResultLength);
break; break;
case MEMORY_AREA_SECTION_VIEW: case MEMORY_AREA_SECTION_VIEW:
Status = MmQuerySectionView(MemoryArea, Address, Info, Status = MmQuerySectionView(MemoryArea, Address, Info,
&ResultLength); ResultLength);
break; break;
case MEMORY_AREA_NO_ACCESS: case MEMORY_AREA_NO_ACCESS:
Info->Type = 0; Info->Type = 0;
@ -231,7 +207,7 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
Info->AllocationBase = MemoryArea->BaseAddress; Info->AllocationBase = MemoryArea->BaseAddress;
Info->RegionSize = MemoryArea->Length; Info->RegionSize = MemoryArea->Length;
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
ResultLength = sizeof(MEMORY_BASIC_INFORMATION); *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
break; break;
case MEMORY_AREA_SHARED_DATA: case MEMORY_AREA_SHARED_DATA:
Info->Type = 0; Info->Type = 0;
@ -242,11 +218,52 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
Info->AllocationBase = MemoryArea->BaseAddress; Info->AllocationBase = MemoryArea->BaseAddress;
Info->RegionSize = MemoryArea->Length; Info->RegionSize = MemoryArea->Length;
Status = STATUS_SUCCESS; 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; break;
default: default:
DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
Status = STATUS_UNSUCCESSFUL; Status = STATUS_UNSUCCESSFUL;
ResultLength = 0; *ResultLength = 0;
} }
} }
break; break;
@ -255,7 +272,7 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
default: default:
{ {
Status = STATUS_INVALID_INFO_CLASS; Status = STATUS_INVALID_INFO_CLASS;
ResultLength = 0; *ResultLength = 0;
break; break;
} }
} }
@ -266,6 +283,52 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
ObDereferenceObject(Process); 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) if (NT_SUCCESS(Status) && ResultLength > 0)
{ {
Status = MmCopyToCaller(VirtualMemoryInformation, &VirtualMemoryInfo, ResultLength); Status = MmCopyToCaller(VirtualMemoryInformation, &VirtualMemoryInfo, ResultLength);