Added two missing casts.
[wine] / debugger / stack.c
1 /*
2  * Debugger stack handling
3  *
4  * Copyright 1995 Alexandre Julliard
5  * Copyright 1996 Eric Youngdale
6  * Copyright 1999 Ove Kåven
7  */
8
9 #include "config.h"
10
11 #include <stdlib.h>
12
13 #include "debugger.h"
14 #include "stackframe.h"
15 #include "winbase.h"
16
17 #ifdef __i386__
18 /*
19  * We keep this info for each frame, so that we can
20  * find local variable information correctly.
21  */
22 struct bt_info
23 {
24   unsigned int       cs;
25   unsigned int       eip;
26   unsigned int       ss;
27   unsigned int       ebp;
28   struct symbol_info frame;
29 };
30
31 static int nframe;
32 static struct bt_info * frames = NULL;
33
34 typedef struct
35 {
36     WORD bp;
37     WORD ip;
38     WORD cs;
39 } FRAME16;
40
41 typedef struct
42 {
43     DWORD bp;
44     DWORD ip;
45     WORD cs;
46 } FRAME32;
47 #endif
48
49
50 /***********************************************************************
51  *           DEBUG_InfoStack
52  *
53  * Dump the top of the stack
54  */
55 void DEBUG_InfoStack(void)
56 {
57 #ifdef __i386__
58     DBG_VALUE   value;
59     
60     value.type = NULL;
61     value.cookie = DV_TARGET;
62     value.addr.seg = DEBUG_context.SegSs;
63     value.addr.off = DEBUG_context.Esp;
64
65     DEBUG_Printf(DBG_CHN_MESG,"Stack dump:\n");
66     switch (DEBUG_GetSelectorType(value.addr.seg)) {
67     case 32: /* 32-bit mode */
68        DEBUG_ExamineMemory( &value, 24, 'x' );
69        break;
70     case 16:  /* 16-bit mode */
71         value.addr.off &= 0xffff;
72         DEBUG_ExamineMemory( &value, 24, 'w' );
73         break;
74     default:
75        DEBUG_Printf(DBG_CHN_MESG, "Bad segment (%ld)\n", value.addr.seg);
76     }
77     DEBUG_Printf(DBG_CHN_MESG,"\n");
78 #endif
79 }
80
81 #ifdef __i386__
82 static void DEBUG_ForceFrame(DBG_ADDR *stack, DBG_ADDR *code, int frameno, int bits, int noisy, const char *caveat)
83 {
84     int theframe = nframe++;
85     frames = (struct bt_info *)DBG_realloc(frames,
86                                            nframe*sizeof(struct bt_info));
87     if (noisy)
88       DEBUG_Printf(DBG_CHN_MESG,"%s%d ", (theframe == curr_frame ? "=>" : "  "),
89               frameno);
90     frames[theframe].cs = code->seg;
91     frames[theframe].eip = code->off;
92     if (noisy)
93       frames[theframe].frame = DEBUG_PrintAddressAndArgs( code, bits, 
94                                                           stack->off, TRUE );
95     else
96       DEBUG_FindNearestSymbol( code, TRUE, 
97                                &frames[theframe].frame.sym, stack->off, 
98                                &frames[theframe].frame.list);
99     frames[theframe].ss = stack->seg;
100     frames[theframe].ebp = stack->off;
101     if (noisy) {
102       DEBUG_Printf( DBG_CHN_MESG, (bits == 16) ? " (bp=%04lx%s)\n" : " (ebp=%08lx%s)\n", stack->off, caveat?caveat:"" );
103     }
104 }
105
106 static BOOL DEBUG_Frame16(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
107 {
108     unsigned int        possible_cs = 0;
109     FRAME16             frame;
110     void*               p = (void*)DEBUG_ToLinear(addr);
111     DBG_ADDR            code;
112     
113     if (!p) return FALSE;
114     
115     if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
116         if (noisy) DEBUG_InvalAddr(addr);
117         return FALSE;
118     }
119     if (!frame.bp) return FALSE;
120
121     if (frame.bp & 1) *cs = frame.cs;
122     else {
123         /* not explicitly marked as far call,
124          * but check whether it could be anyway */
125         if (((frame.cs&7)==7) && (frame.cs != *cs)) {
126             LDT_ENTRY   le;
127          
128             if (GetThreadSelectorEntry( DEBUG_CurrThread->handle, frame.cs, &le) &&
129                 (le.HighWord.Bits.Type & 0x08)) { /* code segment */
130                 /* it is very uncommon to push a code segment cs as
131                  * a parameter, so this should work in most cases */
132                 *cs = possible_cs = frame.cs;
133             }
134         }
135     }
136     code.seg = *cs;
137     code.off = frame.ip;
138     addr->off = frame.bp & ~1;
139     DEBUG_ForceFrame(addr, &code, frameno, 16, noisy, possible_cs ? ", far call assumed" : NULL );
140     return TRUE;
141 }
142
143 static BOOL DEBUG_Frame32(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
144 {
145     FRAME32             frame;
146     void*               p = (void*)DEBUG_ToLinear(addr);
147     DBG_ADDR            code;
148     DWORD               old_bp = addr->off;
149     
150     if (!p) return FALSE;
151     
152     if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
153        if (noisy) DEBUG_InvalAddr(addr);
154        return FALSE;
155     }
156     if (!frame.ip) return FALSE;
157
158     code.seg = *cs;
159     code.off = frame.ip;
160     addr->off = frame.bp;
161     DEBUG_ForceFrame(addr, &code, frameno, 32, noisy, NULL);
162     if (addr->off == old_bp) return FALSE;
163     return TRUE;
164 }
165 #endif
166
167
168 /***********************************************************************
169  *           DEBUG_BackTrace
170  *
171  * Display a stack back-trace.
172  */
173 void DEBUG_BackTrace(BOOL noisy)
174 {
175 #ifdef __i386
176     DBG_ADDR            addr, sw_addr, code, tmp;
177     unsigned int        ss = DEBUG_context.SegSs;
178     unsigned int        cs = DEBUG_context.SegCs;
179     int                 frameno = 0, is16, ok;
180     DWORD               next_switch, cur_switch, p;
181     STACK16FRAME        frame16;
182     STACK32FRAME        frame32;
183     char                ch;
184
185     if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Backtrace:\n" );
186
187     nframe = 0;
188     if (frames) DBG_free( frames );
189     /* frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) ); */
190     frames = NULL;
191
192     if (DEBUG_IsSelectorSystem(ss)) ss = 0;
193     if (DEBUG_IsSelectorSystem(cs)) cs = 0;
194
195     /* first stack frame from registers */
196     switch (DEBUG_GetSelectorType(ss))
197     {
198     case 32:
199         code.seg = cs;
200         code.off = DEBUG_context.Eip;
201         addr.seg = ss;
202         addr.off = DEBUG_context.Ebp;
203         DEBUG_ForceFrame( &addr, &code, frameno, 32, noisy, NULL );
204         if (!(code.seg || code.off)) {
205             /* trying to execute a null pointer... yuck...
206              * if it was a call to null, the return EIP should be
207              * available at SS:ESP, so let's try to retrieve it */
208             tmp.seg = ss;
209             tmp.off = DEBUG_context.Esp;
210             if (DEBUG_READ_MEM((void *)DEBUG_ToLinear(&tmp), &code.off, sizeof(code.off))) {
211                 DEBUG_ForceFrame( &addr, &code, ++frameno, 32, noisy, ", null call assumed" );
212             }
213         }
214         is16 = FALSE;
215         break;
216     case 16:
217         code.seg = cs;
218         code.off = LOWORD(DEBUG_context.Eip);
219         addr.seg = ss;
220         addr.off = LOWORD(DEBUG_context.Ebp);
221         DEBUG_ForceFrame( &addr, &code, frameno, 16, noisy, NULL );
222         is16 = TRUE;
223         break;
224     default:
225         if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad segment '%u'\n", ss);
226         return;
227     }
228
229     /* cur_switch holds address of curr_stack's field in TEB in debuggee 
230      * address space 
231      */
232     cur_switch = (DWORD)DEBUG_CurrThread->teb + OFFSET_OF(TEB, cur_stack);
233     if (!DEBUG_READ_MEM((void*)cur_switch, &next_switch, sizeof(next_switch))) {
234         if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Can't read TEB:cur_stack\n");
235         return;
236     }
237
238     if (is16) {
239         if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
240             if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
241                                      (unsigned long)(STACK32FRAME*)next_switch );
242             return;
243         }
244         cur_switch = (DWORD)frame32.frame16;
245         sw_addr.seg = SELECTOROF(cur_switch);
246         sw_addr.off = OFFSETOF(cur_switch);
247     } else {
248         tmp.seg = SELECTOROF(next_switch);
249         tmp.off = OFFSETOF(next_switch);
250         p = DEBUG_ToLinear(&tmp);
251         
252         if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
253             if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
254                                      (unsigned long)(STACK16FRAME*)p );
255             return;
256         }
257         cur_switch = (DWORD)frame16.frame32;
258         sw_addr.seg = ss;
259         sw_addr.off = cur_switch;
260     }
261     if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
262         sw_addr.seg = (DWORD)-1;
263         sw_addr.off = (DWORD)-1;
264     }
265     
266     for (ok = TRUE; ok;) {
267         if ((frames[frameno].ss == sw_addr.seg) &&
268             (frames[frameno].ebp >= sw_addr.off)) {
269            /* 16<->32 switch...
270             * yes, I know this is confusing, it gave me a headache too */
271            if (is16) {
272               
273                if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
274                   if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
275                                            (unsigned long)(STACK32FRAME*)next_switch );
276                   return;
277                }
278
279                code.seg  = 0;
280                code.off  = frame32.retaddr;
281                
282                cs = 0;
283                addr.seg = 0;
284                addr.off = frame32.ebp;
285                DEBUG_ForceFrame( &addr, &code, ++frameno, 32, noisy, NULL );
286                
287                next_switch = cur_switch;
288                tmp.seg = SELECTOROF(next_switch);
289                tmp.off = OFFSETOF(next_switch);
290                p = DEBUG_ToLinear(&tmp);
291                
292                if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
293                    if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
294                                             (unsigned long)(STACK16FRAME*)p );
295                    return;
296                }
297                cur_switch = (DWORD)frame16.frame32;
298                sw_addr.seg = 0;
299                sw_addr.off = cur_switch;
300                
301                is16 = FALSE;
302            } else {
303               tmp.seg = SELECTOROF(next_switch);
304               tmp.off = OFFSETOF(next_switch);
305               p = DEBUG_ToLinear(&tmp);
306               
307               if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
308                   if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n",
309                                            (unsigned long)(STACK16FRAME*)p );
310                   return;
311               }
312               
313               code.seg  = frame16.cs;
314               code.off  = frame16.ip;
315               
316               cs = frame16.cs;
317               addr.seg = SELECTOROF(next_switch);
318               addr.off = frame16.bp;
319               DEBUG_ForceFrame( &addr, &code, ++frameno, 16, noisy, NULL );
320               
321               next_switch = cur_switch;
322               if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
323                  if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
324                                           (unsigned long)(STACK32FRAME*)next_switch );
325                  return;
326               }
327               cur_switch = (DWORD)frame32.frame16;
328               sw_addr.seg = SELECTOROF(cur_switch);
329               sw_addr.off = OFFSETOF(cur_switch);
330               
331               is16 = TRUE;
332            }
333            if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
334               sw_addr.seg = (DWORD)-1;
335               sw_addr.off = (DWORD)-1;
336            }
337         } else {
338             /* ordinary stack frame */
339            ok = is16 ? DEBUG_Frame16( &addr, &cs, ++frameno, noisy)
340               : DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
341         }
342     }
343     if (noisy) DEBUG_Printf( DBG_CHN_MESG, "\n" );
344 #endif
345 }
346
347 int
348 DEBUG_SetFrame(int newframe)
349 {
350 #ifdef __i386__
351   int           rtn = FALSE;
352
353   curr_frame = newframe;
354
355   if( curr_frame >= nframe )
356     {
357       curr_frame = nframe - 1;
358     }
359
360   if( curr_frame < 0 )
361     {
362       curr_frame = 0;
363     }
364
365    if( frames && frames[curr_frame].frame.list.sourcefile != NULL )
366     {
367       DEBUG_List(&frames[curr_frame].frame.list, NULL, 0);
368     }
369
370   rtn = TRUE;
371   return (rtn);
372 #else /* __i386__ */
373   return FALSE;
374 #endif /* __i386__ */
375 }
376
377 int
378 DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip,
379                       unsigned int * ebp)
380 {
381 #ifdef __i386__
382   /*
383    * If we don't have a valid backtrace, then just return.
384    */
385   if( frames == NULL )
386     {
387       return FALSE;
388     }
389
390   /*
391    * If we don't know what the current function is, then we also have
392    * nothing to report here.
393    */
394   if( frames[curr_frame].frame.sym == NULL )
395     {
396       return FALSE;
397     }
398
399   *name = frames[curr_frame].frame.sym;
400   *eip = frames[curr_frame].eip;
401   *ebp = frames[curr_frame].ebp;
402
403   return TRUE;
404 #else /* __i386__ */
405   return FALSE;
406 #endif /* __i386__ */
407 }
408