Skip to content

Commit b69c6fb

Browse files
committed
patch 8.2.2996: Vim9: when debugging cannot inspect local variables
Problem: Vim9: when debugging cannot inspect local variables. Solution: Make local variables available when debugging.
1 parent 90478f3 commit b69c6fb

7 files changed

Lines changed: 113 additions & 17 deletions

File tree

src/debugger.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ do_debug(char_u *cmd)
218218

219219
if (last_cmd != 0)
220220
{
221-
// Execute debug command: decided where to break next and
221+
// Execute debug command: decide where to break next and
222222
// return.
223223
switch (last_cmd)
224224
{

src/proto/vim9execute.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ void funcstack_check_refcount(funcstack_T *funcstack);
44
char_u *char_from_string(char_u *str, varnumber_T index);
55
char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
66
int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx);
7+
typval_T *lookup_debug_var(char_u *name);
78
int exe_typval_instr(typval_T *tv, typval_T *rettv);
89
char_u *exe_substitute_instr(void);
910
int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, typval_T *rettv);

src/testdir/test_debugger.vim

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ func Test_Backtrace_DefFunction()
853853
enddef
854854

855855
def g:GlobalFunction()
856+
var some = "some var"
856857
CallAFunction()
857858
enddef
858859

@@ -884,19 +885,21 @@ func Test_Backtrace_DefFunction()
884885
\ ':debug call GlobalFunction()',
885886
\ ['cmd: call GlobalFunction()'])
886887

887-
call RunDbgCmd(buf, 'step', ['line 1: CallAFunction()'])
888+
call RunDbgCmd(buf, 'step', ['line 1: var some = "some var"'])
889+
call RunDbgCmd(buf, 'step', ['line 2: CallAFunction()'])
890+
call RunDbgCmd(buf, 'echo some', ['some var'])
888891

889-
" FIXME: not quite right
890892
call RunDbgCmd(buf, 'backtrace', [
891893
\ '\V>backtrace',
892894
\ '\V->0 function GlobalFunction',
893-
\ '\Vline 1: CallAFunction()',
895+
\ '\Vline 2: CallAFunction()',
894896
\ ],
895897
\ #{match: 'pattern'})
896898

897899
call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()'])
898900
call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
899-
" FIXME: repeated line
901+
" Repeated line, because we fist are in the compiled function before the
902+
" EXEC and then in do_cmdline() before the :source command.
900903
call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
901904
call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
902905
call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
@@ -906,7 +909,7 @@ func Test_Backtrace_DefFunction()
906909
call RunDbgCmd(buf, 'step', ['line 14: File2Function()'])
907910
call RunDbgCmd(buf, 'backtrace', [
908911
\ '\V>backtrace',
909-
\ '\V 3 function GlobalFunction[1]',
912+
\ '\V 3 function GlobalFunction[2]',
910913
\ '\V 2 <SNR>\.\*_CallAFunction[1]',
911914
\ '\V 1 <SNR>\.\*_SourceAnotherFile[1]',
912915
\ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
@@ -917,7 +920,7 @@ func Test_Backtrace_DefFunction()
917920
call RunDbgCmd(buf, 'next', ['line 15: End of sourced file'])
918921
call RunDbgCmd(buf, 'backtrace', [
919922
\ '\V>backtrace',
920-
\ '\V 3 function GlobalFunction[1]',
923+
\ '\V 3 function GlobalFunction[2]',
921924
\ '\V 2 <SNR>\.\*_CallAFunction[1]',
922925
\ '\V 1 <SNR>\.\*_SourceAnotherFile[1]',
923926
\ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2996,
753755
/**/
754756
2995,
755757
/**/

src/vim9.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ typedef enum {
168168
ISN_PROF_START, // start a line for profiling
169169
ISN_PROF_END, // end a line for profiling
170170

171-
ISN_DEBUG, // check for debug breakpoint
171+
ISN_DEBUG, // check for debug breakpoint, isn_arg.number is current
172+
// number of local variables
172173

173174
ISN_UNPACK, // unpack list into items, uses isn_arg.unpack
174175
ISN_SHUFFLE, // move item on stack up or down
@@ -447,6 +448,7 @@ struct dfunc_S {
447448
// was compiled.
448449

449450
garray_T df_def_args_isn; // default argument instructions
451+
garray_T df_var_names; // names of local vars
450452

451453
// After compiling "df_instr" and/or "df_instr_prof" is not NULL.
452454
isn_T *df_instr; // function body to be executed

src/vim9compile.c

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,6 @@ struct cctx_S {
177177
compiletype_T ctx_compile_type;
178178

179179
garray_T ctx_locals; // currently visible local variables
180-
int ctx_locals_count; // total number of local variables
181180

182181
int ctx_has_closure; // set to one if a closures was created in
183182
// the function
@@ -574,6 +573,22 @@ generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
574573
return isn;
575574
}
576575

576+
/*
577+
* Generate an ISN_DEBUG instruction.
578+
*/
579+
static isn_T *
580+
generate_instr_debug(cctx_T *cctx)
581+
{
582+
isn_T *isn;
583+
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
584+
+ cctx->ctx_ufunc->uf_dfunc_idx;
585+
586+
if ((isn = generate_instr(cctx, ISN_DEBUG)) == NULL)
587+
return NULL;
588+
isn->isn_arg.number = dfunc->df_var_names.ga_len;
589+
return isn;
590+
}
591+
577592
/*
578593
* If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
579594
* But only for simple types.
@@ -2365,6 +2380,7 @@ reserve_local(
23652380
type_T *type)
23662381
{
23672382
lvar_T *lvar;
2383+
dfunc_T *dfunc;
23682384

23692385
if (arg_exists(name, len, NULL, NULL, NULL, cctx) == OK)
23702386
{
@@ -2381,12 +2397,20 @@ reserve_local(
23812397
// the last ones when leaving a scope, but then variables used in a closure
23822398
// might get overwritten. To keep things simple do not re-use stack
23832399
// entries. This is less efficient, but memory is cheap these days.
2384-
lvar->lv_idx = cctx->ctx_locals_count++;
2400+
dfunc = ((dfunc_T *)def_functions.ga_data) + cctx->ctx_ufunc->uf_dfunc_idx;
2401+
lvar->lv_idx = dfunc->df_var_names.ga_len;
23852402

23862403
lvar->lv_name = vim_strnsave(name, len == 0 ? STRLEN(name) : len);
23872404
lvar->lv_const = isConst;
23882405
lvar->lv_type = type;
23892406

2407+
// Remember the name for debugging.
2408+
if (ga_grow(&dfunc->df_var_names, 1) == FAIL)
2409+
return NULL;
2410+
((char_u **)dfunc->df_var_names.ga_data)[lvar->lv_idx] =
2411+
vim_strsave(lvar->lv_name);
2412+
++dfunc->df_var_names.ga_len;
2413+
23902414
return lvar;
23912415
}
23922416

@@ -7486,7 +7510,7 @@ compile_elseif(char_u *arg, cctx_T *cctx)
74867510
if (cctx->ctx_compile_type == CT_DEBUG)
74877511
{
74887512
// the previous block was skipped, may want to debug this line
7489-
generate_instr(cctx, ISN_DEBUG);
7513+
generate_instr_debug(cctx);
74907514
instr_count = instr->ga_len;
74917515
}
74927516
}
@@ -8239,7 +8263,7 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
82398263
}
82408264
#endif
82418265
if (cctx->ctx_compile_type == CT_DEBUG)
8242-
generate_instr(cctx, ISN_DEBUG);
8266+
generate_instr_debug(cctx);
82438267
}
82448268

82458269
p = skipwhite(arg);
@@ -8976,6 +9000,7 @@ add_def_function(ufunc_T *ufunc)
89769000
ufunc->uf_dfunc_idx = dfunc->df_idx;
89779001
dfunc->df_ufunc = ufunc;
89789002
dfunc->df_name = vim_strsave(ufunc->uf_name);
9003+
ga_init2(&dfunc->df_var_names, sizeof(char_u *), 10);
89799004
++dfunc->df_refcount;
89809005
++def_functions.ga_len;
89819006
return OK;
@@ -9026,7 +9051,21 @@ compile_def_function(
90269051
{
90279052
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
90289053
+ ufunc->uf_dfunc_idx;
9029-
delete_def_function_contents(dfunc, FALSE);
9054+
isn_T *instr_dest;
9055+
9056+
switch (compile_type)
9057+
{
9058+
case CT_PROFILE:
9059+
#ifdef FEAT_PROFILE
9060+
instr_dest = dfunc->df_instr_prof; break;
9061+
#endif
9062+
case CT_NONE: instr_dest = dfunc->df_instr; break;
9063+
case CT_DEBUG: instr_dest = dfunc->df_instr_debug; break;
9064+
}
9065+
if (instr_dest != NULL)
9066+
// Was compiled in this mode before: Free old instructions.
9067+
delete_def_function_contents(dfunc, FALSE);
9068+
ga_clear_strings(&dfunc->df_var_names);
90309069
}
90319070
else
90329071
{
@@ -9202,7 +9241,7 @@ compile_def_function(
92029241
&& cctx.ctx_skip != SKIP_YES)
92039242
{
92049243
debug_lnum = cctx.ctx_lnum;
9205-
generate_instr(&cctx, ISN_DEBUG);
9244+
generate_instr_debug(&cctx);
92069245
}
92079246

92089247
// Some things can be recognized by the first character.
@@ -9670,7 +9709,7 @@ compile_def_function(
96709709
dfunc->df_instr = instr->ga_data;
96719710
dfunc->df_instr_count = instr->ga_len;
96729711
}
9673-
dfunc->df_varcount = cctx.ctx_locals_count;
9712+
dfunc->df_varcount = dfunc->df_var_names.ga_len;
96749713
dfunc->df_has_closure = cctx.ctx_has_closure;
96759714
if (cctx.ctx_outer_used)
96769715
ufunc->uf_flags |= FC_CLOSURE;
@@ -10037,6 +10076,7 @@ delete_def_function_contents(dfunc_T *dfunc, int mark_deleted)
1003710076
int idx;
1003810077

1003910078
ga_clear(&dfunc->df_def_args_isn);
10079+
ga_clear_strings(&dfunc->df_var_names);
1004010080

1004110081
if (dfunc->df_instr != NULL)
1004210082
{

src/vim9execute.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ call_dfunc(
172172
int argcount = argcount_arg;
173173
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
174174
ufunc_T *ufunc = dfunc->df_ufunc;
175+
int did_emsg_before = did_emsg_cumul + did_emsg;
175176
int arg_to_add;
176177
int vararg_count = 0;
177178
int varcount;
@@ -211,6 +212,19 @@ call_dfunc(
211212
}
212213
#endif
213214

215+
// When debugging and using "cont" switches to the not-debugged
216+
// instructions, may need to still compile them.
217+
if ((func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
218+
&& compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
219+
== FAIL)
220+
|| INSTRUCTIONS(dfunc) == NULL)
221+
{
222+
if (did_emsg_cumul + did_emsg == did_emsg_before)
223+
semsg(_(e_function_is_not_compiled_str),
224+
printable_func_name(ufunc));
225+
return FAIL;
226+
}
227+
214228
if (ufunc->uf_va_name != NULL)
215229
{
216230
// Need to make a list out of the vararg arguments.
@@ -1382,6 +1396,36 @@ typedef struct subs_expr_S {
13821396
// Get pointer to a local variable on the stack. Negative for arguments.
13831397
#define STACK_TV_VAR(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx + STACK_FRAME_SIZE + idx)
13841398

1399+
// Set when calling do_debug().
1400+
static ectx_T *debug_context = NULL;
1401+
static int debug_arg_count;
1402+
1403+
/*
1404+
* When debugging lookup "name" and return the typeval.
1405+
* When not found return NULL.
1406+
*/
1407+
typval_T *
1408+
lookup_debug_var(char_u *name)
1409+
{
1410+
int idx;
1411+
dfunc_T *dfunc;
1412+
ectx_T *ectx = debug_context;
1413+
1414+
if (ectx == NULL)
1415+
return NULL;
1416+
dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
1417+
1418+
// Go through the local variable names, from last to first.
1419+
for (idx = debug_arg_count - 1; idx >= 0; --idx)
1420+
{
1421+
char_u *s = ((char_u **)dfunc->df_var_names.ga_data)[idx];
1422+
if (STRCMP(s, name) == 0)
1423+
return STACK_TV_VAR(idx);
1424+
}
1425+
1426+
return NULL;
1427+
}
1428+
13851429
/*
13861430
* Execute instructions in execution context "ectx".
13871431
* Return OK or FAIL;
@@ -4087,7 +4131,7 @@ exec_instructions(ectx_T *ectx)
40874131
funccall_T cookie;
40884132
ufunc_T *cur_ufunc =
40894133
(((dfunc_T *)def_functions.ga_data)
4090-
+ ectx->ec_dfunc_idx)->df_ufunc;
4134+
+ ectx->ec_dfunc_idx)->df_ufunc;
40914135

40924136
cookie.func = cur_ufunc;
40934137
if (iptr->isn_type == ISN_PROF_START)
@@ -4110,11 +4154,14 @@ exec_instructions(ectx_T *ectx)
41104154
+ ectx->ec_dfunc_idx)->df_ufunc;
41114155

41124156
SOURCING_LNUM = iptr->isn_lnum;
4157+
debug_context = ectx;
4158+
debug_arg_count = iptr->isn_arg.number;
41134159
line = ((char_u **)ufunc->uf_lines.ga_data)[
41144160
iptr->isn_lnum - 1];
41154161
if (line == NULL)
41164162
line = (char_u *)"[empty]";
41174163
do_debug(line);
4164+
debug_context = NULL;
41184165
}
41194166
break;
41204167

@@ -5346,7 +5393,8 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
53465393
break;
53475394

53485395
case ISN_DEBUG:
5349-
smsg("%s%4d DEBUG line %d", pfx, current, iptr->isn_lnum);
5396+
smsg("%s%4d DEBUG line %d varcount %lld", pfx, current,
5397+
iptr->isn_lnum, iptr->isn_arg.number);
53505398
break;
53515399

53525400
case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current,

0 commit comments

Comments
 (0)