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