diff options
Diffstat (limited to 'src/nvim/debugger.c')
-rw-r--r-- | src/nvim/debugger.c | 230 |
1 files changed, 127 insertions, 103 deletions
diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 3e0cf82740..f7e70a78ce 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -5,17 +5,33 @@ /// /// Vim script debugger functions +#include <inttypes.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + #include "nvim/ascii.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/debugger.h" #include "nvim/drawscreen.h" #include "nvim/eval.h" +#include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/fileio.h" +#include "nvim/garray.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" #include "nvim/globals.h" +#include "nvim/keycodes.h" +#include "nvim/macros.h" +#include "nvim/memory.h" +#include "nvim/message.h" #include "nvim/os/os.h" +#include "nvim/path.h" #include "nvim/pos.h" #include "nvim/regexp.h" #include "nvim/runtime.h" @@ -114,6 +130,7 @@ void do_debug(char *cmd) for (;;) { msg_scroll = true; need_wait_return = false; + // Save the current typeahead buffer and replace it with an empty one. // This makes sure we get input from the user here and don't interfere // with the commands being executed. Reset "ex_normal_busy" to avoid @@ -300,13 +317,15 @@ static int get_maxbacktrace_level(char *sname) { int maxbacktrace = 0; - if (sname != NULL) { - char *p = sname; - char *q; - while ((q = strstr(p, "..")) != NULL) { - p = q + 2; - maxbacktrace++; - } + if (sname == NULL) { + return 0; + } + + char *p = sname; + char *q; + while ((q = strstr(p, "..")) != NULL) { + p = q + 2; + maxbacktrace++; } return maxbacktrace; } @@ -384,7 +403,7 @@ void ex_debug(exarg_T *eap) debug_break_level = debug_break_level_save; } -static char_u *debug_breakpoint_name = NULL; +static char *debug_breakpoint_name = NULL; static linenr_T debug_breakpoint_lnum; /// When debugging or a breakpoint is set on a skipped command, no debug prompt @@ -393,7 +412,7 @@ static linenr_T debug_breakpoint_lnum; /// a skipped command decides itself that a debug prompt should be displayed, it /// can do so by calling dbg_check_skipped(). static int debug_skipped; -static char_u *debug_skipped_name; +static char *debug_skipped_name; /// Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is /// at or below the break level. But only when the line is actually @@ -407,8 +426,8 @@ void dbg_check_breakpoint(exarg_T *eap) if (!eap->skip) { char *p; // replace K_SNR with "<SNR>" - if (debug_breakpoint_name[0] == K_SPECIAL - && debug_breakpoint_name[1] == KS_EXTRA + if ((uint8_t)debug_breakpoint_name[0] == K_SPECIAL + && (uint8_t)debug_breakpoint_name[1] == KS_EXTRA && debug_breakpoint_name[2] == KE_SNR) { p = "<SNR>"; } else { @@ -441,20 +460,21 @@ void dbg_check_breakpoint(exarg_T *eap) /// @return true when the debug mode is entered this time. bool dbg_check_skipped(exarg_T *eap) { - if (debug_skipped) { - // Save the value of got_int and reset it. We don't want a previous - // interruption cause flushing the input buffer. - int prev_got_int = got_int; - got_int = false; - debug_breakpoint_name = debug_skipped_name; - // eap->skip is true - eap->skip = false; - dbg_check_breakpoint(eap); - eap->skip = true; - got_int |= prev_got_int; - return true; - } - return false; + if (!debug_skipped) { + return false; + } + + // Save the value of got_int and reset it. We don't want a previous + // interruption cause flushing the input buffer. + int prev_got_int = got_int; + got_int = false; + debug_breakpoint_name = debug_skipped_name; + // eap->skip is true + eap->skip = false; + dbg_check_breakpoint(eap); + eap->skip = true; + got_int |= prev_got_int; + return true; } static garray_T dbg_breakp = { 0, 0, sizeof(struct debuggy), 4, NULL }; @@ -498,18 +518,18 @@ static int dbg_parsearg(char *arg, garray_T *gap) struct debuggy *bp = &DEBUGGY(gap, gap->ga_len); // Find "func" or "file". - if (STRNCMP(p, "func", 4) == 0) { + if (strncmp(p, "func", 4) == 0) { bp->dbg_type = DBG_FUNC; - } else if (STRNCMP(p, "file", 4) == 0) { + } else if (strncmp(p, "file", 4) == 0) { bp->dbg_type = DBG_FILE; - } else if (gap != &prof_ga && STRNCMP(p, "here", 4) == 0) { + } else if (gap != &prof_ga && strncmp(p, "here", 4) == 0) { if (curbuf->b_ffname == NULL) { emsg(_(e_noname)); return FAIL; } bp->dbg_type = DBG_FILE; here = true; - } else if (gap != &prof_ga && STRNCMP(p, "expr", 4) == 0) { + } else if (gap != &prof_ga && strncmp(p, "expr", 4) == 0) { bp->dbg_type = DBG_EXPR; } else { semsg(_(e_invarg2), p); @@ -577,33 +597,35 @@ void ex_breakadd(exarg_T *eap) gap = &prof_ga; } - if (dbg_parsearg(eap->arg, gap) == OK) { - struct debuggy *bp = &DEBUGGY(gap, gap->ga_len); - bp->dbg_forceit = eap->forceit; + if (dbg_parsearg(eap->arg, gap) != OK) { + return; + } - if (bp->dbg_type != DBG_EXPR) { - char *pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false); - if (pat != NULL) { - bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); - xfree(pat); + struct debuggy *bp = &DEBUGGY(gap, gap->ga_len); + bp->dbg_forceit = eap->forceit; + + if (bp->dbg_type != DBG_EXPR) { + char *pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false); + if (pat != NULL) { + bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); + xfree(pat); + } + if (pat == NULL || bp->dbg_prog == NULL) { + xfree(bp->dbg_name); + } else { + if (bp->dbg_lnum == 0) { // default line number is 1 + bp->dbg_lnum = 1; } - if (pat == NULL || bp->dbg_prog == NULL) { - xfree(bp->dbg_name); - } else { - if (bp->dbg_lnum == 0) { // default line number is 1 - bp->dbg_lnum = 1; - } - if (eap->cmdidx != CMD_profile) { - DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; - debug_tick++; - } - gap->ga_len++; + if (eap->cmdidx != CMD_profile) { + DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; + debug_tick++; } - } else { - // DBG_EXPR - DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp; - debug_tick++; + gap->ga_len++; } + } else { + // DBG_EXPR + DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp; + debug_tick++; } } @@ -665,32 +687,33 @@ void ex_breakdel(exarg_T *eap) if (todel < 0) { semsg(_("E161: Breakpoint not found: %s"), eap->arg); - } else { - while (!GA_EMPTY(gap)) { - xfree(DEBUGGY(gap, todel).dbg_name); - if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR - && DEBUGGY(gap, todel).dbg_val != NULL) { - tv_free(DEBUGGY(gap, todel).dbg_val); - } - vim_regfree(DEBUGGY(gap, todel).dbg_prog); - gap->ga_len--; - if (todel < gap->ga_len) { - memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1), - (size_t)(gap->ga_len - todel) * sizeof(struct debuggy)); - } - if (eap->cmdidx == CMD_breakdel) { - debug_tick++; - } - if (!del_all) { - break; - } - } + return; + } - // If all breakpoints were removed clear the array. - if (GA_EMPTY(gap)) { - ga_clear(gap); + while (!GA_EMPTY(gap)) { + xfree(DEBUGGY(gap, todel).dbg_name); + if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR + && DEBUGGY(gap, todel).dbg_val != NULL) { + tv_free(DEBUGGY(gap, todel).dbg_val); + } + vim_regfree(DEBUGGY(gap, todel).dbg_prog); + gap->ga_len--; + if (todel < gap->ga_len) { + memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1), + (size_t)(gap->ga_len - todel) * sizeof(struct debuggy)); + } + if (eap->cmdidx == CMD_breakdel) { + debug_tick++; + } + if (!del_all) { + break; } } + + // If all breakpoints were removed clear the array. + if (GA_EMPTY(gap)) { + ga_clear(gap); + } } /// ":breaklist". @@ -698,21 +721,22 @@ void ex_breaklist(exarg_T *eap) { if (GA_EMPTY(&dbg_breakp)) { msg(_("No breakpoints defined")); - } else { - for (int i = 0; i < dbg_breakp.ga_len; i++) { - struct debuggy *bp = &BREAKP(i); - if (bp->dbg_type == DBG_FILE) { - home_replace(NULL, bp->dbg_name, (char *)NameBuff, MAXPATHL, true); - } - if (bp->dbg_type != DBG_EXPR) { - smsg(_("%3d %s %s line %" PRId64), - bp->dbg_nr, - bp->dbg_type == DBG_FUNC ? "func" : "file", - bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff, - (int64_t)bp->dbg_lnum); - } else { - smsg(_("%3d expr %s"), bp->dbg_nr, bp->dbg_name); - } + return; + } + + for (int i = 0; i < dbg_breakp.ga_len; i++) { + struct debuggy *bp = &BREAKP(i); + if (bp->dbg_type == DBG_FILE) { + home_replace(NULL, bp->dbg_name, (char *)NameBuff, MAXPATHL, true); + } + if (bp->dbg_type != DBG_EXPR) { + smsg(_("%3d %s %s line %" PRId64), + bp->dbg_nr, + bp->dbg_type == DBG_FUNC ? "func" : "file", + bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff, + (int64_t)bp->dbg_lnum); + } else { + smsg(_("%3d expr %s"), bp->dbg_nr, bp->dbg_name); } } } @@ -725,7 +749,7 @@ void ex_breaklist(exarg_T *eap) /// @param after after this line number linenr_T dbg_find_breakpoint(bool file, char *fname, linenr_T after) { - return debuggy_find(file, (char_u *)fname, after, &dbg_breakp, NULL); + return debuggy_find(file, fname, after, &dbg_breakp, NULL); } /// @param file true for a file, false for a function @@ -735,7 +759,7 @@ linenr_T dbg_find_breakpoint(bool file, char *fname, linenr_T after) /// @returns true if profiling is on for a function or sourced file. bool has_profiling(bool file, char *fname, bool *fp) { - return debuggy_find(file, (char_u *)fname, (linenr_T)0, &prof_ga, fp) + return debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp) != (linenr_T)0; } @@ -746,11 +770,11 @@ bool has_profiling(bool file, char *fname, bool *fp) /// @param after after this line number /// @param gap either &dbg_breakp or &prof_ga /// @param fp if not NULL: return forceit -static linenr_T debuggy_find(bool file, char_u *fname, linenr_T after, garray_T *gap, bool *fp) +static linenr_T debuggy_find(bool file, char *fname, linenr_T after, garray_T *gap, bool *fp) { struct debuggy *bp; linenr_T lnum = 0; - char_u *name = fname; + char *name = fname; int prev_got_int; // Return quickly when there are no breakpoints. @@ -759,8 +783,8 @@ static linenr_T debuggy_find(bool file, char_u *fname, linenr_T after, garray_T } // Replace K_SNR in function name with "<SNR>". - if (!file && fname[0] == K_SPECIAL) { - name = xmalloc(STRLEN(fname) + 3); + if (!file && (uint8_t)fname[0] == K_SPECIAL) { + name = xmalloc(strlen(fname) + 3); STRCPY(name, "<SNR>"); STRCPY(name + 5, fname + 3); } @@ -791,26 +815,26 @@ static linenr_T debuggy_find(bool file, char_u *fname, linenr_T after, garray_T typval_T *const tv = eval_expr_no_emsg(bp); if (tv != NULL) { if (bp->dbg_val == NULL) { - debug_oldval = typval_tostring(NULL); + debug_oldval = typval_tostring(NULL, true); bp->dbg_val = tv; - debug_newval = typval_tostring(bp->dbg_val); + debug_newval = typval_tostring(bp->dbg_val, true); line = true; } else { if (typval_compare(tv, bp->dbg_val, EXPR_IS, false) == OK && tv->vval.v_number == false) { line = true; - debug_oldval = typval_tostring(bp->dbg_val); + debug_oldval = typval_tostring(bp->dbg_val, true); // Need to evaluate again, typval_compare() overwrites "tv". typval_T *const v = eval_expr_no_emsg(bp); - debug_newval = typval_tostring(v); + debug_newval = typval_tostring(v, true); tv_free(bp->dbg_val); bp->dbg_val = v; } tv_free(tv); } } else if (bp->dbg_val != NULL) { - debug_oldval = typval_tostring(bp->dbg_val); - debug_newval = typval_tostring(NULL); + debug_oldval = typval_tostring(bp->dbg_val, true); + debug_newval = typval_tostring(NULL, true); tv_free(bp->dbg_val); bp->dbg_val = NULL; line = true; @@ -833,6 +857,6 @@ static linenr_T debuggy_find(bool file, char_u *fname, linenr_T after, garray_T void dbg_breakpoint(char *name, linenr_T lnum) { // We need to check if this line is actually executed in do_one_cmd() - debug_breakpoint_name = (char_u *)name; + debug_breakpoint_name = name; debug_breakpoint_lnum = lnum; } |