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