Pass around what kind of transparency an image actually needs. Use
[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 "winternl.h"
34 #include "wine/winbase16.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
38
39 enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
40
41 static const char* wine_dbgstr_addr(const ADDRESS* addr)
42 {
43     if (!addr) return "(null)";
44     switch (addr->Mode)
45     {
46     case AddrModeFlat:
47         return wine_dbg_sprintf("flat<%08lx>", addr->Offset);
48     case AddrMode1616:
49         return wine_dbg_sprintf("1616<%04x:%04lx>", addr->Segment, addr->Offset);
50     case AddrMode1632:
51         return wine_dbg_sprintf("1632<%04x:%08lx>", addr->Segment, addr->Offset);
52     case AddrModeReal:
53         return wine_dbg_sprintf("real<%04x:%04lx>", addr->Segment, addr->Offset);
54     default:
55         return "unknown";
56     }
57 }
58
59 static BOOL CALLBACK read_mem(HANDLE hProcess, DWORD addr, void* buffer,
60                               DWORD size, LPDWORD nread)
61 {
62     return ReadProcessMemory(hProcess, (void*)addr, buffer, size, nread);
63 }
64
65 /* indexes in Reserved array */
66 #define __CurrentMode     0
67 #define __CurrentSwitch   1
68 #define __NextSwitch      2
69
70 #define curr_mode   (frame->Reserved[__CurrentMode])
71 #define curr_switch (frame->Reserved[__CurrentSwitch])
72 #define next_switch (frame->Reserved[__NextSwitch])
73
74 /***********************************************************************
75  *              StackWalk (DBGHELP.@)
76  */
77 BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
78                       LPSTACKFRAME frame, LPVOID ctx,
79                       PREAD_PROCESS_MEMORY_ROUTINE f_read_mem,
80                       PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
81                       PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
82                       PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr)
83 {
84     STACK32FRAME        frame32;
85     STACK16FRAME        frame16;
86     char                ch;
87     ADDRESS             tmp;
88     DWORD               p;
89     WORD                val;
90     BOOL                do_switch;
91
92     TRACE("(%ld, %p, %p, %p, %p, %p, %p, %p, %p)\n",
93           MachineType, hProcess, hThread, frame, ctx,
94           f_read_mem, FunctionTableAccessRoutine,
95           GetModuleBaseRoutine, f_xlat_adr);
96
97     if (MachineType != IMAGE_FILE_MACHINE_I386)
98     {
99         SetLastError(ERROR_INVALID_PARAMETER);
100         return FALSE;
101     }
102
103     /* sanity check */
104     if (curr_mode >= stm_done) return FALSE;
105
106     /* sigh... MS isn't even consistent in the func prototypes */
107     if (!f_read_mem) f_read_mem = read_mem;
108     if (!f_xlat_adr) f_xlat_adr = addr_to_linear;
109
110     TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08lx nSwitch=%08lx\n",
111           wine_dbgstr_addr(&frame->AddrPC), 
112           wine_dbgstr_addr(&frame->AddrFrame),
113           wine_dbgstr_addr(&frame->AddrReturn),
114           wine_dbgstr_addr(&frame->AddrStack), 
115           curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
116           curr_switch, next_switch);
117
118     if (curr_mode == stm_start)
119     {
120         THREAD_BASIC_INFORMATION info;
121
122         if ((frame->AddrPC.Mode == AddrModeFlat) &&
123             (frame->AddrFrame.Mode != AddrModeFlat))
124         {
125             WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n");
126             goto done_err;
127         }
128
129         /* Init done */
130         curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ? 
131             stm_32bit : stm_16bit;
132
133         /* cur_switch holds address of WOW32Reserved field in TEB in debuggee
134          * address space
135          */
136         if (NtQueryInformationThread(hThread, ThreadBasicInformation, &info,    
137                                      sizeof(info), NULL) == STATUS_SUCCESS)
138         {
139             curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved);
140             if (!f_read_mem(hProcess, curr_switch, &next_switch,
141                         sizeof(next_switch), NULL))
142             {
143                 WARN("Can't read TEB:WOW32Reserved\n");
144                 goto done_err;
145             }
146             if (curr_mode == stm_16bit)
147             {
148                 if (!f_read_mem(hProcess, next_switch, &frame32,
149                                 sizeof(frame32), NULL))
150                 {
151                     WARN("Bad stack frame 0x%08lx\n", next_switch);
152                     goto done_err;
153                 }
154                 curr_switch = (DWORD)frame32.frame16;
155                 tmp.Mode    = AddrMode1616;
156                 tmp.Segment = SELECTOROF(curr_switch);
157                 tmp.Offset  = OFFSETOF(curr_switch);
158                 if (!f_read_mem(hProcess, f_xlat_adr(hProcess, hThread, &tmp),
159                                 &ch, sizeof(ch), NULL))
160                     curr_switch = 0xFFFFFFFF;
161             }
162             else
163             {
164                 tmp.Mode    = AddrMode1616;
165                 tmp.Segment = SELECTOROF(next_switch);
166                 tmp.Offset  = OFFSETOF(next_switch);
167                 p = f_xlat_adr(hProcess, hThread, &tmp);
168                 if (!f_read_mem(hProcess, p, &frame16, sizeof(frame16), NULL))
169                 {
170                     WARN("Bad stack frame 0x%08lx\n", p);
171                     goto done_err;
172                 }
173                 curr_switch = (DWORD)frame16.frame32;
174
175                 if (!f_read_mem(hProcess, curr_switch, &ch, sizeof(ch), NULL))
176                     curr_switch = 0xFFFFFFFF;
177             }
178         }
179         else
180             /* FIXME: this will allow to work when we're not attached to a live target, 
181              * but the 16 <=> 32 switch facility won't be available.
182              */
183             curr_switch = 0;
184         frame->AddrReturn.Mode = frame->AddrStack.Mode = (curr_mode == stm_16bit) ? AddrMode1616 : AddrModeFlat;
185         /* don't set up AddrStack on first call. Either the caller has set it up, or
186          * we will get it in the next frame
187          */
188     }
189     else
190     {
191         if (frame->AddrFrame.Offset == 0) goto done_err;
192         if (frame->AddrFrame.Mode == AddrModeFlat)
193         {
194             assert(curr_mode == stm_32bit);
195             do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
196         }
197         else
198         {
199             assert(curr_mode == stm_16bit);
200             do_switch = curr_switch && 
201                 frame->AddrFrame.Segment == SELECTOROF(curr_switch) &&
202                 frame->AddrFrame.Offset >= OFFSETOF(curr_switch);
203         }
204            
205         if (do_switch)
206         {
207             if (curr_mode == stm_16bit)
208             {
209                 if (!f_read_mem(hProcess, next_switch, &frame32, 
210                                 sizeof(frame32), NULL))
211                 {
212                     WARN("Bad stack frame 0x%08lx\n", next_switch);
213                     goto done_err;
214                 }
215
216                 frame->AddrPC.Mode        = AddrModeFlat;
217                 frame->AddrPC.Segment     = 0;
218                 frame->AddrPC.Offset      = frame32.retaddr;
219                 frame->AddrFrame.Mode     = AddrModeFlat;
220                 frame->AddrFrame.Segment  = 0;
221                 frame->AddrFrame.Offset   = frame32.ebp;
222
223                 frame->AddrStack.Mode     = AddrModeFlat;
224                 frame->AddrStack.Segment  = 0;
225                 frame->AddrReturn.Mode    = AddrModeFlat;
226                 frame->AddrReturn.Segment = 0;
227
228                 next_switch = curr_switch;
229                 tmp.Mode    = AddrMode1616;
230                 tmp.Segment = SELECTOROF(next_switch);
231                 tmp.Offset  = OFFSETOF(next_switch);
232                 p = f_xlat_adr(hProcess, hThread, &tmp);
233
234                 if (!f_read_mem(hProcess, p, &frame16, sizeof(frame16), NULL))
235                 {
236                     WARN("Bad stack frame 0x%08lx\n", p);
237                     goto done_err;
238                 }
239                 curr_switch = (DWORD)frame16.frame32;
240                 curr_mode = stm_32bit;
241                 if (!f_read_mem(hProcess, curr_switch, &ch, sizeof(ch), NULL))
242                     curr_switch = 0;
243             }
244             else
245             {
246                 tmp.Mode    = AddrMode1616;
247                 tmp.Segment = SELECTOROF(next_switch);
248                 tmp.Offset  = OFFSETOF(next_switch);
249                 p = f_xlat_adr(hProcess, hThread, &tmp);
250
251                 if (!f_read_mem(hProcess, p, &frame16, sizeof(frame16), NULL))
252                 {
253                     WARN("Bad stack frame 0x%08lx\n", p);
254                     goto done_err;
255                 }
256
257                 TRACE("Got a 16 bit stack switch:"
258                       "\n\tframe32: %08lx"
259                       "\n\tedx:%08lx ecx:%08lx ebp:%08lx"
260                       "\n\tds:%04x es:%04x fs:%04x gs:%04x"
261                       "\n\tcall_from_ip:%08lx module_cs:%04lx relay=%08lx"
262                       "\n\tentry_ip:%04x entry_point:%08lx"
263                       "\n\tbp:%04x ip:%04x cs:%04x\n",
264                       (unsigned long)frame16.frame32,
265                       frame16.edx, frame16.ecx, frame16.ebp,
266                       frame16.ds, frame16.es, frame16.fs, frame16.gs,
267                       frame16.callfrom_ip, frame16.module_cs, frame16.relay,
268                       frame16.entry_ip, frame16.entry_point,
269                       frame16.bp, frame16.ip, frame16.cs);
270
271                       
272                 frame->AddrPC.Mode       = AddrMode1616;
273                 frame->AddrPC.Segment    = frame16.cs;
274                 frame->AddrPC.Offset     = frame16.ip;
275
276                 frame->AddrFrame.Mode    = AddrMode1616;
277                 frame->AddrFrame.Segment = SELECTOROF(next_switch);
278                 frame->AddrFrame.Offset  = frame16.bp;
279
280                 frame->AddrStack.Mode    = AddrMode1616;
281                 frame->AddrStack.Segment = SELECTOROF(next_switch);
282
283                 frame->AddrReturn.Mode    = AddrMode1616;
284                 frame->AddrReturn.Segment = frame16.cs;
285
286                 next_switch = curr_switch;
287                 if (!f_read_mem(hProcess, next_switch, &frame32, sizeof(frame32), NULL))
288                 {
289                     WARN("Bad stack frame 0x%08lx\n", next_switch);
290                     goto done_err;
291                 }
292                 curr_switch = (DWORD)frame32.frame16;
293                 tmp.Mode    = AddrMode1616;
294                 tmp.Segment = SELECTOROF(curr_switch);
295                 tmp.Offset  = OFFSETOF(curr_switch);
296
297                 if (!f_read_mem(hProcess, f_xlat_adr(hProcess, hThread, &tmp),
298                                 &ch, sizeof(ch), NULL))
299                     curr_switch = 0;
300                 curr_mode = stm_16bit;
301             }
302         }
303         else
304         {
305             frame->AddrPC = frame->AddrReturn;
306             if (curr_mode == stm_16bit)
307             {
308                 frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
309                 /* "pop up" previous BP value */
310                 if (!f_read_mem(hProcess, 
311                                 f_xlat_adr(hProcess, hThread, &frame->AddrFrame),
312                                 &val, sizeof(WORD), NULL))
313                     goto done_err;
314                 frame->AddrFrame.Offset = val;
315             }
316             else
317             {
318                 frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
319                 /* "pop up" previous EBP value */
320                 if (!f_read_mem(hProcess, frame->AddrFrame.Offset, 
321                                 &frame->AddrFrame.Offset, sizeof(DWORD), NULL))
322                     goto done_err;
323             }
324         }
325     }
326
327     if (curr_mode == stm_16bit)
328     {
329         int     i;
330
331         p = f_xlat_adr(hProcess, hThread, &frame->AddrFrame);
332         if (!f_read_mem(hProcess, p + sizeof(WORD), &val, sizeof(WORD), NULL))
333             goto done_err;
334         frame->AddrReturn.Offset = val;
335         /* get potential cs if a far call was used */
336         if (!f_read_mem(hProcess, p + 2 * sizeof(WORD), 
337                         &val, sizeof(WORD), NULL))
338             goto done_err;
339         if (frame->AddrFrame.Offset & 1)
340             frame->AddrReturn.Segment = val; /* far call assumed */
341         else
342         {
343             /* not explicitly marked as far call, 
344              * but check whether it could be anyway
345              */
346             if ((val & 7) == 7 && val != frame->AddrReturn.Segment)
347             {
348                 LDT_ENTRY       le;
349
350                 if (GetThreadSelectorEntry(hThread, val, &le) &&
351                     (le.HighWord.Bits.Type & 0x08)) /* code segment */
352                 {
353                     /* it is very uncommon to push a code segment cs as
354                      * a parameter, so this should work in most cases 
355                      */
356                     frame->AddrReturn.Segment = val;
357                 }
358             }
359         }
360         frame->AddrFrame.Offset &= ~1;
361         /* we "pop" parameters as 16 bit entities... of course, this won't
362          * work if the parameter is in fact bigger than 16bit, but
363          * there's no way to know that here
364          */
365         for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
366         {
367             f_read_mem(hProcess, p + (2 + i) * sizeof(WORD), 
368                        &val, sizeof(val), NULL);
369             frame->Params[i] = val;
370         }
371     }
372     else
373     {
374         if (!f_read_mem(hProcess, 
375                         frame->AddrFrame.Offset + sizeof(DWORD),
376                         &frame->AddrReturn.Offset, sizeof(DWORD), NULL))
377         {
378             WARN("Cannot read new frame offset %08lx\n", frame->AddrFrame.Offset + sizeof(DWORD));
379             goto done_err;
380         }
381         f_read_mem(hProcess, 
382                    frame->AddrFrame.Offset + 2 * sizeof(DWORD), 
383                    frame->Params, sizeof(frame->Params), NULL);
384     }
385
386     frame->Far = FALSE;
387     frame->Virtual = FALSE;
388
389     TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08lx nSwitch=%08lx\n",
390           wine_dbgstr_addr(&frame->AddrPC), 
391           wine_dbgstr_addr(&frame->AddrFrame),
392           wine_dbgstr_addr(&frame->AddrReturn),
393           wine_dbgstr_addr(&frame->AddrStack), 
394           curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
395           curr_switch, next_switch);
396
397     return TRUE;
398 done_err:
399     curr_mode = stm_done;
400     return FALSE;
401 }