VirtualBox

Changeset 73377 in vbox


Ignore:
Timestamp:
Jul 27, 2018 8:01:56 AM (6 years ago)
Author:
vboxsync
Message:

DBGFStack: Early code for walking windows unwind tables. (=> office)

File:
1 edited

Legend:

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

    r73360 r73377  
    3131#include <iprt/param.h>
    3232#include <iprt/assert.h>
     33#include <iprt/alloca.h>
     34#include <iprt/mem.h>
    3335#include <iprt/string.h>
    34 #include <iprt/alloca.h>
    35 
    36 
    37 
     36
     37
     38/*********************************************************************************************************************************
     39*   Structures and Typedefs                                                                                                      *
     40*********************************************************************************************************************************/
    3841/**
    39  * Read stack memory.
    40  */
    41 DECLINLINE(int) dbgfR3Read(PUVM pUVM, VMCPUID idCpu, void *pvBuf, PCDBGFADDRESS pSrcAddr, size_t cb, size_t *pcbRead)
     42 * Unwind context.
     43 *
     44 * @note Using a constructor and destructor here for simple+safe cleanup.
     45 *
     46 * @todo Generalize and move to IPRT or some such place.
     47 */
     48typedef struct DBGFUNWINDCTX
     49{
     50    PUVM        m_pUVM;
     51    VMCPUID     m_idCpu;
     52    RTDBGAS     m_hAs;
     53    uint64_t    m_uPc;
     54    uint64_t    m_aGprs[16];
     55
     56    RTDBGMOD    m_hCached;
     57    RTUINTPTR   m_uCachedMapping;
     58    RTUINTPTR   m_cbCachedMapping;
     59    uint8_t    *m_pbCachedInfo;
     60    size_t      m_cbCachedInfo;
     61
     62    DBGFUNWINDCTX(PUVM pUVM, VMCPUID idCpu, PCCPUMCTX pInitialCtx, RTDBGAS hAs)
     63    {
     64        if (pInitialCtx)
     65        {
     66            m_aGprs[X86_GREG_xAX] = pInitialCtx->rax;
     67            m_aGprs[X86_GREG_xCX] = pInitialCtx->rcx;
     68            m_aGprs[X86_GREG_xDX] = pInitialCtx->rdx;
     69            m_aGprs[X86_GREG_xBX] = pInitialCtx->rbx;
     70            m_aGprs[X86_GREG_xSP] = pInitialCtx->rsp;
     71            m_aGprs[X86_GREG_xBP] = pInitialCtx->rbp;
     72            m_aGprs[X86_GREG_xSI] = pInitialCtx->rsi;
     73            m_aGprs[X86_GREG_xDI] = pInitialCtx->rdi;
     74            m_aGprs[X86_GREG_x8 ] = pInitialCtx->r8;
     75            m_aGprs[X86_GREG_x9 ] = pInitialCtx->r9;
     76            m_aGprs[X86_GREG_x10] = pInitialCtx->r10;
     77            m_aGprs[X86_GREG_x11] = pInitialCtx->r11;
     78            m_aGprs[X86_GREG_x12] = pInitialCtx->r12;
     79            m_aGprs[X86_GREG_x13] = pInitialCtx->r13;
     80            m_aGprs[X86_GREG_x14] = pInitialCtx->r14;
     81            m_aGprs[X86_GREG_x15] = pInitialCtx->r15;
     82            m_uPc                 = pInitialCtx->rip;
     83        }
     84        else
     85        {
     86            RT_BZERO(m_aGprs, sizeof(m_aGprs));
     87            m_uPc = 0;
     88        }
     89        m_pUVM            = pUVM;
     90        m_idCpu           = idCpu;
     91        m_hAs             = hAs;
     92
     93        m_hCached         = NIL_RTDBGMOD;
     94        m_uCachedMapping  = 0;
     95        m_cbCachedMapping = 0;
     96        m_pbCachedInfo    = NULL;
     97        m_cbCachedInfo    = 0;
     98    }
     99
     100    ~DBGFUNWINDCTX();
     101
     102} DBGFUNWINDCTX;
     103/** Pointer to unwind context. */
     104typedef DBGFUNWINDCTX *PDBGFUNWINDCTX;
     105
     106
     107static void dbgfR3UnwindCtxFlushCache(PDBGFUNWINDCTX pUnwindCtx)
     108{
     109    if (pUnwindCtx->m_hCached != NIL_RTDBGMOD)
     110    {
     111        RTDbgModRelease(pUnwindCtx->m_hCached);
     112        pUnwindCtx->m_hCached = NIL_RTDBGMOD;
     113    }
     114    if (pUnwindCtx->m_pbCachedInfo)
     115    {
     116        RTMemFree(pUnwindCtx->m_pbCachedInfo);
     117        pUnwindCtx->m_pbCachedInfo = NULL;
     118    }
     119    pUnwindCtx->m_cbCachedInfo = 0;
     120}
     121
     122
     123DBGFUNWINDCTX::~DBGFUNWINDCTX()
     124{
     125    dbgfR3UnwindCtxFlushCache(this);
     126}
     127
     128
     129static bool dbgfR3UnwindCtxSetPcAndSp(PDBGFUNWINDCTX pUnwindCtx, PCDBGFADDRESS pAddrPC, PCDBGFADDRESS pAddrStack)
     130{
     131    pUnwindCtx->m_uPc                 = pAddrPC->FlatPtr;
     132    pUnwindCtx->m_aGprs[X86_GREG_xSP] = pAddrStack->FlatPtr;
     133    return true;
     134}
     135
     136
     137static bool dbgfR3UnwindCtxDoOneFrameCached(PDBGFUNWINDCTX pUnwindCtx, PDBGFADDRESS pAddrFrame)
     138{
     139    if (!pUnwindCtx->m_cbCachedInfo)
     140        return false;
     141
     142    //PCIMAGE_RUNTIME_FUNCTION_ENTRY;
     143    //UNWIND_HISTORY_TABLE
     144
     145    RT_NOREF_PV(pAddrFrame);
     146    return false;
     147}
     148
     149
     150static bool dbgfR3UnwindCtxDoOneFrame(PDBGFUNWINDCTX pUnwindCtx, PDBGFADDRESS pAddrFrame)
     151{
     152    /*
     153     * Hope for the same module as last time around.
     154     */
     155    RTUINTPTR offCache = pUnwindCtx->m_uPc - pUnwindCtx->m_uCachedMapping;
     156    if (offCache < pUnwindCtx->m_cbCachedMapping)
     157        return dbgfR3UnwindCtxDoOneFrameCached(pUnwindCtx, pAddrFrame);
     158
     159    /*
     160     * Try locate the module.
     161     */
     162    RTDBGMOD        hDbgMod = NIL_RTDBGMOD;
     163    RTUINTPTR       uBase   = 0;
     164    RTDBGSEGIDX     idxSeg  = NIL_RTDBGSEGIDX;
     165    int rc = RTDbgAsModuleByAddr(pUnwindCtx->m_hAs, pUnwindCtx->m_uPc, &hDbgMod, &uBase, &idxSeg);
     166    if (RT_SUCCESS(rc))
     167    {
     168        /* We cache the module regardless of unwind info. */
     169        dbgfR3UnwindCtxFlushCache(pUnwindCtx);
     170        pUnwindCtx->m_hCached         = hDbgMod;
     171        pUnwindCtx->m_uCachedMapping  = uBase;
     172        pUnwindCtx->m_cbCachedMapping = RTDbgModSegmentSize(hDbgMod, idxSeg);
     173
     174        /* Play simple for now. */
     175        if (   idxSeg == NIL_RTDBGSEGIDX
     176            && RTDbgModImageGetFormat(hDbgMod) == RTLDRFMT_PE
     177            && RTDbgModImageGetArch(hDbgMod)   == RTLDRARCH_AMD64)
     178        {
     179            /*
     180             * Try query the unwind data.
     181             */
     182            size_t cbNeeded = 0;
     183            rc = RTDbgModImageQueryProp(hDbgMod, RTLDRPROP_UNWIND_INFO, NULL, 0, &cbNeeded);
     184            if (   rc == VERR_BUFFER_OVERFLOW
     185                && cbNeeded > 12
     186                && cbNeeded < _64M)
     187            {
     188                void *pvBuf = RTMemAllocZ(cbNeeded + 32);
     189                if (pvBuf)
     190                {
     191                    rc = RTDbgModImageQueryProp(hDbgMod, RTLDRPROP_UNWIND_INFO, pUnwindCtx->m_pbCachedInfo, cbNeeded, &cbNeeded);
     192                    if (RT_SUCCESS(rc))
     193                    {
     194                        pUnwindCtx->m_pbCachedInfo = (uint8_t *)pvBuf;
     195                        pUnwindCtx->m_cbCachedInfo = cbNeeded;
     196                        return dbgfR3UnwindCtxDoOneFrameCached(pUnwindCtx, pAddrFrame);
     197                    }
     198                    RTMemFree(pvBuf);
     199                }
     200            }
     201        }
     202    }
     203    return false;
     204}
     205
     206
     207
     208/**
     209 * Read stack memory, will init entire buffer.
     210 */
     211DECLINLINE(int) dbgfR3StackRead(PUVM pUVM, VMCPUID idCpu, void *pvBuf, PCDBGFADDRESS pSrcAddr, size_t cb, size_t *pcbRead)
    42212{
    43213    int rc = DBGFR3MemRead(pUVM, idCpu, pSrcAddr, pvBuf, cb);
     
    78248 *       unwind tables).
    79249 */
    80 static int dbgfR3StackWalk(PUVM pUVM, VMCPUID idCpu, RTDBGAS hAs, PDBGFSTACKFRAME pFrame)
     250DECL_NO_INLINE(static, int) dbgfR3StackWalk(PUVM pUVM, VMCPUID idCpu, RTDBGAS hAs, PDBGFSTACKFRAME pFrame)
    81251{
    82252    /*
     
    138308
    139309    Assert(DBGFADDRESS_IS_VALID(&pFrame->AddrFrame));
    140     int rc = dbgfR3Read(pUVM, idCpu, u.pv,
    141                         pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID
    142                         ? &pFrame->AddrReturnFrame
    143                         : &pFrame->AddrFrame,
    144                         cbRead, &cbRead);
     310    int rc = dbgfR3StackRead(pUVM, idCpu, u.pv,
     311                             pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID
     312                             ? &pFrame->AddrReturnFrame
     313                             : &pFrame->AddrFrame,
     314                             cbRead, &cbRead);
    145315    if (    RT_FAILURE(rc)
    146316        ||  cbRead < cbRetAddr + cbStackItem)
     
    321491 * Walks the entire stack allocating memory as we walk.
    322492 */
    323 static DECLCALLBACK(int) dbgfR3StackWalkCtxFull(PUVM pUVM, VMCPUID idCpu, PCCPUMCTXCORE pCtxCore, RTDBGAS hAs,
     493static DECLCALLBACK(int) dbgfR3StackWalkCtxFull(PUVM pUVM, VMCPUID idCpu, PCCPUMCTX pCtx, RTDBGAS hAs,
    324494                                                DBGFCODETYPE enmCodeType,
    325495                                                PCDBGFADDRESS pAddrFrame,
     
    329499                                                PCDBGFSTACKFRAME *ppFirstFrame)
    330500{
     501    DBGFUNWINDCTX UnwindCtx(pUVM, idCpu, pCtx, hAs);
     502
    331503    /* alloc first frame. */
    332504    PDBGFSTACKFRAME pCur = (PDBGFSTACKFRAME)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_STACK, sizeof(*pCur));
     
    344516        pCur->AddrPC = *pAddrPC;
    345517    else if (enmCodeType != DBGFCODETYPE_GUEST)
    346         DBGFR3AddrFromFlat(pUVM, &pCur->AddrPC, pCtxCore->rip);
     518        DBGFR3AddrFromFlat(pUVM, &pCur->AddrPC, pCtx->rip);
    347519    else
    348         rc = DBGFR3AddrFromSelOff(pUVM, idCpu, &pCur->AddrPC, pCtxCore->cs.Sel, pCtxCore->rip);
     520        rc = DBGFR3AddrFromSelOff(pUVM, idCpu, &pCur->AddrPC, pCtx->cs.Sel, pCtx->rip);
    349521    if (RT_SUCCESS(rc))
    350522    {
    351         if (enmReturnType == DBGFRETURNTYPE_INVALID)
    352             switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
    353             {
    354                 case DBGFADDRESS_FLAGS_FAR16: pCur->enmReturnType = DBGFRETURNTYPE_NEAR16; break;
    355                 case DBGFADDRESS_FLAGS_FAR32: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break;
    356                 case DBGFADDRESS_FLAGS_FAR64: pCur->enmReturnType = DBGFRETURNTYPE_NEAR64; break;
    357                 case DBGFADDRESS_FLAGS_RING0:
    358                     pCur->enmReturnType = HC_ARCH_BITS == 64 ? DBGFRETURNTYPE_NEAR64 : DBGFRETURNTYPE_NEAR32;
    359                     break;
    360                 default:
    361                     pCur->enmReturnType = DBGFRETURNTYPE_NEAR32;
    362                     break; /// @todo 64-bit guests
    363             }
    364 
    365523        uint64_t fAddrMask;
    366524        if (enmCodeType == DBGFCODETYPE_RING0)
     
    377535        {
    378536            PVMCPU pVCpu = VMMGetCpuById(pUVM->pVM, idCpu);
    379             CPUMMODE CpuMode = CPUMGetGuestMode(pVCpu);
    380             if (CpuMode == CPUMMODE_REAL)
     537            CPUMMODE enmCpuMode = CPUMGetGuestMode(pVCpu);
     538            if (enmCpuMode == CPUMMODE_REAL)
     539            {
    381540                fAddrMask = UINT16_MAX;
    382             else if (   CpuMode == CPUMMODE_PROTECTED
     541                if (enmReturnType == DBGFRETURNTYPE_INVALID)
     542                    pCur->enmReturnType = DBGFRETURNTYPE_NEAR16;
     543            }
     544            else if (   enmCpuMode == CPUMMODE_PROTECTED
    383545                     || !CPUMIsGuestIn64BitCode(pVCpu))
     546            {
    384547                fAddrMask = UINT32_MAX;
     548                if (enmReturnType == DBGFRETURNTYPE_INVALID)
     549                    pCur->enmReturnType = DBGFRETURNTYPE_NEAR32;
     550            }
    385551            else
     552            {
    386553                fAddrMask = UINT64_MAX;
    387         }
     554                if (enmReturnType == DBGFRETURNTYPE_INVALID)
     555                    pCur->enmReturnType = DBGFRETURNTYPE_NEAR64;
     556            }
     557        }
     558
     559        if (enmReturnType == DBGFRETURNTYPE_INVALID)
     560            switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
     561            {
     562                case DBGFADDRESS_FLAGS_FAR16: pCur->enmReturnType = DBGFRETURNTYPE_NEAR16; break;
     563                case DBGFADDRESS_FLAGS_FAR32: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break;
     564                case DBGFADDRESS_FLAGS_FAR64: pCur->enmReturnType = DBGFRETURNTYPE_NEAR64; break;
     565                case DBGFADDRESS_FLAGS_RING0:
     566                    pCur->enmReturnType = HC_ARCH_BITS == 64 ? DBGFRETURNTYPE_NEAR64 : DBGFRETURNTYPE_NEAR32;
     567                    break;
     568                default:
     569                    pCur->enmReturnType = DBGFRETURNTYPE_NEAR32;
     570                    break;
     571            }
     572
    388573
    389574        if (pAddrStack)
    390575            pCur->AddrStack = *pAddrStack;
    391576        else if (enmCodeType != DBGFCODETYPE_GUEST)
    392             DBGFR3AddrFromFlat(pUVM, &pCur->AddrStack, pCtxCore->rsp & fAddrMask);
     577            DBGFR3AddrFromFlat(pUVM, &pCur->AddrStack, pCtx->rsp & fAddrMask);
    393578        else
    394             rc = DBGFR3AddrFromSelOff(pUVM, idCpu, &pCur->AddrStack, pCtxCore->ss.Sel, pCtxCore->rsp & fAddrMask);
     579            rc = DBGFR3AddrFromSelOff(pUVM, idCpu, &pCur->AddrStack, pCtx->ss.Sel, pCtx->rsp & fAddrMask);
    395580
    396581        if (pAddrFrame)
    397582            pCur->AddrFrame = *pAddrFrame;
    398         else if (enmCodeType != DBGFCODETYPE_GUEST)
    399             DBGFR3AddrFromFlat(pUVM, &pCur->AddrFrame, pCtxCore->rbp & fAddrMask);
    400         else if (RT_SUCCESS(rc))
    401             rc = DBGFR3AddrFromSelOff(pUVM, idCpu, &pCur->AddrFrame, pCtxCore->ss.Sel, pCtxCore->rbp & fAddrMask);
     583        else
     584        {
     585            if (   RT_SUCCESS(rc)
     586                && dbgfR3UnwindCtxSetPcAndSp(&UnwindCtx, &pCur->AddrPC, &pCur->AddrStack)
     587                && dbgfR3UnwindCtxDoOneFrame(&UnwindCtx, &pCur->AddrFrame))
     588            { }
     589            else if (enmCodeType != DBGFCODETYPE_GUEST)
     590                DBGFR3AddrFromFlat(pUVM, &pCur->AddrFrame, pCtx->rbp & fAddrMask);
     591            else if (RT_SUCCESS(rc))
     592                rc = DBGFR3AddrFromSelOff(pUVM, idCpu, &pCur->AddrFrame, pCtx->ss.Sel, pCtx->rbp & fAddrMask);
     593        }
    402594    }
    403595    else
     
    490682     * Get the CPUM context pointer and pass it on the specified EMT.
    491683     */
    492     RTDBGAS         hAs;
    493     PCCPUMCTXCORE   pCtxCore;
     684    RTDBGAS     hAs;
     685    PCCPUMCTX   pCtx;
    494686    switch (enmCodeType)
    495687    {
    496688        case DBGFCODETYPE_GUEST:
    497             pCtxCore = CPUMGetGuestCtxCore(VMMGetCpuById(pVM, idCpu));
    498             hAs = DBGF_AS_GLOBAL;
     689            pCtx = CPUMQueryGuestCtxPtr(VMMGetCpuById(pVM, idCpu));
     690            hAs  = DBGF_AS_GLOBAL;
    499691            break;
    500692        case DBGFCODETYPE_HYPER:
    501             pCtxCore = CPUMGetHyperCtxCore(VMMGetCpuById(pVM, idCpu));
    502             hAs = DBGF_AS_RC_AND_GC_GLOBAL;
     693            pCtx = CPUMQueryGuestCtxPtr(VMMGetCpuById(pVM, idCpu));
     694            hAs  = DBGF_AS_RC_AND_GC_GLOBAL;
    503695            break;
    504696        case DBGFCODETYPE_RING0:
    505             pCtxCore = NULL;    /* No valid context present. */
    506             hAs = DBGF_AS_R0;
     697            pCtx = NULL;    /* No valid context present. */
     698            hAs  = DBGF_AS_R0;
    507699            break;
    508700        default:
     
    510702    }
    511703    return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3StackWalkCtxFull, 10,
    512                                     pUVM, idCpu, pCtxCore, hAs, enmCodeType,
     704                                    pUVM, idCpu, pCtx, hAs, enmCodeType,
    513705                                    pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
    514706}
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