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