VirtualBox

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


Ignore:
Timestamp:
Jul 27, 2018 3:20:29 PM (6 years ago)
Author:
vboxsync
Message:

DBGFR3Stack: Working on PE/AMD64 unwinding.

File:
1 edited

Legend:

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

    r73377 r73388  
    3434#include <iprt/mem.h>
    3535#include <iprt/string.h>
     36#include <iprt/formats/pecoff.h>
    3637
    3738
     
    5960    uint8_t    *m_pbCachedInfo;
    6061    size_t      m_cbCachedInfo;
     62
     63    /** Function table for PE/AMD64 (entire m_pbCachedInfo) . */
     64    PCIMAGE_RUNTIME_FUNCTION_ENTRY  m_paFunctions;
     65    /** Number functions in m_paFunctions. */
     66    size_t                          m_cFunctions;
    6167
    6268    DBGFUNWINDCTX(PUVM pUVM, VMCPUID idCpu, PCCPUMCTX pInitialCtx, RTDBGAS hAs)
     
    96102        m_pbCachedInfo    = NULL;
    97103        m_cbCachedInfo    = 0;
     104        m_paFunctions     = NULL;
     105        m_cFunctions      = 0;
    98106    }
    99107
     
    118126    }
    119127    pUnwindCtx->m_cbCachedInfo = 0;
     128    pUnwindCtx->m_paFunctions  = NULL;
     129    pUnwindCtx->m_cFunctions   = 0;
    120130}
    121131
     
    135145
    136146
    137 static 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
     147/**
     148 * Try read a 64-bit value off the stack.
     149 *
     150 * @param   pUnwindCtx      The unwind context.
     151 * @param   uSrcAddr        The stack address.
     152 * @param   puDst           The read destination.
     153 */
     154static void dbgfR3UnwindCtxLoadU64(PDBGFUNWINDCTX pUnwindCtx, uint64_t uSrcAddr, uint64_t *puDst)
     155{
     156    DBGFADDRESS SrcAddr;
     157    DBGFR3MemRead(pUnwindCtx->m_pUVM, pUnwindCtx->m_idCpu,
     158                  DBGFR3AddrFromFlat(pUnwindCtx->m_pUVM, &SrcAddr, uSrcAddr),
     159                  puDst, sizeof(*puDst));
     160}
     161
     162
     163/**
     164 * Binary searches the lookup table.
     165 *
     166 * @returns RVA of unwind info on success, UINT32_MAX on failure.
     167 * @param   paFunctions     The table to lookup @a offFunctionRva in.
     168 * @param   iEnd            Size of the table.
     169 * @param   uRva            The RVA of the function we want.
     170 */
     171DECLINLINE(PCIMAGE_RUNTIME_FUNCTION_ENTRY)
     172dbgfR3UnwindCtxLookupUnwindInfoRva(PCIMAGE_RUNTIME_FUNCTION_ENTRY paFunctions, size_t iEnd, uint32_t uRva)
     173{
     174    size_t iBegin = 0;
     175    while (iBegin < iEnd)
     176    {
     177        size_t const i = iBegin  + (iEnd - iBegin) / 2;
     178        PCIMAGE_RUNTIME_FUNCTION_ENTRY pEntry = &paFunctions[i];
     179        if (uRva < pEntry->BeginAddress)
     180            iEnd = i;
     181        else if (uRva > pEntry->EndAddress)
     182            iBegin = i + 1;
     183        else
     184            return pEntry;
     185    }
     186    return NULL;
     187}
     188
     189
     190static bool dbgfR3UnwindCtxDoOneFrameCached(PDBGFUNWINDCTX pUnwindCtx, uint32_t uRvaRip, PDBGFADDRESS pAddrFrame)
     191{
     192    /*
     193     * Lookup the unwind info RVA and try read it.
     194     */
     195    PCIMAGE_RUNTIME_FUNCTION_ENTRY pEntry = dbgfR3UnwindCtxLookupUnwindInfoRva(pUnwindCtx->m_paFunctions,
     196                                                                               pUnwindCtx->m_cFunctions, uRvaRip);
     197    if (pEntry)
     198    {
     199        unsigned iFrameReg   = ~0U;
     200        unsigned offFrameReg = 0;
     201
     202        for (;;)
     203        {
     204            /*
     205             * Get the info.
     206             */
     207            union
     208            {
     209                uint32_t uRva;
     210                uint8_t  ab[  RT_OFFSETOF(IMAGE_UNWIND_INFO, aOpcodes)
     211                            + sizeof(IMAGE_UNWIND_CODE) * 256
     212                            + sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)];
     213            } uBuf;
     214
     215            uBuf.uRva = pEntry->UnwindInfoAddress;
     216            size_t cbBuf = sizeof(uBuf);
     217            int rc = RTDbgModImageQueryProp(pUnwindCtx->m_hCached, RTLDRPROP_UNWIND_INFO, &uBuf, cbBuf, &cbBuf);
     218            if (RT_FAILURE(rc))
     219                return false;
     220
     221            /*
     222             * Check the info.
     223             */
     224            ASMCompilerBarrier(); /* we're aliasing */
     225            PCIMAGE_UNWIND_INFO pInfo = (PCIMAGE_UNWIND_INFO)&uBuf;
     226
     227            if (pInfo->Version != 1)
     228                return false;
     229
     230            /*
     231             * Execute the opcodes.
     232             */
     233            unsigned const cOpcodes = pInfo->CountOfCodes;
     234            unsigned       iOpcode  = 0;
     235
     236            /* First, skip opcodes that doesn't apply to us if we're the prolog. */
     237            uint32_t offPc = uRvaRip - pEntry->BeginAddress;
     238            if (offPc < pInfo->SizeOfProlog)
     239                while (iOpcode < cOpcodes && pInfo->aOpcodes[iOpcode].u.CodeOffset > offPc)
     240                    iOpcode++;
     241
     242            /* Execute. */
     243            if (pInfo->FrameRegister != 0)
     244            {
     245                iFrameReg   = pInfo->FrameRegister;
     246                offFrameReg = pInfo->FrameOffset * 16;
     247            }
     248            while (iOpcode < cOpcodes)
     249            {
     250                Assert(pInfo->aOpcodes[iOpcode].u.CodeOffset <= offPc);
     251                switch (pInfo->aOpcodes[iOpcode].u.UnwindOp)
     252                {
     253                    case IMAGE_AMD64_UWOP_PUSH_NONVOL:
     254                        pUnwindCtx->m_aGprs[X86_GREG_xSP] -= 8;
     255                        dbgfR3UnwindCtxLoadU64(pUnwindCtx, pUnwindCtx->m_aGprs[X86_GREG_xSP],
     256                                               &pUnwindCtx->m_aGprs[pInfo->aOpcodes[iOpcode].u.OpInfo]);
     257                        iOpcode++;
     258                        break;
     259
     260                    case IMAGE_AMD64_UWOP_ALLOC_LARGE:
     261                        iOpcode += 3;
     262                        AssertBreak(iOpcode <= cOpcodes);
     263                        pUnwindCtx->m_aGprs[X86_GREG_xSP] -= *(uint32_t const *)&pInfo->aOpcodes[iOpcode - 2];
     264                        break;
     265
     266                    case IMAGE_AMD64_UWOP_ALLOC_SMALL:
     267                        AssertBreak(iOpcode <= cOpcodes);
     268                        pUnwindCtx->m_aGprs[X86_GREG_xSP] -= pInfo->aOpcodes[iOpcode].u.OpInfo * 8 + 8;
     269                        iOpcode++;
     270                        break;
     271
     272                    case IMAGE_AMD64_UWOP_SET_FPREG:
     273                        iFrameReg = pInfo->aOpcodes[iOpcode].u.OpInfo;
     274                        offFrameReg = pInfo->FrameOffset * 16;
     275                        break;
     276
     277                    case IMAGE_AMD64_UWOP_SAVE_NONVOL:
     278                    case IMAGE_AMD64_UWOP_SAVE_NONVOL_FAR:
     279                    {
     280                        bool const     fFar  = pInfo->aOpcodes[iOpcode].u.UnwindOp == IMAGE_AMD64_UWOP_SAVE_NONVOL_FAR;
     281                        unsigned const iGreg = pInfo->aOpcodes[iOpcode].u.OpInfo;
     282                        uint32_t       off   = 0;
     283                        iOpcode++;
     284                        if (iOpcode < cOpcodes)
     285                        {
     286                            off = pInfo->aOpcodes[iOpcode].FrameOffset;
     287                            iOpcode++;
     288                            if (fFar && iOpcode < cOpcodes)
     289                            {
     290                                off |= (uint32_t)pInfo->aOpcodes[iOpcode].FrameOffset << 16;
     291                                iOpcode++;
     292                            }
     293                        }
     294                        off *= 8;
     295                        dbgfR3UnwindCtxLoadU64(pUnwindCtx, pUnwindCtx->m_aGprs[X86_GREG_xSP] + off, &pUnwindCtx->m_aGprs[iGreg]);
     296                        break;
     297                    }
     298
     299                    case IMAGE_AMD64_UWOP_SAVE_XMM128:
     300                        iOpcode += 2;
     301                        break;
     302
     303                    case IMAGE_AMD64_UWOP_SAVE_XMM128_FAR:
     304                        iOpcode += 3;
     305                        break;
     306
     307                    case IMAGE_AMD64_UWOP_PUSH_MACHFRAME:
     308                    {
     309                        Assert(pInfo->aOpcodes[iOpcode].u.OpInfo <= 1);
     310                        if (pInfo->aOpcodes[iOpcode].u.OpInfo)
     311                            pUnwindCtx->m_aGprs[X86_GREG_xSP] -= 8; /* error code */
     312
     313                        pUnwindCtx->m_aGprs[X86_GREG_xSP] -= 8; /* RIP */
     314                        dbgfR3UnwindCtxLoadU64(pUnwindCtx, pUnwindCtx->m_aGprs[X86_GREG_xSP], &pUnwindCtx->m_uPc);
     315
     316                        pUnwindCtx->m_aGprs[X86_GREG_xSP] -= 8; /* CS */
     317                        //dbgfR3UnwindCtxLoadU16(pUnwindCtx, pUnwindCtx->m_aGprs[X86_GREG_xSP], &pUnwindCtx->m_uCs);
     318
     319                        pUnwindCtx->m_aGprs[X86_GREG_xSP] -= 8; /* EFLAGS */
     320                        //dbgfR3UnwindCtxLoadU64(pUnwindCtx, pUnwindCtx->m_aGprs[X86_GREG_xSP], &pUnwindCtx->m_uRFlags);
     321
     322                        pUnwindCtx->m_aGprs[X86_GREG_xSP] -= 8; /* RSP */
     323                        uint64_t uNewRsp = (pUnwindCtx->m_aGprs[X86_GREG_xSP] - 8) & ~(uint64_t)15;
     324                        dbgfR3UnwindCtxLoadU64(pUnwindCtx, pUnwindCtx->m_aGprs[X86_GREG_xSP], &uNewRsp);
     325
     326                        pUnwindCtx->m_aGprs[X86_GREG_xSP] -= 8; /* SS */
     327                        //dbgfR3UnwindCtxLoadU16(pUnwindCtx, pUnwindCtx->m_aGprs[X86_GREG_xSP], &pUnwindCtx->m_uSs);
     328
     329                        pUnwindCtx->m_aGprs[X86_GREG_xSP] = uNewRsp;
     330                        return true;
     331                    }
     332
     333                    case IMAGE_AMD64_UWOP_RESERVED_6:
     334                        AssertFailedReturn(false);
     335
     336                    case IMAGE_AMD64_UWOP_RESERVED_7:
     337                        AssertFailedReturn(false);
     338
     339                    default:
     340                        AssertMsgFailedReturn(("%u\n", pInfo->aOpcodes[iOpcode].u.UnwindOp), false);
     341                }
     342            }
     343
     344            /*
     345             * Chained stuff?
     346             */
     347            if (!(pInfo->Flags & IMAGE_UNW_FLAGS_CHAININFO))
     348                break;
     349            /** @todo impl chains.   */
     350            break;
     351        }
     352
     353        /** @todo do post processing. */
     354    }
    144355
    145356    RT_NOREF_PV(pAddrFrame);
     
    155366    RTUINTPTR offCache = pUnwindCtx->m_uPc - pUnwindCtx->m_uCachedMapping;
    156367    if (offCache < pUnwindCtx->m_cbCachedMapping)
    157         return dbgfR3UnwindCtxDoOneFrameCached(pUnwindCtx, pAddrFrame);
     368        return dbgfR3UnwindCtxDoOneFrameCached(pUnwindCtx, offCache, pAddrFrame);
    158369
    159370    /*
     
    174385        /* Play simple for now. */
    175386        if (   idxSeg == NIL_RTDBGSEGIDX
    176             && RTDbgModImageGetFormat(hDbgMod) == RTLDRFMT_PE
     387            && RTDbgModImageGetFormat(hDbgMod) == RTLDRFMT_32BIT_HACK /// @todo RTLDRFMT_PE (disabled code)
    177388            && RTDbgModImageGetArch(hDbgMod)   == RTLDRARCH_AMD64)
    178389        {
     
    181392             */
    182393            size_t cbNeeded = 0;
    183             rc = RTDbgModImageQueryProp(hDbgMod, RTLDRPROP_UNWIND_INFO, NULL, 0, &cbNeeded);
     394            rc = RTDbgModImageQueryProp(hDbgMod, RTLDRPROP_UNWIND_TABLE, NULL, 0, &cbNeeded);
    184395            if (   rc == VERR_BUFFER_OVERFLOW
    185                 && cbNeeded > 12
     396                && cbNeeded >= sizeof(*pUnwindCtx->m_paFunctions)
    186397                && cbNeeded < _64M)
    187398            {
     
    189400                if (pvBuf)
    190401                {
    191                     rc = RTDbgModImageQueryProp(hDbgMod, RTLDRPROP_UNWIND_INFO, pUnwindCtx->m_pbCachedInfo, cbNeeded, &cbNeeded);
     402                    rc = RTDbgModImageQueryProp(hDbgMod, RTLDRPROP_UNWIND_TABLE, pUnwindCtx->m_pbCachedInfo, cbNeeded, &cbNeeded);
    192403                    if (RT_SUCCESS(rc))
    193404                    {
    194405                        pUnwindCtx->m_pbCachedInfo = (uint8_t *)pvBuf;
    195406                        pUnwindCtx->m_cbCachedInfo = cbNeeded;
    196                         return dbgfR3UnwindCtxDoOneFrameCached(pUnwindCtx, pAddrFrame);
     407                        pUnwindCtx->m_paFunctions  = (PCIMAGE_RUNTIME_FUNCTION_ENTRY)pvBuf;
     408                        pUnwindCtx->m_cFunctions   = cbNeeded / sizeof(*pUnwindCtx->m_paFunctions);
     409
     410                        return dbgfR3UnwindCtxDoOneFrameCached(pUnwindCtx, pUnwindCtx->m_uPc - pUnwindCtx->m_uCachedMapping,
     411                                                               pAddrFrame);
    197412                    }
    198413                    RTMemFree(pvBuf);
     
    203418    return false;
    204419}
    205 
    206420
    207421
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