Add new "walk" command options to list processes and modref's.
[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
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
47
48
49 /***********************************************************************
50  *           DEBUG_InfoStack
51  *
52  * Dump the top of the stack
53  */
54 void DEBUG_InfoStack(void)
55 {
56     DBG_ADDR addr;
57
58     addr.type = NULL;
59     addr.seg = SS_reg(&DEBUG_context);
60     addr.off = ESP_reg(&DEBUG_context);
61
62     fprintf(stderr,"Stack dump:\n");
63     if (IS_SELECTOR_32BIT(addr.seg))
64     {  /* 32-bit mode */
65         DEBUG_ExamineMemory( &addr, 24, 'x' );
66     }
67     else  /* 16-bit mode */
68     {
69         addr.off &= 0xffff;
70         DEBUG_ExamineMemory( &addr, 24, 'w' );
71     }
72     fprintf(stderr,"\n");
73 }
74
75
76 static void DEBUG_ForceFrame(DBG_ADDR *stack, DBG_ADDR *code, int frameno, int bits, int noisy)
77 {
78     int theframe = nframe++;
79     frames = (struct bt_info *)DBG_realloc(frames,
80                                         nframe*sizeof(struct bt_info));
81     if (noisy)
82       fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : "  "),
83               frameno);
84     frames[theframe].cs = code->seg;
85     frames[theframe].eip = code->off;
86     if (noisy)
87       frames[theframe].frame = DEBUG_PrintAddressAndArgs( code, bits, 
88                                                 stack->off, TRUE );
89     else
90       DEBUG_FindNearestSymbol( code, TRUE, 
91                                &frames[theframe].frame.sym, stack->off, 
92                                &frames[theframe].frame.list);
93     frames[theframe].ss = stack->seg;
94     frames[theframe].ebp = stack->off;
95     if (noisy) {
96       fprintf( stderr, (bits == 16) ? " (bp=%04lx)\n" : " (ebp=%08lx)\n", stack->off );
97     }
98 }
99
100 static BOOL DEBUG_Frame16(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
101 {
102     unsigned int ss = addr->seg, possible_cs = 0;
103     FRAME16 *frame = (FRAME16 *)DBG_ADDR_TO_LIN(addr);
104     int theframe = nframe;
105
106     if (!DBG_CHECK_READ_PTR( addr, sizeof(FRAME16) )) return FALSE;
107     if (!frame->bp) return FALSE;
108     nframe++;
109     frames = (struct bt_info *)DBG_realloc(frames,
110                                         nframe*sizeof(struct bt_info));
111     if (noisy)
112       fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : "  "),
113               frameno);
114     if (frame->bp & 1) *cs = frame->cs;
115     else {
116       /* not explicitly marked as far call,
117        * but check whether it could be anyway */
118       if (((frame->cs&7)==7) && (frame->cs != *cs) && !IS_SELECTOR_FREE(frame->cs)) {
119         ldt_entry tcs;
120         LDT_GetEntry( SELECTOR_TO_ENTRY(frame->cs), &tcs );
121         if ( tcs.type == SEGMENT_CODE ) {
122           /* it is very uncommon to push a code segment cs as
123            * a parameter, so this should work in most cases */
124           *cs = possible_cs = frame->cs;
125         }
126       }
127     }
128     frames[theframe].cs = addr->seg = *cs;
129     frames[theframe].eip = addr->off = frame->ip;
130     if (noisy)
131       frames[theframe].frame = DEBUG_PrintAddressAndArgs( addr, 16, 
132                                                 frame->bp, TRUE );
133     else
134       DEBUG_FindNearestSymbol( addr, TRUE, 
135                                &frames[theframe].frame.sym, frame->bp, 
136                                &frames[theframe].frame.list);
137     frames[theframe].ss = addr->seg = ss;
138     frames[theframe].ebp = addr->off = frame->bp & ~1;
139     if (noisy) {
140       fprintf( stderr, " (bp=%04lx", addr->off );
141       if (possible_cs) {
142         fprintf( stderr, ", far call assumed" );
143       }
144       fprintf( stderr, ")\n" );
145     }
146     return TRUE;
147 }
148
149 static BOOL DEBUG_Frame32(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
150 {
151     unsigned int ss = addr->seg;
152     FRAME32 *frame = (FRAME32 *)DBG_ADDR_TO_LIN(addr);
153     int theframe = nframe;
154
155     if (!DBG_CHECK_READ_PTR( addr, sizeof(FRAME32) )) return FALSE;
156     if (!frame->ip) return FALSE;
157     nframe++;
158     frames = (struct bt_info *)DBG_realloc(frames,
159                                         nframe*sizeof(struct bt_info));
160     if (noisy)
161       fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : "  "),
162               frameno);
163     frames[theframe].cs = addr->seg = *cs;
164     frames[theframe].eip = addr->off = frame->ip;
165     if (noisy)
166       frames[theframe].frame = DEBUG_PrintAddressAndArgs( addr, 32, 
167                                                 frame->bp, TRUE );
168     else
169       DEBUG_FindNearestSymbol( addr, TRUE, 
170                                &frames[theframe].frame.sym, frame->bp, 
171                                &frames[theframe].frame.list);
172     if (noisy) fprintf( stderr, " (ebp=%08lx)\n", frame->bp );
173     frames[theframe].ss = addr->seg = ss;
174     frames[theframe].ebp = frame->bp;
175     if (addr->off == frame->bp) return FALSE;
176     addr->off = frame->bp;
177     return TRUE;
178 }
179
180 static void DEBUG_DoBackTrace(int noisy)
181 {
182     DBG_ADDR addr, sw_addr;
183     unsigned int ss = SS_reg(&DEBUG_context), cs = CS_reg(&DEBUG_context);
184     int frameno = 0, is16, ok;
185     DWORD next_switch, cur_switch;
186
187     if (noisy) fprintf( stderr, "Backtrace:\n" );
188
189     nframe = 1;
190     if (frames) DBG_free( frames );
191     frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) );
192     if (noisy)
193       fprintf(stderr,"%s%d ",(curr_frame == 0 ? "=>" : "  "), frameno);
194
195     if (IS_SELECTOR_SYSTEM(ss)) ss = 0;
196     if (IS_SELECTOR_SYSTEM(cs)) cs = 0;
197
198     /* first stack frame from registers */
199     if (IS_SELECTOR_32BIT(ss))
200     {
201         frames[0].cs = addr.seg = cs;
202         frames[0].eip = addr.off = EIP_reg(&DEBUG_context);
203         if (noisy)
204           frames[0].frame = DEBUG_PrintAddress( &addr, 32, TRUE );
205         else
206           DEBUG_FindNearestSymbol( &addr, TRUE, &frames[0].frame.sym, 0, 
207                                                 &frames[0].frame.list);
208         frames[0].ss = addr.seg = ss;
209         frames[0].ebp = addr.off = EBP_reg(&DEBUG_context);
210         if (noisy) fprintf( stderr, " (ebp=%08x)\n", frames[0].ebp );
211         is16 = FALSE;
212     } else {
213         frames[0].cs = addr.seg = cs;
214         frames[0].eip = addr.off = IP_reg(&DEBUG_context);
215         if (noisy)
216           frames[0].frame = DEBUG_PrintAddress( &addr, 16, TRUE );
217         else
218           DEBUG_FindNearestSymbol( &addr, TRUE, &frames[0].frame.sym, 0, 
219                                                 &frames[0].frame.list);
220         frames[0].ss = addr.seg = ss;
221         frames[0].ebp = addr.off = BP_reg(&DEBUG_context);
222         if (noisy) fprintf( stderr, " (bp=%04x)\n", frames[0].ebp );
223         is16 = TRUE;
224     }
225
226     next_switch = THREAD_Current()->cur_stack;
227     if (is16) {
228       if (IsBadReadPtr((STACK32FRAME*)next_switch, sizeof(STACK32FRAME))) {
229          fprintf( stderr, "Bad stack frame %p\n", (STACK32FRAME*)next_switch );
230          return;
231       }
232       cur_switch = (DWORD)((STACK32FRAME*)next_switch)->frame16;
233       sw_addr.seg = SELECTOROF(cur_switch);
234       sw_addr.off = OFFSETOF(cur_switch);
235     } else {
236       if (IsBadReadPtr((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch), sizeof(STACK16FRAME))) {
237          fprintf( stderr, "Bad stack frame %p\n", (STACK16FRAME*)PTR_SEG_TO_LIN(next_switch) );
238          return;
239       }
240       cur_switch = (DWORD)((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch))->frame32;
241       sw_addr.seg = ss;
242       sw_addr.off = cur_switch;
243     }
244     if (DEBUG_IsBadReadPtr(&sw_addr,1)) {
245       sw_addr.seg = (DWORD)-1;
246       sw_addr.off = (DWORD)-1;
247     }
248
249     for (ok = TRUE; ok;) {
250       if ((frames[frameno].ss == sw_addr.seg) &&
251           (frames[frameno].ebp >= sw_addr.off)) {
252         /* 16<->32 switch...
253          * yes, I know this is confusing, it gave me a headache too */
254         if (is16) {
255           STACK32FRAME *frame = (STACK32FRAME*)next_switch;
256           DBG_ADDR code;
257
258           if (IsBadReadPtr((STACK32FRAME*)next_switch, sizeof(STACK32FRAME))) {
259             fprintf( stderr, "Bad stack frame %p\n", (STACK32FRAME*)next_switch );
260             return;
261           }
262           code.type = NULL;
263           code.seg  = 0;
264           code.off  = frame->retaddr;
265
266           cs = 0;
267           addr.seg = 0;
268           addr.off = frame->ebp;
269           DEBUG_ForceFrame( &addr, &code, ++frameno, 32, noisy );
270
271           next_switch = cur_switch;
272           if (IsBadReadPtr((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch), sizeof(STACK16FRAME))) {
273             fprintf( stderr, "Bad stack frame %p\n", (STACK16FRAME*)PTR_SEG_TO_LIN(next_switch) );
274             return;
275           }
276           cur_switch = (DWORD)((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch))->frame32;
277           sw_addr.seg = 0;
278           sw_addr.off = cur_switch;
279
280           is16 = FALSE;
281         } else {
282           STACK16FRAME *frame = (STACK16FRAME*)PTR_SEG_TO_LIN(next_switch);
283           DBG_ADDR code;
284
285           if (IsBadReadPtr((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch), sizeof(STACK16FRAME))) {
286             fprintf( stderr, "Bad stack frame %p\n", (STACK16FRAME*)PTR_SEG_TO_LIN(next_switch) );
287             return;
288           }
289
290           code.type = NULL;
291           code.seg  = frame->cs;
292           code.off  = frame->ip;
293
294           cs = frame->cs;
295           addr.seg = SELECTOROF(next_switch);
296           addr.off = frame->bp;
297           DEBUG_ForceFrame( &addr, &code, ++frameno, 16, noisy );
298
299           next_switch = cur_switch;
300           if (IsBadReadPtr((STACK32FRAME*)next_switch, sizeof(STACK32FRAME))) {
301             fprintf( stderr, "Bad stack frame %p\n", (STACK32FRAME*)next_switch );
302             return;
303           }
304           cur_switch = (DWORD)((STACK32FRAME*)next_switch)->frame16;
305           sw_addr.seg = SELECTOROF(cur_switch);
306           sw_addr.off = OFFSETOF(cur_switch);
307
308           is16 = TRUE;
309         }
310         if (DEBUG_IsBadReadPtr(&sw_addr,1)) {
311           sw_addr.seg = (DWORD)-1;
312           sw_addr.off = (DWORD)-1;
313         }
314       } else {
315         /* ordinary stack frame */
316         ok = is16 ? DEBUG_Frame16( &addr, &cs, ++frameno, noisy)
317                   : DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
318       }
319     }
320     if (noisy) fprintf( stderr, "\n" );
321 }
322
323 /***********************************************************************
324  *           DEBUG_BackTrace
325  *
326  * Display a stack back-trace.
327  */
328 void DEBUG_BackTrace(void)
329 {
330     DEBUG_DoBackTrace( TRUE );
331 }
332
333 /***********************************************************************
334  *           DEBUG_SilentBackTrace
335  *
336  * Display a stack back-trace.
337  */
338 void DEBUG_SilentBackTrace(void)
339 {
340     DEBUG_DoBackTrace( FALSE );
341 }
342
343 int
344 DEBUG_SetFrame(int newframe)
345 {
346   int           rtn = FALSE;
347
348   curr_frame = newframe;
349
350   if( curr_frame >= nframe )
351     {
352       curr_frame = nframe - 1;
353     }
354
355   if( curr_frame < 0 )
356     {
357       curr_frame = 0;
358     }
359
360    if( frames && frames[curr_frame].frame.list.sourcefile != NULL )
361     {
362       DEBUG_List(&frames[curr_frame].frame.list, NULL, 0);
363     }
364
365   rtn = TRUE;
366   return (rtn);
367 }
368
369 int
370 DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip,
371                       unsigned int * ebp)
372 {
373   /*
374    * If we don't have a valid backtrace, then just return.
375    */
376   if( frames == NULL )
377     {
378       return FALSE;
379     }
380
381   /*
382    * If we don't know what the current function is, then we also have
383    * nothing to report here.
384    */
385   if( frames[curr_frame].frame.sym == NULL )
386     {
387       return FALSE;
388     }
389
390   *name = frames[curr_frame].frame.sym;
391   *eip = frames[curr_frame].eip;
392   *ebp = frames[curr_frame].ebp;
393
394   return TRUE;
395 }
396