Winstation space cannot be viewed in kd because the debugger is timid in its use of page tables. If its page and page table are resident, a virtual address can always be found and viewed by using the page tables directly. The mapping from virtual to physical can be done by hand by first indexing into the Page Directory of any process participating in the Winstation session, then indexing into the Page Table pointed to by the Page Directory.
Although it is fun to do this once or twice by hand, after that a kd extension is desireable. Code for an extension is included below.
Page Directory PD_pa ----> +---------+ | PDE's | +---------+ | | +---------+ | ... | Page Table +---------+ PDE_pa ---> | PT_pa | ------> +---------+ +---------+ | PTE's | | ... | +---------+ +---------+ | | +---------+ | ... | Page +---------+ PTE_pa ----> | PA_pa | ------> +---------+ +---------+ | | | ... | +---------+ +---------+ | ... | +---------+ VA_pa ----> | DWORD | +---------+ | ... | +---------+
PD_pa
: physical address of page directory.
PDE_pa
: physical address of PDE mapping the virtual address.
PT_pa
: physical address of page in the page table mapping
the virtual address.
PTE_pa
physical address of the PTE mapping the virtual address.:
PA_pa
: physical address of the page in which the virtual address
resides.
VA_pa
: physical address of the virtual address.
/* * kd extension to chase virtual memory address * through the page tables. * * Author: burtonr@citrix.com * Date: 1 March 2000 * */ #include <nt.h> #include <windef.h> #include <ntkdexts.h> #include <string.h> static PNTKD_READ_PHYSICAL_MEMORY ReadPhysical ; static PNTKD_OUTPUT_ROUTINE OutputRoutine ; static PNTKD_GET_EXPRESSION GetExpressionRoutine ; #define HELP_VATOPA "vatopa page_directory_phy_addr virtual_addr" enum _VirtualToPhysicalReturnStatus { Ok, CantAccessMemory, PdeInvalid, PteInvalid, LargePage } ; enum _VirtualToPhysicalReturnStatus VirtualToPhysicalUsingDirbase( DWORD dir_base, DWORD virtual_address, DWORD * physical_address, DWORD verbose ) { DWORD PDE, PTE ; PHYSICAL_ADDRESS pPDE = { 0L, 0L } ; PHYSICAL_ADDRESS pPTE = { 0L, 0L } ; PHYSICAL_ADDRESS pVA = { 0L, 0L } ; enum _VirtualToPhysicalReturnStatus rs = Ok ; do { pPDE.LowPart = ( dir_base & 0xfffff000 ) | ((virtual_address & 0xffc00000) >> 20 ) ; if ( !ReadPhysical( pPDE, (LPVOID)&PDE, sizeof(PDE), NULL ) ) { rs = CantAccessMemory ; break ; } if ( !(PDE & 1) ) { rs = PdeInvalid ; break ; } if ( (PDE & 0x80) ) { rs = LargePage ; pVA.LowPart = ( PDE & 0xffc00000 ) | (virtual_address & 0x003fffff) ; break ; } pPTE.LowPart = ( PDE & 0xfffff000 ) | ((virtual_address & 0x003ff000) >> 10 ) ; if (!ReadPhysical( pPTE, &PTE, sizeof(PTE), NULL ) ) { rs = CantAccessMemory ; break ; } if ( !(PTE & 1) ) { rs = PteInvalid ; break ; } pVA.LowPart = ( PTE & 0xfffff000 ) | (virtual_address & 0x00000fff) ; } while ( 0 ) ; if ( physical_address ) *physical_address = pVA.LowPart ; if ( verbose ) { OutputRoutine("\n Phys. Adr. Data\n") ; OutputRoutine(" PDE: 0x%08x 0x%08x\n", pPDE.LowPart, PDE ) ; OutputRoutine(" PTE: 0x%08x 0x%08x\n\n", pPTE.LowPart, PTE ) ; } return rs ; } void vatopa( DWORD dwCurrentPc, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { DWORD page_directory, virtual_address, physical_address ; LPSTR arg1, arg2 ; ReadPhysical = lpExtensionApis->lpReadPhysicalMemRoutine ; OutputRoutine = lpExtensionApis->lpOutputRoutine ; GetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine ; if ( (arg1 = strtok( lpArgumentString, " " )) && (arg2 = strtok( NULL, " " )) ) { page_directory = GetExpressionRoutine( arg1 ) ; virtual_address = GetExpressionRoutine( arg2 ) ; } else { OutputRoutine("usage: %s\n", HELP_VATOPA) ; return ; } switch ( VirtualToPhysicalUsingDirbase( page_directory, virtual_address, &physical_address, 1 )) { case CantAccessMemory: OutputRoutine("error: can't access memory.\n") ; break ; case PteInvalid: OutputRoutine("PTE marked invalid. Page not resident.\n") ; break ; case PdeInvalid: OutputRoutine("PDE marked invalid. Page table not resident.\n") ; break ; case LargePage: OutputRoutine("PDE marked Large. No Page Table needed.\n") ; /* fall through to case Ok */ case Ok: default: OutputRoutine("Physical Address: 0x%08x\n", physical_address ) ; } } void help( DWORD dwCurrentPc, PNTKD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) { OutputRoutine = lpExtensionApis->lpOutputRoutine ; OutputRoutine("%s\n", HELP_VATOPA) ; OutputRoutine("%s\n", "Ex: vatopa cr3 c0300c00\n" ) ; }
Burton Rosenberg
1 March 2000