Showing the Disassembly from a .DMP File (Automating Crash Dump Analysis Part 4)

When investigating a crash, it can often be beneficial to see the assembly leading up too, and even following the event. It turns out that generating the corresponding assembly at an address is pretty easy. The hard part is finding a good starting point for enumerating if we want to look backwards from a given address. On machine architectures that use a variable length instruction set, we can't necessarily walk backwards and expect to get the correct instruction listing, so we need to jump backwards to a know good location, then fast-forward to where we want to be.

 

This function will take the IDebugControl and IDebugSymbols interface pointers opened earlier, then dump out 'numLines' of assembly instructions preceding and following the crash at 'addr'. The input address can be taken from the stack frame or the exception record in the event information.

HRESULT DumpDisassembly(IDebugControl *control, IDebugSymbols *symbols,

    ULONG64 addr, int numLines)

    {

    HRESULT hr = S_OK;

 

    char asmBuffer[1024] = {0};

    ULONG asmSize = 0;

    ULONG64 endAddr = 0;

    ULONG64 ip = addr;

    ULONG64 funcStart = 0;

    ULONG64 offset = 0;

    ULONG procType = 0;

    bool fixedInstructionLength = false;

 

    printf("\nDisassembly\n");

 

    //

    // test for an invalid instruction pointer

    //

    if(addr == 0)

        {

        printf(" no data at address 0x00000000\n");

        return hr;

        }

 

    //

    // determine the algorithm to use

    //

    hr = control->GetEffectiveProcessorType(&procType);

    if(SUCCEEDED(hr))

        {

        if(procType == IMAGE_FILE_MACHINE_ARM)

            fixedInstructionLength = true;

        // insert additional fixed length instruction

        // platforms here

        }

 

    //

    // locate the start of the function

    //

    symbols->GetNameByOffset(addr, NULL, 0, NULL, &offset);

    funcStart = addr - offset;

 

    //

    // find the beginning address

    //

    if(fixedInstructionLength)

        {

        // if we are using a fixed length instruction set

        // then we can easily step backward n lines

        ip = addr;

        hr = control->GetNearInstruction(addr, -numLines, &ip);

        }

    else

        {

        // on a variable length instruction architecture, we need

        // to start at a known good location (funcStart in this case).

        // Then walk each instruction until we get to the addr,

        // keeping track of the history in a circular buffer.

        ULONG64 *circBuffer = new(std::nothrow) ULONG64[numLines];

        size_t index = 0;

        if(circBuffer)

            {

      // initialize the buffer

            for(int i=0; i<numLines; i++)

                circBuffer[i] = 0;

 

            // make sure there is at least one entry

            circBuffer[0] = ip;

 

            // walk from the start till the addr

           ip = funcStart;

            while(ip < addr)

                {

                circBuffer[index] = ip;

 

                hr = control->GetNearInstruction(ip, 1, &ip);

                if(FAILED(hr)) ++ip;

 

                index = (index+1) % numLines;

                }

 

            // find the oldest (non-zero) entry

            do

                {

                ip = circBuffer[index];

                index = (index+1) % numLines;

                } while(ip == 0);

 

            delete[] circBuffer;

  }

        }

 

    // make sure we don't go past the beginning of the funciton

    if(ip < funcStart) ip = funcStart;

 

    //

    // dump out the instructions before and after the event

    //

    for(int lines=0; lines<numLines; )

        {

      hr = control->Disassemble(ip, DEBUG_DISASM_EFFECTIVE_ADDRESS,

            asmBuffer, ARRAYSIZE(asmBuffer)-1, &asmSize, &endAddr);

 

        if(FAILED(hr))

            break;

 

        if(ip == addr)

            printf("> %s", asmBuffer);

        else

            printf(" %s", asmBuffer);

 

        if(ip > addr) ++lines;

 

        ip = endAddr;

        }

 

    return hr;

    }

 

MSDN References

· GetEffectiveProcessorType

· GetNameByOffset

· GetNearInstruction

· Disassemble