| /* | |
| * Debugger stack handling | |
| * | |
| * Copyright 1995 Alexandre Julliard | |
| * Copyright 1996 Eric Youngdale | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include "xmalloc.h" | |
| #include "windows.h" | |
| #include "debugger.h" | |
| /* | |
| * We keep this info for each frame, so that we can | |
| * find local variable information correctly. | |
| */ | |
| struct bt_info | |
| { | |
| unsigned int eip; | |
| unsigned int ess; | |
| unsigned int ebp; | |
| struct symbol_info frame; | |
| }; | |
| static int nframe; | |
| static struct bt_info * frames = NULL; | |
| int curr_frame; | |
| typedef struct | |
| { | |
| WORD bp; | |
| WORD ip; | |
| WORD cs; | |
| } FRAME16; | |
| typedef struct | |
| { | |
| DWORD bp; | |
| DWORD ip; | |
| WORD cs; | |
| } FRAME32; | |
| /*********************************************************************** | |
| * DEBUG_InfoStack | |
| * | |
| * Dump the top of the stack | |
| */ | |
| void DEBUG_InfoStack(void) | |
| { | |
| DBG_ADDR addr = { NULL, SS_reg(&DEBUG_context), ESP_reg(&DEBUG_context) }; | |
| fprintf(stderr,"Stack dump:\n"); | |
| if (IS_SELECTOR_32BIT(addr.seg)) | |
| { /* 32-bit mode */ | |
| DEBUG_ExamineMemory( &addr, 24, 'x' ); | |
| } | |
| else /* 16-bit mode */ | |
| { | |
| addr.off &= 0xffff; | |
| DEBUG_ExamineMemory( &addr, 24, 'w' ); | |
| } | |
| fprintf(stderr,"\n"); | |
| } | |
| /*********************************************************************** | |
| * DEBUG_BackTrace | |
| * | |
| * Display a stack back-trace. | |
| */ | |
| void DEBUG_BackTrace(void) | |
| { | |
| DBG_ADDR addr; | |
| int frameno = 0; | |
| fprintf(stderr,"Backtrace:\n"); | |
| if (IS_SELECTOR_SYSTEM(SS_reg(&DEBUG_context))) /* system stack */ | |
| { | |
| nframe = 1; | |
| if (frames) free( frames ); | |
| frames = (struct bt_info *) xmalloc( sizeof(struct bt_info) ); | |
| fprintf(stderr,"%s%d ",(curr_frame == 0 ? "=>" : " "), frameno++); | |
| addr.seg = 0; | |
| addr.off = EIP_reg(&DEBUG_context); | |
| frames[0].eip = addr.off; | |
| frames[0].frame = DEBUG_PrintAddress( &addr, 32, TRUE ); | |
| fprintf( stderr, "\n" ); | |
| frames[0].ebp = addr.off = EBP_reg(&DEBUG_context); | |
| while (addr.off) | |
| { | |
| FRAME32 *frame = (FRAME32 *)addr.off; | |
| if (!DBG_CHECK_READ_PTR( &addr, sizeof(FRAME32) )) return; | |
| if (!frame->ip) break; | |
| nframe++; | |
| frames = (struct bt_info *)xrealloc(frames, | |
| nframe*sizeof(struct bt_info)); | |
| fprintf(stderr,"%s%d ", (frameno == curr_frame ? "=>" : " "), | |
| frameno); | |
| addr.off = frame->ip; | |
| frames[frameno].eip = addr.off; | |
| frames[frameno].ebp = frame->bp; | |
| frames[frameno].frame = DEBUG_PrintAddressAndArgs( &addr, 32, | |
| frame->bp, TRUE ); | |
| frameno++; | |
| fprintf( stderr, "\n" ); | |
| if (addr.off == frame->bp) break; | |
| addr.off = frame->bp; | |
| } | |
| } | |
| else /* 16-bit mode */ | |
| { | |
| WORD ss = SS_reg(&DEBUG_context), cs = CS_reg(&DEBUG_context); | |
| if (GET_SEL_FLAGS(ss) & LDT_FLAGS_32BIT) | |
| { | |
| fprintf( stderr, "Not implemented: 32-bit backtrace on a different stack segment.\n" ); | |
| return; | |
| } | |
| fprintf( stderr,"%d ", frameno++ ); | |
| addr.seg = cs; | |
| addr.off = IP_reg(&DEBUG_context); | |
| DEBUG_PrintAddress( &addr, 16, TRUE ); | |
| fprintf( stderr, "\n" ); | |
| addr.seg = ss; | |
| addr.off = BP_reg(&DEBUG_context) & ~1; | |
| for (;;) | |
| { | |
| FRAME16 *frame = (FRAME16 *)DBG_ADDR_TO_LIN(&addr); | |
| if (!DBG_CHECK_READ_PTR( &addr, sizeof(FRAME16) )) return; | |
| if (!frame->bp) break; | |
| if (frame->bp & 1) cs = frame->cs; | |
| fprintf( stderr,"%d ", frameno++ ); | |
| addr.seg = cs; | |
| addr.off = frame->ip; | |
| DEBUG_PrintAddress( &addr, 16, TRUE ); | |
| fprintf( stderr, "\n" ); | |
| addr.seg = ss; | |
| addr.off = frame->bp & ~1; | |
| } | |
| } | |
| fprintf( stderr, "\n" ); | |
| } | |
| /*********************************************************************** | |
| * DEBUG_SilentBackTrace | |
| * | |
| * Display a stack back-trace. | |
| */ | |
| void DEBUG_SilentBackTrace(void) | |
| { | |
| DBG_ADDR addr; | |
| int frameno = 0; | |
| nframe = 1; | |
| if (frames) free( frames ); | |
| frames = (struct bt_info *) xmalloc( sizeof(struct bt_info) ); | |
| if (IS_SELECTOR_SYSTEM(SS_reg(&DEBUG_context))) /* system stack */ | |
| { | |
| addr.seg = 0; | |
| addr.off = EIP_reg(&DEBUG_context); | |
| frames[0].eip = addr.off; | |
| DEBUG_FindNearestSymbol( &addr, TRUE, &frames[0].frame.sym, 0, | |
| &frames[0].frame.list); | |
| frames[0].ebp = addr.off = EBP_reg(&DEBUG_context); | |
| frameno++; | |
| while (addr.off) | |
| { | |
| FRAME32 *frame = (FRAME32 *)addr.off; | |
| if (!DBG_CHECK_READ_PTR( &addr, sizeof(FRAME32) )) return; | |
| if (!frame->ip) break; | |
| nframe++; | |
| frames = (struct bt_info *)xrealloc(frames, | |
| nframe*sizeof(struct bt_info)); | |
| addr.off = frame->ip; | |
| frames[frameno].eip = addr.off; | |
| frames[frameno].ebp = frame->bp; | |
| DEBUG_FindNearestSymbol( &addr, TRUE, | |
| &frames[frameno].frame.sym, frame->bp, | |
| &frames[frameno].frame.list); | |
| frameno++; | |
| addr.off = frame->bp; | |
| } | |
| } | |
| else /* 16-bit mode */ | |
| { | |
| /* | |
| * Not implemented here. I am not entirely sure how best to handle | |
| * this stuff. | |
| */ | |
| } | |
| } | |
| int | |
| DEBUG_SetFrame(int newframe) | |
| { | |
| int rtn = FALSE; | |
| curr_frame = newframe; | |
| if( curr_frame >= nframe ) | |
| { | |
| curr_frame = nframe - 1; | |
| } | |
| if( curr_frame < 0 ) | |
| { | |
| curr_frame = 0; | |
| } | |
| if( frames[curr_frame].frame.list.sourcefile != NULL ) | |
| { | |
| DEBUG_List(&frames[curr_frame].frame.list, NULL, 0); | |
| } | |
| rtn = TRUE; | |
| return (rtn); | |
| } | |
| int | |
| DEBUG_GetCurrentFrame(struct name_hash ** name, unsigned int * eip, | |
| unsigned int * ebp) | |
| { | |
| /* | |
| * If we don't have a valid backtrace, then just return. | |
| */ | |
| if( frames == NULL ) | |
| { | |
| return FALSE; | |
| } | |
| /* | |
| * If we don't know what the current function is, then we also have | |
| * nothing to report here. | |
| */ | |
| if( frames[curr_frame].frame.sym == NULL ) | |
| { | |
| return FALSE; | |
| } | |
| *name = frames[curr_frame].frame.sym; | |
| *eip = frames[curr_frame].eip; | |
| *ebp = frames[curr_frame].ebp; | |
| return TRUE; | |
| } | |