Commit 911436bf authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

- 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
parent fb949605
......@@ -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
......@@ -439,6 +480,21 @@ void DEBUG_AddWatchpoint( const DBG_VALUE *_value, BOOL is_write )
}
/***********************************************************************
* 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
*
* Delete a breakpoint.
......@@ -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);
}
......
......@@ -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
......@@ -92,32 +90,31 @@ line: command
| error tEOL { yyerrok; }
command:
tQUIT tEOL { DEBUG_CurrThread->dbg_exec_count = 1;
DEBUG_CurrThread->dbg_exec_mode = EXEC_KILL; return 1; }
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 0; }
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 0; }
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 0; }
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 0; }
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 0; }
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 0; }
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 0; }
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 0; }
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 0; }
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 0; }
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 0; }
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 ); }
......@@ -130,21 +127,22 @@ command:
| 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; }
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 ); }
| 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); }
| 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, & $$ );
| '*' 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(); }
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(); }
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 = 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
{
ret_ok = FALSE;
do {
__TRY {
issue_prompt();
if (yyparse()) {
DEBUG_CurrThread->dbg_exec_mode = EXEC_KILL;
ret_ok = TRUE;
} else {
flush_symbols();
if ((ret = yyparse())) {
DEBUG_FlushSymbols();
DEBUG_GetCurrentAddress( &addr );
ret_ok = DEBUG_ValidateRegisters() &&
DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear(&addr), &ch, 1);
}
ret_ok = (DEBUG_CurrThread) ? DEBUG_ValidateRegisters() : TRUE;
} else {
ret_ok = TRUE;
}
__EXCEPT(wine_dbg_cmd)
{
} __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;
return ret;
}
int yyerror(char* s)
{
DEBUG_Printf(DBG_CHN_MESG,"%s\n", s);
DEBUG_Printf(DBG_CHN_MESG, "%s\n", s);
return 0;
}
......@@ -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,12 +42,15 @@ 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; }
......@@ -70,17 +68,16 @@ STRING \"[^\n"]+\"
"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 );
yylval.integer = (yylval.integer << 8) | *last;
<FORMAT_EXPECTED>"/"{DIGIT}+{FORMAT} { char* last;
yylval.integer = strtol( yytext+1, &last, NULL ) << 8;
yylval.integer |= *last;
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,7 +118,8 @@ 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; }
......@@ -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; }
<PATH_EXPECTED>{PATHNAME} { yylval.string = DEBUG_MakeSymbol(yytext); return tPATH; }
[ \t]+ /* Eat up whitespace */
<*>[ \t]+ /* Eat up whitespace */
. { if (syntax_error == 0)
{
syntax_error ++; DEBUG_Printf(DBG_CHN_MESG, "Syntax Error\n");
}
<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)
{
......@@ -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)
{
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);
......@@ -256,11 +247,11 @@ extern int DEBUG_AddBPCondition(int bpnum, struct expr * exp);
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;
#else
#elif defined(__sparc__)
addr->seg = 0;
addr->off = GET_IP( &DEBUG_context );
addr->off = DEBUG_context.pc;
#else
# error You must define GET_IP for this CPU
#endif
}
......
......@@ -92,6 +92,21 @@ DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, int type)
}
/***********************************************************************
* 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
*
* ELF modules are also entered into the list - this is so that we
......@@ -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",
......@@ -400,12 +514,11 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de, LPDWORD cont)
break;
}
*cont = DEBUG_HandleException(&de->u.Exception.ExceptionRecord,
ret = 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 {
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", DEBUG_CurrPid);
DEBUG_Printf(DBG_CHN_MESG, " on pid %ld\n", pid);
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;
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESHOWWINDOW;
startup.wShowWindow = SW_SHOWNORMAL;
if (!(cmdLine = DBG_alloc(len = 1))) goto oom_leave;
cmdLine[0] = '\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]);
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 (!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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment