Exemple #1
0
size_t      GCDump::DumpGCTable(PTR_CBYTE      gcInfoBlock,
                                unsigned       methodSize,
                                bool           verifyGCTables)
{
    GCInfoToken gcInfoToken = { dac_cast<PTR_VOID>(gcInfoBlock), gcInfoVersion };
    GcInfoDecoder hdrdecoder(gcInfoToken,
                             (GcInfoDecoderFlags)(  DECODE_SECURITY_OBJECT
                                     | DECODE_GS_COOKIE
                                     | DECODE_CODE_LENGTH
                                     | DECODE_PSP_SYM
                                     | DECODE_VARARG
                                     | DECODE_GENERICS_INST_CONTEXT
                                     | DECODE_GC_LIFETIMES
                                     | DECODE_PROLOG_LENGTH
                                     | DECODE_RETURN_KIND),
                             0);

    if (NO_SECURITY_OBJECT != hdrdecoder.GetSecurityObjectStackSlot() ||
            NO_GENERICS_INST_CONTEXT != hdrdecoder.GetGenericsInstContextStackSlot() ||
            NO_GS_COOKIE == hdrdecoder.GetGSCookieStackSlot())
    {
        gcPrintf("Prolog size: ");
        UINT32 prologSize = hdrdecoder.GetPrologSize();
        gcPrintf("%d\n", prologSize);
    }

    gcPrintf("Security object: ");
    if (NO_SECURITY_OBJECT == hdrdecoder.GetSecurityObjectStackSlot())
    {
        gcPrintf("<none>\n");
    }
    else
    {
        INT32 ofs = hdrdecoder.GetSecurityObjectStackSlot();
        char sign = '+';

        if (ofs < 0)
        {
            sign = '-';
            ofs = -ofs;
        }

        gcPrintf("caller.sp%c%x\n", sign, ofs);
    }

    gcPrintf("GS cookie: ");
    if (NO_GS_COOKIE == hdrdecoder.GetGSCookieStackSlot())
    {
        gcPrintf("<none>\n");
    }
    else
    {
        INT32 ofs = hdrdecoder.GetGSCookieStackSlot();
        char sign = '+';

        if (ofs < 0)
        {
            sign = '-';
            ofs = -ofs;
        }

        gcPrintf("caller.sp%c%x\n", sign, ofs);

        UINT32 validRangeStart = hdrdecoder.GetGSCookieValidRangeStart();
        UINT32 validRangeEnd = hdrdecoder.GetGSCookieValidRangeEnd();
        gcPrintf("GS cookie valid range: [%x;%x)\n", validRangeStart, validRangeEnd);
    }

    gcPrintf("PSPSym: ");
    if (NO_PSP_SYM == hdrdecoder.GetPSPSymStackSlot())
    {
        gcPrintf("<none>\n");
    }
    else
    {
        INT32 ofs = hdrdecoder.GetPSPSymStackSlot();
        char sign = '+';

        if (ofs < 0)
        {
            sign = '-';
            ofs = -ofs;
        }

#ifdef _TARGET_AMD64_
        // The PSPSym is relative to InitialSP on X64 and CallerSP on other platforms.
        gcPrintf("initial.sp%c%x\n", sign, ofs);
#else
        gcPrintf("caller.sp%c%x\n", sign, ofs);
#endif
    }

    gcPrintf("Generics inst context: ");
    if (NO_GENERICS_INST_CONTEXT == hdrdecoder.GetGenericsInstContextStackSlot())
    {
        gcPrintf("<none>\n");
    }
    else
    {
        INT32 ofs = hdrdecoder.GetGenericsInstContextStackSlot();
        char sign = '+';

        if (ofs < 0)
        {
            sign = '-';
            ofs = -ofs;
        }

        gcPrintf("caller.sp%c%x\n", sign, ofs);
    }

    gcPrintf("PSP slot: ");
    if (NO_PSP_SYM == hdrdecoder.GetPSPSymStackSlot())
    {
        gcPrintf("<none>\n");
    }
    else
    {
        INT32 ofs = hdrdecoder.GetPSPSymStackSlot();
        char sign = '+';

        if (ofs < 0)
        {
            sign = '-';
            ofs = -ofs;
        }

        gcPrintf("caller.sp%c%x\n", sign, ofs);

    }

    gcPrintf("GenericInst slot: ");
    if (NO_GENERICS_INST_CONTEXT == hdrdecoder.GetGenericsInstContextStackSlot())
    {
        gcPrintf("<none>\n");
    }
    else
    {
        INT32 ofs = hdrdecoder.GetGenericsInstContextStackSlot();
        char sign = '+';

        if (ofs < 0)
        {
            sign = '-';
            ofs = -ofs;
        }

        gcPrintf("caller.sp%c%x ", sign, ofs);

        if (hdrdecoder.HasMethodDescGenericsInstContext())
            gcPrintf("(GENERIC_PARAM_CONTEXT_METHODDESC)\n");
        else if (hdrdecoder.HasMethodTableGenericsInstContext())
            gcPrintf("(GENERIC_PARAM_CONTEXT_METHODHANDLE)\n");
        else
            gcPrintf("(GENERIC_PARAM_CONTEXT_THIS)\n");
    }

    gcPrintf("Varargs: %u\n", hdrdecoder.GetIsVarArg());
    gcPrintf("Frame pointer: %s\n", NO_STACK_BASE_REGISTER == hdrdecoder.GetStackBaseRegister()
             ? "<none>"
             : GetRegName(hdrdecoder.GetStackBaseRegister()));

    gcPrintf("Wants Report Only Leaf: %u\n", hdrdecoder.WantsReportOnlyLeaf());

#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA
    gcPrintf("Size of parameter area: %x\n", hdrdecoder.GetSizeOfStackParameterArea());
#endif

    ReturnKind returnKind = hdrdecoder.GetReturnKind();
    gcPrintf("Return Kind: %s\n", ReturnKindToString(returnKind));

    UINT32 cbEncodedMethodSize = hdrdecoder.GetCodeLength();
    gcPrintf("Code size: %x\n", cbEncodedMethodSize);

    GcInfoDumper dumper(gcInfoToken);

    GcInfoDumpState state;
    state.LastCodeOffset = -1;
    state.fAnythingPrinted = FALSE;
    state.fSafePoint = FALSE;
    state.FrameRegister = hdrdecoder.GetStackBaseRegister();
    state.pfnPrintf = gcPrintf;

    GcInfoDumper::EnumerateStateChangesResults result = dumper.EnumerateStateChanges(
                &InterruptibleStateChangeCallback,
                &RegisterStateChangeCallback,
                &StackSlotStateChangeCallback,
                &SafePointCallback,
                &state);

    if (state.fAnythingPrinted)
        gcPrintf("\n");

    switch (result)
    {
    case GcInfoDumper::SUCCESS:
        // do nothing
        break;

    case GcInfoDumper::OUT_OF_MEMORY:
        gcPrintf("out of memory\n");
        break;

    case GcInfoDumper::REPORTED_REGISTER_IN_CALLERS_FRAME:
        gcPrintf("reported register in caller's frame\n");
        break;

    case GcInfoDumper::REPORTED_FRAME_POINTER:
        gcPrintf("reported frame register\n");
        break;

    case GcInfoDumper::REPORTED_INVALID_BASE_REGISTER:
        gcPrintf("reported pointer relative to wrong base register\n");
        break;

    case GcInfoDumper::REPORTED_INVALID_POINTER:
        gcPrintf("reported invalid pointer\n");
        break;

    case GcInfoDumper::DECODER_FAILED:
        gcPrintf("decoder failed\n");
        break;

    default:
        gcPrintf("invalid GC info\n");
        break;
    }

    return (result == GcInfoDumper::SUCCESS) ? dumper.GetGCInfoSize() : 0;
}
Exemple #2
0
GcInfoDumper::EnumerateStateChangesResults GcInfoDumper::EnumerateStateChanges (
        InterruptibleStateChangeProc *pfnInterruptibleStateChange,
        RegisterStateChangeProc *pfnRegisterStateChange,
        StackSlotStateChangeProc *pfnStackSlotStateChange,
        OnSafePointProc *pfnSafePointFunc,
        PVOID pvData)
{
    m_Error = SUCCESS;
    
    //
    // Save callback functions for use by helper functions
    //
    
    m_pfnRegisterStateChange = pfnRegisterStateChange;
    m_pfnStackSlotStateChange = pfnStackSlotStateChange;
    m_pvCallbackData = pvData;

    //
    // Decode header information
    //
    GcInfoDecoder hdrdecoder(m_pbGCInfo,
                             (GcInfoDecoderFlags)(  DECODE_SECURITY_OBJECT
                                                  | DECODE_CODE_LENGTH
                                                  | DECODE_GC_LIFETIMES
                                                  | DECODE_VARARG),
                             0);

    UINT32 cbEncodedMethodSize = hdrdecoder.GetCodeLength();
    m_StackBaseRegister = hdrdecoder.GetStackBaseRegister();

    //
    // Set up a bogus REGDISPLAY to pass to EnumerateLiveSlots.  This will
    // allow us to later identify registers or stack offsets passed to the
    // callback.
    //

    REGDISPLAY regdisp;

    ZeroMemory(&regdisp, sizeof(regdisp));

    regdisp.pContext = &regdisp.ctxOne;
    regdisp.IsCallerContextValid = TRUE;
    regdisp.pCurrentContext = &regdisp.ctxOne;
    regdisp.pCallerContext = &regdisp.ctxTwo;

#define NEXT_ADDRESS() (UniqueAddress += ADDRESS_SPACING)

    UINT iReg;

#ifdef _WIN64
    ULONG64 UniqueAddress = ADDRESS_SPACING*2;
    ULONG64 *pReg;
#else
    DWORD UniqueAddress = ADDRESS_SPACING*2;
    DWORD *pReg;
#endif

#define FILL_REGS(start, count)                                             \
    do {                                                                    \
        for (iReg = 0, pReg = &regdisp.start; iReg < count; iReg++, pReg++) \
        {                                                                   \
            *pReg = NEXT_ADDRESS();                                         \
        }                                                                   \
    } while (0)

#ifdef _TARGET_AMD64_
    FILL_REGS(pCurrentContext->Rax, 16);
    FILL_REGS(pCallerContext->Rax, 16); 

    regdisp.pCurrentContextPointers = &regdisp.ctxPtrsOne;
    regdisp.pCallerContextPointers = &regdisp.ctxPtrsTwo;

    ULONGLONG **ppCurrentRax = &regdisp.pCurrentContextPointers->Rax;
    ULONGLONG **ppCallerRax  = &regdisp.pCallerContextPointers ->Rax;

    for (iReg = 0; iReg < 16; iReg++)
    {
        *(ppCurrentRax + iReg) = &regdisp.pCurrentContext->Rax + iReg;
        *(ppCallerRax  + iReg) = &regdisp.pCallerContext ->Rax + iReg;
    }
#elif defined(_TARGET_ARM_)
    FILL_REGS(pCurrentContext->R0, 16);
    FILL_REGS(pCallerContext->R0, 16);

    regdisp.pCurrentContextPointers = &regdisp.ctxPtrsOne;
    regdisp.pCallerContextPointers = &regdisp.ctxPtrsTwo;
    
    ULONG **ppCurrentReg = &regdisp.pCurrentContextPointers->R4;
    ULONG **ppCallerReg  = &regdisp.pCallerContextPointers->R4;
    
    for (iReg = 0; iReg < 8; iReg++)
    {
        *(ppCurrentReg + iReg) = &regdisp.pCurrentContext->R4 + iReg;
        *(ppCallerReg  + iReg) = &regdisp.pCallerContext->R4 + iReg;
    }
    /// Set Lr
    *(ppCurrentReg + 8) = &regdisp.pCurrentContext->R4 + 10;
    *(ppCallerReg + 8) = &regdisp.pCallerContext->R4 + 10;
    ULONG **ppVolatileReg = &regdisp.volatileCurrContextPointers.R0;
    for (iReg = 0; iReg < 4; iReg++)
    {
        *(ppVolatileReg+iReg) = &regdisp.pCurrentContext->R0 + iReg;
    }
    /// Set R12
    *(ppVolatileReg+4) = &regdisp.pCurrentContext->R0+12;
#endif

#undef FILL_REGS
#undef NEXT_ADDRESS

    SyncRegDisplayToCurrentContext(&regdisp);

    //
    // Enumerate pointers at every possible offset.
    //

#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
    GcInfoDecoder safePointDecoder(m_pbGCInfo, (GcInfoDecoderFlags)0, 0);
#endif

    {
        GcInfoDecoder untrackedDecoder(m_pbGCInfo, DECODE_GC_LIFETIMES, 0);
        untrackedDecoder.EnumerateUntrackedSlots(&regdisp,
                    0,
                    &LivePointerCallback,
                    this);

        BOOL fStop = ReportPointerDifferences(
                    -2,
                    &regdisp,
                    NULL);

        FreePointerRecords(m_pRecords);
        m_pRecords = NULL;

        if (fStop || m_Error)
            return m_Error;
    }

    LivePointerRecord *pLastState = NULL;
    BOOL fPrevInterruptible = FALSE;

    for (UINT32 offset = 0; offset <= cbEncodedMethodSize; offset++)
    {
        BOOL fNewInterruptible = FALSE;

        GcInfoDecoder decoder1(m_pbGCInfo,
                               (GcInfoDecoderFlags)(  DECODE_SECURITY_OBJECT
                                                    | DECODE_CODE_LENGTH
                                                    | DECODE_VARARG
                                                    | DECODE_INTERRUPTIBILITY),
                               offset);

        fNewInterruptible = decoder1.IsInterruptible();

        if (fNewInterruptible != fPrevInterruptible)
        {
            if (pfnInterruptibleStateChange(offset, fNewInterruptible, pvData))
                break;

            fPrevInterruptible = fNewInterruptible;
        }

        unsigned flags = ActiveStackFrame;

#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
        UINT32 safePointOffset = offset;
#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_) 
        safePointOffset++;
#endif
        if(safePointDecoder.IsSafePoint(safePointOffset))
        {
            _ASSERTE(!fNewInterruptible);
            if (pfnSafePointFunc(offset, pvData))
                break;

            flags = 0;
        }
#endif
        
        GcInfoDecoder decoder2(m_pbGCInfo,
                               (GcInfoDecoderFlags)(  DECODE_SECURITY_OBJECT
                                                    | DECODE_CODE_LENGTH
                                                    | DECODE_VARARG
                                                    | DECODE_GC_LIFETIMES
                                                    | DECODE_NO_VALIDATION),
                               offset);

        _ASSERTE(!m_pRecords);

        if(!fNewInterruptible && (flags == ActiveStackFrame))
        {
            // Decoding at non-interruptible offsets is only 
            //  valid in the ExecutionAborted case
            flags |= ExecutionAborted;
        }
        
        if (!decoder2.EnumerateLiveSlots(
                    &regdisp,
                    true,
                    flags | NoReportUntracked,
                    &LivePointerCallback,
                    this))
        {
            m_Error = DECODER_FAILED;
        }
        
        if (m_Error)
            break;

        if (ReportPointerDifferences(
                offset,
                &regdisp,
                pLastState))
        {
            break;
        }

        if (m_Error)
            break;

        FreePointerRecords(pLastState);

        pLastState = m_pRecords;
        m_pRecords = NULL;

        size_t tempSize = decoder2.GetNumBytesRead();
        if( m_gcInfoSize < tempSize )
            m_gcInfoSize = tempSize;
    }

    FreePointerRecords(pLastState);

    FreePointerRecords(m_pRecords);
    m_pRecords = NULL;

    return m_Error;
}