Work around problems on Solaris if config.h is not included.
[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             sw_addr.off && (frames[frameno].ebp >= sw_addr.off))
274         {
275            /* 16<->32 switch...
276             * yes, I know this is confusing, it gave me a headache too */
277            if (is16) {
278               
279                if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
280                   if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
281                                            (unsigned long)(STACK32FRAME*)next_switch );
282                   return;
283                }
284
285                code.seg  = 0;
286                code.off  = frame32.retaddr;
287                
288                cs = 0;
289                addr.seg = 0;
290                addr.off = frame32.ebp;
291                DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_32, noisy, NULL );
292                
293                next_switch = cur_switch;
294                tmp.seg = SELECTOROF(next_switch);
295                tmp.off = OFFSETOF(next_switch);
296                p = DEBUG_ToLinear(&tmp);
297                
298                if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
299                    if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
300                                             (unsigned long)(STACK16FRAME*)p );
301                    return;
302                }
303                cur_switch = (DWORD)frame16.frame32;
304                sw_addr.seg = 0;
305                sw_addr.off = cur_switch;
306                
307                is16 = FALSE;
308            } else {
309               tmp.seg = SELECTOROF(next_switch);
310               tmp.off = OFFSETOF(next_switch);
311               p = DEBUG_ToLinear(&tmp);
312               
313               if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
314                   if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n",
315                                            (unsigned long)(STACK16FRAME*)p );
316                   return;
317               }
318               
319               code.seg  = frame16.cs;
320               code.off  = frame16.ip;
321               
322               cs = frame16.cs;
323               addr.seg = SELECTOROF(next_switch);
324               addr.off = frame16.bp;
325               DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_16, noisy, NULL );
326               
327               next_switch = cur_switch;
328               if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
329                  if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
330                                           (unsigned long)(STACK32FRAME*)next_switch );
331                  return;
332               }
333               cur_switch = (DWORD)frame32.frame16;
334               sw_addr.seg = SELECTOROF(cur_switch);
335               sw_addr.off = OFFSETOF(cur_switch);
336               
337               is16 = TRUE;
338            }
339            if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
340               sw_addr.seg = (DWORD)-1;
341               sw_addr.off = (DWORD)-1;
342            }
343         } else {
344             /* ordinary stack frame */
345            ok = is16 ? DEBUG_Frame16( &addr, &cs, ++frameno, noisy)
346               : DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
347         }
348     }
349     if (noisy) DEBUG_Printf( DBG_CHN_MESG, "\n" );
350 #endif
351 }
352
353 int
354 DEBUG_SetFrame(int newframe)
355 {
356 #ifdef __i386__
357   int           rtn = FALSE;
358
359   curr_frame = newframe;
360
361   if( curr_frame >= nframe )
362     {
363       curr_frame = nframe - 1;
364     }
365
366   if( curr_frame < 0 )
367     {
368       curr_frame = 0;
369     }
370
371    if( frames && frames[curr_frame].frame.list.sourcefile != NULL )
372     {
373       DEBUG_List(&frames[curr_frame].frame.list, NULL, 0);
374     }
375
376   rtn = TRUE;
377   return (rtn);
378 #else /* __i386__ */
379   return FALSE;
380 #endif /* __i386__ */
381 }
382
383 int
384 DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip,
385                       unsigned int * ebp)
386 {
387 #ifdef __i386__
388   /*
389    * If we don't have a valid backtrace, then just return.
390    */
391   if( frames == NULL )
392     {
393       return FALSE;
394     }
395
396   /*
397    * If we don't know what the current function is, then we also have
398    * nothing to report here.
399    */
400   if( frames[curr_frame].frame.sym == NULL )
401     {
402       return FALSE;
403     }
404
405   *name = frames[curr_frame].frame.sym;
406   *eip = frames[curr_frame].eip;
407   *ebp = frames[curr_frame].ebp;
408
409   return TRUE;
410 #else /* __i386__ */
411   return FALSE;
412 #endif /* __i386__ */
413 }
414