GDB (API)
|
00001 /* Process record and replay target for GDB, the GNU debugger. 00002 00003 Copyright (C) 2008-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "gdbcmd.h" 00022 #include "completer.h" 00023 #include "record.h" 00024 #include "observer.h" 00025 #include "inferior.h" 00026 #include "common/common-utils.h" 00027 #include "cli/cli-utils.h" 00028 #include "disasm.h" 00029 00030 #include <ctype.h> 00031 00032 /* This is the debug switch for process record. */ 00033 unsigned int record_debug = 0; 00034 00035 /* The number of instructions to print in "record instruction-history". */ 00036 static unsigned int record_insn_history_size = 10; 00037 00038 /* The variable registered as control variable in the "record 00039 instruction-history" command. Necessary for extra input 00040 validation. */ 00041 static unsigned int record_insn_history_size_setshow_var; 00042 00043 /* The number of functions to print in "record function-call-history". */ 00044 static unsigned int record_call_history_size = 10; 00045 00046 /* The variable registered as control variable in the "record 00047 call-history" command. Necessary for extra input validation. */ 00048 static unsigned int record_call_history_size_setshow_var; 00049 00050 struct cmd_list_element *record_cmdlist = NULL; 00051 struct cmd_list_element *record_goto_cmdlist = NULL; 00052 struct cmd_list_element *set_record_cmdlist = NULL; 00053 struct cmd_list_element *show_record_cmdlist = NULL; 00054 struct cmd_list_element *info_record_cmdlist = NULL; 00055 00056 #define DEBUG(msg, args...) \ 00057 if (record_debug) \ 00058 fprintf_unfiltered (gdb_stdlog, "record: " msg "\n", ##args) 00059 00060 /* Find the record target in the target stack. */ 00061 00062 static struct target_ops * 00063 find_record_target (void) 00064 { 00065 struct target_ops *t; 00066 00067 for (t = current_target.beneath; t != NULL; t = t->beneath) 00068 if (t->to_stratum == record_stratum) 00069 return t; 00070 00071 return NULL; 00072 } 00073 00074 /* Check that recording is active. Throw an error, if it isn't. */ 00075 00076 static struct target_ops * 00077 require_record_target (void) 00078 { 00079 struct target_ops *t; 00080 00081 t = find_record_target (); 00082 if (t == NULL) 00083 error (_("No record target is currently active.\n" 00084 "Use one of the \"target record-<tab><tab>\" commands first.")); 00085 00086 return t; 00087 } 00088 00089 /* See record.h. */ 00090 00091 int 00092 record_read_memory (struct gdbarch *gdbarch, 00093 CORE_ADDR memaddr, gdb_byte *myaddr, 00094 ssize_t len) 00095 { 00096 int ret = target_read_memory (memaddr, myaddr, len); 00097 00098 if (ret != 0) 00099 DEBUG ("error reading memory at addr %s len = %ld.\n", 00100 paddress (gdbarch, memaddr), (long) len); 00101 00102 return ret; 00103 } 00104 00105 /* Stop recording. */ 00106 00107 static void 00108 record_stop (struct target_ops *t) 00109 { 00110 DEBUG ("stop %s", t->to_shortname); 00111 00112 if (t->to_stop_recording != NULL) 00113 t->to_stop_recording (); 00114 } 00115 00116 /* Unpush the record target. */ 00117 00118 static void 00119 record_unpush (struct target_ops *t) 00120 { 00121 DEBUG ("unpush %s", t->to_shortname); 00122 00123 unpush_target (t); 00124 } 00125 00126 /* See record.h. */ 00127 00128 void 00129 record_disconnect (struct target_ops *t, char *args, int from_tty) 00130 { 00131 gdb_assert (t->to_stratum == record_stratum); 00132 00133 DEBUG ("disconnect %s", t->to_shortname); 00134 00135 record_stop (t); 00136 record_unpush (t); 00137 00138 target_disconnect (args, from_tty); 00139 } 00140 00141 /* See record.h. */ 00142 00143 void 00144 record_detach (struct target_ops *t, char *args, int from_tty) 00145 { 00146 gdb_assert (t->to_stratum == record_stratum); 00147 00148 DEBUG ("detach %s", t->to_shortname); 00149 00150 record_stop (t); 00151 record_unpush (t); 00152 00153 target_detach (args, from_tty); 00154 } 00155 00156 /* See record.h. */ 00157 00158 void 00159 record_mourn_inferior (struct target_ops *t) 00160 { 00161 gdb_assert (t->to_stratum == record_stratum); 00162 00163 DEBUG ("mourn inferior %s", t->to_shortname); 00164 00165 /* It is safer to not stop recording. Resources will be freed when 00166 threads are discarded. */ 00167 record_unpush (t); 00168 00169 target_mourn_inferior (); 00170 } 00171 00172 /* See record.h. */ 00173 00174 void 00175 record_kill (struct target_ops *t) 00176 { 00177 gdb_assert (t->to_stratum == record_stratum); 00178 00179 DEBUG ("kill %s", t->to_shortname); 00180 00181 /* It is safer to not stop recording. Resources will be freed when 00182 threads are discarded. */ 00183 record_unpush (t); 00184 00185 target_kill (); 00186 } 00187 00188 /* Implement "show record debug" command. */ 00189 00190 static void 00191 show_record_debug (struct ui_file *file, int from_tty, 00192 struct cmd_list_element *c, const char *value) 00193 { 00194 fprintf_filtered (file, _("Debugging of process record target is %s.\n"), 00195 value); 00196 } 00197 00198 /* Alias for "target record". */ 00199 00200 static void 00201 cmd_record_start (char *args, int from_tty) 00202 { 00203 execute_command ("target record-full", from_tty); 00204 } 00205 00206 /* Truncate the record log from the present point 00207 of replay until the end. */ 00208 00209 static void 00210 cmd_record_delete (char *args, int from_tty) 00211 { 00212 require_record_target (); 00213 00214 if (!target_record_is_replaying ()) 00215 { 00216 printf_unfiltered (_("Already at end of record list.\n")); 00217 return; 00218 } 00219 00220 if (!target_supports_delete_record ()) 00221 { 00222 printf_unfiltered (_("The current record target does not support " 00223 "this operation.\n")); 00224 return; 00225 } 00226 00227 if (!from_tty || query (_("Delete the log from this point forward " 00228 "and begin to record the running message " 00229 "at current PC?"))) 00230 target_delete_record (); 00231 } 00232 00233 /* Implement the "stoprecord" or "record stop" command. */ 00234 00235 static void 00236 cmd_record_stop (char *args, int from_tty) 00237 { 00238 struct target_ops *t; 00239 00240 t = require_record_target (); 00241 00242 record_stop (t); 00243 record_unpush (t); 00244 00245 printf_unfiltered (_("Process record is stopped and all execution " 00246 "logs are deleted.\n")); 00247 00248 observer_notify_record_changed (current_inferior (), 0); 00249 } 00250 00251 /* The "set record" command. */ 00252 00253 static void 00254 set_record_command (char *args, int from_tty) 00255 { 00256 printf_unfiltered (_("\"set record\" must be followed " 00257 "by an apporpriate subcommand.\n")); 00258 help_list (set_record_cmdlist, "set record ", all_commands, gdb_stdout); 00259 } 00260 00261 /* The "show record" command. */ 00262 00263 static void 00264 show_record_command (char *args, int from_tty) 00265 { 00266 cmd_show_list (show_record_cmdlist, from_tty, ""); 00267 } 00268 00269 /* The "info record" command. */ 00270 00271 static void 00272 info_record_command (char *args, int from_tty) 00273 { 00274 struct target_ops *t; 00275 00276 t = find_record_target (); 00277 if (t == NULL) 00278 { 00279 printf_filtered (_("No record target is currently active.\n")); 00280 return; 00281 } 00282 00283 printf_filtered (_("Active record target: %s\n"), t->to_shortname); 00284 if (t->to_info_record != NULL) 00285 t->to_info_record (); 00286 } 00287 00288 /* The "record save" command. */ 00289 00290 static void 00291 cmd_record_save (char *args, int from_tty) 00292 { 00293 char *recfilename, recfilename_buffer[40]; 00294 00295 require_record_target (); 00296 00297 if (args != NULL && *args != 0) 00298 recfilename = args; 00299 else 00300 { 00301 /* Default recfile name is "gdb_record.PID". */ 00302 xsnprintf (recfilename_buffer, sizeof (recfilename_buffer), 00303 "gdb_record.%d", ptid_get_pid (inferior_ptid)); 00304 recfilename = recfilename_buffer; 00305 } 00306 00307 target_save_record (recfilename); 00308 } 00309 00310 /* "record goto" command. Argument is an instruction number, 00311 as given by "info record". 00312 00313 Rewinds the recording (forward or backward) to the given instruction. */ 00314 00315 void 00316 cmd_record_goto (char *arg, int from_tty) 00317 { 00318 ULONGEST insn; 00319 00320 if (arg == NULL || *arg == '\0') 00321 error (_("Command requires an argument (insn number to go to).")); 00322 00323 insn = parse_and_eval_long (arg); 00324 00325 require_record_target (); 00326 target_goto_record (insn); 00327 } 00328 00329 /* The "record goto begin" command. */ 00330 00331 static void 00332 cmd_record_goto_begin (char *arg, int from_tty) 00333 { 00334 if (arg != NULL && *arg != '\0') 00335 error (_("Junk after argument: %s."), arg); 00336 00337 require_record_target (); 00338 target_goto_record_begin (); 00339 } 00340 00341 /* The "record goto end" command. */ 00342 00343 static void 00344 cmd_record_goto_end (char *arg, int from_tty) 00345 { 00346 if (arg != NULL && *arg != '\0') 00347 error (_("Junk after argument: %s."), arg); 00348 00349 require_record_target (); 00350 target_goto_record_end (); 00351 } 00352 00353 /* Read an instruction number from an argument string. */ 00354 00355 static ULONGEST 00356 get_insn_number (char **arg) 00357 { 00358 ULONGEST number; 00359 const char *begin, *end, *pos; 00360 00361 begin = *arg; 00362 pos = skip_spaces_const (begin); 00363 00364 if (!isdigit (*pos)) 00365 error (_("Expected positive number, got: %s."), pos); 00366 00367 number = strtoulst (pos, &end, 10); 00368 00369 *arg += (end - begin); 00370 00371 return number; 00372 } 00373 00374 /* Read a context size from an argument string. */ 00375 00376 static int 00377 get_context_size (char **arg) 00378 { 00379 char *pos; 00380 int number; 00381 00382 pos = skip_spaces (*arg); 00383 00384 if (!isdigit (*pos)) 00385 error (_("Expected positive number, got: %s."), pos); 00386 00387 return strtol (pos, arg, 10); 00388 } 00389 00390 /* Complain about junk at the end of an argument string. */ 00391 00392 static void 00393 no_chunk (char *arg) 00394 { 00395 if (*arg != 0) 00396 error (_("Junk after argument: %s."), arg); 00397 } 00398 00399 /* Read instruction-history modifiers from an argument string. */ 00400 00401 static int 00402 get_insn_history_modifiers (char **arg) 00403 { 00404 int modifiers; 00405 char *args; 00406 00407 modifiers = 0; 00408 args = *arg; 00409 00410 if (args == NULL) 00411 return modifiers; 00412 00413 while (*args == '/') 00414 { 00415 ++args; 00416 00417 if (*args == '\0') 00418 error (_("Missing modifier.")); 00419 00420 for (; *args; ++args) 00421 { 00422 if (isspace (*args)) 00423 break; 00424 00425 if (*args == '/') 00426 continue; 00427 00428 switch (*args) 00429 { 00430 case 'm': 00431 modifiers |= DISASSEMBLY_SOURCE; 00432 modifiers |= DISASSEMBLY_FILENAME; 00433 break; 00434 case 'r': 00435 modifiers |= DISASSEMBLY_RAW_INSN; 00436 break; 00437 case 'f': 00438 modifiers |= DISASSEMBLY_OMIT_FNAME; 00439 break; 00440 case 'p': 00441 modifiers |= DISASSEMBLY_OMIT_PC; 00442 break; 00443 default: 00444 error (_("Invalid modifier: %c."), *args); 00445 } 00446 } 00447 00448 args = skip_spaces (args); 00449 } 00450 00451 /* Update the argument string. */ 00452 *arg = args; 00453 00454 return modifiers; 00455 } 00456 00457 /* The "set record instruction-history-size / set record 00458 function-call-history-size" commands are unsigned, with UINT_MAX 00459 meaning unlimited. The target interfaces works with signed int 00460 though, to indicate direction, so map "unlimited" to INT_MAX, which 00461 is about the same as unlimited in practice. If the user does have 00462 a log that huge, she can fetch it in chunks across several requests, 00463 but she'll likely have other problems first... */ 00464 00465 static int 00466 command_size_to_target_size (unsigned int size) 00467 { 00468 gdb_assert (size <= INT_MAX || size == UINT_MAX); 00469 00470 if (size == UINT_MAX) 00471 return INT_MAX; 00472 else 00473 return size; 00474 } 00475 00476 /* The "record instruction-history" command. */ 00477 00478 static void 00479 cmd_record_insn_history (char *arg, int from_tty) 00480 { 00481 int flags, size; 00482 00483 require_record_target (); 00484 00485 flags = get_insn_history_modifiers (&arg); 00486 00487 size = command_size_to_target_size (record_insn_history_size); 00488 00489 if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) 00490 target_insn_history (size, flags); 00491 else if (strcmp (arg, "-") == 0) 00492 target_insn_history (-size, flags); 00493 else 00494 { 00495 ULONGEST begin, end; 00496 00497 begin = get_insn_number (&arg); 00498 00499 if (*arg == ',') 00500 { 00501 arg = skip_spaces (++arg); 00502 00503 if (*arg == '+') 00504 { 00505 arg += 1; 00506 size = get_context_size (&arg); 00507 00508 no_chunk (arg); 00509 00510 target_insn_history_from (begin, size, flags); 00511 } 00512 else if (*arg == '-') 00513 { 00514 arg += 1; 00515 size = get_context_size (&arg); 00516 00517 no_chunk (arg); 00518 00519 target_insn_history_from (begin, -size, flags); 00520 } 00521 else 00522 { 00523 end = get_insn_number (&arg); 00524 00525 no_chunk (arg); 00526 00527 target_insn_history_range (begin, end, flags); 00528 } 00529 } 00530 else 00531 { 00532 no_chunk (arg); 00533 00534 target_insn_history_from (begin, size, flags); 00535 } 00536 00537 dont_repeat (); 00538 } 00539 } 00540 00541 /* Read function-call-history modifiers from an argument string. */ 00542 00543 static int 00544 get_call_history_modifiers (char **arg) 00545 { 00546 int modifiers; 00547 char *args; 00548 00549 modifiers = 0; 00550 args = *arg; 00551 00552 if (args == NULL) 00553 return modifiers; 00554 00555 while (*args == '/') 00556 { 00557 ++args; 00558 00559 if (*args == '\0') 00560 error (_("Missing modifier.")); 00561 00562 for (; *args; ++args) 00563 { 00564 if (isspace (*args)) 00565 break; 00566 00567 if (*args == '/') 00568 continue; 00569 00570 switch (*args) 00571 { 00572 case 'l': 00573 modifiers |= RECORD_PRINT_SRC_LINE; 00574 break; 00575 case 'i': 00576 modifiers |= RECORD_PRINT_INSN_RANGE; 00577 break; 00578 default: 00579 error (_("Invalid modifier: %c."), *args); 00580 } 00581 } 00582 00583 args = skip_spaces (args); 00584 } 00585 00586 /* Update the argument string. */ 00587 *arg = args; 00588 00589 return modifiers; 00590 } 00591 00592 /* The "record function-call-history" command. */ 00593 00594 static void 00595 cmd_record_call_history (char *arg, int from_tty) 00596 { 00597 int flags, size; 00598 00599 require_record_target (); 00600 00601 flags = get_call_history_modifiers (&arg); 00602 00603 size = command_size_to_target_size (record_call_history_size); 00604 00605 if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) 00606 target_call_history (size, flags); 00607 else if (strcmp (arg, "-") == 0) 00608 target_call_history (-size, flags); 00609 else 00610 { 00611 ULONGEST begin, end; 00612 00613 begin = get_insn_number (&arg); 00614 00615 if (*arg == ',') 00616 { 00617 arg = skip_spaces (++arg); 00618 00619 if (*arg == '+') 00620 { 00621 arg += 1; 00622 size = get_context_size (&arg); 00623 00624 no_chunk (arg); 00625 00626 target_call_history_from (begin, size, flags); 00627 } 00628 else if (*arg == '-') 00629 { 00630 arg += 1; 00631 size = get_context_size (&arg); 00632 00633 no_chunk (arg); 00634 00635 target_call_history_from (begin, -size, flags); 00636 } 00637 else 00638 { 00639 end = get_insn_number (&arg); 00640 00641 no_chunk (arg); 00642 00643 target_call_history_range (begin, end, flags); 00644 } 00645 } 00646 else 00647 { 00648 no_chunk (arg); 00649 00650 target_call_history_from (begin, size, flags); 00651 } 00652 00653 dont_repeat (); 00654 } 00655 } 00656 00657 /* Helper for "set record instruction-history-size" and "set record 00658 function-call-history-size" input validation. COMMAND_VAR is the 00659 variable registered in the command as control variable. *SETTING 00660 is the real setting the command allows changing. */ 00661 00662 static void 00663 validate_history_size (unsigned int *command_var, unsigned int *setting) 00664 { 00665 if (*command_var != UINT_MAX && *command_var > INT_MAX) 00666 { 00667 unsigned int new_value = *command_var; 00668 00669 /* Restore previous value. */ 00670 *command_var = *setting; 00671 error (_("integer %u out of range"), new_value); 00672 } 00673 00674 /* Commit new value. */ 00675 *setting = *command_var; 00676 } 00677 00678 /* Called by do_setshow_command. We only want values in the 00679 [0..INT_MAX] range, while the command's machinery accepts 00680 [0..UINT_MAX]. See command_size_to_target_size. */ 00681 00682 static void 00683 set_record_insn_history_size (char *args, int from_tty, 00684 struct cmd_list_element *c) 00685 { 00686 validate_history_size (&record_insn_history_size_setshow_var, 00687 &record_insn_history_size); 00688 } 00689 00690 /* Called by do_setshow_command. We only want values in the 00691 [0..INT_MAX] range, while the command's machinery accepts 00692 [0..UINT_MAX]. See command_size_to_target_size. */ 00693 00694 static void 00695 set_record_call_history_size (char *args, int from_tty, 00696 struct cmd_list_element *c) 00697 { 00698 validate_history_size (&record_call_history_size_setshow_var, 00699 &record_call_history_size); 00700 } 00701 00702 /* Provide a prototype to silence -Wmissing-prototypes. */ 00703 extern initialize_file_ftype _initialize_record; 00704 00705 void 00706 _initialize_record (void) 00707 { 00708 struct cmd_list_element *c; 00709 00710 add_setshow_zuinteger_cmd ("record", no_class, &record_debug, 00711 _("Set debugging of record/replay feature."), 00712 _("Show debugging of record/replay feature."), 00713 _("When enabled, debugging output for " 00714 "record/replay feature is displayed."), 00715 NULL, show_record_debug, &setdebuglist, 00716 &showdebuglist); 00717 00718 add_setshow_uinteger_cmd ("instruction-history-size", no_class, 00719 &record_insn_history_size_setshow_var, _("\ 00720 Set number of instructions to print in \"record instruction-history\"."), _("\ 00721 Show number of instructions to print in \"record instruction-history\"."), _("\ 00722 A size of \"unlimited\" means unlimited instructions. The default is 10."), 00723 set_record_insn_history_size, NULL, 00724 &set_record_cmdlist, &show_record_cmdlist); 00725 00726 add_setshow_uinteger_cmd ("function-call-history-size", no_class, 00727 &record_call_history_size_setshow_var, _("\ 00728 Set number of function to print in \"record function-call-history\"."), _("\ 00729 Show number of functions to print in \"record function-call-history\"."), _("\ 00730 A size of \"unlimited\" means unlimited lines. The default is 10."), 00731 set_record_call_history_size, NULL, 00732 &set_record_cmdlist, &show_record_cmdlist); 00733 00734 c = add_prefix_cmd ("record", class_obscure, cmd_record_start, 00735 _("Start recording."), 00736 &record_cmdlist, "record ", 0, &cmdlist); 00737 set_cmd_completer (c, filename_completer); 00738 00739 add_com_alias ("rec", "record", class_obscure, 1); 00740 add_prefix_cmd ("record", class_support, set_record_command, 00741 _("Set record options"), &set_record_cmdlist, 00742 "set record ", 0, &setlist); 00743 add_alias_cmd ("rec", "record", class_obscure, 1, &setlist); 00744 add_prefix_cmd ("record", class_support, show_record_command, 00745 _("Show record options"), &show_record_cmdlist, 00746 "show record ", 0, &showlist); 00747 add_alias_cmd ("rec", "record", class_obscure, 1, &showlist); 00748 add_prefix_cmd ("record", class_support, info_record_command, 00749 _("Info record options"), &info_record_cmdlist, 00750 "info record ", 0, &infolist); 00751 add_alias_cmd ("rec", "record", class_obscure, 1, &infolist); 00752 00753 c = add_cmd ("save", class_obscure, cmd_record_save, 00754 _("Save the execution log to a file.\n\ 00755 Argument is optional filename.\n\ 00756 Default filename is 'gdb_record.<process_id>'."), 00757 &record_cmdlist); 00758 set_cmd_completer (c, filename_completer); 00759 00760 add_cmd ("delete", class_obscure, cmd_record_delete, 00761 _("Delete the rest of execution log and start recording it anew."), 00762 &record_cmdlist); 00763 add_alias_cmd ("d", "delete", class_obscure, 1, &record_cmdlist); 00764 add_alias_cmd ("del", "delete", class_obscure, 1, &record_cmdlist); 00765 00766 add_cmd ("stop", class_obscure, cmd_record_stop, 00767 _("Stop the record/replay target."), 00768 &record_cmdlist); 00769 add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist); 00770 00771 add_prefix_cmd ("goto", class_obscure, cmd_record_goto, _("\ 00772 Restore the program to its state at instruction number N.\n\ 00773 Argument is instruction number, as shown by 'info record'."), 00774 &record_goto_cmdlist, "record goto ", 1, &record_cmdlist); 00775 00776 add_cmd ("begin", class_obscure, cmd_record_goto_begin, 00777 _("Go to the beginning of the execution log."), 00778 &record_goto_cmdlist); 00779 add_alias_cmd ("start", "begin", class_obscure, 1, &record_goto_cmdlist); 00780 00781 add_cmd ("end", class_obscure, cmd_record_goto_end, 00782 _("Go to the end of the execution log."), 00783 &record_goto_cmdlist); 00784 00785 add_cmd ("instruction-history", class_obscure, cmd_record_insn_history, _("\ 00786 Print disassembled instructions stored in the execution log.\n\ 00787 With a /m modifier, source lines are included (if available).\n\ 00788 With a /r modifier, raw instructions in hex are included.\n\ 00789 With a /f modifier, function names are omitted.\n\ 00790 With a /p modifier, current position markers are omitted.\n\ 00791 With no argument, disassembles ten more instructions after the previous \ 00792 disassembly.\n\ 00793 \"record instruction-history -\" disassembles ten instructions before a \ 00794 previous disassembly.\n\ 00795 One argument specifies an instruction number as shown by 'info record', and \ 00796 ten instructions are disassembled after that instruction.\n\ 00797 Two arguments with comma between them specify starting and ending instruction \ 00798 numbers to disassemble.\n\ 00799 If the second argument is preceded by '+' or '-', it specifies the distance \ 00800 from the first argument.\n\ 00801 The number of instructions to disassemble can be defined with \"set record \ 00802 instruction-history-size\"."), 00803 &record_cmdlist); 00804 00805 add_cmd ("function-call-history", class_obscure, cmd_record_call_history, _("\ 00806 Prints the execution history at function granularity.\n\ 00807 It prints one line for each sequence of instructions that belong to the same \ 00808 function.\n\ 00809 Without modifiers, it prints the function name.\n\ 00810 With a /l modifier, the source file and line number range is included.\n\ 00811 With a /i modifier, the instruction number range is included.\n\ 00812 With no argument, prints ten more lines after the previous ten-line print.\n\ 00813 \"record function-call-history -\" prints ten lines before a previous ten-line \ 00814 print.\n\ 00815 One argument specifies a function number as shown by 'info record', and \ 00816 ten lines are printed after that function.\n\ 00817 Two arguments with comma between them specify a range of functions to print.\n\ 00818 If the second argument is preceded by '+' or '-', it specifies the distance \ 00819 from the first argument.\n\ 00820 The number of functions to print can be defined with \"set record \ 00821 function-call-history-size\"."), 00822 &record_cmdlist); 00823 00824 /* Sync command control variables. */ 00825 record_insn_history_size_setshow_var = record_insn_history_size; 00826 record_call_history_size_setshow_var = record_call_history_size; 00827 }