|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: walk.c ! 8: ! 9: Abstract: ! 10: ! 11: This file provides support for stack walking. ! 12: ! 13: Author: ! 14: ! 15: Wesley Witt (wesw) 1-May-1993 ! 16: ! 17: Environment: ! 18: ! 19: User Mode ! 20: ! 21: --*/ ! 22: ! 23: #include <windows.h> ! 24: #include <stdlib.h> ! 25: #include <stdio.h> ! 26: #include <string.h> ! 27: ! 28: #include "drwatson.h" ! 29: #include "proto.h" ! 30: ! 31: // prototypes ! 32: ! 33: static BOOL ValidateReturnAddress ( DWORD dwRetAddr, PDEBUGPACKET dp ); ! 34: static DWORD GetReturnAddress (DWORD *pdwStackAddr, PDEBUGPACKET dp); ! 35: static PFPO_DATA FindFpoDataForModule( DWORD dwPCAddr, PDEBUGPACKET dp ); ! 36: static PFPO_DATA SearchFpoData( DWORD key, PFPO_DATA base, DWORD num ); ! 37: static BOOL SetNonFpoFrameAddress( PSTACKWALK pstk, PDEBUGPACKET dp ); ! 38: ! 39: ! 40: ! 41: BOOL ! 42: SetNonFpoFrameAddress( PSTACKWALK pstk, PDEBUGPACKET dp ) ! 43: { ! 44: DWORD stack[4]; ! 45: DWORD dwRetAddr; ! 46: DWORD dwStackAddr; ! 47: PFPO_DATA pFpoData; ! 48: int cb; ! 49: ! 50: ! 51: // read the first 2 dwords off the stack ! 52: if (!ReadProcessMemory( dp->hProcess, ! 53: (LPVOID)pstk->frame, ! 54: (LPVOID)stack, ! 55: 8, ! 56: (LPDWORD)&cb )) { ! 57: return FALSE; ! 58: } ! 59: ! 60: // a previous function in the call stack was a fpo function that used ebp as ! 61: // a general purpose register. ul contains the ebp value that was good before ! 62: // that function executed. it is that ebp that we want, not what was just read ! 63: // from the stack. what was just read from the stack is totally bogus. ! 64: if (pstk->ul > 0) { ! 65: stack[0] = pstk->ul; ! 66: pstk->ul = 0; ! 67: } ! 68: pFpoData = FindFpoDataForModule(stack[1], dp); ! 69: pstk->pFpoData = pFpoData; ! 70: if (pFpoData) { ! 71: //-------------------------------------------- ! 72: // this is the code for NON-FPO -> FPO frames ! 73: //-------------------------------------------- ! 74: pstk->ul = stack[0]; ! 75: pstk->frame += (pFpoData->cdwLocals * 4) + 8; ! 76: if (pFpoData->cbFrame == FRAME_FPO) { ! 77: pstk->frame += (pFpoData->cbRegs * 4); ! 78: } ! 79: // this necessary because we need to account for any parameters that ! 80: // were passed to the non-fpo function ! 81: if (pFpoData->cbFrame == FRAME_FPO) { ! 82: if (!ReadProcessMemory( dp->hProcess, ! 83: (LPVOID)pstk->frame, ! 84: (LPVOID)&stack[2], ! 85: 8, ! 86: (LPDWORD)&cb )) { ! 87: return FALSE; ! 88: } ! 89: if (!ValidateReturnAddress(stack[2], dp)) { ! 90: dwStackAddr = pstk->frame; ! 91: dwRetAddr = GetReturnAddress(&dwStackAddr, dp); ! 92: if (dwRetAddr == 0) { ! 93: return FALSE; ! 94: } ! 95: pstk->frame = dwStackAddr - 4; ! 96: } ! 97: else { ! 98: pstk->frame -= 4; ! 99: } ! 100: } ! 101: } ! 102: else { ! 103: //------------------------------------------------ ! 104: // this is the code for NON-FPO -> NON-FPO frames ! 105: //------------------------------------------------ ! 106: pstk->pFpoData = 0; ! 107: ! 108: // dwSaveBP will be -1 when the first frame is being processed and the frame ! 109: // has not been setup (ie EBP has not been pushed). ! 110: if (pstk->ul < 0) { ! 111: pstk->frame = dp->tctx->frame; ! 112: pstk->ul = 0; ! 113: } ! 114: else { ! 115: pstk->frame = stack[0]; ! 116: } ! 117: } ! 118: ! 119: // set the program counter to the return address ! 120: pstk->pc = stack[1]; ! 121: return TRUE; ! 122: } ! 123: ! 124: ! 125: BOOL ! 126: StackWalkNext( PSTACKWALK pstk, PDEBUGPACKET dp ) ! 127: { ! 128: DWORD dwRetAddr; ! 129: DWORD dwStackAddr; ! 130: DWORD dwTemp; ! 131: DWORD stack[2]; ! 132: PFPO_DATA pCpcFpoData; ! 133: PFPO_DATA pRetFpoData; ! 134: int cb; ! 135: ! 136: ! 137: // check to see if the current frame is an fpo frame ! 138: pCpcFpoData = FindFpoDataForModule(pstk->pc, dp); ! 139: if (pCpcFpoData) { ! 140: if (!ReadProcessMemory( dp->hProcess, ! 141: (LPVOID)pstk->frame, ! 142: (LPVOID)stack, ! 143: 8, ! 144: (LPDWORD)&cb )) { ! 145: return FALSE; ! 146: } ! 147: dwRetAddr = stack[1]; ! 148: // is EBP used as a general purpose register in the function? ! 149: if (pCpcFpoData->fUseBP == 1) { ! 150: // backup and get the ebp register off the stack ! 151: pstk->frame -= (pCpcFpoData->cdwLocals * 4) - ! 152: ((pCpcFpoData->cbRegs - 1) * 4); ! 153: if (!ReadProcessMemory( dp->hProcess, ! 154: (LPVOID)pstk->frame, ! 155: (LPVOID)&pstk->ul, ! 156: 4, ! 157: (LPDWORD)&cb )) { ! 158: return FALSE; ! 159: } ! 160: pstk->frame += (pCpcFpoData->cdwLocals * 4) - ! 161: ((pCpcFpoData->cbRegs - 1) * 4); ! 162: } ! 163: // account for parameters and the current frame ! 164: pstk->frame += (pCpcFpoData->cdwParams * 4) + 8; ! 165: // check to see if the next frame is an fpo frame ! 166: pRetFpoData = FindFpoDataForModule(dwRetAddr, dp); ! 167: if (pRetFpoData) { ! 168: //----------------------------------------- ! 169: // this is the code for FPO -> FPO frames ! 170: //----------------------------------------- ! 171: pstk->frame += (pRetFpoData->cdwLocals * 4); ! 172: pstk->pFpoData = pRetFpoData; ! 173: if (pRetFpoData->cbFrame == FRAME_FPO) { ! 174: pstk->frame += (pRetFpoData->cbRegs * 4); ! 175: // this necessary because of registers that may have been saved ! 176: // that we don't know about ! 177: dwStackAddr = pstk->frame; ! 178: dwTemp = GetReturnAddress(&dwStackAddr, dp); ! 179: if (dwTemp == 0) { ! 180: return FALSE; ! 181: } ! 182: pstk->frame = dwStackAddr - 4; ! 183: } ! 184: } ! 185: else { ! 186: //-------------------------------------------- ! 187: // this is the code for FPO -> NON-FPO frames ! 188: //-------------------------------------------- ! 189: pstk->pFpoData = 0; ! 190: if (pCpcFpoData->fUseBP == 1) { ! 191: pstk->frame = pstk->ul; ! 192: pstk->ul = 0; ! 193: } ! 194: else ! 195: if (pstk->ul != 0) { ! 196: pstk->frame = pstk->ul; ! 197: pstk->ul = 0; ! 198: } ! 199: } ! 200: pstk->pc = dwRetAddr; ! 201: } ! 202: else { ! 203: if (!SetNonFpoFrameAddress( pstk, dp )) { ! 204: return FALSE; ! 205: } ! 206: } ! 207: ! 208: // this is what should normally stop the stack walk ! 209: if (!ValidateReturnAddress(pstk->pc, dp)) { ! 210: return FALSE; ! 211: } ! 212: ! 213: if (!ReadProcessMemory( dp->hProcess, ! 214: (LPVOID)(pstk->frame+8), ! 215: (LPVOID)pstk->params, ! 216: 16, ! 217: (LPDWORD)&cb )) { ! 218: return FALSE; ! 219: } ! 220: ! 221: return TRUE; ! 222: } ! 223: ! 224: ! 225: BOOL ! 226: StackWalkInit( PSTACKWALK pstk, PDEBUGPACKET dp ) ! 227: { ! 228: UCHAR code[3]; ! 229: PFPO_DATA pFpoData; ! 230: int cb; ! 231: PMODULEINFO mi; ! 232: ! 233: ! 234: pstk->pc = dp->tctx->pc; ! 235: ! 236: pFpoData = FindFpoDataForModule(pstk->pc, dp); ! 237: pstk->pFpoData = pFpoData; ! 238: if (pFpoData) { ! 239: pstk->frame = dp->tctx->stack; ! 240: mi = GetModuleForPC( dp, dp->tctx->pc ); ! 241: if (mi == NULL) { ! 242: return FALSE; ! 243: } ! 244: if (dp->tctx->pc == mi->dwLoadAddress+pFpoData->ulOffStart) { ! 245: // first byte of code ! 246: pstk->frame -= 4; ! 247: pstk->ul = dp->tctx->frame; ! 248: } ! 249: else { ! 250: // somewhere in the body ! 251: pstk->frame += (pFpoData->cdwLocals * 4); ! 252: if (pFpoData->cbRegs != 7) { ! 253: pstk->frame += (pFpoData->cbRegs * 4); ! 254: } ! 255: pstk->frame -= 4; ! 256: if (pFpoData->fUseBP == 1) { ! 257: // the last item pushed onto the stack was EBP ! 258: if (!ReadProcessMemory( dp->hProcess, ! 259: (LPVOID)pstk->frame, ! 260: (LPVOID)&pstk->ul, ! 261: 4, ! 262: (LPDWORD)&cb )) { ! 263: return FALSE; ! 264: } ! 265: } ! 266: else { ! 267: pstk->ul = dp->tctx->frame; ! 268: } ! 269: } ! 270: } ! 271: else { ! 272: pstk->ul = 0; ! 273: if (!ReadProcessMemory( dp->hProcess, ! 274: (LPVOID)pstk->pc, ! 275: (LPVOID)code, ! 276: 3, ! 277: (LPDWORD)&cb )) { ! 278: return FALSE; ! 279: } ! 280: if ((code[0] == 0x55) || (code[0] == 0x8b && code[1] == 0xec)) { ! 281: pstk->frame = dp->tctx->stack; ! 282: if (code[0] == 0x55) { ! 283: pstk->frame -= 4; ! 284: pstk->ul = -1; ! 285: } ! 286: } ! 287: else { ! 288: pstk->frame = dp->tctx->frame; ! 289: } ! 290: } ! 291: ! 292: if (!ReadProcessMemory( dp->hProcess, ! 293: (LPVOID)(pstk->frame+8), ! 294: (LPVOID)pstk->params, ! 295: 16, ! 296: (LPDWORD)&cb )) { ! 297: return FALSE; ! 298: } ! 299: ! 300: return TRUE; ! 301: } ! 302: ! 303: PFPO_DATA ! 304: SearchFpoData( DWORD key, PFPO_DATA base, DWORD num ) ! 305: { ! 306: PFPO_DATA lo = base; ! 307: PFPO_DATA hi = base + (num - 1); ! 308: PFPO_DATA mid; ! 309: DWORD half; ! 310: ! 311: while (lo <= hi) { ! 312: if (half = num / 2) { ! 313: mid = lo + (num & 1 ? half : (half - 1)); ! 314: if ((key >= mid->ulOffStart)&&(key < (mid->ulOffStart+mid->cbProcSize))) { ! 315: return mid; ! 316: } ! 317: if (key < mid->ulOffStart) { ! 318: hi = mid - 1; ! 319: num = num & 1 ? half : half-1; ! 320: } ! 321: else { ! 322: lo = mid + 1; ! 323: num = half; ! 324: } ! 325: } ! 326: else ! 327: if (num) { ! 328: if ((key >= lo->ulOffStart)&&(key < (lo->ulOffStart+lo->cbProcSize))) { ! 329: return lo; ! 330: } ! 331: else { ! 332: break; ! 333: } ! 334: } ! 335: else { ! 336: break; ! 337: } ! 338: } ! 339: return(NULL); ! 340: } ! 341: ! 342: PFPO_DATA ! 343: FindFpoDataForModule( DWORD dwPCAddr, PDEBUGPACKET dp ) ! 344: { ! 345: PMODULEINFO mi; ! 346: PFPO_DATA pFpoData; ! 347: ! 348: mi = GetModuleForPC( dp, dwPCAddr ); ! 349: ! 350: /* ! 351: * If the address was not found in any dll then return FALSE ! 352: */ ! 353: ! 354: if (mi == NULL) { ! 355: return FALSE; ! 356: } ! 357: ! 358: if (!mi->pFpoData) { ! 359: return FALSE; ! 360: } ! 361: ! 362: /* ! 363: * Search for the PC in the fpo data ! 364: */ ! 365: dwPCAddr -= mi->dwLoadAddress; ! 366: pFpoData = SearchFpoData( dwPCAddr, mi->pFpoData, mi->dwEntries ); ! 367: return pFpoData; ! 368: } ! 369: ! 370: DWORD ! 371: GetReturnAddress (DWORD *pdwStackAddr, PDEBUGPACKET dp ) ! 372: { ! 373: DWORD stack[64]; ! 374: DWORD i, sw; ! 375: ! 376: sw = 64*4; ! 377: if(!ReadProcessMemory(dp->hProcess, (LPVOID)*pdwStackAddr, (LPVOID)stack, sw, &sw)) { ! 378: sw = 0xFFF - (*pdwStackAddr & 0xFFF); ! 379: if(!ReadProcessMemory(dp->hProcess, (LPVOID)*pdwStackAddr, (LPVOID)stack, sw, &sw)) { ! 380: return 0; ! 381: } ! 382: } ! 383: // scan thru the stack looking for a return address ! 384: for (i=0; i<sw/4; i++) { ! 385: if (ValidateReturnAddress(stack[i], dp)) { ! 386: *pdwStackAddr += (i * 4); ! 387: return stack[i]; ! 388: } ! 389: } ! 390: return 0; ! 391: } ! 392: ! 393: BOOL ! 394: ValidateReturnAddress ( DWORD dwRetAddr, PDEBUGPACKET dp ) ! 395: { ! 396: PMODULEINFO mi; ! 397: ! 398: mi = GetModuleForPC( dp, dwRetAddr ); ! 399: ! 400: if (mi == NULL) { ! 401: return FALSE; ! 402: } ! 403: ! 404: return TRUE; ! 405: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.