mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
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.
This commit is contained in:
@@ -218,7 +218,7 @@ do_debug(char_u *cmd)
|
|||||||
|
|
||||||
if (last_cmd != 0)
|
if (last_cmd != 0)
|
||||||
{
|
{
|
||||||
// Execute debug command: decided where to break next and
|
// Execute debug command: decide where to break next and
|
||||||
// return.
|
// return.
|
||||||
switch (last_cmd)
|
switch (last_cmd)
|
||||||
{
|
{
|
||||||
|
@@ -4,6 +4,7 @@ void funcstack_check_refcount(funcstack_T *funcstack);
|
|||||||
char_u *char_from_string(char_u *str, varnumber_T index);
|
char_u *char_from_string(char_u *str, varnumber_T index);
|
||||||
char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
|
char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
|
||||||
int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx);
|
int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx);
|
||||||
|
typval_T *lookup_debug_var(char_u *name);
|
||||||
int exe_typval_instr(typval_T *tv, typval_T *rettv);
|
int exe_typval_instr(typval_T *tv, typval_T *rettv);
|
||||||
char_u *exe_substitute_instr(void);
|
char_u *exe_substitute_instr(void);
|
||||||
int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, typval_T *rettv);
|
int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, typval_T *rettv);
|
||||||
|
@@ -853,6 +853,7 @@ func Test_Backtrace_DefFunction()
|
|||||||
enddef
|
enddef
|
||||||
|
|
||||||
def g:GlobalFunction()
|
def g:GlobalFunction()
|
||||||
|
var some = "some var"
|
||||||
CallAFunction()
|
CallAFunction()
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
@@ -884,19 +885,21 @@ func Test_Backtrace_DefFunction()
|
|||||||
\ ':debug call GlobalFunction()',
|
\ ':debug call GlobalFunction()',
|
||||||
\ ['cmd: call GlobalFunction()'])
|
\ ['cmd: call GlobalFunction()'])
|
||||||
|
|
||||||
call RunDbgCmd(buf, 'step', ['line 1: CallAFunction()'])
|
call RunDbgCmd(buf, 'step', ['line 1: var some = "some var"'])
|
||||||
|
call RunDbgCmd(buf, 'step', ['line 2: CallAFunction()'])
|
||||||
|
call RunDbgCmd(buf, 'echo some', ['some var'])
|
||||||
|
|
||||||
" FIXME: not quite right
|
|
||||||
call RunDbgCmd(buf, 'backtrace', [
|
call RunDbgCmd(buf, 'backtrace', [
|
||||||
\ '\V>backtrace',
|
\ '\V>backtrace',
|
||||||
\ '\V->0 function GlobalFunction',
|
\ '\V->0 function GlobalFunction',
|
||||||
\ '\Vline 1: CallAFunction()',
|
\ '\Vline 2: CallAFunction()',
|
||||||
\ ],
|
\ ],
|
||||||
\ #{match: 'pattern'})
|
\ #{match: 'pattern'})
|
||||||
|
|
||||||
call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()'])
|
call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()'])
|
||||||
call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
|
call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
|
||||||
" FIXME: repeated line
|
" Repeated line, because we fist are in the compiled function before the
|
||||||
|
" EXEC and then in do_cmdline() before the :source command.
|
||||||
call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
|
call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
|
||||||
call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
|
call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
|
||||||
call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
|
call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
|
||||||
@@ -906,7 +909,7 @@ func Test_Backtrace_DefFunction()
|
|||||||
call RunDbgCmd(buf, 'step', ['line 14: File2Function()'])
|
call RunDbgCmd(buf, 'step', ['line 14: File2Function()'])
|
||||||
call RunDbgCmd(buf, 'backtrace', [
|
call RunDbgCmd(buf, 'backtrace', [
|
||||||
\ '\V>backtrace',
|
\ '\V>backtrace',
|
||||||
\ '\V 3 function GlobalFunction[1]',
|
\ '\V 3 function GlobalFunction[2]',
|
||||||
\ '\V 2 <SNR>\.\*_CallAFunction[1]',
|
\ '\V 2 <SNR>\.\*_CallAFunction[1]',
|
||||||
\ '\V 1 <SNR>\.\*_SourceAnotherFile[1]',
|
\ '\V 1 <SNR>\.\*_SourceAnotherFile[1]',
|
||||||
\ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
|
\ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
|
||||||
@@ -917,7 +920,7 @@ func Test_Backtrace_DefFunction()
|
|||||||
call RunDbgCmd(buf, 'next', ['line 15: End of sourced file'])
|
call RunDbgCmd(buf, 'next', ['line 15: End of sourced file'])
|
||||||
call RunDbgCmd(buf, 'backtrace', [
|
call RunDbgCmd(buf, 'backtrace', [
|
||||||
\ '\V>backtrace',
|
\ '\V>backtrace',
|
||||||
\ '\V 3 function GlobalFunction[1]',
|
\ '\V 3 function GlobalFunction[2]',
|
||||||
\ '\V 2 <SNR>\.\*_CallAFunction[1]',
|
\ '\V 2 <SNR>\.\*_CallAFunction[1]',
|
||||||
\ '\V 1 <SNR>\.\*_SourceAnotherFile[1]',
|
\ '\V 1 <SNR>\.\*_SourceAnotherFile[1]',
|
||||||
\ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
|
\ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
|
||||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2996,
|
||||||
/**/
|
/**/
|
||||||
2995,
|
2995,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -168,7 +168,8 @@ typedef enum {
|
|||||||
ISN_PROF_START, // start a line for profiling
|
ISN_PROF_START, // start a line for profiling
|
||||||
ISN_PROF_END, // end a line for profiling
|
ISN_PROF_END, // end a line for profiling
|
||||||
|
|
||||||
ISN_DEBUG, // check for debug breakpoint
|
ISN_DEBUG, // check for debug breakpoint, isn_arg.number is current
|
||||||
|
// number of local variables
|
||||||
|
|
||||||
ISN_UNPACK, // unpack list into items, uses isn_arg.unpack
|
ISN_UNPACK, // unpack list into items, uses isn_arg.unpack
|
||||||
ISN_SHUFFLE, // move item on stack up or down
|
ISN_SHUFFLE, // move item on stack up or down
|
||||||
@@ -447,6 +448,7 @@ struct dfunc_S {
|
|||||||
// was compiled.
|
// was compiled.
|
||||||
|
|
||||||
garray_T df_def_args_isn; // default argument instructions
|
garray_T df_def_args_isn; // default argument instructions
|
||||||
|
garray_T df_var_names; // names of local vars
|
||||||
|
|
||||||
// After compiling "df_instr" and/or "df_instr_prof" is not NULL.
|
// After compiling "df_instr" and/or "df_instr_prof" is not NULL.
|
||||||
isn_T *df_instr; // function body to be executed
|
isn_T *df_instr; // function body to be executed
|
||||||
|
@@ -177,7 +177,6 @@ struct cctx_S {
|
|||||||
compiletype_T ctx_compile_type;
|
compiletype_T ctx_compile_type;
|
||||||
|
|
||||||
garray_T ctx_locals; // currently visible local variables
|
garray_T ctx_locals; // currently visible local variables
|
||||||
int ctx_locals_count; // total number of local variables
|
|
||||||
|
|
||||||
int ctx_has_closure; // set to one if a closures was created in
|
int ctx_has_closure; // set to one if a closures was created in
|
||||||
// the function
|
// the function
|
||||||
@@ -574,6 +573,22 @@ generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
|
|||||||
return isn;
|
return isn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate an ISN_DEBUG instruction.
|
||||||
|
*/
|
||||||
|
static isn_T *
|
||||||
|
generate_instr_debug(cctx_T *cctx)
|
||||||
|
{
|
||||||
|
isn_T *isn;
|
||||||
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||||
|
+ cctx->ctx_ufunc->uf_dfunc_idx;
|
||||||
|
|
||||||
|
if ((isn = generate_instr(cctx, ISN_DEBUG)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
isn->isn_arg.number = dfunc->df_var_names.ga_len;
|
||||||
|
return isn;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
|
* If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
|
||||||
* But only for simple types.
|
* But only for simple types.
|
||||||
@@ -2365,6 +2380,7 @@ reserve_local(
|
|||||||
type_T *type)
|
type_T *type)
|
||||||
{
|
{
|
||||||
lvar_T *lvar;
|
lvar_T *lvar;
|
||||||
|
dfunc_T *dfunc;
|
||||||
|
|
||||||
if (arg_exists(name, len, NULL, NULL, NULL, cctx) == OK)
|
if (arg_exists(name, len, NULL, NULL, NULL, cctx) == OK)
|
||||||
{
|
{
|
||||||
@@ -2381,12 +2397,20 @@ reserve_local(
|
|||||||
// the last ones when leaving a scope, but then variables used in a closure
|
// the last ones when leaving a scope, but then variables used in a closure
|
||||||
// might get overwritten. To keep things simple do not re-use stack
|
// might get overwritten. To keep things simple do not re-use stack
|
||||||
// entries. This is less efficient, but memory is cheap these days.
|
// entries. This is less efficient, but memory is cheap these days.
|
||||||
lvar->lv_idx = cctx->ctx_locals_count++;
|
dfunc = ((dfunc_T *)def_functions.ga_data) + cctx->ctx_ufunc->uf_dfunc_idx;
|
||||||
|
lvar->lv_idx = dfunc->df_var_names.ga_len;
|
||||||
|
|
||||||
lvar->lv_name = vim_strnsave(name, len == 0 ? STRLEN(name) : len);
|
lvar->lv_name = vim_strnsave(name, len == 0 ? STRLEN(name) : len);
|
||||||
lvar->lv_const = isConst;
|
lvar->lv_const = isConst;
|
||||||
lvar->lv_type = type;
|
lvar->lv_type = type;
|
||||||
|
|
||||||
|
// Remember the name for debugging.
|
||||||
|
if (ga_grow(&dfunc->df_var_names, 1) == FAIL)
|
||||||
|
return NULL;
|
||||||
|
((char_u **)dfunc->df_var_names.ga_data)[lvar->lv_idx] =
|
||||||
|
vim_strsave(lvar->lv_name);
|
||||||
|
++dfunc->df_var_names.ga_len;
|
||||||
|
|
||||||
return lvar;
|
return lvar;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7486,7 +7510,7 @@ compile_elseif(char_u *arg, cctx_T *cctx)
|
|||||||
if (cctx->ctx_compile_type == CT_DEBUG)
|
if (cctx->ctx_compile_type == CT_DEBUG)
|
||||||
{
|
{
|
||||||
// the previous block was skipped, may want to debug this line
|
// the previous block was skipped, may want to debug this line
|
||||||
generate_instr(cctx, ISN_DEBUG);
|
generate_instr_debug(cctx);
|
||||||
instr_count = instr->ga_len;
|
instr_count = instr->ga_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8239,7 +8263,7 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (cctx->ctx_compile_type == CT_DEBUG)
|
if (cctx->ctx_compile_type == CT_DEBUG)
|
||||||
generate_instr(cctx, ISN_DEBUG);
|
generate_instr_debug(cctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
p = skipwhite(arg);
|
p = skipwhite(arg);
|
||||||
@@ -8976,6 +9000,7 @@ add_def_function(ufunc_T *ufunc)
|
|||||||
ufunc->uf_dfunc_idx = dfunc->df_idx;
|
ufunc->uf_dfunc_idx = dfunc->df_idx;
|
||||||
dfunc->df_ufunc = ufunc;
|
dfunc->df_ufunc = ufunc;
|
||||||
dfunc->df_name = vim_strsave(ufunc->uf_name);
|
dfunc->df_name = vim_strsave(ufunc->uf_name);
|
||||||
|
ga_init2(&dfunc->df_var_names, sizeof(char_u *), 10);
|
||||||
++dfunc->df_refcount;
|
++dfunc->df_refcount;
|
||||||
++def_functions.ga_len;
|
++def_functions.ga_len;
|
||||||
return OK;
|
return OK;
|
||||||
@@ -9026,7 +9051,21 @@ compile_def_function(
|
|||||||
{
|
{
|
||||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||||
+ ufunc->uf_dfunc_idx;
|
+ ufunc->uf_dfunc_idx;
|
||||||
delete_def_function_contents(dfunc, FALSE);
|
isn_T *instr_dest;
|
||||||
|
|
||||||
|
switch (compile_type)
|
||||||
|
{
|
||||||
|
case CT_PROFILE:
|
||||||
|
#ifdef FEAT_PROFILE
|
||||||
|
instr_dest = dfunc->df_instr_prof; break;
|
||||||
|
#endif
|
||||||
|
case CT_NONE: instr_dest = dfunc->df_instr; break;
|
||||||
|
case CT_DEBUG: instr_dest = dfunc->df_instr_debug; break;
|
||||||
|
}
|
||||||
|
if (instr_dest != NULL)
|
||||||
|
// Was compiled in this mode before: Free old instructions.
|
||||||
|
delete_def_function_contents(dfunc, FALSE);
|
||||||
|
ga_clear_strings(&dfunc->df_var_names);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -9202,7 +9241,7 @@ compile_def_function(
|
|||||||
&& cctx.ctx_skip != SKIP_YES)
|
&& cctx.ctx_skip != SKIP_YES)
|
||||||
{
|
{
|
||||||
debug_lnum = cctx.ctx_lnum;
|
debug_lnum = cctx.ctx_lnum;
|
||||||
generate_instr(&cctx, ISN_DEBUG);
|
generate_instr_debug(&cctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some things can be recognized by the first character.
|
// Some things can be recognized by the first character.
|
||||||
@@ -9670,7 +9709,7 @@ nextline:
|
|||||||
dfunc->df_instr = instr->ga_data;
|
dfunc->df_instr = instr->ga_data;
|
||||||
dfunc->df_instr_count = instr->ga_len;
|
dfunc->df_instr_count = instr->ga_len;
|
||||||
}
|
}
|
||||||
dfunc->df_varcount = cctx.ctx_locals_count;
|
dfunc->df_varcount = dfunc->df_var_names.ga_len;
|
||||||
dfunc->df_has_closure = cctx.ctx_has_closure;
|
dfunc->df_has_closure = cctx.ctx_has_closure;
|
||||||
if (cctx.ctx_outer_used)
|
if (cctx.ctx_outer_used)
|
||||||
ufunc->uf_flags |= FC_CLOSURE;
|
ufunc->uf_flags |= FC_CLOSURE;
|
||||||
@@ -10037,6 +10076,7 @@ delete_def_function_contents(dfunc_T *dfunc, int mark_deleted)
|
|||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
ga_clear(&dfunc->df_def_args_isn);
|
ga_clear(&dfunc->df_def_args_isn);
|
||||||
|
ga_clear_strings(&dfunc->df_var_names);
|
||||||
|
|
||||||
if (dfunc->df_instr != NULL)
|
if (dfunc->df_instr != NULL)
|
||||||
{
|
{
|
||||||
|
@@ -172,6 +172,7 @@ call_dfunc(
|
|||||||
int argcount = argcount_arg;
|
int argcount = argcount_arg;
|
||||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
|
||||||
ufunc_T *ufunc = dfunc->df_ufunc;
|
ufunc_T *ufunc = dfunc->df_ufunc;
|
||||||
|
int did_emsg_before = did_emsg_cumul + did_emsg;
|
||||||
int arg_to_add;
|
int arg_to_add;
|
||||||
int vararg_count = 0;
|
int vararg_count = 0;
|
||||||
int varcount;
|
int varcount;
|
||||||
@@ -211,6 +212,19 @@ call_dfunc(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// When debugging and using "cont" switches to the not-debugged
|
||||||
|
// instructions, may need to still compile them.
|
||||||
|
if ((func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
|
||||||
|
&& compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
|
||||||
|
== FAIL)
|
||||||
|
|| INSTRUCTIONS(dfunc) == NULL)
|
||||||
|
{
|
||||||
|
if (did_emsg_cumul + did_emsg == did_emsg_before)
|
||||||
|
semsg(_(e_function_is_not_compiled_str),
|
||||||
|
printable_func_name(ufunc));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
if (ufunc->uf_va_name != NULL)
|
if (ufunc->uf_va_name != NULL)
|
||||||
{
|
{
|
||||||
// Need to make a list out of the vararg arguments.
|
// Need to make a list out of the vararg arguments.
|
||||||
@@ -1382,6 +1396,36 @@ typedef struct subs_expr_S {
|
|||||||
// Get pointer to a local variable on the stack. Negative for arguments.
|
// Get pointer to a local variable on the stack. Negative for arguments.
|
||||||
#define STACK_TV_VAR(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx + STACK_FRAME_SIZE + idx)
|
#define STACK_TV_VAR(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx + STACK_FRAME_SIZE + idx)
|
||||||
|
|
||||||
|
// Set when calling do_debug().
|
||||||
|
static ectx_T *debug_context = NULL;
|
||||||
|
static int debug_arg_count;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When debugging lookup "name" and return the typeval.
|
||||||
|
* When not found return NULL.
|
||||||
|
*/
|
||||||
|
typval_T *
|
||||||
|
lookup_debug_var(char_u *name)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
dfunc_T *dfunc;
|
||||||
|
ectx_T *ectx = debug_context;
|
||||||
|
|
||||||
|
if (ectx == NULL)
|
||||||
|
return NULL;
|
||||||
|
dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
|
||||||
|
|
||||||
|
// Go through the local variable names, from last to first.
|
||||||
|
for (idx = debug_arg_count - 1; idx >= 0; --idx)
|
||||||
|
{
|
||||||
|
char_u *s = ((char_u **)dfunc->df_var_names.ga_data)[idx];
|
||||||
|
if (STRCMP(s, name) == 0)
|
||||||
|
return STACK_TV_VAR(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute instructions in execution context "ectx".
|
* Execute instructions in execution context "ectx".
|
||||||
* Return OK or FAIL;
|
* Return OK or FAIL;
|
||||||
@@ -4087,7 +4131,7 @@ exec_instructions(ectx_T *ectx)
|
|||||||
funccall_T cookie;
|
funccall_T cookie;
|
||||||
ufunc_T *cur_ufunc =
|
ufunc_T *cur_ufunc =
|
||||||
(((dfunc_T *)def_functions.ga_data)
|
(((dfunc_T *)def_functions.ga_data)
|
||||||
+ ectx->ec_dfunc_idx)->df_ufunc;
|
+ ectx->ec_dfunc_idx)->df_ufunc;
|
||||||
|
|
||||||
cookie.func = cur_ufunc;
|
cookie.func = cur_ufunc;
|
||||||
if (iptr->isn_type == ISN_PROF_START)
|
if (iptr->isn_type == ISN_PROF_START)
|
||||||
@@ -4110,11 +4154,14 @@ exec_instructions(ectx_T *ectx)
|
|||||||
+ ectx->ec_dfunc_idx)->df_ufunc;
|
+ ectx->ec_dfunc_idx)->df_ufunc;
|
||||||
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
|
debug_context = ectx;
|
||||||
|
debug_arg_count = iptr->isn_arg.number;
|
||||||
line = ((char_u **)ufunc->uf_lines.ga_data)[
|
line = ((char_u **)ufunc->uf_lines.ga_data)[
|
||||||
iptr->isn_lnum - 1];
|
iptr->isn_lnum - 1];
|
||||||
if (line == NULL)
|
if (line == NULL)
|
||||||
line = (char_u *)"[empty]";
|
line = (char_u *)"[empty]";
|
||||||
do_debug(line);
|
do_debug(line);
|
||||||
|
debug_context = NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -5346,7 +5393,8 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ISN_DEBUG:
|
case ISN_DEBUG:
|
||||||
smsg("%s%4d DEBUG line %d", pfx, current, iptr->isn_lnum);
|
smsg("%s%4d DEBUG line %d varcount %lld", pfx, current,
|
||||||
|
iptr->isn_lnum, iptr->isn_arg.number);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current,
|
case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current,
|
||||||
|
Reference in New Issue
Block a user