Revisited console support (got rid of old hacks and private editline
[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_THREAD* thread, 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( thread->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(DWORD tid, BOOL noisy)
178 {
179 #ifdef __i386
180     DBG_ADDR            addr, sw_addr, code, tmp;
181     unsigned int        ss, cs;
182     int                 frameno = 0, is16, ok;
183     DWORD               next_switch, cur_switch, p;
184     STACK16FRAME        frame16;
185     STACK32FRAME        frame32;
186     char                ch;
187     CONTEXT             ctx;
188     DBG_THREAD*         thread;
189
190     int                 copy_nframe = 0;
191     int                 copy_curr_frame = 0;
192     struct bt_info*     copy_frames = NULL;
193     
194     if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Backtrace:\n" );
195
196     if (tid == DEBUG_CurrTid)
197     {
198          ctx = DEBUG_context;
199          thread = DEBUG_CurrThread;
200
201          if (frames) DBG_free( frames );
202          /* frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) ); */
203     }
204     else
205     {
206          thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
207
208          if (!thread)
209          {
210               DEBUG_Printf( DBG_CHN_MESG, "Unknown thread id (0x%08lx) in current process\n", tid);
211               return;
212          }
213          memset(&ctx, 0, sizeof(ctx));
214          ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_SEGMENTS;
215
216          if ( SuspendThread( thread->handle ) == -1 ||
217               !GetThreadContext( thread->handle, &ctx ))
218          {
219               DEBUG_Printf( DBG_CHN_MESG, "Can't get context for thread id (0x%08lx) in current process\n", tid);
220               return;
221          }
222          /* need to avoid trashing stack frame for current thread */
223          copy_nframe = nframe;
224          copy_frames = frames;
225          copy_curr_frame = curr_frame;
226          curr_frame = 0;
227     }
228
229     nframe = 0;
230     frames = NULL;
231
232     cs = ctx.SegCs;
233     ss = ctx.SegSs;
234
235     if (DEBUG_IsSelectorSystem(ss)) ss = 0;
236     if (DEBUG_IsSelectorSystem(cs)) cs = 0;
237
238     /* first stack frame from registers */
239     switch (DEBUG_GetSelectorType(ss))
240     {
241     case MODE_32:
242         code.seg = cs;
243         code.off = ctx.Eip;
244         addr.seg = ss;
245         addr.off = ctx.Ebp;
246         DEBUG_ForceFrame( &addr, &code, frameno, MODE_32, noisy, NULL );
247         if (!(code.seg || code.off)) {
248             /* trying to execute a null pointer... yuck...
249              * if it was a call to null, the return EIP should be
250              * available at SS:ESP, so let's try to retrieve it */
251             tmp.seg = ss;
252             tmp.off = ctx.Esp;
253             if (DEBUG_READ_MEM((void *)DEBUG_ToLinear(&tmp), &code.off, sizeof(code.off))) {
254                 DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_32, noisy, ", null call assumed" );
255             }
256         }
257         is16 = FALSE;
258         break;
259     case MODE_16:
260     case MODE_VM86:
261         code.seg = cs;
262         code.off = LOWORD(ctx.Eip);
263         addr.seg = ss;
264         addr.off = LOWORD(ctx.Ebp);
265         DEBUG_ForceFrame( &addr, &code, frameno, MODE_16, noisy, NULL );
266         is16 = TRUE;
267         break;
268     default:
269         if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad segment '%x'\n", ss);
270         return;
271     }
272
273     /* cur_switch holds address of curr_stack's field in TEB in debuggee 
274      * address space 
275      */
276     cur_switch = (DWORD)thread->teb + OFFSET_OF(TEB, cur_stack);
277     if (!DEBUG_READ_MEM((void*)cur_switch, &next_switch, sizeof(next_switch))) {
278         if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Can't read TEB:cur_stack\n");
279         return;
280     }
281
282     if (is16) {
283         if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
284             if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
285                                      (unsigned long)(STACK32FRAME*)next_switch );
286             return;
287         }
288         cur_switch = (DWORD)frame32.frame16;
289         sw_addr.seg = SELECTOROF(cur_switch);
290         sw_addr.off = OFFSETOF(cur_switch);
291     } else {
292         tmp.seg = SELECTOROF(next_switch);
293         tmp.off = OFFSETOF(next_switch);
294         p = DEBUG_ToLinear(&tmp);
295         
296         if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
297             if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
298                                      (unsigned long)(STACK16FRAME*)p );
299             return;
300         }
301         cur_switch = (DWORD)frame16.frame32;
302         sw_addr.seg = ss;
303         sw_addr.off = cur_switch;
304     }
305     if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
306         sw_addr.seg = (DWORD)-1;
307         sw_addr.off = (DWORD)-1;
308     }
309     
310     for (ok = TRUE; ok;) {
311         if ((frames[frameno].ss == sw_addr.seg) &&
312             sw_addr.off && (frames[frameno].ebp >= sw_addr.off))
313         {
314            /* 16<->32 switch...
315             * yes, I know this is confusing, it gave me a headache too */
316            if (is16) {
317               
318                if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
319                   if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
320                                            (unsigned long)(STACK32FRAME*)next_switch );
321                   return;
322                }
323
324                code.seg  = 0;
325                code.off  = frame32.retaddr;
326                
327                cs = 0;
328                addr.seg = 0;
329                addr.off = frame32.ebp;
330                DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_32, noisy, NULL );
331                
332                next_switch = cur_switch;
333                tmp.seg = SELECTOROF(next_switch);
334                tmp.off = OFFSETOF(next_switch);
335                p = DEBUG_ToLinear(&tmp);
336                
337                if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
338                    if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
339                                             (unsigned long)(STACK16FRAME*)p );
340                    return;
341                }
342                cur_switch = (DWORD)frame16.frame32;
343                sw_addr.seg = 0;
344                sw_addr.off = cur_switch;
345                
346                is16 = FALSE;
347            } else {
348               tmp.seg = SELECTOROF(next_switch);
349               tmp.off = OFFSETOF(next_switch);
350               p = DEBUG_ToLinear(&tmp);
351               
352               if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
353                   if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n",
354                                            (unsigned long)(STACK16FRAME*)p );
355                   return;
356               }
357               
358               code.seg  = frame16.cs;
359               code.off  = frame16.ip;
360               
361               cs = frame16.cs;
362               addr.seg = SELECTOROF(next_switch);
363               addr.off = frame16.bp;
364               DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_16, noisy, NULL );
365               
366               next_switch = cur_switch;
367               if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
368                  if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n", 
369                                           (unsigned long)(STACK32FRAME*)next_switch );
370                  return;
371               }
372               cur_switch = (DWORD)frame32.frame16;
373               sw_addr.seg = SELECTOROF(cur_switch);
374               sw_addr.off = OFFSETOF(cur_switch);
375               
376               is16 = TRUE;
377            }
378            if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
379               sw_addr.seg = (DWORD)-1;
380               sw_addr.off = (DWORD)-1;
381            }
382         } else {
383             /* ordinary stack frame */
384            ok = is16 ? DEBUG_Frame16( thread, &addr, &cs, ++frameno, noisy)
385               : DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
386         }
387     }
388     if (noisy) DEBUG_Printf( DBG_CHN_MESG, "\n" );
389
390     if (tid != DEBUG_CurrTid)
391     {
392          ResumeThread( thread->handle );
393          /* restore stack frame for current thread */
394          if (frames) DBG_free( frames );
395          frames = copy_frames;
396          nframe = copy_nframe;
397          curr_frame = copy_curr_frame;
398     }
399 #endif
400 }
401
402 int
403 DEBUG_SetFrame(int newframe)
404 {
405 #ifdef __i386__
406   int           rtn = FALSE;
407
408   curr_frame = newframe;
409
410   if( curr_frame >= nframe )
411     {
412       curr_frame = nframe - 1;
413     }
414
415   if( curr_frame < 0 )
416     {
417       curr_frame = 0;
418     }
419
420    if( frames && frames[curr_frame].frame.list.sourcefile != NULL )
421     {
422       DEBUG_List(&frames[curr_frame].frame.list, NULL, 0);
423     }
424
425   rtn = TRUE;
426   return (rtn);
427 #else /* __i386__ */
428   return FALSE;
429 #endif /* __i386__ */
430 }
431
432 int
433 DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip,
434                       unsigned int * ebp)
435 {
436 #ifdef __i386__
437   /*
438    * If we don't have a valid backtrace, then just return.
439    */
440   if( frames == NULL )
441     {
442       return FALSE;
443     }
444
445   /*
446    * If we don't know what the current function is, then we also have
447    * nothing to report here.
448    */
449   if( frames[curr_frame].frame.sym == NULL )
450     {
451       return FALSE;
452     }
453
454   *name = frames[curr_frame].frame.sym;
455   *eip = frames[curr_frame].eip;
456   *ebp = frames[curr_frame].ebp;
457
458   return TRUE;
459 #else /* __i386__ */
460   return FALSE;
461 #endif /* __i386__ */
462 }
463