- cleaned-up break handling
- better integration of debugger inner loops (parser & events) - added attach command - improved parser so that it can be entered without any process loaded - added BreakOnFirstChance internal variable - disabled NE module symbol module (which is broken with ASS) - misc portability cleanups
This commit is contained in:
parent
fb949605ba
commit
911436bfeb
|
@ -369,6 +369,47 @@ void DEBUG_AddBreakpoint( const DBG_VALUE *_value, BOOL (*func)(void) )
|
|||
DEBUG_Printf( DBG_CHN_MESG, "\n" );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_AddBreakpointFromId
|
||||
*
|
||||
* Add a breakpoint from a function name (and eventually a line #)
|
||||
*/
|
||||
void DEBUG_AddBreakpointFromId(const char *name, int lineno)
|
||||
{
|
||||
DBG_VALUE value;
|
||||
|
||||
if (DEBUG_GetSymbolValue(name, lineno, &value, TRUE))
|
||||
DEBUG_AddBreakpoint(&value, NULL);
|
||||
else
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint\n");
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_AddBreakpointFromLineno
|
||||
*
|
||||
* Add a breakpoint from a line number in current file
|
||||
*/
|
||||
void DEBUG_AddBreakpointFromLineno(int lineno)
|
||||
{
|
||||
DBG_VALUE value;
|
||||
|
||||
DEBUG_GetCurrentAddress(&value.addr);
|
||||
|
||||
if (lineno != -1) {
|
||||
struct name_hash* nh;
|
||||
|
||||
DEBUG_FindNearestSymbol(&value.addr, TRUE, &nh, 0, NULL);
|
||||
if (nh == NULL) {
|
||||
DEBUG_Printf(DBG_CHN_MESG,"Unable to add breakpoint\n");
|
||||
return;
|
||||
}
|
||||
DEBUG_GetLineNumberAddr(nh, lineno, &value.addr, TRUE);
|
||||
}
|
||||
|
||||
value.type = NULL;
|
||||
value.cookie = DV_TARGET;
|
||||
DEBUG_AddBreakpoint( &value, NULL );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_AddWatchpoint
|
||||
|
@ -438,6 +479,21 @@ void DEBUG_AddWatchpoint( const DBG_VALUE *_value, BOOL is_write )
|
|||
DEBUG_Printf( DBG_CHN_MESG, "\n" );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_AddWathpointFromId
|
||||
*
|
||||
* Add a watchpoint from a symbol name (and eventually a line #)
|
||||
*/
|
||||
void DEBUG_AddWatchpointFromId(const char *name, int lineno)
|
||||
{
|
||||
DBG_VALUE value;
|
||||
|
||||
if( DEBUG_GetSymbolValue(name, lineno, &value, TRUE) )
|
||||
DEBUG_AddWatchpoint( &value, 1 );
|
||||
else
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Unable to add watchpoint\n");
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_DelBreakpoint
|
||||
*
|
||||
|
@ -921,8 +977,6 @@ enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
|
|||
DEBUG_context.EFlags |= STEP_FLAG;
|
||||
#endif
|
||||
break;
|
||||
case EXEC_KILL:
|
||||
break;
|
||||
default:
|
||||
RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
|
||||
}
|
||||
|
|
357
debugger/dbg.y
357
debugger/dbg.y
|
@ -21,7 +21,6 @@
|
|||
#include "task.h"
|
||||
|
||||
extern FILE * yyin;
|
||||
int curr_frame = 0;
|
||||
|
||||
static void issue_prompt(void);
|
||||
static void mode_command(int);
|
||||
|
@ -37,20 +36,19 @@ int yyerror(char *);
|
|||
int integer;
|
||||
struct list_id listing;
|
||||
struct expr * expression;
|
||||
struct datatype * type;
|
||||
struct datatype* type;
|
||||
}
|
||||
|
||||
%token tCONT tPASS tSTEP tLIST tNEXT tQUIT tHELP tBACKTRACE tINFO tWALK tUP tDOWN
|
||||
%token tENABLE tDISABLE tBREAK tWATCH tDELETE tSET tMODE tPRINT tEXAM tABORT
|
||||
%token tCLASS tMAPS tMODULE tSTACK tSEGMENTS tREGS tWND tQUEUE tLOCAL
|
||||
%token tPROCESS tTHREAD tMODREF
|
||||
%token tEOL tSTRING tDEBUGSTR
|
||||
%token tPROCESS tTHREAD tMODREF tEOL
|
||||
%token tFRAME tSHARE tCOND tDISPLAY tUNDISPLAY tDISASSEMBLE
|
||||
%token tSTEPI tNEXTI tFINISH tSHOW tDIR tWHATIS
|
||||
%token <string> tPATH
|
||||
%token <string> tIDENTIFIER tSTRING tDEBUGSTR tINTVAR
|
||||
%token <integer> tNUM tFORMAT
|
||||
%token tSYMBOLFILE
|
||||
%token tSYMBOLFILE tRUN tATTACH tNOPROCESS
|
||||
|
||||
%token tCHAR tSHORT tINT tLONG tFLOAT tDOUBLE tUNSIGNED tSIGNED
|
||||
%token tSTRUCT tUNION tENUM
|
||||
|
@ -84,67 +82,67 @@ int yyerror(char *);
|
|||
|
||||
%%
|
||||
|
||||
input: line { issue_prompt(); }
|
||||
| input line { issue_prompt(); }
|
||||
input: line { issue_prompt(); }
|
||||
| input line { issue_prompt(); }
|
||||
|
||||
line: command
|
||||
| tEOL
|
||||
| error tEOL { yyerrok; }
|
||||
| error tEOL { yyerrok; }
|
||||
|
||||
command:
|
||||
tQUIT tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_KILL; return 1; }
|
||||
| tHELP tEOL { DEBUG_Help(); }
|
||||
| tHELP tINFO tEOL { DEBUG_HelpInfo(); }
|
||||
| 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(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 { 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(); }
|
||||
| tDISPLAY tEOL { DEBUG_InfoDisplay(); }
|
||||
| tDISPLAY expr tEOL { DEBUG_AddDisplay($2, 1, 0); }
|
||||
| tDISPLAY tFORMAT expr tEOL { DEBUG_AddDisplay($3, $2 >> 8, $2 & 0xff); }
|
||||
| tDELETE tDISPLAY tNUM tEOL { DEBUG_DelDisplay( $3 ); }
|
||||
| tDELETE tDISPLAY tEOL { DEBUG_DelDisplay( -1 ); }
|
||||
| tUNDISPLAY tNUM tEOL { DEBUG_DelDisplay( $2 ); }
|
||||
| tUNDISPLAY tEOL { DEBUG_DelDisplay( -1 ); }
|
||||
| tCOND tNUM tEOL { DEBUG_AddBPCondition($2, NULL); }
|
||||
| tCOND tNUM expr tEOL { DEBUG_AddBPCondition($2, $3); }
|
||||
| tSYMBOLFILE pathname tEOL{ DEBUG_ReadSymbolTable($2); }
|
||||
| tWHATIS expr_addr tEOL { DEBUG_PrintType(&$2); DEBUG_FreeExprMem(); }
|
||||
tQUIT tEOL { return FALSE; }
|
||||
| tHELP tEOL { DEBUG_Help(); }
|
||||
| tHELP tINFO tEOL { DEBUG_HelpInfo(); }
|
||||
| tCONT tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_CONT; return TRUE; }
|
||||
| tPASS tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_PASS; return TRUE; }
|
||||
| tCONT tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_CONT; return TRUE; }
|
||||
| tSTEP tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEP_INSTR; return TRUE; }
|
||||
| tNEXT tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEP_OVER; return TRUE; }
|
||||
| tSTEP tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEP_INSTR; return TRUE; }
|
||||
| tNEXT tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEP_OVER; return TRUE; }
|
||||
| tSTEPI tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEPI_INSTR; return TRUE; }
|
||||
| tNEXTI tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEPI_OVER; return TRUE; }
|
||||
| tSTEPI tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEPI_INSTR; return TRUE; }
|
||||
| tNEXTI tNUM tEOL { DEBUG_CurrThread->dbg_exec_count = $2;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_STEPI_OVER; return TRUE; }
|
||||
| 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(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 { DEBUG_CurrThread->dbg_exec_count = 0;
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_FINISH; return TRUE; }
|
||||
| tSHOW tDIR tEOL { DEBUG_ShowDir(); }
|
||||
| tDIR pathname tEOL { DEBUG_AddPath( $2 ); }
|
||||
| tDIR tEOL { DEBUG_NukePath(); }
|
||||
| tDISPLAY tEOL { DEBUG_InfoDisplay(); }
|
||||
| tDISPLAY expr tEOL { DEBUG_AddDisplay($2, 1, 0); }
|
||||
| tDISPLAY tFORMAT expr tEOL{ DEBUG_AddDisplay($3, $2 >> 8, $2 & 0xff); }
|
||||
| tDELETE tDISPLAY tNUM tEOL{ DEBUG_DelDisplay( $3 ); }
|
||||
| tDELETE tDISPLAY tEOL { DEBUG_DelDisplay( -1 ); }
|
||||
| tUNDISPLAY tNUM tEOL { DEBUG_DelDisplay( $2 ); }
|
||||
| tUNDISPLAY tEOL { DEBUG_DelDisplay( -1 ); }
|
||||
| tCOND tNUM tEOL { DEBUG_AddBPCondition($2, NULL); }
|
||||
| tCOND tNUM expr tEOL { DEBUG_AddBPCondition($2, $3); }
|
||||
| tSYMBOLFILE pathname tEOL { DEBUG_ReadSymbolTable($2); }
|
||||
| tWHATIS expr_addr tEOL { DEBUG_PrintType(&$2); DEBUG_FreeExprMem(); }
|
||||
| tATTACH tNUM tEOL { DEBUG_Attach($2, FALSE); return TRUE; }
|
||||
| list_command
|
||||
| disassemble_command
|
||||
| set_command
|
||||
|
@ -154,6 +152,8 @@ command:
|
|||
| watch_command
|
||||
| info_command
|
||||
| walk_command
|
||||
| run_command
|
||||
| noprocess_state
|
||||
|
||||
set_command:
|
||||
tSET lval_addr '=' expr_value tEOL { DEBUG_WriteMemory( &$2, $4 );
|
||||
|
@ -180,83 +180,33 @@ list_arg:
|
|||
| pathname ':' tNUM { $$.sourcefile = $1; $$.line = $3; }
|
||||
| tIDENTIFIER { DEBUG_GetFuncInfo( & $$, NULL, $1); }
|
||||
| pathname ':' tIDENTIFIER { DEBUG_GetFuncInfo( & $$, $1, $3); }
|
||||
| '*' expr_addr { DEBUG_FindNearestSymbol( & $2.addr, FALSE, NULL,
|
||||
0, & $$ );
|
||||
DEBUG_FreeExprMem(); }
|
||||
| '*' expr_addr { DEBUG_FindNearestSymbol( & $2.addr, FALSE, NULL, 0, & $$ );
|
||||
DEBUG_FreeExprMem(); }
|
||||
|
||||
x_command:
|
||||
tEXAM expr_addr tEOL { DEBUG_ExamineMemory( &$2, 1, 'x');
|
||||
DEBUG_FreeExprMem(); }
|
||||
tEXAM expr_addr tEOL { DEBUG_ExamineMemory( &$2, 1, 'x'); DEBUG_FreeExprMem(); }
|
||||
| tEXAM tFORMAT expr_addr tEOL { DEBUG_ExamineMemory( &$3, $2>>8, $2&0xff );
|
||||
DEBUG_FreeExprMem(); }
|
||||
DEBUG_FreeExprMem(); }
|
||||
|
||||
print_command:
|
||||
tPRINT expr_addr tEOL { DEBUG_Print( &$2, 1, 0, 0 );
|
||||
DEBUG_FreeExprMem(); }
|
||||
tPRINT expr_addr tEOL { DEBUG_Print( &$2, 1, 0, 0 ); DEBUG_FreeExprMem(); }
|
||||
| tPRINT tFORMAT expr_addr tEOL { DEBUG_Print( &$3, $2 >> 8, $2 & 0xff, 0 );
|
||||
DEBUG_FreeExprMem(); }
|
||||
DEBUG_FreeExprMem(); }
|
||||
|
||||
break_command:
|
||||
tBREAK '*' expr_addr tEOL { DEBUG_AddBreakpoint( &$3, NULL );
|
||||
DEBUG_FreeExprMem(); }
|
||||
| tBREAK tIDENTIFIER tEOL { DBG_VALUE value;
|
||||
if( DEBUG_GetSymbolValue($2, -1, &value, TRUE) )
|
||||
{
|
||||
DEBUG_AddBreakpoint( &value, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_Printf(DBG_CHN_MESG,"Unable to add breakpoint\n");
|
||||
}
|
||||
}
|
||||
| tBREAK tIDENTIFIER ':' tNUM tEOL { DBG_VALUE value;
|
||||
if( DEBUG_GetSymbolValue($2, $4, &value, TRUE) )
|
||||
{
|
||||
DEBUG_AddBreakpoint( &value, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_Printf(DBG_CHN_MESG,"Unable to add breakpoint\n");
|
||||
}
|
||||
}
|
||||
| tBREAK tNUM tEOL { struct name_hash *nh;
|
||||
DBG_VALUE value;
|
||||
DEBUG_GetCurrentAddress( &value.addr );
|
||||
DEBUG_FindNearestSymbol(&value.addr, TRUE,
|
||||
&nh, 0, NULL);
|
||||
if( nh != NULL )
|
||||
{
|
||||
DEBUG_GetLineNumberAddr(nh, $2, &value.addr, TRUE);
|
||||
value.type = NULL;
|
||||
value.cookie = DV_TARGET;
|
||||
DEBUG_AddBreakpoint( &value, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_Printf(DBG_CHN_MESG,"Unable to add breakpoint\n");
|
||||
}
|
||||
}
|
||||
|
||||
| tBREAK tEOL { DBG_VALUE value;
|
||||
DEBUG_GetCurrentAddress( &value.addr );
|
||||
value.type = NULL;
|
||||
value.cookie = DV_TARGET;
|
||||
DEBUG_AddBreakpoint( &value, NULL );
|
||||
}
|
||||
tBREAK '*' expr_addr tEOL{ DEBUG_AddBreakpoint( &$3, NULL ); DEBUG_FreeExprMem(); }
|
||||
| tBREAK tIDENTIFIER tEOL { DEBUG_AddBreakpointFromId($2, -1); }
|
||||
| tBREAK tIDENTIFIER ':' tNUM tEOL { DEBUG_AddBreakpointFromId($2, $4); }
|
||||
| tBREAK tNUM tEOL { DEBUG_AddBreakpointFromLineno($2); }
|
||||
| tBREAK tEOL { DEBUG_AddBreakpointFromLineno(-1); }
|
||||
|
||||
watch_command:
|
||||
tWATCH '*' expr_addr tEOL { DEBUG_AddWatchpoint( &$3, 1 );
|
||||
DEBUG_FreeExprMem(); }
|
||||
| tWATCH tIDENTIFIER tEOL { DBG_VALUE value;
|
||||
if( DEBUG_GetSymbolValue($2, -1, &value, TRUE) )
|
||||
DEBUG_AddWatchpoint( &value, 1 );
|
||||
else
|
||||
DEBUG_Printf(DBG_CHN_MESG,"Unable to add breakpoint\n");
|
||||
}
|
||||
tWATCH '*' expr_addr tEOL { DEBUG_AddWatchpoint( &$3, 1 ); DEBUG_FreeExprMem(); }
|
||||
| tWATCH tIDENTIFIER tEOL { DEBUG_AddWatchpointFromId($2, -1); }
|
||||
|
||||
info_command:
|
||||
tINFO tBREAK tEOL { DEBUG_InfoBreakpoints(); }
|
||||
| tINFO tCLASS tSTRING tEOL { DEBUG_InfoClass( $3 ); DEBUG_FreeExprMem(); }
|
||||
| tINFO tCLASS tSTRING tEOL { DEBUG_InfoClass( $3 ); }
|
||||
| tINFO tSHARE tEOL { DEBUG_InfoShare(); }
|
||||
| tINFO tMODULE expr_value tEOL { DEBUG_DumpModule( $3 ); DEBUG_FreeExprMem(); }
|
||||
| tINFO tQUEUE expr_value tEOL { DEBUG_DumpQueue( $3 ); DEBUG_FreeExprMem(); }
|
||||
|
@ -265,8 +215,7 @@ info_command:
|
|||
| tINFO tSEGMENTS tEOL { DEBUG_InfoSegments( 0, -1 ); }
|
||||
| tINFO tSTACK tEOL { DEBUG_InfoStack(); }
|
||||
| tINFO tMAPS tEOL { DEBUG_InfoVirtual(); }
|
||||
| tINFO tWND expr_value tEOL { DEBUG_InfoWindow( (HWND)$3 );
|
||||
DEBUG_FreeExprMem(); }
|
||||
| tINFO tWND expr_value tEOL{ DEBUG_InfoWindow( (HWND)$3 ); DEBUG_FreeExprMem(); }
|
||||
| tINFO tLOCAL tEOL { DEBUG_InfoLocals(); }
|
||||
| tINFO tDISPLAY tEOL { DEBUG_InfoDisplay(); }
|
||||
|
||||
|
@ -278,8 +227,15 @@ walk_command:
|
|||
| tWALK tWND tNUM tEOL { DEBUG_WalkWindows( $3, 0 ); }
|
||||
| tWALK tPROCESS tEOL { DEBUG_WalkProcess(); }
|
||||
| tWALK tTHREAD tEOL { DEBUG_WalkThreads(); }
|
||||
| tWALK tMODREF expr_value tEOL { DEBUG_WalkModref( $3 ); }
|
||||
| tWALK tMODREF expr_value tEOL { DEBUG_WalkModref( $3 ); DEBUG_FreeExprMem(); }
|
||||
|
||||
run_command:
|
||||
tRUN tEOL { DEBUG_Run(NULL); }
|
||||
| tRUN tSTRING tEOL { DEBUG_Run($2); }
|
||||
|
||||
noprocess_state:
|
||||
tNOPROCESS tEOL {} /* <CR> shall not barf anything */
|
||||
| tNOPROCESS tSTRING tEOL { DEBUG_Printf(DBG_CHN_MESG, "No process loaded, cannot execute '%s'\n", $2); }
|
||||
|
||||
type_cast:
|
||||
'(' type_expr ')' { $$ = $2; }
|
||||
|
@ -292,7 +248,7 @@ type_expr:
|
|||
| tUNSIGNED tINT { $$ = DEBUG_TypeCast(DT_BASIC, "unsigned int"); }
|
||||
| tLONG tUNSIGNED tINT { $$ = DEBUG_TypeCast(DT_BASIC, "long unsigned int"); }
|
||||
| tLONG tLONG tINT { $$ = DEBUG_TypeCast(DT_BASIC, "long long int"); }
|
||||
| tLONG tLONG tUNSIGNED tINT { $$ = DEBUG_TypeCast(DT_BASIC, "long long unsigned int"); }
|
||||
| tLONG tLONG tUNSIGNED tINT{ $$ = DEBUG_TypeCast(DT_BASIC, "long long unsigned int"); }
|
||||
| tSHORT tINT { $$ = DEBUG_TypeCast(DT_BASIC, "short int"); }
|
||||
| tSHORT tUNSIGNED tINT { $$ = DEBUG_TypeCast(DT_BASIC, "short unsigned int"); }
|
||||
| tSIGNED tCHAR { $$ = DEBUG_TypeCast(DT_BASIC, "signed char"); }
|
||||
|
@ -424,136 +380,41 @@ static WINE_EXCEPTION_FILTER(wine_dbg_cmd)
|
|||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_Main
|
||||
* DEBUG_Parser
|
||||
*
|
||||
* Debugger main loop.
|
||||
* Debugger editline parser
|
||||
*/
|
||||
BOOL DEBUG_Main( BOOL is_debug, BOOL force, DWORD code )
|
||||
BOOL DEBUG_Parser(void)
|
||||
{
|
||||
int newmode;
|
||||
BOOL ret_ok;
|
||||
char ch;
|
||||
|
||||
BOOL ret_ok;
|
||||
BOOL ret = TRUE;
|
||||
#ifdef YYDEBUG
|
||||
yydebug = 0;
|
||||
#endif
|
||||
|
||||
yyin = stdin;
|
||||
|
||||
DEBUG_SuspendExecution();
|
||||
|
||||
if (!is_debug)
|
||||
{
|
||||
#ifdef __i386__
|
||||
if (DEBUG_IsSelectorSystem(DEBUG_context.SegCs))
|
||||
DEBUG_Printf( DBG_CHN_MESG, " in 32-bit code (0x%08lx).\n", DEBUG_context.Eip );
|
||||
else
|
||||
DEBUG_Printf( DBG_CHN_MESG, " in 16-bit code (%04x:%04lx).\n",
|
||||
(WORD)DEBUG_context.SegCs, DEBUG_context.Eip );
|
||||
#else
|
||||
DEBUG_Printf( DBG_CHN_MESG, " (0x%08lx).\n", GET_IP(&DEBUG_context) );
|
||||
#endif
|
||||
}
|
||||
|
||||
DEBUG_LoadEntryPoints("Loading new modules symbols:\n");
|
||||
|
||||
if (force || !(is_debug && DEBUG_ShouldContinue( code,
|
||||
DEBUG_CurrThread->dbg_exec_mode,
|
||||
&DEBUG_CurrThread->dbg_exec_count )))
|
||||
{
|
||||
DBG_ADDR addr;
|
||||
DEBUG_GetCurrentAddress( &addr );
|
||||
|
||||
#ifdef __i386__
|
||||
switch (newmode = DEBUG_GetSelectorType(addr.seg)) {
|
||||
case 16: case 32: break;
|
||||
default: DEBUG_Printf(DBG_CHN_MESG, "Bad CS (%ld)\n", addr.seg); newmode = 32;
|
||||
}
|
||||
#else
|
||||
newmode = 32;
|
||||
#endif
|
||||
if (newmode != DEBUG_CurrThread->dbg_mode)
|
||||
DEBUG_Printf(DBG_CHN_MESG,"In %d bit mode.\n", DEBUG_CurrThread->dbg_mode = newmode);
|
||||
|
||||
DEBUG_DoDisplay();
|
||||
|
||||
if (is_debug || force)
|
||||
{
|
||||
/*
|
||||
* Do a quiet backtrace so that we have an idea of what the situation
|
||||
* is WRT the source files.
|
||||
*/
|
||||
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 ||
|
||||
(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, DEBUG_CurrThread->dbg_mode, TRUE );
|
||||
DEBUG_Printf(DBG_CHN_MESG,": ");
|
||||
DEBUG_Disasm( &addr, TRUE );
|
||||
DEBUG_Printf( DBG_CHN_MESG, "\n" );
|
||||
}
|
||||
|
||||
ret_ok = 0;
|
||||
do
|
||||
{
|
||||
__TRY
|
||||
{
|
||||
issue_prompt();
|
||||
if (yyparse()) {
|
||||
DEBUG_CurrThread->dbg_exec_mode = EXEC_KILL;
|
||||
ret_ok = TRUE;
|
||||
} else {
|
||||
flush_symbols();
|
||||
|
||||
DEBUG_GetCurrentAddress( &addr );
|
||||
ret_ok = DEBUG_ValidateRegisters() &&
|
||||
DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear(&addr), &ch, 1);
|
||||
}
|
||||
}
|
||||
__EXCEPT(wine_dbg_cmd)
|
||||
{
|
||||
ret_ok = FALSE;
|
||||
}
|
||||
__ENDTRY;
|
||||
|
||||
} while (!ret_ok);
|
||||
}
|
||||
|
||||
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 (DEBUG_CurrThread->dbg_exec_mode == EXEC_CONT || DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS)
|
||||
DEBUG_CurrThread->dbg_exec_count = 0;
|
||||
|
||||
return (DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS) ? DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
|
||||
ret_ok = FALSE;
|
||||
do {
|
||||
__TRY {
|
||||
issue_prompt();
|
||||
if ((ret = yyparse())) {
|
||||
DEBUG_FlushSymbols();
|
||||
|
||||
ret_ok = (DEBUG_CurrThread) ? DEBUG_ValidateRegisters() : TRUE;
|
||||
} else {
|
||||
ret_ok = TRUE;
|
||||
}
|
||||
} __EXCEPT(wine_dbg_cmd) {
|
||||
ret_ok = FALSE;
|
||||
}
|
||||
__ENDTRY;
|
||||
|
||||
} while (!ret_ok);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int yyerror(char* s)
|
||||
{
|
||||
DEBUG_Printf(DBG_CHN_MESG,"%s\n", s);
|
||||
DEBUG_Printf(DBG_CHN_MESG, "%s\n", s);
|
||||
return 0;
|
||||
}
|
||||
|
|
107
debugger/debug.l
107
debugger/debug.l
|
@ -2,6 +2,7 @@
|
|||
* Lexical scanner for command line parsing
|
||||
*
|
||||
* Copyright 1993 Eric Youngdale
|
||||
* 2000 Eric Pouech
|
||||
*/
|
||||
|
||||
%{
|
||||
|
@ -10,12 +11,6 @@
|
|||
#include "debugger.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
#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
|
||||
|
||||
#ifndef DONT_USE_READLINE
|
||||
#undef YY_INPUT
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
|
@ -23,7 +18,7 @@
|
|||
YY_FATAL_ERROR( "read() in flex scanner failed" );
|
||||
|
||||
static int dbg_read(char * buf, int size);
|
||||
static char * make_symbol(char *);
|
||||
static char * DEBUG_MakeSymbol(char *);
|
||||
|
||||
#endif /* DONT_USE_READLINE */
|
||||
|
||||
|
@ -47,40 +42,42 @@ STRING \"[^\n"]+\"
|
|||
%s WALK_CMD
|
||||
%s SHOW_CMD
|
||||
%s NOCMD
|
||||
%s DEBUGSTR
|
||||
|
||||
%x ASTRING_EXPECTED
|
||||
%x NOPROCESS
|
||||
%%
|
||||
/* set to special state when no process is loaded. */
|
||||
if (!DEBUG_CurrProcess && YYSTATE == INITIAL) {BEGIN(NOPROCESS);}
|
||||
|
||||
\n { BEGIN(0); syntax_error = 0;
|
||||
return tEOL; } /*Indicates end of command. Reset state. */
|
||||
<*>\n { BEGIN(INITIAL); syntax_error = 0; return tEOL; }
|
||||
/* Indicates end of command. Reset state. */
|
||||
|
||||
"||" { return OP_LOR; }
|
||||
"&&" { return OP_LAND; }
|
||||
"==" { return OP_EQ; }
|
||||
"!=" { return OP_NE; }
|
||||
"<=" { return OP_LE; }
|
||||
">=" { return OP_GE; }
|
||||
"<<" { return OP_SHL; }
|
||||
">>" { return OP_SHR; }
|
||||
"->" { return OP_DRF; }
|
||||
[-+<=>|&^()*/%:!~,\.] { return *yytext; }
|
||||
"[" { return *yytext; }
|
||||
"]" { return *yytext; }
|
||||
"||" { return OP_LOR; }
|
||||
"&&" { return OP_LAND; }
|
||||
"==" { return OP_EQ; }
|
||||
"!=" { return OP_NE; }
|
||||
"<=" { return OP_LE; }
|
||||
">=" { return OP_GE; }
|
||||
"<<" { return OP_SHL; }
|
||||
">>" { return OP_SHR; }
|
||||
"->" { return OP_DRF; }
|
||||
[-+<=>|&^()*/%:!~,\.] { return *yytext; }
|
||||
"[" { return *yytext; }
|
||||
"]" { return *yytext; }
|
||||
|
||||
"0x"{HEXDIGIT}+ { sscanf(yytext, "%x", &yylval.integer); return tNUM; }
|
||||
{DIGIT}+ { sscanf(yytext, "%d", &yylval.integer); return tNUM; }
|
||||
"0x"{HEXDIGIT}+ { sscanf(yytext, "%x", &yylval.integer); return tNUM; }
|
||||
{DIGIT}+ { sscanf(yytext, "%d", &yylval.integer); return tNUM; }
|
||||
|
||||
<FORMAT_EXPECTED>"/"{DIGIT}+{FORMAT} { char* last;
|
||||
yylval.integer = strtol( yytext+1, &last, NULL ) << 8;
|
||||
yylval.integer |= *last;
|
||||
return tFORMAT; }
|
||||
|
||||
<FORMAT_EXPECTED>"/"{DIGIT}+{FORMAT} { char * last;
|
||||
yylval.integer = strtol( yytext+1, &last, NULL );
|
||||
yylval.integer = (yylval.integer << 8) | *last;
|
||||
return tFORMAT; }
|
||||
<FORMAT_EXPECTED>"/"{FORMAT} { yylval.integer = (1 << 8) | yytext[1]; return tFORMAT; }
|
||||
|
||||
|
||||
<FORMAT_EXPECTED>"/"{FORMAT} { yylval.integer = (1 << 8) | yytext[1]; return tFORMAT; }
|
||||
|
||||
{STRING} { yylval.string = make_symbol(yytext); return tSTRING; }
|
||||
<DEBUGSTR>[a-z+\-,]* { yylval.string = yytext; return tDEBUGSTR; }
|
||||
{STRING} { yylval.string = DEBUG_MakeSymbol(yytext); return tSTRING; }
|
||||
<ASTRING_EXPECTED>[^\n]+ { char* p = yytext; while (*p == ' ' || *p == '\t') p++;
|
||||
yylval.string = DEBUG_MakeSymbol(p); return tSTRING; }
|
||||
|
||||
<INITIAL>info|inf|in { BEGIN(INFO_CMD); return tINFO; }
|
||||
<INITIAL>up { BEGIN(NOCMD); return tUP; }
|
||||
|
@ -93,9 +90,9 @@ STRING \"[^\n"]+\"
|
|||
<INITIAL,INFO_CMD,DEL_CMD>display|displa|displ|disp { BEGIN(FORMAT_EXPECTED); return tDISPLAY; }
|
||||
<INITIAL>undisplay|undispla|undispl|undisp|undis|undi|und { BEGIN(NOCMD); return tUNDISPLAY; }
|
||||
<INITIAL>delete|delet|dele|del { BEGIN(DEL_CMD); return tDELETE; }
|
||||
<INITIAL>quit|qui|qu|q { BEGIN(NOCMD); return tQUIT; }
|
||||
<INITIAL,NOPROCESS>quit|qui|qu|q { BEGIN(NOCMD); return tQUIT; }
|
||||
<INITIAL>set|se { BEGIN(NOCMD); return tSET; }
|
||||
<INITIAL>walk|w { BEGIN(WALK_CMD); return tWALK; }
|
||||
<INITIAL,NOPROCESS>walk|w { BEGIN(WALK_CMD); return tWALK; }
|
||||
<INITIAL>x { BEGIN(FORMAT_EXPECTED); return tEXAM; }
|
||||
<INITIAL>help|hel|he|"?" { BEGIN(HELP_CMD); return tHELP; }
|
||||
|
||||
|
@ -121,11 +118,12 @@ STRING \"[^\n"]+\"
|
|||
<INITIAL,INFO_CMD,DEL_CMD>break|brea|bre|br|b { BEGIN(PATH_EXPECTED); return tBREAK; }
|
||||
<INITIAL>watch|watc|wat { BEGIN(PATH_EXPECTED); return tWATCH; }
|
||||
<INITIAL>whatis|whati|what { BEGIN(PATH_EXPECTED); return tWHATIS; }
|
||||
|
||||
<INITIAL,NOPROCESS>run|ru|r { BEGIN(ASTRING_EXPECTED); return tRUN;}
|
||||
<NOPROCESS>attach|attac|atta|att { BEGIN(NOCMD); return tATTACH; }
|
||||
<INFO_CMD>share|shar|sha { return tSHARE; }
|
||||
<INFO_CMD>locals|local|loca|loc { return tLOCAL; }
|
||||
<INFO_CMD,WALK_CMD>class|clas|cla { return tCLASS; }
|
||||
<INFO_CMD,WALK_CMD>module|modul|modu|mod { return tMODULE; }
|
||||
<INFO_CMD,WALK_CMD>module|modul|modu|mod { return tMODULE; }
|
||||
<INFO_CMD,WALK_CMD>queue|queu|que { return tQUEUE; }
|
||||
<INFO_CMD,WALK_CMD>process|proces|proce|proc { return tPROCESS; }
|
||||
<INFO_CMD,WALK_CMD>threads|thread|threa|thre|thr|th { return tTHREAD; }
|
||||
|
@ -138,7 +136,7 @@ STRING \"[^\n"]+\"
|
|||
<HELP_CMD>info|inf|in { return tINFO; }
|
||||
|
||||
<INITIAL,SHOW_CMD>directories|directorie|directori|director|directo|direct|direc|direc|dir {
|
||||
BEGIN(PATH_EXPECTED); return tDIR; }
|
||||
BEGIN(PATH_EXPECTED); return tDIR; }
|
||||
|
||||
char { return tCHAR; }
|
||||
short { return tSHORT; }
|
||||
|
@ -152,20 +150,18 @@ struct { return tSTRUCT; }
|
|||
union { return tUNION; }
|
||||
enum { return tENUM; }
|
||||
|
||||
{IDENTIFIER} { yylval.string = make_symbol(yytext); return tIDENTIFIER; }
|
||||
"$"{IDENTIFIER} { yylval.string = make_symbol(yytext+1); return tINTVAR; }
|
||||
{IDENTIFIER} { yylval.string = DEBUG_MakeSymbol(yytext); return tIDENTIFIER; }
|
||||
"$"{IDENTIFIER} { yylval.string = DEBUG_MakeSymbol(yytext+1); return tINTVAR; }
|
||||
|
||||
<PATH_EXPECTED>{PATHNAME} { yylval.string = make_symbol(yytext); return tPATH; }
|
||||
|
||||
[ \t]+ /* Eat up whitespace */
|
||||
|
||||
. { if (syntax_error == 0)
|
||||
{
|
||||
syntax_error ++; DEBUG_Printf(DBG_CHN_MESG, "Syntax Error\n");
|
||||
}
|
||||
}
|
||||
<PATH_EXPECTED>{PATHNAME} { yylval.string = DEBUG_MakeSymbol(yytext); return tPATH; }
|
||||
|
||||
<*>[ \t]+ /* Eat up whitespace */
|
||||
|
||||
<NOPROCESS>. { BEGIN(ASTRING_EXPECTED); yyless(0); return tNOPROCESS;}
|
||||
<*>. { if (syntax_error == 0) {
|
||||
syntax_error++;
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Syntax Error (%s)\n", yytext); }
|
||||
}
|
||||
%%
|
||||
|
||||
#ifndef yywrap
|
||||
|
@ -206,7 +202,7 @@ static int dbg_read(char * buf, int size)
|
|||
|
||||
for (;;)
|
||||
{
|
||||
flush_symbols();
|
||||
DEBUG_FlushSymbols();
|
||||
line = readline ("Wine-dbg>");
|
||||
if (!line)
|
||||
{
|
||||
|
@ -226,7 +222,7 @@ static int dbg_read(char * buf, int size)
|
|||
add_history( line );
|
||||
strncpy( last_line, line, 255 );
|
||||
last_line[255] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
free( line );
|
||||
line = last_line;
|
||||
|
@ -249,14 +245,15 @@ static int dbg_read(char * buf, int size)
|
|||
static char *local_symbols[30];
|
||||
static int next_symbol;
|
||||
|
||||
static char * make_symbol(char * symbol)
|
||||
static char * DEBUG_MakeSymbol(char * symbol)
|
||||
{
|
||||
return local_symbols[next_symbol++] = DBG_strdup(symbol);
|
||||
assert(0 <= next_symbol && next_symbol < (sizeof(local_symbols) / sizeof(local_symbols[0])));
|
||||
return local_symbols[next_symbol++] = DBG_strdup(symbol);
|
||||
}
|
||||
|
||||
void flush_symbols(void)
|
||||
void DEBUG_FlushSymbols(void)
|
||||
{
|
||||
while(--next_symbol>= 0) DBG_free(local_symbols[next_symbol]);
|
||||
while(--next_symbol >= 0) DBG_free(local_symbols[next_symbol]);
|
||||
next_symbol = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,6 @@ enum exec_mode
|
|||
* and set breakpoint there - not at the
|
||||
* instr just after the call.
|
||||
*/
|
||||
EXEC_KILL /* terminate debugging session */
|
||||
};
|
||||
|
||||
#define DBG_BREAK 0
|
||||
|
@ -224,24 +223,16 @@ typedef struct {
|
|||
|
||||
#define OFFSET_OF(__c,__f) ((int)(((char*)&(((__c*)0)->__f))-((char*)0)))
|
||||
|
||||
|
||||
|
||||
#ifdef __i386__
|
||||
# define GET_IP(context) ((DWORD)(context)->Eip)
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
# define GET_IP(context) ((DWORD)(context)->pc)
|
||||
#endif
|
||||
|
||||
#if !defined(GET_IP)
|
||||
# error You must define GET_IP for this CPU
|
||||
#endif
|
||||
|
||||
/* from winelib.so */
|
||||
extern void DEBUG_ExternalDebugger(void);
|
||||
|
||||
/* debugger/break.c */
|
||||
extern void DEBUG_SetBreakpoints( BOOL set );
|
||||
extern void DEBUG_AddBreakpoint( const DBG_VALUE *addr, BOOL (*func)(void) );
|
||||
extern void DEBUG_AddBreakpointFromId( const char *name, int lineno );
|
||||
extern void DEBUG_AddBreakpointFromLineno( int lineno );
|
||||
extern void DEBUG_AddWatchpoint( const DBG_VALUE *addr, int is_write );
|
||||
extern void DEBUG_AddWatchpointFromId( const char *name, int lineno );
|
||||
extern void DEBUG_DelBreakpoint( int num );
|
||||
extern void DEBUG_EnableBreakpoint( int num, BOOL enable );
|
||||
extern void DEBUG_InfoBreakpoints(void);
|
||||
|
@ -250,17 +241,17 @@ extern BOOL DEBUG_ShouldContinue( DWORD code, 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);
|
||||
extern int DEBUG_AddBPCondition(int bpnum, struct expr * exp);
|
||||
extern int DEBUG_AddBPCondition(int bpnum, struct expr * exp);
|
||||
|
||||
/* debugger/db_disasm.c */
|
||||
extern void DEBUG_Disasm( DBG_ADDR *addr, int display );
|
||||
|
||||
/* debugger/dbg.y */
|
||||
extern BOOL DEBUG_Main( BOOL is_debug, BOOL force, DWORD code );
|
||||
extern BOOL DEBUG_Parser(void);
|
||||
extern void DEBUG_Exit( DWORD );
|
||||
|
||||
/* debugger/debug.l */
|
||||
extern void flush_symbols(void);
|
||||
extern void DEBUG_FlushSymbols(void);
|
||||
|
||||
/* debugger/display.c */
|
||||
extern int DEBUG_DoDisplay(void);
|
||||
|
@ -294,9 +285,6 @@ extern struct expr * DEBUG_CloneExpr(const struct expr * exp);
|
|||
extern int DEBUG_FreeExpr(struct expr * exp);
|
||||
extern int DEBUG_DisplayExpr(const struct expr * exp);
|
||||
|
||||
/* debugger/external.c */
|
||||
extern void DEBUG_ExternalDebugger(void);
|
||||
|
||||
/* debugger/hash.c */
|
||||
extern struct name_hash * DEBUG_AddSymbol( const char *name,
|
||||
const DBG_VALUE *addr,
|
||||
|
@ -378,6 +366,7 @@ extern DBG_MODULE* DEBUG_AddModule(const char* name, int type,
|
|||
void* mod_addr, HMODULE hmod);
|
||||
extern DBG_MODULE* DEBUG_FindModuleByName(const char* name, int type);
|
||||
extern DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, int type);
|
||||
extern DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process);
|
||||
extern DBG_MODULE* DEBUG_RegisterPEModule(HMODULE, u_long load_addr, const char* name);
|
||||
extern DBG_MODULE* DEBUG_RegisterELFModule(u_long load_addr, const char* name);
|
||||
extern void DEBUG_InfoShare(void);
|
||||
|
@ -456,8 +445,11 @@ extern int DEBUG_Printf(int chn, const char* format, ...) __attribute__((format
|
|||
extern int DEBUG_Printf(int chn, const char* format, ...);
|
||||
#endif
|
||||
extern DBG_INTVAR* DEBUG_GetIntVar(const char*);
|
||||
extern BOOL DEBUG_Attach(DWORD pid, BOOL cofe);
|
||||
extern void DEBUG_Run(const char* args);
|
||||
extern int curr_frame;
|
||||
|
||||
/* Choose your allocator! */
|
||||
/* Choose your allocator! */
|
||||
#if 1
|
||||
/* this one is libc's fast one */
|
||||
extern void* DEBUG_XMalloc(size_t size);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
INTERNAL_VAR(BreakAllThreadsStartup, FALSE, NULL, DEBUG_TypeIntConst)
|
||||
INTERNAL_VAR(BreakOnCritSectTimeOut, FALSE, NULL, DEBUG_TypeIntConst)
|
||||
INTERNAL_VAR(BreakOnAttach, FALSE, NULL, DEBUG_TypeIntConst)
|
||||
INTERNAL_VAR(BreakOnFirstChance, TRUE, NULL, DEBUG_TypeIntConst)
|
||||
|
||||
/* output handling */
|
||||
INTERNAL_VAR(ConChannelMask, DBG_CHN_MESG, NULL, DEBUG_TypeIntConst)
|
||||
|
|
|
@ -117,9 +117,11 @@ void DEBUG_GetCurrentAddress( DBG_ADDR *addr )
|
|||
if (!DEBUG_FixSegment( addr ) && DEBUG_IsSelectorSystem(addr->seg))
|
||||
addr->seg = 0;
|
||||
addr->off = DEBUG_context.Eip;
|
||||
#elif defined(__sparc__)
|
||||
addr->seg = 0;
|
||||
addr->off = DEBUG_context.pc;
|
||||
#else
|
||||
addr->seg = 0;
|
||||
addr->off = GET_IP( &DEBUG_context );
|
||||
# error You must define GET_IP for this CPU
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,21 @@ DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, int type)
|
|||
return wmod;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_GetProcessMainModule
|
||||
*/
|
||||
DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process)
|
||||
{
|
||||
DBG_MODULE* wmod;
|
||||
|
||||
if (!process) return NULL;
|
||||
|
||||
/* main module is the first to be loaded on a given process, so it's the last on
|
||||
* the list */
|
||||
for (wmod = process->modules; wmod && wmod->next; wmod = wmod->next);
|
||||
return wmod;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_RegisterELFModule
|
||||
*
|
||||
|
@ -139,6 +154,7 @@ DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr, const char
|
|||
return wmod;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/***********************************************************************
|
||||
* DEBUG_GetEP16
|
||||
*
|
||||
|
@ -230,6 +246,7 @@ static void DEBUG_LoadModule16(HMODULE hModule, NE_MODULE* module, char* moduleA
|
|||
}
|
||||
GlobalUnlock16(module->nrname_handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_LoadModule32
|
||||
|
@ -355,10 +372,14 @@ void DEBUG_LoadModule32(const char* name, HANDLE hFile, DWORD base)
|
|||
*/
|
||||
int DEBUG_LoadEntryPoints(const char* pfx)
|
||||
{
|
||||
int first = 0;
|
||||
/* FIXME: with address space separation in space, this is plain wrong
|
||||
* it requires the 16 bit WOW debugging interface...
|
||||
*/
|
||||
#if 0
|
||||
MODULEENTRY entry;
|
||||
NE_MODULE module;
|
||||
void* moduleAddr;
|
||||
int first = 0;
|
||||
int rowcount = 0;
|
||||
int len;
|
||||
|
||||
|
@ -390,6 +411,7 @@ int DEBUG_LoadEntryPoints(const char* pfx)
|
|||
|
||||
DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule);
|
||||
} while (ModuleNext16(&entry));
|
||||
#endif
|
||||
|
||||
if (first) DEBUG_Printf(DBG_CHN_MESG, "\n");
|
||||
return first;
|
||||
|
|
|
@ -121,6 +121,9 @@ void DEBUG_InfoRegisters(void)
|
|||
*/
|
||||
BOOL DEBUG_ValidateRegisters(void)
|
||||
{
|
||||
DBG_ADDR addr;
|
||||
char ch;
|
||||
|
||||
#ifdef __i386__
|
||||
if (DEBUG_context.EFlags & V86_FLAG) return TRUE;
|
||||
|
||||
|
@ -157,9 +160,13 @@ BOOL DEBUG_ValidateRegisters(void)
|
|||
(WORD)DEBUG_context.SegSs );
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
#undef CHECK_SEG
|
||||
#else
|
||||
return TRUE;
|
||||
/* to be written */
|
||||
#endif
|
||||
|
||||
/* check if PC is correct */
|
||||
DEBUG_GetCurrentAddress(&addr);
|
||||
return DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear(&addr), &ch, 1);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ struct bt_info
|
|||
|
||||
static int nframe;
|
||||
static struct bt_info * frames = NULL;
|
||||
int curr_frame;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
|
@ -897,7 +897,11 @@ DEBUG_Print( const DBG_VALUE *value, int count, char format, int level )
|
|||
}
|
||||
}
|
||||
break;
|
||||
case DT_FUNC:
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Function at ???\n");
|
||||
break;
|
||||
default:
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Unknown type (%d)\n", value->type->type);
|
||||
assert(FALSE);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ DBG_THREAD* DEBUG_CurrThread = NULL;
|
|||
DWORD DEBUG_CurrTid;
|
||||
DWORD DEBUG_CurrPid;
|
||||
CONTEXT DEBUG_context;
|
||||
int curr_frame = 0;
|
||||
static char* DEBUG_LastCmdLine = NULL;
|
||||
|
||||
static DBG_PROCESS* proc = NULL;
|
||||
DBG_INTVAR DEBUG_IntVars[DBG_IV_LAST];
|
||||
|
@ -164,6 +166,7 @@ static void DEBUG_DelProcess(DBG_PROCESS* p)
|
|||
if (p->prev) p->prev->next = p->next;
|
||||
if (p->next) p->next->prev = p->prev;
|
||||
if (p == proc) proc = p->next;
|
||||
if (p == DEBUG_CurrProcess) DEBUG_CurrProcess = NULL;
|
||||
DBG_free(p);
|
||||
}
|
||||
|
||||
|
@ -253,17 +256,120 @@ static void DEBUG_DelThread(DBG_THREAD* t)
|
|||
if (t->next) t->next->prev = t->prev;
|
||||
if (t == t->process->threads) t->process->threads = t->next;
|
||||
t->process->num_threads--;
|
||||
if (t == DEBUG_CurrThread) DEBUG_CurrThread = NULL;
|
||||
DBG_free(t);
|
||||
}
|
||||
|
||||
static BOOL DEBUG_HandleException( EXCEPTION_RECORD *rec, BOOL first_chance, BOOL force )
|
||||
BOOL DEBUG_Attach(DWORD pid, BOOL cofe)
|
||||
{
|
||||
if (!(DEBUG_CurrProcess = DEBUG_AddProcess(pid, 0))) return FALSE;
|
||||
|
||||
if (!DebugActiveProcess(pid)) {
|
||||
DEBUG_Printf(DBG_CHN_ERR, "Can't attach process %ld: %ld\n",
|
||||
pid, GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
DEBUG_CurrProcess->continue_on_first_exception = cofe;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL DEBUG_ExceptionProlog(BOOL is_debug, BOOL force, DWORD code)
|
||||
{
|
||||
DBG_ADDR addr;
|
||||
int newmode;
|
||||
|
||||
DEBUG_GetCurrentAddress(&addr);
|
||||
DEBUG_SuspendExecution();
|
||||
|
||||
if (!is_debug) {
|
||||
#ifdef __i386__
|
||||
if (DEBUG_IsSelectorSystem(DEBUG_context.SegCs))
|
||||
DEBUG_Printf(DBG_CHN_MESG, " in 32-bit code (0x%08lx).\n", addr.off);
|
||||
else
|
||||
DEBUG_Printf(DBG_CHN_MESG, " in 16-bit code (%04x:%04lx).\n",
|
||||
LOWORD(addr.seg), addr.off);
|
||||
#else
|
||||
DEBUG_Printf(DBG_CHN_MESG, " (0x%08lx).\n", addr.off);
|
||||
#endif
|
||||
}
|
||||
|
||||
DEBUG_LoadEntryPoints("Loading new modules symbols:\n");
|
||||
|
||||
if (!force && is_debug &&
|
||||
DEBUG_ShouldContinue(code,
|
||||
DEBUG_CurrThread->dbg_exec_mode,
|
||||
&DEBUG_CurrThread->dbg_exec_count))
|
||||
return FALSE;
|
||||
|
||||
#ifdef __i386__
|
||||
switch (newmode = DEBUG_GetSelectorType(addr.seg)) {
|
||||
case 16: case 32: break;
|
||||
default: DEBUG_Printf(DBG_CHN_MESG, "Bad CS (%ld)\n", addr.seg); newmode = 32;
|
||||
}
|
||||
#else
|
||||
newmode = 32;
|
||||
#endif
|
||||
if (newmode != DEBUG_CurrThread->dbg_mode)
|
||||
DEBUG_Printf(DBG_CHN_MESG,"In %d bit mode.\n", DEBUG_CurrThread->dbg_mode = newmode);
|
||||
|
||||
DEBUG_DoDisplay();
|
||||
|
||||
if (is_debug || force) {
|
||||
/*
|
||||
* Do a quiet backtrace so that we have an idea of what the situation
|
||||
* is WRT the source files.
|
||||
*/
|
||||
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 ||
|
||||
(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, DEBUG_CurrThread->dbg_mode, TRUE );
|
||||
DEBUG_Printf(DBG_CHN_MESG,": ");
|
||||
DEBUG_Disasm( &addr, TRUE );
|
||||
DEBUG_Printf( DBG_CHN_MESG, "\n" );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD DEBUG_ExceptionEpilog(void)
|
||||
{
|
||||
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 (DEBUG_CurrThread->dbg_exec_mode == EXEC_CONT || DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS)
|
||||
DEBUG_CurrThread->dbg_exec_count = 0;
|
||||
|
||||
return (DEBUG_CurrThread->dbg_exec_mode == EXEC_PASS) ? DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
|
||||
}
|
||||
|
||||
static BOOL DEBUG_HandleException(EXCEPTION_RECORD *rec, BOOL first_chance, BOOL force, LPDWORD cont)
|
||||
{
|
||||
BOOL is_debug = FALSE;
|
||||
BOOL ret;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
/* FIXME: need for a configuration var ? */
|
||||
/* pass to app first ??? */
|
||||
/* if (first_chance && !force) return 0; */
|
||||
*cont = DBG_CONTINUE;
|
||||
if (first_chance && !force && !DBG_IVAR(BreakOnFirstChance)) return TRUE;
|
||||
|
||||
switch (rec->ExceptionCode)
|
||||
{
|
||||
|
@ -276,50 +382,50 @@ static BOOL DEBUG_HandleException( EXCEPTION_RECORD *rec, BOOL first_chance, BOO
|
|||
if (!is_debug)
|
||||
{
|
||||
/* print some infos */
|
||||
DEBUG_Printf( DBG_CHN_MESG, "%s: ",
|
||||
first_chance ? "First chance exception" : "Unhandled exception" );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "%s: ",
|
||||
first_chance ? "First chance exception" : "Unhandled exception");
|
||||
switch (rec->ExceptionCode)
|
||||
{
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "divide by zero" );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "divide by zero");
|
||||
break;
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "overflow" );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "overflow");
|
||||
break;
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "array bounds " );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "array bounds ");
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "illegal instruction" );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "illegal instruction");
|
||||
break;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "stack overflow" );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "stack overflow");
|
||||
break;
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "priviledged instruction" );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "priviledged instruction");
|
||||
break;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
if (rec->NumberParameters == 2)
|
||||
DEBUG_Printf( DBG_CHN_MESG, "page fault on %s access to 0x%08lx",
|
||||
DEBUG_Printf(DBG_CHN_MESG, "page fault on %s access to 0x%08lx",
|
||||
rec->ExceptionInformation[0] ? "write" : "read",
|
||||
rec->ExceptionInformation[1] );
|
||||
rec->ExceptionInformation[1]);
|
||||
else
|
||||
DEBUG_Printf( DBG_CHN_MESG, "page fault" );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "page fault");
|
||||
break;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "Alignment" );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Alignment");
|
||||
break;
|
||||
case CONTROL_C_EXIT:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "^C" );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "^C");
|
||||
break;
|
||||
case EXCEPTION_CRITICAL_SECTION_WAIT:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "critical section %08lx wait failed",
|
||||
rec->ExceptionInformation[0] );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "critical section %08lx wait failed",
|
||||
rec->ExceptionInformation[0]);
|
||||
if (!DBG_IVAR(BreakOnCritSectTimeOut))
|
||||
return DBG_CONTINUE;
|
||||
return TRUE;
|
||||
break;
|
||||
default:
|
||||
DEBUG_Printf( DBG_CHN_MESG, "%08lx", rec->ExceptionCode );
|
||||
DEBUG_Printf(DBG_CHN_MESG, "%08lx", rec->ExceptionCode);
|
||||
break;
|
||||
}
|
||||
DEBUG_Printf(DBG_CHN_MESG, "\n");
|
||||
|
@ -334,7 +440,15 @@ static BOOL DEBUG_HandleException( EXCEPTION_RECORD *rec, BOOL first_chance, BOO
|
|||
#endif
|
||||
DEBUG_CurrThread->dbg_exec_mode, DEBUG_CurrThread->dbg_exec_count);
|
||||
|
||||
ret = DEBUG_Main( is_debug, force, rec->ExceptionCode );
|
||||
if (DEBUG_ExceptionProlog(is_debug, force, rec->ExceptionCode)) {
|
||||
for (;;) {
|
||||
ret = DEBUG_Parser();
|
||||
if (!ret || DEBUG_CurrThread->dbg_exec_mode != EXEC_PASS || first_chance)
|
||||
break;
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Cannot pass on last chance exception. You must use cont\n");
|
||||
}
|
||||
}
|
||||
*cont = DEBUG_ExceptionEpilog();
|
||||
|
||||
DEBUG_Printf(DBG_CHN_TRACE,
|
||||
"Exiting debugger PC=%lx EFL=%08lx mode=%d count=%d\n",
|
||||
|
@ -352,7 +466,7 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de, LPDWORD cont)
|
|||
{
|
||||
char buffer[256];
|
||||
BOOL ret;
|
||||
|
||||
|
||||
DEBUG_CurrPid = de->dwProcessId;
|
||||
DEBUG_CurrTid = de->dwThreadId;
|
||||
|
||||
|
@ -400,12 +514,11 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de, LPDWORD cont)
|
|||
break;
|
||||
}
|
||||
|
||||
*cont = DEBUG_HandleException(&de->u.Exception.ExceptionRecord,
|
||||
de->u.Exception.dwFirstChance,
|
||||
DEBUG_CurrThread->wait_for_first_exception);
|
||||
if (DEBUG_CurrThread->dbg_exec_mode == EXEC_KILL) {
|
||||
ret = FALSE;
|
||||
} else {
|
||||
ret = DEBUG_HandleException(&de->u.Exception.ExceptionRecord,
|
||||
de->u.Exception.dwFirstChance,
|
||||
DEBUG_CurrThread->wait_for_first_exception,
|
||||
cont);
|
||||
if (DEBUG_CurrThread) {
|
||||
DEBUG_CurrThread->wait_for_first_exception = 0;
|
||||
SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context);
|
||||
}
|
||||
|
@ -533,7 +646,8 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de, LPDWORD cont)
|
|||
/* kill last thread */
|
||||
DEBUG_DelThread(DEBUG_CurrProcess->threads);
|
||||
DEBUG_DelProcess(DEBUG_CurrProcess);
|
||||
ret = FALSE;
|
||||
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Process of pid=%08lx has terminated\n", DEBUG_CurrPid);
|
||||
break;
|
||||
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
|
@ -591,31 +705,73 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de, LPDWORD cont)
|
|||
ret = TRUE;
|
||||
}
|
||||
__ENDTRY;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD DEBUG_MainLoop(DWORD pid)
|
||||
static DWORD DEBUG_MainLoop(void)
|
||||
{
|
||||
DEBUG_EVENT de;
|
||||
DWORD cont;
|
||||
BOOL ret = TRUE;
|
||||
BOOL ret;
|
||||
|
||||
DEBUG_Printf(DBG_CHN_MESG, " on pid %ld\n", pid);
|
||||
DEBUG_Printf(DBG_CHN_MESG, " on pid %ld\n", DEBUG_CurrPid);
|
||||
|
||||
while (ret && WaitForDebugEvent(&de, INFINITE)) {
|
||||
ret = DEBUG_HandleDebugEvent(&de, &cont);
|
||||
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, cont);
|
||||
}
|
||||
for (ret = TRUE; ret; ) {
|
||||
/* wait until we get at least one loaded process */
|
||||
while (!proc && (ret = DEBUG_Parser()));
|
||||
if (!ret) break;
|
||||
|
||||
while (ret && WaitForDebugEvent(&de, INFINITE)) {
|
||||
ret = DEBUG_HandleDebugEvent(&de, &cont);
|
||||
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, cont);
|
||||
}
|
||||
};
|
||||
|
||||
DEBUG_Printf(DBG_CHN_MESG, "WineDbg terminated on pid %ld\n", pid);
|
||||
DEBUG_Printf(DBG_CHN_MESG, "WineDbg terminated on pid %ld\n", DEBUG_CurrPid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL DEBUG_Start(LPSTR cmdLine)
|
||||
{
|
||||
PROCESS_INFORMATION info;
|
||||
STARTUPINFOA startup;
|
||||
|
||||
memset(&startup, 0, sizeof(startup));
|
||||
startup.cb = sizeof(startup);
|
||||
startup.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startup.wShowWindow = SW_SHOWNORMAL;
|
||||
|
||||
if (!CreateProcess(NULL, cmdLine, NULL, NULL,
|
||||
FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info)) {
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Couldn't start process '%s'\n", cmdLine);
|
||||
return FALSE;
|
||||
}
|
||||
DEBUG_CurrPid = info.dwProcessId;
|
||||
if (!(DEBUG_CurrProcess = DEBUG_AddProcess(DEBUG_CurrPid, 0))) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void DEBUG_Run(const char* args)
|
||||
{
|
||||
DBG_MODULE* wmod = DEBUG_GetProcessMainModule(DEBUG_CurrProcess);
|
||||
const char* pgm = (wmod) ? wmod->module_name : "none";
|
||||
|
||||
if (args) {
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Run (%s) with '%s'\n", pgm, args);
|
||||
} else {
|
||||
if (!DEBUG_LastCmdLine) {
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Cannot find previously used command line.\n");
|
||||
return;
|
||||
}
|
||||
DEBUG_Start(DEBUG_LastCmdLine);
|
||||
}
|
||||
}
|
||||
|
||||
int DEBUG_main(int argc, char** argv)
|
||||
{
|
||||
DWORD pid = 0, retv = 0;
|
||||
DWORD retv = 0;
|
||||
|
||||
#ifdef DBG_need_heap
|
||||
/* Initialize the debugger heap. */
|
||||
|
@ -641,66 +797,55 @@ int DEBUG_main(int argc, char** argv)
|
|||
}
|
||||
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Starting WineDbg... ");
|
||||
|
||||
if (argc == 3) {
|
||||
HANDLE hEvent;
|
||||
DWORD pid;
|
||||
|
||||
if ((pid = atoi(argv[1])) != 0 && (hEvent = atoi(argv[2])) != 0) {
|
||||
if (!(DEBUG_CurrProcess = DEBUG_AddProcess(pid, 0))) goto leave;
|
||||
DEBUG_CurrProcess->continue_on_first_exception = TRUE;
|
||||
BOOL ret = DEBUG_Attach(pid, TRUE);
|
||||
|
||||
if (!DebugActiveProcess(pid)) {
|
||||
DEBUG_Printf(DBG_CHN_ERR, "Can't attach process %ld: %ld\n",
|
||||
pid, GetLastError());
|
||||
SetEvent(hEvent);
|
||||
goto leave;
|
||||
}
|
||||
SetEvent(hEvent);
|
||||
} else {
|
||||
pid = 0;
|
||||
}
|
||||
}
|
||||
if (argc == 1) {
|
||||
LPSTR org, ptr;
|
||||
|
||||
DEBUG_Printf(DBG_CHN_MESG, "\n");
|
||||
DEBUG_WalkProcess();
|
||||
pid = strtol(org = readline("Enter pid to debug: "), &ptr, 0);
|
||||
if (pid && ptr && ptr != org && *ptr == '\0') {
|
||||
if (!(DEBUG_CurrProcess = DEBUG_AddProcess(pid, 0))) goto leave;
|
||||
|
||||
if (!DebugActiveProcess(pid)) {
|
||||
if (!ret) {
|
||||
DEBUG_Printf(DBG_CHN_ERR, "Can't attach process %ld: %ld\n",
|
||||
pid, GetLastError());
|
||||
DEBUG_CurrPid, GetLastError());
|
||||
goto leave;
|
||||
}
|
||||
} else {
|
||||
pid = 0;
|
||||
DEBUG_CurrPid = pid;
|
||||
}
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
PROCESS_INFORMATION info;
|
||||
STARTUPINFOA startup;
|
||||
if (DEBUG_CurrPid == 0 && argc > 1) {
|
||||
int i, len;
|
||||
LPSTR cmdLine;
|
||||
|
||||
if (!(cmdLine = DBG_alloc(len = 1))) goto oom_leave;
|
||||
cmdLine[0] = '\0';
|
||||
|
||||
memset(&startup, 0, sizeof(startup));
|
||||
startup.cb = sizeof(startup);
|
||||
startup.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startup.wShowWindow = SW_SHOWNORMAL;
|
||||
for (i = 1; i < argc; i++) {
|
||||
len += strlen(argv[i]) + 1;
|
||||
if (!(cmdLine = DBG_realloc(cmdLine, len))) goto oom_leave;
|
||||
strcat(cmdLine, argv[i]);
|
||||
cmdLine[len - 2] = ' ';
|
||||
cmdLine[len - 1] = '\0';
|
||||
}
|
||||
|
||||
if (!CreateProcess(NULL, argv[1], NULL, NULL,
|
||||
FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info)) {
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Couldn't start process '%s'\n", argv[1]);
|
||||
if (!DEBUG_Start(cmdLine)) {
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Couldn't start process '%s'\n", cmdLine);
|
||||
goto leave;
|
||||
}
|
||||
pid = info.dwProcessId;
|
||||
DBG_free(DEBUG_LastCmdLine);
|
||||
DEBUG_LastCmdLine = cmdLine;
|
||||
}
|
||||
|
||||
if (pid) retv = DEBUG_MainLoop(pid);
|
||||
retv = DEBUG_MainLoop();
|
||||
leave:
|
||||
/* saves modified variables */
|
||||
DEBUG_IntVarsRW(FALSE);
|
||||
|
||||
return retv;
|
||||
|
||||
oom_leave:
|
||||
DEBUG_Printf(DBG_CHN_MESG, "Out of memory\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,9 +10,7 @@ point of view and processes/threads from a Windows point of view.
|
|||
|
||||
Each Windows' thread is implemented as a Unix process (under Linux
|
||||
using the clone syscall), meaning that all threads of a same Windows'
|
||||
process share the same (unix) address space (currently, one of wine
|
||||
limitation is that several windows processes run in the same (unix)
|
||||
address space. it's being worked on).
|
||||
process share the same (unix) address space.
|
||||
|
||||
In the following:
|
||||
+ W-process means a process in Windows' terminology
|
||||
|
@ -69,22 +67,13 @@ winedbg "hl.exe -windowed"
|
|||
II.2 Attaching
|
||||
--------------
|
||||
WineDbg can also launched without any command line argument:
|
||||
- if a wineserver is running, WineDbg lists the running W-processes
|
||||
(and their wpid:s), and let you pick up the wpid of the W-process you
|
||||
want to debug.
|
||||
- WineDbg is started without any attached process. You can get a list
|
||||
of running W-processes (and their wpid:s) using 'walk process'
|
||||
command, and then, with the attach command, pick up the wpid of the
|
||||
W-process you want to debug.
|
||||
|
||||
This is (for now) a neat feature for the following reasons:
|
||||
* debug an already started application
|
||||
+ launching WineDbg this way let WineDbg and the debugged process run
|
||||
in a *separate address space* (launching with 'winedbg myprog.exe'
|
||||
doesn't), and most of the deadlocks seen when running the debugger
|
||||
disappear (because there is no crit sect shared by both
|
||||
processes). That's the best (but far from being acceptable) current
|
||||
way to debug an application
|
||||
|
||||
This last advantage shall disappear when address space separation is
|
||||
in place. At that time, only the ability to debug an already started
|
||||
process will remain.
|
||||
|
||||
II.3 On exception
|
||||
-----------------
|
||||
|
@ -188,6 +177,9 @@ modifications to those options are automatically saved when WineDbg
|
|||
terminates).
|
||||
|
||||
Here's the list of all options:
|
||||
|
||||
III.2.1 Controling when the debugger is entered
|
||||
|
||||
BreakAllThreadsStartup set to TRUE if at all threads start-up the
|
||||
debugger stops
|
||||
set to FALSE if only at the first thread
|
||||
|
@ -204,11 +196,30 @@ BreakOnAttach, set to TRUE if when WineDbg attaches to an
|
|||
context of an exception event (the next event
|
||||
which is the exception event is of course
|
||||
relevant), that option is likely to be FALSE.
|
||||
BreakOnFirstChance an exception can generate two debug events.
|
||||
The first one is passed to the debugger (known
|
||||
as a first chance) just after the
|
||||
exception. The debugger can then decides
|
||||
either to resume execution (see winedbg's cont
|
||||
command) or pass the exception up to the
|
||||
exception handler chain in the program (if it
|
||||
exists) (winedbg implements this thru the pass
|
||||
command). If none of the exception handlers
|
||||
takes care of the exception, the exception
|
||||
event is sent again to the debugger (known as
|
||||
last chance exception). You cannot pass on a
|
||||
last exception. When the BreakOnFirstChance
|
||||
exception is TRUE, then winedbg is entered for
|
||||
both first and last chance execptions (to
|
||||
FALSE, it's only entered for last chance exceptions).
|
||||
|
||||
III.2.1 Output handling
|
||||
|
||||
ConChannelMask mask of active debugger output channels on
|
||||
console
|
||||
StdChannelMask mask of active debugger output channels on
|
||||
stderr
|
||||
|
||||
UseXTerm set to TRUE if the debugger uses its own xterm
|
||||
window for console input/output
|
||||
set to FALSE is the debugger uses the current
|
||||
|
@ -241,6 +252,17 @@ example >& shell redirect command), you'll get in that file both
|
|||
outputs. It may be interesting to look in the relay trace for specific
|
||||
values which the process segv:ed on.
|
||||
|
||||
III.2.3 Context information
|
||||
|
||||
ThreadId ID of the W-thread currently examined by the
|
||||
debugger
|
||||
ProcessId ID of the W-thread currently examined by the
|
||||
debugger
|
||||
<registers> All CPU registers are also available
|
||||
|
||||
The ThreadId and ProcessId variables can be handy to set conditional
|
||||
breakpoints on a given thread or process.
|
||||
|
||||
IV WineDbg commands
|
||||
===================
|
||||
|
||||
|
@ -249,6 +271,9 @@ IV.1 Misc
|
|||
abort aborts the debugger
|
||||
quit exits the debugger
|
||||
|
||||
attach N attach to a W-process (N is its ID). IDs can be
|
||||
obtained thru walk process command
|
||||
|
||||
help prints some help on the commands
|
||||
help info prints some help on info commands
|
||||
|
||||
|
@ -417,8 +442,7 @@ V.2 Using other Windows debuggers
|
|||
You can use any Windows' debugging API compliant debugger with
|
||||
Wine. Some reports have been made of success with VisualStudio
|
||||
debugger (in remote mode, only the hub runs in Wine).
|
||||
GoVest fully runs in Wine, but is plagued with the same address space
|
||||
issues as WineDbg as stated in II.2
|
||||
GoVest fully runs in Wine.
|
||||
|
||||
V.3 Main differences between winedbg and regular Unix debuggers
|
||||
---------------------------------------------------------------
|
||||
|
@ -444,6 +468,5 @@ VI Limitations
|
|||
|
||||
16 bit processes are not supported (but calls to 16 bit code in 32 bit
|
||||
applications is).
|
||||
Lack of address space separation exhibits some deadlocks.
|
||||
|
||||
Last updated: 5/21/2000 by ericP
|
||||
Last updated: 6/14/2000 by ericP
|
||||
|
|
Loading…
Reference in New Issue