No longer directly accessing debuggee memory.
Execution context (mode, steps...) are now linked to a thread. Removed some X11 crst hacks. Rewrote info/walk commands. Removed direct debugger invocation code (and moved the rest to the new winedbg.c file).
This commit is contained in:
parent
00641d5b1c
commit
527eea99f8
|
@ -20,7 +20,8 @@ C_SRCS = \
|
|||
source.c \
|
||||
stabs.c \
|
||||
stack.c \
|
||||
types.c
|
||||
types.c \
|
||||
winedbg.c
|
||||
|
||||
EXTRA_SRCS = dbg.y debug.l
|
||||
EXTRA_OBJS = y.tab.o lex.yy.o
|
||||
|
|
301
debugger/break.c
301
debugger/break.c
|
@ -7,83 +7,43 @@
|
|||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include "wine/winbase16.h"
|
||||
#include "module.h"
|
||||
#include "neexe.h"
|
||||
#include "process.h"
|
||||
#include "task.h"
|
||||
#include "miscemu.h"
|
||||
#include "toolhelp.h"
|
||||
#include "debugger.h"
|
||||
#include "dosexe.h"
|
||||
|
||||
#define INT3 0xcc /* int 3 opcode */
|
||||
|
||||
#define MAX_BREAKPOINTS 100
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DBG_ADDR addr;
|
||||
BYTE addrlen;
|
||||
BYTE opcode;
|
||||
BOOL16 enabled;
|
||||
WORD skipcount;
|
||||
BOOL16 in_use;
|
||||
struct expr * condition;
|
||||
} BREAKPOINT;
|
||||
|
||||
static BREAKPOINT breakpoints[MAX_BREAKPOINTS];
|
||||
|
||||
static int next_bp = 1; /* breakpoint 0 is reserved for step-over */
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_ChangeOpcode
|
||||
*
|
||||
* Change the opcode at segment:addr.
|
||||
*/
|
||||
static void DEBUG_SetOpcode( const DBG_ADDR *addr, BYTE op )
|
||||
{
|
||||
BYTE *ptr = DBG_ADDR_TO_LIN(addr);
|
||||
|
||||
/* There are a couple of problems with this. On Linux prior to
|
||||
1.1.62, this call fails (ENOACCESS) due to a bug in fs/exec.c.
|
||||
This code is currently not tested at all on BSD.
|
||||
How do I get the old protection in order to restore it later on?
|
||||
*/
|
||||
if (mprotect((caddr_t)((int)ptr & (~4095)), 4096,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
|
||||
{
|
||||
perror( "Can't set break point" );
|
||||
return;
|
||||
}
|
||||
*ptr = op;
|
||||
/* mprotect((caddr_t)(addr->off & ~4095), 4096,
|
||||
PROT_READ | PROT_EXEC ); */
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_IsStepOverInstr
|
||||
*
|
||||
* Determine if the instruction at CS:EIP is an instruction that
|
||||
* we need to step over (like a call or a repetitive string move).
|
||||
*/
|
||||
static BOOL DEBUG_IsStepOverInstr()
|
||||
static BOOL DEBUG_IsStepOverInstr(void)
|
||||
{
|
||||
#ifdef __i386__
|
||||
BYTE *instr = (BYTE *)CTX_SEG_OFF_TO_LIN( &DEBUG_context,
|
||||
CS_reg(&DEBUG_context),
|
||||
EIP_reg(&DEBUG_context) );
|
||||
BYTE* instr;
|
||||
BYTE ch;
|
||||
DBG_ADDR addr;
|
||||
|
||||
addr.seg = DEBUG_context.SegCs;
|
||||
addr.off = DEBUG_context.Eip;
|
||||
/* FIXME: old code was using V86BASE(DEBUG_context)
|
||||
* instead of passing thru DOSMEM_MemoryBase
|
||||
*/
|
||||
instr = (BYTE*)DEBUG_ToLinear(&addr);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
switch(*instr)
|
||||
if (!DEBUG_READ_MEM(instr, &ch, sizeof(ch)))
|
||||
return FALSE;
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
/* Skip all prefixes */
|
||||
|
||||
|
@ -109,8 +69,9 @@ static BOOL DEBUG_IsStepOverInstr()
|
|||
return TRUE;
|
||||
|
||||
case 0xff: /* call <regmodrm> */
|
||||
return (((instr[1] & 0x38) == 0x10) ||
|
||||
((instr[1] & 0x38) == 0x18));
|
||||
if (!DEBUG_READ_MEM(instr + 1, &ch, sizeof(ch)))
|
||||
return FALSE;
|
||||
return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
|
||||
|
||||
/* Handle string instructions */
|
||||
|
||||
|
@ -149,21 +110,21 @@ static BOOL DEBUG_IsStepOverInstr()
|
|||
BOOL DEBUG_IsFctReturn(void)
|
||||
{
|
||||
#ifdef __i386__
|
||||
BYTE *instr = (BYTE *)CTX_SEG_OFF_TO_LIN( &DEBUG_context,
|
||||
CS_reg(&DEBUG_context),
|
||||
EIP_reg(&DEBUG_context) );
|
||||
BYTE* instr;
|
||||
BYTE ch;
|
||||
DBG_ADDR addr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
switch(*instr)
|
||||
{
|
||||
case 0xc2:
|
||||
case 0xc3:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
addr.seg = DEBUG_context.SegCs;
|
||||
addr.off = DEBUG_context.Eip;
|
||||
/* FIXME: old code was using V86BASE(DEBUG_context)
|
||||
* instead of passing thru DOSMEM_MemoryBase
|
||||
*/
|
||||
instr = (BYTE*)DEBUG_ToLinear(&addr);
|
||||
|
||||
if (!DEBUG_READ_MEM(instr, &ch, sizeof(ch)))
|
||||
return FALSE;
|
||||
|
||||
return (ch == 0xc2) || (ch == 0xc3);
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
|
@ -177,21 +138,20 @@ BOOL DEBUG_IsFctReturn(void)
|
|||
*/
|
||||
void DEBUG_SetBreakpoints( BOOL set )
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
char ch;
|
||||
|
||||
for (i = 0; i < MAX_BREAKPOINTS; i++)
|
||||
{
|
||||
if (breakpoints[i].in_use && breakpoints[i].enabled)
|
||||
if (breakpoints[i].refcount && breakpoints[i].enabled)
|
||||
{
|
||||
/* Note: we check for read here, because if reading is allowed */
|
||||
/* writing permission will be forced in DEBUG_SetOpcode. */
|
||||
if (DEBUG_IsBadReadPtr( &breakpoints[i].addr, 1 ))
|
||||
ch = set ? INT3 : breakpoints[i].opcode;
|
||||
|
||||
if (!DEBUG_WRITE_MEM( (void*)DEBUG_ToLinear(&breakpoints[i].addr), &ch, sizeof(ch) ))
|
||||
{
|
||||
fprintf( stderr, "Invalid address for breakpoint %d, disabling it\n", i );
|
||||
breakpoints[i].enabled = FALSE;
|
||||
}
|
||||
else DEBUG_SetOpcode( &breakpoints[i].addr,
|
||||
set ? INT3 : breakpoints[i].opcode );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +169,7 @@ int DEBUG_FindBreakpoint( const DBG_ADDR *addr )
|
|||
|
||||
for (i = 0; i < MAX_BREAKPOINTS; i++)
|
||||
{
|
||||
if (breakpoints[i].in_use && breakpoints[i].enabled &&
|
||||
if (breakpoints[i].refcount && breakpoints[i].enabled &&
|
||||
breakpoints[i].addr.seg == addr->seg &&
|
||||
breakpoints[i].addr.off == addr->off) return i;
|
||||
}
|
||||
|
@ -227,9 +187,9 @@ void DEBUG_AddBreakpoint( const DBG_ADDR *address )
|
|||
DBG_ADDR addr = *address;
|
||||
int num;
|
||||
unsigned int seg2;
|
||||
BYTE *p;
|
||||
BYTE ch;
|
||||
|
||||
DBG_FIX_ADDR_SEG( &addr, CS_reg(&DEBUG_context) );
|
||||
DEBUG_FixAddress( &addr, DEBUG_context.SegCs );
|
||||
|
||||
if( addr.type != NULL && addr.type == DEBUG_TypeIntConst )
|
||||
{
|
||||
|
@ -243,27 +203,38 @@ void DEBUG_AddBreakpoint( const DBG_ADDR *address )
|
|||
addr.off = DEBUG_GetExprValue(&addr, NULL);
|
||||
addr.seg = seg2;
|
||||
}
|
||||
if (!DBG_CHECK_READ_PTR( &addr, 1 )) return;
|
||||
|
||||
if ((num = DEBUG_FindBreakpoint(&addr)) >= 1)
|
||||
{
|
||||
breakpoints[num].refcount++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear( &addr ), &ch, sizeof(ch)))
|
||||
return;
|
||||
|
||||
if (next_bp < MAX_BREAKPOINTS)
|
||||
num = next_bp++;
|
||||
else /* try to find an empty slot */
|
||||
{
|
||||
for (num = 1; num < MAX_BREAKPOINTS; num++)
|
||||
if (!breakpoints[num].in_use) break;
|
||||
if (!breakpoints[num].refcount) break;
|
||||
if (num >= MAX_BREAKPOINTS)
|
||||
{
|
||||
fprintf( stderr, "Too many breakpoints. Please delete some.\n" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
p = DBG_ADDR_TO_LIN( &addr );
|
||||
breakpoints[num].addr = addr;
|
||||
breakpoints[num].addrlen = !addr.seg ? 32 :
|
||||
(GET_SEL_FLAGS(addr.seg) & LDT_FLAGS_32BIT) ? 32 : 16;
|
||||
breakpoints[num].opcode = *p;
|
||||
breakpoints[num].addrlen = 32;
|
||||
#ifdef __i386__
|
||||
if (addr.seg)
|
||||
breakpoints[num].addrlen = DEBUG_GetSelectorType( addr.seg );
|
||||
if (breakpoints[num].addrlen == 0) fprintf(stderr, "in bad shape\n");
|
||||
#endif
|
||||
breakpoints[num].opcode = ch;
|
||||
breakpoints[num].enabled = TRUE;
|
||||
breakpoints[num].in_use = TRUE;
|
||||
breakpoints[num].refcount = 1;
|
||||
breakpoints[num].skipcount = 0;
|
||||
fprintf( stderr, "Breakpoint %d at ", num );
|
||||
DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].addrlen,
|
||||
|
@ -279,12 +250,15 @@ void DEBUG_AddBreakpoint( const DBG_ADDR *address )
|
|||
*/
|
||||
void DEBUG_DelBreakpoint( int num )
|
||||
{
|
||||
if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use)
|
||||
if ((num <= 0) || (num >= next_bp) || !breakpoints[num].refcount)
|
||||
{
|
||||
fprintf( stderr, "Invalid breakpoint number %d\n", num );
|
||||
return;
|
||||
}
|
||||
|
||||
if (--breakpoints[num].refcount > 0)
|
||||
return;
|
||||
|
||||
if( breakpoints[num].condition != NULL )
|
||||
{
|
||||
DEBUG_FreeExpr(breakpoints[num].condition);
|
||||
|
@ -292,7 +266,7 @@ void DEBUG_DelBreakpoint( int num )
|
|||
}
|
||||
|
||||
breakpoints[num].enabled = FALSE;
|
||||
breakpoints[num].in_use = FALSE;
|
||||
breakpoints[num].refcount = 0;
|
||||
breakpoints[num].skipcount = 0;
|
||||
}
|
||||
|
||||
|
@ -304,12 +278,12 @@ void DEBUG_DelBreakpoint( int num )
|
|||
*/
|
||||
void DEBUG_EnableBreakpoint( int num, BOOL enable )
|
||||
{
|
||||
if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use)
|
||||
if ((num <= 0) || (num >= next_bp) || !breakpoints[num].refcount)
|
||||
{
|
||||
fprintf( stderr, "Invalid breakpoint number %d\n", num );
|
||||
return;
|
||||
}
|
||||
breakpoints[num].enabled = enable;
|
||||
breakpoints[num].enabled = (enable) ? TRUE : FALSE;
|
||||
breakpoints[num].skipcount = 0;
|
||||
}
|
||||
|
||||
|
@ -326,67 +300,21 @@ void DEBUG_InfoBreakpoints(void)
|
|||
fprintf( stderr, "Breakpoints:\n" );
|
||||
for (i = 1; i < next_bp; i++)
|
||||
{
|
||||
if (breakpoints[i].in_use)
|
||||
if (breakpoints[i].refcount)
|
||||
{
|
||||
fprintf( stderr, "%d: %c ", i, breakpoints[i].enabled ? 'y' : 'n');
|
||||
DEBUG_PrintAddress( &breakpoints[i].addr, breakpoints[i].addrlen,
|
||||
TRUE);
|
||||
fprintf( stderr, "\n" );
|
||||
DEBUG_PrintAddress( &breakpoints[i].addr, breakpoints[i].addrlen, TRUE);
|
||||
fprintf( stderr, " (%u)\n", breakpoints[i].refcount );
|
||||
if( breakpoints[i].condition != NULL )
|
||||
{
|
||||
fprintf(stderr, "\t\tstop when ");
|
||||
{
|
||||
fprintf(stderr, "\t\tstop when ");
|
||||
DEBUG_DisplayExpr(breakpoints[i].condition);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_AddTaskEntryBreakpoint
|
||||
*
|
||||
* Add a breakpoint at the entry point of the given task
|
||||
*/
|
||||
void DEBUG_AddTaskEntryBreakpoint( HTASK16 hTask )
|
||||
{
|
||||
TDB *pTask = (TDB *)GlobalLock16( hTask );
|
||||
NE_MODULE *pModule;
|
||||
DBG_ADDR addr = { NULL, 0, 0 };
|
||||
|
||||
if ( pTask )
|
||||
{
|
||||
if (!(pModule = NE_GetPtr( pTask->hModule ))) return;
|
||||
if (pModule->flags & NE_FFLAGS_LIBMODULE) return; /* Library */
|
||||
|
||||
if (pModule->lpDosTask) { /* DOS module */
|
||||
addr.seg = pModule->lpDosTask->init_cs | ((DWORD)pModule->self << 16);
|
||||
addr.off = pModule->lpDosTask->init_ip;
|
||||
fprintf( stderr, "DOS task '%s': ", NE_MODULE_NAME( pModule ) );
|
||||
DEBUG_AddBreakpoint( &addr );
|
||||
} else
|
||||
if (!(pModule->flags & NE_FFLAGS_WIN32)) /* NE module */
|
||||
{
|
||||
addr.seg =
|
||||
GlobalHandleToSel16(NE_SEG_TABLE(pModule)[pModule->cs-1].hSeg);
|
||||
addr.off = pModule->ip;
|
||||
fprintf( stderr, "Win16 task '%s': ", NE_MODULE_NAME( pModule ) );
|
||||
DEBUG_AddBreakpoint( &addr );
|
||||
}
|
||||
else /* PE module */
|
||||
{
|
||||
addr.seg = 0;
|
||||
addr.off = (DWORD)RVA_PTR( pModule->module32,
|
||||
OptionalHeader.AddressOfEntryPoint);
|
||||
fprintf( stderr, "Win32 task '%s': ", NE_MODULE_NAME( pModule ) );
|
||||
DEBUG_AddBreakpoint( &addr );
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_SetBreakpoints( TRUE ); /* Setup breakpoints */
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_ShouldContinue
|
||||
*
|
||||
|
@ -401,21 +329,22 @@ BOOL DEBUG_ShouldContinue( enum exec_mode mode, int * count )
|
|||
struct list_id list;
|
||||
|
||||
#ifdef __i386__
|
||||
/* If not single-stepping, back up over the int3 instruction */
|
||||
if (!(EFL_reg(&DEBUG_context) & STEP_FLAG)) EIP_reg(&DEBUG_context)--;
|
||||
/* If not single-stepping, back up over the int3 instruction */
|
||||
if (!(DEBUG_context.EFlags & STEP_FLAG))
|
||||
DEBUG_context.Eip--;
|
||||
#endif
|
||||
|
||||
DEBUG_GetCurrentAddress( &addr );
|
||||
bpnum = DEBUG_FindBreakpoint( &addr );
|
||||
breakpoints[0].enabled = 0; /* disable the step-over breakpoint */
|
||||
breakpoints[0].enabled = FALSE; /* disable the step-over breakpoint */
|
||||
|
||||
if ((bpnum != 0) && (bpnum != -1))
|
||||
{
|
||||
if( breakpoints[bpnum].condition != NULL )
|
||||
{
|
||||
{
|
||||
cond_addr = DEBUG_EvalExpr(breakpoints[bpnum].condition);
|
||||
if( cond_addr.type == NULL )
|
||||
{
|
||||
{
|
||||
/*
|
||||
* Something wrong - unable to evaluate this expression.
|
||||
*/
|
||||
|
@ -423,21 +352,21 @@ BOOL DEBUG_ShouldContinue( enum exec_mode mode, int * count )
|
|||
DEBUG_DisplayExpr(breakpoints[bpnum].condition);
|
||||
fprintf(stderr, "\nTurning off condition\n");
|
||||
DEBUG_AddBPCondition(bpnum, NULL);
|
||||
}
|
||||
}
|
||||
else if( ! DEBUG_GetExprValue( &cond_addr, NULL) )
|
||||
{
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( breakpoints[bpnum].skipcount > 0 )
|
||||
{
|
||||
{
|
||||
breakpoints[bpnum].skipcount--;
|
||||
if( breakpoints[bpnum].skipcount > 0 )
|
||||
{
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf( stderr, "Stopped on breakpoint %d at ", bpnum );
|
||||
DEBUG_PrintAddress( &breakpoints[bpnum].addr,
|
||||
breakpoints[bpnum].addrlen, TRUE );
|
||||
|
@ -449,9 +378,9 @@ BOOL DEBUG_ShouldContinue( enum exec_mode mode, int * count )
|
|||
*/
|
||||
DEBUG_FindNearestSymbol( &addr, TRUE, NULL, 0, &list);
|
||||
if( list.sourcefile != NULL )
|
||||
{
|
||||
{
|
||||
DEBUG_List(&list, NULL, 0);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -460,8 +389,7 @@ BOOL DEBUG_ShouldContinue( enum exec_mode mode, int * count )
|
|||
* get the current function, and figure out if we are exactly
|
||||
* on a line number or not.
|
||||
*/
|
||||
if( mode == EXEC_STEP_OVER
|
||||
|| mode == EXEC_STEP_INSTR )
|
||||
if( mode == EXEC_STEP_OVER || mode == EXEC_STEP_INSTR )
|
||||
{
|
||||
if( DEBUG_CheckLinenoStatus(&addr) == AT_LINENUMBER )
|
||||
{
|
||||
|
@ -499,14 +427,24 @@ BOOL DEBUG_ShouldContinue( enum exec_mode mode, int * count )
|
|||
#ifdef __i386__
|
||||
/* If there's no breakpoint and we are not single-stepping, then we */
|
||||
/* must have encountered an int3 in the Windows program; let's skip it. */
|
||||
if ((bpnum == -1) && !(EFL_reg(&DEBUG_context) & STEP_FLAG))
|
||||
EIP_reg(&DEBUG_context)++;
|
||||
if ((bpnum == -1) && !(DEBUG_context.EFlags & STEP_FLAG))
|
||||
DEBUG_context.Eip++;
|
||||
#endif
|
||||
|
||||
/* no breakpoint, continue if in continuous mode */
|
||||
/* no breakpoint, continue if in continuous mode */
|
||||
return (mode == EXEC_CONT || mode == EXEC_PASS || mode == EXEC_FINISH);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_RestartExecution
|
||||
*
|
||||
* Remove all breakpoints before entering the debug loop
|
||||
*/
|
||||
void DEBUG_SuspendExecution( void )
|
||||
{
|
||||
DEBUG_SetBreakpoints( FALSE );
|
||||
breakpoints[0] = DEBUG_CurrThread->stepOverBP;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_RestartExecution
|
||||
|
@ -522,7 +460,8 @@ enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
|
|||
int delta;
|
||||
int status;
|
||||
enum exec_mode ret_mode;
|
||||
BYTE *instr;
|
||||
DWORD instr;
|
||||
unsigned char ch;
|
||||
|
||||
DEBUG_GetCurrentAddress( &addr );
|
||||
|
||||
|
@ -548,7 +487,7 @@ enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
|
|||
{
|
||||
if( mode == EXEC_CONT && count > 1 )
|
||||
{
|
||||
fprintf(stderr,"Not stopped at any breakpoint; argument ignored.\n");
|
||||
fprintf(stderr, "Not stopped at any breakpoint; argument ignored.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,16 +496,17 @@ enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
|
|||
mode = ret_mode = EXEC_STEPI_INSTR;
|
||||
}
|
||||
|
||||
instr = DBG_ADDR_TO_LIN( &addr );
|
||||
instr = DEBUG_ToLinear( &addr );
|
||||
DEBUG_READ_MEM((void*)instr, &ch, sizeof(ch));
|
||||
/*
|
||||
* See if the function we are stepping into has debug info
|
||||
* and line numbers. If not, then we step over it instead.
|
||||
* FIXME - we need to check for things like thunks or trampolines,
|
||||
* as the actual function may in fact have debug info.
|
||||
*/
|
||||
if( *instr == 0xe8 )
|
||||
if( ch == 0xe8 )
|
||||
{
|
||||
delta = *(unsigned int*) (instr + 1);
|
||||
DEBUG_READ_MEM((void*)(instr + 1), &delta, sizeof(delta));
|
||||
addr2 = addr;
|
||||
DEBUG_Disasm(&addr2, FALSE);
|
||||
addr2.off += delta;
|
||||
|
@ -612,7 +552,7 @@ enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
|
|||
case EXEC_CONT: /* Continuous execution */
|
||||
case EXEC_PASS: /* Continue, passing exception */
|
||||
#ifdef __i386__
|
||||
EFL_reg(&DEBUG_context) &= ~STEP_FLAG;
|
||||
DEBUG_context.EFlags &= ~STEP_FLAG;
|
||||
#endif
|
||||
DEBUG_SetBreakpoints( TRUE );
|
||||
break;
|
||||
|
@ -625,14 +565,16 @@ enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
|
|||
* address just after the call.
|
||||
*/
|
||||
#ifdef __i386__
|
||||
addr.off = *((unsigned int *) ESP_reg(&DEBUG_context) + 2);
|
||||
EFL_reg(&DEBUG_context) &= ~STEP_FLAG;
|
||||
DEBUG_READ_MEM((void*)(DEBUG_context.Esp +
|
||||
2 * sizeof(unsigned int)),
|
||||
&addr.off, sizeof(addr.off));
|
||||
DEBUG_context.EFlags &= ~STEP_FLAG;
|
||||
#endif
|
||||
breakpoints[0].addr = addr;
|
||||
breakpoints[0].enabled = TRUE;
|
||||
breakpoints[0].in_use = TRUE;
|
||||
breakpoints[0].refcount = 1;
|
||||
breakpoints[0].skipcount = 0;
|
||||
breakpoints[0].opcode = *(BYTE *)DBG_ADDR_TO_LIN( &addr );
|
||||
DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].opcode, sizeof(char));
|
||||
DEBUG_SetBreakpoints( TRUE );
|
||||
break;
|
||||
|
||||
|
@ -642,14 +584,14 @@ enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
|
|||
if (DEBUG_IsStepOverInstr())
|
||||
{
|
||||
#ifdef __i386__
|
||||
EFL_reg(&DEBUG_context) &= ~STEP_FLAG;
|
||||
DEBUG_context.EFlags &= ~STEP_FLAG;
|
||||
#endif
|
||||
DEBUG_Disasm(&addr, FALSE);
|
||||
breakpoints[0].addr = addr;
|
||||
breakpoints[0].enabled = TRUE;
|
||||
breakpoints[0].in_use = TRUE;
|
||||
breakpoints[0].refcount = 1;
|
||||
breakpoints[0].skipcount = 0;
|
||||
breakpoints[0].opcode = *(BYTE *)DBG_ADDR_TO_LIN( &addr );
|
||||
DEBUG_READ_MEM((void*)DEBUG_ToLinear( &addr ), &breakpoints[0].opcode, sizeof(char));
|
||||
DEBUG_SetBreakpoints( TRUE );
|
||||
break;
|
||||
}
|
||||
|
@ -658,17 +600,18 @@ enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
|
|||
case EXEC_STEP_INSTR: /* Single-stepping an instruction */
|
||||
case EXEC_STEPI_INSTR: /* Single-stepping an instruction */
|
||||
#ifdef __i386__
|
||||
EFL_reg(&DEBUG_context) |= STEP_FLAG;
|
||||
DEBUG_context.EFlags |= STEP_FLAG;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
DEBUG_CurrThread->stepOverBP = breakpoints[0];
|
||||
return ret_mode;
|
||||
}
|
||||
|
||||
int
|
||||
DEBUG_AddBPCondition(int num, struct expr * exp)
|
||||
{
|
||||
if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use)
|
||||
if ((num <= 0) || (num >= next_bp) || !breakpoints[num].refcount)
|
||||
{
|
||||
fprintf( stderr, "Invalid breakpoint number %d\n", num );
|
||||
return FALSE;
|
||||
|
|
|
@ -892,27 +892,29 @@ static const int db_lengths[] = {
|
|||
static unsigned int db_get_task_value( const DBG_ADDR *addr,
|
||||
int size, int is_signed )
|
||||
{
|
||||
unsigned int result;
|
||||
unsigned char *p = DBG_ADDR_TO_LIN( addr );
|
||||
unsigned int result = 0;
|
||||
char buffer[4];
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case 4:
|
||||
if (is_signed) result = (unsigned int) *(int *)p;
|
||||
else result = *(unsigned int *)p;
|
||||
break;
|
||||
case 2:
|
||||
if (is_signed) result = (unsigned int) *(short int *)p;
|
||||
else result = *(unsigned short int *)p;
|
||||
break;
|
||||
case 1:
|
||||
if (is_signed) result = (unsigned int) *(char *)p;
|
||||
else result = *(unsigned char *)p;
|
||||
break;
|
||||
default:
|
||||
if (size != 1 && size != 2 && size != 4) {
|
||||
fprintf(stderr, "Illegal size specified\n");
|
||||
result = 0;
|
||||
break;
|
||||
} else {
|
||||
DEBUG_READ_MEM((void*)DEBUG_ToLinear( addr ), buffer, size);
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case 4:
|
||||
if (is_signed) result = (unsigned int) *(int *)buffer;
|
||||
else result = *(unsigned int *)buffer;
|
||||
break;
|
||||
case 2:
|
||||
if (is_signed) result = (unsigned int) *(short int *)buffer;
|
||||
else result = *(unsigned short int *)buffer;
|
||||
break;
|
||||
case 1:
|
||||
if (is_signed) result = (unsigned int) *(char *)buffer;
|
||||
else result = *(unsigned char *)buffer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1041,18 +1043,16 @@ void db_print_address(char *seg, int size, struct i_addr *addrp, int byref)
|
|||
/* try to get destination of indirect call
|
||||
does not work for segmented adresses */
|
||||
if (!seg && byref) {
|
||||
DBG_ADDR dbg_addr = {NULL, 0, 0};
|
||||
void* a1;
|
||||
void* a2;
|
||||
|
||||
dbg_addr.off = addrp->disp;
|
||||
fprintf(stderr,"0x%x -> ", addrp->disp);
|
||||
if (DEBUG_IsBadReadPtr( &dbg_addr, sizeof(LPDWORD))) {
|
||||
fprintf(stderr, "(invalid source)");
|
||||
} else {
|
||||
dbg_addr.off = *(LPDWORD)(addrp->disp);
|
||||
if (DEBUG_IsBadReadPtr( &dbg_addr, sizeof(DWORD)))
|
||||
fprintf(stderr, "(invalid destination)");
|
||||
else
|
||||
db_task_printsym(dbg_addr.off, 0);
|
||||
if (!DEBUG_READ_MEM((void*)addrp->disp, &a1, sizeof(a1))) {
|
||||
fprintf(stderr, "(invalid source)");
|
||||
} else if (!DEBUG_READ_MEM(a1, &a2, sizeof(a2))) {
|
||||
fprintf(stderr, "(invalid destination)");
|
||||
} else {
|
||||
db_task_printsym((unsigned long)a1, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1172,7 +1172,11 @@ void DEBUG_Disasm( DBG_ADDR *addr, int display )
|
|||
* Set this so we get can supress the printout if we need to.
|
||||
*/
|
||||
db_display = display;
|
||||
db_disasm_16 = IS_SELECTOR_V86(addr->seg) || !IS_SELECTOR_32BIT(addr->seg);
|
||||
switch (DEBUG_GetSelectorType(addr->seg)) {
|
||||
case 16: db_disasm_16 = 1; break;
|
||||
case 32: db_disasm_16 = 0; break;
|
||||
default: fprintf(stderr, "Bad selector %ld\n", addr->seg); return;
|
||||
}
|
||||
|
||||
get_value_inc( inst, addr, 1, FALSE );
|
||||
|
||||
|
|
418
debugger/dbg.y
418
debugger/dbg.y
|
@ -12,51 +12,21 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#include "winbase.h"
|
||||
#include "module.h"
|
||||
#include "task.h"
|
||||
#include "options.h"
|
||||
#include "queue.h"
|
||||
#include "wine/winbase16.h"
|
||||
#include "winnt.h"
|
||||
#include "x11drv.h"
|
||||
#include "win.h"
|
||||
#include "debugger.h"
|
||||
#include "neexe.h"
|
||||
#include "process.h"
|
||||
#include "server.h"
|
||||
#include "main.h"
|
||||
#include "expr.h"
|
||||
#include "user.h"
|
||||
#include "wine/exception.h"
|
||||
|
||||
extern FILE * yyin;
|
||||
unsigned int dbg_mode = 0;
|
||||
HANDLE dbg_heap = 0;
|
||||
int curr_frame = 0;
|
||||
|
||||
static enum exec_mode dbg_exec_mode = EXEC_CONT;
|
||||
static int dbg_exec_count = 0;
|
||||
|
||||
void issue_prompt(void);
|
||||
void mode_command(int);
|
||||
void flush_symbols(void);
|
||||
int yylex(void);
|
||||
int yyerror(char *);
|
||||
|
||||
#ifdef DBG_need_heap
|
||||
#define malloc(x) DBG_alloc(x)
|
||||
#define realloc(x,y) DBG_realloc(x,y)
|
||||
#define free(x) DBG_free(x)
|
||||
#endif
|
||||
|
||||
extern void VIRTUAL_Dump(void); /* memory/virtual.c */
|
||||
|
||||
%}
|
||||
|
||||
%union
|
||||
|
@ -126,41 +96,41 @@ command:
|
|||
tQUIT tEOL { DEBUG_Exit(0); }
|
||||
| tHELP tEOL { DEBUG_Help(); }
|
||||
| tHELP tINFO tEOL { DEBUG_HelpInfo(); }
|
||||
| tCONT tEOL { dbg_exec_count = 1;
|
||||
dbg_exec_mode = EXEC_CONT; return 0; }
|
||||
| tPASS tEOL { dbg_exec_count = 1;
|
||||
dbg_exec_mode = EXEC_PASS; return 0; }
|
||||
| tCONT tNUM tEOL { dbg_exec_count = $2;
|
||||
dbg_exec_mode = EXEC_CONT; return 0; }
|
||||
| tSTEP tEOL { dbg_exec_count = 1;
|
||||
dbg_exec_mode = EXEC_STEP_INSTR; return 0; }
|
||||
| tNEXT tEOL { dbg_exec_count = 1;
|
||||
dbg_exec_mode = EXEC_STEP_OVER; return 0; }
|
||||
| tSTEP tNUM tEOL { dbg_exec_count = $2;
|
||||
dbg_exec_mode = EXEC_STEP_INSTR; return 0; }
|
||||
| tNEXT tNUM tEOL { dbg_exec_count = $2;
|
||||
dbg_exec_mode = EXEC_STEP_OVER; return 0; }
|
||||
| tSTEPI tEOL { dbg_exec_count = 1;
|
||||
dbg_exec_mode = EXEC_STEPI_INSTR; return 0; }
|
||||
| tNEXTI tEOL { dbg_exec_count = 1;
|
||||
dbg_exec_mode = EXEC_STEPI_OVER; return 0; }
|
||||
| tSTEPI tNUM tEOL { dbg_exec_count = $2;
|
||||
dbg_exec_mode = EXEC_STEPI_INSTR; return 0; }
|
||||
| tNEXTI tNUM tEOL { dbg_exec_count = $2;
|
||||
dbg_exec_mode = EXEC_STEPI_OVER; return 0; }
|
||||
| tCONT tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_CONT; return 0; }
|
||||
| tPASS tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_PASS; return 0; }
|
||||
| tCONT tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_CONT; return 0; }
|
||||
| tSTEP tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEP_INSTR; return 0; }
|
||||
| tNEXT tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEP_OVER; return 0; }
|
||||
| tSTEP tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEP_INSTR; return 0; }
|
||||
| tNEXT tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEP_OVER; return 0; }
|
||||
| tSTEPI tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEPI_INSTR; return 0; }
|
||||
| tNEXTI tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEPI_OVER; return 0; }
|
||||
| tSTEPI tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEPI_INSTR; return 0; }
|
||||
| tNEXTI tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEPI_OVER; return 0; }
|
||||
| tABORT tEOL { kill(getpid(), SIGABRT); }
|
||||
| tMODE tNUM tEOL { mode_command($2); }
|
||||
| tENABLE tNUM tEOL { DEBUG_EnableBreakpoint( $2, TRUE ); }
|
||||
| tDISABLE tNUM tEOL { DEBUG_EnableBreakpoint( $2, FALSE ); }
|
||||
| tDELETE tBREAK tNUM tEOL { DEBUG_DelBreakpoint( $3 ); }
|
||||
| tBACKTRACE tEOL { DEBUG_BackTrace(); }
|
||||
| tBACKTRACE tEOL { DEBUG_BackTrace(TRUE); }
|
||||
| tUP tEOL { DEBUG_SetFrame( curr_frame + 1 ); }
|
||||
| tUP tNUM tEOL { DEBUG_SetFrame( curr_frame + $2 ); }
|
||||
| tDOWN tEOL { DEBUG_SetFrame( curr_frame - 1 ); }
|
||||
| tDOWN tNUM tEOL { DEBUG_SetFrame( curr_frame - $2 ); }
|
||||
| tFRAME tNUM tEOL { DEBUG_SetFrame( $2 ); }
|
||||
| tFINISH tEOL { dbg_exec_count = 0;
|
||||
dbg_exec_mode = EXEC_FINISH; return 0; }
|
||||
| tFINISH tEOL { DEBUG_CurrThread->dbg_exec_count = 0;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_FINISH; return 0; }
|
||||
| tSHOW tDIR tEOL { DEBUG_ShowDir(); }
|
||||
| tDIR pathname tEOL { DEBUG_AddPath( $2 ); }
|
||||
| tDIR tEOL { DEBUG_NukePath(); }
|
||||
|
@ -173,7 +143,6 @@ command:
|
|||
| tUNDISPLAY tEOL { DEBUG_DelDisplay( -1 ); }
|
||||
| tCOND tNUM tEOL { DEBUG_AddBPCondition($2, NULL); }
|
||||
| tCOND tNUM expr tEOL { DEBUG_AddBPCondition($2, $3); }
|
||||
| tDEBUGMSG tDEBUGSTR tEOL { MAIN_ParseDebugOptions($2); }
|
||||
| tSYMBOLFILE pathname tEOL{ DEBUG_ReadSymbolTable($2); }
|
||||
| list_command
|
||||
| disassemble_command
|
||||
|
@ -274,32 +243,30 @@ break_command:
|
|||
|
||||
info_command:
|
||||
tINFO tBREAK tEOL { DEBUG_InfoBreakpoints(); }
|
||||
| tINFO tCLASS expr_value tEOL { CLASS_DumpClass( (struct tagCLASS *)$3 );
|
||||
DEBUG_FreeExprMem(); }
|
||||
| tINFO tCLASS tSTRING tEOL { DEBUG_InfoClass( $3 ); DEBUG_FreeExprMem(); }
|
||||
| tINFO tSHARE tEOL { DEBUG_InfoShare(); }
|
||||
| tINFO tMODULE expr_value tEOL { NE_DumpModule( $3 );
|
||||
| tINFO tMODULE expr_value tEOL { DEBUG_DumpModule( $3 );
|
||||
DEBUG_FreeExprMem(); }
|
||||
| tINFO tQUEUE expr_value tEOL { QUEUE_DumpQueue( $3 );
|
||||
| tINFO tQUEUE expr_value tEOL { DEBUG_DumpQueue( $3 );
|
||||
DEBUG_FreeExprMem(); }
|
||||
| tINFO tREGS tEOL { DEBUG_InfoRegisters(); }
|
||||
| tINFO tSEGMENTS expr_value tEOL { LDT_Print( SELECTOR_TO_ENTRY($3), 1 );
|
||||
DEBUG_FreeExprMem(); }
|
||||
| tINFO tSEGMENTS tEOL { LDT_Print( 0, -1 ); }
|
||||
| tINFO tSEGMENTS expr_value tEOL { DEBUG_InfoSegments( $3, 1 ); DEBUG_FreeExprMem(); }
|
||||
| tINFO tSEGMENTS tEOL { DEBUG_InfoSegments( 0, -1 ); }
|
||||
| tINFO tSTACK tEOL { DEBUG_InfoStack(); }
|
||||
| tINFO tMAPS tEOL { VIRTUAL_Dump(); }
|
||||
| tINFO tWND expr_value tEOL { WIN_DumpWindow( $3 );
|
||||
| tINFO tMAPS tEOL { DEBUG_InfoVirtual(); }
|
||||
| tINFO tWND expr_value tEOL { DEBUG_InfoWindow( (HWND)$3 );
|
||||
DEBUG_FreeExprMem(); }
|
||||
| tINFO tLOCAL tEOL { DEBUG_InfoLocals(); }
|
||||
| tINFO tDISPLAY tEOL { DEBUG_InfoDisplay(); }
|
||||
|
||||
walk_command:
|
||||
tWALK tCLASS tEOL { CLASS_WalkClasses(); }
|
||||
| tWALK tMODULE tEOL { NE_WalkModules(); }
|
||||
| tWALK tQUEUE tEOL { QUEUE_WalkQueues(); }
|
||||
| tWALK tWND tEOL { WIN_WalkWindows( 0, 0 ); }
|
||||
| tWALK tWND tNUM tEOL { WIN_WalkWindows( $3, 0 ); }
|
||||
| tWALK tPROCESS tEOL { PROCESS_WalkProcess(); }
|
||||
| tWALK tMODREF expr_value tEOL { MODULE_WalkModref( $3 ); }
|
||||
tWALK tCLASS tEOL { DEBUG_WalkClasses(); }
|
||||
| tWALK tMODULE tEOL { DEBUG_WalkModules(); }
|
||||
| tWALK tQUEUE tEOL { DEBUG_WalkQueues(); }
|
||||
| tWALK tWND tEOL { DEBUG_WalkWindows( 0, 0 ); }
|
||||
| tWALK tWND tNUM tEOL { DEBUG_WalkWindows( $3, 0 ); }
|
||||
| tWALK tPROCESS tEOL { DEBUG_WalkProcess(); }
|
||||
| tWALK tMODREF expr_value tEOL { DEBUG_WalkModref( $3 ); }
|
||||
|
||||
|
||||
type_cast:
|
||||
|
@ -326,11 +293,13 @@ type_expr:
|
|||
| tENUM tIDENTIFIER { $$ = DEBUG_TypeCast(DT_ENUM, $2); }
|
||||
|
||||
expr_addr:
|
||||
expr { $$ = DEBUG_EvalExpr($1); }
|
||||
expr { $$ = DEBUG_EvalExpr($1); }
|
||||
|
||||
expr_value:
|
||||
expr { DBG_ADDR addr = DEBUG_EvalExpr($1);
|
||||
$$ = addr.off ? *(unsigned int *) addr.off : 0; }
|
||||
expr { DBG_ADDR addr = DEBUG_EvalExpr($1);
|
||||
/* expr_value is typed as an integer */
|
||||
if (!addr.off || !DEBUG_READ_MEM((void*)addr.off, &$$, sizeof($$)))
|
||||
$$ = 0; }
|
||||
/*
|
||||
* The expr rule builds an expression tree. When we are done, we call
|
||||
* EvalExpr to evaluate the value of the expression. The advantage of
|
||||
|
@ -410,50 +379,27 @@ issue_prompt(){
|
|||
|
||||
void mode_command(int newmode)
|
||||
{
|
||||
if ((newmode == 16) || (newmode == 32)) dbg_mode = newmode;
|
||||
if ((newmode == 16) || (newmode == 32)) DEBUG_CurrThread->dbg_mode = newmode;
|
||||
else fprintf(stderr,"Invalid mode (use 16 or 32)\n");
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_Freeze
|
||||
*/
|
||||
static void DEBUG_Freeze( BOOL freeze )
|
||||
static WINE_EXCEPTION_FILTER(no_symbol)
|
||||
{
|
||||
static BOOL frozen = FALSE;
|
||||
|
||||
if ( freeze && !frozen )
|
||||
{
|
||||
if ( X11DRV_CritSection.LockSemaphore )
|
||||
{
|
||||
/* Don't freeze thread currently holding the X crst! */
|
||||
EnterCriticalSection( &X11DRV_CritSection );
|
||||
CLIENT_DebuggerRequest( DEBUGGER_FREEZE_ALL );
|
||||
LeaveCriticalSection( &X11DRV_CritSection );
|
||||
}
|
||||
else
|
||||
CLIENT_DebuggerRequest( DEBUGGER_FREEZE_ALL );
|
||||
|
||||
frozen = TRUE;
|
||||
}
|
||||
|
||||
if ( !freeze && frozen )
|
||||
{
|
||||
CLIENT_DebuggerRequest( DEBUGGER_UNFREEZE_ALL );
|
||||
frozen = FALSE;
|
||||
}
|
||||
if (GetExceptionCode() == DEBUG_STATUS_NO_SYMBOL)
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_Exit
|
||||
*
|
||||
* Kill current process.
|
||||
*
|
||||
*/
|
||||
void DEBUG_Exit( DWORD exit_code )
|
||||
{
|
||||
DEBUG_Freeze( FALSE );
|
||||
|
||||
TASK_KillTask( 0 ); /* FIXME: should not be necessary */
|
||||
TerminateProcess( GetCurrentProcess(), exit_code );
|
||||
TASK_KillTask( 0 ); /* FIXME: should not be necessary */
|
||||
TerminateProcess( DEBUG_CurrProcess->handle, exit_code );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -461,261 +407,131 @@ void DEBUG_Exit( DWORD exit_code )
|
|||
*
|
||||
* Debugger main loop.
|
||||
*/
|
||||
static void DEBUG_Main( BOOL is_debug )
|
||||
BOOL DEBUG_Main( BOOL is_debug, BOOL force )
|
||||
{
|
||||
static int loaded_symbols = 0;
|
||||
static BOOL in_debugger = FALSE;
|
||||
char SymbolTableFile[256];
|
||||
int newmode;
|
||||
BOOL ret_ok;
|
||||
char ch;
|
||||
|
||||
#ifdef YYDEBUG
|
||||
yydebug = 0;
|
||||
#endif
|
||||
|
||||
if (in_debugger)
|
||||
{
|
||||
fprintf( stderr, " inside debugger, trying to invoke external debugger.\n" );
|
||||
DEBUG_ExternalDebugger();
|
||||
DEBUG_Exit(1);
|
||||
}
|
||||
in_debugger = TRUE;
|
||||
yyin = stdin;
|
||||
|
||||
DEBUG_SetBreakpoints( FALSE );
|
||||
DEBUG_SuspendExecution();
|
||||
|
||||
if (!is_debug)
|
||||
{
|
||||
#ifdef __i386__
|
||||
if (IS_SELECTOR_SYSTEM(CS_reg(&DEBUG_context)))
|
||||
fprintf( stderr, " in 32-bit code (0x%08lx).\n", EIP_reg(&DEBUG_context));
|
||||
if (DEBUG_IsSelectorSystem(DEBUG_context.SegCs))
|
||||
fprintf( stderr, " in 32-bit code (0x%08lx).\n", DEBUG_context.Eip );
|
||||
else
|
||||
fprintf( stderr, " in 16-bit code (%04x:%04lx).\n",
|
||||
(WORD)CS_reg(&DEBUG_context), EIP_reg(&DEBUG_context) );
|
||||
(WORD)DEBUG_context.SegCs, DEBUG_context.Eip );
|
||||
#else
|
||||
fprintf( stderr, " (%p).\n", GET_IP(&DEBUG_context) );
|
||||
fprintf( stderr, " (%p).\n", GET_IP(DEBUG_CurrThread->context) );
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!loaded_symbols)
|
||||
{
|
||||
loaded_symbols++;
|
||||
if (DEBUG_LoadEntryPoints("Loading new modules symbols:\n"))
|
||||
DEBUG_ProcessDeferredDebug();
|
||||
|
||||
DEBUG_Freeze( TRUE );
|
||||
|
||||
#ifdef DBG_need_heap
|
||||
/*
|
||||
* Initialize the debugger heap.
|
||||
*/
|
||||
dbg_heap = HeapCreate(HEAP_NO_SERIALIZE, 0x1000, 0x8000000); /* 128MB */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize the type handling stuff.
|
||||
*/
|
||||
DEBUG_InitTypes();
|
||||
DEBUG_InitCVDataTypes();
|
||||
|
||||
/*
|
||||
* In some cases we can read the stabs information directly
|
||||
* from the executable. If this is the case, we don't need
|
||||
* to bother with trying to read a symbol file, as the stabs
|
||||
* also have line number and local variable information.
|
||||
* As long as gcc is used for the compiler, stabs will
|
||||
* be the default. On SVr4, DWARF could be used, but we
|
||||
* don't grok that yet, and in this case we fall back to using
|
||||
* the wine.sym file.
|
||||
*/
|
||||
if( DEBUG_ReadExecutableDbgInfo() == FALSE )
|
||||
{
|
||||
char *symfilename = "wine.sym";
|
||||
struct stat statbuf;
|
||||
if (-1 == stat(symfilename, &statbuf) )
|
||||
symfilename = LIBDIR "wine.sym";
|
||||
|
||||
PROFILE_GetWineIniString( "wine", "SymbolTableFile", symfilename,
|
||||
SymbolTableFile, sizeof(SymbolTableFile));
|
||||
DEBUG_ReadSymbolTable( SymbolTableFile );
|
||||
}
|
||||
DEBUG_LoadEntryPoints(NULL);
|
||||
DEBUG_ProcessDeferredDebug();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DEBUG_LoadEntryPoints("Loading new modules symbols:\n"))
|
||||
DEBUG_ProcessDeferredDebug();
|
||||
}
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "Entering debugger PC=%x, mode=%d, count=%d\n",
|
||||
EIP_reg(&DEBUG_context),
|
||||
dbg_exec_mode, dbg_exec_count);
|
||||
|
||||
sleep(1);
|
||||
#endif
|
||||
|
||||
if (!is_debug || !DEBUG_ShouldContinue( dbg_exec_mode, &dbg_exec_count ))
|
||||
if (force || !(is_debug && DEBUG_ShouldContinue( DEBUG_CurrThread->dbg_exec_mode, &DEBUG_CurrThread->dbg_exec_count )))
|
||||
{
|
||||
DBG_ADDR addr;
|
||||
DEBUG_GetCurrentAddress( &addr );
|
||||
|
||||
DEBUG_Freeze( TRUE );
|
||||
|
||||
/* Put the display in a correct state */
|
||||
if (USER_Driver) USER_Driver->pBeginDebugging();
|
||||
/* EPP if (USER_Driver) USER_Driver->pBeginDebugging(); */
|
||||
|
||||
#ifdef __i386__
|
||||
newmode = ISV86(&DEBUG_context) ? 16 : IS_SELECTOR_32BIT(addr.seg) ? 32 : 16;
|
||||
switch (newmode = DEBUG_GetSelectorType(addr.seg)) {
|
||||
case 16: case 32: break;
|
||||
default: fprintf(stderr, "Bad CS (%ld)\n", addr.seg); newmode = 32;
|
||||
}
|
||||
#else
|
||||
newmode = 32;
|
||||
#endif
|
||||
if (newmode != dbg_mode)
|
||||
fprintf(stderr,"In %d bit mode.\n", dbg_mode = newmode);
|
||||
if (newmode != DEBUG_CurrThread->dbg_mode)
|
||||
fprintf(stderr,"In %d bit mode.\n", DEBUG_CurrThread->dbg_mode = newmode);
|
||||
|
||||
DEBUG_DoDisplay();
|
||||
|
||||
if (!is_debug) /* This is a real crash, dump some info */
|
||||
{
|
||||
DEBUG_InfoRegisters();
|
||||
DEBUG_InfoStack();
|
||||
#ifdef __i386__
|
||||
if (dbg_mode == 16)
|
||||
{
|
||||
LDT_Print( SELECTOR_TO_ENTRY(DS_reg(&DEBUG_context)), 1 );
|
||||
if (ES_reg(&DEBUG_context) != DS_reg(&DEBUG_context))
|
||||
LDT_Print( SELECTOR_TO_ENTRY(ES_reg(&DEBUG_context)), 1 );
|
||||
}
|
||||
LDT_Print( SELECTOR_TO_ENTRY(FS_reg(&DEBUG_context)), 1 );
|
||||
#endif
|
||||
DEBUG_BackTrace();
|
||||
}
|
||||
else
|
||||
if (is_debug || force)
|
||||
{
|
||||
/*
|
||||
* Do a quiet backtrace so that we have an idea of what the situation
|
||||
* is WRT the source files.
|
||||
*/
|
||||
DEBUG_SilentBackTrace();
|
||||
DEBUG_BackTrace(FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a real crash, dump some info */
|
||||
DEBUG_InfoRegisters();
|
||||
DEBUG_InfoStack();
|
||||
#ifdef __i386__
|
||||
if (DEBUG_CurrThread->dbg_mode == 16)
|
||||
{
|
||||
DEBUG_InfoSegments( DEBUG_context.SegDs >> 3, 1 );
|
||||
if (DEBUG_context.SegEs != DEBUG_context.SegDs)
|
||||
DEBUG_InfoSegments( DEBUG_context.SegEs >> 3, 1 );
|
||||
}
|
||||
DEBUG_InfoSegments( DEBUG_context.SegFs >> 3, 1 );
|
||||
#endif
|
||||
DEBUG_BackTrace(TRUE);
|
||||
}
|
||||
|
||||
if (!is_debug ||
|
||||
(dbg_exec_mode == EXEC_STEPI_OVER) ||
|
||||
(dbg_exec_mode == EXEC_STEPI_INSTR))
|
||||
(DEBUG_CurrThread->dbg_exec_mode == EXEC_STEPI_OVER) ||
|
||||
(DEBUG_CurrThread->dbg_exec_mode == EXEC_STEPI_INSTR))
|
||||
{
|
||||
/* Show where we crashed */
|
||||
curr_frame = 0;
|
||||
DEBUG_PrintAddress( &addr, dbg_mode, TRUE );
|
||||
DEBUG_PrintAddress( &addr, DEBUG_CurrThread->dbg_mode, TRUE );
|
||||
fprintf(stderr,": ");
|
||||
if (DBG_CHECK_READ_PTR( &addr, 1 ))
|
||||
{
|
||||
DEBUG_Disasm( &addr, TRUE );
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
DEBUG_Disasm( &addr, TRUE );
|
||||
fprintf( stderr, "\n" );
|
||||
}
|
||||
|
||||
ret_ok = 0;
|
||||
do
|
||||
{
|
||||
issue_prompt();
|
||||
yyparse();
|
||||
flush_symbols();
|
||||
__TRY
|
||||
{
|
||||
issue_prompt();
|
||||
yyparse();
|
||||
flush_symbols();
|
||||
|
||||
DEBUG_GetCurrentAddress( &addr );
|
||||
if ((ret_ok = DEBUG_ValidateRegisters()))
|
||||
ret_ok = DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear( &addr ), &ch, 1 );
|
||||
}
|
||||
__EXCEPT(no_symbol)
|
||||
{
|
||||
fprintf(stderr, "Undefined symbol\n");
|
||||
ret_ok = 0;
|
||||
}
|
||||
__ENDTRY;
|
||||
|
||||
DEBUG_GetCurrentAddress( &addr );
|
||||
ret_ok = DEBUG_ValidateRegisters();
|
||||
if (ret_ok) ret_ok = DBG_CHECK_READ_PTR( &addr, 1 );
|
||||
} while (!ret_ok);
|
||||
}
|
||||
|
||||
dbg_exec_mode = DEBUG_RestartExecution( dbg_exec_mode, dbg_exec_count );
|
||||
DEBUG_CurrThread->dbg_exec_mode = DEBUG_RestartExecution( DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count );
|
||||
/*
|
||||
* This will have gotten absorbed into the breakpoint info
|
||||
* if it was used. Otherwise it would have been ignored.
|
||||
* In any case, we don't mess with it any more.
|
||||
*/
|
||||
if ((dbg_exec_mode == EXEC_CONT) || (dbg_exec_mode == EXEC_PASS))
|
||||
{
|
||||
dbg_exec_count = 0;
|
||||
if ((DEBUG_CurrThread->dbg_exec_mode == EXEC_CONT) || (DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS))
|
||||
DEBUG_CurrThread->dbg_exec_count = 0;
|
||||
|
||||
DEBUG_Freeze( FALSE );
|
||||
}
|
||||
|
||||
in_debugger = FALSE;
|
||||
|
||||
if (USER_Driver) USER_Driver->pEndDebugging();
|
||||
/* EPP if (USER_Driver) USER_Driver->pEndDebugging(); */
|
||||
|
||||
return (DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS) ? 0 : DBG_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
DWORD wine_debugger( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
|
||||
{
|
||||
BOOL is_debug = FALSE;
|
||||
|
||||
if (first_chance && !Options.debug) return 0; /* pass to app first */
|
||||
|
||||
switch(rec->ExceptionCode)
|
||||
{
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
is_debug = TRUE;
|
||||
break;
|
||||
case CONTROL_C_EXIT:
|
||||
if (!Options.debug) DEBUG_Exit(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_debug)
|
||||
{
|
||||
/* print some infos */
|
||||
fprintf( stderr, "%s: ",
|
||||
first_chance ? "First chance exception" : "Unhandled exception" );
|
||||
switch(rec->ExceptionCode)
|
||||
{
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
fprintf( stderr, "divide by zero" );
|
||||
break;
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
fprintf( stderr, "overflow" );
|
||||
break;
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
fprintf( stderr, "array bounds " );
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
fprintf( stderr, "illegal instruction" );
|
||||
break;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
fprintf( stderr, "stack overflow" );
|
||||
break;
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
fprintf( stderr, "priviledged instruction" );
|
||||
break;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
if (rec->NumberParameters == 2)
|
||||
fprintf( stderr, "page fault on %s access to 0x%08lx",
|
||||
rec->ExceptionInformation[0] ? "write" : "read",
|
||||
rec->ExceptionInformation[1] );
|
||||
else
|
||||
fprintf( stderr, "page fault" );
|
||||
break;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
fprintf( stderr, "Alignment" );
|
||||
break;
|
||||
case CONTROL_C_EXIT:
|
||||
fprintf( stderr, "^C" );
|
||||
break;
|
||||
case EXCEPTION_CRITICAL_SECTION_WAIT:
|
||||
fprintf( stderr, "critical section %08lx wait failed", rec->ExceptionInformation[0] );
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "%08lx", rec->ExceptionCode );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_context = *context;
|
||||
DEBUG_Main( is_debug );
|
||||
*context = DEBUG_context;
|
||||
return (dbg_exec_mode == EXEC_PASS) ? 0 : DBG_CONTINUE;
|
||||
}
|
||||
|
||||
int yyerror(char * s)
|
||||
int yyerror(char* s)
|
||||
{
|
||||
fprintf(stderr,"%s\n", s);
|
||||
return 0;
|
||||
|
|
|
@ -119,7 +119,6 @@ $gs { yylval.reg = REG_GS; return tREG; }
|
|||
<INITIAL>frame|fram|fra|fr { BEGIN(NOCMD); return tFRAME; }
|
||||
<INITIAL>list|lis|li|l { BEGIN(PATH_EXPECTED); return tLIST; }
|
||||
<INITIAL>enable|enabl|enab|ena { BEGIN(NOCMD); return tENABLE;}
|
||||
<INITIAL>debugmsg|debugms|debugm|debug|debu|deb { BEGIN(DEBUGSTR); return tDEBUGMSG;}
|
||||
<INITIAL>disable|disabl|disab|disa|dis { BEGIN(NOCMD); return tDISABLE; }
|
||||
<INITIAL>disassemble|disassembl|disassemb|disassem|disasse|disass|disas { BEGIN(NOCMD); return tDISASSEMBLE; }
|
||||
<INITIAL,INFO_CMD,DEL_CMD>display|displa|displ|disp { BEGIN(FORMAT_EXPECTED); return tDISPLAY; }
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
|
||||
#include <sys/types.h> /* u_long ... */
|
||||
#include "windef.h"
|
||||
#include "miscemu.h"
|
||||
#include "winbase.h"
|
||||
|
||||
#ifdef __i386__
|
||||
#define STEP_FLAG 0x100 /* single step flag */
|
||||
#define V86_FLAG 0x00020000
|
||||
#endif
|
||||
|
||||
#define SYM_FUNC 0x0
|
||||
#define SYM_DATA 0x1
|
||||
|
@ -83,43 +86,73 @@ struct wine_locals {
|
|||
|
||||
typedef struct wine_locals WineLocals;
|
||||
|
||||
enum exec_mode
|
||||
{
|
||||
EXEC_CONT, /* Continuous execution */
|
||||
EXEC_PASS, /* Continue, passing exception to app */
|
||||
EXEC_STEP_OVER, /* Stepping over a call to next source line */
|
||||
EXEC_STEP_INSTR, /* Step to next source line, stepping in if needed */
|
||||
EXEC_STEPI_OVER, /* Stepping over a call */
|
||||
EXEC_STEPI_INSTR, /* Single-stepping an instruction */
|
||||
EXEC_FINISH, /* Step until we exit current frame */
|
||||
EXEC_STEP_OVER_TRAMPOLINE /* Step over trampoline. Requires that
|
||||
* we dig the real return value off the stack
|
||||
* and set breakpoint there - not at the
|
||||
* instr just after the call.
|
||||
*/
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DBG_ADDR addr;
|
||||
BYTE addrlen;
|
||||
BYTE opcode;
|
||||
WORD skipcount;
|
||||
WORD enabled : 1,
|
||||
refcount;
|
||||
struct expr * condition;
|
||||
} BREAKPOINT;
|
||||
|
||||
typedef struct tagWINE_DBG_THREAD {
|
||||
struct tagWINE_DBG_PROCESS* process;
|
||||
HANDLE handle;
|
||||
DWORD tid;
|
||||
LPVOID start;
|
||||
LPVOID teb;
|
||||
int wait_for_first_exception;
|
||||
int dbg_mode;
|
||||
enum exec_mode dbg_exec_mode;
|
||||
int dbg_exec_count;
|
||||
BREAKPOINT stepOverBP;
|
||||
struct tagWINE_DBG_THREAD* next;
|
||||
struct tagWINE_DBG_THREAD* prev;
|
||||
} WINE_DBG_THREAD;
|
||||
|
||||
typedef struct tagWINE_DBG_PROCESS {
|
||||
HANDLE handle;
|
||||
DWORD pid;
|
||||
WINE_DBG_THREAD* threads;
|
||||
struct tagWINE_DBG_PROCESS* next;
|
||||
struct tagWINE_DBG_PROCESS* prev;
|
||||
} WINE_DBG_PROCESS;
|
||||
|
||||
extern WINE_DBG_PROCESS* DEBUG_CurrProcess;
|
||||
extern WINE_DBG_THREAD* DEBUG_CurrThread;
|
||||
extern CONTEXT DEBUG_context;
|
||||
|
||||
#define DEBUG_READ_MEM(addr, buf, len) \
|
||||
(ReadProcessMemory(DEBUG_CurrProcess->handle, (addr), (buf), (len), NULL))
|
||||
|
||||
#define DEBUG_WRITE_MEM(addr, buf, len) \
|
||||
(WriteProcessMemory(DEBUG_CurrProcess->handle, (addr), (buf), (len), NULL))
|
||||
|
||||
#define DEBUG_READ_MEM_VERBOSE(addr, buf, len) \
|
||||
(DEBUG_READ_MEM((addr), (buf), (len)) || (DEBUG_InvalLinAddr( addr ),0))
|
||||
|
||||
#define DEBUG_WRITE_MEM_VERBOSE(addr, buf, len) \
|
||||
(DEBUG_WRITE_MEM((addr), (buf), (len)) || (DEBUG_InvalLinAddr( addr ),0))
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#define DBG_V86_MODULE(seg) ((seg)>>16)
|
||||
#define IS_SELECTOR_V86(seg) DBG_V86_MODULE(seg)
|
||||
|
||||
#define DBG_FIX_ADDR_SEG(addr,default) { \
|
||||
if ((addr)->seg == 0xffffffff) (addr)->seg = (default); \
|
||||
if (!IS_SELECTOR_V86((addr)->seg)) \
|
||||
if (IS_SELECTOR_SYSTEM((addr)->seg)) (addr)->seg = 0; }
|
||||
|
||||
#define DBG_ADDR_TO_LIN(addr) \
|
||||
(IS_SELECTOR_V86((addr)->seg) \
|
||||
? (char*)(DOSMEM_MemoryBase(DBG_V86_MODULE((addr)->seg)) + \
|
||||
((((addr)->seg)&0xFFFF)<<4)+(addr)->off) : \
|
||||
(IS_SELECTOR_SYSTEM((addr)->seg) ? (char *)(addr)->off \
|
||||
: (char *)PTR_SEG_OFF_TO_LIN((addr)->seg,(addr)->off)))
|
||||
|
||||
#else /* __i386__ */
|
||||
|
||||
#define DBG_FIX_ADDR_SEG(addr,default)
|
||||
#define DBG_ADDR_TO_LIN(addr) ((char *)(addr)->off)
|
||||
|
||||
#endif /* __386__ */
|
||||
|
||||
#define DBG_CHECK_READ_PTR(addr,len) \
|
||||
(!DEBUG_IsBadReadPtr((addr),(len)) || \
|
||||
(fprintf(stderr,"*** Invalid address "), \
|
||||
DEBUG_PrintAddress((addr),dbg_mode, FALSE), \
|
||||
fprintf(stderr,"\n"),0))
|
||||
|
||||
#define DBG_CHECK_WRITE_PTR(addr,len) \
|
||||
(!DEBUG_IsBadWritePtr((addr),(len)) || \
|
||||
(fprintf(stderr,"*** Invalid address "), \
|
||||
DEBUG_PrintAddress(addr,dbg_mode, FALSE), \
|
||||
fprintf(stderr,"\n"),0))
|
||||
|
||||
#ifdef REG_SP /* Some Sun includes define this */
|
||||
#undef REG_SP
|
||||
#endif
|
||||
|
@ -128,42 +161,24 @@ enum debug_regs
|
|||
{
|
||||
REG_EAX, REG_EBX, REG_ECX, REG_EDX, REG_ESI,
|
||||
REG_EDI, REG_EBP, REG_EFL, REG_EIP, REG_ESP,
|
||||
REG_AX, REG_BX, REG_CX, REG_DX, REG_SI,
|
||||
REG_DI, REG_BP, REG_FL, REG_IP, REG_SP,
|
||||
REG_CS, REG_DS, REG_ES, REG_SS, REG_FS, REG_GS
|
||||
REG_AX, REG_BX, REG_CX, REG_DX, REG_SI,
|
||||
REG_DI, REG_BP, REG_FL, REG_IP, REG_SP,
|
||||
REG_CS, REG_DS, REG_ES, REG_SS, REG_FS, REG_GS
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
enum exec_mode
|
||||
{
|
||||
EXEC_CONT, /* Continuous execution */
|
||||
EXEC_PASS, /* Continue, passing exception to app */
|
||||
EXEC_STEP_OVER, /* Stepping over a call to next source line */
|
||||
EXEC_STEP_INSTR, /* Step to next source line, stepping in if needed */
|
||||
EXEC_STEPI_OVER, /* Stepping over a call */
|
||||
EXEC_STEPI_INSTR, /* Single-stepping an instruction */
|
||||
EXEC_FINISH, /* Step until we exit current frame */
|
||||
EXEC_STEP_OVER_TRAMPOLINE /* Step over trampoline. Requires that
|
||||
* we dig the real return value off the stack
|
||||
* and set breakpoint there - not at the
|
||||
* instr just after the call.
|
||||
*/
|
||||
};
|
||||
|
||||
extern CONTEXT DEBUG_context; /* debugger/registers.c */
|
||||
extern unsigned int dbg_mode;
|
||||
extern HANDLE dbg_heap;
|
||||
#define OFFSET_OF(__c,__f) ((int)(((char*)&(((__c*)0)->__f))-((char*)0)))
|
||||
|
||||
/* debugger/break.c */
|
||||
extern void DEBUG_SetBreakpoints( BOOL set );
|
||||
extern int DEBUG_FindBreakpoint( const DBG_ADDR *addr );
|
||||
extern int DEBUG_FindBreakpoint( const DBG_ADDR *addr );
|
||||
extern void DEBUG_AddBreakpoint( const DBG_ADDR *addr );
|
||||
extern void DEBUG_DelBreakpoint( int num );
|
||||
extern void DEBUG_EnableBreakpoint( int num, BOOL enable );
|
||||
extern void DEBUG_InfoBreakpoints(void);
|
||||
extern void DEBUG_AddTaskEntryBreakpoint( HTASK16 hTask );
|
||||
extern BOOL DEBUG_HandleTrap(void);
|
||||
extern BOOL DEBUG_ShouldContinue( enum exec_mode mode, int * count );
|
||||
extern void DEBUG_SuspendExecution( void );
|
||||
extern enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count );
|
||||
extern BOOL DEBUG_IsFctReturn(void);
|
||||
|
||||
|
@ -185,8 +200,8 @@ struct expr * DEBUG_StructExpr(struct expr *, const char * element);
|
|||
struct expr * DEBUG_ArrayExpr(struct expr *, struct expr * index);
|
||||
struct expr * DEBUG_CallExpr(const char *, int nargs, ...);
|
||||
struct expr * DEBUG_TypeCastExpr(struct datatype *, struct expr *);
|
||||
extern int DEBUG_ExprValue(DBG_ADDR *, unsigned int *);
|
||||
DBG_ADDR DEBUG_EvalExpr(struct expr *);
|
||||
extern int DEBUG_ExprValue(const DBG_ADDR *, unsigned int *);
|
||||
extern DBG_ADDR DEBUG_EvalExpr(struct expr *);
|
||||
extern int DEBUG_DelDisplay(int displaynum);
|
||||
extern struct expr * DEBUG_CloneExpr(struct expr * exp);
|
||||
extern int DEBUG_FreeExpr(struct expr * exp);
|
||||
|
@ -211,7 +226,7 @@ extern struct name_hash * DEBUG_AddInvSymbol( const char *name,
|
|||
const DBG_ADDR *addr,
|
||||
const char * sourcefile);
|
||||
extern BOOL DEBUG_GetSymbolValue( const char * name, const int lineno,
|
||||
DBG_ADDR *addr, int );
|
||||
DBG_ADDR *addr, int );
|
||||
extern BOOL DEBUG_SetSymbolValue( const char * name, const DBG_ADDR *addr );
|
||||
extern const char * DEBUG_FindNearestSymbol( const DBG_ADDR *addr, int flag,
|
||||
struct name_hash ** rtn,
|
||||
|
@ -251,13 +266,32 @@ extern struct symbol_info DEBUG_PrintAddressAndArgs( const DBG_ADDR *addr,
|
|||
int addrlen,
|
||||
unsigned int ebp,
|
||||
int flag );
|
||||
extern void DEBUG_InfoClass(const char* clsName);
|
||||
extern void DEBUG_WalkClasses(void);
|
||||
extern void DEBUG_WalkModref(DWORD p);
|
||||
extern void DEBUG_DumpModule(DWORD mod);
|
||||
extern void DEBUG_WalkModules(void);
|
||||
extern void DEBUG_WalkProcess(void);
|
||||
extern void DEBUG_DumpQueue(DWORD q);
|
||||
extern void DEBUG_WalkQueues(void);
|
||||
extern void DEBUG_InfoSegments(DWORD s, int v);
|
||||
extern void DEBUG_InfoVirtual(void);
|
||||
extern void DEBUG_InfoWindow(HWND hWnd);
|
||||
extern void DEBUG_WalkWindows(HWND hWnd, int indent);
|
||||
|
||||
/* debugger/memory.c */
|
||||
extern BOOL DEBUG_IsBadReadPtr( const DBG_ADDR *address, int size );
|
||||
extern BOOL DEBUG_IsBadWritePtr( const DBG_ADDR *address, int size );
|
||||
extern int DEBUG_ReadMemory( const DBG_ADDR *address );
|
||||
extern void DEBUG_WriteMemory( const DBG_ADDR *address, int value );
|
||||
extern void DEBUG_ExamineMemory( const DBG_ADDR *addr, int count, char format);
|
||||
extern void DEBUG_InvalLinAddr( void* addr );
|
||||
#ifdef __i386__
|
||||
extern void DEBUG_GetCurrentAddress( DBG_ADDR * );
|
||||
extern DWORD DEBUG_ToLinear( const DBG_ADDR *address );
|
||||
extern void DEBUG_FixAddress( DBG_ADDR *address, DWORD def );
|
||||
extern BOOL DEBUG_FixSegment( DBG_ADDR* addr );
|
||||
extern int DEBUG_GetSelectorType( WORD sel );
|
||||
extern int DEBUG_IsSelectorSystem( WORD sel );
|
||||
#endif
|
||||
|
||||
/* debugger/registers.c */
|
||||
extern void DEBUG_SetRegister( enum debug_regs reg, int val );
|
||||
|
@ -268,8 +302,7 @@ extern int DEBUG_PrintRegister(enum debug_regs reg);
|
|||
|
||||
/* debugger/stack.c */
|
||||
extern void DEBUG_InfoStack(void);
|
||||
extern void DEBUG_BackTrace(void);
|
||||
extern void DEBUG_SilentBackTrace(void);
|
||||
extern void DEBUG_BackTrace(BOOL noisy);
|
||||
extern int DEBUG_InfoLocals(void);
|
||||
extern int DEBUG_SetFrame(int newframe);
|
||||
extern int DEBUG_GetCurrentFrame(struct name_hash ** name,
|
||||
|
@ -293,7 +326,7 @@ extern void DEBUG_InitTypes(void);
|
|||
extern struct datatype * DEBUG_NewDataType(enum debug_type xtype,
|
||||
const char * typename);
|
||||
extern unsigned int
|
||||
DEBUG_TypeDerefPointer(DBG_ADDR * addr, struct datatype ** newtype);
|
||||
DEBUG_TypeDerefPointer(const DBG_ADDR * addr, struct datatype ** newtype);
|
||||
extern int DEBUG_AddStructElement(struct datatype * dt,
|
||||
char * name, struct datatype * type,
|
||||
int offset, int size);
|
||||
|
@ -306,9 +339,9 @@ extern unsigned int DEBUG_FindStructElement(DBG_ADDR * addr,
|
|||
const char * ele_name, int * tmpbuf);
|
||||
extern struct datatype * DEBUG_GetPointerType(struct datatype * dt);
|
||||
extern int DEBUG_GetObjectSize(struct datatype * dt);
|
||||
extern unsigned int DEBUG_ArrayIndex(DBG_ADDR * addr, DBG_ADDR * result, int index);
|
||||
extern unsigned int DEBUG_ArrayIndex(const DBG_ADDR * addr, DBG_ADDR * result, int index);
|
||||
extern struct datatype * DEBUG_FindOrMakePointerType(struct datatype * reftype);
|
||||
extern long long int DEBUG_GetExprValue(DBG_ADDR * addr, char ** format);
|
||||
extern long long int DEBUG_GetExprValue(const DBG_ADDR * addr, char ** format);
|
||||
extern int DEBUG_SetBitfieldParams(struct datatype * dt, int offset,
|
||||
int nbits, struct datatype * dt2);
|
||||
extern int DEBUG_CopyFieldlist(struct datatype * dt, struct datatype * dt2);
|
||||
|
@ -322,24 +355,26 @@ extern void DEBUG_AddPath(const char * path);
|
|||
extern void DEBUG_List(struct list_id * line1, struct list_id * line2,
|
||||
int delta);
|
||||
extern void DEBUG_NukePath(void);
|
||||
extern void DEBUG_GetCurrentAddress( DBG_ADDR * );
|
||||
extern void DEBUG_Disassemble( const DBG_ADDR *, const DBG_ADDR*, int offset );
|
||||
|
||||
/* debugger/external.c */
|
||||
extern void DEBUG_ExternalDebugger(void);
|
||||
|
||||
/* debugger/dbg.y */
|
||||
extern DWORD wine_debugger( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance );
|
||||
extern void DEBUG_Exit( DWORD exit_code );
|
||||
extern BOOL DEBUG_Main( BOOL is_debug, BOOL force );
|
||||
|
||||
/* Choose your allocator! */
|
||||
#if 1
|
||||
/* this one is libc's fast one */
|
||||
#include "xmalloc.h"
|
||||
#define DBG_alloc(x) xmalloc(x)
|
||||
#define DBG_realloc(x,y) xrealloc(x,y)
|
||||
#define DBG_free(x) free(x)
|
||||
#define DBG_strdup(x) xstrdup(x)
|
||||
extern void* DEBUG_XMalloc(size_t size);
|
||||
extern void* DEBUG_XReAlloc(void *ptr, size_t size);
|
||||
extern char* DEBUG_XStrDup(const char *str);
|
||||
|
||||
#define DBG_alloc(x) DEBUG_XMalloc(x)
|
||||
#define DBG_realloc(x,y) DEBUG_XReAlloc(x,y)
|
||||
#define DBG_free(x) free(x)
|
||||
#define DBG_strdup(x) DEBUG_XStrDup(x)
|
||||
#else
|
||||
/* this one is slow (takes 5 minutes to load the debugger on my machine),
|
||||
but is pretty crash-proof (can step through malloc() without problems,
|
||||
|
@ -352,6 +387,9 @@ extern void DEBUG_Exit( DWORD exit_code );
|
|||
#define DBG_free(x) HeapFree(dbg_heap,0,x)
|
||||
#define DBG_strdup(x) HEAP_strdupA(dbg_heap,0,x)
|
||||
#define DBG_need_heap
|
||||
extern HANDLE dbg_heap;
|
||||
#endif
|
||||
|
||||
#define DEBUG_STATUS_NO_SYMBOL 0x80003000
|
||||
|
||||
#endif /* __WINE_DEBUGGER_H */
|
|
@ -11,9 +11,6 @@
|
|||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "neexe.h"
|
||||
#include "module.h"
|
||||
#include "selectors.h"
|
||||
#include "debugger.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
|
|
@ -299,7 +299,6 @@ DEBUG_EvalExpr(struct expr * exp)
|
|||
DBG_ADDR exp1;
|
||||
DBG_ADDR exp2;
|
||||
unsigned int cexp[5];
|
||||
int (*fptr)();
|
||||
int scale1;
|
||||
int scale2;
|
||||
int scale3;
|
||||
|
@ -332,12 +331,20 @@ DEBUG_EvalExpr(struct expr * exp)
|
|||
rtn.seg = 0;
|
||||
break;
|
||||
case EXPR_TYPE_SYMBOL:
|
||||
if( !DEBUG_GetSymbolValue(exp->un.symbol.name, -1, &rtn, FALSE ) )
|
||||
{
|
||||
rtn.type = NULL;
|
||||
rtn.off = 0;
|
||||
rtn.seg = 0;
|
||||
};
|
||||
if( !DEBUG_GetSymbolValue(exp->un.symbol.name, -1, &rtn, FALSE) )
|
||||
{
|
||||
#if 1
|
||||
RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL);
|
||||
#else
|
||||
static char ret[128];
|
||||
|
||||
/* FIXME: this is an ugly hack... but at least we know
|
||||
* the symbol is not defined
|
||||
*/
|
||||
sprintf(ret, "\"Symbol %s is not defined.\"", exp->un.symbol.name);
|
||||
rtn = DEBUG_EvalExpr(DEBUG_StringExpr(ret));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case EXPR_TYPE_PSTRUCT:
|
||||
exp1 = DEBUG_EvalExpr(exp->un.structure.exp1);
|
||||
|
@ -388,6 +395,13 @@ DEBUG_EvalExpr(struct expr * exp)
|
|||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* FIXME: NEWDBG NIY */
|
||||
/* Anyway, I wonder how this could work depending on the calling order of
|
||||
* the function (cdecl vs pascal for example)
|
||||
*/
|
||||
int (*fptr)();
|
||||
|
||||
fptr = (int (*)()) rtn.off;
|
||||
switch(exp->un.call.nargs)
|
||||
{
|
||||
|
@ -410,8 +424,16 @@ DEBUG_EvalExpr(struct expr * exp)
|
|||
exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2], cexp[3], cexp[4]);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "Function call no longer implemented\n");
|
||||
/* would need to set up a call to this function, and then restore the current
|
||||
* context afterwards...
|
||||
*/
|
||||
exp->un.call.result = 0;
|
||||
#endif
|
||||
rtn.type = DEBUG_TypeInt;
|
||||
rtn.off = (unsigned int) &exp->un.call.result;
|
||||
|
||||
break;
|
||||
case EXPR_TYPE_REGISTER:
|
||||
rtn.type = DEBUG_TypeIntConst;
|
||||
|
@ -419,11 +441,11 @@ DEBUG_EvalExpr(struct expr * exp)
|
|||
rtn.off = (unsigned int) &exp->un.rgister.result;
|
||||
#ifdef __i386__
|
||||
if( exp->un.rgister.reg == REG_EIP )
|
||||
rtn.seg = CS_reg(&DEBUG_context);
|
||||
rtn.seg = DEBUG_context.SegCs;
|
||||
else
|
||||
rtn.seg = DS_reg(&DEBUG_context);
|
||||
rtn.seg = DEBUG_context.SegDs;
|
||||
#endif
|
||||
DBG_FIX_ADDR_SEG( &rtn, 0 );
|
||||
DEBUG_FixAddress( &rtn, 0 );
|
||||
break;
|
||||
case EXPR_TYPE_BINOP:
|
||||
exp1 = DEBUG_EvalExpr(exp->un.binop.exp1);
|
||||
|
@ -497,11 +519,7 @@ DEBUG_EvalExpr(struct expr * exp)
|
|||
rtn.seg = VAL(exp1);
|
||||
exp->un.binop.result = VAL(exp2);
|
||||
#ifdef __i386__
|
||||
if (ISV86(&DEBUG_context)) {
|
||||
TDB *pTask = (TDB*)GlobalLock16( GetCurrentTask() );
|
||||
rtn.seg |= (DWORD)(pTask?(pTask->hModule):0)<<16;
|
||||
GlobalUnlock16( GetCurrentTask() );
|
||||
}
|
||||
DEBUG_FixSegment(&rtn);
|
||||
#endif
|
||||
break;
|
||||
case EXP_OP_LOR:
|
||||
|
@ -623,12 +641,12 @@ DEBUG_EvalExpr(struct expr * exp)
|
|||
exp->un.unop.result = ~VAL(exp1);
|
||||
break;
|
||||
case EXP_OP_DEREF:
|
||||
rtn.seg = 0;
|
||||
rtn.seg = 0;
|
||||
rtn.off = (unsigned int) DEBUG_TypeDerefPointer(&exp1, &rtn.type);
|
||||
break;
|
||||
case EXP_OP_FORCE_DEREF:
|
||||
rtn.seg = exp1.seg;
|
||||
rtn.off = *(unsigned int *) exp1.off;
|
||||
rtn.off = DEBUG_READ_MEM((void*)exp1.off, &rtn.off, sizeof(rtn.off));
|
||||
break;
|
||||
case EXP_OP_ADDR:
|
||||
rtn.seg = 0;
|
||||
|
@ -686,10 +704,6 @@ DEBUG_DisplayExpr(struct expr * exp)
|
|||
fprintf(stderr, ".%s", exp->un.structure.element_name);
|
||||
break;
|
||||
case EXPR_TYPE_CALL:
|
||||
/*
|
||||
* First, evaluate all of the arguments. If any of them are not
|
||||
* evaluable, then bail.
|
||||
*/
|
||||
fprintf(stderr, "%s(",exp->un.call.funcname);
|
||||
for(i=0; i < exp->un.call.nargs; i++)
|
||||
{
|
||||
|
@ -841,10 +855,6 @@ DEBUG_CloneExpr(struct expr * exp)
|
|||
rtn->un.structure.element_name = DBG_strdup(exp->un.structure.element_name);
|
||||
break;
|
||||
case EXPR_TYPE_CALL:
|
||||
/*
|
||||
* First, evaluate all of the arguments. If any of them are not
|
||||
* evaluable, then bail.
|
||||
*/
|
||||
for(i=0; i < exp->un.call.nargs; i++)
|
||||
{
|
||||
rtn->un.call.arg[i] = DEBUG_CloneExpr(exp->un.call.arg[i]);
|
||||
|
@ -898,10 +908,6 @@ DEBUG_FreeExpr(struct expr * exp)
|
|||
DBG_free((char *) exp->un.structure.element_name);
|
||||
break;
|
||||
case EXPR_TYPE_CALL:
|
||||
/*
|
||||
* First, evaluate all of the arguments. If any of them are not
|
||||
* evaluable, then bail.
|
||||
*/
|
||||
for(i=0; i < exp->un.call.nargs; i++)
|
||||
{
|
||||
DEBUG_FreeExpr(exp->un.call.arg[i]);
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "neexe.h"
|
||||
#include "module.h"
|
||||
#include "process.h"
|
||||
#include "selectors.h"
|
||||
#include "debugger.h"
|
||||
#include "toolhelp.h"
|
||||
|
||||
|
@ -335,7 +334,7 @@ BOOL DEBUG_Normalize(struct name_hash * nh )
|
|||
* Get the address of a named symbol.
|
||||
*/
|
||||
BOOL DEBUG_GetSymbolValue( const char * name, const int lineno,
|
||||
DBG_ADDR *addr, int bp_flag )
|
||||
DBG_ADDR *addr, int bp_flag )
|
||||
{
|
||||
char buffer[256];
|
||||
struct name_hash *nh;
|
||||
|
@ -450,7 +449,7 @@ BOOL DEBUG_SetSymbolValue( const char * name, const DBG_ADDR *addr )
|
|||
if (!nh) return FALSE;
|
||||
nh->addr = *addr;
|
||||
nh->flags &= SYM_INVALID;
|
||||
DBG_FIX_ADDR_SEG( &nh->addr, DS_reg(&DEBUG_context) );
|
||||
DEBUG_FixAddress( &nh->addr, DEBUG_context.SegDs );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -477,6 +476,7 @@ const char * DEBUG_FindNearestSymbol( const DBG_ADDR *addr, int flag,
|
|||
char * lineinfo, *sourcefile;
|
||||
int i;
|
||||
char linebuff[16];
|
||||
unsigned val;
|
||||
|
||||
if( rtn != NULL )
|
||||
{
|
||||
|
@ -637,9 +637,9 @@ const char * DEBUG_FindNearestSymbol( const DBG_ADDR *addr, int flag,
|
|||
{
|
||||
strcat(arglist, ", ");
|
||||
}
|
||||
DEBUG_READ_MEM_VERBOSE(ptr, &val, sizeof(val));
|
||||
sprintf(argtmp, "%s=0x%x", nearest->local_vars[i].name, val);
|
||||
|
||||
sprintf(argtmp, "%s=0x%x", nearest->local_vars[i].name,
|
||||
*ptr);
|
||||
strcat(arglist, argtmp);
|
||||
}
|
||||
if( arglist[0] == '(' )
|
||||
|
@ -1367,13 +1367,26 @@ BOOL DEBUG_GetStackSymbolValue( const char * name, DBG_ADDR *addr )
|
|||
/* FIXME: what if regno == 0 ($eax) */
|
||||
if( curr_func->local_vars[i].regno != 0 )
|
||||
{
|
||||
#if 0
|
||||
/* FIXME: NEWDBG NIY */
|
||||
/* this is a hack: addr points to the current processor context
|
||||
* (as defined while entering the debugger), and uses a pointer
|
||||
* to main memory (thus sharing the process address space *AND*
|
||||
* the debugger address space, which is not good with address
|
||||
* space separation in place)
|
||||
*/
|
||||
/*
|
||||
* Register variable. Point to DEBUG_context field.
|
||||
*/
|
||||
addr->seg = 0;
|
||||
addr->off = ((DWORD)&DEBUG_context) + reg_ofs[curr_func->local_vars[i].regno];
|
||||
addr->off = ((DWORD)DEBUG_context) + reg_ofs[curr_func->local_vars[i].regno];
|
||||
addr->type = curr_func->local_vars[i].type;
|
||||
|
||||
#else
|
||||
fprintf(stderr, "No longer supported: value of register variable\n");
|
||||
addr->seg = 0;
|
||||
addr->off = 0;
|
||||
addr->type = NULL;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1395,7 +1408,7 @@ DEBUG_InfoLocals()
|
|||
unsigned int eip;
|
||||
int i;
|
||||
unsigned int * ptr;
|
||||
int rtn = FALSE;
|
||||
unsigned int val;
|
||||
|
||||
if( DEBUG_GetCurrentFrame(&curr_func, &eip, &ebp) == FALSE )
|
||||
{
|
||||
|
@ -1433,16 +1446,14 @@ DEBUG_InfoLocals()
|
|||
}
|
||||
else
|
||||
{
|
||||
ptr = (unsigned int *) (ebp + curr_func->local_vars[i].offset);
|
||||
DEBUG_READ_MEM_VERBOSE((void*)(ebp + curr_func->local_vars[i].offset),
|
||||
&val, sizeof(val));
|
||||
fprintf(stderr, "%s:%s == 0x%8.8x\n",
|
||||
curr_func->name, curr_func->local_vars[i].name,
|
||||
*ptr);
|
||||
curr_func->name, curr_func->local_vars[i].name, val);
|
||||
}
|
||||
}
|
||||
|
||||
rtn = TRUE;
|
||||
|
||||
return (rtn);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
267
debugger/info.c
267
debugger/info.c
|
@ -8,6 +8,10 @@
|
|||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
#include "toolhelp.h"
|
||||
#include "debugger.h"
|
||||
#include "expr.h"
|
||||
|
||||
|
@ -28,7 +32,7 @@ void DEBUG_PrintBasic( const DBG_ADDR *addr, int count, char format )
|
|||
}
|
||||
|
||||
default_format = NULL;
|
||||
value = DEBUG_GetExprValue((DBG_ADDR *) addr, &default_format);
|
||||
value = DEBUG_GetExprValue(addr, &default_format);
|
||||
|
||||
switch(format)
|
||||
{
|
||||
|
@ -188,3 +192,264 @@ NULL
|
|||
|
||||
while(infotext[i]) fprintf(stderr,"%s\n", infotext[i++]);
|
||||
}
|
||||
|
||||
/* FIXME: merge InfoClass and InfoClass2 */
|
||||
void DEBUG_InfoClass(const char* name)
|
||||
{
|
||||
WNDCLASSEXA wca;
|
||||
|
||||
if (!GetClassInfoExA(0, name, &wca)) {
|
||||
fprintf(stderr, "Cannot find class '%s'\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Class '%s':\n", name);
|
||||
fprintf(stderr,
|
||||
"style=%08x wndProc=%08lx\n"
|
||||
"inst=%04x icon=%04x cursor=%04x bkgnd=%04x\n"
|
||||
"clsExtra=%d winExtra=%d\n",
|
||||
wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
|
||||
wca.hIcon, wca.hCursor, wca.hbrBackground,
|
||||
wca.cbClsExtra, wca.cbWndExtra);
|
||||
|
||||
/* FIXME:
|
||||
* + print #windows (or even list of windows...)
|
||||
* + print extra bytes => this requires a window handle on this very class...
|
||||
*/
|
||||
}
|
||||
|
||||
static void DEBUG_InfoClass2(HWND hWnd, const char* name)
|
||||
{
|
||||
WNDCLASSEXA wca;
|
||||
|
||||
if (!GetClassInfoExA(GetWindowLongA(hWnd, GWL_HINSTANCE), name, &wca)) {
|
||||
fprintf(stderr, "Cannot find class '%s'\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Class '%s':\n", name);
|
||||
fprintf(stderr,
|
||||
"style=%08x wndProc=%08lx\n"
|
||||
"inst=%04x icon=%04x cursor=%04x bkgnd=%04x\n"
|
||||
"clsExtra=%d winExtra=%d\n",
|
||||
wca.style, (DWORD)wca.lpfnWndProc, wca.hInstance,
|
||||
wca.hIcon, wca.hCursor, wca.hbrBackground,
|
||||
wca.cbClsExtra, wca.cbWndExtra);
|
||||
|
||||
if (wca.cbClsExtra) {
|
||||
int i;
|
||||
WORD w;
|
||||
|
||||
fprintf(stderr, "Extra bytes:" );
|
||||
for (i = 0; i < wca.cbClsExtra / 2; i++) {
|
||||
w = GetClassWord(hWnd, i * 2);
|
||||
/* FIXME: depends on i386 endian-ity */
|
||||
fprintf(stderr, " %02x", HIBYTE(w));
|
||||
fprintf(stderr, " %02x", LOBYTE(w));
|
||||
}
|
||||
fprintf(stderr, "\n" );
|
||||
}
|
||||
fprintf(stderr, "\n" );
|
||||
}
|
||||
|
||||
struct class_walker {
|
||||
ATOM* table;
|
||||
int used;
|
||||
int alloc;
|
||||
};
|
||||
|
||||
static void DEBUG_WalkClassesHelper(HWND hWnd, struct class_walker* cw)
|
||||
{
|
||||
char clsName[128];
|
||||
int i;
|
||||
ATOM atom;
|
||||
HWND child;
|
||||
|
||||
if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
|
||||
return;
|
||||
if ((atom = FindAtomA(clsName)) == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < cw->used; i++) {
|
||||
if (cw->table[i] == atom)
|
||||
break;
|
||||
}
|
||||
if (i == cw->used) {
|
||||
if (cw->used >= cw->alloc) {
|
||||
cw->alloc += 16;
|
||||
cw->table = DBG_realloc(cw->table, cw->alloc * sizeof(ATOM));
|
||||
}
|
||||
cw->table[cw->used++] = atom;
|
||||
DEBUG_InfoClass2(hWnd, clsName);
|
||||
}
|
||||
do {
|
||||
if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
|
||||
DEBUG_WalkClassesHelper(child, cw);
|
||||
} while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
|
||||
}
|
||||
|
||||
void DEBUG_WalkClasses(void)
|
||||
{
|
||||
struct class_walker cw;
|
||||
|
||||
cw.table = NULL;
|
||||
cw.used = cw.alloc = 0;
|
||||
DEBUG_WalkClassesHelper(GetDesktopWindow(), &cw);
|
||||
DBG_free(cw.table);
|
||||
}
|
||||
|
||||
void DEBUG_DumpModule(DWORD mod)
|
||||
{
|
||||
fprintf(stderr, "No longer doing info module '0x%08lx'\n", mod);
|
||||
}
|
||||
|
||||
void DEBUG_WalkModules(void)
|
||||
{
|
||||
fprintf(stderr, "No longer walking modules list\n");
|
||||
}
|
||||
|
||||
void DEBUG_DumpQueue(DWORD q)
|
||||
{
|
||||
fprintf(stderr, "No longer doing info queue '0x%08lx'\n", q);
|
||||
}
|
||||
|
||||
void DEBUG_WalkQueues(void)
|
||||
{
|
||||
fprintf(stderr, "No longer walking queues list\n");
|
||||
}
|
||||
|
||||
void DEBUG_InfoWindow(HWND hWnd)
|
||||
{
|
||||
char clsName[128];
|
||||
char wndName[128];
|
||||
RECT clientRect;
|
||||
RECT windowRect;
|
||||
int i;
|
||||
WORD w;
|
||||
|
||||
if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
|
||||
strcpy(clsName, "-- Unknown --");
|
||||
if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
|
||||
strcpy(wndName, "-- Empty --");
|
||||
if (!GetClientRect(hWnd, &clientRect))
|
||||
SetRectEmpty(&clientRect);
|
||||
if (!GetWindowRect(hWnd, &windowRect))
|
||||
SetRectEmpty(&windowRect);
|
||||
|
||||
/* FIXME missing fields: hmemTaskQ, hrgnUpdate, dce, flags, pProp, scroll */
|
||||
fprintf(stderr,
|
||||
"next=0x%04x child=0x%04x parent=0x%04x owner=0x%04x class='%s'\n"
|
||||
"inst=%08lx active=%04x idmenu=%08lx\n"
|
||||
"style=%08lx exstyle=%08lx wndproc=%08lx text='%s'\n"
|
||||
"client=%d,%d-%d,%d window=%d,%d-%d,%d sysmenu=%04x\n",
|
||||
GetWindow(hWnd, GW_HWNDNEXT),
|
||||
GetWindow(hWnd, GW_CHILD),
|
||||
GetParent(hWnd),
|
||||
GetWindow(hWnd, GW_OWNER),
|
||||
clsName,
|
||||
GetWindowLongA(hWnd, GWL_HINSTANCE),
|
||||
GetLastActivePopup(hWnd),
|
||||
GetWindowLongA(hWnd, GWL_ID),
|
||||
GetWindowLongA(hWnd, GWL_STYLE),
|
||||
GetWindowLongA(hWnd, GWL_EXSTYLE),
|
||||
GetWindowLongA(hWnd, GWL_WNDPROC),
|
||||
wndName,
|
||||
clientRect.left, clientRect.top, clientRect.right, clientRect.bottom,
|
||||
windowRect.left, windowRect.top, windowRect.right, windowRect.bottom,
|
||||
GetSystemMenu(hWnd, FALSE));
|
||||
|
||||
if (GetClassLongA(hWnd, GCL_CBWNDEXTRA)) {
|
||||
fprintf(stderr, "Extra bytes:" );
|
||||
for (i = 0; i < GetClassLongA(hWnd, GCL_CBWNDEXTRA) / 2; i++) {
|
||||
w = GetWindowWord(hWnd, i * 2);
|
||||
/* FIXME: depends on i386 endian-ity */
|
||||
fprintf(stderr, " %02x", HIBYTE(w));
|
||||
fprintf(stderr, " %02x", LOBYTE(w));
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void DEBUG_WalkWindows(HWND hWnd, int indent)
|
||||
{
|
||||
char clsName[128];
|
||||
char wndName[128];
|
||||
HWND child;
|
||||
|
||||
if (!IsWindow(hWnd))
|
||||
hWnd = GetDesktopWindow();
|
||||
|
||||
if (!indent) /* first time around */
|
||||
fprintf(stderr,
|
||||
"%-16.16s %-17.17s %-8.8s %s\n",
|
||||
"hwnd", "Class Name", " Style", " WndProc Text");
|
||||
|
||||
do {
|
||||
if (!GetClassNameA(hWnd, clsName, sizeof(clsName)))
|
||||
strcpy(clsName, "-- Unknown --");
|
||||
if (!GetWindowTextA(hWnd, wndName, sizeof(wndName)))
|
||||
strcpy(wndName, "-- Empty --");
|
||||
|
||||
/* FIXME: missing hmemTaskQ */
|
||||
fprintf(stderr, "%*s%04x%*s", indent, "", hWnd, 13-indent,"");
|
||||
fprintf(stderr, "%-17.17s %08lx %08lx %.14s\n",
|
||||
clsName, GetWindowLongA(hWnd, GWL_STYLE),
|
||||
GetWindowLongA(hWnd, GWL_WNDPROC), wndName);
|
||||
|
||||
if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
|
||||
DEBUG_WalkWindows(child, indent + 1 );
|
||||
} while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
|
||||
}
|
||||
|
||||
void DEBUG_WalkProcess(void)
|
||||
{
|
||||
fprintf(stderr, "No longer walking processes list\n");
|
||||
}
|
||||
|
||||
void DEBUG_WalkModref(DWORD p)
|
||||
{
|
||||
fprintf(stderr, "No longer walking module references list\n");
|
||||
}
|
||||
|
||||
void DEBUG_InfoSegments(DWORD start, int length)
|
||||
{
|
||||
char flags[3];
|
||||
DWORD i;
|
||||
LDT_ENTRY le;
|
||||
|
||||
if (length == -1) length = (8192 - start);
|
||||
|
||||
for (i = start; i < start + length; i++)
|
||||
{
|
||||
if (!GetThreadSelectorEntry(DEBUG_CurrThread->handle, (i << 3)|7, &le))
|
||||
continue;
|
||||
|
||||
if (le.HighWord.Bits.Type & 0x08)
|
||||
{
|
||||
flags[0] = (le.HighWord.Bits.Type & 0x2) ? 'r' : '-';
|
||||
flags[1] = '-';
|
||||
flags[2] = 'x';
|
||||
}
|
||||
else
|
||||
{
|
||||
flags[0] = 'r';
|
||||
flags[1] = (le.HighWord.Bits.Type & 0x2) ? 'w' : '-';
|
||||
flags[2] = '-';
|
||||
}
|
||||
fprintf(stderr,
|
||||
"%04lx: sel=%04lx base=%08x limit=%08x %d-bit %c%c%c\n",
|
||||
i, (i<<3)|7,
|
||||
(le.HighWord.Bits.BaseHi << 24) +
|
||||
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow,
|
||||
((le.HighWord.Bits.LimitHi << 8) + le.LimitLow) <<
|
||||
(le.HighWord.Bits.Granularity ? 12 : 0),
|
||||
le.HighWord.Bits.Default_Big ? 32 : 16,
|
||||
flags[0], flags[1], flags[2] );
|
||||
}
|
||||
}
|
||||
|
||||
void DEBUG_InfoVirtual(void)
|
||||
{
|
||||
fprintf(stderr, "No longer providing virtual mapping information\n");
|
||||
}
|
||||
|
|
|
@ -8,147 +8,126 @@
|
|||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "wine/winbase16.h"
|
||||
#include <string.h>
|
||||
#include "debugger.h"
|
||||
#include "miscemu.h"
|
||||
#include "winbase.h"
|
||||
|
||||
|
||||
/************************************************************
|
||||
*
|
||||
* Check if linear pointer in [addr, addr+size[
|
||||
* read (rwflag == 1)
|
||||
* or
|
||||
* write (rwflag == 0)
|
||||
************************************************************/
|
||||
|
||||
BOOL DEBUG_checkmap_bad( const char *addr, size_t size, int rwflag)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[200]; /* temporary line buffer */
|
||||
char prot[5]; /* protection string */
|
||||
char *start, *end;
|
||||
int ret = TRUE;
|
||||
|
||||
#ifdef linux
|
||||
/*
|
||||
The entries in /proc/self/maps are of the form:
|
||||
08000000-08002000 r-xp 00000000 03:41 2361
|
||||
08002000-08003000 rw-p 00001000 03:41 2361
|
||||
08003000-08005000 rwxp 00000000 00:00 0
|
||||
40000000-40005000 r-xp 00000000 03:41 67219
|
||||
40005000-40006000 rw-p 00004000 03:41 67219
|
||||
40006000-40007000 rw-p 00000000 00:00 0
|
||||
...
|
||||
start end perm ??? major:minor inode
|
||||
|
||||
Only permissions start and end are used here
|
||||
*/
|
||||
#else
|
||||
/*
|
||||
% cat /proc/curproc/map
|
||||
start end resident private perm type
|
||||
0x1000 0xe000 12 0 r-x COW vnode
|
||||
0xe000 0x10000 2 2 rwx COW vnode
|
||||
0x10000 0x27000 4 4 rwx default
|
||||
0x800e000 0x800f000 1 1 rw- default
|
||||
0xefbde000 0xefbfe000 1 1 rwx default
|
||||
|
||||
COW = "copy on write"
|
||||
|
||||
|
||||
% cat /proc/curproc/map on FreeBSD 3.0
|
||||
start end ? ? ? prot ? ? ? ? ? ?
|
||||
0x8048000 0x8054000 12 14 114770 r-x 2 1 0x0 COW NC vnode
|
||||
0x8054000 0x8055000 1 0 166664 rwx 1 0 0x2180 COW NNC vnode
|
||||
0x8055000 0x806a000 5 0 166662 rwx 1 0 0x2180 NCOW NNC default
|
||||
0x28054000 0x28055000 1 0 166666 rwx 1 0 0x2180 NCOW NNC default
|
||||
0xefbde000 0xefbfe000 1 0 166663 rwx 1 0 0x2180 NCOW NNC default
|
||||
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
if (!(fp = fopen("/proc/self/maps","r")) &&
|
||||
!(fp = fopen("/proc/curproc/map","r"))
|
||||
)
|
||||
return FALSE;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
/*
|
||||
* *FOO* read(2) less than length of /proc/.../map fails with EFBIG
|
||||
*
|
||||
* $ dd bs=256 </proc/curproc/map
|
||||
* dd: stdin: File too large
|
||||
* 0+0 records in
|
||||
* 0+0 records out
|
||||
* 0 bytes transferred in 0.001595 secs (0 bytes/sec)
|
||||
*/
|
||||
setvbuf(fp, (char *)NULL, _IOFBF, 0x4000);
|
||||
#endif
|
||||
while (fgets( buf, sizeof(buf)-1, fp)) {
|
||||
#ifdef linux
|
||||
sscanf(buf, "%x-%x %3s", (int *) &start, (int *) &end, prot);
|
||||
#else
|
||||
sscanf(buf, "%x %x %*d %*d %3s", (int *) &start, (int *) &end, prot);
|
||||
if (prot[0]!='r' && prot[0]!='-') /* FreeBSD 3.0 format */
|
||||
sscanf(buf, "%x %x %*d %*d %*d %3s", (int *) &start, (int *) &end, prot);
|
||||
#endif
|
||||
if ( end <= addr)
|
||||
continue;
|
||||
if (start <= addr && addr+size <= end) {
|
||||
if (rwflag)
|
||||
ret = (prot[0] != 'r'); /* test for reading */
|
||||
else
|
||||
ret = (prot[1] != 'w'); /* test for writing */
|
||||
}
|
||||
break;
|
||||
}
|
||||
fclose( fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_IsBadReadPtr
|
||||
*
|
||||
* Check if we are allowed to read memory at 'address'.
|
||||
*/
|
||||
BOOL DEBUG_IsBadReadPtr( const DBG_ADDR *address, int size )
|
||||
{
|
||||
#ifdef __i386__
|
||||
if (!IS_SELECTOR_V86(address->seg))
|
||||
if (address->seg) /* segmented addr */
|
||||
{
|
||||
if (IsBadReadPtr16( (SEGPTR)MAKELONG( (WORD)address->off,
|
||||
(WORD)address->seg ), size ))
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
return DEBUG_checkmap_bad( DBG_ADDR_TO_LIN(address), size, 1);
|
||||
}
|
||||
#include "wine/winbase16.h"
|
||||
|
||||
#define DBG_V86_MODULE(seg) ((seg)>>16)
|
||||
#define IS_SELECTOR_V86(seg) DBG_V86_MODULE(seg)
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_IsBadWritePtr
|
||||
*
|
||||
* Check if we are allowed to write memory at 'address'.
|
||||
*/
|
||||
BOOL DEBUG_IsBadWritePtr( const DBG_ADDR *address, int size )
|
||||
static void DEBUG_Die(const char* msg)
|
||||
{
|
||||
#ifdef __i386__
|
||||
if (!IS_SELECTOR_V86(address->seg))
|
||||
if (address->seg) /* segmented addr */
|
||||
{
|
||||
/* Note: we use IsBadReadPtr here because we are */
|
||||
/* always allowed to write to read-only segments */
|
||||
if (IsBadReadPtr16( (SEGPTR)MAKELONG( (WORD)address->off,
|
||||
(WORD)address->seg ), size ))
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
return DEBUG_checkmap_bad( DBG_ADDR_TO_LIN(address), size, 0);
|
||||
fprintf(stderr, msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void* DEBUG_XMalloc(size_t size)
|
||||
{
|
||||
void *res = malloc(size ? size : 1);
|
||||
if (res == NULL)
|
||||
DEBUG_Die("Memory exhausted.\n");
|
||||
memset(res, 0, size);
|
||||
return res;
|
||||
}
|
||||
|
||||
void* DEBUG_XReAlloc(void *ptr, size_t size)
|
||||
{
|
||||
void* res = realloc(ptr, size);
|
||||
if ((res == NULL) && size)
|
||||
DEBUG_Die("Memory exhausted.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
char* DEBUG_XStrDup(const char *str)
|
||||
{
|
||||
char *res = strdup(str);
|
||||
if (!res)
|
||||
DEBUG_Die("Memory exhausted.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
void DEBUG_FixAddress( DBG_ADDR *addr, DWORD def)
|
||||
{
|
||||
if (addr->seg == 0xffffffff) addr->seg = def;
|
||||
if (!IS_SELECTOR_V86(addr->seg) && DEBUG_IsSelectorSystem(addr->seg)) addr->seg = 0;
|
||||
}
|
||||
|
||||
BOOL DEBUG_FixSegment( DBG_ADDR* addr )
|
||||
{
|
||||
/* V86 mode ? */
|
||||
if (DEBUG_context.EFlags & V86_FLAG) {
|
||||
addr->seg |= (DWORD)(GetExePtr(GetCurrentTask())) << 16;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD DEBUG_ToLinear( const DBG_ADDR *addr )
|
||||
{
|
||||
LDT_ENTRY le;
|
||||
|
||||
if (IS_SELECTOR_V86(addr->seg))
|
||||
return DOSMEM_MemoryBase(DBG_V86_MODULE(addr->seg)) + (((addr->seg)&0xFFFF)<<4) + addr->off;
|
||||
if (DEBUG_IsSelectorSystem(addr->seg))
|
||||
return addr->off;
|
||||
|
||||
if (GetThreadSelectorEntry( DEBUG_CurrThread->handle, addr->seg, &le)) {
|
||||
return (le.HighWord.Bits.BaseHi << 24) + (le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->off;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DEBUG_GetSelectorType( WORD sel )
|
||||
{
|
||||
LDT_ENTRY le;
|
||||
|
||||
if (sel == 0)
|
||||
return 32;
|
||||
if (IS_SELECTOR_V86(sel))
|
||||
return 16;
|
||||
if (GetThreadSelectorEntry( DEBUG_CurrThread->handle, sel, &le))
|
||||
return le.HighWord.Bits.Default_Big ? 32 : 16;
|
||||
/* selector doesn't exist */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determine if sel is a system selector (i.e. not managed by Wine) */
|
||||
BOOL DEBUG_IsSelectorSystem(WORD sel)
|
||||
{
|
||||
return !(sel & 4) || (((sel & 0xFFFF) >> 3) < 17);
|
||||
}
|
||||
#endif /* __i386__ */
|
||||
|
||||
void DEBUG_GetCurrentAddress( DBG_ADDR *addr )
|
||||
{
|
||||
addr->type = NULL;
|
||||
#ifdef __i386__
|
||||
addr->seg = DEBUG_context.SegCs;
|
||||
|
||||
if (!DEBUG_FixSegment( addr ) && DEBUG_IsSelectorSystem(addr->seg))
|
||||
addr->seg = 0;
|
||||
addr->off = DEBUG_context.Eip;
|
||||
#else
|
||||
addr->seg = 0;
|
||||
addr->off = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DEBUG_InvalLinAddr( void* addr )
|
||||
{
|
||||
DBG_ADDR address;
|
||||
|
||||
address.type = NULL;
|
||||
address.seg = 0;
|
||||
address.off = (unsigned long)addr;
|
||||
|
||||
fprintf(stderr,"*** Invalid address ");
|
||||
DEBUG_PrintAddress(&address, DEBUG_CurrThread->dbg_mode, FALSE);
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_ReadMemory
|
||||
|
@ -157,11 +136,15 @@ BOOL DEBUG_IsBadWritePtr( const DBG_ADDR *address, int size )
|
|||
*/
|
||||
int DEBUG_ReadMemory( const DBG_ADDR *address )
|
||||
{
|
||||
DBG_ADDR addr = *address;
|
||||
|
||||
DBG_FIX_ADDR_SEG( &addr, DS_reg(&DEBUG_context) );
|
||||
if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return 0;
|
||||
return *(int *)DBG_ADDR_TO_LIN( &addr );
|
||||
DBG_ADDR addr = *address;
|
||||
void* lin;
|
||||
int value;
|
||||
|
||||
DEBUG_FixAddress( &addr, DEBUG_context.SegDs );
|
||||
lin = (void*)DEBUG_ToLinear( &addr );
|
||||
if (!DEBUG_READ_MEM_VERBOSE(lin, &value, sizeof(value)))
|
||||
value = 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
@ -172,11 +155,12 @@ int DEBUG_ReadMemory( const DBG_ADDR *address )
|
|||
*/
|
||||
void DEBUG_WriteMemory( const DBG_ADDR *address, int value )
|
||||
{
|
||||
DBG_ADDR addr = *address;
|
||||
DBG_ADDR addr = *address;
|
||||
void* lin;
|
||||
|
||||
DBG_FIX_ADDR_SEG( &addr, DS_reg(&DEBUG_context) );
|
||||
if (!DBG_CHECK_WRITE_PTR( &addr, sizeof(int) )) return;
|
||||
*(int *)DBG_ADDR_TO_LIN( &addr ) = value;
|
||||
DEBUG_FixAddress( &addr, DEBUG_context.SegDs );
|
||||
lin = (void*)DEBUG_ToLinear( &addr );
|
||||
DEBUG_WRITE_MEM_VERBOSE(lin, &value, sizeof(value));
|
||||
}
|
||||
|
||||
|
||||
|
@ -188,15 +172,14 @@ void DEBUG_WriteMemory( const DBG_ADDR *address, int value )
|
|||
void DEBUG_ExamineMemory( const DBG_ADDR *address, int count, char format )
|
||||
{
|
||||
DBG_ADDR addr = * address;
|
||||
unsigned int * dump;
|
||||
int i;
|
||||
unsigned char * pnt;
|
||||
unsigned int seg2;
|
||||
struct datatype * testtype;
|
||||
unsigned short int * wdump;
|
||||
|
||||
DBG_FIX_ADDR_SEG( &addr, (format == 'i') ?
|
||||
CS_reg(&DEBUG_context) : DS_reg(&DEBUG_context) );
|
||||
DEBUG_FixAddress( &addr,
|
||||
(format == 'i') ?
|
||||
DEBUG_context.SegCs :
|
||||
DEBUG_context.SegDs );
|
||||
|
||||
/*
|
||||
* Dereference pointer to get actual memory address we need to be
|
||||
|
@ -212,15 +195,15 @@ void DEBUG_ExamineMemory( const DBG_ADDR *address, int count, char format )
|
|||
* else in 32-bit space. Grab it, and we
|
||||
* should be all set.
|
||||
*/
|
||||
seg2 = addr.seg;
|
||||
unsigned int seg2 = addr.seg;
|
||||
addr.seg = 0;
|
||||
addr.off = DEBUG_GetExprValue(&addr, NULL);
|
||||
addr.seg = seg2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!DBG_CHECK_READ_PTR( &addr, 1 )) return;
|
||||
DEBUG_TypeDerefPointer(&addr, &testtype);
|
||||
if (DEBUG_TypeDerefPointer(&addr, &testtype) == 0)
|
||||
return;
|
||||
if( testtype != NULL || addr.type == DEBUG_TypeIntConst )
|
||||
{
|
||||
addr.off = DEBUG_GetExprValue(&addr, NULL);
|
||||
|
@ -235,135 +218,71 @@ void DEBUG_ExamineMemory( const DBG_ADDR *address, int count, char format )
|
|||
|
||||
if (format != 'i' && count > 1)
|
||||
{
|
||||
DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
|
||||
DEBUG_PrintAddress( &addr, DEBUG_CurrThread->dbg_mode, FALSE );
|
||||
fprintf(stderr,": ");
|
||||
}
|
||||
|
||||
pnt = DBG_ADDR_TO_LIN( &addr );
|
||||
pnt = (void*)DEBUG_ToLinear( &addr );
|
||||
|
||||
switch(format)
|
||||
{
|
||||
case 'u': {
|
||||
WCHAR *ptr = (WCHAR*)pnt;
|
||||
WCHAR wch;
|
||||
if (count == 1) count = 256;
|
||||
while (count--)
|
||||
{
|
||||
if (!DBG_CHECK_READ_PTR( &addr, sizeof(WCHAR) )) return;
|
||||
if (!*ptr) break;
|
||||
addr.off++;
|
||||
fputc( (char)*ptr++, stderr );
|
||||
if (!DEBUG_READ_MEM_VERBOSE(pnt, &wch, sizeof(wch)))
|
||||
break;
|
||||
pnt += sizeof(wch);
|
||||
fputc( (char)wch, stderr );
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
return;
|
||||
}
|
||||
case 's':
|
||||
case 's': {
|
||||
char ch;
|
||||
|
||||
if (count == 1) count = 256;
|
||||
while (count--)
|
||||
{
|
||||
if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return;
|
||||
if (!*pnt) break;
|
||||
addr.off++;
|
||||
fputc( *pnt++, stderr );
|
||||
if (!DEBUG_READ_MEM_VERBOSE(pnt, &ch, sizeof(ch)))
|
||||
break;
|
||||
pnt++;
|
||||
fputc( ch, stderr );
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
return;
|
||||
|
||||
}
|
||||
case 'i':
|
||||
while (count--)
|
||||
{
|
||||
DEBUG_PrintAddress( &addr, dbg_mode, TRUE );
|
||||
DEBUG_PrintAddress( &addr, DEBUG_CurrThread->dbg_mode, TRUE );
|
||||
fprintf(stderr,": ");
|
||||
if (!DBG_CHECK_READ_PTR( &addr, 1 )) return;
|
||||
DEBUG_Disasm( &addr, TRUE );
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
return;
|
||||
case 'x':
|
||||
dump = (unsigned int *)pnt;
|
||||
for(i=0; i<count; i++)
|
||||
{
|
||||
if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return;
|
||||
fprintf(stderr," %8.8x", *dump++);
|
||||
addr.off += sizeof(int);
|
||||
if ((i % 4) == 3)
|
||||
{
|
||||
fprintf(stderr,"\n");
|
||||
DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
|
||||
fprintf(stderr,": ");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
return;
|
||||
|
||||
case 'd':
|
||||
dump = (unsigned int *)pnt;
|
||||
for(i=0; i<count; i++)
|
||||
{
|
||||
if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return;
|
||||
fprintf(stderr," %10d", *dump++);
|
||||
addr.off += sizeof(int);
|
||||
if ((i % 4) == 3)
|
||||
{
|
||||
fprintf(stderr,"\n");
|
||||
DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
|
||||
fprintf(stderr,": ");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
return;
|
||||
|
||||
case 'w':
|
||||
wdump = (unsigned short *)pnt;
|
||||
for(i=0; i<count; i++)
|
||||
{
|
||||
if (!DBG_CHECK_READ_PTR( &addr, sizeof(short) )) return;
|
||||
fprintf(stderr," %04x", *wdump++);
|
||||
addr.off += sizeof(short);
|
||||
if ((i % 8) == 7)
|
||||
{
|
||||
fprintf(stderr,"\n");
|
||||
DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
|
||||
fprintf(stderr,": ");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
return;
|
||||
|
||||
case 'c':
|
||||
for(i=0; i<count; i++)
|
||||
{
|
||||
if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return;
|
||||
if(*pnt < 0x20)
|
||||
{
|
||||
fprintf(stderr," ");
|
||||
pnt++;
|
||||
}
|
||||
else fprintf(stderr," %c", *pnt++);
|
||||
addr.off++;
|
||||
if ((i % 32) == 31)
|
||||
{
|
||||
fprintf(stderr,"\n");
|
||||
DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
|
||||
fprintf(stderr,": ");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
return;
|
||||
|
||||
case 'b':
|
||||
for(i=0; i<count; i++)
|
||||
{
|
||||
if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return;
|
||||
fprintf(stderr," %02x", (*pnt++) & 0xff);
|
||||
addr.off++;
|
||||
if ((i % 16) == 15)
|
||||
{
|
||||
fprintf(stderr,"\n");
|
||||
DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
|
||||
fprintf(stderr,": ");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
return;
|
||||
#define DO_DUMP2(_t,_l,_f,_vv) { \
|
||||
_t _v; \
|
||||
for(i=0; i<count; i++) { \
|
||||
if (!DEBUG_READ_MEM_VERBOSE(pnt, &_v, sizeof(_t))) break; \
|
||||
fprintf(stderr,_f,(_vv)); \
|
||||
pnt += sizeof(_t); addr.off += sizeof(_t); \
|
||||
if ((i % (_l)) == (_l)-1) { \
|
||||
fprintf(stderr,"\n"); \
|
||||
DEBUG_PrintAddress( &addr, DEBUG_CurrThread->dbg_mode, FALSE );\
|
||||
fprintf(stderr,": ");\
|
||||
} \
|
||||
} \
|
||||
fprintf(stderr,"\n"); \
|
||||
} \
|
||||
return
|
||||
#define DO_DUMP(_t,_l,_f) DO_DUMP2(_t,_l,_f,_v)
|
||||
|
||||
case 'x': DO_DUMP(int, 4, " %8.8x");
|
||||
case 'd': DO_DUMP(unsigned int, 4, " %10d");
|
||||
case 'w': DO_DUMP(unsigned short, 8, " %04x");
|
||||
case 'c': DO_DUMP2(char, 32, " %c", (_v < 0x20) ? ' ' : _v);
|
||||
case 'b': DO_DUMP2(char, 16, " %02x", (_v) & 0xff);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,8 @@
|
|||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "selectors.h"
|
||||
#include "debugger.h"
|
||||
|
||||
CONTEXT DEBUG_context;
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_SetRegister
|
||||
*
|
||||
|
@ -22,70 +19,73 @@ void DEBUG_SetRegister( enum debug_regs reg, int val )
|
|||
#ifdef __i386__
|
||||
switch(reg)
|
||||
{
|
||||
case REG_EAX: EAX_reg(&DEBUG_context) = val; break;
|
||||
case REG_EBX: EBX_reg(&DEBUG_context) = val; break;
|
||||
case REG_ECX: ECX_reg(&DEBUG_context) = val; break;
|
||||
case REG_EDX: EDX_reg(&DEBUG_context) = val; break;
|
||||
case REG_ESI: ESI_reg(&DEBUG_context) = val; break;
|
||||
case REG_EDI: EDI_reg(&DEBUG_context) = val; break;
|
||||
case REG_EBP: EBP_reg(&DEBUG_context) = val; break;
|
||||
case REG_EFL: EFL_reg(&DEBUG_context) = val; break;
|
||||
case REG_EIP: EIP_reg(&DEBUG_context) = val; break;
|
||||
case REG_ESP: ESP_reg(&DEBUG_context) = val; break;
|
||||
case REG_CS: CS_reg(&DEBUG_context) = val; break;
|
||||
case REG_DS: DS_reg(&DEBUG_context) = val; break;
|
||||
case REG_ES: ES_reg(&DEBUG_context) = val; break;
|
||||
case REG_SS: SS_reg(&DEBUG_context) = val; break;
|
||||
case REG_FS: FS_reg(&DEBUG_context) = val; break;
|
||||
case REG_GS: GS_reg(&DEBUG_context) = val; break;
|
||||
case REG_AX: SET_LOWORD(EAX_reg(&DEBUG_context),val); break;
|
||||
case REG_BX: SET_LOWORD(EBX_reg(&DEBUG_context),val); break;
|
||||
case REG_CX: SET_LOWORD(ECX_reg(&DEBUG_context),val); break;
|
||||
case REG_DX: SET_LOWORD(EDX_reg(&DEBUG_context),val); break;
|
||||
case REG_SI: SET_LOWORD(ESI_reg(&DEBUG_context),val); break;
|
||||
case REG_DI: SET_LOWORD(EDI_reg(&DEBUG_context),val); break;
|
||||
case REG_BP: SET_LOWORD(EBP_reg(&DEBUG_context),val); break;
|
||||
case REG_FL: SET_LOWORD(EFL_reg(&DEBUG_context),val); break;
|
||||
case REG_IP: SET_LOWORD(EIP_reg(&DEBUG_context),val); break;
|
||||
case REG_SP: SET_LOWORD(ESP_reg(&DEBUG_context),val); break;
|
||||
case REG_EAX: DEBUG_context.Eax = val; break;
|
||||
case REG_EBX: DEBUG_context.Ebx = val; break;
|
||||
case REG_ECX: DEBUG_context.Ecx = val; break;
|
||||
case REG_EDX: DEBUG_context.Edx = val; break;
|
||||
case REG_ESI: DEBUG_context.Esi = val; break;
|
||||
case REG_EDI: DEBUG_context.Edi = val; break;
|
||||
case REG_EBP: DEBUG_context.Ebp = val; break;
|
||||
case REG_EFL: DEBUG_context.EFlags = val; break;
|
||||
case REG_EIP: DEBUG_context.Eip = val; break;
|
||||
case REG_ESP: DEBUG_context.Esp = val; break;
|
||||
case REG_CS: DEBUG_context.SegCs = val; break;
|
||||
case REG_DS: DEBUG_context.SegDs = val; break;
|
||||
case REG_ES: DEBUG_context.SegEs = val; break;
|
||||
case REG_SS: DEBUG_context.SegSs = val; break;
|
||||
case REG_FS: DEBUG_context.SegFs = val; break;
|
||||
case REG_GS: DEBUG_context.SegGs = val; break;
|
||||
#define SET_LOW_WORD(dw,lw) ((dw) = ((dw) & 0xFFFF0000) | LOWORD(lw))
|
||||
case REG_AX: SET_LOW_WORD(DEBUG_context.Eax,val); break;
|
||||
case REG_BX: SET_LOW_WORD(DEBUG_context.Ebx,val); break;
|
||||
case REG_CX: SET_LOW_WORD(DEBUG_context.Ecx,val); break;
|
||||
case REG_DX: SET_LOW_WORD(DEBUG_context.Edx,val); break;
|
||||
case REG_SI: SET_LOW_WORD(DEBUG_context.Esi,val); break;
|
||||
case REG_DI: SET_LOW_WORD(DEBUG_context.Edi,val); break;
|
||||
case REG_BP: SET_LOW_WORD(DEBUG_context.Ebp,val); break;
|
||||
case REG_FL: SET_LOW_WORD(DEBUG_context.EFlags,val); break;
|
||||
case REG_IP: SET_LOW_WORD(DEBUG_context.Eip,val); break;
|
||||
case REG_SP: SET_LOW_WORD(DEBUG_context.Esp,val); break;
|
||||
#undef SET_LOWORD
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
DEBUG_PrintRegister(enum debug_regs reg)
|
||||
int DEBUG_PrintRegister(enum debug_regs reg)
|
||||
{
|
||||
#ifdef __i386__
|
||||
char* val = NULL;
|
||||
switch(reg)
|
||||
{
|
||||
case REG_EAX: fprintf(stderr, "%%eax"); break;
|
||||
case REG_EBX: fprintf(stderr, "%%ebx"); break;
|
||||
case REG_ECX: fprintf(stderr, "%%ecx"); break;
|
||||
case REG_EDX: fprintf(stderr, "%%edx"); break;
|
||||
case REG_ESI: fprintf(stderr, "%%esi"); break;
|
||||
case REG_EDI: fprintf(stderr, "%%edi"); break;
|
||||
case REG_EBP: fprintf(stderr, "%%ebp"); break;
|
||||
case REG_EFL: fprintf(stderr, "%%efl"); break;
|
||||
case REG_EIP: fprintf(stderr, "%%eip"); break;
|
||||
case REG_ESP: fprintf(stderr, "%%esp"); break;
|
||||
case REG_AX: fprintf(stderr, "%%ax"); break;
|
||||
case REG_BX: fprintf(stderr, "%%bx"); break;
|
||||
case REG_CX: fprintf(stderr, "%%cx"); break;
|
||||
case REG_DX: fprintf(stderr, "%%dx"); break;
|
||||
case REG_SI: fprintf(stderr, "%%si"); break;
|
||||
case REG_DI: fprintf(stderr, "%%di"); break;
|
||||
case REG_BP: fprintf(stderr, "%%bp"); break;
|
||||
case REG_FL: fprintf(stderr, "%%fl"); break;
|
||||
case REG_IP: fprintf(stderr, "%%ip"); break;
|
||||
case REG_SP: fprintf(stderr, "%%sp"); break;
|
||||
case REG_CS: fprintf(stderr, "%%cs"); break;
|
||||
case REG_DS: fprintf(stderr, "%%ds"); break;
|
||||
case REG_ES: fprintf(stderr, "%%es"); break;
|
||||
case REG_SS: fprintf(stderr, "%%ss"); break;
|
||||
case REG_FS: fprintf(stderr, "%%fs"); break;
|
||||
case REG_GS: fprintf(stderr, "%%gs"); break;
|
||||
case REG_EAX: val = "%%eax"; break;
|
||||
case REG_EBX: val = "%%ebx"; break;
|
||||
case REG_ECX: val = "%%ecx"; break;
|
||||
case REG_EDX: val = "%%edx"; break;
|
||||
case REG_ESI: val = "%%esi"; break;
|
||||
case REG_EDI: val = "%%edi"; break;
|
||||
case REG_EBP: val = "%%ebp"; break;
|
||||
case REG_EFL: val = "%%efl"; break;
|
||||
case REG_EIP: val = "%%eip"; break;
|
||||
case REG_ESP: val = "%%esp"; break;
|
||||
case REG_AX: val = "%%ax"; break;
|
||||
case REG_BX: val = "%%bx"; break;
|
||||
case REG_CX: val = "%%cx"; break;
|
||||
case REG_DX: val = "%%dx"; break;
|
||||
case REG_SI: val = "%%si"; break;
|
||||
case REG_DI: val = "%%di"; break;
|
||||
case REG_BP: val = "%%bp"; break;
|
||||
case REG_FL: val = "%%fl"; break;
|
||||
case REG_IP: val = "%%ip"; break;
|
||||
case REG_SP: val = "%%sp"; break;
|
||||
case REG_CS: val = "%%cs"; break;
|
||||
case REG_DS: val = "%%ds"; break;
|
||||
case REG_ES: val = "%%es"; break;
|
||||
case REG_SS: val = "%%ss"; break;
|
||||
case REG_FS: val = "%%fs"; break;
|
||||
case REG_GS: val = "%%gs"; break;
|
||||
}
|
||||
if (val) fprintf(stderr, val);
|
||||
return TRUE;
|
||||
#else
|
||||
return FALSE;
|
||||
|
@ -102,32 +102,32 @@ int DEBUG_GetRegister( enum debug_regs reg )
|
|||
#ifdef __i386__
|
||||
switch(reg)
|
||||
{
|
||||
case REG_EAX: return EAX_reg(&DEBUG_context);
|
||||
case REG_EBX: return EBX_reg(&DEBUG_context);
|
||||
case REG_ECX: return ECX_reg(&DEBUG_context);
|
||||
case REG_EDX: return EDX_reg(&DEBUG_context);
|
||||
case REG_ESI: return ESI_reg(&DEBUG_context);
|
||||
case REG_EDI: return EDI_reg(&DEBUG_context);
|
||||
case REG_EBP: return EBP_reg(&DEBUG_context);
|
||||
case REG_EFL: return EFL_reg(&DEBUG_context);
|
||||
case REG_EIP: return EIP_reg(&DEBUG_context);
|
||||
case REG_ESP: return ESP_reg(&DEBUG_context);
|
||||
case REG_CS: return CS_reg(&DEBUG_context);
|
||||
case REG_DS: return DS_reg(&DEBUG_context);
|
||||
case REG_ES: return ES_reg(&DEBUG_context);
|
||||
case REG_SS: return SS_reg(&DEBUG_context);
|
||||
case REG_FS: return FS_reg(&DEBUG_context);
|
||||
case REG_GS: return GS_reg(&DEBUG_context);
|
||||
case REG_AX: return LOWORD(EAX_reg(&DEBUG_context));
|
||||
case REG_BX: return LOWORD(EBX_reg(&DEBUG_context));
|
||||
case REG_CX: return LOWORD(ECX_reg(&DEBUG_context));
|
||||
case REG_DX: return LOWORD(EDX_reg(&DEBUG_context));
|
||||
case REG_SI: return LOWORD(ESI_reg(&DEBUG_context));
|
||||
case REG_DI: return LOWORD(EDI_reg(&DEBUG_context));
|
||||
case REG_BP: return LOWORD(EBP_reg(&DEBUG_context));
|
||||
case REG_FL: return LOWORD(EFL_reg(&DEBUG_context));
|
||||
case REG_IP: return LOWORD(EIP_reg(&DEBUG_context));
|
||||
case REG_SP: return LOWORD(ESP_reg(&DEBUG_context));
|
||||
case REG_EAX: return DEBUG_context.Eax;
|
||||
case REG_EBX: return DEBUG_context.Ebx;
|
||||
case REG_ECX: return DEBUG_context.Ecx;
|
||||
case REG_EDX: return DEBUG_context.Edx;
|
||||
case REG_ESI: return DEBUG_context.Esi;
|
||||
case REG_EDI: return DEBUG_context.Edi;
|
||||
case REG_EBP: return DEBUG_context.Ebp;
|
||||
case REG_EFL: return DEBUG_context.EFlags;
|
||||
case REG_EIP: return DEBUG_context.Eip;
|
||||
case REG_ESP: return DEBUG_context.Esp;
|
||||
case REG_CS: return DEBUG_context.SegCs;
|
||||
case REG_DS: return DEBUG_context.SegDs;
|
||||
case REG_ES: return DEBUG_context.SegEs;
|
||||
case REG_SS: return DEBUG_context.SegSs;
|
||||
case REG_FS: return DEBUG_context.SegFs;
|
||||
case REG_GS: return DEBUG_context.SegGs;
|
||||
case REG_AX: return LOWORD(DEBUG_context.Eax);
|
||||
case REG_BX: return LOWORD(DEBUG_context.Ebx);
|
||||
case REG_CX: return LOWORD(DEBUG_context.Ecx);
|
||||
case REG_DX: return LOWORD(DEBUG_context.Edx);
|
||||
case REG_SI: return LOWORD(DEBUG_context.Esi);
|
||||
case REG_DI: return LOWORD(DEBUG_context.Edi);
|
||||
case REG_BP: return LOWORD(DEBUG_context.Ebp);
|
||||
case REG_FL: return LOWORD(DEBUG_context.EFlags);
|
||||
case REG_IP: return LOWORD(DEBUG_context.Eip);
|
||||
case REG_SP: return LOWORD(DEBUG_context.Esp);
|
||||
}
|
||||
#endif
|
||||
return 0; /* should not happen */
|
||||
|
@ -200,35 +200,35 @@ void DEBUG_InfoRegisters(void)
|
|||
#ifdef __i386__
|
||||
/* First get the segment registers out of the way */
|
||||
fprintf( stderr," CS:%04x SS:%04x DS:%04x ES:%04x FS:%04x GS:%04x",
|
||||
(WORD)CS_reg(&DEBUG_context), (WORD)SS_reg(&DEBUG_context),
|
||||
(WORD)DS_reg(&DEBUG_context), (WORD)ES_reg(&DEBUG_context),
|
||||
(WORD)FS_reg(&DEBUG_context), (WORD)GS_reg(&DEBUG_context) );
|
||||
if (dbg_mode == 16)
|
||||
(WORD)DEBUG_context.SegCs, (WORD)DEBUG_context.SegSs,
|
||||
(WORD)DEBUG_context.SegDs, (WORD)DEBUG_context.SegEs,
|
||||
(WORD)DEBUG_context.SegFs, (WORD)DEBUG_context.SegGs );
|
||||
if (DEBUG_CurrThread->dbg_mode == 16)
|
||||
{
|
||||
char flag[33];
|
||||
|
||||
fprintf( stderr,"\n IP:%04x SP:%04x BP:%04x FLAGS:%04x(%s)\n",
|
||||
LOWORD(EIP_reg(&DEBUG_context)), LOWORD(ESP_reg(&DEBUG_context)),
|
||||
LOWORD(EBP_reg(&DEBUG_context)), LOWORD(EFL_reg(&DEBUG_context)),
|
||||
DEBUG_Flags(LOWORD(EFL_reg(&DEBUG_context)), flag));
|
||||
LOWORD(DEBUG_context.Eip), LOWORD(DEBUG_context.Esp),
|
||||
LOWORD(DEBUG_context.Ebp), LOWORD(DEBUG_context.EFlags),
|
||||
DEBUG_Flags(LOWORD(DEBUG_context.EFlags), flag));
|
||||
fprintf( stderr," AX:%04x BX:%04x CX:%04x DX:%04x SI:%04x DI:%04x\n",
|
||||
AX_reg(&DEBUG_context), BX_reg(&DEBUG_context),
|
||||
CX_reg(&DEBUG_context), DX_reg(&DEBUG_context),
|
||||
SI_reg(&DEBUG_context), DI_reg(&DEBUG_context) );
|
||||
LOWORD(DEBUG_context.Eax), LOWORD(DEBUG_context.Ebx),
|
||||
LOWORD(DEBUG_context.Ecx), LOWORD(DEBUG_context.Edx),
|
||||
LOWORD(DEBUG_context.Esi), LOWORD(DEBUG_context.Edi) );
|
||||
}
|
||||
else /* 32-bit mode */
|
||||
{
|
||||
char flag[33];
|
||||
|
||||
fprintf( stderr, "\n EIP:%08lx ESP:%08lx EBP:%08lx EFLAGS:%08lx(%s)\n",
|
||||
EIP_reg(&DEBUG_context), ESP_reg(&DEBUG_context),
|
||||
EBP_reg(&DEBUG_context), EFL_reg(&DEBUG_context),
|
||||
DEBUG_Flags(EFL_reg(&DEBUG_context), flag));
|
||||
DEBUG_context.Eip, DEBUG_context.Esp,
|
||||
DEBUG_context.Ebp, DEBUG_context.EFlags,
|
||||
DEBUG_Flags(DEBUG_context.EFlags, flag));
|
||||
fprintf( stderr, " EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n",
|
||||
EAX_reg(&DEBUG_context), EBX_reg(&DEBUG_context),
|
||||
ECX_reg(&DEBUG_context), EDX_reg(&DEBUG_context) );
|
||||
DEBUG_context.Eax, DEBUG_context.Ebx,
|
||||
DEBUG_context.Ecx, DEBUG_context.Edx );
|
||||
fprintf( stderr, " ESI:%08lx EDI:%08lx\n",
|
||||
ESI_reg(&DEBUG_context), EDI_reg(&DEBUG_context) );
|
||||
DEBUG_context.Esi, DEBUG_context.Edi );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -243,15 +243,12 @@ void DEBUG_InfoRegisters(void)
|
|||
BOOL DEBUG_ValidateRegisters(void)
|
||||
{
|
||||
#ifdef __i386__
|
||||
WORD cs, ds;
|
||||
|
||||
if (ISV86(&DEBUG_context)) return TRUE;
|
||||
if (DEBUG_context.EFlags & V86_FLAG) return TRUE;
|
||||
|
||||
#if 0
|
||||
/* Check that a selector is a valid ring-3 LDT selector, or a NULL selector */
|
||||
#define CHECK_SEG(seg,name) \
|
||||
if (((seg) & ~3) && \
|
||||
((((seg) & 7) != 7) || IS_LDT_ENTRY_FREE(SELECTOR_TO_ENTRY(seg)))) \
|
||||
{ \
|
||||
if (((seg) & ~3) && ((((seg) & 7) != 7) || !DEBUG_IsSelector(seg))) { \
|
||||
fprintf( stderr, "*** Invalid value for %s register: %04x\n", \
|
||||
(name), (WORD)(seg) ); \
|
||||
return FALSE; \
|
||||
|
@ -259,26 +256,26 @@ BOOL DEBUG_ValidateRegisters(void)
|
|||
|
||||
cs = __get_cs();
|
||||
ds = __get_ds();
|
||||
if (CS_reg(&DEBUG_context) != cs) CHECK_SEG(CS_reg(&DEBUG_context), "CS");
|
||||
if (SS_reg(&DEBUG_context) != ds) CHECK_SEG(SS_reg(&DEBUG_context), "SS");
|
||||
if (DS_reg(&DEBUG_context) != ds) CHECK_SEG(DS_reg(&DEBUG_context), "DS");
|
||||
if (ES_reg(&DEBUG_context) != ds) CHECK_SEG(ES_reg(&DEBUG_context), "ES");
|
||||
if (FS_reg(&DEBUG_context) != ds) CHECK_SEG(FS_reg(&DEBUG_context), "FS");
|
||||
if (GS_reg(&DEBUG_context) != ds) CHECK_SEG(GS_reg(&DEBUG_context), "GS");
|
||||
if (CS_reg(DEBUG_context) != cs) CHECK_SEG(CS_reg(DEBUG_context), "CS");
|
||||
if (SS_reg(DEBUG_context) != ds) CHECK_SEG(SS_reg(DEBUG_context), "SS");
|
||||
if (DS_reg(DEBUG_context) != ds) CHECK_SEG(DS_reg(DEBUG_context), "DS");
|
||||
if (ES_reg(DEBUG_context) != ds) CHECK_SEG(ES_reg(DEBUG_context), "ES");
|
||||
if (FS_reg(DEBUG_context) != ds) CHECK_SEG(FS_reg(DEBUG_context), "FS");
|
||||
if (GS_reg(DEBUG_context) != ds) CHECK_SEG(GS_reg(DEBUG_context), "GS");
|
||||
#endif
|
||||
|
||||
/* Check that CS and SS are not NULL */
|
||||
|
||||
if (!ISV86(&DEBUG_context))
|
||||
if (!(CS_reg(&DEBUG_context) & ~3))
|
||||
if (!(DEBUG_context.SegCs & ~3))
|
||||
{
|
||||
fprintf( stderr, "*** Invalid value for CS register: %04x\n",
|
||||
(WORD)CS_reg(&DEBUG_context) );
|
||||
(WORD)DEBUG_context.SegCs );
|
||||
return FALSE;
|
||||
}
|
||||
if (!(SS_reg(&DEBUG_context) & ~3))
|
||||
if (!(DEBUG_context.SegSs & ~3))
|
||||
{
|
||||
fprintf( stderr, "*** Invalid value for SS register: %04x\n",
|
||||
(WORD)SS_reg(&DEBUG_context) );
|
||||
(WORD)DEBUG_context.SegSs );
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
|
|
@ -22,11 +22,7 @@
|
|||
#define PATH_MAX _MAX_PATH
|
||||
#endif
|
||||
|
||||
#include "wine/winbase16.h"
|
||||
#include "pe_image.h"
|
||||
#include "peexe.h"
|
||||
#include "debugger.h"
|
||||
#include "task.h"
|
||||
|
||||
struct searchlist
|
||||
{
|
||||
|
@ -428,36 +424,17 @@ DEBUG_List(struct list_id * source1, struct list_id * source2,
|
|||
|
||||
DBG_ADDR DEBUG_LastDisassemble={NULL,0,0};
|
||||
|
||||
void DEBUG_GetCurrentAddress( DBG_ADDR *addr )
|
||||
{
|
||||
#ifdef __i386__
|
||||
TDB *pTask = (TDB*)GlobalLock16( GetCurrentTask() );
|
||||
|
||||
addr->type = NULL;
|
||||
addr->seg = CS_reg(&DEBUG_context);
|
||||
addr->off = EIP_reg(&DEBUG_context);
|
||||
|
||||
if (ISV86(&DEBUG_context)) addr->seg |= (DWORD)(pTask? pTask->hModule : 0) << 16;
|
||||
else if (IS_SELECTOR_SYSTEM(addr->seg)) addr->seg = 0;
|
||||
|
||||
GlobalUnlock16( GetCurrentTask() );
|
||||
#else
|
||||
addr->type = NULL;
|
||||
addr->seg = 0;
|
||||
addr->off = (DWORD)GET_IP(&DEBUG_context);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_disassemble(DBG_ADDR *addr)
|
||||
{
|
||||
DEBUG_PrintAddress( addr, dbg_mode, TRUE );
|
||||
fprintf(stderr,": ");
|
||||
if (!DBG_CHECK_READ_PTR( addr, 1 )) return 0;
|
||||
DEBUG_Disasm( addr, TRUE );
|
||||
fprintf(stderr,"\n");
|
||||
return 1;
|
||||
char ch;
|
||||
|
||||
DEBUG_PrintAddress( addr, DEBUG_CurrThread->dbg_mode, TRUE );
|
||||
fprintf(stderr,": ");
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear(addr), &ch, sizeof(ch))) return 0;
|
||||
DEBUG_Disasm( addr, TRUE );
|
||||
fprintf(stderr,"\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -465,7 +442,7 @@ _disassemble_fixaddr(DBG_ADDR *addr) {
|
|||
DWORD seg2;
|
||||
struct datatype *testtype;
|
||||
|
||||
DBG_FIX_ADDR_SEG(addr,CS_reg(&DEBUG_context));
|
||||
DEBUG_FixAddress(addr, DEBUG_context.SegCs);
|
||||
if( addr->type != NULL )
|
||||
{
|
||||
if( addr->type == DEBUG_TypeIntConst )
|
||||
|
@ -482,7 +459,6 @@ _disassemble_fixaddr(DBG_ADDR *addr) {
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!DBG_CHECK_READ_PTR( addr, 1 )) return;
|
||||
DEBUG_TypeDerefPointer(addr, &testtype);
|
||||
if( testtype != NULL || addr->type == DEBUG_TypeIntConst )
|
||||
addr->off = DEBUG_GetExprValue(addr, NULL);
|
||||
|
|
|
@ -134,8 +134,6 @@ static void stab_strcpy(char * dest, const char * source)
|
|||
*dest++ = '\0';
|
||||
}
|
||||
|
||||
extern void DEBUG_PrintAType(struct datatype*, int);
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
unsigned long value;
|
||||
|
|
479
debugger/stack.c
479
debugger/stack.c
|
@ -12,7 +12,7 @@
|
|||
#include "debugger.h"
|
||||
#include "stackframe.h"
|
||||
|
||||
|
||||
#ifdef __i386__
|
||||
/*
|
||||
* We keep this info for each frame, so that we can
|
||||
* find local variable information correctly.
|
||||
|
@ -43,7 +43,7 @@ typedef struct
|
|||
DWORD ip;
|
||||
WORD cs;
|
||||
} FRAME32;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -57,18 +57,20 @@ void DEBUG_InfoStack(void)
|
|||
DBG_ADDR addr;
|
||||
|
||||
addr.type = NULL;
|
||||
addr.seg = SS_reg(&DEBUG_context);
|
||||
addr.off = ESP_reg(&DEBUG_context);
|
||||
addr.seg = DEBUG_context.SegSs;
|
||||
addr.off = DEBUG_context.Esp;
|
||||
|
||||
fprintf(stderr,"Stack dump:\n");
|
||||
if (IS_SELECTOR_32BIT(addr.seg))
|
||||
{ /* 32-bit mode */
|
||||
DEBUG_ExamineMemory( &addr, 24, 'x' );
|
||||
}
|
||||
else /* 16-bit mode */
|
||||
{
|
||||
switch (DEBUG_GetSelectorType(addr.seg)) {
|
||||
case 32: /* 32-bit mode */
|
||||
DEBUG_ExamineMemory( &addr, 24, 'x' );
|
||||
break;
|
||||
case 16: /* 16-bit mode */
|
||||
addr.off &= 0xffff;
|
||||
DEBUG_ExamineMemory( &addr, 24, 'w' );
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Bad segment (%ld)\n", addr.seg);
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
#endif
|
||||
|
@ -79,7 +81,7 @@ static void DEBUG_ForceFrame(DBG_ADDR *stack, DBG_ADDR *code, int frameno, int b
|
|||
{
|
||||
int theframe = nframe++;
|
||||
frames = (struct bt_info *)DBG_realloc(frames,
|
||||
nframe*sizeof(struct bt_info));
|
||||
nframe*sizeof(struct bt_info));
|
||||
if (noisy)
|
||||
fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : " "),
|
||||
frameno);
|
||||
|
@ -87,7 +89,7 @@ static void DEBUG_ForceFrame(DBG_ADDR *stack, DBG_ADDR *code, int frameno, int b
|
|||
frames[theframe].eip = code->off;
|
||||
if (noisy)
|
||||
frames[theframe].frame = DEBUG_PrintAddressAndArgs( code, bits,
|
||||
stack->off, TRUE );
|
||||
stack->off, TRUE );
|
||||
else
|
||||
DEBUG_FindNearestSymbol( code, TRUE,
|
||||
&frames[theframe].frame.sym, stack->off,
|
||||
|
@ -101,265 +103,284 @@ static void DEBUG_ForceFrame(DBG_ADDR *stack, DBG_ADDR *code, int frameno, int b
|
|||
|
||||
static BOOL DEBUG_Frame16(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
|
||||
{
|
||||
unsigned int ss = addr->seg, possible_cs = 0;
|
||||
FRAME16 *frame = (FRAME16 *)DBG_ADDR_TO_LIN(addr);
|
||||
int theframe = nframe;
|
||||
|
||||
if (DEBUG_IsBadReadPtr( addr, sizeof(FRAME16) )) {
|
||||
if (noisy) {
|
||||
fprintf(stderr,"*** Invalid address ");
|
||||
DEBUG_PrintAddress(addr, dbg_mode, FALSE);
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
return FALSE;
|
||||
unsigned int ss = addr->seg, possible_cs = 0;
|
||||
FRAME16 frame;
|
||||
int theframe = nframe;
|
||||
void* p = (void*)DEBUG_ToLinear(addr);
|
||||
|
||||
if (!p) return FALSE;
|
||||
|
||||
if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
|
||||
if (noisy) {
|
||||
fprintf(stderr,"*** Invalid address ");
|
||||
DEBUG_PrintAddress(addr, DEBUG_CurrThread->dbg_mode, FALSE);
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if (!frame->bp) return FALSE;
|
||||
if (!frame.bp) return FALSE;
|
||||
nframe++;
|
||||
frames = (struct bt_info *)DBG_realloc(frames,
|
||||
nframe*sizeof(struct bt_info));
|
||||
nframe*sizeof(struct bt_info));
|
||||
if (noisy)
|
||||
fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : " "),
|
||||
frameno);
|
||||
if (frame->bp & 1) *cs = frame->cs;
|
||||
fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : " "),
|
||||
frameno);
|
||||
if (frame.bp & 1) *cs = frame.cs;
|
||||
else {
|
||||
/* not explicitly marked as far call,
|
||||
* but check whether it could be anyway */
|
||||
if (((frame->cs&7)==7) && (frame->cs != *cs) && !IS_SELECTOR_FREE(frame->cs)) {
|
||||
ldt_entry tcs;
|
||||
LDT_GetEntry( SELECTOR_TO_ENTRY(frame->cs), &tcs );
|
||||
if ( tcs.type == SEGMENT_CODE ) {
|
||||
/* it is very uncommon to push a code segment cs as
|
||||
* a parameter, so this should work in most cases */
|
||||
*cs = possible_cs = frame->cs;
|
||||
}
|
||||
}
|
||||
/* not explicitly marked as far call,
|
||||
* but check whether it could be anyway */
|
||||
if (((frame.cs&7)==7) && (frame.cs != *cs)) {
|
||||
LDT_ENTRY le;
|
||||
|
||||
if (GetThreadSelectorEntry( DEBUG_CurrThread->handle, frame.cs, &le) &&
|
||||
(le.HighWord.Bits.Type & 0x08)) { /* code segment */
|
||||
/* it is very uncommon to push a code segment cs as
|
||||
* a parameter, so this should work in most cases */
|
||||
*cs = possible_cs = frame.cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
frames[theframe].cs = addr->seg = *cs;
|
||||
frames[theframe].eip = addr->off = frame->ip;
|
||||
frames[theframe].eip = addr->off = frame.ip;
|
||||
if (noisy)
|
||||
frames[theframe].frame = DEBUG_PrintAddressAndArgs( addr, 16,
|
||||
frame->bp, TRUE );
|
||||
frames[theframe].frame = DEBUG_PrintAddressAndArgs( addr, 16,
|
||||
frame.bp, TRUE );
|
||||
else
|
||||
DEBUG_FindNearestSymbol( addr, TRUE,
|
||||
&frames[theframe].frame.sym, frame->bp,
|
||||
&frames[theframe].frame.list);
|
||||
DEBUG_FindNearestSymbol( addr, TRUE,
|
||||
&frames[theframe].frame.sym, frame.bp,
|
||||
&frames[theframe].frame.list);
|
||||
frames[theframe].ss = addr->seg = ss;
|
||||
frames[theframe].ebp = addr->off = frame->bp & ~1;
|
||||
frames[theframe].ebp = addr->off = frame.bp & ~1;
|
||||
if (noisy) {
|
||||
fprintf( stderr, " (bp=%04lx", addr->off );
|
||||
if (possible_cs) {
|
||||
fprintf( stderr, ", far call assumed" );
|
||||
}
|
||||
fprintf( stderr, ")\n" );
|
||||
fprintf( stderr, " (bp=%04lx", addr->off );
|
||||
if (possible_cs) {
|
||||
fprintf( stderr, ", far call assumed" );
|
||||
}
|
||||
fprintf( stderr, ")\n" );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL DEBUG_Frame32(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
|
||||
{
|
||||
unsigned int ss = addr->seg;
|
||||
FRAME32 *frame = (FRAME32 *)DBG_ADDR_TO_LIN(addr);
|
||||
int theframe = nframe;
|
||||
|
||||
if (DEBUG_IsBadReadPtr( addr, sizeof(FRAME32) )) {
|
||||
unsigned int ss = addr->seg;
|
||||
FRAME32 frame;
|
||||
int theframe = nframe;
|
||||
void* p = (void*)DEBUG_ToLinear(addr);
|
||||
|
||||
if (!p) return FALSE;
|
||||
|
||||
if (!DEBUG_READ_MEM(p, &frame, sizeof(frame))) {
|
||||
if (noisy) {
|
||||
fprintf(stderr,"*** Invalid address ");
|
||||
DEBUG_PrintAddress(addr, dbg_mode, FALSE);
|
||||
DEBUG_PrintAddress(addr, DEBUG_CurrThread->dbg_mode, FALSE);
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if (!frame->ip) return FALSE;
|
||||
if (!frame.ip) return FALSE;
|
||||
|
||||
nframe++;
|
||||
frames = (struct bt_info *)DBG_realloc(frames,
|
||||
nframe*sizeof(struct bt_info));
|
||||
nframe*sizeof(struct bt_info));
|
||||
if (noisy)
|
||||
fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : " "),
|
||||
frameno);
|
||||
fprintf(stderr,"%s%d ", (theframe == curr_frame ? "=>" : " "),
|
||||
frameno);
|
||||
frames[theframe].cs = addr->seg = *cs;
|
||||
frames[theframe].eip = addr->off = frame->ip;
|
||||
frames[theframe].eip = addr->off = frame.ip;
|
||||
if (noisy)
|
||||
frames[theframe].frame = DEBUG_PrintAddressAndArgs( addr, 32,
|
||||
frame->bp, TRUE );
|
||||
frames[theframe].frame = DEBUG_PrintAddressAndArgs( addr, 32,
|
||||
frame.bp, TRUE );
|
||||
else
|
||||
DEBUG_FindNearestSymbol( addr, TRUE,
|
||||
&frames[theframe].frame.sym, frame->bp,
|
||||
&frames[theframe].frame.list);
|
||||
if (noisy) fprintf( stderr, " (ebp=%08lx)\n", frame->bp );
|
||||
DEBUG_FindNearestSymbol( addr, TRUE,
|
||||
&frames[theframe].frame.sym, frame.bp,
|
||||
&frames[theframe].frame.list);
|
||||
if (noisy) fprintf( stderr, " (ebp=%08lx)\n", frame.bp );
|
||||
frames[theframe].ss = addr->seg = ss;
|
||||
frames[theframe].ebp = frame->bp;
|
||||
if (addr->off == frame->bp) return FALSE;
|
||||
addr->off = frame->bp;
|
||||
frames[theframe].ebp = frame.bp;
|
||||
if (addr->off == frame.bp) return FALSE;
|
||||
addr->off = frame.bp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void DEBUG_DoBackTrace(int noisy)
|
||||
{
|
||||
DBG_ADDR addr, sw_addr;
|
||||
unsigned int ss = SS_reg(&DEBUG_context), cs = CS_reg(&DEBUG_context);
|
||||
int frameno = 0, is16, ok;
|
||||
DWORD next_switch, cur_switch;
|
||||
|
||||
if (noisy) fprintf( stderr, "Backtrace:\n" );
|
||||
|
||||
nframe = 1;
|
||||
if (frames) DBG_free( frames );
|
||||
frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) );
|
||||
if (noisy)
|
||||
fprintf(stderr,"%s%d ",(curr_frame == 0 ? "=>" : " "), frameno);
|
||||
|
||||
if (IS_SELECTOR_SYSTEM(ss)) ss = 0;
|
||||
if (IS_SELECTOR_SYSTEM(cs)) cs = 0;
|
||||
|
||||
/* first stack frame from registers */
|
||||
if (IS_SELECTOR_32BIT(ss))
|
||||
{
|
||||
frames[0].cs = addr.seg = cs;
|
||||
frames[0].eip = addr.off = EIP_reg(&DEBUG_context);
|
||||
if (noisy)
|
||||
frames[0].frame = DEBUG_PrintAddress( &addr, 32, TRUE );
|
||||
else
|
||||
DEBUG_FindNearestSymbol( &addr, TRUE, &frames[0].frame.sym, 0,
|
||||
&frames[0].frame.list);
|
||||
frames[0].ss = addr.seg = ss;
|
||||
frames[0].ebp = addr.off = EBP_reg(&DEBUG_context);
|
||||
if (noisy) fprintf( stderr, " (ebp=%08x)\n", frames[0].ebp );
|
||||
is16 = FALSE;
|
||||
} else {
|
||||
frames[0].cs = addr.seg = cs;
|
||||
frames[0].eip = addr.off = LOWORD(EIP_reg(&DEBUG_context));
|
||||
if (noisy)
|
||||
frames[0].frame = DEBUG_PrintAddress( &addr, 16, TRUE );
|
||||
else
|
||||
DEBUG_FindNearestSymbol( &addr, TRUE, &frames[0].frame.sym, 0,
|
||||
&frames[0].frame.list);
|
||||
frames[0].ss = addr.seg = ss;
|
||||
frames[0].ebp = addr.off = BP_reg(&DEBUG_context);
|
||||
if (noisy) fprintf( stderr, " (bp=%04x)\n", frames[0].ebp );
|
||||
is16 = TRUE;
|
||||
}
|
||||
|
||||
next_switch = NtCurrentTeb()->cur_stack;
|
||||
if (is16) {
|
||||
if (IsBadReadPtr((STACK32FRAME*)next_switch, sizeof(STACK32FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK32FRAME*)next_switch );
|
||||
return;
|
||||
}
|
||||
cur_switch = (DWORD)((STACK32FRAME*)next_switch)->frame16;
|
||||
sw_addr.seg = SELECTOROF(cur_switch);
|
||||
sw_addr.off = OFFSETOF(cur_switch);
|
||||
} else {
|
||||
if (IsBadReadPtr((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch), sizeof(STACK16FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK16FRAME*)PTR_SEG_TO_LIN(next_switch) );
|
||||
return;
|
||||
}
|
||||
cur_switch = (DWORD)((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch))->frame32;
|
||||
sw_addr.seg = ss;
|
||||
sw_addr.off = cur_switch;
|
||||
}
|
||||
if (DEBUG_IsBadReadPtr(&sw_addr,1)) {
|
||||
sw_addr.seg = (DWORD)-1;
|
||||
sw_addr.off = (DWORD)-1;
|
||||
}
|
||||
|
||||
for (ok = TRUE; ok;) {
|
||||
if ((frames[frameno].ss == sw_addr.seg) &&
|
||||
(frames[frameno].ebp >= sw_addr.off)) {
|
||||
/* 16<->32 switch...
|
||||
* yes, I know this is confusing, it gave me a headache too */
|
||||
if (is16) {
|
||||
STACK32FRAME *frame = (STACK32FRAME*)next_switch;
|
||||
DBG_ADDR code;
|
||||
|
||||
if (IsBadReadPtr((STACK32FRAME*)next_switch, sizeof(STACK32FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK32FRAME*)next_switch );
|
||||
return;
|
||||
}
|
||||
code.type = NULL;
|
||||
code.seg = 0;
|
||||
code.off = frame->retaddr;
|
||||
|
||||
cs = 0;
|
||||
addr.seg = 0;
|
||||
addr.off = frame->ebp;
|
||||
DEBUG_ForceFrame( &addr, &code, ++frameno, 32, noisy );
|
||||
|
||||
next_switch = cur_switch;
|
||||
if (IsBadReadPtr((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch), sizeof(STACK16FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK16FRAME*)PTR_SEG_TO_LIN(next_switch) );
|
||||
return;
|
||||
}
|
||||
cur_switch = (DWORD)((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch))->frame32;
|
||||
sw_addr.seg = 0;
|
||||
sw_addr.off = cur_switch;
|
||||
|
||||
is16 = FALSE;
|
||||
} else {
|
||||
STACK16FRAME *frame = (STACK16FRAME*)PTR_SEG_TO_LIN(next_switch);
|
||||
DBG_ADDR code;
|
||||
|
||||
if (IsBadReadPtr((STACK16FRAME*)PTR_SEG_TO_LIN(next_switch), sizeof(STACK16FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK16FRAME*)PTR_SEG_TO_LIN(next_switch) );
|
||||
return;
|
||||
}
|
||||
|
||||
code.type = NULL;
|
||||
code.seg = frame->cs;
|
||||
code.off = frame->ip;
|
||||
|
||||
cs = frame->cs;
|
||||
addr.seg = SELECTOROF(next_switch);
|
||||
addr.off = frame->bp;
|
||||
DEBUG_ForceFrame( &addr, &code, ++frameno, 16, noisy );
|
||||
|
||||
next_switch = cur_switch;
|
||||
if (IsBadReadPtr((STACK32FRAME*)next_switch, sizeof(STACK32FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK32FRAME*)next_switch );
|
||||
return;
|
||||
}
|
||||
cur_switch = (DWORD)((STACK32FRAME*)next_switch)->frame16;
|
||||
sw_addr.seg = SELECTOROF(cur_switch);
|
||||
sw_addr.off = OFFSETOF(cur_switch);
|
||||
|
||||
is16 = TRUE;
|
||||
}
|
||||
if (DEBUG_IsBadReadPtr(&sw_addr,1)) {
|
||||
sw_addr.seg = (DWORD)-1;
|
||||
sw_addr.off = (DWORD)-1;
|
||||
}
|
||||
} else {
|
||||
/* ordinary stack frame */
|
||||
ok = is16 ? DEBUG_Frame16( &addr, &cs, ++frameno, noisy)
|
||||
: DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
|
||||
}
|
||||
}
|
||||
if (noisy) fprintf( stderr, "\n" );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_BackTrace
|
||||
*
|
||||
* Display a stack back-trace.
|
||||
*/
|
||||
void DEBUG_BackTrace(void)
|
||||
void DEBUG_BackTrace(BOOL noisy)
|
||||
{
|
||||
#ifdef __i386__
|
||||
DEBUG_DoBackTrace( TRUE );
|
||||
#endif
|
||||
}
|
||||
#ifdef __i386
|
||||
DBG_ADDR addr, sw_addr, code, tmp;
|
||||
unsigned int ss = DEBUG_context.SegSs;
|
||||
unsigned int cs = DEBUG_context.SegCs;
|
||||
int frameno = 0, is16, ok;
|
||||
DWORD next_switch, cur_switch, p;
|
||||
STACK16FRAME frame16;
|
||||
STACK32FRAME frame32;
|
||||
char ch;
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_SilentBackTrace
|
||||
*
|
||||
* Display a stack back-trace.
|
||||
*/
|
||||
void DEBUG_SilentBackTrace(void)
|
||||
{
|
||||
#ifdef __i386__
|
||||
DEBUG_DoBackTrace( FALSE );
|
||||
if (noisy) fprintf( stderr, "Backtrace:\n" );
|
||||
|
||||
nframe = 1;
|
||||
if (frames) DBG_free( frames );
|
||||
frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) );
|
||||
if (noisy)
|
||||
fprintf(stderr,"%s%d ",(curr_frame == 0 ? "=>" : " "), frameno);
|
||||
|
||||
if (DEBUG_IsSelectorSystem(ss)) ss = 0;
|
||||
if (DEBUG_IsSelectorSystem(cs)) cs = 0;
|
||||
|
||||
/* first stack frame from registers */
|
||||
switch (DEBUG_GetSelectorType(ss))
|
||||
{
|
||||
case 32:
|
||||
frames[0].cs = addr.seg = cs;
|
||||
frames[0].eip = addr.off = DEBUG_context.Eip;
|
||||
if (noisy)
|
||||
frames[0].frame = DEBUG_PrintAddress( &addr, 32, TRUE );
|
||||
else
|
||||
DEBUG_FindNearestSymbol( &addr, TRUE, &frames[0].frame.sym, 0,
|
||||
&frames[0].frame.list);
|
||||
frames[0].ss = addr.seg = ss;
|
||||
frames[0].ebp = addr.off = DEBUG_context.Ebp;
|
||||
if (noisy) fprintf( stderr, " (ebp=%08x)\n", frames[0].ebp );
|
||||
is16 = FALSE;
|
||||
break;
|
||||
case 16:
|
||||
frames[0].cs = addr.seg = cs;
|
||||
frames[0].eip = addr.off = LOWORD(DEBUG_context.Eip);
|
||||
if (noisy)
|
||||
frames[0].frame = DEBUG_PrintAddress( &addr, 16, TRUE );
|
||||
else
|
||||
DEBUG_FindNearestSymbol( &addr, TRUE, &frames[0].frame.sym, 0,
|
||||
&frames[0].frame.list);
|
||||
frames[0].ss = addr.seg = ss;
|
||||
frames[0].ebp = addr.off = LOWORD(DEBUG_context.Ebp);
|
||||
if (noisy) fprintf( stderr, " (bp=%04x)\n", frames[0].ebp );
|
||||
is16 = TRUE;
|
||||
break;
|
||||
default:
|
||||
if (noisy) fprintf( stderr, "Bad segment '%u'\n", ss);
|
||||
return;
|
||||
}
|
||||
|
||||
/* cur_switch holds address of curr_stack's field in TEB in debuggee
|
||||
* address space
|
||||
*/
|
||||
cur_switch = (DWORD)DEBUG_CurrThread->teb + OFFSET_OF(TEB, cur_stack);
|
||||
if (!DEBUG_READ_MEM((void*)cur_switch, &next_switch, sizeof(next_switch))) {
|
||||
if (noisy) fprintf( stderr, "Can't read TEB:cur_stack\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (is16) {
|
||||
if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n",
|
||||
(STACK32FRAME*)next_switch );
|
||||
return;
|
||||
}
|
||||
cur_switch = (DWORD)frame32.frame16;
|
||||
sw_addr.seg = SELECTOROF(cur_switch);
|
||||
sw_addr.off = OFFSETOF(cur_switch);
|
||||
} else {
|
||||
tmp.seg = SELECTOROF(next_switch);
|
||||
tmp.off = OFFSETOF(next_switch);
|
||||
p = DEBUG_ToLinear(&tmp);
|
||||
|
||||
if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK16FRAME*)p );
|
||||
return;
|
||||
}
|
||||
cur_switch = (DWORD)frame16.frame32;
|
||||
sw_addr.seg = ss;
|
||||
sw_addr.off = cur_switch;
|
||||
}
|
||||
if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
|
||||
sw_addr.seg = (DWORD)-1;
|
||||
sw_addr.off = (DWORD)-1;
|
||||
}
|
||||
|
||||
for (ok = TRUE; ok;) {
|
||||
if ((frames[frameno].ss == sw_addr.seg) &&
|
||||
(frames[frameno].ebp >= sw_addr.off)) {
|
||||
/* 16<->32 switch...
|
||||
* yes, I know this is confusing, it gave me a headache too */
|
||||
if (is16) {
|
||||
|
||||
if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n", (STACK32FRAME*)next_switch );
|
||||
return;
|
||||
}
|
||||
code.type = NULL;
|
||||
code.seg = 0;
|
||||
code.off = frame32.retaddr;
|
||||
|
||||
cs = 0;
|
||||
addr.seg = 0;
|
||||
addr.off = frame32.ebp;
|
||||
DEBUG_ForceFrame( &addr, &code, ++frameno, 32, noisy );
|
||||
|
||||
next_switch = cur_switch;
|
||||
tmp.seg = SELECTOROF(next_switch);
|
||||
tmp.off = OFFSETOF(next_switch);
|
||||
p = DEBUG_ToLinear(&tmp);
|
||||
|
||||
if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n",
|
||||
(STACK16FRAME*)p );
|
||||
return;
|
||||
}
|
||||
cur_switch = (DWORD)frame16.frame32;
|
||||
sw_addr.seg = 0;
|
||||
sw_addr.off = cur_switch;
|
||||
|
||||
is16 = FALSE;
|
||||
} else {
|
||||
tmp.seg = SELECTOROF(next_switch);
|
||||
tmp.off = OFFSETOF(next_switch);
|
||||
p = DEBUG_ToLinear(&tmp);
|
||||
|
||||
if (!DEBUG_READ_MEM((void*)p, &frame16, sizeof(STACK16FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n",
|
||||
(STACK16FRAME*)p );
|
||||
return;
|
||||
}
|
||||
|
||||
code.type = NULL;
|
||||
code.seg = frame16.cs;
|
||||
code.off = frame16.ip;
|
||||
|
||||
cs = frame16.cs;
|
||||
addr.seg = SELECTOROF(next_switch);
|
||||
addr.off = frame16.bp;
|
||||
DEBUG_ForceFrame( &addr, &code, ++frameno, 16, noisy );
|
||||
|
||||
next_switch = cur_switch;
|
||||
if (!DEBUG_READ_MEM((void*)next_switch, &frame32, sizeof(STACK32FRAME))) {
|
||||
if (noisy) fprintf( stderr, "Bad stack frame %p\n",
|
||||
(STACK32FRAME*)next_switch );
|
||||
return;
|
||||
}
|
||||
cur_switch = (DWORD)frame32.frame16;
|
||||
sw_addr.seg = SELECTOROF(cur_switch);
|
||||
sw_addr.off = OFFSETOF(cur_switch);
|
||||
|
||||
is16 = TRUE;
|
||||
}
|
||||
if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear(&sw_addr), &ch, sizeof(ch))) {
|
||||
sw_addr.seg = (DWORD)-1;
|
||||
sw_addr.off = (DWORD)-1;
|
||||
}
|
||||
} else {
|
||||
/* ordinary stack frame */
|
||||
ok = is16 ? DEBUG_Frame16( &addr, &cs, ++frameno, noisy)
|
||||
: DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
|
||||
}
|
||||
}
|
||||
if (noisy) fprintf( stderr, "\n" );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -345,7 +345,7 @@ DEBUG_InitTypes()
|
|||
}
|
||||
|
||||
long long int
|
||||
DEBUG_GetExprValue(DBG_ADDR * addr, char ** format)
|
||||
DEBUG_GetExprValue(const DBG_ADDR * addr, char ** format)
|
||||
{
|
||||
DBG_ADDR address = *addr;
|
||||
unsigned int rtn;
|
||||
|
@ -360,12 +360,10 @@ DEBUG_GetExprValue(DBG_ADDR * addr, char ** format)
|
|||
switch(addr->type->type)
|
||||
{
|
||||
case DT_BASIC:
|
||||
if (!DBG_CHECK_READ_PTR( &address, addr->type->un.basic.basic_size))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)addr->off, &rtn, addr->type->un.basic.basic_size))
|
||||
return 0;
|
||||
|
||||
memcpy(&rtn, (char *) addr->off, addr->type->un.basic.basic_size);
|
||||
if( (addr->type->un.basic.b_signed)
|
||||
&& ((addr->type->un.basic.basic_size & 3) != 0)
|
||||
&& ((rtn >> (addr->type->un.basic.basic_size * 8 - 1)) != 0) )
|
||||
|
@ -388,8 +386,9 @@ DEBUG_GetExprValue(DBG_ADDR * addr, char ** format)
|
|||
}
|
||||
break;
|
||||
case DT_POINTER:
|
||||
if (!DBG_CHECK_READ_PTR( &address, 1 )) return 0;
|
||||
rtn = (unsigned int) *((unsigned char **)addr->off);
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)addr->off, &rtn, sizeof(void*)))
|
||||
return 0;
|
||||
|
||||
type2 = addr->type->un.pointer.pointsto;
|
||||
|
||||
if (!type2)
|
||||
|
@ -402,9 +401,8 @@ DEBUG_GetExprValue(DBG_ADDR * addr, char ** format)
|
|||
if( type2->type == DT_BASIC && type2->un.basic.basic_size == 1 )
|
||||
{
|
||||
def_format = "\"%s\"";
|
||||
address.off = rtn;
|
||||
address.seg = 0;
|
||||
if (!DBG_CHECK_READ_PTR( &address, 1 )) return 0;
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)rtn, &rtn, 1))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
@ -414,13 +412,13 @@ DEBUG_GetExprValue(DBG_ADDR * addr, char ** format)
|
|||
break;
|
||||
case DT_ARRAY:
|
||||
case DT_STRUCT:
|
||||
if (!DBG_CHECK_READ_PTR( &address, 1 )) return 0;
|
||||
rtn = (unsigned int) *((unsigned char **)addr->off);
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)addr->off, &rtn, sizeof(rtn)))
|
||||
return 0;
|
||||
def_format = "0x%8.8x";
|
||||
break;
|
||||
case DT_ENUM:
|
||||
if (!DBG_CHECK_READ_PTR( &address, 1 )) return 0;
|
||||
rtn = (unsigned int) *((unsigned char **)addr->off);
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)addr->off, &rtn, sizeof(rtn)))
|
||||
return 0;
|
||||
for(e = addr->type->un.enumeration.members; e; e = e->next )
|
||||
{
|
||||
if( e->value == rtn )
|
||||
|
@ -452,22 +450,23 @@ DEBUG_GetExprValue(DBG_ADDR * addr, char ** format)
|
|||
}
|
||||
|
||||
unsigned int
|
||||
DEBUG_TypeDerefPointer(DBG_ADDR * addr, struct datatype ** newtype)
|
||||
DEBUG_TypeDerefPointer(const DBG_ADDR * addr, struct datatype ** newtype)
|
||||
{
|
||||
DBG_ADDR address = *addr;
|
||||
unsigned int val;
|
||||
|
||||
/*
|
||||
* Make sure that this really makes sense.
|
||||
*/
|
||||
if( addr->type->type != DT_POINTER )
|
||||
if( addr->type->type != DT_POINTER || !DEBUG_READ_MEM((void*)addr->off, &val, sizeof(val)))
|
||||
{
|
||||
*newtype = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*newtype = addr->type->un.pointer.pointsto;
|
||||
address.off = *(unsigned int*) (addr->off);
|
||||
return (unsigned int)DBG_ADDR_TO_LIN(&address); /* FIXME: is this right (or "better") ? */
|
||||
address.off = val;
|
||||
return DEBUG_ToLinear(&address); /* FIXME: is this right (or "better") ? */
|
||||
}
|
||||
|
||||
unsigned int
|
||||
|
@ -718,7 +717,7 @@ int DEBUG_GetObjectSize(struct datatype * dt)
|
|||
}
|
||||
|
||||
unsigned int
|
||||
DEBUG_ArrayIndex(DBG_ADDR * addr, DBG_ADDR * result, int index)
|
||||
DEBUG_ArrayIndex(const DBG_ADDR * addr, DBG_ADDR * result, int index)
|
||||
{
|
||||
int size;
|
||||
|
||||
|
|
|
@ -0,0 +1,479 @@
|
|||
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
|
||||
|
||||
/* Wine internal debugger
|
||||
* Interface to Windows debugger API
|
||||
* Eric Pouech (c) 2000
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include "debugger.h"
|
||||
#include "winbase.h"
|
||||
#include "winreg.h"
|
||||
#include "debugtools.h"
|
||||
#include "options.h"
|
||||
|
||||
#ifdef DBG_need_heap
|
||||
HANDLE dbg_heap = 0;
|
||||
#endif
|
||||
|
||||
DEFAULT_DEBUG_CHANNEL(winedbg);
|
||||
|
||||
WINE_DBG_PROCESS* DEBUG_CurrProcess = NULL;
|
||||
WINE_DBG_THREAD* DEBUG_CurrThread = NULL;
|
||||
CONTEXT DEBUG_context;
|
||||
|
||||
static WINE_DBG_PROCESS* proc = NULL;
|
||||
|
||||
static WINE_DBG_PROCESS* DEBUG_GetProcess(DWORD pid)
|
||||
{
|
||||
WINE_DBG_PROCESS* p;
|
||||
|
||||
for (p = proc; p; p = p->next)
|
||||
if (p->pid == pid) break;
|
||||
return p;
|
||||
}
|
||||
|
||||
static WINE_DBG_PROCESS* DEBUG_AddProcess(DWORD pid, HANDLE h)
|
||||
{
|
||||
WINE_DBG_PROCESS* p = DBG_alloc(sizeof(WINE_DBG_PROCESS));
|
||||
if (!p)
|
||||
return NULL;
|
||||
p->handle = h;
|
||||
p->pid = pid;
|
||||
p->threads = NULL;
|
||||
|
||||
p->next = proc;
|
||||
p->prev = NULL;
|
||||
if (proc) proc->prev = p;
|
||||
proc = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void DEBUG_DelThread(WINE_DBG_THREAD* p);
|
||||
|
||||
static void DEBUG_DelProcess(WINE_DBG_PROCESS* p)
|
||||
{
|
||||
if (p->threads != NULL) {
|
||||
ERR("Shouldn't happen\n");
|
||||
while (p->threads) DEBUG_DelThread(p->threads);
|
||||
}
|
||||
if (p->prev) p->prev->next = p->next;
|
||||
if (p->next) p->next->prev = p->prev;
|
||||
if (p == proc) proc = p->next;
|
||||
DBG_free(p);
|
||||
}
|
||||
|
||||
static void DEBUG_InitCurrProcess(void)
|
||||
{
|
||||
#ifdef DBG_need_heap
|
||||
/*
|
||||
* Initialize the debugger heap.
|
||||
*/
|
||||
dbg_heap = HeapCreate(HEAP_NO_SERIALIZE, 0x1000, 0x8000000); /* 128MB */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize the type handling stuff.
|
||||
*/
|
||||
DEBUG_InitTypes();
|
||||
DEBUG_InitCVDataTypes();
|
||||
|
||||
/*
|
||||
* In some cases we can read the stabs information directly
|
||||
* from the executable. If this is the case, we don't need
|
||||
* to bother with trying to read a symbol file, as the stabs
|
||||
* also have line number and local variable information.
|
||||
* As long as gcc is used for the compiler, stabs will
|
||||
* be the default. On SVr4, DWARF could be used, but we
|
||||
* don't grok that yet, and in this case we fall back to using
|
||||
* the wine.sym file.
|
||||
*/
|
||||
if( DEBUG_ReadExecutableDbgInfo() == FALSE )
|
||||
{
|
||||
char* symfilename = "wine.sym";
|
||||
struct stat statbuf;
|
||||
HKEY hWineConf, hkey;
|
||||
DWORD count;
|
||||
char symbolTableFile[256];
|
||||
|
||||
if (-1 == stat(symfilename, &statbuf) )
|
||||
symfilename = LIBDIR "wine.sym";
|
||||
|
||||
strcpy(symbolTableFile, symfilename);
|
||||
if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", &hWineConf)) {
|
||||
if (!RegOpenKeyA(hWineConf, "wine", &hkey)) {
|
||||
count = sizeof(symbolTableFile);
|
||||
RegQueryValueA(hkey, "SymbolTableFile", symbolTableFile, &count);
|
||||
RegCloseKey(hkey);
|
||||
}
|
||||
RegCloseKey(hWineConf);
|
||||
}
|
||||
DEBUG_ReadSymbolTable(symbolTableFile);
|
||||
}
|
||||
DEBUG_LoadEntryPoints(NULL);
|
||||
DEBUG_ProcessDeferredDebug();
|
||||
}
|
||||
|
||||
static BOOL DEBUG_ProcessGetString(char* buffer, int size,
|
||||
HANDLE hp, LPVOID addr)
|
||||
{
|
||||
LPVOID ad;
|
||||
DWORD sz;
|
||||
|
||||
if ( addr
|
||||
&& ReadProcessMemory(hp, addr, &ad, sizeof(ad), &sz)
|
||||
&& sz == sizeof(ad)
|
||||
&& ad
|
||||
&& ReadProcessMemory(hp, ad, buffer, size, &sz))
|
||||
return TRUE;
|
||||
*(WCHAR*)buffer = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static WINE_DBG_THREAD* DEBUG_GetThread(WINE_DBG_PROCESS* p, DWORD tid)
|
||||
{
|
||||
WINE_DBG_THREAD* t;
|
||||
|
||||
for (t = p->threads; t; t = t->next)
|
||||
if (t->tid == tid) break;
|
||||
return t;
|
||||
}
|
||||
|
||||
static WINE_DBG_THREAD* DEBUG_AddThread(WINE_DBG_PROCESS* p, DWORD tid,
|
||||
HANDLE h, LPVOID start, LPVOID teb)
|
||||
{
|
||||
WINE_DBG_THREAD* t = DBG_alloc(sizeof(WINE_DBG_THREAD));
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
t->handle = h;
|
||||
t->tid = tid;
|
||||
t->start = start;
|
||||
t->teb = teb;
|
||||
t->process = p;
|
||||
t->wait_for_first_exception = 0;
|
||||
t->dbg_exec_mode = EXEC_CONT;
|
||||
t->dbg_exec_count = 0;
|
||||
|
||||
t->next = p->threads;
|
||||
t->prev = NULL;
|
||||
if (p->threads) p->threads->prev = t;
|
||||
p->threads = t;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void DEBUG_InitCurrThread(void)
|
||||
{
|
||||
if (!Options.debug) return;
|
||||
|
||||
if (DEBUG_CurrThread->start) {
|
||||
DBG_ADDR addr;
|
||||
|
||||
DEBUG_SetBreakpoints(FALSE);
|
||||
addr.seg = 0;
|
||||
addr.off = (DWORD)DEBUG_CurrThread->start;
|
||||
DEBUG_AddBreakpoint(&addr);
|
||||
DEBUG_SetBreakpoints(TRUE);
|
||||
} else {
|
||||
DEBUG_CurrThread->wait_for_first_exception = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void DEBUG_DelThread(WINE_DBG_THREAD* t)
|
||||
{
|
||||
if (t->prev) t->prev->next = t->next;
|
||||
if (t->next) t->next->prev = t->prev;
|
||||
if (t == t->process->threads) t->process->threads = t->next;
|
||||
DBG_free(t);
|
||||
}
|
||||
|
||||
static BOOL DEBUG_HandleException( EXCEPTION_RECORD *rec, BOOL first_chance, BOOL force )
|
||||
{
|
||||
BOOL is_debug = FALSE;
|
||||
BOOL ret;
|
||||
|
||||
if (first_chance && !Options.debug && !force ) return 0; /* pass to app first */
|
||||
|
||||
switch (rec->ExceptionCode)
|
||||
{
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
is_debug = TRUE;
|
||||
break;
|
||||
case CONTROL_C_EXIT:
|
||||
if (!Options.debug) DEBUG_Exit(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_debug)
|
||||
{
|
||||
/* print some infos */
|
||||
fprintf( stderr, "%s: ",
|
||||
first_chance ? "First chance exception" : "Unhandled exception" );
|
||||
switch(rec->ExceptionCode)
|
||||
{
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
fprintf( stderr, "divide by zero" );
|
||||
break;
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
fprintf( stderr, "overflow" );
|
||||
break;
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
fprintf( stderr, "array bounds " );
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
fprintf( stderr, "illegal instruction" );
|
||||
break;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
fprintf( stderr, "stack overflow" );
|
||||
break;
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
fprintf( stderr, "priviledged instruction" );
|
||||
break;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
if (rec->NumberParameters == 2)
|
||||
fprintf( stderr, "page fault on %s access to 0x%08lx",
|
||||
rec->ExceptionInformation[0] ? "write" : "read",
|
||||
rec->ExceptionInformation[1] );
|
||||
else
|
||||
fprintf( stderr, "page fault" );
|
||||
break;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
fprintf( stderr, "Alignment" );
|
||||
break;
|
||||
case CONTROL_C_EXIT:
|
||||
fprintf( stderr, "^C" );
|
||||
break;
|
||||
case EXCEPTION_CRITICAL_SECTION_WAIT:
|
||||
fprintf( stderr, "critical section %08lx wait failed",
|
||||
rec->ExceptionInformation[0] );
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "%08lx", rec->ExceptionCode );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
fprintf(stderr, "Entering debugger PC=%lx EFL=%08lx mode=%d count=%d\n",
|
||||
DEBUG_context.Eip, DEBUG_context.EFlags,
|
||||
DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
|
||||
#endif
|
||||
|
||||
ret = DEBUG_Main( is_debug, force );
|
||||
#if 1
|
||||
fprintf(stderr, "Exiting debugger PC=%lx EFL=%08lx mode=%d count=%d\n",
|
||||
DEBUG_context.Eip, DEBUG_context.EFlags,
|
||||
DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static DWORD CALLBACK DEBUG_MainLoop(LPVOID pid)
|
||||
{
|
||||
DEBUG_EVENT de;
|
||||
char buffer[256];
|
||||
DWORD cont;
|
||||
|
||||
TRACE("WineDbg started on pid %ld\n", (DWORD)pid);
|
||||
|
||||
if (!DebugActiveProcess((DWORD)pid))
|
||||
TRACE("Can't debug process %ld: %ld\n", (DWORD)pid, GetLastError());
|
||||
|
||||
while (WaitForDebugEvent(&de, INFINITE)) {
|
||||
cont = 0L;
|
||||
|
||||
if ((DEBUG_CurrProcess = DEBUG_GetProcess(de.dwProcessId)) != NULL)
|
||||
DEBUG_CurrThread = DEBUG_GetThread(DEBUG_CurrProcess, de.dwThreadId);
|
||||
else
|
||||
DEBUG_CurrThread = NULL;
|
||||
|
||||
switch (de.dwDebugEventCode) {
|
||||
case EXCEPTION_DEBUG_EVENT:
|
||||
if (!DEBUG_CurrThread) break;
|
||||
|
||||
TRACE("%08lx:%08lx: exception code=%08lx %d\n",
|
||||
de.dwProcessId, de.dwThreadId,
|
||||
de.u.Exception.ExceptionRecord.ExceptionCode,
|
||||
DEBUG_CurrThread->wait_for_first_exception);
|
||||
|
||||
DEBUG_context.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_SEGMENTS|CONTEXT_DEBUG_REGISTERS;
|
||||
if (!GetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context)) {
|
||||
WARN("Can't get thread's context\n");
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE("%p:%p\n", de.u.Exception.ExceptionRecord.ExceptionAddress,
|
||||
(void*)DEBUG_context.Eip);
|
||||
|
||||
cont = DEBUG_HandleException(&de.u.Exception.ExceptionRecord,
|
||||
de.u.Exception.dwFirstChance,
|
||||
DEBUG_CurrThread->wait_for_first_exception);
|
||||
|
||||
if (DEBUG_CurrThread->wait_for_first_exception) {
|
||||
DEBUG_CurrThread->wait_for_first_exception = 0;
|
||||
#ifdef __i386__
|
||||
DEBUG_context.Eip--;
|
||||
#endif
|
||||
}
|
||||
SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context);
|
||||
break;
|
||||
|
||||
case CREATE_THREAD_DEBUG_EVENT:
|
||||
TRACE("%08lx:%08lx: create thread D @%p\n", de.dwProcessId, de.dwThreadId,
|
||||
de.u.CreateThread.lpStartAddress);
|
||||
|
||||
if (DEBUG_CurrProcess == NULL) {
|
||||
ERR("Unknown process\n");
|
||||
break;
|
||||
}
|
||||
if (DEBUG_GetThread(DEBUG_CurrProcess, de.dwThreadId) != NULL) {
|
||||
TRACE("Thread already listed, skipping\n");
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess,
|
||||
de.dwThreadId,
|
||||
de.u.CreateThread.hThread,
|
||||
de.u.CreateThread.lpStartAddress,
|
||||
de.u.CreateThread.lpThreadLocalBase);
|
||||
if (!DEBUG_CurrThread) {
|
||||
ERR("Couldn't create thread\n");
|
||||
break;
|
||||
}
|
||||
DEBUG_InitCurrThread();
|
||||
break;
|
||||
|
||||
case CREATE_PROCESS_DEBUG_EVENT:
|
||||
DEBUG_ProcessGetString(buffer, sizeof(buffer),
|
||||
de.u.CreateProcessInfo.hProcess,
|
||||
de.u.LoadDll.lpImageName);
|
||||
|
||||
/* FIXME unicode ? de.u.CreateProcessInfo.fUnicode */
|
||||
TRACE("%08lx:%08lx: create process %s @%p\n",
|
||||
de.dwProcessId, de.dwThreadId,
|
||||
buffer,
|
||||
de.u.CreateProcessInfo.lpStartAddress);
|
||||
|
||||
if (DEBUG_GetProcess(de.dwProcessId) != NULL) {
|
||||
TRACE("Skipping already defined process\n");
|
||||
break;
|
||||
}
|
||||
DEBUG_CurrProcess = DEBUG_AddProcess(de.dwProcessId,
|
||||
de.u.CreateProcessInfo.hProcess);
|
||||
if (DEBUG_CurrProcess == NULL) {
|
||||
ERR("Unknown process\n");
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE("%08lx:%08lx: create thread I @%p\n", de.dwProcessId, de.dwThreadId,
|
||||
de.u.CreateProcessInfo.lpStartAddress);
|
||||
|
||||
DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess,
|
||||
de.dwThreadId,
|
||||
de.u.CreateProcessInfo.hThread,
|
||||
de.u.CreateProcessInfo.lpStartAddress,
|
||||
de.u.CreateProcessInfo.lpThreadLocalBase);
|
||||
if (!DEBUG_CurrThread) {
|
||||
ERR("Couldn't create thread\n");
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_InitCurrProcess();
|
||||
DEBUG_InitCurrThread();
|
||||
break;
|
||||
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
TRACE("%08lx:%08lx: exit thread (%ld)\n",
|
||||
de.dwProcessId, de.dwThreadId, de.u.ExitThread.dwExitCode);
|
||||
|
||||
if (DEBUG_CurrThread == NULL) {
|
||||
ERR("Unknown thread\n");
|
||||
break;
|
||||
}
|
||||
/* FIXME: remove break point set on thread startup */
|
||||
DEBUG_DelThread(DEBUG_CurrThread);
|
||||
break;
|
||||
|
||||
case EXIT_PROCESS_DEBUG_EVENT:
|
||||
TRACE("%08lx:%08lx: exit process (%ld)\n",
|
||||
de.dwProcessId, de.dwThreadId, de.u.ExitProcess.dwExitCode);
|
||||
|
||||
if (DEBUG_CurrProcess == NULL) {
|
||||
ERR("Unknown process\n");
|
||||
break;
|
||||
}
|
||||
/* kill last thread */
|
||||
DEBUG_DelThread(DEBUG_CurrProcess->threads);
|
||||
/* FIXME: remove break point set on thread startup */
|
||||
DEBUG_DelProcess(DEBUG_CurrProcess);
|
||||
break;
|
||||
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
if (DEBUG_CurrThread == NULL) {
|
||||
ERR("Unknown thread\n");
|
||||
break;
|
||||
}
|
||||
DEBUG_ProcessGetString(buffer, sizeof(buffer),
|
||||
DEBUG_CurrThread->process->handle,
|
||||
de.u.LoadDll.lpImageName);
|
||||
|
||||
/* FIXME unicode: de.u.LoadDll.fUnicode */
|
||||
TRACE("%08lx:%08lx: loads DLL %s @%p\n", de.dwProcessId, de.dwThreadId,
|
||||
buffer, de.u.LoadDll.lpBaseOfDll);
|
||||
break;
|
||||
|
||||
case UNLOAD_DLL_DEBUG_EVENT:
|
||||
TRACE("%08lx:%08lx: unload DLL @%p\n", de.dwProcessId, de.dwThreadId,
|
||||
de.u.UnloadDll.lpBaseOfDll);
|
||||
break;
|
||||
|
||||
case OUTPUT_DEBUG_STRING_EVENT:
|
||||
if (DEBUG_CurrThread == NULL) {
|
||||
ERR("Unknown thread\n");
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_ProcessGetString(buffer, sizeof(buffer),
|
||||
DEBUG_CurrThread->process->handle,
|
||||
de.u.DebugString.lpDebugStringData);
|
||||
|
||||
|
||||
/* fixme unicode de.u.DebugString.fUnicode ? */
|
||||
TRACE("%08lx:%08lx: output debug string (%s)\n",
|
||||
de.dwProcessId, de.dwThreadId,
|
||||
buffer);
|
||||
break;
|
||||
|
||||
case RIP_EVENT:
|
||||
TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
|
||||
de.dwProcessId, de.dwThreadId, de.u.RipInfo.dwError,
|
||||
de.u.RipInfo.dwType);
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("%08lx:%08lx: unknown event (%ld)\n",
|
||||
de.dwProcessId, de.dwThreadId, de.dwDebugEventCode);
|
||||
}
|
||||
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, cont);
|
||||
}
|
||||
|
||||
TRACE("WineDbg terminated on pid %ld\n", (DWORD)pid);
|
||||
|
||||
return 0L;
|
||||
}
|
||||
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
|
||||
void DEBUG_StartDebugger(DWORD pid)
|
||||
{
|
||||
if (Options.debug)
|
||||
CreateThread(NULL, 0, DEBUG_MainLoop, (LPVOID)pid, 0, NULL);
|
||||
}
|
||||
|
|
@ -163,6 +163,7 @@ char dbch_wave[] = "\003wave";
|
|||
char dbch_win[] = "\003win";
|
||||
char dbch_win16drv[] = "\003win16drv";
|
||||
char dbch_win32[] = "\003win32";
|
||||
char dbch_winedbg[] = "\003winedbg";
|
||||
char dbch_wing[] = "\003wing";
|
||||
char dbch_winsock[] = "\003winsock";
|
||||
char dbch_winspool[] = "\003winspool";
|
||||
|
@ -170,7 +171,7 @@ char dbch_wnet[] = "\003wnet";
|
|||
char dbch_x11[] = "\003x11";
|
||||
char dbch_x11drv[] = "\003x11drv";
|
||||
|
||||
#define DEBUG_CHANNEL_COUNT 163
|
||||
#define DEBUG_CHANNEL_COUNT 164
|
||||
|
||||
static char * const debug_channels[DEBUG_CHANNEL_COUNT] = {
|
||||
dbch_accel,
|
||||
|
@ -330,6 +331,7 @@ static char * const debug_channels[DEBUG_CHANNEL_COUNT] = {
|
|||
dbch_win,
|
||||
dbch_win16drv,
|
||||
dbch_win32,
|
||||
dbch_winedbg,
|
||||
dbch_wing,
|
||||
dbch_winsock,
|
||||
dbch_winspool,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <assert.h>
|
||||
#include "wine/winbase16.h"
|
||||
#include "callback.h"
|
||||
#include "debugger.h"
|
||||
#include "main.h"
|
||||
#include "miscemu.h"
|
||||
#include "module.h"
|
||||
|
@ -22,6 +21,7 @@
|
|||
static int MAIN_argc;
|
||||
static char **MAIN_argv;
|
||||
|
||||
extern void DEBUG_StartDebugger(DWORD);
|
||||
|
||||
/***********************************************************************
|
||||
* Main loop of initial task
|
||||
|
@ -29,7 +29,6 @@ static char **MAIN_argv;
|
|||
void MAIN_EmulatorRun( void )
|
||||
{
|
||||
char startProg[256], defProg[256];
|
||||
HINSTANCE handle;
|
||||
int i, tasks = 0;
|
||||
MSG msg;
|
||||
BOOL err_msg = FALSE;
|
||||
|
@ -71,18 +70,31 @@ void MAIN_EmulatorRun( void )
|
|||
/* Load and run executables given on command line */
|
||||
for (i = 1; i < MAIN_argc; i++)
|
||||
{
|
||||
if ((handle = WinExec( MAIN_argv[i], SW_SHOWNORMAL )) < 32)
|
||||
{
|
||||
PROCESS_INFORMATION info;
|
||||
STARTUPINFOA startup;
|
||||
|
||||
memset(&startup, 0, sizeof(startup));
|
||||
startup.cb = sizeof(startup);
|
||||
startup.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startup.wShowWindow = SW_SHOWNORMAL;
|
||||
|
||||
if (!CreateProcessA(NULL, MAIN_argv[i], NULL, NULL, FALSE, 0,
|
||||
NULL, NULL, &startup, &info)) {
|
||||
err_msg = TRUE;
|
||||
MESSAGE("wine: can't exec '%s': ", MAIN_argv[i]);
|
||||
switch (handle)
|
||||
{
|
||||
case 2: MESSAGE("main executable or required DLL not found\n" ); break;
|
||||
case 11: MESSAGE("invalid exe file\n" ); break;
|
||||
default: MESSAGE("error=%d\n", handle ); break;
|
||||
}
|
||||
MESSAGE("wine: can't exec '%s': ", MAIN_argv[i]);
|
||||
switch (GetLastError())
|
||||
{
|
||||
case 2: MESSAGE("file not found\n" ); break;
|
||||
case 11: MESSAGE("invalid exe file\n" ); break;
|
||||
default: MESSAGE("error=%ld\n", GetLastError() ); break;
|
||||
}
|
||||
}
|
||||
else tasks++;
|
||||
else
|
||||
{
|
||||
tasks++;
|
||||
/* hack until wine debugger can be moved to a separate process */
|
||||
DEBUG_StartDebugger(info.dwProcessId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!tasks)
|
||||
|
|
Loading…
Reference in New Issue