Exemple #1
0
void OBJECTHANDLE_EnumMemoryRegions(OBJECTHANDLE handle)
{
    SUPPORTS_DAC;
    PTR_TADDR ref = PTR_TADDR(handle);
    if (ref.IsValid())
    {
        ref.EnumMem();
        
        PTR_Object obj = PTR_Object(*ref);
        if (obj.IsValid())
        {
            obj->EnumMemoryRegions();
        }
    }
}
Exemple #2
0
// 
// DacEnumCodeForStackwalk
// This is a helper function to enumerate the instructions around a call site to aid heuristics
// used by debugger stack walkers.
// 
// Arguments:
//     taCallEnd - target address of the instruction just after the call instruction for the stack
//                 frame we want to examine(i.e. the return address for the next frame).
// 
// Note that this is shared by our two stackwalks during minidump generation, 
// code:Thread::EnumMemoryRegionsWorker and code:ClrDataAccess::EnumMemWalkStackHelper.  Ideally 
// we'd only have one stackwalk, but we currently have two different APIs for stackwalking 
// (CLR StackFrameIterator and IXCLRDataStackWalk), and we must ensure that the memory needed 
// for either is captured in a minidump.  Eventually, all clients should get moved over to the
// arrowhead debugging architecture, at which time we can rip out all the IXCLRData APIs, and
// so this logic could just be private to the EnumMem code for Thread.
//
void DacEnumCodeForStackwalk(TADDR taCallEnd)
{
    if (taCallEnd == 0)
        return;
    //
    // x86 stack walkers often end up having to guess
    // about what's a return address on the stack.
    // Doing so involves looking at the code at the
    // possible call site and seeing if it could
    // reach the callee.  Save enough code and around
    // the call site to allow this with a dump.
    //
    // For whatever reason 64-bit platforms require us to save
    // the instructions around the call sites on the stack as well.
    // Otherwise we cannnot show the stack in a minidump.
    //
    // Note that everything we do here is a heuristic that won't always work in general.
    // Eg., part of the 2xMAX_INSTRUCTION_LENGTH range might not be mapped (we could be
    // right on a page boundary).  More seriously, X86 is not necessarily parsable in reverse
    // (eg. there could be a segment-override prefix in front of the call instruction that
    // we miss).  So we'll dump what we can and ignore any failures.  Ideally we'd better
    // quantify exactly what debuggers need and why, and try and avoid these ugly heuristics.
    // It seems like these heuristics are too tightly coupled to the implementation details
    // of some specific debugger stackwalking algorithm.
    //  
    DacEnumMemoryRegion(taCallEnd - MAX_INSTRUCTION_LENGTH, MAX_INSTRUCTION_LENGTH * 2, false);

#if defined(_TARGET_X86_)
    // If it was an indirect call we also need to save the data indirected through.
    // Note that this only handles absolute indirect calls (ModR/M byte of 0x15), all the other forms of
    // indirect calls are register-relative, and so we'd have to do a much more complicated decoding based
    // on the register context.  Regardless, it seems like this is fundamentally error-prone because it's 
    // aways possible that the call instruction was not 6 bytes long, and we could have some other instructions
    // that happen to match the pattern we're looking for.
    PTR_BYTE callCode = PTR_BYTE(taCallEnd - 6);
    PTR_BYTE callMrm = PTR_BYTE(taCallEnd - 5);
    PTR_TADDR callInd = PTR_TADDR(taCallEnd - 4);
    if (callCode.IsValid() &&
        (*callCode == 0xff) &&
        callMrm.IsValid() &&
        (*callMrm == 0x15) &&
        callInd.IsValid())
    {
        DacEnumMemoryRegion(*callInd, sizeof(TADDR), false);
    }
#endif // #ifdef _TARGET_X86_
}
Exemple #3
0
    lazyState->_esi = baseState->_esi;
    lazyState->_ebx = baseState->_ebx;
    lazyState->_ebp = baseState->captureEbp;
#ifndef DACCESS_COMPILE
    lazyState->_pEdi = &baseState->_edi;
    lazyState->_pEsi = &baseState->_esi;
    lazyState->_pEbx = &baseState->_ebx;
    lazyState->_pEbp = &baseState->_ebp;
#endif

    // We have captured the state of the registers as they exist in 'captureState'
    // we need to simulate execution from the return address captured in 'captureState
    // until we return from the caller of captureState.

    PTR_BYTE ip = PTR_BYTE(baseState->captureEip);
    PTR_TADDR ESP = PTR_TADDR(baseState->captureEsp);
    ESP++;                                 // pop captureState's return address


    // VC now has small helper calls that it uses in epilogs.  We need to walk into these
    // helpers if we are to decode the stack properly.  After we walk the helper we need
    // to return and continue walking the epiliog.  This varaible remembers were to return to
    PTR_BYTE epilogCallRet = PTR_BYTE((TADDR)0);

    // The very first conditional jump that we are going to encounter is
    // the one testing for the return value of LazyMachStateCaptureState.
    // The non-zero path is the one directly leading to a return statement.
    // This variable keeps track of whether we are still looking for that
    // first conditional jump.
    BOOL bFirstCondJmp = TRUE;