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
28 #include "stackframe.h"
33 * We keep this info for each frame, so that we can
34 * find local variable information correctly.
42 struct symbol_info frame;
46 static struct bt_info * frames = NULL;
64 /***********************************************************************
67 * Dump the top of the stack
69 void DEBUG_InfoStack(void)
75 value.cookie = DV_TARGET;
76 value.addr.seg = DEBUG_context.SegSs;
77 value.addr.off = DEBUG_context.Esp;
79 DEBUG_Printf("Stack dump:\n");
80 switch (DEBUG_GetSelectorType(value.addr.seg))
82 case MODE_32: /* 32-bit mode */
83 DEBUG_ExamineMemory( &value, 24, 'x' );
85 case MODE_16: /* 16-bit mode */
87 value.addr.off &= 0xffff;
88 DEBUG_ExamineMemory( &value, 24, 'w' );
91 DEBUG_Printf("Bad segment (%ld)\n", value.addr.seg);
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));
105 DEBUG_Printf("%s%d ", (theframe == curr_frame ? "=>" : " "),
107 frames[theframe].cs = code->seg;
108 frames[theframe].eip = code->off;
110 frames[theframe].frame = DEBUG_PrintAddressAndArgs( code, mode, stack->off, TRUE );
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;
118 DEBUG_Printf((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;
127 void* p = (void*)DEBUG_ToLinear(addr);
130 if (!p) return FALSE;
132 if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
133 if (noisy) DEBUG_InvalAddr(addr);
136 if (!frame.bp) return FALSE;
138 if (frame.bp & 1) *cs = frame.cs;
140 /* not explicitly marked as far call,
141 * but check whether it could be anyway */
142 if (((frame.cs&7)==7) && (frame.cs != *cs)) {
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;
155 addr->off = frame.bp & ~1;
156 DEBUG_ForceFrame(addr, &code, frameno, MODE_16, noisy,
157 possible_cs ? ", far call assumed" : NULL );
161 static BOOL DEBUG_Frame32(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
164 void* p = (void*)DEBUG_ToLinear(addr);
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);
174 if (!frame.ip) return FALSE;
178 addr->off = frame.bp;
179 DEBUG_ForceFrame(addr, &code, frameno, MODE_32, noisy, NULL);
180 if (addr->off == old_bp) return FALSE;
186 /***********************************************************************
189 * Display a stack back-trace.
191 void DEBUG_BackTrace(DWORD tid, BOOL noisy)
194 DBG_ADDR addr, sw_addr, code, tmp;
196 int frameno = 0, is16, ok;
197 DWORD next_switch, cur_switch, p;
198 STACK16FRAME frame16;
199 STACK32FRAME frame32;
205 int copy_curr_frame = 0;
206 struct bt_info* copy_frames = NULL;
208 if (noisy) DEBUG_Printf("Backtrace:\n");
210 if (tid == DEBUG_CurrTid)
213 thread = DEBUG_CurrThread;
215 if (frames) DBG_free( frames );
216 /* frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) ); */
220 thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
224 DEBUG_Printf("Unknown thread id (0x%08lx) in current process\n", tid);
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("Can't get context for thread id (0x%08lx) in current process\n", tid);
236 /* need to avoid trashing stack frame for current thread */
237 copy_nframe = nframe;
238 copy_frames = frames;
239 copy_curr_frame = curr_frame;
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))
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 */
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" );
276 code.off = LOWORD(ctx.Eip);
278 addr.off = LOWORD(ctx.Ebp);
279 DEBUG_ForceFrame( &addr, &code, frameno, MODE_16, noisy, NULL );
283 if (noisy) DEBUG_Printf("Bad segment '%x'\n", ss);
287 /* cur_switch holds address of curr_stack's field in TEB in debuggee
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");
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 );
302 cur_switch = (DWORD)frame32.frame16;
303 sw_addr.seg = SELECTOROF(cur_switch);
304 sw_addr.off = OFFSETOF(cur_switch);
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("Bad stack frame 0x%08lx\n",
312 (unsigned long)(STACK16FRAME*)p );
315 cur_switch = (DWORD)frame16.frame32;
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))
329 * yes, I know this is confusing, it gave me a headache too */
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 );
339 code.off = frame32.retaddr;
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("Bad stack frame 0x%08lx\n",
353 (unsigned long)(STACK16FRAME*)p );
356 cur_switch = (DWORD)frame16.frame32;
358 sw_addr.off = cur_switch;
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("Bad stack frame 0x%08lx\n",
368 (unsigned long)(STACK16FRAME*)p );
372 code.seg = frame16.cs;
373 code.off = frame16.ip;
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("Bad stack frame 0x%08lx\n",
383 (unsigned long)(STACK32FRAME*)next_switch );
386 cur_switch = (DWORD)frame32.frame16;
387 sw_addr.seg = SELECTOROF(cur_switch);
388 sw_addr.off = OFFSETOF(cur_switch);
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;
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("\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;
417 DEBUG_SetFrame(int newframe)
422 curr_frame = newframe;
424 if( curr_frame >= nframe )
426 curr_frame = nframe - 1;
434 if( frames && frames[curr_frame].frame.list.sourcefile != NULL )
436 DEBUG_List(&frames[curr_frame].frame.list, NULL, 0);
443 #endif /* __i386__ */
447 DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip,
452 * If we don't have a valid backtrace, then just return.
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 )
468 *name = frames[curr_frame].frame.sym;
469 *eip = frames[curr_frame].eip;
470 *ebp = frames[curr_frame].ebp;
475 #endif /* __i386__ */