Beginnings on implementations of SetupCreateDiskSpaceListA/W,
[wine] / programs / winedbg / 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  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26
27 #include "debugger.h"
28 #include "stackframe.h"
29 #include "winbase.h"
30
31 #ifdef __i386__
32 /*
33  * We keep this info for each frame, so that we can
34  * find local variable information correctly.
35  */
36 struct bt_info
37 {
38   unsigned int       cs;
39   unsigned int       eip;
40   unsigned int       ss;
41   unsigned int       ebp;
42   struct symbol_info frame;
43 };
44
45 static int nframe;
46 static struct bt_info * frames = NULL;
47
48 typedef struct
49 {
50     WORD bp;
51     WORD ip;
52     WORD cs;
53 } FRAME16;
54
55 typedef struct
56 {
57     DWORD bp;
58     DWORD ip;
59     WORD cs;
60 } FRAME32;
61 #endif
62
63
64 /***********************************************************************
65  *           DEBUG_InfoStack
66  *
67  * Dump the top of the stack
68  */
69 void DEBUG_InfoStack(void)
70 {
71 #ifdef __i386__
72     DBG_VALUE   value;
73
74     value.type = NULL;
75     value.cookie = DV_TARGET;
76     value.addr.seg = DEBUG_context.SegSs;
77     value.addr.off = DEBUG_context.Esp;
78
79     DEBUG_Printf("Stack dump:\n");
80     switch (DEBUG_GetSelectorType(value.addr.seg))
81     {
82     case MODE_32: /* 32-bit mode */
83        DEBUG_ExamineMemory( &value, 24, 'x' );
84        break;
85     case MODE_16:  /* 16-bit mode */
86     case MODE_VM86:
87         value.addr.off &= 0xffff;
88         DEBUG_ExamineMemory( &value, 24, 'w' );
89         break;
90     default:
91        DEBUG_Printf("Bad segment (%ld)\n", value.addr.seg);
92     }
93     DEBUG_Printf("\n");
94 #endif
95 }
96
97 #ifdef __i386__
98 static void DEBUG_ForceFrame(DBG_ADDR *stack, DBG_ADDR *code, int frameno, enum dbg_mode mode,
99                              int noisy, const char *caveat)
100 {
101     int theframe = nframe++;
102     frames = (struct bt_info *)DBG_realloc(frames,
103                                            nframe*sizeof(struct bt_info));
104     if (noisy)
105       DEBUG_Printf("%s%d ", (theframe == curr_frame ? "=>" : "  "),
106               frameno);
107     frames[theframe].cs = code->seg;
108     frames[theframe].eip = code->off;
109     if (noisy)
110         frames[theframe].frame = DEBUG_PrintAddressAndArgs( code, mode, stack->off, TRUE );
111     else
112       DEBUG_FindNearestSymbol( code, TRUE,
113                                &frames[theframe].frame.sym, stack->off,
114                                &frames[theframe].frame.list);
115     frames[theframe].ss = stack->seg;
116     frames[theframe].ebp = stack->off;
117     if (noisy) {
118       DEBUG_Printf((mode != MODE_32) ? " (bp=%04lx%s)\n" : " (ebp=%08lx%s)\n",
119                    stack->off, caveat ? caveat : "");
120     }
121 }
122
123 static BOOL DEBUG_Frame16(DBG_THREAD* thread, DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
124 {
125     unsigned int        possible_cs = 0;
126     FRAME16             frame;
127     void*               p = (void*)DEBUG_ToLinear(addr);
128     DBG_ADDR            code;
129
130     if (!p) return FALSE;
131
132     if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
133         if (noisy) DEBUG_InvalAddr(addr);
134         return FALSE;
135     }
136     if (!frame.bp) return FALSE;
137
138     if (frame.bp & 1) *cs = frame.cs;
139     else {
140         /* not explicitly marked as far call,
141          * but check whether it could be anyway */
142         if (((frame.cs&7)==7) && (frame.cs != *cs)) {
143             LDT_ENTRY   le;
144
145             if (GetThreadSelectorEntry( thread->handle, frame.cs, &le) &&
146                 (le.HighWord.Bits.Type & 0x08)) { /* code segment */
147                 /* it is very uncommon to push a code segment cs as
148                  * a parameter, so this should work in most cases */
149                 *cs = possible_cs = frame.cs;
150             }
151         }
152     }
153     code.seg = *cs;
154     code.off = frame.ip;
155     addr->off = frame.bp & ~1;
156     DEBUG_ForceFrame(addr, &code, frameno, MODE_16, noisy,
157                      possible_cs ? ", far call assumed" : NULL );
158     return TRUE;
159 }
160
161 static BOOL DEBUG_Frame32(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
162 {
163     FRAME32             frame;
164     void*               p = (void*)DEBUG_ToLinear(addr);
165     DBG_ADDR            code;
166     DWORD               old_bp = addr->off;
167
168     if (!p) return FALSE;
169
170     if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
171        if (noisy) DEBUG_InvalAddr(addr);
172        return FALSE;
173     }
174     if (!frame.ip) return FALSE;
175
176     code.seg = *cs;
177     code.off = frame.ip;
178     addr->off = frame.bp;
179     DEBUG_ForceFrame(addr, &code, frameno, MODE_32, noisy, NULL);
180     if (addr->off == old_bp) return FALSE;
181     return TRUE;
182 }
183 #endif
184
185
186 /***********************************************************************
187  *           DEBUG_BackTrace
188  *
189  * Display a stack back-trace.
190  */
191 void DEBUG_BackTrace(DWORD tid, BOOL noisy)
192 {
193 #ifdef __i386
194     DBG_ADDR            addr, sw_addr, code, tmp;
195     unsigned int        ss, cs;
196     int                 frameno = 0, is16, ok;
197     DWORD               next_switch, cur_switch, p;
198     STACK16FRAME        frame16;
199     STACK32FRAME        frame32;
200     char                ch;
201     CONTEXT             ctx;
202     DBG_THREAD*         thread;
203
204     int                 copy_nframe = 0;
205     int                 copy_curr_frame = 0;
206     struct bt_info*     copy_frames = NULL;
207
208     if (noisy) DEBUG_Printf("Backtrace:\n");
209
210     if (tid == DEBUG_CurrTid)
211     {
212          ctx = DEBUG_context;
213          thread = DEBUG_CurrThread;
214
215          if (frames) DBG_free( frames );
216          /* frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) ); */
217     }
218     else
219     {
220          thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
221
222          if (!thread)
223          {
224               DEBUG_Printf("Unknown thread id (0x%08lx) in current process\n", tid);
225               return;
226          }
227          memset(&ctx, 0, sizeof(ctx));
228          ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_SEGMENTS;
229
230          if ( SuspendThread( thread->handle ) == -1 ||
231               !GetThreadContext( thread->handle, &ctx ))
232          {
233               DEBUG_Printf("Can't get context for thread id (0x%08lx) in current process\n", tid);
234               return;
235          }
236          /* need to avoid trashing stack frame for current thread */
237          copy_nframe = nframe;
238          copy_frames = frames;
239          copy_curr_frame = curr_frame;
240          curr_frame = 0;
241     }
242
243     nframe = 0;
244     frames = NULL;
245
246     cs = ctx.SegCs;
247     ss = ctx.SegSs;
248
249     if (DEBUG_IsSelectorSystem(ss)) ss = 0;
250     if (DEBUG_IsSelectorSystem(cs)) cs = 0;
251
252     /* first stack frame from registers */
253     switch (DEBUG_GetSelectorType(ss))
254     {
255     case MODE_32:
256         code.seg = cs;
257         code.off = ctx.Eip;
258         addr.seg = ss;
259         addr.off = ctx.Ebp;
260         DEBUG_ForceFrame( &addr, &code, frameno, MODE_32, noisy, NULL );
261         if (!(code.seg || code.off)) {
262             /* trying to execute a null pointer... yuck...
263              * if it was a call to null, the return EIP should be
264              * available at SS:ESP, so let's try to retrieve it */
265             tmp.seg = ss;
266             tmp.off = ctx.Esp;
267             if (DEBUG_READ_MEM((void *)DEBUG_ToLinear(&tmp), &code.off, sizeof(code.off))) {
268                 DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_32, noisy, ", null call assumed" );
269             }
270         }
271         is16 = FALSE;
272         break;
273     case MODE_16:
274     case MODE_VM86:
275         code.seg = cs;
276         code.off = LOWORD(ctx.Eip);
277         addr.seg = ss;
278         addr.off = LOWORD(ctx.Ebp);
279         DEBUG_ForceFrame( &addr, &code, frameno, MODE_16, noisy, NULL );
280         is16 = TRUE;
281         break;
282     default:
283         if (noisy) DEBUG_Printf("Bad segment '%x'\n", ss);
284         return;
285     }
286
287     /* cur_switch holds address of curr_stack's field in TEB in debuggee
288      * address space
289      */
290     cur_switch = (DWORD)thread->teb + OFFSET_OF(TEB, cur_stack);
291     if (!DEBUG_READ_MEM((void*)cur_switch, &next_switch, sizeof(next_switch))) {
292         if (noisy) DEBUG_Printf("Can't read TEB:cur_stack\n");
293         return;
294     }
295
296     if (is16) {
297         if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
298             if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
299                                     (unsigned long)(STACK32FRAME*)next_switch );
300             return;
301         }
302         cur_switch = (DWORD)frame32.frame16;
303         sw_addr.seg = SELECTOROF(cur_switch);
304         sw_addr.off = OFFSETOF(cur_switch);
305     } else {
306         tmp.seg = SELECTOROF(next_switch);
307         tmp.off = OFFSETOF(next_switch);
308         p = DEBUG_ToLinear(&tmp);
309
310         if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
311             if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
312                                     (unsigned long)(STACK16FRAME*)p );
313             return;
314         }
315         cur_switch = (DWORD)frame16.frame32;
316         sw_addr.seg = ss;
317         sw_addr.off = cur_switch;
318     }
319     if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
320         sw_addr.seg = (DWORD)-1;
321         sw_addr.off = (DWORD)-1;
322     }
323
324     for (ok = TRUE; ok;) {
325         if ((frames[frameno].ss == sw_addr.seg) &&
326             sw_addr.off && (frames[frameno].ebp >= sw_addr.off))
327         {
328            /* 16<->32 switch...
329             * yes, I know this is confusing, it gave me a headache too */
330            if (is16) {
331
332                if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
333                   if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
334                                           (unsigned long)(STACK32FRAME*)next_switch );
335                   return;
336                }
337
338                code.seg  = 0;
339                code.off  = frame32.retaddr;
340
341                cs = 0;
342                addr.seg = 0;
343                addr.off = frame32.ebp;
344                DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_32, noisy, NULL );
345
346                next_switch = cur_switch;
347                tmp.seg = SELECTOROF(next_switch);
348                tmp.off = OFFSETOF(next_switch);
349                p = DEBUG_ToLinear(&tmp);
350
351                if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
352                    if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
353                                            (unsigned long)(STACK16FRAME*)p );
354                    return;
355                }
356                cur_switch = (DWORD)frame16.frame32;
357                sw_addr.seg = 0;
358                sw_addr.off = cur_switch;
359
360                is16 = FALSE;
361            } else {
362               tmp.seg = SELECTOROF(next_switch);
363               tmp.off = OFFSETOF(next_switch);
364               p = DEBUG_ToLinear(&tmp);
365
366               if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
367                   if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
368                                           (unsigned long)(STACK16FRAME*)p );
369                   return;
370               }
371
372               code.seg  = frame16.cs;
373               code.off  = frame16.ip;
374
375               cs = frame16.cs;
376               addr.seg = SELECTOROF(next_switch);
377               addr.off = frame16.bp;
378               DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_16, noisy, NULL );
379
380               next_switch = cur_switch;
381               if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
382                  if (noisy) DEBUG_Printf("Bad stack frame 0x%08lx\n",
383                                          (unsigned long)(STACK32FRAME*)next_switch );
384                  return;
385               }
386               cur_switch = (DWORD)frame32.frame16;
387               sw_addr.seg = SELECTOROF(cur_switch);
388               sw_addr.off = OFFSETOF(cur_switch);
389
390               is16 = TRUE;
391            }
392            if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
393               sw_addr.seg = (DWORD)-1;
394               sw_addr.off = (DWORD)-1;
395            }
396         } else {
397             /* ordinary stack frame */
398            ok = is16 ? DEBUG_Frame16( thread, &addr, &cs, ++frameno, noisy)
399               : DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
400         }
401     }
402     if (noisy) DEBUG_Printf("\n");
403
404     if (tid != DEBUG_CurrTid)
405     {
406          ResumeThread( thread->handle );
407          /* restore stack frame for current thread */
408          if (frames) DBG_free( frames );
409          frames = copy_frames;
410          nframe = copy_nframe;
411          curr_frame = copy_curr_frame;
412     }
413 #endif
414 }
415
416 int
417 DEBUG_SetFrame(int newframe)
418 {
419 #ifdef __i386__
420   int           rtn = FALSE;
421
422   curr_frame = newframe;
423
424   if( curr_frame >= nframe )
425     {
426       curr_frame = nframe - 1;
427     }
428
429   if( curr_frame < 0 )
430     {
431       curr_frame = 0;
432     }
433
434    if( frames && frames[curr_frame].frame.list.sourcefile != NULL )
435     {
436       DEBUG_List(&frames[curr_frame].frame.list, NULL, 0);
437     }
438
439   rtn = TRUE;
440   return (rtn);
441 #else /* __i386__ */
442   return FALSE;
443 #endif /* __i386__ */
444 }
445
446 int
447 DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip,
448                       unsigned int * ebp)
449 {
450 #ifdef __i386__
451   /*
452    * If we don't have a valid backtrace, then just return.
453    */
454   if( frames == NULL )
455     {
456       return FALSE;
457     }
458
459   /*
460    * If we don't know what the current function is, then we also have
461    * nothing to report here.
462    */
463   if( frames[curr_frame].frame.sym == NULL )
464     {
465       return FALSE;
466     }
467
468   *name = frames[curr_frame].frame.sym;
469   *eip = frames[curr_frame].eip;
470   *ebp = frames[curr_frame].ebp;
471
472   return TRUE;
473 #else /* __i386__ */
474   return FALSE;
475 #endif /* __i386__ */
476 }