Assorted spelling fixes.
[wine] / dlls / dbghelp / stack.c
1 /*
2  * Stack walking
3  *
4  * Copyright 1995 Alexandre Julliard
5  * Copyright 1996 Eric Youngdale
6  * Copyright 1999 Ove Kåven
7  * Copyright 2004 Eric Pouech
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "config.h"
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <assert.h>
29
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"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
39
40 enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
41
42 static const char* wine_dbgstr_addr(const ADDRESS* addr)
43 {
44     if (!addr) return "(null)";
45     switch (addr->Mode)
46     {
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";
57     }
58 }
59
60 /* indexes in Reserved array */
61 #define __CurrentMode     0
62 #define __CurrentSwitch   1
63 #define __NextSwitch      2
64
65 #define curr_mode   (frame->Reserved[__CurrentMode])
66 #define curr_switch (frame->Reserved[__CurrentSwitch])
67 #define next_switch (frame->Reserved[__NextSwitch])
68
69 /***********************************************************************
70  *              StackWalk (DBGHELP.@)
71  */
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)
78 {
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;
88
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);
93
94     if (MachineType != IMAGE_FILE_MACHINE_I386)
95     {
96         SetLastError(ERROR_INVALID_PARAMETER);
97         return FALSE;
98     }
99
100     /* sanity check */
101     if (curr_mode >= stm_done) return FALSE;
102
103     if (!f_read_mem) f_read_mem = ReadProcessMemory;
104     if (!f_xlat_adr) f_xlat_adr = addr_to_linear;
105
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);
113
114     if (curr_mode == stm_start)
115     {
116         THREAD_BASIC_INFORMATION info;
117
118         /* Init done */
119         curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ? 
120             stm_32bit : stm_16bit;
121
122         /* Get the current ESP (don't know if this is valid) */
123         if (ctx)
124         {
125             frame->AddrStack.Segment = 0;
126             frame->AddrStack.Offset  = ctx->Esp;
127             frame->AddrStack.Mode    = AddrModeFlat;
128         }
129         /* cur_switch holds address of curr_stack's field in TEB in debuggee
130          * address space
131          */
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))
138         {
139             WARN("Can't read TEB:cur_stack\n");
140             goto done_err;
141         }
142         if (curr_mode == stm_16bit)
143         {
144             if (!f_read_mem(hProcess, (void*)next_switch, &frame32, 
145                             sizeof(frame32), NULL))
146             {
147                 WARN("Bad stack frame 0x%08lx\n", next_switch);
148                 goto done_err;
149             }
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;
163         }
164         else
165         {
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))
171             {
172                 WARN("Bad stack frame 0x%08lx\n", p);
173                 goto done_err;
174             }
175             curr_switch = (DWORD)frame16.frame32;
176
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;
184         }
185     }
186     else
187     {
188         if (frame->AddrFrame.Offset == 0) goto done_err;
189         if (frame->AddrFrame.Mode == AddrModeFlat)
190         {
191             assert(curr_mode == stm_32bit);
192             do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
193         }
194         else
195         {
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);
200         }
201            
202         if (do_switch)
203         {
204             if (curr_mode == stm_16bit)
205             {
206                 if (!f_read_mem(hProcess, (void*)next_switch, &frame32, 
207                                 sizeof(frame32), NULL))
208                 {
209                     WARN("Bad stack frame 0x%08lx\n", next_switch);
210                     goto done_err;
211                 }
212
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;
219
220                 frame->AddrStack.Mode     = AddrModeFlat;
221                 frame->AddrStack.Segment  = 0;
222                 frame->AddrReturn.Mode    = AddrModeFlat;
223                 frame->AddrReturn.Segment = 0;
224
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);
230
231                 if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
232                 {
233                     WARN("Bad stack frame 0x%08lx\n", p);
234                     goto done_err;
235                 }
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;
240             }
241             else
242             {
243                 tmp.Mode    = AddrMode1616;
244                 tmp.Segment = SELECTOROF(next_switch);
245                 tmp.Offset  = OFFSETOF(next_switch);
246                 p = f_xlat_adr(hProcess, hThread, &tmp);
247
248                 if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
249                 {
250                     WARN("Bad stack frame 0x%08lx\n", p);
251                     goto done_err;
252                 }
253
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);
267
268                       
269                 frame->AddrPC.Mode       = AddrMode1616;
270                 frame->AddrPC.Segment    = frame16.cs;
271                 frame->AddrPC.Offset     = frame16.ip;
272
273                 frame->AddrFrame.Mode    = AddrMode1616;
274                 frame->AddrFrame.Segment = SELECTOROF(next_switch);
275                 frame->AddrFrame.Offset  = frame16.bp;
276
277                 frame->AddrStack.Mode    = AddrMode1616;
278                 frame->AddrStack.Segment = SELECTOROF(next_switch);
279
280                 frame->AddrReturn.Mode    = AddrMode1616;
281                 frame->AddrReturn.Segment = frame16.cs;
282
283                 next_switch = curr_switch;
284                 if (!f_read_mem(hProcess, (void*)next_switch, &frame32, sizeof(frame32),
285                                 NULL))
286                 {
287                     WARN("Bad stack frame 0x%08lx\n", next_switch);
288                     goto done_err;
289                 }
290                 curr_switch = (DWORD)frame32.frame16;
291                 tmp.Mode    = AddrMode1616;
292                 tmp.Segment = SELECTOROF(curr_switch);
293                 tmp.Offset  = OFFSETOF(curr_switch);
294
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;
299             }
300         }
301         else
302         {
303             frame->AddrPC = frame->AddrReturn;
304             if (curr_mode == stm_16bit)
305             {
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;
313             }
314             else
315             {
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;
321             }
322         }
323     }
324
325     if (curr_mode == stm_16bit)
326     {
327         int     i;
328
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
340         {
341             /* not explicitly marked as far call, 
342              * but check whether it could be anyway
343              */
344             if ((val & 7) == 7 && val != frame->AddrReturn.Segment)
345             {
346                 LDT_ENTRY       le;
347
348                 if (GetThreadSelectorEntry(hThread, val, &le) &&
349                     (le.HighWord.Bits.Type & 0x08)) /* code segment */
350                 {
351                     /* it is very uncommon to push a code segment cs as
352                      * a parameter, so this should work in most cases 
353                      */
354                     frame->AddrReturn.Segment = val;
355                 }
356             }
357         }
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
362          */
363         for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
364         {
365             f_read_mem(hProcess, (void*)(p + (2 + i) * sizeof(WORD)), 
366                        &val, sizeof(val), NULL);
367             frame->Params[i] = val;
368         }
369     }
370     else
371     {
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);
379     }
380
381     frame->Far = FALSE;
382     frame->Virtual = FALSE;
383
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);
391
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
403 }