File:  [WindowsNT SDKs] / mstools / samples / sdktools / image / drwatson / i386 / walk.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:24:28 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntsdk-nov-1993, ntsdk-jul-1993, HEAD
Microsoft Windows NT Build 511 (SDK Final Release) 07-24-1993

/*++

Copyright (c) 1993  Microsoft Corporation

Module Name:

    walk.c

Abstract:

    This file provides support for stack walking.

Author:

    Wesley Witt (wesw) 1-May-1993

Environment:

    User Mode

--*/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "drwatson.h"
#include "proto.h"

// prototypes

static BOOL ValidateReturnAddress ( DWORD dwRetAddr, PDEBUGPACKET dp );
static DWORD GetReturnAddress (DWORD *pdwStackAddr, PDEBUGPACKET dp);
static PFPO_DATA FindFpoDataForModule( DWORD dwPCAddr, PDEBUGPACKET dp );
static PFPO_DATA SearchFpoData( DWORD key, PFPO_DATA base, DWORD num );
static BOOL SetNonFpoFrameAddress( PSTACKWALK pstk, PDEBUGPACKET dp );



BOOL
SetNonFpoFrameAddress( PSTACKWALK pstk, PDEBUGPACKET dp )
{
    DWORD       stack[4];
    DWORD       dwRetAddr;
    DWORD       dwStackAddr;
    PFPO_DATA   pFpoData;
    int         cb;


    // read the first 2 dwords off the stack
    if (!ReadProcessMemory( dp->hProcess,
                            (LPVOID)pstk->frame,
                            (LPVOID)stack,
                            8,
                            (LPDWORD)&cb )) {
        return FALSE;
    }

    // a previous function in the call stack was a fpo function that used ebp as
    // a general purpose register.  ul contains the ebp value that was good  before
    // that function executed.  it is that ebp that we want, not what was just read
    // from the stack.  what was just read from the stack is totally bogus.
    if (pstk->ul > 0) {
        stack[0] = pstk->ul;
        pstk->ul = 0;
    }
    pFpoData = FindFpoDataForModule(stack[1], dp);
    pstk->pFpoData = pFpoData;
    if (pFpoData) {
        //--------------------------------------------
        // this is the code for NON-FPO -> FPO frames
        //--------------------------------------------
        pstk->ul = stack[0];
        pstk->frame += (pFpoData->cdwLocals * 4) + 8;
        if (pFpoData->cbFrame == FRAME_FPO) {
            pstk->frame += (pFpoData->cbRegs * 4);
        }
        // this necessary because we need to account for any parameters that
        // were passed to the non-fpo function
        if (pFpoData->cbFrame == FRAME_FPO) {
            if (!ReadProcessMemory( dp->hProcess,
                                    (LPVOID)pstk->frame,
                                    (LPVOID)&stack[2],
                                    8,
                                    (LPDWORD)&cb )) {
                return FALSE;
            }
            if (!ValidateReturnAddress(stack[2], dp)) {
                dwStackAddr = pstk->frame;
                dwRetAddr = GetReturnAddress(&dwStackAddr, dp);
                if (dwRetAddr == 0) {
                    return FALSE;
                }
                pstk->frame = dwStackAddr - 4;
            }
            else {
                pstk->frame -= 4;
            }
        }
    }
    else {
        //------------------------------------------------
        // this is the code for NON-FPO -> NON-FPO frames
        //------------------------------------------------
        pstk->pFpoData = 0;

        // dwSaveBP will be -1 when the first frame is being processed and the frame
        // has not been setup (ie EBP has not been pushed).
        if (pstk->ul < 0) {
            pstk->frame = dp->tctx->frame;
            pstk->ul = 0;
        }
        else {
            pstk->frame = stack[0];
        }
    }

    // set the program counter to the return address
    pstk->pc = stack[1];
    return TRUE;
}


BOOL
StackWalkNext( PSTACKWALK pstk, PDEBUGPACKET dp )
{
    DWORD          dwRetAddr;
    DWORD          dwStackAddr;
    DWORD          dwTemp;
    DWORD          stack[2];
    PFPO_DATA      pCpcFpoData;
    PFPO_DATA      pRetFpoData;
    int            cb;


    // check to see if the current frame is an fpo frame
    pCpcFpoData = FindFpoDataForModule(pstk->pc, dp);
    if (pCpcFpoData) {
        if (!ReadProcessMemory( dp->hProcess,
                                (LPVOID)pstk->frame,
                                (LPVOID)stack,
                                8,
                                (LPDWORD)&cb )) {
            return FALSE;
        }
        dwRetAddr = stack[1];
        // is EBP used as a general purpose register in the function?
        if (pCpcFpoData->fUseBP == 1) {
            // backup and get the ebp register off the stack
            pstk->frame -= (pCpcFpoData->cdwLocals * 4) -
                            ((pCpcFpoData->cbRegs - 1) * 4);
            if (!ReadProcessMemory( dp->hProcess,
                                    (LPVOID)pstk->frame,
                                    (LPVOID)&pstk->ul,
                                    4,
                                    (LPDWORD)&cb )) {
                return FALSE;
            }
            pstk->frame += (pCpcFpoData->cdwLocals * 4) -
                           ((pCpcFpoData->cbRegs - 1) * 4);
        }
        // account for parameters and the current frame
        pstk->frame += (pCpcFpoData->cdwParams * 4) + 8;
        // check to see if the next frame is an fpo frame
        pRetFpoData = FindFpoDataForModule(dwRetAddr, dp);
        if (pRetFpoData) {
            //-----------------------------------------
            // this is the code for FPO -> FPO frames
            //-----------------------------------------
            pstk->frame += (pRetFpoData->cdwLocals * 4);
            pstk->pFpoData = pRetFpoData;
            if (pRetFpoData->cbFrame == FRAME_FPO) {
                pstk->frame += (pRetFpoData->cbRegs * 4);
                // this necessary because of registers that may have been saved
                // that we don't know about
                dwStackAddr = pstk->frame;
                dwTemp = GetReturnAddress(&dwStackAddr, dp);
                if (dwTemp == 0) {
                    return FALSE;
                }
                pstk->frame = dwStackAddr - 4;
            }
        }
        else {
            //--------------------------------------------
            // this is the code for FPO -> NON-FPO frames
            //--------------------------------------------
            pstk->pFpoData = 0;
            if (pCpcFpoData->fUseBP == 1) {
                pstk->frame = pstk->ul;
                pstk->ul = 0;
            }
            else
            if (pstk->ul != 0) {
                pstk->frame = pstk->ul;
                pstk->ul = 0;
            }
        }
        pstk->pc = dwRetAddr;
    }
    else {
        if (!SetNonFpoFrameAddress( pstk, dp )) {
            return FALSE;
        }
    }

    // this is what should normally stop the stack walk
    if (!ValidateReturnAddress(pstk->pc, dp)) {
        return FALSE;
    }

    if (!ReadProcessMemory( dp->hProcess,
                            (LPVOID)(pstk->frame+8),
                            (LPVOID)pstk->params,
                            16,
                            (LPDWORD)&cb )) {
        return FALSE;
    }

    return TRUE;
}


BOOL
StackWalkInit( PSTACKWALK pstk, PDEBUGPACKET dp )
{
    UCHAR               code[3];
    PFPO_DATA           pFpoData;
    int                 cb;
    PMODULEINFO         mi;


    pstk->pc = dp->tctx->pc;

    pFpoData = FindFpoDataForModule(pstk->pc, dp);
    pstk->pFpoData = pFpoData;
    if (pFpoData) {
        pstk->frame = dp->tctx->stack;
        mi = GetModuleForPC( dp, dp->tctx->pc );
        if (mi == NULL) {
            return FALSE;
        }
        if (dp->tctx->pc == mi->dwLoadAddress+pFpoData->ulOffStart) {
            // first byte of code
            pstk->frame -= 4;
            pstk->ul = dp->tctx->frame;
        }
        else {
            // somewhere in the body
            pstk->frame += (pFpoData->cdwLocals * 4);
            if (pFpoData->cbRegs != 7) {
                pstk->frame += (pFpoData->cbRegs * 4);
            }
            pstk->frame -= 4;
            if (pFpoData->fUseBP == 1) {
                // the last item pushed onto the stack was EBP
                if (!ReadProcessMemory( dp->hProcess,
                                        (LPVOID)pstk->frame,
                                        (LPVOID)&pstk->ul,
                                        4,
                                        (LPDWORD)&cb )) {
                    return FALSE;
                }
            }
            else {
                pstk->ul = dp->tctx->frame;
            }
        }
    }
    else {
        pstk->ul = 0;
        if (!ReadProcessMemory( dp->hProcess,
                                (LPVOID)pstk->pc,
                                (LPVOID)code,
                                3,
                                (LPDWORD)&cb )) {
            return FALSE;
        }
        if ((code[0] == 0x55) || (code[0] == 0x8b && code[1] == 0xec)) {
            pstk->frame = dp->tctx->stack;
            if (code[0] == 0x55) {
                pstk->frame -= 4;
                pstk->ul = -1;
            }
        }
        else {
            pstk->frame = dp->tctx->frame;
        }
    }

    if (!ReadProcessMemory( dp->hProcess,
                            (LPVOID)(pstk->frame+8),
                            (LPVOID)pstk->params,
                            16,
                            (LPDWORD)&cb )) {
        return FALSE;
    }

    return TRUE;
}

PFPO_DATA
SearchFpoData( DWORD key, PFPO_DATA base, DWORD num )
{
    PFPO_DATA  lo = base;
    PFPO_DATA  hi = base + (num - 1);
    PFPO_DATA  mid;
    DWORD      half;

    while (lo <= hi) {
            if (half = num / 2) {
                    mid = lo + (num & 1 ? half : (half - 1));
                    if ((key >= mid->ulOffStart)&&(key < (mid->ulOffStart+mid->cbProcSize))) {
                        return mid;
                    }
                    if (key < mid->ulOffStart) {
                            hi = mid - 1;
                            num = num & 1 ? half : half-1;
                    }
                    else {
                            lo = mid + 1;
                            num = half;
                    }
            }
            else
            if (num) {
                if ((key >= lo->ulOffStart)&&(key < (lo->ulOffStart+lo->cbProcSize))) {
                    return lo;
                }
                else {
                    break;
                }
            }
            else {
                    break;
            }
    }
    return(NULL);
}

PFPO_DATA
FindFpoDataForModule( DWORD dwPCAddr, PDEBUGPACKET dp )
{
    PMODULEINFO         mi;
    PFPO_DATA           pFpoData;

    mi = GetModuleForPC( dp, dwPCAddr );

    /*
     * If the address was not found in any dll then return FALSE
     */

    if (mi == NULL) {
        return FALSE;
    }

    if (!mi->pFpoData) {
        return FALSE;
    }

    /*
     * Search for the PC in the fpo data
     */
    dwPCAddr -= mi->dwLoadAddress;
    pFpoData = SearchFpoData( dwPCAddr, mi->pFpoData, mi->dwEntries );
    return pFpoData;
}

DWORD
GetReturnAddress (DWORD *pdwStackAddr, PDEBUGPACKET dp )
{
    DWORD       stack[64];
    DWORD       i, sw;

    sw = 64*4;
    if(!ReadProcessMemory(dp->hProcess, (LPVOID)*pdwStackAddr, (LPVOID)stack, sw, &sw)) {
        sw = 0xFFF - (*pdwStackAddr & 0xFFF);
        if(!ReadProcessMemory(dp->hProcess, (LPVOID)*pdwStackAddr, (LPVOID)stack, sw, &sw)) {
            return 0;
        }
    }
    // scan thru the stack looking for a return address
    for (i=0; i<sw/4; i++) {
        if (ValidateReturnAddress(stack[i], dp)) {
            *pdwStackAddr += (i * 4);
            return stack[i];
        }
    }
    return 0;
}

BOOL
ValidateReturnAddress ( DWORD dwRetAddr, PDEBUGPACKET dp )
{
    PMODULEINFO mi;

    mi = GetModuleForPC( dp, dwRetAddr );

    if (mi == NULL) {
        return FALSE;
    }

    return TRUE;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.