Make LockWindowUpdate return more Windows-like values.
[wine/multimedia.git] / debugger / stack.c
blob36333f761ce265e629f1e67fba516d7f10cd5501
1 /*
2 * Debugger stack handling
4 * Copyright 1995 Alexandre Julliard
5 * Copyright 1996 Eric Youngdale
6 * Copyright 1999 Ove Kåven
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.
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.
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
23 #include "config.h"
25 #include <stdlib.h>
27 #include "debugger.h"
28 #include "stackframe.h"
29 #include "winbase.h"
31 #ifdef __i386__
33 * We keep this info for each frame, so that we can
34 * find local variable information correctly.
36 struct bt_info
38 unsigned int cs;
39 unsigned int eip;
40 unsigned int ss;
41 unsigned int ebp;
42 struct symbol_info frame;
45 static int nframe;
46 static struct bt_info * frames = NULL;
48 typedef struct
50 WORD bp;
51 WORD ip;
52 WORD cs;
53 } FRAME16;
55 typedef struct
57 DWORD bp;
58 DWORD ip;
59 WORD cs;
60 } FRAME32;
61 #endif
64 /***********************************************************************
65 * DEBUG_InfoStack
67 * Dump the top of the stack
69 void DEBUG_InfoStack(void)
71 #ifdef __i386__
72 DBG_VALUE value;
74 value.type = NULL;
75 value.cookie = DV_TARGET;
76 value.addr.seg = DEBUG_context.SegSs;
77 value.addr.off = DEBUG_context.Esp;
79 DEBUG_Printf(DBG_CHN_MESG,"Stack dump:\n");
80 switch (DEBUG_GetSelectorType(value.addr.seg))
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(DBG_CHN_MESG, "Bad segment (%ld)\n", value.addr.seg);
93 DEBUG_Printf(DBG_CHN_MESG,"\n");
94 #endif
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)
101 int theframe = nframe++;
102 frames = (struct bt_info *)DBG_realloc(frames,
103 nframe*sizeof(struct bt_info));
104 if (noisy)
105 DEBUG_Printf(DBG_CHN_MESG,"%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( DBG_CHN_MESG, (mode != MODE_32) ? " (bp=%04lx%s)\n" : " (ebp=%08lx%s)\n",
119 stack->off, caveat?caveat:"" );
123 static BOOL DEBUG_Frame16(DBG_THREAD* thread, DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
125 unsigned int possible_cs = 0;
126 FRAME16 frame;
127 void* p = (void*)DEBUG_ToLinear(addr);
128 DBG_ADDR code;
130 if (!p) return FALSE;
132 if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
133 if (noisy) DEBUG_InvalAddr(addr);
134 return FALSE;
136 if (!frame.bp) return FALSE;
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;
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;
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;
161 static BOOL DEBUG_Frame32(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
163 FRAME32 frame;
164 void* p = (void*)DEBUG_ToLinear(addr);
165 DBG_ADDR code;
166 DWORD old_bp = addr->off;
168 if (!p) return FALSE;
170 if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
171 if (noisy) DEBUG_InvalAddr(addr);
172 return FALSE;
174 if (!frame.ip) return FALSE;
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;
183 #endif
186 /***********************************************************************
187 * DEBUG_BackTrace
189 * Display a stack back-trace.
191 void DEBUG_BackTrace(DWORD tid, BOOL noisy)
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;
204 int copy_nframe = 0;
205 int copy_curr_frame = 0;
206 struct bt_info* copy_frames = NULL;
208 if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Backtrace:\n" );
210 if (tid == DEBUG_CurrTid)
212 ctx = DEBUG_context;
213 thread = DEBUG_CurrThread;
215 if (frames) DBG_free( frames );
216 /* frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) ); */
218 else
220 thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
222 if (!thread)
224 DEBUG_Printf( DBG_CHN_MESG, "Unknown thread id (0x%08lx) in current process\n", tid);
225 return;
227 memset(&ctx, 0, sizeof(ctx));
228 ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_SEGMENTS;
230 if ( SuspendThread( thread->handle ) == -1 ||
231 !GetThreadContext( thread->handle, &ctx ))
233 DEBUG_Printf( DBG_CHN_MESG, "Can't get context for thread id (0x%08lx) in current process\n", tid);
234 return;
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;
243 nframe = 0;
244 frames = NULL;
246 cs = ctx.SegCs;
247 ss = ctx.SegSs;
249 if (DEBUG_IsSelectorSystem(ss)) ss = 0;
250 if (DEBUG_IsSelectorSystem(cs)) cs = 0;
252 /* first stack frame from registers */
253 switch (DEBUG_GetSelectorType(ss))
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" );
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( DBG_CHN_MESG, "Bad segment '%x'\n", ss);
284 return;
287 /* cur_switch holds address of curr_stack's field in TEB in debuggee
288 * address space
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( DBG_CHN_MESG, "Can't read TEB:cur_stack\n");
293 return;
296 if (is16) {
297 if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
298 if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n",
299 (unsigned long)(STACK32FRAME*)next_switch );
300 return;
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);
310 if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
311 if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n",
312 (unsigned long)(STACK16FRAME*)p );
313 return;
315 cur_switch = (DWORD)frame16.frame32;
316 sw_addr.seg = ss;
317 sw_addr.off = cur_switch;
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;
324 for (ok = TRUE; ok;) {
325 if ((frames[frameno].ss == sw_addr.seg) &&
326 sw_addr.off && (frames[frameno].ebp >= sw_addr.off))
328 /* 16<->32 switch...
329 * yes, I know this is confusing, it gave me a headache too */
330 if (is16) {
332 if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
333 if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n",
334 (unsigned long)(STACK32FRAME*)next_switch );
335 return;
338 code.seg = 0;
339 code.off = frame32.retaddr;
341 cs = 0;
342 addr.seg = 0;
343 addr.off = frame32.ebp;
344 DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_32, noisy, NULL );
346 next_switch = cur_switch;
347 tmp.seg = SELECTOROF(next_switch);
348 tmp.off = OFFSETOF(next_switch);
349 p = DEBUG_ToLinear(&tmp);
351 if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
352 if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n",
353 (unsigned long)(STACK16FRAME*)p );
354 return;
356 cur_switch = (DWORD)frame16.frame32;
357 sw_addr.seg = 0;
358 sw_addr.off = cur_switch;
360 is16 = FALSE;
361 } else {
362 tmp.seg = SELECTOROF(next_switch);
363 tmp.off = OFFSETOF(next_switch);
364 p = DEBUG_ToLinear(&tmp);
366 if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
367 if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n",
368 (unsigned long)(STACK16FRAME*)p );
369 return;
372 code.seg = frame16.cs;
373 code.off = frame16.ip;
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 );
380 next_switch = cur_switch;
381 if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
382 if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Bad stack frame 0x%08lx\n",
383 (unsigned long)(STACK32FRAME*)next_switch );
384 return;
386 cur_switch = (DWORD)frame32.frame16;
387 sw_addr.seg = SELECTOROF(cur_switch);
388 sw_addr.off = OFFSETOF(cur_switch);
390 is16 = TRUE;
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;
396 } else {
397 /* ordinary stack frame */
398 ok = is16 ? DEBUG_Frame16( thread, &addr, &cs, ++frameno, noisy)
399 : DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
402 if (noisy) DEBUG_Printf( DBG_CHN_MESG, "\n" );
404 if (tid != DEBUG_CurrTid)
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;
413 #endif
417 DEBUG_SetFrame(int newframe)
419 #ifdef __i386__
420 int rtn = FALSE;
422 curr_frame = newframe;
424 if( curr_frame >= nframe )
426 curr_frame = nframe - 1;
429 if( curr_frame < 0 )
431 curr_frame = 0;
434 if( frames && frames[curr_frame].frame.list.sourcefile != NULL )
436 DEBUG_List(&frames[curr_frame].frame.list, NULL, 0);
439 rtn = TRUE;
440 return (rtn);
441 #else /* __i386__ */
442 return FALSE;
443 #endif /* __i386__ */
447 DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip,
448 unsigned int * ebp)
450 #ifdef __i386__
452 * If we don't have a valid backtrace, then just return.
454 if( frames == NULL )
456 return FALSE;
460 * If we don't know what the current function is, then we also have
461 * nothing to report here.
463 if( frames[curr_frame].frame.sym == NULL )
465 return FALSE;
468 *name = frames[curr_frame].frame.sym;
469 *eip = frames[curr_frame].eip;
470 *ebp = frames[curr_frame].ebp;
472 return TRUE;
473 #else /* __i386__ */
474 return FALSE;
475 #endif /* __i386__ */