|
|
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.