# HG changeset patch # User Bram Moolenaar # Date 1624210203 -7200 # Node ID 2818b8108d92d1f819578b9573d4081043d60960 # Parent 8572a0949d11f84fdf161a46a0ca07a8ae283322 patch 8.2.3026: Vim9: cannot set breakpoint in compiled function Commit: https://github.com/vim/vim/commit/4f8f54280fa728b7d5a63b67d02b60a3b3dce543 Author: Bram Moolenaar Date: Sun Jun 20 19:28:14 2021 +0200 patch 8.2.3026: Vim9: cannot set breakpoint in compiled function Problem: Vim9: cannot set breakpoint in compiled function. Solution: Check for breakpoint when calling a function. diff --git a/src/debugger.c b/src/debugger.c --- a/src/debugger.c +++ b/src/debugger.c @@ -606,7 +606,7 @@ dbg_parsearg( } if (bp->dbg_type == DBG_FUNC) - bp->dbg_name = vim_strsave(p); + bp->dbg_name = vim_strsave(STRNCMP(p, "g:", 2) == 0 ? p + 2 : p); else if (here) bp->dbg_name = vim_strsave(curbuf->b_ffname); else if (bp->dbg_type == DBG_EXPR) diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1629,6 +1629,11 @@ typedef struct # endif garray_T uf_lines; // function lines + + int uf_debug_tick; // when last checked for a breakpoint in this + // function. + int uf_has_breakpoint; // TRUE when a breakpoint has been set in + // this function. # ifdef FEAT_PROFILE int uf_profiling; // TRUE when func is being profiled int uf_prof_initialized; diff --git a/src/testdir/test_debugger.vim b/src/testdir/test_debugger.vim --- a/src/testdir/test_debugger.vim +++ b/src/testdir/test_debugger.vim @@ -932,6 +932,31 @@ func Test_Backtrace_DefFunction() call delete('Xtest2.vim') endfunc +func Test_debug_DefFunction() + CheckCWD + let file =<< trim END + vim9script + def g:SomeFunc() + echo "here" + echo "and" + echo "there" + enddef + breakadd func 2 g:SomeFunc + END + call writefile(file, 'XtestDebug.vim') + + let buf = RunVimInTerminal('-S XtestDebug.vim', {}) + + call RunDbgCmd(buf,':call SomeFunc()', ['line 2: echo "and"']) + call RunDbgCmd(buf,'next', ['line 3: echo "there"']) + + call RunDbgCmd(buf, 'cont') + + call StopVimInTerminal(buf) + call delete('Xtest1.vim') + call delete('Xtest2.vim') +endfunc + func Test_debug_def_function() CheckCWD let file =<< trim END diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3026, +/**/ 3025, /**/ 3024, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -1804,9 +1804,9 @@ typedef enum { // Keep in sync with INSTRUCTIONS(). #ifdef FEAT_PROFILE -# define COMPILE_TYPE(ufunc) (debug_break_level > 0 ? CT_DEBUG : do_profiling == PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE) +# define COMPILE_TYPE(ufunc) (debug_break_level > 0 || ufunc->uf_has_breakpoint ? CT_DEBUG : do_profiling == PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE) #else -# define COMPILE_TYPE(ufunc) debug_break_level > 0 ? CT_DEBUG : CT_NONE +# define COMPILE_TYPE(ufunc) debug_break_level > 0 || ufunc->uf_has_breakpoint ? CT_DEBUG : CT_NONE #endif /* diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -498,7 +498,7 @@ extern garray_T def_functions; // Keep in sync with COMPILE_TYPE() #ifdef FEAT_PROFILE # define INSTRUCTIONS(dfunc) \ - (debug_break_level > 0 \ + (debug_break_level > 0 || dfunc->df_ufunc->uf_has_breakpoint \ ? (dfunc)->df_instr_debug \ : ((do_profiling == PROF_YES && (dfunc->df_ufunc)->uf_profiling) \ ? (dfunc)->df_instr_prof \ diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -148,6 +148,23 @@ exe_newlist(int count, ectx_T *ectx) } /* + * If debug_tick changed check if "ufunc" has a breakpoint and update + * "uf_has_breakpoint". + */ + static void +update_has_breakpoint(ufunc_T *ufunc) +{ + if (ufunc->uf_debug_tick != debug_tick) + { + linenr_T breakpoint; + + ufunc->uf_debug_tick = debug_tick; + breakpoint = dbg_find_breakpoint(FALSE, ufunc->uf_name, 0); + ufunc->uf_has_breakpoint = breakpoint > 0; + } +} + +/* * Call compiled function "cdf_idx" from compiled code. * This adds a stack frame and sets the instruction pointer to the start of the * called function. @@ -1444,6 +1461,20 @@ handle_debug(isn_T *iptr, ectx_T *ectx) garray_T ga; int lnum; + if (ex_nesting_level > debug_break_level) + { + linenr_T breakpoint; + + if (!ufunc->uf_has_breakpoint) + return; + + // check for the next breakpoint if needed + breakpoint = dbg_find_breakpoint(FALSE, ufunc->uf_name, + iptr->isn_lnum - 1); + if (breakpoint <= 0 || breakpoint > iptr->isn_lnum) + return; + } + SOURCING_LNUM = iptr->isn_lnum; debug_context = ectx; debug_var_count = iptr->isn_arg.number; @@ -4206,8 +4237,7 @@ exec_instructions(ectx_T *ectx) break; case ISN_DEBUG: - if (ex_nesting_level <= debug_break_level) - handle_debug(iptr, ectx); + handle_debug(iptr, ectx); break; case ISN_SHUFFLE: @@ -4383,6 +4413,9 @@ call_def_function( #undef STACK_TV_VAR #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx) + // Update uf_has_breakpoint if needed. + update_has_breakpoint(ufunc); + if (ufunc->uf_def_status == UF_NOT_COMPILED || ufunc->uf_def_status == UF_COMPILE_ERROR || (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))