VirtualBox

Changeset 106383 in vbox for trunk/src/VBox/VMM/VMMR3


Ignore:
Timestamp:
Oct 16, 2024 1:54:40 PM (3 months ago)
Author:
vboxsync
Message:

VMM/DBGFStack: Some early stack walking code, bugref:10393

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/DBGFStack.cpp

    r106061 r106383  
    7676    {
    7777        m_State.u32Magic     = RTDBGUNWINDSTATE_MAGIC;
     78#if defined(VBOX_VMM_TARGET_ARMV8)
     79        m_State.enmArch      = RTLDRARCH_ARM64;
     80#else
    7881        m_State.enmArch      = RTLDRARCH_AMD64;
     82#endif
    7983        m_State.pfnReadStack = dbgfR3StackReadCallback;
    8084        m_State.pvUser       = this;
     
    8387        {
    8488#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;
    8697#else
    8798            m_State.u.x86.auRegs[X86_GREG_xAX] = pInitialCtx->rax;
     
    163174static DECLCALLBACK(int) dbgfR3StackReadCallback(PRTDBGUNWINDSTATE pThis, RTUINTPTR uSp, size_t cbToRead, void *pvDst)
    164175{
     176#if defined(VBOX_VMM_TARGET_ARMV8)
     177    Assert(pThis->enmArch == RTLDRARCH_ARM64);
     178#else
    165179    Assert(   pThis->enmArch == RTLDRARCH_AMD64
    166180           || pThis->enmArch == RTLDRARCH_X86_32);
     181#endif
    167182
    168183    PDBGFUNWINDCTX pUnwindCtx = (PDBGFUNWINDCTX)pThis->pvUser;
     
    173188    else
    174189    {
     190#if defined(VBOX_VMM_TARGET_ARMV8)
     191        DBGFR3AddrFromFlat(pUnwindCtx->m_pUVM, &SrcAddr, uSp);
     192#else
    175193        if (   pThis->enmArch == RTLDRARCH_X86_32
    176194            || pThis->enmArch == RTLDRARCH_X86_16)
     
    183201        else
    184202            DBGFR3AddrFromFlat(pUnwindCtx->m_pUVM, &SrcAddr, uSp);
     203#endif
    185204    }
    186205    if (RT_SUCCESS(rc))
     
    202221static bool dbgfR3UnwindCtxSetPcAndSp(PDBGFUNWINDCTX pUnwindCtx, PCDBGFADDRESS pAddrPC, PCDBGFADDRESS pAddrStack)
    203222{
     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
    204231    Assert(   pUnwindCtx->m_State.enmArch == RTLDRARCH_AMD64
    205232           || pUnwindCtx->m_State.enmArch == RTLDRARCH_X86_32);
     
    219246        pUnwindCtx->m_State.u.x86.auSegs[X86_SREG_SS]  = pAddrStack->Sel;
    220247    }
     248#endif
     249
    221250    return true;
    222251}
     
    293322}
    294323
     324#if !defined(VBOX_VMM_TARGET_ARMV8) /** @todo Unused on ARMv8 for now. */
    295325/**
    296326 * Collects sure registers on frame exit.
     
    306336    pFrame->paSureRegs = NULL;
    307337
     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
    308410    if (   pState->enmArch == RTLDRARCH_AMD64
    309411        || pState->enmArch == RTLDRARCH_X86_32
     
    393495        }
    394496    }
     497#endif
    395498
    396499    return VINF_SUCCESS;
    397500}
    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 */
     513DECL_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
    400715/**
    401716 * Internal worker routine.
     
    7931108    return VINF_SUCCESS;
    7941109}
     1110#endif
    7951111
    7961112
     
    8511167            PVMCPU const   pVCpu      = pUVM->pVM->apCpusR3[idCpu];
    8521168            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
    8531176            if (enmCpuMode == CPUMMODE_REAL)
    8541177            {
     
    8701193                    pCur->enmReturnType = RTDBGRETURNTYPE_NEAR64;
    8711194            }
    872         }
    873 
     1195#endif
     1196        }
     1197
     1198#if !defined(VBOX_VMM_TARGET_ARMV8)
    8741199        if (enmReturnType == RTDBGRETURNTYPE_INVALID)
    8751200            switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
     
    8851210                    break;
    8861211            }
     1212#endif
    8871213
    8881214
    8891215#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);
    8931226#else
    8941227        if (pAddrStack)
     
    9171250            pCur->enmReturnType = UnwindCtx.m_State.enmRetType;
    9181251            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
    9191255            if (!UnwindCtx.m_fIsHostRing0)
    9201256                rc = DBGFR3AddrFromSelOff(UnwindCtx.m_pUVM, UnwindCtx.m_idCpu, &pCur->AddrFrame,
     
    9221258            else
    9231259                DBGFR3AddrFromHostR0(&pCur->AddrFrame, UnwindCtx.m_State.u.x86.FrameAddr.off);
     1260#endif
    9241261        }
    9251262        /*
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette