- Timestamp:
- Aug 24, 2007 12:47:24 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGConsole.cpp
r4253 r4330 3125 3125 3126 3126 /** 3127 * The 'dpd*' commands. 3127 * Best guess at which paging mode currently applies to the guest 3128 * paging structures. 3129 * 3130 * This have to come up with a decent answer even when the guest 3131 * is in non-paged protected mode or real mode. 3132 * 3133 * @returns cr3. 3134 * @param pDbgc The DBGC instance. 3135 * @param pfPAE Where to store the page address extension indicator. 3136 * @param pfLME Where to store the long mode enabled indicator. 3137 * @param pfPSE Where to store the page size extension indicator. 3138 * @param pfPGE Where to store the page global enabled indicator. 3139 * @param pfNXE Where to store the no-execution enabled inidicator. 3140 */ 3141 static RTGCPHYS dbgcGetGuestPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE) 3142 { 3143 RTGCUINTREG cr4 = CPUMGetGuestCR4(pDbgc->pVM); 3144 *pfPSE = !!(cr4 & X86_CR4_PSE); 3145 *pfPGE = !!(cr4 & X86_CR4_PGE); 3146 *pfPAE = !!(cr4 & X86_CR4_PAE); 3147 *pfLME = CPUMGetGuestMode(pDbgc->pVM) == CPUMMODE_LONG; 3148 *pfNXE = false; /* GUEST64 GUESTNX */ 3149 return CPUMGetGuestCR3(pDbgc->pVM); 3150 } 3151 3152 3153 /** 3154 * Determin the shadow paging mode. 3155 * 3156 * @returns cr3. 3157 * @param pDbgc The DBGC instance. 3158 * @param pfPAE Where to store the page address extension indicator. 3159 * @param pfLME Where to store the long mode enabled indicator. 3160 * @param pfPSE Where to store the page size extension indicator. 3161 * @param pfPGE Where to store the page global enabled indicator. 3162 * @param pfNXE Where to store the no-execution enabled inidicator. 3163 */ 3164 static RTHCPHYS dbgcGetShadowPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE) 3165 { 3166 *pfPSE = true; 3167 *pfPGE = false; 3168 switch (PGMGetShadowMode(pDbgc->pVM)) 3169 { 3170 default: 3171 case PGMMODE_32_BIT: 3172 *pfPAE = *pfLME = *pfNXE = false; 3173 break; 3174 case PGMMODE_PAE: 3175 *pfLME = *pfNXE = false; 3176 *pfPAE = true; 3177 break; 3178 case PGMMODE_PAE_NX: 3179 *pfLME = false; 3180 *pfPAE = *pfNXE = true; 3181 break; 3182 case PGMMODE_AMD64: 3183 *pfNXE = false; 3184 *pfPAE = *pfLME = true; 3185 break; 3186 case PGMMODE_AMD64_NX: 3187 *pfPAE = *pfLME = *pfNXE = true; 3188 break; 3189 } 3190 return PGMGetHyperCR3(pDbgc->pVM); 3191 } 3192 3193 3194 /** 3195 * The 'dpd', 'dpda', 'dpdb', 'dpdg' and 'dpdh' commands. 3128 3196 * 3129 3197 * @returns VBox status. … … 3149 3217 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n"); 3150 3218 3151 3152 /* 3153 * Where to start dumping page directory entries? 3154 */ 3219 /* 3220 * Guest or shadow page directories? Get the paging parameters. 3221 */ 3222 bool fGuest = pCmd->pszCmd[3] != 'h'; 3223 if (!pCmd->pszCmd[3] || !pCmd->pszCmd[3] == 'a') 3224 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 3225 ? pDbgc->fRegCtxGuest 3226 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType); 3227 3228 bool fPAE, fLME, fPSE, fPGE, fNXE; 3229 uint64_t cr3 = fGuest 3230 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE) 3231 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE); 3232 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE); 3233 3234 /* 3235 * Setup default arugment if none was specified. 3236 * Fix address / index confusion. 3237 */ 3238 DBGCVAR VarDefault; 3239 if (!cArgs) 3240 { 3241 if (pCmd->pszCmd[3] == 'a') 3242 { 3243 if (fLME || fPAE) 3244 return DBGCCmdHlpPrintf(pCmdHlp, "Default argument for 'dpda' hasn't been fully implemented yet. Try with an address or use one of the other commands.\n"); 3245 if (fGuest) 3246 DBGCVAR_INIT_GC_PHYS(&VarDefault, cr3); 3247 else 3248 DBGCVAR_INIT_HC_PHYS(&VarDefault, cr3); 3249 } 3250 else 3251 DBGCVAR_INIT_GC_FLAT(&VarDefault, 0); 3252 paArgs = &VarDefault; 3253 cArgs = 1; 3254 } 3255 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER) 3256 { 3257 Assert(pCmd->pszCmd[3] != 'a'); 3258 VarDefault = paArgs[0]; 3259 if (VarDefault.u.u64Number <= 1024) 3260 { 3261 if (fPAE) 3262 return DBGCCmdHlpPrintf(pCmdHlp, "PDE indexing is only implemented for 32-bit paging.\n"); 3263 if (VarDefault.u.u64Number >= PAGE_SIZE / cbEntry) 3264 return DBGCCmdHlpPrintf(pCmdHlp, "PDE index is out of range [0..%d].\n", PAGE_SIZE / cbEntry - 1); 3265 VarDefault.u.u64Number <<= X86_PD_SHIFT; 3266 } 3267 VarDefault.enmType = DBGCVAR_TYPE_GC_FLAT; 3268 paArgs = &VarDefault; 3269 } 3270 3271 /* 3272 * Locate the PDE to start displaying at. 3273 * 3274 * The 'dpda' command takes the address of a PDE, while the others are guest 3275 * virtual address which PDEs should be displayed. So, 'dpda' is rather simple 3276 * while the others require us to do all the tedious walking thru the paging 3277 * hierarchy to find the intended PDE. 3278 */ 3279 unsigned iEntry = ~0U; /* The page directory index. ~0U for 'dpta'. */ 3280 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PDE (iEntry != ~0U). */ 3281 DBGCVAR VarPDEAddr; /* The address of the current PDE. */ 3282 unsigned cEntries; /* The number of entries to display. */ 3283 unsigned cEntriesMax; /* The max number of entries to display. */ 3155 3284 int rc; 3156 unsigned cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE); 3157 unsigned cEntries = PAGE_SIZE / sizeof(VBOXPDE); 3158 unsigned off = ~0; 3159 uint32_t u32CR4 = X86_CR4_PSE; 3160 DBGCVAR VarAddr; 3161 if (cArgs == 0 || pCmd->pszCmd[3] != 'a') 3162 { 3285 if (pCmd->pszCmd[3] == 'a') 3286 { 3287 VarPDEAddr = paArgs[0]; 3288 switch (VarPDEAddr.enmRangeType) 3289 { 3290 case DBGCVAR_RANGE_BYTES: cEntries = VarPDEAddr.u64Range / cbEntry; break; 3291 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPDEAddr.u64Range; break; 3292 default: cEntries = 10; break; 3293 } 3294 cEntriesMax = PAGE_SIZE / cbEntry; 3295 } 3296 else 3297 { 3298 /* 3299 * Determin the range. 3300 */ 3301 switch (paArgs[0].enmRangeType) 3302 { 3303 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break; 3304 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break; 3305 default: cEntries = 10; break; 3306 } 3307 3163 3308 /* 3164 * Get defaults.3309 * Normalize the input address, it must be a flat GC address. 3165 3310 */ 3166 off = 0; 3167 if ( pCmd->pszCmd[3] == 'g' 3168 || (pDbgc->fRegCtxGuest && (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a'))) 3169 { 3170 u32CR4 = CPUMGetGuestCR4(pVM); 3171 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%%%%cr3"); 3172 } 3311 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]); 3312 if (VBOX_FAILURE(rc)) 3313 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]); 3314 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT) 3315 { 3316 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat; 3317 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT; 3318 } 3319 if (fPAE) 3320 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_PAE_SHIFT) - 1); 3173 3321 else 3174 { 3175 /** @todo fix hypervisor CR4 value! */ 3176 //u32CR4 = CPUMGetHyperCR4(pVM); 3177 u32CR4 = X86_CR4_PGE | X86_CR4_PSE; 3178 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "#%%%%.cr3"); 3179 } 3180 if (VBOX_FAILURE(rc)) 3181 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "(Getting (.)cr3.)"); 3182 3183 if (cArgs > 0) 3184 { 3185 cEntries = 3; 3186 if (!DBGCVAR_ISPOINTER(paArgs[0].enmType)) 3187 { 3188 /* 3189 * Add index. 3190 */ 3191 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarAddr, paArgs[0].u.u64Number * sizeof(VBOXPTE)); 3192 if (VBOX_FAILURE(rc)) 3193 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarAddr, paArgs[0].u.u64Number * sizeof(VBOXPTE)); 3194 if (paArgs[0].u.u64Number >= PAGE_SIZE / sizeof(VBOXPDE)) 3195 off = ~0; 3196 else 3197 { 3198 off = (unsigned)paArgs[0].u.u64Number; 3199 cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE) - off; 3200 } 3201 } 3202 else 3203 { 3204 /* 3205 * Pointer which we want the page directory entry for. 3206 * Start by making sure it's a GC pointer. 3207 */ 3208 DBGCVAR VarTmp; 3209 rc = pCmdHlp->pfnEval(pCmdHlp, &VarTmp, "%%(%Dv)", &paArgs[0]); 3210 if (VBOX_FAILURE(rc)) 3211 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%Dv) failed.", &paArgs[0]); 3212 3213 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarAddr, (VarTmp.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPTE)); 3214 if (VBOX_FAILURE(rc)) 3215 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarAddr, (VarTmp.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPTE)); 3216 off = VarTmp.u.GCFlat >> PGDIR_SHIFT; 3217 cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE) - off; 3218 } 3219 } 3220 } 3221 else 3222 VarAddr = paArgs[0]; 3223 3224 /* 3225 * Range. 3226 */ 3227 unsigned i = cArgs; 3228 while (i-- > 0) 3229 { 3230 if (paArgs[i].enmRangeType == DBGCVAR_RANGE_ELEMENTS) 3231 { 3232 cEntries = (unsigned)RT_MIN(paArgs[i].u64Range, cEntriesMax); 3233 break; 3234 } 3235 else if (paArgs[i].enmRangeType == DBGCVAR_RANGE_BYTES) 3236 { 3237 cEntries = (unsigned)RT_MIN(paArgs[i].u64Range / sizeof(VBOXPDE), cEntriesMax); 3238 break; 3239 } 3240 } 3241 3242 /* 3243 * Dump loop. 3244 */ 3245 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, off != ~0U ? "%DV (index %#x):\n" : "%DV:\n", &VarAddr, off); 3246 if (VBOX_FAILURE(rc)) 3247 return rc; 3248 for (;;) 3322 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_SHIFT) - 1); 3323 3324 /* 3325 * Do the paging walk until we get to the page directory. 3326 */ 3327 DBGCVAR VarCur; 3328 if (fGuest) 3329 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3); 3330 else 3331 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3); 3332 if (fLME) 3333 { 3334 /* Page Map Level 4 Lookup. */ 3335 /* Check if it's a valid address first? */ 3336 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK; 3337 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E); 3338 X86PML4E Pml4e; 3339 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL); 3340 if (VBOX_FAILURE(rc)) 3341 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur); 3342 if (!Pml4e.n.u1Present) 3343 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr); 3344 3345 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK; 3346 Assert(fPAE); 3347 } 3348 if (fPAE) 3349 { 3350 /* Page directory pointer table. */ 3351 X86PDPE Pdpe; 3352 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK) * sizeof(Pdpe); 3353 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL); 3354 if (VBOX_FAILURE(rc)) 3355 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur); 3356 if (!Pdpe.n.u1Present) 3357 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr); 3358 3359 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK; 3360 VarPDEAddr = VarCur; 3361 VarPDEAddr.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK; 3362 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDEPAE); 3363 } 3364 else 3365 { 3366 /* 32-bit legacy - CR3 == page directory. */ 3367 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK; 3368 VarPDEAddr = VarCur; 3369 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDE); 3370 } 3371 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry; 3372 iEntry /= cbEntry; 3373 } 3374 3375 /* adjust cEntries */ 3376 cEntries = RT_MAX(1, cEntries); 3377 cEntries = RT_MIN(cEntries, cEntriesMax); 3378 3379 /* 3380 * The display loop. 3381 */ 3382 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (index %#x):\n" : "%DV:\n", 3383 &VarPDEAddr, iEntry); 3384 do 3249 3385 { 3250 3386 /* 3251 3387 * Read. 3252 3388 */ 3253 VBOXPDE Pde; 3254 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarAddr, NULL); 3389 X86PDEPAE Pde; 3390 Pde.u = 0; 3391 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, cbEntry, &VarPDEAddr, NULL); 3255 3392 if (VBOX_FAILURE(rc)) 3256 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &VarAddr);3393 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarPDEAddr); 3257 3394 3258 3395 /* 3259 3396 * Display. 3260 3397 */ 3261 if (off != ~0U) 3262 { 3263 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%03x %08x: ", off, off << PGDIR_SHIFT); 3264 off++; 3265 } 3266 if ((u32CR4 & X86_CR4_PSE) && Pde.b.u1Size) 3267 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 3268 "%08x big phys=%08x %s %s %s %s %s avl=%02x %s %s %s %s\n", 3269 Pde.u, Pde.b.u10PageNo << PGDIR_SHIFT, Pde.b.u1Present ? "p " : "np", Pde.b.u1Write ? "w" : "r", 3270 Pde.b.u1User ? "u" : "s", Pde.b.u1Accessed ? "a " : "na", Pde.b.u1Dirty ? "d " : "nd", 3271 Pde.b.u3Available, Pde.b.u1Global ? "G" : " ", Pde.b.u1WriteThru ? "pwt" : " ", 3272 Pde.b.u1CacheDisable ? "pcd" : " ", Pde.b.u1PAT ? "pat" : ""); 3398 if (iEntry != ~0U) 3399 { 3400 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr); 3401 iEntry++; 3402 } 3403 if (fPSE && Pde.b.u1Size) 3404 DBGCCmdHlpPrintf(pCmdHlp, 3405 fPAE 3406 ? "%016llx big phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s" 3407 : "%08llx big phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s", 3408 Pde.u, 3409 Pde.u & X86_PDE_PAE_PG_MASK, 3410 Pde.b.u1Present ? "p " : "np", 3411 Pde.b.u1Write ? "w" : "r", 3412 Pde.b.u1User ? "u" : "s", 3413 Pde.b.u1Accessed ? "a " : "na", 3414 Pde.b.u1Dirty ? "d " : "nd", 3415 Pde.b.u3Available, 3416 Pde.b.u1Global ? (fPGE ? "g" : "G") : " ", 3417 Pde.b.u1WriteThru ? "pwt" : " ", 3418 Pde.b.u1CacheDisable ? "pcd" : " ", 3419 Pde.b.u1PAT ? "pat" : "", 3420 Pde.b.u1NoExecute ? (fNXE ? "nx" : "NX") : " "); 3273 3421 else 3274 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 3275 "%08x 4kb phys=%08x %s %s %s %s %s avl=%02x %s %s %s %s\n", 3276 Pde.u, Pde.n.u20PageNo << PAGE_SHIFT, Pde.n.u1Present ? "p " : "np", Pde.n.u1Write ? "w" : "r", 3277 Pde.n.u1User ? "u" : "s", Pde.n.u1Accessed ? "a " : "na", Pde.u & BIT(6) ? "6 " : " ", 3278 Pde.n.u3Available, Pde.u & BIT(8) ? "8" : " ", Pde.n.u1WriteThru ? "pwt" : " ", 3279 Pde.n.u1CacheDisable ? "pcd" : " ", Pde.u & BIT(7) ? "7" : ""); 3422 DBGCCmdHlpPrintf(pCmdHlp, 3423 fPAE 3424 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s" 3425 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s", 3426 Pde.u, 3427 Pde.u & X86_PDE_PAE_PG_MASK, 3428 Pde.n.u1Present ? "p " : "np", 3429 Pde.n.u1Write ? "w" : "r", 3430 Pde.n.u1User ? "u" : "s", 3431 Pde.n.u1Accessed ? "a " : "na", 3432 Pde.u & BIT(6) ? "6 " : " ", 3433 Pde.n.u3Available, 3434 Pde.u & BIT(8) ? "8" : " ", 3435 Pde.n.u1WriteThru ? "pwt" : " ", 3436 Pde.n.u1CacheDisable ? "pcd" : " ", 3437 Pde.u & BIT(7) ? "7" : "", 3438 Pde.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " "); 3439 if (Pde.u & UINT64_C(0x7fff000000000000)) 3440 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pde.u & UINT64_C(0x7fff000000000000))); 3441 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 3280 3442 if (VBOX_FAILURE(rc)) 3281 3443 return rc; 3282 3444 3283 3445 /* 3284 * Next3446 * Advance. 3285 3447 */ 3286 if (cEntries-- <= 1) 3287 break; 3288 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarAddr, sizeof(VBOXPDE)); 3289 if (VBOX_FAILURE(rc)) 3290 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarAddr, sizeof(VBOXPDE)); 3291 } 3448 VarPDEAddr.u.u64Number += cbEntry; 3449 if (iEntry != ~0U) 3450 VarGCPtr.u.GCFlat += 1 << (fPAE ? X86_PD_PAE_SHIFT : X86_PD_SHIFT); 3451 } while (cEntries-- > 0); 3292 3452 3293 3453 NOREF(pResult); 3294 3454 return VINF_SUCCESS; 3295 3455 } 3456 3296 3457 3297 3458 /** … … 3339 3500 || (pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType))) 3340 3501 ) 3341 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");3502 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n"); 3342 3503 if (!pVM) 3343 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n"); 3344 3345 3346 /* 3347 * Where to start dumping page directory entries? 3348 */ 3504 return DBGCCmdHlpPrintf(pCmdHlp, "error: No VM.\n"); 3505 3506 /* 3507 * Guest or shadow page tables? Get the paging parameters. 3508 */ 3509 bool fGuest = pCmd->pszCmd[3] != 'h'; 3510 if (!pCmd->pszCmd[3] || !pCmd->pszCmd[3] == 'a') 3511 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 3512 ? pDbgc->fRegCtxGuest 3513 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType); 3514 3515 bool fPAE, fLME, fPSE, fPGE, fNXE; 3516 uint64_t cr3 = fGuest 3517 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE) 3518 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE); 3519 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE); 3520 3521 /* 3522 * Locate the PTE to start displaying at. 3523 * 3524 * The 'dpta' command takes the address of a PTE, while the others are guest 3525 * virtual address which PTEs should be displayed. So, 'pdta' is rather simple 3526 * while the others require us to do all the tedious walking thru the paging 3527 * hierarchy to find the intended PTE. 3528 */ 3529 unsigned iEntry = ~0U; /* The page table index. ~0U for 'dpta'. */ 3530 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PTE (iEntry != ~0U). */ 3531 DBGCVAR VarPTEAddr; /* The address of the current PTE. */ 3532 unsigned cEntries; /* The number of entries to display. */ 3533 unsigned cEntriesMax; /* The max number of entries to display. */ 3349 3534 int rc; 3350 unsigned cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE); 3351 unsigned cEntries = PAGE_SIZE / sizeof(VBOXPDE); 3352 unsigned off = ~0; 3353 DBGCVAR VarGCPtr; /* only valid with off == ~0 */ 3354 DBGCVAR VarPTEAddr; 3355 if (pCmd->pszCmd[3] != 'a') 3356 { 3535 if (pCmd->pszCmd[3] == 'a') 3536 { 3537 VarPTEAddr = paArgs[0]; 3538 switch (VarPTEAddr.enmRangeType) 3539 { 3540 case DBGCVAR_RANGE_BYTES: cEntries = VarPTEAddr.u64Range / cbEntry; break; 3541 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPTEAddr.u64Range; break; 3542 default: cEntries = 10; break; 3543 } 3544 cEntriesMax = PAGE_SIZE / cbEntry; 3545 } 3546 else 3547 { 3548 /* 3549 * Determin the range. 3550 */ 3551 switch (paArgs[0].enmRangeType) 3552 { 3553 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break; 3554 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break; 3555 default: cEntries = 10; break; 3556 } 3557 3357 3558 /* 3358 * Get page directory and cr4. 3359 */ 3360 bool fHyper; 3361 uint32_t u32CR4; 3362 off = 0; 3363 if ( pCmd->pszCmd[3] == 'g' 3364 || (pDbgc->fRegCtxGuest && (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a'))) 3365 { 3366 u32CR4 = CPUMGetGuestCR4(pVM); 3367 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "%%%%cr3"); 3368 fHyper = false; 3369 } 3370 else 3371 { 3372 /** @todo fix hypervisor CR4 value! */ 3373 //u32CR4 = CPUMGetHyperCR4(pVM); 3374 u32CR4 = X86_CR4_PGE | X86_CR4_PSE; 3375 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "#%%%%.cr3"); 3376 fHyper = true; 3377 } 3378 if (VBOX_FAILURE(rc)) 3379 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "(Getting (.)cr3.)"); 3380 3381 /* 3382 * Find page directory entry for the address. 3383 * Make sure it's a flat address first. 3559 * Normalize the input address, it must be a flat GC address. 3384 3560 */ 3385 3561 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]); 3386 3562 if (VBOX_FAILURE(rc)) 3387 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]); 3388 3389 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "(%Dv) + %#x", &VarPTEAddr, (VarGCPtr.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPDE)); 3390 if (VBOX_FAILURE(rc)) 3391 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "(%Dv) + %#x", &VarPTEAddr, (VarGCPtr.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPDE)); 3392 3563 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]); 3564 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT) 3565 { 3566 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat; 3567 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT; 3568 } 3569 VarGCPtr.u.GCFlat &= ~(RTGCPTR)PAGE_OFFSET_MASK; 3393 3570 3394 3571 /* 3395 * Now read the page directory entry for this GC address.3572 * Do the paging walk until we get to the page table. 3396 3573 */ 3397 VBOXPDE Pde; 3398 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarPTEAddr, NULL); 3399 if (VBOX_FAILURE(rc)) 3400 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &VarPTEAddr); 3401 3402 /* 3403 * Check for presentness and handle big using dpd[gh]. 3404 */ 3405 if ((u32CR4 & X86_CR4_PSE) && Pde.b.u1Size) 3406 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr); 3407 3408 if (!Pde.n.u1Present) 3409 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Page table for %Dv is not present.\n", &VarGCPtr); 3410 3411 /* 3412 * Calc page table address and setup offset and counts. 3413 */ 3414 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, fHyper ? "#%%%%%#x" : "%%%%%#x", Pde.u & X86_PDE_PG_MASK); 3415 if (VBOX_FAILURE(rc)) 3416 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, fHyper ? "#%%%%%#x" : "%%%%%#x", Pde.u & X86_PDE_PG_MASK); 3417 3418 cEntries = 10; 3419 off = (VarGCPtr.u.GCFlat >> PAGE_SHIFT) & PTE_MASK; 3420 cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE) - off; 3421 VarGCPtr.u.GCFlat &= ~PAGE_OFFSET_MASK; /* Make it page table base address. */ 3422 } 3423 else 3424 VarPTEAddr = paArgs[0]; 3425 3426 /* 3427 * Range. 3428 */ 3429 unsigned i = cArgs; 3430 while (i-- > 0) 3431 { 3432 if (paArgs[i].enmRangeType == DBGCVAR_RANGE_ELEMENTS) 3433 { 3434 cEntries = (unsigned)RT_MIN(paArgs[i].u64Range, cEntriesMax); 3435 break; 3436 } 3437 else if (paArgs[i].enmRangeType == DBGCVAR_RANGE_BYTES) 3438 { 3439 cEntries = (unsigned)RT_MIN(paArgs[i].u64Range / sizeof(VBOXPDE), cEntriesMax); 3440 break; 3441 } 3442 } 3443 3444 /* 3445 * Dump loop. 3446 */ 3447 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, off != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n", &VarPTEAddr, &VarGCPtr, off); 3448 if (VBOX_FAILURE(rc)) 3449 return rc; 3450 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "%DV + %#x", &VarPTEAddr, sizeof(VBOXPTE) * off); 3451 if (VBOX_FAILURE(rc)) 3452 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarPTEAddr, sizeof(VBOXPTE) * off); 3453 for (;;) 3574 DBGCVAR VarCur; 3575 if (fGuest) 3576 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3); 3577 else 3578 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3); 3579 if (fLME) 3580 { 3581 /* Page Map Level 4 Lookup. */ 3582 /* Check if it's a valid address first? */ 3583 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK; 3584 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E); 3585 X86PML4E Pml4e; 3586 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL); 3587 if (VBOX_FAILURE(rc)) 3588 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur); 3589 if (!Pml4e.n.u1Present) 3590 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr); 3591 3592 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK; 3593 Assert(fPAE); 3594 } 3595 if (fPAE) 3596 { 3597 /* Page directory pointer table. */ 3598 X86PDPE Pdpe; 3599 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK) * sizeof(Pdpe); 3600 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL); 3601 if (VBOX_FAILURE(rc)) 3602 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur); 3603 if (!Pdpe.n.u1Present) 3604 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr); 3605 3606 VarCur.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK; 3607 3608 /* Page directory (PAE). */ 3609 X86PDEPAE Pde; 3610 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK) * sizeof(Pde); 3611 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL); 3612 if (VBOX_FAILURE(rc)) 3613 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur); 3614 if (!Pde.n.u1Present) 3615 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr); 3616 if (fPSE && Pde.n.u1Size) 3617 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr); 3618 3619 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK; 3620 VarPTEAddr = VarCur; 3621 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PAE_PG_MASK; 3622 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTEPAE); 3623 } 3624 else 3625 { 3626 /* Page directory (legacy). */ 3627 X86PDE Pde; 3628 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK) * sizeof(Pde); 3629 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL); 3630 if (VBOX_FAILURE(rc)) 3631 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur); 3632 if (!Pde.n.u1Present) 3633 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr); 3634 if (fPSE && Pde.n.u1Size) 3635 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr); 3636 3637 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_SHIFT) & X86_PT_MASK; 3638 VarPTEAddr = VarCur; 3639 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PG_MASK; 3640 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTE); 3641 } 3642 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry; 3643 iEntry /= cbEntry; 3644 } 3645 3646 /* adjust cEntries */ 3647 cEntries = RT_MAX(1, cEntries); 3648 cEntries = RT_MIN(cEntries, cEntriesMax); 3649 3650 /* 3651 * The display loop. 3652 */ 3653 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n", 3654 &VarPTEAddr, &VarGCPtr, iEntry); 3655 do 3454 3656 { 3455 3657 /* 3456 3658 * Read. 3457 3659 */ 3458 VBOXPTE Pte; 3459 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pte, sizeof(Pte), &VarPTEAddr, NULL); 3660 X86PTEPAE Pte; 3661 Pte.u = 0; 3662 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pte, cbEntry, &VarPTEAddr, NULL); 3460 3663 if (VBOX_FAILURE(rc)) 3461 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Readingmemory at %DV.\n", &VarPTEAddr);3664 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PTE memory at %DV.\n", &VarPTEAddr); 3462 3665 3463 3666 /* 3464 3667 * Display. 3465 3668 */ 3466 if (off != ~0U) 3467 { 3468 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%03x %DV: ", off, &VarGCPtr); 3469 off++; 3470 } 3471 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 3472 "%08x 4kb phys=%08x %s %s %s %s %s avl=%02x %s %s %s %s\n", 3473 Pte.u, Pte.n.u20PageNo << PAGE_SHIFT, Pte.n.u1Present ? "p " : "np", Pte.n.u1Write ? "w" : "r", 3474 Pte.n.u1User ? "u" : "s", Pte.n.u1Accessed ? "a " : "na", Pte.n.u1Dirty ? "d " : "nd", 3475 Pte.n.u3Available, Pte.n.u1Global ? "G" : " ", Pte.n.u1WriteThru ? "pwt" : " ", 3476 Pte.n.u1CacheDisable ? "pcd" : " ", Pte.n.u1PAT ? "pat" : " "); 3669 if (iEntry != ~0U) 3670 { 3671 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr); 3672 iEntry++; 3673 } 3674 DBGCCmdHlpPrintf(pCmdHlp, 3675 fPAE 3676 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s" 3677 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s", 3678 Pte.u, 3679 Pte.u & X86_PTE_PAE_PG_MASK, 3680 Pte.n.u1Present ? "p " : "np", 3681 Pte.n.u1Write ? "w" : "r", 3682 Pte.n.u1User ? "u" : "s", 3683 Pte.n.u1Accessed ? "a " : "na", 3684 Pte.n.u1Dirty ? "d " : "nd", 3685 Pte.n.u3Available, 3686 Pte.n.u1Global ? (fPGE ? "g" : "G") : " ", 3687 Pte.n.u1WriteThru ? "pwt" : " ", 3688 Pte.n.u1CacheDisable ? "pcd" : " ", 3689 Pte.n.u1PAT ? "pat" : " ", 3690 Pte.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " " 3691 ); 3692 if (Pte.u & UINT64_C(0x7fff000000000000)) 3693 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pte.u & UINT64_C(0x7fff000000000000))); 3694 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 3477 3695 if (VBOX_FAILURE(rc)) 3478 3696 return rc; 3479 3697 3480 3698 /* 3481 * Next3699 * Advance. 3482 3700 */ 3483 if (cEntries-- <= 1) 3484 break; 3485 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "%DV + %#x", &VarPTEAddr, sizeof(VBOXPDE)); 3486 if (VBOX_FAILURE(rc)) 3487 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarPTEAddr, sizeof(VBOXPDE)); 3488 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%DV + %#x", &VarGCPtr, PAGE_SIZE); 3489 if (VBOX_FAILURE(rc)) 3490 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarGCPtr, sizeof(VBOXPDE)); 3491 } 3701 VarPTEAddr.u.u64Number += cbEntry; 3702 if (iEntry != ~0U) 3703 VarGCPtr.u.GCFlat += PAGE_SIZE; 3704 } while (cEntries-- > 0); 3492 3705 3493 3706 NOREF(pResult);
Note:
See TracChangeset
for help on using the changeset viewer.