- 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
diff --git a/debugger/break.c b/debugger/break.c index 7c00b59..2a1e4e9 100644 --- a/debugger/break.c +++ b/debugger/break.c
@@ -369,6 +369,47 @@ 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 @@ } /*********************************************************************** + * 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 @@ DEBUG_context.EFlags |= STEP_FLAG; #endif break; - case EXEC_KILL: - break; default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL); }
diff --git a/debugger/dbg.y b/debugger/dbg.y index 7d1fdde..4d93dda 100644 --- a/debugger/dbg.y +++ b/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 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 @@ %% -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 @@ | 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 @@ | 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 @@ | 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 @@ | 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 @@ | 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 @@ } /*********************************************************************** - * 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; }
diff --git a/debugger/debug.l b/debugger/debug.l index 0adf93c..cb8dc64 100644 --- a/debugger/debug.l +++ b/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 @@ %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 @@ <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 @@ <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 @@ <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 @@ 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 @@ for (;;) { - flush_symbols(); + DEBUG_FlushSymbols(); line = readline ("Wine-dbg>"); if (!line) { @@ -226,7 +222,7 @@ add_history( line ); strncpy( last_line, line, 255 ); last_line[255] = '\0'; - } + } free( line ); line = last_line; @@ -249,14 +245,15 @@ 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; }
diff --git a/debugger/debugger.h b/debugger/debugger.h index 3514380..4ee5935 100644 --- a/debugger/debugger.h +++ b/debugger/debugger.h
@@ -112,7 +112,6 @@ * 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 @@ #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 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 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 @@ 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, ...); #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);
diff --git a/debugger/intvar.h b/debugger/intvar.h index 27675b0..ac30a56 100644 --- a/debugger/intvar.h +++ b/debugger/intvar.h
@@ -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)
diff --git a/debugger/memory.c b/debugger/memory.c index d1feb93..455e94e 100644 --- a/debugger/memory.c +++ b/debugger/memory.c
@@ -117,9 +117,11 @@ 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 }
diff --git a/debugger/module.c b/debugger/module.c index 5ab651a..011cc75 100644 --- a/debugger/module.c +++ b/debugger/module.c
@@ -92,6 +92,21 @@ } /*********************************************************************** + * 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 @@ return wmod; } +#if 0 /*********************************************************************** * DEBUG_GetEP16 * @@ -230,6 +246,7 @@ } GlobalUnlock16(module->nrname_handle); } +#endif /*********************************************************************** * DEBUG_LoadModule32 @@ -355,10 +372,14 @@ */ 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 @@ DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule); } while (ModuleNext16(&entry)); +#endif if (first) DEBUG_Printf(DBG_CHN_MESG, "\n"); return first;
diff --git a/debugger/registers.c b/debugger/registers.c index 4dde821..4ff5952 100644 --- a/debugger/registers.c +++ b/debugger/registers.c
@@ -121,6 +121,9 @@ */ BOOL DEBUG_ValidateRegisters(void) { + DBG_ADDR addr; + char ch; + #ifdef __i386__ if (DEBUG_context.EFlags & V86_FLAG) return TRUE; @@ -157,9 +160,13 @@ (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); }
diff --git a/debugger/stack.c b/debugger/stack.c index 36ed896..8e4c99f 100644 --- a/debugger/stack.c +++ b/debugger/stack.c
@@ -30,7 +30,6 @@ static int nframe; static struct bt_info * frames = NULL; -int curr_frame; typedef struct {
diff --git a/debugger/types.c b/debugger/types.c index cab945b..65cee4a 100644 --- a/debugger/types.c +++ b/debugger/types.c
@@ -897,7 +897,11 @@ } } 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; }
diff --git a/debugger/winedbg.c b/debugger/winedbg.c index e459456..bf4d344 100644 --- a/debugger/winedbg.c +++ b/debugger/winedbg.c
@@ -28,6 +28,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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 @@ { char buffer[256]; BOOL ret; - + DEBUG_CurrPid = de->dwProcessId; DEBUG_CurrTid = de->dwThreadId; @@ -400,12 +514,11 @@ 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 @@ /* 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 @@ 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 @@ } 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; } - -
diff --git a/documentation/winedbg b/documentation/winedbg index 04835ed..f77c6e8 100644 --- a/documentation/winedbg +++ b/documentation/winedbg
@@ -10,9 +10,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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