Changeset 106383 in vbox for trunk/src/VBox/VMM/VMMR3
- Timestamp:
- Oct 16, 2024 1:54:40 PM (3 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/DBGFStack.cpp
r106061 r106383 76 76 { 77 77 m_State.u32Magic = RTDBGUNWINDSTATE_MAGIC; 78 #if defined(VBOX_VMM_TARGET_ARMV8) 79 m_State.enmArch = RTLDRARCH_ARM64; 80 #else 78 81 m_State.enmArch = RTLDRARCH_AMD64; 82 #endif 79 83 m_State.pfnReadStack = dbgfR3StackReadCallback; 80 84 m_State.pvUser = this; … … 83 87 { 84 88 #if defined(VBOX_VMM_TARGET_ARMV8) 85 AssertFailed(); 89 AssertCompile(RT_ELEMENTS(m_State.u.armv8.auGprs) == RT_ELEMENTS(pInitialCtx->aGRegs)); 90 91 m_State.uPc = pInitialCtx->Pc.u64; 92 m_State.u.armv8.uSpEl0 = pInitialCtx->aSpReg[0].u64; 93 m_State.u.armv8.uSpEl1 = pInitialCtx->aSpReg[1].u64; 94 95 for (uint32_t i = 0; i < RT_ELEMENTS(m_State.u.armv8.auGprs); i++) 96 m_State.u.armv8.auGprs[i] = pInitialCtx->aGRegs[i].x; 86 97 #else 87 98 m_State.u.x86.auRegs[X86_GREG_xAX] = pInitialCtx->rax; … … 163 174 static DECLCALLBACK(int) dbgfR3StackReadCallback(PRTDBGUNWINDSTATE pThis, RTUINTPTR uSp, size_t cbToRead, void *pvDst) 164 175 { 176 #if defined(VBOX_VMM_TARGET_ARMV8) 177 Assert(pThis->enmArch == RTLDRARCH_ARM64); 178 #else 165 179 Assert( pThis->enmArch == RTLDRARCH_AMD64 166 180 || pThis->enmArch == RTLDRARCH_X86_32); 181 #endif 167 182 168 183 PDBGFUNWINDCTX pUnwindCtx = (PDBGFUNWINDCTX)pThis->pvUser; … … 173 188 else 174 189 { 190 #if defined(VBOX_VMM_TARGET_ARMV8) 191 DBGFR3AddrFromFlat(pUnwindCtx->m_pUVM, &SrcAddr, uSp); 192 #else 175 193 if ( pThis->enmArch == RTLDRARCH_X86_32 176 194 || pThis->enmArch == RTLDRARCH_X86_16) … … 183 201 else 184 202 DBGFR3AddrFromFlat(pUnwindCtx->m_pUVM, &SrcAddr, uSp); 203 #endif 185 204 } 186 205 if (RT_SUCCESS(rc)) … … 202 221 static bool dbgfR3UnwindCtxSetPcAndSp(PDBGFUNWINDCTX pUnwindCtx, PCDBGFADDRESS pAddrPC, PCDBGFADDRESS pAddrStack) 203 222 { 223 #if defined(VBOX_VMM_TARGET_ARMV8) 224 Assert(pUnwindCtx->m_State.enmArch == RTLDRARCH_ARM64); 225 226 Assert(!DBGFADDRESS_IS_FAR(pAddrPC)); 227 pUnwindCtx->m_State.uPc = pAddrPC->FlatPtr; 228 Assert(!DBGFADDRESS_IS_FAR(pAddrStack)); 229 pUnwindCtx->m_State.u.armv8.uSpEl1 = pAddrStack->FlatPtr; /** @todo EL0 stack pointer. */ 230 #else 204 231 Assert( pUnwindCtx->m_State.enmArch == RTLDRARCH_AMD64 205 232 || pUnwindCtx->m_State.enmArch == RTLDRARCH_X86_32); … … 219 246 pUnwindCtx->m_State.u.x86.auSegs[X86_SREG_SS] = pAddrStack->Sel; 220 247 } 248 #endif 249 221 250 return true; 222 251 } … … 293 322 } 294 323 324 #if !defined(VBOX_VMM_TARGET_ARMV8) /** @todo Unused on ARMv8 for now. */ 295 325 /** 296 326 * Collects sure registers on frame exit. … … 306 336 pFrame->paSureRegs = NULL; 307 337 338 #if defined(VBOX_VMM_TARGET_ARMV8) 339 if (pState->enmArch == RTLDRARCH_ARM64) 340 { 341 if (pState->u.armv8.Loaded.fAll) 342 { 343 /* 344 * Count relevant registers. 345 */ 346 uint32_t cRegs = 0; 347 if (pState->u.armv8.Loaded.s.fRegs) 348 for (uint32_t f = 1; f < RT_BIT_32(RT_ELEMENTS(pState->u.armv8.auGprs)); f <<= 1) 349 if (pState->u.armv8.Loaded.s.fRegs & f) 350 cRegs++; 351 if (pState->u.armv8.Loaded.s.fSpEl0) 352 cRegs++; 353 if (pState->u.armv8.Loaded.s.fSpEl1) 354 cRegs++; 355 if (pState->u.armv8.Loaded.s.fPc) 356 cRegs++; 357 if (cRegs > 0) 358 { 359 /* 360 * Allocate the arrays. 361 */ 362 PDBGFREGVALEX paSureRegs = (PDBGFREGVALEX)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_STACK, sizeof(DBGFREGVALEX) * cRegs); 363 AssertReturn(paSureRegs, VERR_NO_MEMORY); 364 pFrame->paSureRegs = paSureRegs; 365 pFrame->cSureRegs = cRegs; 366 367 /* 368 * Popuplate the arrays. 369 */ 370 uint32_t iReg = 0; 371 if (pState->u.armv8.Loaded.s.fRegs) 372 for (uint32_t i = 0; i < RT_ELEMENTS(pState->u.armv8.auGprs); i++) 373 if (pState->u.armv8.Loaded.s.fRegs & RT_BIT(i)) 374 { 375 paSureRegs[iReg].Value.u64 = pState->u.armv8.auGprs[i]; 376 paSureRegs[iReg].enmType = DBGFREGVALTYPE_U64; 377 paSureRegs[iReg].enmReg = (DBGFREG)(DBGFREG_ARMV8_GREG_X0 + i); 378 iReg++; 379 } 380 381 if (iReg < cRegs) 382 { 383 if (pState->u.armv8.Loaded.s.fSpEl0) 384 { 385 paSureRegs[iReg].Value.u64 = pState->u.armv8.uSpEl0; 386 paSureRegs[iReg].enmType = DBGFREGVALTYPE_U64; 387 paSureRegs[iReg].enmReg = DBGFREG_ARMV8_SP_EL0; 388 iReg++; 389 } 390 if (pState->u.armv8.Loaded.s.fSpEl1) 391 { 392 paSureRegs[iReg].Value.u64 = pState->u.armv8.uSpEl1; 393 paSureRegs[iReg].enmType = DBGFREGVALTYPE_U64; 394 paSureRegs[iReg].enmReg = DBGFREG_ARMV8_SP_EL1; 395 iReg++; 396 } 397 if (pState->u.armv8.Loaded.s.fPc) 398 { 399 paSureRegs[iReg].Value.u64 = pState->uPc; 400 paSureRegs[iReg].enmType = DBGFREGVALTYPE_U64; 401 paSureRegs[iReg].enmReg = DBGFREG_ARMV8_PC; 402 iReg++; 403 } 404 } 405 Assert(iReg == cRegs); 406 } 407 } 408 } 409 #else 308 410 if ( pState->enmArch == RTLDRARCH_AMD64 309 411 || pState->enmArch == RTLDRARCH_X86_32 … … 393 495 } 394 496 } 497 #endif 395 498 396 499 return VINF_SUCCESS; 397 500 } 398 399 501 #endif 502 503 504 #if defined(VBOX_VMM_TARGET_ARMV8) 505 /** 506 * Internal worker routine. 507 * 508 * On aarch64 the typical stack frame layout is like this: 509 * .. .. 510 * 4 return address 511 * 0 old fp; current fp points here 512 */ 513 DECL_NO_INLINE(static, int) dbgfR3StackWalk(PDBGFUNWINDCTX pUnwindCtx, PDBGFSTACKFRAME pFrame, bool fFirst) 514 { 515 /* 516 * Stop if we got a read error in the previous run. 517 */ 518 if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_LAST) 519 return VERR_NO_MORE_FILES; 520 521 /* 522 * Advance the frame (except for the first). 523 */ 524 if (!fFirst) /** @todo we can probably eliminate this fFirst business... */ 525 { 526 /* frame, pc and stack is taken from the existing frames return members. */ 527 pFrame->AddrFrame = pFrame->AddrReturnFrame; 528 pFrame->AddrPC = pFrame->AddrReturnPC; 529 pFrame->pSymPC = pFrame->pSymReturnPC; 530 pFrame->pLinePC = pFrame->pLineReturnPC; 531 532 /* increment the frame number. */ 533 pFrame->iFrame++; 534 535 /* UNWIND_INFO_RET -> USED_UNWIND; return type */ 536 if (!(pFrame->fFlags & DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET)) 537 pFrame->fFlags &= ~DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO; 538 else 539 { 540 pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO; 541 pFrame->fFlags &= ~DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET; 542 if (pFrame->enmReturnFrameReturnType != RTDBGRETURNTYPE_INVALID) 543 { 544 pFrame->enmReturnType = pFrame->enmReturnFrameReturnType; 545 pFrame->enmReturnFrameReturnType = RTDBGRETURNTYPE_INVALID; 546 } 547 } 548 pFrame->fFlags &= ~DBGFSTACKFRAME_FLAGS_TRAP_FRAME; 549 } 550 551 /* 552 * Figure the return address size and use the old PC to guess stack item size. 553 */ 554 unsigned const cbRetAddr = 8; 555 unsigned const cbStackItem = 8; /** @todo AARCH32. */ 556 PVMCPUCC const pVCpu = pUnwindCtx->m_pUVM->pVM->apCpusR3[pUnwindCtx->m_idCpu]; 557 558 /* 559 * Read the raw frame data. 560 * We double cbRetAddr in case we have a far return. 561 */ 562 union 563 { 564 uint64_t *pu64; 565 uint32_t *pu32; 566 uint8_t *pb; 567 void *pv; 568 } u, uRet, uArgs, uBp; 569 size_t cbRead = cbRetAddr * 2 + cbStackItem + sizeof(pFrame->Args); 570 u.pv = alloca(cbRead); 571 uBp = u; 572 uRet.pb = u.pb + cbStackItem; 573 uArgs.pb = u.pb + cbStackItem + cbRetAddr; 574 575 Assert(DBGFADDRESS_IS_VALID(&pFrame->AddrFrame)); 576 int rc = dbgfR3StackRead(pUnwindCtx->m_pUVM, pUnwindCtx->m_idCpu, u.pv, &pFrame->AddrFrame, cbRead, &cbRead); 577 if ( RT_FAILURE(rc) 578 || cbRead < cbRetAddr + cbStackItem) 579 pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_LAST; 580 581 /* 582 * Return Frame address. 583 * 584 * If we used unwind info to get here, the unwind register context will be 585 * positioned after the return instruction has been executed. We start by 586 * picking up the rBP register here for return frame and will try improve 587 * on it further down by using unwind info. 588 */ 589 pFrame->AddrReturnFrame = pFrame->AddrFrame; 590 if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO) 591 { 592 AssertFailed(); /** @todo */ 593 } 594 else 595 { 596 switch (cbStackItem) 597 { 598 case 4: pFrame->AddrReturnFrame.off = *uBp.pu32; break; 599 case 8: pFrame->AddrReturnFrame.off = CPUMGetGCPtrPacStripped(pVCpu, *uBp.pu64); break; 600 default: AssertMsgFailedReturn(("cbStackItem=%d\n", cbStackItem), VERR_DBGF_STACK_IPE_1); 601 } 602 603 pFrame->AddrReturnFrame.FlatPtr += pFrame->AddrReturnFrame.off - pFrame->AddrFrame.off; 604 } 605 606 /* 607 * Return Stack Address. 608 */ 609 pFrame->AddrReturnStack = pFrame->AddrReturnFrame; 610 if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO) 611 { 612 AssertFailed(); 613 } 614 else 615 { 616 pFrame->AddrReturnStack.off += cbStackItem + cbRetAddr; 617 pFrame->AddrReturnStack.FlatPtr += cbStackItem + cbRetAddr; 618 } 619 620 /* 621 * Return PC. 622 */ 623 pFrame->AddrReturnPC = pFrame->AddrPC; 624 if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO) 625 { 626 AssertFailed(); 627 } 628 else 629 { 630 switch (pFrame->enmReturnType) 631 { 632 case RTDBGRETURNTYPE_NEAR64: 633 if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC)) 634 { 635 pFrame->AddrReturnPC.FlatPtr += CPUMGetGCPtrPacStripped(pVCpu, *uRet.pu64) - pFrame->AddrReturnPC.off; 636 pFrame->AddrReturnPC.off = CPUMGetGCPtrPacStripped(pVCpu, *uRet.pu64); 637 } 638 else 639 DBGFR3AddrFromFlat(pUnwindCtx->m_pUVM, &pFrame->AddrReturnPC, CPUMGetGCPtrPacStripped(pVCpu, *uRet.pu64)); 640 break; 641 default: 642 AssertMsgFailed(("enmReturnType=%d\n", pFrame->enmReturnType)); 643 return VERR_INVALID_PARAMETER; 644 } 645 } 646 647 648 pFrame->pSymReturnPC = DBGFR3AsSymbolByAddrA(pUnwindCtx->m_pUVM, pUnwindCtx->m_hAs, &pFrame->AddrReturnPC, 649 RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL | RTDBGSYMADDR_FLAGS_SKIP_ABS_IN_DEFERRED, 650 NULL /*poffDisp*/, NULL /*phMod*/); 651 pFrame->pLineReturnPC = DBGFR3AsLineByAddrA(pUnwindCtx->m_pUVM, pUnwindCtx->m_hAs, &pFrame->AddrReturnPC, 652 NULL /*poffDisp*/, NULL /*phMod*/); 653 654 /* 655 * Frame bitness flag. 656 */ 657 /** @todo use previous return type for this? */ 658 pFrame->fFlags &= ~(DBGFSTACKFRAME_FLAGS_32BIT | DBGFSTACKFRAME_FLAGS_64BIT); 659 switch (cbStackItem) 660 { 661 case 4: pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_32BIT; break; 662 case 8: pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_64BIT; break; 663 default: AssertMsgFailedReturn(("cbStackItem=%d\n", cbStackItem), VERR_DBGF_STACK_IPE_2); 664 } 665 666 /* 667 * The arguments. 668 */ 669 memcpy(&pFrame->Args, uArgs.pv, sizeof(pFrame->Args)); 670 671 /* 672 * Collect register changes. 673 * Then call the OS layer to assist us (e.g. NT trap frames). 674 */ 675 if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO) 676 { 677 AssertFailed(); 678 } 679 680 /* 681 * Try use unwind information to locate the return frame pointer (for the 682 * next loop iteration). 683 */ 684 Assert(!(pFrame->fFlags & DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET)); 685 pFrame->enmReturnFrameReturnType = RTDBGRETURNTYPE_INVALID; 686 if (!(pFrame->fFlags & DBGFSTACKFRAME_FLAGS_LAST)) 687 { 688 /* Set PC and SP if we didn't unwind our way here (context will then point 689 and the return PC and SP already). */ 690 if (!(pFrame->fFlags & DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO)) 691 { 692 dbgfR3UnwindCtxSetPcAndSp(pUnwindCtx, &pFrame->AddrReturnPC, &pFrame->AddrReturnStack); 693 pUnwindCtx->m_State.u.armv8.auGprs[ARMV8_A64_REG_BP] = pFrame->AddrReturnFrame.off; 694 } 695 if (pUnwindCtx->m_State.enmArch == RTLDRARCH_ARM64) 696 pUnwindCtx->m_State.u.armv8.Loaded.fAll = 0; 697 else 698 AssertFailed(); 699 if (dbgfR3UnwindCtxDoOneFrame(pUnwindCtx)) 700 { 701 Assert(!pUnwindCtx->m_fIsHostRing0); 702 703 DBGFADDRESS AddrReturnFrame = pFrame->AddrReturnFrame; 704 DBGFR3AddrFromFlat(pUnwindCtx->m_pUVM, &AddrReturnFrame, pUnwindCtx->m_State.u.armv8.FrameAddr); 705 pFrame->AddrReturnFrame = AddrReturnFrame; 706 707 pFrame->enmReturnFrameReturnType = pUnwindCtx->m_State.enmRetType; 708 pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET; 709 } 710 } 711 712 return VINF_SUCCESS; 713 } 714 #else 400 715 /** 401 716 * Internal worker routine. … … 793 1108 return VINF_SUCCESS; 794 1109 } 1110 #endif 795 1111 796 1112 … … 851 1167 PVMCPU const pVCpu = pUVM->pVM->apCpusR3[idCpu]; 852 1168 CPUMMODE const enmCpuMode = CPUMGetGuestMode(pVCpu); 1169 #if defined(VBOX_VMM_TARGET_ARMV8) 1170 /** @todo */ 1171 Assert(enmCpuMode == CPUMMODE_ARMV8_AARCH64); RT_NOREF(enmCpuMode); 1172 fAddrMask = UINT64_MAX; 1173 if (enmReturnType == RTDBGRETURNTYPE_INVALID) 1174 pCur->enmReturnType = RTDBGRETURNTYPE_NEAR64; 1175 #else 853 1176 if (enmCpuMode == CPUMMODE_REAL) 854 1177 { … … 870 1193 pCur->enmReturnType = RTDBGRETURNTYPE_NEAR64; 871 1194 } 872 } 873 1195 #endif 1196 } 1197 1198 #if !defined(VBOX_VMM_TARGET_ARMV8) 874 1199 if (enmReturnType == RTDBGRETURNTYPE_INVALID) 875 1200 switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) … … 885 1210 break; 886 1211 } 1212 #endif 887 1213 888 1214 889 1215 #if defined(VBOX_VMM_TARGET_ARMV8) 890 RT_NOREF(pAddrFrame, pAddrStack); 891 AssertFailed(); 892 rc = VERR_NOT_IMPLEMENTED; 1216 if (pAddrStack) 1217 pCur->AddrStack = *pAddrStack; 1218 else 1219 DBGFR3AddrFromFlat(pUVM, &pCur->AddrStack, pCtx->aSpReg[1].u64 & fAddrMask); /** @todo EL0 stack. */ 1220 1221 Assert(!(pCur->fFlags & DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO)); 1222 if (pAddrFrame) 1223 pCur->AddrFrame = *pAddrFrame; 1224 else 1225 DBGFR3AddrFromFlat(pUVM, &pCur->AddrFrame, pCtx->aGRegs[ARMV8_A64_REG_BP].x & fAddrMask); 893 1226 #else 894 1227 if (pAddrStack) … … 917 1250 pCur->enmReturnType = UnwindCtx.m_State.enmRetType; 918 1251 pCur->fFlags |= DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO; 1252 #if defined(VBOX_VMM_TARGET_ARMV8) 1253 DBGFR3AddrFromFlat(pUVM, &pCur->AddrFrame, UnwindCtx.m_State.u.armv8.FrameAddr); 1254 #else 919 1255 if (!UnwindCtx.m_fIsHostRing0) 920 1256 rc = DBGFR3AddrFromSelOff(UnwindCtx.m_pUVM, UnwindCtx.m_idCpu, &pCur->AddrFrame, … … 922 1258 else 923 1259 DBGFR3AddrFromHostR0(&pCur->AddrFrame, UnwindCtx.m_State.u.x86.FrameAddr.off); 1260 #endif 924 1261 } 925 1262 /*
Note:
See TracChangeset
for help on using the changeset viewer.