| /* |
| * Debugger stack handling |
| * |
| * Copyright 1995 Alexandre Julliard |
| * Copyright 1996 Eric Youngdale |
| */ |
| |
| #include <stdio.h> |
| #include <malloc.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 ebp; |
| struct name_hash * frame; |
| }; |
| |
| static int nframe; |
| static struct bt_info * frames = NULL; |
| int curr_frame; |
| static char * reg_name[] = |
| { |
| "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" |
| }; |
| |
| 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; |
| |
| fprintf(stderr,"Stack dump:\n"); |
| if ((SS_reg(&DEBUG_context) == WINE_DATA_SELECTOR) || |
| (GET_SEL_FLAGS(SS_reg(&DEBUG_context)) & LDT_FLAGS_32BIT)) |
| { /* 32-bit mode */ |
| addr.seg = 0; |
| addr.off = ESP_reg(&DEBUG_context); |
| DEBUG_ExamineMemory( &addr, 24, 'x' ); |
| } |
| else /* 16-bit mode */ |
| { |
| addr.seg = SS_reg(&DEBUG_context); |
| addr.off = SP_reg(&DEBUG_context); |
| 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 (SS_reg(&DEBUG_context) == WINE_DATA_SELECTOR) /* 32-bit mode */ |
| { |
| 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" ); |
| 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_GetSymbolValue |
| * |
| * Get the address of a named symbol from the current stack frame. |
| */ |
| BOOL32 DEBUG_GetStackSymbolValue( const char * name, DBG_ADDR *addr ) |
| { |
| struct name_hash * curr_func; |
| int i; |
| |
| /* |
| * If we don't have a valid backtrace, then just return. |
| */ |
| if( frames == NULL ) |
| { |
| return FALSE; |
| } |
| |
| curr_func = frames[curr_frame].frame; |
| |
| /* |
| * If we don't know what the current function is, then we also have |
| * nothing to report here. |
| */ |
| if( curr_func == NULL ) |
| { |
| return FALSE; |
| } |
| |
| for(i=0; i < curr_func->n_locals; i++ ) |
| { |
| /* |
| * Test the range of validity of the local variable. This |
| * comes up with RBRAC/LBRAC stabs in particular. |
| */ |
| if( (curr_func->local_vars[i].pc_start != 0) |
| && ((frames[curr_frame].eip - curr_func->addr.off) |
| < curr_func->local_vars[i].pc_start) ) |
| { |
| continue; |
| } |
| |
| if( (curr_func->local_vars[i].pc_end != 0) |
| && ((frames[curr_frame].eip - curr_func->addr.off) |
| > curr_func->local_vars[i].pc_end) ) |
| { |
| continue; |
| } |
| |
| if( strcmp(name, curr_func->local_vars[i].name) == 0 ) |
| { |
| /* |
| * OK, we found it. Now figure out what to do with this. |
| */ |
| if( curr_func->local_vars[i].regno != 0 ) |
| { |
| /* |
| * Register variable. We don't know how to treat |
| * this yet. |
| */ |
| return FALSE; |
| } |
| |
| addr->seg = 0; |
| addr->off = frames[curr_frame].ebp + curr_func->local_vars[i].offset; |
| |
| return TRUE; |
| } |
| } |
| return FALSE; |
| } |
| |
| int |
| DEBUG_SetFrame(int newframe) |
| { |
| int rtn = FALSE; |
| /* |
| * Nothing for now. Add support later. |
| */ |
| |
| curr_frame = newframe; |
| if( curr_frame < 0 ) |
| { |
| curr_frame = 0; |
| } |
| |
| if( curr_frame >= nframe ) |
| { |
| curr_frame = nframe - 1; |
| } |
| |
| rtn = TRUE; |
| return (rtn); |
| } |
| |
| int |
| DEBUG_InfoLocals() |
| { |
| struct name_hash * curr_func; |
| int i; |
| int rtn = FALSE; |
| unsigned int * ptr; |
| |
| /* |
| * If we don't have a valid backtrace, then just return. |
| */ |
| if( frames == NULL ) |
| { |
| return FALSE; |
| } |
| |
| curr_func = frames[curr_frame].frame; |
| |
| /* |
| * If we don't know what the current function is, then we also have |
| * nothing to report here. |
| */ |
| if( curr_func == NULL ) |
| { |
| return FALSE; |
| } |
| |
| for(i=0; i < curr_func->n_locals; i++ ) |
| { |
| /* |
| * Test the range of validity of the local variable. This |
| * comes up with RBRAC/LBRAC stabs in particular. |
| */ |
| if( (curr_func->local_vars[i].pc_start != 0) |
| && ((frames[curr_frame].eip - curr_func->addr.off) |
| < curr_func->local_vars[i].pc_start) ) |
| { |
| continue; |
| } |
| |
| if( (curr_func->local_vars[i].pc_end != 0) |
| && ((frames[curr_frame].eip - curr_func->addr.off) |
| > curr_func->local_vars[i].pc_end) ) |
| { |
| continue; |
| } |
| |
| if( curr_func->local_vars[i].offset == 0 ) |
| { |
| fprintf(stderr, "%s:%s optimized into register $%s \n", |
| curr_func->name, curr_func->local_vars[i].name, |
| reg_name[curr_func->local_vars[i].regno]); |
| } |
| else |
| { |
| ptr = (unsigned int *) (frames[curr_frame].ebp |
| + curr_func->local_vars[i].offset); |
| fprintf(stderr, "%s:%s == 0x%8.8x\n", |
| curr_func->name, curr_func->local_vars[i].name, |
| *ptr); |
| } |
| } |
| |
| rtn = TRUE; |
| |
| return (rtn); |
| } |