debugger.c (24240B)
1 /// @file debugger.c 2 /// 3 /// Vim script debugger functions 4 5 #include <inttypes.h> 6 #include <stdbool.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include "nvim/ascii_defs.h" 11 #include "nvim/buffer_defs.h" 12 #include "nvim/charset.h" 13 #include "nvim/cmdexpand_defs.h" 14 #include "nvim/debugger.h" 15 #include "nvim/drawscreen.h" 16 #include "nvim/errors.h" 17 #include "nvim/eval.h" 18 #include "nvim/eval/typval.h" 19 #include "nvim/eval/typval_defs.h" 20 #include "nvim/ex_cmds_defs.h" 21 #include "nvim/ex_docmd.h" 22 #include "nvim/ex_getln.h" 23 #include "nvim/fileio.h" 24 #include "nvim/garray.h" 25 #include "nvim/garray_defs.h" 26 #include "nvim/getchar.h" 27 #include "nvim/getchar_defs.h" 28 #include "nvim/gettext_defs.h" 29 #include "nvim/globals.h" 30 #include "nvim/keycodes.h" 31 #include "nvim/macros_defs.h" 32 #include "nvim/memory.h" 33 #include "nvim/message.h" 34 #include "nvim/os/os.h" 35 #include "nvim/os/os_defs.h" 36 #include "nvim/path.h" 37 #include "nvim/pos_defs.h" 38 #include "nvim/regexp.h" 39 #include "nvim/runtime.h" 40 #include "nvim/runtime_defs.h" 41 #include "nvim/state_defs.h" 42 #include "nvim/types_defs.h" 43 #include "nvim/vim_defs.h" 44 45 /// batch mode debugging: don't save and restore typeahead. 46 static bool debug_greedy = false; 47 48 static char *debug_oldval = NULL; // old and newval for debug expressions 49 static char *debug_newval = NULL; 50 51 /// The list of breakpoints: dbg_breakp. 52 /// This is a grow-array of structs. 53 struct debuggy { 54 int dbg_nr; ///< breakpoint number 55 int dbg_type; ///< DBG_FUNC or DBG_FILE or DBG_EXPR 56 char *dbg_name; ///< function, expression or file name 57 regprog_T *dbg_prog; ///< regexp program 58 linenr_T dbg_lnum; ///< line number in function or file 59 int dbg_forceit; ///< ! used 60 typval_T *dbg_val; ///< last result of watchexpression 61 int dbg_level; ///< stored nested level for expr 62 }; 63 64 #include "debugger.c.generated.h" 65 66 /// Debug mode. Repeatedly get Ex commands, until told to continue normal 67 /// execution. 68 void do_debug(char *cmd) 69 { 70 int save_msg_scroll = msg_scroll; 71 int save_State = State; 72 int save_did_emsg = did_emsg; 73 const bool save_cmd_silent = cmd_silent; 74 int save_msg_silent = msg_silent; 75 int save_emsg_silent = emsg_silent; 76 bool save_redir_off = redir_off; 77 tasave_T typeaheadbuf; 78 bool typeahead_saved = false; 79 int save_ignore_script = 0; 80 char *cmdline = NULL; 81 char *p; 82 char *tail = NULL; 83 static int last_cmd = 0; 84 #define CMD_CONT 1 85 #define CMD_NEXT 2 86 #define CMD_STEP 3 87 #define CMD_FINISH 4 88 #define CMD_QUIT 5 89 #define CMD_INTERRUPT 6 90 #define CMD_BACKTRACE 7 91 #define CMD_FRAME 8 92 #define CMD_UP 9 93 #define CMD_DOWN 10 94 95 RedrawingDisabled++; // don't redisplay the window 96 no_wait_return++; // don't wait for return 97 did_emsg = false; // don't use error from debugged stuff 98 cmd_silent = false; // display commands 99 msg_silent = false; // display messages 100 emsg_silent = false; // display error messages 101 redir_off = true; // don't redirect debug commands 102 103 State = MODE_NORMAL; 104 debug_mode = true; 105 106 if (!debug_did_msg) { 107 msg(_("Entering Debug mode. Type \"cont\" to continue."), 0); 108 } 109 if (debug_oldval != NULL) { 110 smsg(0, _("Oldval = \"%s\""), debug_oldval); 111 XFREE_CLEAR(debug_oldval); 112 } 113 if (debug_newval != NULL) { 114 smsg(0, _("Newval = \"%s\""), debug_newval); 115 XFREE_CLEAR(debug_newval); 116 } 117 char *sname = estack_sfile(ESTACK_NONE); 118 if (sname != NULL) { 119 msg(sname, 0); 120 } 121 xfree(sname); 122 if (SOURCING_LNUM != 0) { 123 smsg(0, _("line %" PRId64 ": %s"), (int64_t)SOURCING_LNUM, cmd); 124 } else { 125 smsg(0, _("cmd: %s"), cmd); 126 } 127 128 // Repeat getting a command and executing it. 129 while (true) { 130 msg_scroll = true; 131 need_wait_return = false; 132 133 // Save the current typeahead buffer and replace it with an empty one. 134 // This makes sure we get input from the user here and don't interfere 135 // with the commands being executed. Reset "ex_normal_busy" to avoid 136 // the side effects of using ":normal". Save the stuff buffer and make 137 // it empty. Set ignore_script to avoid reading from script input. 138 int save_ex_normal_busy = ex_normal_busy; 139 ex_normal_busy = 0; 140 if (!debug_greedy) { 141 save_typeahead(&typeaheadbuf); 142 typeahead_saved = true; 143 save_ignore_script = ignore_script; 144 ignore_script = true; 145 } 146 147 // don't debug any function call, e.g. from an expression mapping 148 int n = debug_break_level; 149 debug_break_level = -1; 150 151 xfree(cmdline); 152 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL, CALLBACK_NONE, false, NULL); 153 154 debug_break_level = n; 155 if (typeahead_saved) { 156 restore_typeahead(&typeaheadbuf); 157 ignore_script = save_ignore_script; 158 } 159 ex_normal_busy = save_ex_normal_busy; 160 161 cmdline_row = msg_row; 162 msg_starthere(); 163 if (cmdline != NULL) { 164 // If this is a debug command, set "last_cmd". 165 // If not, reset "last_cmd". 166 // For a blank line use previous command. 167 p = skipwhite(cmdline); 168 if (*p != NUL) { 169 switch (*p) { 170 case 'c': 171 last_cmd = CMD_CONT; 172 tail = "ont"; 173 break; 174 case 'n': 175 last_cmd = CMD_NEXT; 176 tail = "ext"; 177 break; 178 case 's': 179 last_cmd = CMD_STEP; 180 tail = "tep"; 181 break; 182 case 'f': 183 last_cmd = 0; 184 if (p[1] == 'r') { 185 last_cmd = CMD_FRAME; 186 tail = "rame"; 187 } else { 188 last_cmd = CMD_FINISH; 189 tail = "inish"; 190 } 191 break; 192 case 'q': 193 last_cmd = CMD_QUIT; 194 tail = "uit"; 195 break; 196 case 'i': 197 last_cmd = CMD_INTERRUPT; 198 tail = "nterrupt"; 199 break; 200 case 'b': 201 last_cmd = CMD_BACKTRACE; 202 if (p[1] == 't') { 203 tail = "t"; 204 } else { 205 tail = "acktrace"; 206 } 207 break; 208 case 'w': 209 last_cmd = CMD_BACKTRACE; 210 tail = "here"; 211 break; 212 case 'u': 213 last_cmd = CMD_UP; 214 tail = "p"; 215 break; 216 case 'd': 217 last_cmd = CMD_DOWN; 218 tail = "own"; 219 break; 220 default: 221 last_cmd = 0; 222 } 223 if (last_cmd != 0) { 224 // Check that the tail matches. 225 p++; 226 while (*p != NUL && *p == *tail) { 227 p++; 228 tail++; 229 } 230 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) { 231 last_cmd = 0; 232 } 233 } 234 } 235 236 if (last_cmd != 0) { 237 // Execute debug command: decide where to break next and return. 238 switch (last_cmd) { 239 case CMD_CONT: 240 debug_break_level = -1; 241 break; 242 case CMD_NEXT: 243 debug_break_level = ex_nesting_level; 244 break; 245 case CMD_STEP: 246 debug_break_level = 9999; 247 break; 248 case CMD_FINISH: 249 debug_break_level = ex_nesting_level - 1; 250 break; 251 case CMD_QUIT: 252 got_int = true; 253 debug_break_level = -1; 254 break; 255 case CMD_INTERRUPT: 256 got_int = true; 257 debug_break_level = 9999; 258 // Do not repeat ">interrupt" cmd, continue stepping. 259 last_cmd = CMD_STEP; 260 break; 261 case CMD_BACKTRACE: 262 do_showbacktrace(cmd); 263 continue; 264 case CMD_FRAME: 265 if (*p == NUL) { 266 do_showbacktrace(cmd); 267 } else { 268 p = skipwhite(p); 269 do_setdebugtracelevel(p); 270 } 271 continue; 272 case CMD_UP: 273 debug_backtrace_level++; 274 do_checkbacktracelevel(); 275 continue; 276 case CMD_DOWN: 277 debug_backtrace_level--; 278 do_checkbacktracelevel(); 279 continue; 280 } 281 // Going out reset backtrace_level 282 debug_backtrace_level = 0; 283 break; 284 } 285 286 // don't debug this command 287 n = debug_break_level; 288 debug_break_level = -1; 289 do_cmdline(cmdline, getexline, NULL, DOCMD_VERBOSE|DOCMD_EXCRESET); 290 debug_break_level = n; 291 } 292 lines_left = Rows - 1; 293 } 294 xfree(cmdline); 295 296 RedrawingDisabled--; 297 no_wait_return--; 298 redraw_all_later(UPD_NOT_VALID); 299 need_wait_return = false; 300 msg_scroll = save_msg_scroll; 301 lines_left = Rows - 1; 302 State = save_State; 303 debug_mode = false; 304 did_emsg = save_did_emsg; 305 cmd_silent = save_cmd_silent; 306 msg_silent = save_msg_silent; 307 emsg_silent = save_emsg_silent; 308 redir_off = save_redir_off; 309 310 // Only print the message again when typing a command before coming back here. 311 debug_did_msg = true; 312 } 313 314 static int get_maxbacktrace_level(char *sname) 315 { 316 int maxbacktrace = 0; 317 318 if (sname == NULL) { 319 return 0; 320 } 321 322 char *p = sname; 323 char *q; 324 while ((q = strstr(p, "..")) != NULL) { 325 p = q + 2; 326 maxbacktrace++; 327 } 328 return maxbacktrace; 329 } 330 331 static void do_setdebugtracelevel(char *arg) 332 { 333 int level = atoi(arg); 334 if (*arg == '+' || level < 0) { 335 debug_backtrace_level += level; 336 } else { 337 debug_backtrace_level = level; 338 } 339 340 do_checkbacktracelevel(); 341 } 342 343 static void do_checkbacktracelevel(void) 344 { 345 if (debug_backtrace_level < 0) { 346 debug_backtrace_level = 0; 347 msg(_("frame is zero"), 0); 348 } else { 349 char *sname = estack_sfile(ESTACK_NONE); 350 int max = get_maxbacktrace_level(sname); 351 352 if (debug_backtrace_level > max) { 353 debug_backtrace_level = max; 354 smsg(0, _("frame at highest level: %d"), max); 355 } 356 xfree(sname); 357 } 358 } 359 360 static void do_showbacktrace(char *cmd) 361 { 362 char *sname = estack_sfile(ESTACK_NONE); 363 int max = get_maxbacktrace_level(sname); 364 if (sname != NULL) { 365 int i = 0; 366 char *cur = sname; 367 while (!got_int) { 368 char *next = strstr(cur, ".."); 369 if (next != NULL) { 370 *next = NUL; 371 } 372 if (i == max - debug_backtrace_level) { 373 smsg(0, "->%d %s", max - i, cur); 374 } else { 375 smsg(0, " %d %s", max - i, cur); 376 } 377 i++; 378 if (next == NULL) { 379 break; 380 } 381 *next = '.'; 382 cur = next + 2; 383 } 384 xfree(sname); 385 } 386 387 if (SOURCING_LNUM != 0) { 388 smsg(0, _("line %" PRId64 ": %s"), (int64_t)SOURCING_LNUM, cmd); 389 } else { 390 smsg(0, _("cmd: %s"), cmd); 391 } 392 } 393 394 /// ":debug". 395 void ex_debug(exarg_T *eap) 396 { 397 int debug_break_level_save = debug_break_level; 398 399 debug_break_level = 9999; 400 do_cmdline_cmd(eap->arg); 401 debug_break_level = debug_break_level_save; 402 } 403 404 static char *debug_breakpoint_name = NULL; 405 static linenr_T debug_breakpoint_lnum; 406 407 /// When debugging or a breakpoint is set on a skipped command, no debug prompt 408 /// is shown by do_one_cmd(). This situation is indicated by debug_skipped, and 409 /// debug_skipped_name is then set to the source name in the breakpoint case. If 410 /// a skipped command decides itself that a debug prompt should be displayed, it 411 /// can do so by calling dbg_check_skipped(). 412 static bool debug_skipped; 413 static char *debug_skipped_name; 414 415 /// Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is 416 /// at or below the break level. But only when the line is actually 417 /// executed. Return true and set breakpoint_name for skipped commands that 418 /// decide to execute something themselves. 419 /// Called from do_one_cmd() before executing a command. 420 void dbg_check_breakpoint(exarg_T *eap) 421 { 422 debug_skipped = false; 423 if (debug_breakpoint_name != NULL) { 424 if (!eap->skip) { 425 char *p; 426 // replace K_SNR with "<SNR>" 427 if ((uint8_t)debug_breakpoint_name[0] == K_SPECIAL 428 && (uint8_t)debug_breakpoint_name[1] == KS_EXTRA 429 && debug_breakpoint_name[2] == KE_SNR) { 430 p = "<SNR>"; 431 } else { 432 p = ""; 433 } 434 smsg(0, _("Breakpoint in \"%s%s\" line %" PRId64), 435 p, 436 debug_breakpoint_name + (*p == NUL ? 0 : 3), 437 (int64_t)debug_breakpoint_lnum); 438 debug_breakpoint_name = NULL; 439 do_debug(eap->cmd); 440 } else { 441 debug_skipped = true; 442 debug_skipped_name = debug_breakpoint_name; 443 debug_breakpoint_name = NULL; 444 } 445 } else if (ex_nesting_level <= debug_break_level) { 446 if (!eap->skip) { 447 do_debug(eap->cmd); 448 } else { 449 debug_skipped = true; 450 debug_skipped_name = NULL; 451 } 452 } 453 } 454 455 /// Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was 456 /// set. 457 /// 458 /// @return true when the debug mode is entered this time. 459 bool dbg_check_skipped(exarg_T *eap) 460 { 461 if (!debug_skipped) { 462 return false; 463 } 464 465 // Save the value of got_int and reset it. We don't want a previous 466 // interruption cause flushing the input buffer. 467 bool prev_got_int = got_int; 468 got_int = false; 469 debug_breakpoint_name = debug_skipped_name; 470 // eap->skip is true 471 eap->skip = false; 472 dbg_check_breakpoint(eap); 473 eap->skip = true; 474 got_int |= prev_got_int; 475 return true; 476 } 477 478 static garray_T dbg_breakp = { 0, 0, sizeof(struct debuggy), 4, NULL }; 479 #define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx]) 480 #define DEBUGGY(gap, idx) (((struct debuggy *)(gap)->ga_data)[idx]) 481 static int last_breakp = 0; // nr of last defined breakpoint 482 static bool has_expr_breakpoint = false; 483 484 // Profiling uses file and func names similar to breakpoints. 485 static garray_T prof_ga = { 0, 0, sizeof(struct debuggy), 4, NULL }; 486 #define DBG_FUNC 1 487 #define DBG_FILE 2 488 #define DBG_EXPR 3 489 490 /// Evaluate the "bp->dbg_name" expression and return the result. 491 /// Disables error messages. 492 static typval_T *eval_expr_no_emsg(struct debuggy *const bp) 493 FUNC_ATTR_NONNULL_ALL 494 { 495 // Disable error messages, a bad expression would make Vim unusable. 496 emsg_off++; 497 typval_T *const tv = eval_expr(bp->dbg_name, NULL); 498 emsg_off--; 499 return tv; 500 } 501 502 /// Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them 503 /// in the entry just after the last one in dbg_breakp. Note that "dbg_name" 504 /// is allocated. 505 /// Returns FAIL for failure. 506 /// 507 /// @param arg 508 /// @param gap either &dbg_breakp or &prof_ga 509 static int dbg_parsearg(char *arg, garray_T *gap) 510 { 511 char *p = arg; 512 bool here = false; 513 514 ga_grow(gap, 1); 515 516 struct debuggy *bp = &DEBUGGY(gap, gap->ga_len); 517 518 // Find "func" or "file". 519 if (strncmp(p, "func", 4) == 0) { 520 bp->dbg_type = DBG_FUNC; 521 } else if (strncmp(p, "file", 4) == 0) { 522 bp->dbg_type = DBG_FILE; 523 } else if (gap != &prof_ga && strncmp(p, "here", 4) == 0) { 524 if (curbuf->b_ffname == NULL) { 525 emsg(_(e_noname)); 526 return FAIL; 527 } 528 bp->dbg_type = DBG_FILE; 529 here = true; 530 } else if (gap != &prof_ga && strncmp(p, "expr", 4) == 0) { 531 bp->dbg_type = DBG_EXPR; 532 } else { 533 semsg(_(e_invarg2), p); 534 return FAIL; 535 } 536 p = skipwhite(p + 4); 537 538 // Find optional line number. 539 if (here) { 540 bp->dbg_lnum = curwin->w_cursor.lnum; 541 } else if (gap != &prof_ga && ascii_isdigit(*p)) { 542 bp->dbg_lnum = getdigits_int32(&p, true, 0); 543 p = skipwhite(p); 544 } else { 545 bp->dbg_lnum = 0; 546 } 547 548 // Find the function or file name. Don't accept a function name with (). 549 if ((!here && *p == NUL) 550 || (here && *p != NUL) 551 || (bp->dbg_type == DBG_FUNC && strstr(p, "()") != NULL)) { 552 semsg(_(e_invarg2), arg); 553 return FAIL; 554 } 555 556 if (bp->dbg_type == DBG_FUNC) { 557 bp->dbg_name = xstrdup(strncmp(p, "g:", 2) == 0 ? p + 2 : p); 558 } else if (here) { 559 bp->dbg_name = xstrdup(curbuf->b_ffname); 560 } else if (bp->dbg_type == DBG_EXPR) { 561 bp->dbg_name = xstrdup(p); 562 bp->dbg_val = eval_expr_no_emsg(bp); 563 } else { 564 // Expand the file name in the same way as do_source(). This means 565 // doing it twice, so that $DIR/file gets expanded when $DIR is 566 // "~/dir". 567 char *q = expand_env_save(p); 568 if (q == NULL) { 569 return FAIL; 570 } 571 p = expand_env_save(q); 572 xfree(q); 573 if (p == NULL) { 574 return FAIL; 575 } 576 if (*p != '*') { 577 bp->dbg_name = fix_fname(p); 578 xfree(p); 579 } else { 580 bp->dbg_name = p; 581 } 582 } 583 584 if (bp->dbg_name == NULL) { 585 return FAIL; 586 } 587 return OK; 588 } 589 590 /// ":breakadd". Also used for ":profile". 591 void ex_breakadd(exarg_T *eap) 592 { 593 garray_T *gap = &dbg_breakp; 594 if (eap->cmdidx == CMD_profile) { 595 gap = &prof_ga; 596 } 597 598 if (dbg_parsearg(eap->arg, gap) != OK) { 599 return; 600 } 601 602 struct debuggy *bp = &DEBUGGY(gap, gap->ga_len); 603 bp->dbg_forceit = eap->forceit; 604 605 if (bp->dbg_type != DBG_EXPR) { 606 char *pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false); 607 if (pat != NULL) { 608 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 609 xfree(pat); 610 } 611 if (pat == NULL || bp->dbg_prog == NULL) { 612 xfree(bp->dbg_name); 613 } else { 614 if (bp->dbg_lnum == 0) { // default line number is 1 615 bp->dbg_lnum = 1; 616 } 617 if (eap->cmdidx != CMD_profile) { 618 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; 619 debug_tick++; 620 } 621 gap->ga_len++; 622 } 623 } else { 624 // DBG_EXPR 625 DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp; 626 debug_tick++; 627 if (gap == &dbg_breakp) { 628 has_expr_breakpoint = true; 629 } 630 } 631 } 632 633 /// ":debuggreedy". 634 void ex_debuggreedy(exarg_T *eap) 635 { 636 if (eap->addr_count == 0 || eap->line2 != 0) { 637 debug_greedy = true; 638 } else { 639 debug_greedy = false; 640 } 641 } 642 643 static void update_has_expr_breakpoint(void) 644 { 645 has_expr_breakpoint = false; 646 for (int i = 0; i < dbg_breakp.ga_len; i++) { 647 if (BREAKP(i).dbg_type == DBG_EXPR) { 648 has_expr_breakpoint = true; 649 break; 650 } 651 } 652 } 653 654 /// ":breakdel" and ":profdel". 655 void ex_breakdel(exarg_T *eap) 656 { 657 int todel = -1; 658 bool del_all = false; 659 linenr_T best_lnum = 0; 660 garray_T *gap = &dbg_breakp; 661 662 if (eap->cmdidx == CMD_profdel) { 663 gap = &prof_ga; 664 } 665 666 if (ascii_isdigit(*eap->arg)) { 667 // ":breakdel {nr}" 668 int nr = atoi(eap->arg); 669 for (int i = 0; i < gap->ga_len; i++) { 670 if (DEBUGGY(gap, i).dbg_nr == nr) { 671 todel = i; 672 break; 673 } 674 } 675 } else if (*eap->arg == '*') { 676 todel = 0; 677 del_all = true; 678 } else { 679 // ":breakdel {func|file|expr} [lnum] {name}" 680 if (dbg_parsearg(eap->arg, gap) == FAIL) { 681 return; 682 } 683 struct debuggy *bp = &DEBUGGY(gap, gap->ga_len); 684 for (int i = 0; i < gap->ga_len; i++) { 685 struct debuggy *bpi = &DEBUGGY(gap, i); 686 if (bp->dbg_type == bpi->dbg_type 687 && strcmp(bp->dbg_name, bpi->dbg_name) == 0 688 && (bp->dbg_lnum == bpi->dbg_lnum 689 || (bp->dbg_lnum == 0 690 && (best_lnum == 0 691 || bpi->dbg_lnum < best_lnum)))) { 692 todel = i; 693 best_lnum = bpi->dbg_lnum; 694 } 695 } 696 xfree(bp->dbg_name); 697 } 698 699 if (todel < 0) { 700 semsg(_("E161: Breakpoint not found: %s"), eap->arg); 701 return; 702 } 703 704 while (!GA_EMPTY(gap)) { 705 xfree(DEBUGGY(gap, todel).dbg_name); 706 if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR 707 && DEBUGGY(gap, todel).dbg_val != NULL) { 708 tv_free(DEBUGGY(gap, todel).dbg_val); 709 } 710 vim_regfree(DEBUGGY(gap, todel).dbg_prog); 711 gap->ga_len--; 712 if (todel < gap->ga_len) { 713 memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1), 714 (size_t)(gap->ga_len - todel) * sizeof(struct debuggy)); 715 } 716 if (eap->cmdidx == CMD_breakdel) { 717 debug_tick++; 718 } 719 if (!del_all) { 720 break; 721 } 722 } 723 724 // If all breakpoints were removed clear the array. 725 if (GA_EMPTY(gap)) { 726 ga_clear(gap); 727 } 728 if (gap == &dbg_breakp) { 729 update_has_expr_breakpoint(); 730 } 731 } 732 733 /// ":breaklist". 734 void ex_breaklist(exarg_T *eap) 735 { 736 if (GA_EMPTY(&dbg_breakp)) { 737 msg(_("No breakpoints defined"), 0); 738 return; 739 } 740 741 for (int i = 0; i < dbg_breakp.ga_len; i++) { 742 struct debuggy *bp = &BREAKP(i); 743 if (bp->dbg_type == DBG_FILE) { 744 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, true); 745 } 746 if (bp->dbg_type != DBG_EXPR) { 747 smsg(0, _("%3d %s %s line %" PRId64), 748 bp->dbg_nr, 749 bp->dbg_type == DBG_FUNC ? "func" : "file", 750 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff, 751 (int64_t)bp->dbg_lnum); 752 } else { 753 smsg(0, _("%3d expr %s"), bp->dbg_nr, bp->dbg_name); 754 } 755 } 756 } 757 758 /// Find a breakpoint for a function or sourced file. 759 /// Returns line number at which to break; zero when no matching breakpoint. 760 /// 761 /// @param file true for a file, false for a function 762 /// @param fname file or function name 763 /// @param after after this line number 764 linenr_T dbg_find_breakpoint(bool file, char *fname, linenr_T after) 765 { 766 return debuggy_find(file, fname, after, &dbg_breakp, NULL); 767 } 768 769 /// @param file true for a file, false for a function 770 /// @param fname file or function name 771 /// @param fp[out] forceit 772 /// 773 /// @returns true if profiling is on for a function or sourced file. 774 bool has_profiling(bool file, char *fname, bool *fp) 775 { 776 return debuggy_find(file, fname, 0, &prof_ga, fp) 777 != 0; 778 } 779 780 /// Common code for dbg_find_breakpoint() and has_profiling(). 781 /// 782 /// @param file true for a file, false for a function 783 /// @param fname file or function name 784 /// @param after after this line number 785 /// @param gap either &dbg_breakp or &prof_ga 786 /// @param fp if not NULL: return forceit 787 static linenr_T debuggy_find(bool file, char *fname, linenr_T after, garray_T *gap, bool *fp) 788 { 789 struct debuggy *bp; 790 linenr_T lnum = 0; 791 char *name = fname; 792 793 // Return quickly when there are no breakpoints. 794 if (GA_EMPTY(gap)) { 795 return 0; 796 } 797 798 // Replace K_SNR in function name with "<SNR>". 799 if (!file && (uint8_t)fname[0] == K_SPECIAL) { 800 name = xmalloc(strlen(fname) + 3); 801 STRCPY(name, "<SNR>"); 802 STRCPY(name + 5, fname + 3); 803 } 804 805 for (int i = 0; i < gap->ga_len; i++) { 806 // Skip entries that are not useful or are for a line that is beyond 807 // an already found breakpoint. 808 bp = &DEBUGGY(gap, i); 809 if ((bp->dbg_type == DBG_FILE) == file 810 && bp->dbg_type != DBG_EXPR 811 && (gap == &prof_ga 812 || (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))) { 813 // Save the value of got_int and reset it. We don't want a 814 // previous interruption cancel matching, only hitting CTRL-C 815 // while matching should abort it. 816 bool prev_got_int = got_int; 817 got_int = false; 818 if (vim_regexec_prog(&bp->dbg_prog, false, name, 0)) { 819 lnum = bp->dbg_lnum; 820 if (fp != NULL) { 821 *fp = bp->dbg_forceit; 822 } 823 } 824 got_int |= prev_got_int; 825 } else if (bp->dbg_type == DBG_EXPR) { 826 bool line = false; 827 828 typval_T *const tv = eval_expr_no_emsg(bp); 829 if (tv != NULL) { 830 if (bp->dbg_val == NULL) { 831 xfree(debug_oldval); 832 debug_oldval = typval_tostring(NULL, true); 833 bp->dbg_val = tv; 834 xfree(debug_newval); 835 debug_newval = typval_tostring(bp->dbg_val, true); 836 line = true; 837 } else { 838 if (typval_compare(tv, bp->dbg_val, EXPR_IS, false) == OK 839 && tv->vval.v_number == false) { 840 line = true; 841 xfree(debug_oldval); 842 debug_oldval = typval_tostring(bp->dbg_val, true); 843 // Need to evaluate again, typval_compare() overwrites "tv". 844 typval_T *const v = eval_expr_no_emsg(bp); 845 xfree(debug_newval); 846 debug_newval = typval_tostring(v, true); 847 tv_free(bp->dbg_val); 848 bp->dbg_val = v; 849 } 850 tv_free(tv); 851 } 852 } else if (bp->dbg_val != NULL) { 853 xfree(debug_oldval); 854 debug_oldval = typval_tostring(bp->dbg_val, true); 855 xfree(debug_newval); 856 debug_newval = typval_tostring(NULL, true); 857 tv_free(bp->dbg_val); 858 bp->dbg_val = NULL; 859 line = true; 860 } 861 862 if (line) { 863 lnum = after > 0 ? after : 1; 864 break; 865 } 866 } 867 } 868 if (name != fname) { 869 xfree(name); 870 } 871 872 return lnum; 873 } 874 875 /// Called when a breakpoint was encountered. 876 void dbg_breakpoint(char *name, linenr_T lnum) 877 { 878 // We need to check if this line is actually executed in do_one_cmd() 879 debug_breakpoint_name = name; 880 debug_breakpoint_lnum = lnum; 881 }