No longer directly accessing debuggee memory.
[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 #include <stdio.h>
11 #include <stdlib.h>
12 #include "debugger.h"
13 #include "stackframe.h"
14
15 #ifdef __i386__
16 /*
17  * We keep this info for each frame, so that we can
18  * find local variable information correctly.
19  */
20 struct bt_info
21 {
22   unsigned int       cs;
23   unsigned int       eip;
24   unsigned int       ss;
25   unsigned int       ebp;
26   struct symbol_info frame;
27 };
28
29 static int nframe;
30 static struct bt_info * frames = NULL;
31 int curr_frame;
32
33 typedef struct
34 {
35     WORD bp;
36     WORD ip;
37     WORD cs;
38 } FRAME16;
39
40 typedef struct
41 {
42     DWORD bp;
43     DWORD ip;
44     WORD cs;
45 } FRAME32;
46 #endif
47
48
49 /***********************************************************************
50  *           DEBUG_InfoStack
51  *
52  * Dump the top of the stack
53  */
54 void DEBUG_InfoStack(void)
55 {
56 #ifdef __i386__
57     DBG_ADDR addr;
58
59     addr.type = NULL;
60     addr.seg = DEBUG_context.SegSs;
61     addr.off = DEBUG_context.Esp;
62
63     fprintf(stderr,"Stack dump:\n");
64     switch (DEBUG_GetSelectorType(addr.seg)) {
65     case 32: /* 32-bit mode */
66        DEBUG_ExamineMemory( &addr, 24, 'x' );
67        break;
68     case 16:  /* 16-bit mode */
69         addr.off &= 0xffff;
70         DEBUG_ExamineMemory( &addr, 24, 'w' );
71         break;
72     default:
73        fprintf(stderr, "Bad segment (%ld)\n", addr.seg);
74     }
75     fprintf(stderr,"\n");
76 #endif
77 }
78
79 #ifdef __i386__
80 static void DEBUG_ForceFrame(DBG_ADDR *stack, DBG_ADDR *code, int frameno, int bits, int noisy)
81 {
82     int theframe = nframe++;
83     frames = (struct bt_info *)DBG_realloc(frames,
84                                            nframe*sizeof(struct bt_info));
85     if (noisy)
86       fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : "  "),
87               frameno);
88     frames[theframe].cs = code->seg;
89     frames[theframe].eip = code->off;
90     if (noisy)
91       frames[theframe].frame = DEBUG_PrintAddressAndArgs( code, bits, 
92                                                           stack->off, TRUE );
93     else
94       DEBUG_FindNearestSymbol( code, TRUE, 
95                                &frames[theframe].frame.sym, stack->off, 
96                                &frames[theframe].frame.list);
97     frames[theframe].ss = stack->seg;
98     frames[theframe].ebp = stack->off;
99     if (noisy) {
100       fprintf( stderr, (bits == 16) ? " (bp=%04lx)\n" : " (ebp=%08lx)\n", stack->off );
101     }
102 }
103
104 static BOOL DEBUG_Frame16(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
105 {
106     unsigned int        ss = addr->seg, possible_cs = 0;
107     FRAME16             frame;
108     int                 theframe = nframe;
109     void*               p = (void*)DEBUG_ToLinear(addr);
110     
111     if (!p) return FALSE;
112     
113     if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
114         if (noisy) {
115             fprintf(stderr,"*** Invalid address ");
116             DEBUG_PrintAddress(addr, DEBUG_CurrThread->dbg_mode, FALSE);
117             fprintf(stderr,"\n");
118         }
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         fprintf(stderr,"%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         fprintf( stderr, " (bp=%04lx", addr->off );
156         if (possible_cs) {
157             fprintf( stderr, ", far call assumed" );
158         }
159         fprintf( stderr, ")\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) {
175           fprintf(stderr,"*** Invalid address ");
176           DEBUG_PrintAddress(addr, DEBUG_CurrThread->dbg_mode, FALSE);
177           fprintf(stderr,"\n");
178        }
179        return FALSE;
180     }
181     if (!frame.ip) return FALSE;
182     
183     nframe++;
184     frames = (struct bt_info *)DBG_realloc(frames,
185                                            nframe*sizeof(struct bt_info));
186     if (noisy)
187        fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : "  "),
188                frameno);
189     frames[theframe].cs = addr->seg = *cs;
190     frames[theframe].eip = addr->off = frame.ip;
191     if (noisy)
192         frames[theframe].frame = DEBUG_PrintAddressAndArgs( addr, 32, 
193                                                             frame.bp, TRUE );
194     else
195         DEBUG_FindNearestSymbol( addr, TRUE, 
196                                  &frames[theframe].frame.sym, frame.bp, 
197                                  &frames[theframe].frame.list);
198     if (noisy) fprintf( stderr, " (ebp=%08lx)\n", frame.bp );
199     frames[theframe].ss = addr->seg = ss;
200     frames[theframe].ebp = frame.bp;
201     if (addr->off == frame.bp) return FALSE;
202     addr->off = frame.bp;
203     return TRUE;
204 }
205 #endif
206
207
208 /***********************************************************************
209  *           DEBUG_BackTrace
210  *
211  * Display a stack back-trace.
212  */
213 void DEBUG_BackTrace(BOOL noisy)
214 {
215 #ifdef __i386
216     DBG_ADDR            addr, sw_addr, code, tmp;
217     unsigned int        ss = DEBUG_context.SegSs;
218     unsigned int        cs = DEBUG_context.SegCs;
219     int                 frameno = 0, is16, ok;
220     DWORD               next_switch, cur_switch, p;
221     STACK16FRAME        frame16;
222     STACK32FRAME        frame32;
223     char                ch;
224
225     if (noisy) fprintf( stderr, "Backtrace:\n" );
226
227     nframe = 1;
228     if (frames) DBG_free( frames );
229     frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) );
230     if (noisy)
231         fprintf(stderr,"%s%d ",(curr_frame == 0 ? "=>" : "  "), frameno);
232
233     if (DEBUG_IsSelectorSystem(ss)) ss = 0;
234     if (DEBUG_IsSelectorSystem(cs)) cs = 0;
235
236     /* first stack frame from registers */
237     switch (DEBUG_GetSelectorType(ss))
238     {
239     case 32:
240         frames[0].cs = addr.seg = cs;
241         frames[0].eip = addr.off = DEBUG_context.Eip;
242         if (noisy)
243             frames[0].frame = DEBUG_PrintAddress( &addr, 32, TRUE );
244         else
245             DEBUG_FindNearestSymbol( &addr, TRUE, &frames[0].frame.sym, 0, 
246                                      &frames[0].frame.list);
247         frames[0].ss = addr.seg = ss;
248         frames[0].ebp = addr.off = DEBUG_context.Ebp;
249         if (noisy) fprintf( stderr, " (ebp=%08x)\n", frames[0].ebp );
250         is16 = FALSE;
251         break;
252     case 16:
253         frames[0].cs = addr.seg = cs;
254         frames[0].eip = addr.off = LOWORD(DEBUG_context.Eip);
255         if (noisy)
256             frames[0].frame = DEBUG_PrintAddress( &addr, 16, TRUE );
257         else
258             DEBUG_FindNearestSymbol( &addr, TRUE, &frames[0].frame.sym, 0, 
259                                      &frames[0].frame.list);
260         frames[0].ss = addr.seg = ss;
261         frames[0].ebp = addr.off = LOWORD(DEBUG_context.Ebp);
262         if (noisy) fprintf( stderr, " (bp=%04x)\n", frames[0].ebp );
263         is16 = TRUE;
264         break;
265     default:
266         if (noisy) fprintf( stderr, "Bad segment '%u'\n", ss);
267         return;
268     }
269
270     /* cur_switch holds address of curr_stack's field in TEB in debuggee 
271      * address space 
272      */
273     cur_switch = (DWORD)DEBUG_CurrThread->teb + OFFSET_OF(TEB, cur_stack);
274     if (!DEBUG_READ_MEM((void*)cur_switch, &next_switch, sizeof(next_switch))) {
275         if (noisy) fprintf( stderr, "Can't read TEB:cur_stack\n");
276         return;
277     }
278
279     if (is16) {
280         if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
281             if (noisy) fprintf( stderr, "Bad stack frame %p\n", 
282                                 (STACK32FRAME*)next_switch );
283             return;
284         }
285         cur_switch = (DWORD)frame32.frame16;
286         sw_addr.seg = SELECTOROF(cur_switch);
287         sw_addr.off = OFFSETOF(cur_switch);
288     } else {
289         tmp.seg = SELECTOROF(next_switch);
290         tmp.off = OFFSETOF(next_switch);
291         p = DEBUG_ToLinear(&tmp);
292         
293         if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
294             if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK16FRAME*)p );
295             return;
296         }
297         cur_switch = (DWORD)frame16.frame32;
298         sw_addr.seg = ss;
299         sw_addr.off = cur_switch;
300     }
301     if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
302         sw_addr.seg = (DWORD)-1;
303         sw_addr.off = (DWORD)-1;
304     }
305     
306     for (ok = TRUE; ok;) {
307         if ((frames[frameno].ss == sw_addr.seg) &&
308             (frames[frameno].ebp >= sw_addr.off)) {
309            /* 16<->32 switch...
310             * yes, I know this is confusing, it gave me a headache too */
311            if (is16) {
312               
313                if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
314                   if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK32FRAME*)next_switch );
315                   return;
316                }
317                code.type = NULL;
318                code.seg  = 0;
319                code.off  = frame32.retaddr;
320                
321                cs = 0;
322                addr.seg = 0;
323                addr.off = frame32.ebp;
324                DEBUG_ForceFrame( &addr, &code, ++frameno, 32, noisy );
325                
326                next_switch = cur_switch;
327                tmp.seg = SELECTOROF(next_switch);
328                tmp.off = OFFSETOF(next_switch);
329                p = DEBUG_ToLinear(&tmp);
330                
331                if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
332                    if (noisy) fprintf( stderr, "Bad stack frame %p\n", 
333                                        (STACK16FRAME*)p );
334                    return;
335                }
336                cur_switch = (DWORD)frame16.frame32;
337                sw_addr.seg = 0;
338                sw_addr.off = cur_switch;
339                
340                is16 = FALSE;
341            } else {
342               tmp.seg = SELECTOROF(next_switch);
343               tmp.off = OFFSETOF(next_switch);
344               p = DEBUG_ToLinear(&tmp);
345               
346               if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
347                   if (noisy) fprintf( stderr, "Bad stack frame %p\n",
348                                       (STACK16FRAME*)p );
349                   return;
350               }
351               
352               code.type = NULL;
353               code.seg  = frame16.cs;
354               code.off  = frame16.ip;
355               
356               cs = frame16.cs;
357               addr.seg = SELECTOROF(next_switch);
358               addr.off = frame16.bp;
359               DEBUG_ForceFrame( &addr, &code, ++frameno, 16, noisy );
360               
361               next_switch = cur_switch;
362               if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
363                  if (noisy) fprintf( stderr, "Bad stack frame %p\n", 
364                                      (STACK32FRAME*)next_switch );
365                  return;
366               }
367               cur_switch = (DWORD)frame32.frame16;
368               sw_addr.seg = SELECTOROF(cur_switch);
369               sw_addr.off = OFFSETOF(cur_switch);
370               
371               is16 = TRUE;
372            }
373            if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
374               sw_addr.seg = (DWORD)-1;
375               sw_addr.off = (DWORD)-1;
376            }
377         } else {
378             /* ordinary stack frame */
379            ok = is16 ? DEBUG_Frame16( &addr, &cs, ++frameno, noisy)
380               : DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
381         }
382     }
383     if (noisy) fprintf( stderr, "\n" );
384 #endif
385 }
386
387 int
388 DEBUG_SetFrame(int newframe)
389 {
390   int           rtn = FALSE;
391
392   curr_frame = newframe;
393
394   if( curr_frame >= nframe )
395     {
396       curr_frame = nframe - 1;
397     }
398
399   if( curr_frame < 0 )
400     {
401       curr_frame = 0;
402     }
403
404    if( frames && frames[curr_frame].frame.list.sourcefile != NULL )
405     {
406       DEBUG_List(&frames[curr_frame].frame.list, NULL, 0);
407     }
408
409   rtn = TRUE;
410   return (rtn);
411 }
412
413 int
414 DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip,
415                       unsigned int * ebp)
416 {
417   /*
418    * If we don't have a valid backtrace, then just return.
419    */
420   if( frames == NULL )
421     {
422       return FALSE;
423     }
424
425   /*
426    * If we don't know what the current function is, then we also have
427    * nothing to report here.
428    */
429   if( frames[curr_frame].frame.sym == NULL )
430     {
431       return FALSE;
432     }
433
434   *name = frames[curr_frame].frame.sym;
435   *eip = frames[curr_frame].eip;
436   *ebp = frames[curr_frame].ebp;
437
438   return TRUE;
439 }
440