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