Assorted spelling fixes.
[wine/multimedia.git] / dlls / dbghelp / stack.c
blobb094df97cbc4b82cdb61e784b863cafd48a73d46
1 /*
2 * Stack walking
4 * Copyright 1995 Alexandre Julliard
5 * Copyright 1996 Eric Youngdale
6 * Copyright 1999 Ove Kåven
7 * Copyright 2004 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <assert.h>
30 #include "dbghelp_private.h"
31 #include "winreg.h"
32 #include "ntstatus.h"
33 #include "thread.h" /* FIXME: must be included before winternl.h */
34 #include "winternl.h"
35 #include "wine/debug.h"
36 #include "stackframe.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
40 enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
42 static const char* wine_dbgstr_addr(const ADDRESS* addr)
44 if (!addr) return "(null)";
45 switch (addr->Mode)
47 case AddrModeFlat:
48 return wine_dbg_sprintf("flat<%08lx>", addr->Offset);
49 case AddrMode1616:
50 return wine_dbg_sprintf("1616<%04x:%04lx>", addr->Segment, addr->Offset);
51 case AddrMode1632:
52 return wine_dbg_sprintf("1632<%04x:%08lx>", addr->Segment, addr->Offset);
53 case AddrModeReal:
54 return wine_dbg_sprintf("real<%04x:%04lx>", addr->Segment, addr->Offset);
55 default:
56 return "unknown";
60 /* indexes in Reserved array */
61 #define __CurrentMode 0
62 #define __CurrentSwitch 1
63 #define __NextSwitch 2
65 #define curr_mode (frame->Reserved[__CurrentMode])
66 #define curr_switch (frame->Reserved[__CurrentSwitch])
67 #define next_switch (frame->Reserved[__NextSwitch])
69 /***********************************************************************
70 * StackWalk (DBGHELP.@)
72 BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
73 LPSTACKFRAME frame, LPVOID _ctx,
74 PREAD_PROCESS_MEMORY_ROUTINE f_read_mem,
75 PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
76 PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
77 PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr)
79 #ifdef __i386__
80 CONTEXT* ctx = (CONTEXT*)_ctx;
81 STACK32FRAME frame32;
82 STACK16FRAME frame16;
83 char ch;
84 ADDRESS tmp;
85 DWORD p;
86 WORD val;
87 BOOL do_switch;
89 TRACE("(%ld, %p, %p, %p, %p, %p, %p, %p, %p)\n",
90 MachineType, hProcess, hThread, frame, _ctx,
91 f_read_mem, FunctionTableAccessRoutine,
92 GetModuleBaseRoutine, f_xlat_adr);
94 if (MachineType != IMAGE_FILE_MACHINE_I386)
96 SetLastError(ERROR_INVALID_PARAMETER);
97 return FALSE;
100 /* sanity check */
101 if (curr_mode >= stm_done) return FALSE;
103 if (!f_read_mem) f_read_mem = ReadProcessMemory;
104 if (!f_xlat_adr) f_xlat_adr = addr_to_linear;
106 TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08lx nSwitch=%08lx\n",
107 wine_dbgstr_addr(&frame->AddrPC),
108 wine_dbgstr_addr(&frame->AddrFrame),
109 wine_dbgstr_addr(&frame->AddrReturn),
110 wine_dbgstr_addr(&frame->AddrStack),
111 curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
112 curr_switch, next_switch);
114 if (curr_mode == stm_start)
116 THREAD_BASIC_INFORMATION info;
118 /* Init done */
119 curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ?
120 stm_32bit : stm_16bit;
122 /* Get the current ESP (don't know if this is valid) */
123 if (ctx)
125 frame->AddrStack.Segment = 0;
126 frame->AddrStack.Offset = ctx->Esp;
127 frame->AddrStack.Mode = AddrModeFlat;
129 /* cur_switch holds address of curr_stack's field in TEB in debuggee
130 * address space
132 if (NtQueryInformationThread(hThread, ThreadBasicInformation, &info,
133 sizeof(info), NULL) != STATUS_SUCCESS)
134 goto done_err;
135 curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, cur_stack);
136 if (!f_read_mem(hProcess, (void*)curr_switch, &next_switch,
137 sizeof(next_switch), NULL))
139 WARN("Can't read TEB:cur_stack\n");
140 goto done_err;
142 if (curr_mode == stm_16bit)
144 if (!f_read_mem(hProcess, (void*)next_switch, &frame32,
145 sizeof(frame32), NULL))
147 WARN("Bad stack frame 0x%08lx\n", next_switch);
148 goto done_err;
150 curr_switch = (DWORD)frame32.frame16;
151 tmp.Mode = AddrMode1616;
152 tmp.Segment = SELECTOROF(curr_switch);
153 tmp.Offset = OFFSETOF(curr_switch);
154 if (!f_read_mem(hProcess, (void*)f_xlat_adr(hProcess, hThread, &tmp),
155 &ch, sizeof(ch), NULL))
156 curr_switch = 0xFFFFFFFF;
157 frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrMode1616;
158 /* "pop up" previous BP value */
159 if (!f_read_mem(hProcess, (void*)frame->AddrFrame.Offset,
160 &val, sizeof(WORD), NULL))
161 goto done_err;
162 frame->AddrFrame.Offset = val;
164 else
166 tmp.Mode = AddrMode1616;
167 tmp.Segment = SELECTOROF(next_switch);
168 tmp.Offset = OFFSETOF(next_switch);
169 p = f_xlat_adr(hProcess, hThread, &tmp);
170 if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
172 WARN("Bad stack frame 0x%08lx\n", p);
173 goto done_err;
175 curr_switch = (DWORD)frame16.frame32;
177 if (!f_read_mem(hProcess, (void*)curr_switch, &ch, sizeof(ch), NULL))
178 curr_switch = 0xFFFFFFFF;
179 frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrModeFlat;
180 /* "pop up" previous EBP value */
181 if (!f_read_mem(hProcess, (void*)frame->AddrFrame.Offset,
182 &frame->AddrFrame.Offset, sizeof(DWORD), NULL))
183 goto done_err;
186 else
188 if (frame->AddrFrame.Offset == 0) goto done_err;
189 if (frame->AddrFrame.Mode == AddrModeFlat)
191 assert(curr_mode == stm_32bit);
192 do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
194 else
196 assert(curr_mode == stm_16bit);
197 do_switch = OFFSETOF(curr_switch) &&
198 frame->AddrFrame.Segment == SELECTOROF(curr_switch) &&
199 frame->AddrFrame.Offset >= OFFSETOF(curr_switch);
202 if (do_switch)
204 if (curr_mode == stm_16bit)
206 if (!f_read_mem(hProcess, (void*)next_switch, &frame32,
207 sizeof(frame32), NULL))
209 WARN("Bad stack frame 0x%08lx\n", next_switch);
210 goto done_err;
213 frame->AddrPC.Mode = AddrModeFlat;
214 frame->AddrPC.Segment = 0;
215 frame->AddrPC.Offset = frame32.retaddr;
216 frame->AddrFrame.Mode = AddrModeFlat;
217 frame->AddrFrame.Segment = 0;
218 frame->AddrFrame.Offset = frame32.ebp;
220 frame->AddrStack.Mode = AddrModeFlat;
221 frame->AddrStack.Segment = 0;
222 frame->AddrReturn.Mode = AddrModeFlat;
223 frame->AddrReturn.Segment = 0;
225 next_switch = curr_switch;
226 tmp.Mode = AddrMode1616;
227 tmp.Segment = SELECTOROF(next_switch);
228 tmp.Offset = OFFSETOF(next_switch);
229 p = f_xlat_adr(hProcess, hThread, &tmp);
231 if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
233 WARN("Bad stack frame 0x%08lx\n", p);
234 goto done_err;
236 curr_switch = (DWORD)frame16.frame32;
237 curr_mode = stm_32bit;
238 if (!f_read_mem(hProcess, (void*)curr_switch, &ch, sizeof(ch), NULL))
239 curr_switch = 0xFFFFFFFF;
241 else
243 tmp.Mode = AddrMode1616;
244 tmp.Segment = SELECTOROF(next_switch);
245 tmp.Offset = OFFSETOF(next_switch);
246 p = f_xlat_adr(hProcess, hThread, &tmp);
248 if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
250 WARN("Bad stack frame 0x%08lx\n", p);
251 goto done_err;
254 TRACE("Got a 16 bit stack switch:"
255 "\n\tframe32: %08lx"
256 "\n\tedx:%08lx ecx:%08lx ebp:%08lx"
257 "\n\tds:%04x es:%04x fs:%04x gs:%04x"
258 "\n\tcall_from_ip:%08lx module_cs:%04lx relay=%08lx"
259 "\n\tentry_ip:%04x entry_point:%08lx"
260 "\n\tbp:%04x ip:%04x cs:%04x\n",
261 (unsigned long)frame16.frame32,
262 frame16.edx, frame16.ecx, frame16.ebp,
263 frame16.ds, frame16.es, frame16.fs, frame16.gs,
264 frame16.callfrom_ip, frame16.module_cs, frame16.relay,
265 frame16.entry_ip, frame16.entry_point,
266 frame16.bp, frame16.ip, frame16.cs);
269 frame->AddrPC.Mode = AddrMode1616;
270 frame->AddrPC.Segment = frame16.cs;
271 frame->AddrPC.Offset = frame16.ip;
273 frame->AddrFrame.Mode = AddrMode1616;
274 frame->AddrFrame.Segment = SELECTOROF(next_switch);
275 frame->AddrFrame.Offset = frame16.bp;
277 frame->AddrStack.Mode = AddrMode1616;
278 frame->AddrStack.Segment = SELECTOROF(next_switch);
280 frame->AddrReturn.Mode = AddrMode1616;
281 frame->AddrReturn.Segment = frame16.cs;
283 next_switch = curr_switch;
284 if (!f_read_mem(hProcess, (void*)next_switch, &frame32, sizeof(frame32),
285 NULL))
287 WARN("Bad stack frame 0x%08lx\n", next_switch);
288 goto done_err;
290 curr_switch = (DWORD)frame32.frame16;
291 tmp.Mode = AddrMode1616;
292 tmp.Segment = SELECTOROF(curr_switch);
293 tmp.Offset = OFFSETOF(curr_switch);
295 if (!f_read_mem(hProcess, (void*)f_xlat_adr(hProcess, hThread, &tmp),
296 &ch, sizeof(ch), NULL))
297 curr_switch = 0xFFFFFFFF;
298 curr_mode = stm_16bit;
301 else
303 frame->AddrPC = frame->AddrReturn;
304 if (curr_mode == stm_16bit)
306 frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
307 /* "pop up" previous BP value */
308 if (!f_read_mem(hProcess,
309 (void*)f_xlat_adr(hProcess, hThread, &frame->AddrFrame),
310 &val, sizeof(WORD), NULL))
311 goto done_err;
312 frame->AddrFrame.Offset = val;
314 else
316 frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
317 /* "pop up" previous EBP value */
318 if (!f_read_mem(hProcess, (void*)frame->AddrFrame.Offset,
319 &frame->AddrFrame.Offset, sizeof(DWORD), NULL))
320 goto done_err;
325 if (curr_mode == stm_16bit)
327 int i;
329 p = f_xlat_adr(hProcess, hThread, &frame->AddrFrame);
330 if (!f_read_mem(hProcess, (void*)(p + sizeof(WORD)), &val, sizeof(WORD), NULL))
331 goto done_err;
332 frame->AddrReturn.Offset = val;
333 /* get potential cs if a far call was used */
334 if (!f_read_mem(hProcess, (void*)(p + 2 * sizeof(WORD)),
335 &val, sizeof(WORD), NULL))
336 goto done_err;
337 if (frame->AddrFrame.Offset & 1)
338 frame->AddrReturn.Segment = val; /* far call assumed */
339 else
341 /* not explicitly marked as far call,
342 * but check whether it could be anyway
344 if ((val & 7) == 7 && val != frame->AddrReturn.Segment)
346 LDT_ENTRY le;
348 if (GetThreadSelectorEntry(hThread, val, &le) &&
349 (le.HighWord.Bits.Type & 0x08)) /* code segment */
351 /* it is very uncommon to push a code segment cs as
352 * a parameter, so this should work in most cases
354 frame->AddrReturn.Segment = val;
358 frame->AddrFrame.Offset &= ~1;
359 /* we "pop" parameters as 16 bit entities... of course, this won't
360 * work if the parameter is in fact bigger than 16bit, but
361 * there's no way to know that here
363 for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
365 f_read_mem(hProcess, (void*)(p + (2 + i) * sizeof(WORD)),
366 &val, sizeof(val), NULL);
367 frame->Params[i] = val;
370 else
372 if (!f_read_mem(hProcess,
373 (void*)(frame->AddrFrame.Offset + sizeof(DWORD)),
374 &frame->AddrReturn.Offset, sizeof(DWORD), NULL))
375 goto done_err;
376 f_read_mem(hProcess,
377 (void*)(frame->AddrFrame.Offset + 2 * sizeof(DWORD)),
378 frame->Params, sizeof(frame->Params), NULL);
381 frame->Far = FALSE;
382 frame->Virtual = FALSE;
384 TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08lx nSwitch=%08lx\n",
385 wine_dbgstr_addr(&frame->AddrPC),
386 wine_dbgstr_addr(&frame->AddrFrame),
387 wine_dbgstr_addr(&frame->AddrReturn),
388 wine_dbgstr_addr(&frame->AddrStack),
389 curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
390 curr_switch, next_switch);
392 return TRUE;
393 done_err:
394 curr_mode = stm_done;
395 return FALSE;
396 #else /* __i386__ */
397 FIXME("(%ld, %p, %p, %p, %p, %p, %p, %p, %p): stub\n",
398 MachineType, hProcess, hThread, frame, _ctx,
399 f_read_mem, FunctionTableAccessRoutine,
400 GetModuleBaseRoutine, f_xlat_adr);
401 return FALSE;
402 #endif