1 /* Process record and replay target for GDB, the GNU debugger. 2 3 Copyright (C) 2008-2016 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "defs.h" 21 #include "gdbcmd.h" 22 #include "completer.h" 23 #include "record.h" 24 #include "observer.h" 25 #include "inferior.h" 26 #include "common/common-utils.h" 27 #include "cli/cli-utils.h" 28 #include "disasm.h" 29 30 #include <ctype.h> 31 32 /* This is the debug switch for process record. */ 33 unsigned int record_debug = 0; 34 35 /* The number of instructions to print in "record instruction-history". */ 36 static unsigned int record_insn_history_size = 10; 37 38 /* The variable registered as control variable in the "record 39 instruction-history" command. Necessary for extra input 40 validation. */ 41 static unsigned int record_insn_history_size_setshow_var; 42 43 /* The number of functions to print in "record function-call-history". */ 44 static unsigned int record_call_history_size = 10; 45 46 /* The variable registered as control variable in the "record 47 call-history" command. Necessary for extra input validation. */ 48 static unsigned int record_call_history_size_setshow_var; 49 50 struct cmd_list_element *record_cmdlist = NULL; 51 struct cmd_list_element *record_goto_cmdlist = NULL; 52 struct cmd_list_element *set_record_cmdlist = NULL; 53 struct cmd_list_element *show_record_cmdlist = NULL; 54 struct cmd_list_element *info_record_cmdlist = NULL; 55 56 #define DEBUG(msg, args...) \ 57 if (record_debug) \ 58 fprintf_unfiltered (gdb_stdlog, "record: " msg "\n", ##args) 59 60 /* See record.h. */ 61 62 struct target_ops * 63 find_record_target (void) 64 { 65 return find_target_at (record_stratum); 66 } 67 68 /* Check that recording is active. Throw an error, if it isn't. */ 69 70 static struct target_ops * 71 require_record_target (void) 72 { 73 struct target_ops *t; 74 75 t = find_record_target (); 76 if (t == NULL) 77 error (_("No record target is currently active.\n" 78 "Use one of the \"target record-<tab><tab>\" commands first.")); 79 80 return t; 81 } 82 83 /* See record.h. */ 84 85 void 86 record_preopen (void) 87 { 88 /* Check if a record target is already running. */ 89 if (find_record_target () != NULL) 90 error (_("The process is already being recorded. Use \"record stop\" to " 91 "stop recording first.")); 92 } 93 94 /* See record.h. */ 95 96 int 97 record_read_memory (struct gdbarch *gdbarch, 98 CORE_ADDR memaddr, gdb_byte *myaddr, 99 ssize_t len) 100 { 101 int ret = target_read_memory (memaddr, myaddr, len); 102 103 if (ret != 0) 104 DEBUG ("error reading memory at addr %s len = %ld.\n", 105 paddress (gdbarch, memaddr), (long) len); 106 107 return ret; 108 } 109 110 /* Stop recording. */ 111 112 static void 113 record_stop (struct target_ops *t) 114 { 115 DEBUG ("stop %s", t->to_shortname); 116 117 t->to_stop_recording (t); 118 } 119 120 /* Unpush the record target. */ 121 122 static void 123 record_unpush (struct target_ops *t) 124 { 125 DEBUG ("unpush %s", t->to_shortname); 126 127 unpush_target (t); 128 } 129 130 /* See record.h. */ 131 132 void 133 record_disconnect (struct target_ops *t, const char *args, int from_tty) 134 { 135 gdb_assert (t->to_stratum == record_stratum); 136 137 DEBUG ("disconnect %s", t->to_shortname); 138 139 record_stop (t); 140 record_unpush (t); 141 142 target_disconnect (args, from_tty); 143 } 144 145 /* See record.h. */ 146 147 void 148 record_detach (struct target_ops *t, const char *args, int from_tty) 149 { 150 gdb_assert (t->to_stratum == record_stratum); 151 152 DEBUG ("detach %s", t->to_shortname); 153 154 record_stop (t); 155 record_unpush (t); 156 157 target_detach (args, from_tty); 158 } 159 160 /* See record.h. */ 161 162 void 163 record_mourn_inferior (struct target_ops *t) 164 { 165 gdb_assert (t->to_stratum == record_stratum); 166 167 DEBUG ("mourn inferior %s", t->to_shortname); 168 169 /* It is safer to not stop recording. Resources will be freed when 170 threads are discarded. */ 171 record_unpush (t); 172 173 target_mourn_inferior (); 174 } 175 176 /* See record.h. */ 177 178 void 179 record_kill (struct target_ops *t) 180 { 181 gdb_assert (t->to_stratum == record_stratum); 182 183 DEBUG ("kill %s", t->to_shortname); 184 185 /* It is safer to not stop recording. Resources will be freed when 186 threads are discarded. */ 187 record_unpush (t); 188 189 target_kill (); 190 } 191 192 /* See record.h. */ 193 194 int 195 record_check_stopped_by_breakpoint (struct address_space *aspace, CORE_ADDR pc, 196 enum target_stop_reason *reason) 197 { 198 if (breakpoint_inserted_here_p (aspace, pc)) 199 { 200 if (hardware_breakpoint_inserted_here_p (aspace, pc)) 201 *reason = TARGET_STOPPED_BY_HW_BREAKPOINT; 202 else 203 *reason = TARGET_STOPPED_BY_SW_BREAKPOINT; 204 return 1; 205 } 206 207 *reason = TARGET_STOPPED_BY_NO_REASON; 208 return 0; 209 } 210 211 /* Implement "show record debug" command. */ 212 213 static void 214 show_record_debug (struct ui_file *file, int from_tty, 215 struct cmd_list_element *c, const char *value) 216 { 217 fprintf_filtered (file, _("Debugging of process record target is %s.\n"), 218 value); 219 } 220 221 /* Alias for "target record". */ 222 223 static void 224 cmd_record_start (char *args, int from_tty) 225 { 226 execute_command ("target record-full", from_tty); 227 } 228 229 /* Truncate the record log from the present point 230 of replay until the end. */ 231 232 static void 233 cmd_record_delete (char *args, int from_tty) 234 { 235 require_record_target (); 236 237 if (!target_record_is_replaying (inferior_ptid)) 238 { 239 printf_unfiltered (_("Already at end of record list.\n")); 240 return; 241 } 242 243 if (!target_supports_delete_record ()) 244 { 245 printf_unfiltered (_("The current record target does not support " 246 "this operation.\n")); 247 return; 248 } 249 250 if (!from_tty || query (_("Delete the log from this point forward " 251 "and begin to record the running message " 252 "at current PC?"))) 253 target_delete_record (); 254 } 255 256 /* Implement the "stoprecord" or "record stop" command. */ 257 258 static void 259 cmd_record_stop (char *args, int from_tty) 260 { 261 struct target_ops *t; 262 263 t = require_record_target (); 264 265 record_stop (t); 266 record_unpush (t); 267 268 printf_unfiltered (_("Process record is stopped and all execution " 269 "logs are deleted.\n")); 270 271 observer_notify_record_changed (current_inferior (), 0, NULL, NULL); 272 } 273 274 /* The "set record" command. */ 275 276 static void 277 set_record_command (char *args, int from_tty) 278 { 279 printf_unfiltered (_("\"set record\" must be followed " 280 "by an apporpriate subcommand.\n")); 281 help_list (set_record_cmdlist, "set record ", all_commands, gdb_stdout); 282 } 283 284 /* The "show record" command. */ 285 286 static void 287 show_record_command (char *args, int from_tty) 288 { 289 cmd_show_list (show_record_cmdlist, from_tty, ""); 290 } 291 292 /* The "info record" command. */ 293 294 static void 295 info_record_command (char *args, int from_tty) 296 { 297 struct target_ops *t; 298 299 t = find_record_target (); 300 if (t == NULL) 301 { 302 printf_filtered (_("No record target is currently active.\n")); 303 return; 304 } 305 306 printf_filtered (_("Active record target: %s\n"), t->to_shortname); 307 t->to_info_record (t); 308 } 309 310 /* The "record save" command. */ 311 312 static void 313 cmd_record_save (char *args, int from_tty) 314 { 315 char *recfilename, recfilename_buffer[40]; 316 317 require_record_target (); 318 319 if (args != NULL && *args != 0) 320 recfilename = args; 321 else 322 { 323 /* Default recfile name is "gdb_record.PID". */ 324 xsnprintf (recfilename_buffer, sizeof (recfilename_buffer), 325 "gdb_record.%d", ptid_get_pid (inferior_ptid)); 326 recfilename = recfilename_buffer; 327 } 328 329 target_save_record (recfilename); 330 } 331 332 /* See record.h. */ 333 334 void 335 record_goto (const char *arg) 336 { 337 ULONGEST insn; 338 339 if (arg == NULL || *arg == '\0') 340 error (_("Command requires an argument (insn number to go to).")); 341 342 insn = parse_and_eval_long (arg); 343 344 require_record_target (); 345 target_goto_record (insn); 346 } 347 348 /* "record goto" command. Argument is an instruction number, 349 as given by "info record". 350 351 Rewinds the recording (forward or backward) to the given instruction. */ 352 353 static void 354 cmd_record_goto (char *arg, int from_tty) 355 { 356 record_goto (arg); 357 } 358 359 /* The "record goto begin" command. */ 360 361 static void 362 cmd_record_goto_begin (char *arg, int from_tty) 363 { 364 if (arg != NULL && *arg != '\0') 365 error (_("Junk after argument: %s."), arg); 366 367 require_record_target (); 368 target_goto_record_begin (); 369 } 370 371 /* The "record goto end" command. */ 372 373 static void 374 cmd_record_goto_end (char *arg, int from_tty) 375 { 376 if (arg != NULL && *arg != '\0') 377 error (_("Junk after argument: %s."), arg); 378 379 require_record_target (); 380 target_goto_record_end (); 381 } 382 383 /* Read an instruction number from an argument string. */ 384 385 static ULONGEST 386 get_insn_number (char **arg) 387 { 388 ULONGEST number; 389 const char *begin, *end, *pos; 390 391 begin = *arg; 392 pos = skip_spaces_const (begin); 393 394 if (!isdigit (*pos)) 395 error (_("Expected positive number, got: %s."), pos); 396 397 number = strtoulst (pos, &end, 10); 398 399 *arg += (end - begin); 400 401 return number; 402 } 403 404 /* Read a context size from an argument string. */ 405 406 static int 407 get_context_size (char **arg) 408 { 409 char *pos; 410 int number; 411 412 pos = skip_spaces (*arg); 413 414 if (!isdigit (*pos)) 415 error (_("Expected positive number, got: %s."), pos); 416 417 return strtol (pos, arg, 10); 418 } 419 420 /* Complain about junk at the end of an argument string. */ 421 422 static void 423 no_chunk (char *arg) 424 { 425 if (*arg != 0) 426 error (_("Junk after argument: %s."), arg); 427 } 428 429 /* Read instruction-history modifiers from an argument string. */ 430 431 static int 432 get_insn_history_modifiers (char **arg) 433 { 434 int modifiers; 435 char *args; 436 437 modifiers = 0; 438 args = *arg; 439 440 if (args == NULL) 441 return modifiers; 442 443 while (*args == '/') 444 { 445 ++args; 446 447 if (*args == '\0') 448 error (_("Missing modifier.")); 449 450 for (; *args; ++args) 451 { 452 if (isspace (*args)) 453 break; 454 455 if (*args == '/') 456 continue; 457 458 switch (*args) 459 { 460 case 'm': 461 case 's': 462 modifiers |= DISASSEMBLY_SOURCE; 463 modifiers |= DISASSEMBLY_FILENAME; 464 break; 465 case 'r': 466 modifiers |= DISASSEMBLY_RAW_INSN; 467 break; 468 case 'f': 469 modifiers |= DISASSEMBLY_OMIT_FNAME; 470 break; 471 case 'p': 472 modifiers |= DISASSEMBLY_OMIT_PC; 473 break; 474 default: 475 error (_("Invalid modifier: %c."), *args); 476 } 477 } 478 479 args = skip_spaces (args); 480 } 481 482 /* Update the argument string. */ 483 *arg = args; 484 485 return modifiers; 486 } 487 488 /* The "set record instruction-history-size / set record 489 function-call-history-size" commands are unsigned, with UINT_MAX 490 meaning unlimited. The target interfaces works with signed int 491 though, to indicate direction, so map "unlimited" to INT_MAX, which 492 is about the same as unlimited in practice. If the user does have 493 a log that huge, she can fetch it in chunks across several requests, 494 but she'll likely have other problems first... */ 495 496 static int 497 command_size_to_target_size (unsigned int size) 498 { 499 gdb_assert (size <= INT_MAX || size == UINT_MAX); 500 501 if (size == UINT_MAX) 502 return INT_MAX; 503 else 504 return size; 505 } 506 507 /* The "record instruction-history" command. */ 508 509 static void 510 cmd_record_insn_history (char *arg, int from_tty) 511 { 512 int flags, size; 513 514 require_record_target (); 515 516 flags = get_insn_history_modifiers (&arg); 517 518 size = command_size_to_target_size (record_insn_history_size); 519 520 if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) 521 target_insn_history (size, flags); 522 else if (strcmp (arg, "-") == 0) 523 target_insn_history (-size, flags); 524 else 525 { 526 ULONGEST begin, end; 527 528 begin = get_insn_number (&arg); 529 530 if (*arg == ',') 531 { 532 arg = skip_spaces (++arg); 533 534 if (*arg == '+') 535 { 536 arg += 1; 537 size = get_context_size (&arg); 538 539 no_chunk (arg); 540 541 target_insn_history_from (begin, size, flags); 542 } 543 else if (*arg == '-') 544 { 545 arg += 1; 546 size = get_context_size (&arg); 547 548 no_chunk (arg); 549 550 target_insn_history_from (begin, -size, flags); 551 } 552 else 553 { 554 end = get_insn_number (&arg); 555 556 no_chunk (arg); 557 558 target_insn_history_range (begin, end, flags); 559 } 560 } 561 else 562 { 563 no_chunk (arg); 564 565 target_insn_history_from (begin, size, flags); 566 } 567 568 dont_repeat (); 569 } 570 } 571 572 /* Read function-call-history modifiers from an argument string. */ 573 574 static int 575 get_call_history_modifiers (char **arg) 576 { 577 int modifiers; 578 char *args; 579 580 modifiers = 0; 581 args = *arg; 582 583 if (args == NULL) 584 return modifiers; 585 586 while (*args == '/') 587 { 588 ++args; 589 590 if (*args == '\0') 591 error (_("Missing modifier.")); 592 593 for (; *args; ++args) 594 { 595 if (isspace (*args)) 596 break; 597 598 if (*args == '/') 599 continue; 600 601 switch (*args) 602 { 603 case 'l': 604 modifiers |= RECORD_PRINT_SRC_LINE; 605 break; 606 case 'i': 607 modifiers |= RECORD_PRINT_INSN_RANGE; 608 break; 609 case 'c': 610 modifiers |= RECORD_PRINT_INDENT_CALLS; 611 break; 612 default: 613 error (_("Invalid modifier: %c."), *args); 614 } 615 } 616 617 args = skip_spaces (args); 618 } 619 620 /* Update the argument string. */ 621 *arg = args; 622 623 return modifiers; 624 } 625 626 /* The "record function-call-history" command. */ 627 628 static void 629 cmd_record_call_history (char *arg, int from_tty) 630 { 631 int flags, size; 632 633 require_record_target (); 634 635 flags = get_call_history_modifiers (&arg); 636 637 size = command_size_to_target_size (record_call_history_size); 638 639 if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) 640 target_call_history (size, flags); 641 else if (strcmp (arg, "-") == 0) 642 target_call_history (-size, flags); 643 else 644 { 645 ULONGEST begin, end; 646 647 begin = get_insn_number (&arg); 648 649 if (*arg == ',') 650 { 651 arg = skip_spaces (++arg); 652 653 if (*arg == '+') 654 { 655 arg += 1; 656 size = get_context_size (&arg); 657 658 no_chunk (arg); 659 660 target_call_history_from (begin, size, flags); 661 } 662 else if (*arg == '-') 663 { 664 arg += 1; 665 size = get_context_size (&arg); 666 667 no_chunk (arg); 668 669 target_call_history_from (begin, -size, flags); 670 } 671 else 672 { 673 end = get_insn_number (&arg); 674 675 no_chunk (arg); 676 677 target_call_history_range (begin, end, flags); 678 } 679 } 680 else 681 { 682 no_chunk (arg); 683 684 target_call_history_from (begin, size, flags); 685 } 686 687 dont_repeat (); 688 } 689 } 690 691 /* Helper for "set record instruction-history-size" and "set record 692 function-call-history-size" input validation. COMMAND_VAR is the 693 variable registered in the command as control variable. *SETTING 694 is the real setting the command allows changing. */ 695 696 static void 697 validate_history_size (unsigned int *command_var, unsigned int *setting) 698 { 699 if (*command_var != UINT_MAX && *command_var > INT_MAX) 700 { 701 unsigned int new_value = *command_var; 702 703 /* Restore previous value. */ 704 *command_var = *setting; 705 error (_("integer %u out of range"), new_value); 706 } 707 708 /* Commit new value. */ 709 *setting = *command_var; 710 } 711 712 /* Called by do_setshow_command. We only want values in the 713 [0..INT_MAX] range, while the command's machinery accepts 714 [0..UINT_MAX]. See command_size_to_target_size. */ 715 716 static void 717 set_record_insn_history_size (char *args, int from_tty, 718 struct cmd_list_element *c) 719 { 720 validate_history_size (&record_insn_history_size_setshow_var, 721 &record_insn_history_size); 722 } 723 724 /* Called by do_setshow_command. We only want values in the 725 [0..INT_MAX] range, while the command's machinery accepts 726 [0..UINT_MAX]. See command_size_to_target_size. */ 727 728 static void 729 set_record_call_history_size (char *args, int from_tty, 730 struct cmd_list_element *c) 731 { 732 validate_history_size (&record_call_history_size_setshow_var, 733 &record_call_history_size); 734 } 735 736 /* Provide a prototype to silence -Wmissing-prototypes. */ 737 extern initialize_file_ftype _initialize_record; 738 739 void 740 _initialize_record (void) 741 { 742 struct cmd_list_element *c; 743 744 add_setshow_zuinteger_cmd ("record", no_class, &record_debug, 745 _("Set debugging of record/replay feature."), 746 _("Show debugging of record/replay feature."), 747 _("When enabled, debugging output for " 748 "record/replay feature is displayed."), 749 NULL, show_record_debug, &setdebuglist, 750 &showdebuglist); 751 752 add_setshow_uinteger_cmd ("instruction-history-size", no_class, 753 &record_insn_history_size_setshow_var, _("\ 754 Set number of instructions to print in \"record instruction-history\"."), _("\ 755 Show number of instructions to print in \"record instruction-history\"."), _("\ 756 A size of \"unlimited\" means unlimited instructions. The default is 10."), 757 set_record_insn_history_size, NULL, 758 &set_record_cmdlist, &show_record_cmdlist); 759 760 add_setshow_uinteger_cmd ("function-call-history-size", no_class, 761 &record_call_history_size_setshow_var, _("\ 762 Set number of function to print in \"record function-call-history\"."), _("\ 763 Show number of functions to print in \"record function-call-history\"."), _("\ 764 A size of \"unlimited\" means unlimited lines. The default is 10."), 765 set_record_call_history_size, NULL, 766 &set_record_cmdlist, &show_record_cmdlist); 767 768 c = add_prefix_cmd ("record", class_obscure, cmd_record_start, 769 _("Start recording."), 770 &record_cmdlist, "record ", 0, &cmdlist); 771 set_cmd_completer (c, filename_completer); 772 773 add_com_alias ("rec", "record", class_obscure, 1); 774 add_prefix_cmd ("record", class_support, set_record_command, 775 _("Set record options"), &set_record_cmdlist, 776 "set record ", 0, &setlist); 777 add_alias_cmd ("rec", "record", class_obscure, 1, &setlist); 778 add_prefix_cmd ("record", class_support, show_record_command, 779 _("Show record options"), &show_record_cmdlist, 780 "show record ", 0, &showlist); 781 add_alias_cmd ("rec", "record", class_obscure, 1, &showlist); 782 add_prefix_cmd ("record", class_support, info_record_command, 783 _("Info record options"), &info_record_cmdlist, 784 "info record ", 0, &infolist); 785 add_alias_cmd ("rec", "record", class_obscure, 1, &infolist); 786 787 c = add_cmd ("save", class_obscure, cmd_record_save, 788 _("Save the execution log to a file.\n\ 789 Argument is optional filename.\n\ 790 Default filename is 'gdb_record.<process_id>'."), 791 &record_cmdlist); 792 set_cmd_completer (c, filename_completer); 793 794 add_cmd ("delete", class_obscure, cmd_record_delete, 795 _("Delete the rest of execution log and start recording it anew."), 796 &record_cmdlist); 797 add_alias_cmd ("d", "delete", class_obscure, 1, &record_cmdlist); 798 add_alias_cmd ("del", "delete", class_obscure, 1, &record_cmdlist); 799 800 add_cmd ("stop", class_obscure, cmd_record_stop, 801 _("Stop the record/replay target."), 802 &record_cmdlist); 803 add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist); 804 805 add_prefix_cmd ("goto", class_obscure, cmd_record_goto, _("\ 806 Restore the program to its state at instruction number N.\n\ 807 Argument is instruction number, as shown by 'info record'."), 808 &record_goto_cmdlist, "record goto ", 1, &record_cmdlist); 809 810 add_cmd ("begin", class_obscure, cmd_record_goto_begin, 811 _("Go to the beginning of the execution log."), 812 &record_goto_cmdlist); 813 add_alias_cmd ("start", "begin", class_obscure, 1, &record_goto_cmdlist); 814 815 add_cmd ("end", class_obscure, cmd_record_goto_end, 816 _("Go to the end of the execution log."), 817 &record_goto_cmdlist); 818 819 add_cmd ("instruction-history", class_obscure, cmd_record_insn_history, _("\ 820 Print disassembled instructions stored in the execution log.\n\ 821 With a /m or /s modifier, source lines are included (if available).\n\ 822 With a /r modifier, raw instructions in hex are included.\n\ 823 With a /f modifier, function names are omitted.\n\ 824 With a /p modifier, current position markers are omitted.\n\ 825 With no argument, disassembles ten more instructions after the previous \ 826 disassembly.\n\ 827 \"record instruction-history -\" disassembles ten instructions before a \ 828 previous disassembly.\n\ 829 One argument specifies an instruction number as shown by 'info record', and \ 830 ten instructions are disassembled after that instruction.\n\ 831 Two arguments with comma between them specify starting and ending instruction \ 832 numbers to disassemble.\n\ 833 If the second argument is preceded by '+' or '-', it specifies the distance \ 834 from the first argument.\n\ 835 The number of instructions to disassemble can be defined with \"set record \ 836 instruction-history-size\"."), 837 &record_cmdlist); 838 839 add_cmd ("function-call-history", class_obscure, cmd_record_call_history, _("\ 840 Prints the execution history at function granularity.\n\ 841 It prints one line for each sequence of instructions that belong to the same \ 842 function.\n\ 843 Without modifiers, it prints the function name.\n\ 844 With a /l modifier, the source file and line number range is included.\n\ 845 With a /i modifier, the instruction number range is included.\n\ 846 With a /c modifier, the output is indented based on the call stack depth.\n\ 847 With no argument, prints ten more lines after the previous ten-line print.\n\ 848 \"record function-call-history -\" prints ten lines before a previous ten-line \ 849 print.\n\ 850 One argument specifies a function number as shown by 'info record', and \ 851 ten lines are printed after that function.\n\ 852 Two arguments with comma between them specify a range of functions to print.\n\ 853 If the second argument is preceded by '+' or '-', it specifies the distance \ 854 from the first argument.\n\ 855 The number of functions to print can be defined with \"set record \ 856 function-call-history-size\"."), 857 &record_cmdlist); 858 859 /* Sync command control variables. */ 860 record_insn_history_size_setshow_var = record_insn_history_size; 861 record_call_history_size_setshow_var = record_call_history_size; 862 } 863