+/* Read function-call-history modifiers from an argument string. */
+
+static int
+get_call_history_modifiers (char **arg)
+{
+ int modifiers;
+ char *args;
+
+ modifiers = 0;
+ args = *arg;
+
+ if (args == NULL)
+ return modifiers;
+
+ while (*args == '/')
+ {
+ ++args;
+
+ if (*args == '\0')
+ error (_("Missing modifier."));
+
+ for (; *args; ++args)
+ {
+ if (isspace (*args))
+ break;
+
+ if (*args == '/')
+ continue;
+
+ switch (*args)
+ {
+ case 'l':
+ modifiers |= RECORD_PRINT_SRC_LINE;
+ break;
+ case 'i':
+ modifiers |= RECORD_PRINT_INSN_RANGE;
+ break;
+ case 'c':
+ modifiers |= RECORD_PRINT_INDENT_CALLS;
+ break;
+ default:
+ error (_("Invalid modifier: %c."), *args);
+ }
+ }
+
+ args = skip_spaces (args);
+ }
+
+ /* Update the argument string. */
+ *arg = args;
+
+ return modifiers;
+}
+
+/* The "record function-call-history" command. */
+
+static void
+cmd_record_call_history (char *arg, int from_tty)
+{
+ int flags, size;
+
+ require_record_target ();
+
+ flags = get_call_history_modifiers (&arg);
+
+ size = command_size_to_target_size (record_call_history_size);
+
+ if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0)
+ target_call_history (size, flags);
+ else if (strcmp (arg, "-") == 0)
+ target_call_history (-size, flags);
+ else
+ {
+ ULONGEST begin, end;
+
+ begin = get_insn_number (&arg);
+
+ if (*arg == ',')
+ {
+ arg = skip_spaces (++arg);
+
+ if (*arg == '+')
+ {
+ arg += 1;
+ size = get_context_size (&arg);
+
+ no_chunk (arg);
+
+ target_call_history_from (begin, size, flags);
+ }
+ else if (*arg == '-')
+ {
+ arg += 1;
+ size = get_context_size (&arg);
+
+ no_chunk (arg);
+
+ target_call_history_from (begin, -size, flags);
+ }
+ else
+ {
+ end = get_insn_number (&arg);
+
+ no_chunk (arg);
+
+ target_call_history_range (begin, end, flags);
+ }
+ }
+ else
+ {
+ no_chunk (arg);
+
+ target_call_history_from (begin, size, flags);
+ }
+
+ dont_repeat ();
+ }
+}
+
+/* Helper for "set record instruction-history-size" and "set record
+ function-call-history-size" input validation. COMMAND_VAR is the
+ variable registered in the command as control variable. *SETTING
+ is the real setting the command allows changing. */
+
+static void
+validate_history_size (unsigned int *command_var, unsigned int *setting)
+{
+ if (*command_var != UINT_MAX && *command_var > INT_MAX)
+ {
+ unsigned int new_value = *command_var;
+
+ /* Restore previous value. */
+ *command_var = *setting;
+ error (_("integer %u out of range"), new_value);
+ }
+
+ /* Commit new value. */
+ *setting = *command_var;
+}
+
+/* Called by do_setshow_command. We only want values in the
+ [0..INT_MAX] range, while the command's machinery accepts
+ [0..UINT_MAX]. See command_size_to_target_size. */
+
+static void
+set_record_insn_history_size (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ validate_history_size (&record_insn_history_size_setshow_var,
+ &record_insn_history_size);
+}
+
+/* Called by do_setshow_command. We only want values in the
+ [0..INT_MAX] range, while the command's machinery accepts
+ [0..UINT_MAX]. See command_size_to_target_size. */
+
+static void
+set_record_call_history_size (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ validate_history_size (&record_call_history_size_setshow_var,
+ &record_call_history_size);
+}
+