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