From e31489760cd64c40bc4d058fc632224121bd160d Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 15 Dec 2017 15:15:54 -0700 Subject: [PATCH] breakpoints should work even if they're hit repeatedly. --- src/engine/debugger.c | 31 ++++++--- src/engine/function.c | 17 ++++- test/debugger.py | 146 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 181 insertions(+), 13 deletions(-) diff --git a/src/engine/debugger.c b/src/engine/debugger.c index b58371d2b..e2f235b9b 100644 --- a/src/engine/debugger.c +++ b/src/engine/debugger.c @@ -469,7 +469,8 @@ void debug_on_instruction( FRAME * frame, OBJECT * file, int line ) { int breakpoint_id; assert( debug_is_debugging() ); - if ( debug_state == DEBUG_NEXT && debug_depth <= 0 && debug_line != line ) + if ( debug_state == DEBUG_NEXT && + ( debug_depth < 0 || ( debug_depth == 0 && debug_line != line ) ) ) { debug_file = file; debug_line = line; @@ -483,14 +484,15 @@ void debug_on_instruction( FRAME * frame, OBJECT * file, int line ) debug_frame = frame; debug_end_stepping(); } - else if ( debug_state == DEBUG_FINISH && debug_depth <= 0 ) + else if ( debug_state == DEBUG_FINISH && debug_depth < 0 ) { debug_file = file; debug_line = line; debug_frame = frame; debug_end_stepping(); } - else if ( ( debug_file == NULL || ! object_equal( file, debug_file ) || line != debug_line ) && + else if ( ( debug_file == NULL || ! object_equal( file, debug_file ) || + line != debug_line || debug_depth != 0 ) && ( breakpoint_id = handle_line_breakpoint( file, line ) ) ) { debug_file = file; @@ -498,12 +500,19 @@ void debug_on_instruction( FRAME * frame, OBJECT * file, int line ) debug_frame = frame; debug_on_breakpoint( breakpoint_id ); } + else if ( ( debug_state == DEBUG_RUN || debug_state == DEBUG_FINISH ) && + ( debug_depth < 0 || ( debug_depth == 0 && debug_line != line ) ) ) + { + debug_file = NULL; + debug_line = 0; + } } void debug_on_enter_function( FRAME * frame, OBJECT * name, OBJECT * file, int line ) { int breakpoint_id; assert( debug_is_debugging() ); + ++debug_depth; if ( debug_state == DEBUG_STEP && file ) { debug_file = file; @@ -519,18 +528,18 @@ void debug_on_enter_function( FRAME * frame, OBJECT * name, OBJECT * file, int l debug_frame = frame; debug_on_breakpoint( breakpoint_id ); } - else if ( debug_state == DEBUG_NEXT || debug_state == DEBUG_FINISH ) - { - ++debug_depth; - } } void debug_on_exit_function( OBJECT * name ) { assert( debug_is_debugging() ); - if ( debug_state == DEBUG_NEXT || debug_state == DEBUG_FINISH ) + --debug_depth; + if ( debug_depth < 0 ) { - --debug_depth; + /* The current location is no longer valid + after we return from the containing function. */ + debug_file = NULL; + debug_line = 0; } } @@ -544,11 +553,13 @@ static int child_pid; static void debug_child_continue( int argc, const char * * argv ) { debug_state = DEBUG_RUN; + debug_depth = 0; } static void debug_child_step( int argc, const char * * argv ) { debug_state = DEBUG_STEP; + debug_depth = 0; } static void debug_child_next( int argc, const char * * argv ) @@ -560,7 +571,7 @@ static void debug_child_next( int argc, const char * * argv ) static void debug_child_finish( int argc, const char * * argv ) { debug_state = DEBUG_FINISH; - debug_depth = 1; + debug_depth = 0; } static void debug_child_kill( int argc, const char * * argv ) diff --git a/src/engine/function.c b/src/engine/function.c index 46ec40fea..d426f5386 100644 --- a/src/engine/function.c +++ b/src/engine/function.c @@ -2434,12 +2434,17 @@ static void compile_append_chain( PARSE * parse, compiler * c ) } } -static void compile_parse( PARSE * parse, compiler * c, int result_location ) +static void compile_emit_debug(compiler * c, int line) { #ifdef JAM_DEBUGGER if ( debug_is_debugging() ) - compile_emit( c, INSTR_DEBUG_LINE, parse->line ); + compile_emit( c, INSTR_DEBUG_LINE, line ); #endif +} + +static void compile_parse( PARSE * parse, compiler * c, int result_location ) +{ + compile_emit_debug(c, parse->line); if ( parse->type == PARSE_APPEND ) { compile_append_chain( parse, c ); @@ -2495,6 +2500,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) compile_emit( c, INSTR_FOR_INIT, 0 ); compile_set_label( c, top ); compile_emit_branch( c, INSTR_FOR_LOOP, end ); + compile_emit_debug( c, parse->line ); compile_emit( c, INSTR_SET, var ); compile_push_break_scope( c, end ); @@ -2649,6 +2655,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) group->elems, 0 ) )->s ); var_parse_group_free( group ); compile_parse( parse->right, c, RESULT_STACK ); + compile_emit_debug(c, parse->line); compile_emit( c, INSTR_PUSH_LOCAL, name ); compile_push_cleanup( c, INSTR_POP_LOCAL, name ); compile_parse( parse->third, c, nested_result ); @@ -2660,6 +2667,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) var_parse_group_compile( group, c ); var_parse_group_free( group ); compile_parse( parse->right, c, RESULT_STACK ); + compile_emit_debug(c, parse->line); compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 ); compile_push_cleanup( c, INSTR_POP_LOCAL_GROUP, 0 ); compile_parse( parse->third, c, nested_result ); @@ -2671,6 +2679,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) { compile_parse( parse->left, c, RESULT_STACK ); compile_parse( parse->right, c, RESULT_STACK ); + compile_emit_debug(c, parse->line); compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 ); compile_push_cleanup( c, INSTR_POP_LOCAL_GROUP, 0 ); compile_parse( parse->third, c, nested_result ); @@ -2820,6 +2829,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) group->elems, 0 ) )->s ); var_parse_group_free( group ); compile_parse( parse->right, c, RESULT_STACK ); + compile_emit_debug(c, parse->line); if ( result_location != RESULT_NONE ) { compile_emit( c, INSTR_SET_RESULT, 1 ); @@ -2831,6 +2841,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) var_parse_group_compile( group, c ); var_parse_group_free( group ); compile_parse( parse->right, c, RESULT_STACK ); + compile_emit_debug(c, parse->line); if ( result_location != RESULT_NONE ) { compile_emit( c, INSTR_SET_RESULT, 1 ); @@ -2842,6 +2853,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) { compile_parse( parse->left, c, RESULT_STACK ); compile_parse( parse->right, c, RESULT_STACK ); + compile_emit_debug(c, parse->line); if ( result_location != RESULT_NONE ) { compile_emit( c, INSTR_SET_RESULT, 1 ); @@ -2875,6 +2887,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) compile_parse( parse->third, c, RESULT_STACK ); compile_parse( parse->right, c, RESULT_STACK ); + compile_emit_debug(c, parse->line); switch ( parse->num ) { case ASSIGN_APPEND: compile_emit( c, INSTR_APPEND_ON, 0 ); break; diff --git a/test/debugger.py b/test/debugger.py index 9edfa84c0..7b696a0fc 100644 --- a/test/debugger.py +++ b/test/debugger.py @@ -97,6 +97,9 @@ Breakpoint 1, f ( ) at test.jam:8 """) t.cleanup() +# Note: step doesn't need to worry about breakpoints, +# as it always stops at the next line executed. + def test_next(): t = make_tester() t.write("test.jam", """\ @@ -137,6 +140,51 @@ Breakpoint 1, f ( ) at test.jam:7 """) t.cleanup() +def test_next_breakpoint(): + """next should stop if it encounters a breakpoint. + If the normal end point happens to be a breakpoint, + then it should be reported as normal stepping.""" + t = make_tester() + t.write("test.jam", """\ + rule f ( recurse ? ) + { + if $(recurse) { f ; } + a = 1 ; + } + rule g ( ) + { + b = 2 ; + } + f true ; + g ; + """) + run(t, """\ +(b2db) break f +Breakpoint 1 set at f +(b2db) break g +Breakpoint 2 set at g +(b2db) break test.jam:4 +Breakpoint 3 set at test.jam:4 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( true ) at test.jam:3 +3 if $(recurse) { f ; } +(b2db) next +Breakpoint 1, f ( ) at test.jam:3 +3 if $(recurse) { f ; } +(b2db) next +4 a = 1 ; +(b2db) next +4 a = 1 ; +(b2db) next +11 g ; +(b2db) next +Breakpoint 2, g ( ) at test.jam:8 +8 b = 2 ; +(b2db) quit +""") + t.cleanup() + def test_finish(): t = make_tester() t.write("test.jam", """\ @@ -178,7 +226,100 @@ Breakpoint 1, f ( ) at test.jam:3 (b2db) quit """) t.cleanup() - + +def test_finish_breakpoints(): + """finish should stop when it reaches a breakpoint.""" + t = make_tester() + t.write("test.jam", """\ + rule f ( recurse * ) + { + if $(recurse) + { + a = [ f $(recurse[2-]) ] ; + } + } + rule g ( list * ) + { + for local v in $(list) + { + x = $(v) ; + } + } + f 1 2 ; + g 1 2 ; + """) + run(t, """\ +(b2db) break test.jam:5 +Breakpoint 1 set at test.jam:5 +(b2db) break test.jam:12 +Breakpoint 2 set at test.jam:12 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( 1 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) finish +Breakpoint 1, f ( 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) finish +5 a = [ f $(recurse[2-]) ] ; +(b2db) finish +16 g 1 2 ; +(b2db) finish +Breakpoint 2, g ( 1 2 ) at test.jam:12 +12 x = $(v) ; +(b2db) finish +Breakpoint 2, g ( 1 2 ) at test.jam:12 +12 x = $(v) ; +(b2db) quit +""") + t.cleanup() + +def test_continue_breakpoints(): + """continue should stop when it reaches a breakpoint""" + t = make_tester() + t.write("test.jam", """\ + rule f ( recurse * ) + { + if $(recurse) + { + a = [ f $(recurse[2-]) ] ; + } + } + rule g ( list * ) + { + for local v in $(list) + { + x = $(v) ; + } + } + f 1 2 ; + g 1 2 ; + """) + run(t, """\ +(b2db) break test.jam:5 +Breakpoint 1 set at test.jam:5 +(b2db) break test.jam:12 +Breakpoint 2 set at test.jam:12 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( 1 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) continue +Breakpoint 1, f ( 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) continue +Breakpoint 1, f ( 1 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) continue +Breakpoint 2, g ( 1 2 ) at test.jam:12 +12 x = $(v) ; +(b2db) continue +Breakpoint 2, g ( 1 2 ) at test.jam:12 +12 x = $(v) ; +(b2db) quit +""") + t.cleanup() + def test_breakpoints(): """Tests the interaction between the following commands: break, clear, delete, disable, enable""" @@ -519,7 +660,10 @@ test_run() test_exit_status() test_step() test_next() +test_next_breakpoint() test_finish() +test_finish_breakpoints() +test_continue_breakpoints() test_breakpoints() test_breakpoints_running() test_backtrace()