• R/O
  • HTTP
  • SSH
  • HTTPS

提交

標籤
無標籤

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

GNU Binutils with patches for OS216


Commit MetaInfo

修訂9bec6088410ea9627f0abbe676716b89c0436eae (tree)
時間2019-06-05 07:30:03
作者Pedro Alves <palves@redh...>
CommiterPedro Alves

Log Message

Make "frame apply" support -OPT options

This adds support for '-'-style options to the "frame apply" family of
commands -- "frame apply COUNT", "frame apply level", "frame apply
all", "faas" and "tfaas".

The -q/-c/-s flags were already supported, -past-main/-past-entry is
new:

~
(gdb) help frame apply all
Apply a command to all frames.

Usage: frame apply all [OPTION]... COMMAND
Prints the frame location information followed by COMMAND output.

By default, an error raised during the execution of COMMAND
aborts "frame apply".

Options:

-q
Disables printing the frame location information.
-c
Print any error raised by COMMAND and continue.
-s
Silently ignore any errors or empty output produced by COMMAND.
-past-main [on|off]
Set whether backtraces should continue past "main".
Normally the caller of "main" is not of interest, so GDB will terminate
the backtrace at "main". Set this if you need to see the rest
of the stack trace.
-past-entry [on|off]
Set whether backtraces should continue past the entry point of a program.
Normally there are no callers beyond the entry point of a program, so GDB
will terminate the backtrace there. Set this if you need to see
the rest of the stack trace.

~

TAB completion of options is now supported. Also, TAB completion of
COMMAND in "frame apply all COMMAND" does the right thing now, making
use of complete_command, added by the previous patch. E.g.:

(gdb) thread apply all -ascending frame apply all -past-main print -[TAB]
-address -elements -pretty -symbol
-array -null-stop -repeats -union
-array-indexes -object -static-members -vtbl
(gdb) thread apply all -ascending frame apply all -past-main print glo[TAB]
global1 global2

The change to tfaas_command is necessary because otherwise you get
this:

(gdb) tfaas --
Unrecognized option at: frame apply all -s --

That's because the above is equivalent to:

(gdb) thread apply all -s frame apply all -s --

and the "--" instructs "thread apply" to consider everything up to
"--" as its command options. And from that view, "frame" is an
invalid option.

The change makes tfaas be equivalent to:

(gdb) thread apply all -s -- frame apply all -s --

gdb/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>

* cli/cli-utils.c (parse_flags_qcs): Use validate_flags_qcs.
(validate_flags_qcs): New.
* cli/cli-utils.h (struct qcs_flags): Change field types to int.
(validate_flags_qcs): Declare.
* stack.c (qcs_flag_option_def, fr_qcs_flags_option_defs): New.
(make_frame_apply_options_def_group): New.
(frame_apply_command_count): Process options with
gdb::option::process_options.
(frame_apply_completer): New.
(frame_apply_level_completer, frame_apply_all_completer)
(frame_apply_completer): New.
(_initialize_stack): Update help of "frame apply", "frame apply
level", "frame apply all" and "faas" to mention supported options
and install command completers.
* stack.h (frame_apply_all_completer): Declare.
* thread.c: Include "stack.h".
(tfaas_command): Add "--".
(_initialize_thread): Update help "tfaas" to mention supported
options and install command completer.

gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>

* gdb.base/options.exp (test-frame-apply): New.
(top level): Test print commands with different "frame apply"
prefixes.

Change Summary

差異

--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -573,8 +573,18 @@ parse_flags_qcs (const char *which_command, const char **str,
573573 gdb_assert_not_reached ("int qcs flag out of bound");
574574 }
575575
576- if (flags->cont && flags->silent)
577- error (_("%s: -c and -s are mutually exclusive"), which_command);
576+ validate_flags_qcs (which_command, flags);
578577
579578 return true;
580579 }
580+
581+/* See documentation in cli-utils.h. */
582+
583+void
584+validate_flags_qcs (const char *which_command, qcs_flags *flags)
585+{
586+ if (flags->cont && flags->silent)
587+ error (_("%s: -c and -s are mutually exclusive"), which_command);
588+}
589+
590+/* See documentation in cli-utils.h. */
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -229,13 +229,14 @@ check_for_argument (char **str, const char *arg)
229229 such that FLAGS [N - 1] is the valid found flag. */
230230 extern int parse_flags (const char **str, const char *flags);
231231
232-/* qcs_flags struct regroups the flags parsed by parse_flags_qcs. */
232+/* qcs_flags struct groups the -q, -c, and -s flags parsed by "thread
233+ apply" and "frame apply" commands */
233234
234235 struct qcs_flags
235236 {
236- bool quiet = false;
237- bool cont = false;
238- bool silent = false;
237+ int quiet = false;
238+ int cont = false;
239+ int silent = false;
239240 };
240241
241242 /* A helper function that uses parse_flags to handle the flags qcs :
@@ -259,4 +260,9 @@ struct qcs_flags
259260 extern bool parse_flags_qcs (const char *which_command, const char **str,
260261 qcs_flags *flags);
261262
263+/* Validate FLAGS. Throws an error if both FLAGS->CONT and
264+ FLAGS->SILENT are true. WHICH_COMMAND is included in the error
265+ message. */
266+extern void validate_flags_qcs (const char *which_command, qcs_flags *flags);
267+
262268 #endif /* CLI_CLI_UTILS_H */
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2823,6 +2823,42 @@ func_command (const char *arg, int from_tty)
28232823 }
28242824 }
28252825
2826+/* The qcs command line flags for the "frame apply" commands. Keep
2827+ this in sync with the "thread apply" commands. */
2828+
2829+using qcs_flag_option_def
2830+ = gdb::option::flag_option_def<qcs_flags>;
2831+
2832+static const gdb::option::option_def fr_qcs_flags_option_defs[] = {
2833+ qcs_flag_option_def {
2834+ "q", [] (qcs_flags *opt) { return &opt->quiet; },
2835+ N_("Disables printing the frame location information."),
2836+ },
2837+
2838+ qcs_flag_option_def {
2839+ "c", [] (qcs_flags *opt) { return &opt->cont; },
2840+ N_("Print any error raised by COMMAND and continue."),
2841+ },
2842+
2843+ qcs_flag_option_def {
2844+ "s", [] (qcs_flags *opt) { return &opt->silent; },
2845+ N_("Silently ignore any errors or empty output produced by COMMAND."),
2846+ },
2847+};
2848+
2849+/* Create an option_def_group array for all the "frame apply" options,
2850+ with FLAGS and SET_BT_OPTS as context. */
2851+
2852+static inline std::array<gdb::option::option_def_group, 2>
2853+make_frame_apply_options_def_group (qcs_flags *flags,
2854+ set_backtrace_options *set_bt_opts)
2855+{
2856+ return {{
2857+ { {fr_qcs_flags_option_defs}, flags },
2858+ { {set_backtrace_option_defs}, set_bt_opts },
2859+ }};
2860+}
2861+
28262862 /* Apply a GDB command to all stack frames, or a set of identified frames,
28272863 or innermost COUNT frames.
28282864 With a negative COUNT, apply command on outermost -COUNT frames.
@@ -2852,10 +2888,13 @@ frame_apply_command_count (const char *which_command,
28522888 struct frame_info *trailing, int count)
28532889 {
28542890 qcs_flags flags;
2855- struct frame_info *fi;
2891+ set_backtrace_options set_bt_opts = user_set_backtrace_options;
28562892
2857- while (cmd != NULL && parse_flags_qcs (which_command, &cmd, &flags))
2858- ;
2893+ auto group = make_frame_apply_options_def_group (&flags, &set_bt_opts);
2894+ gdb::option::process_options
2895+ (&cmd, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group);
2896+
2897+ validate_flags_qcs (which_command, &flags);
28592898
28602899 if (cmd == NULL || *cmd == '\0')
28612900 error (_("Please specify a command to apply on the selected frames"));
@@ -2866,7 +2905,12 @@ frame_apply_command_count (const char *which_command,
28662905 these also. */
28672906 scoped_restore_current_thread restore_thread;
28682907
2869- for (fi = trailing; fi && count--; fi = get_prev_frame (fi))
2908+ /* These options are handled quite deep in the unwind machinery, so
2909+ we get to pass them down by swapping globals. */
2910+ scoped_restore restore_set_backtrace_options
2911+ = make_scoped_restore (&user_set_backtrace_options, set_bt_opts);
2912+
2913+ for (frame_info *fi = trailing; fi && count--; fi = get_prev_frame (fi))
28702914 {
28712915 QUIT;
28722916
@@ -2909,6 +2953,104 @@ frame_apply_command_count (const char *which_command,
29092953 }
29102954 }
29112955
2956+/* Completer for the "frame apply ..." commands. */
2957+
2958+static void
2959+frame_apply_completer (completion_tracker &tracker, const char *text)
2960+{
2961+ const auto group = make_frame_apply_options_def_group (nullptr, nullptr);
2962+ if (gdb::option::complete_options
2963+ (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group))
2964+ return;
2965+
2966+ complete_nested_command_line (tracker, text);
2967+}
2968+
2969+/* Completer for the "frame apply" commands. */
2970+
2971+static void
2972+frame_apply_level_cmd_completer (struct cmd_list_element *ignore,
2973+ completion_tracker &tracker,
2974+ const char *text, const char */*word*/)
2975+{
2976+ /* Do this explicitly because there's an early return below. */
2977+ tracker.set_use_custom_word_point (true);
2978+
2979+ number_or_range_parser levels (text);
2980+
2981+ /* Skip the LEVEL list to find the options and command args. */
2982+ try
2983+ {
2984+ while (!levels.finished ())
2985+ {
2986+ /* Call for effect. */
2987+ levels.get_number ();
2988+
2989+ if (levels.in_range ())
2990+ levels.skip_range ();
2991+ }
2992+ }
2993+ catch (const gdb_exception_error &ex)
2994+ {
2995+ /* get_number throws if it parses a negative number, for
2996+ example. But a seemingly negative number may be the start of
2997+ an option instead. */
2998+ }
2999+
3000+ const char *cmd = levels.cur_tok ();
3001+
3002+ if (cmd == text)
3003+ {
3004+ /* No level list yet. */
3005+ return;
3006+ }
3007+
3008+ /* Check if we're past a valid LEVEL already. */
3009+ if (levels.finished ()
3010+ && cmd > text && !isspace (cmd[-1]))
3011+ return;
3012+
3013+ /* We're past LEVELs, advance word point. */
3014+ tracker.advance_custom_word_point_by (cmd - text);
3015+ text = cmd;
3016+
3017+ frame_apply_completer (tracker, text);
3018+}
3019+
3020+/* Completer for the "frame apply all" command. */
3021+
3022+void
3023+frame_apply_all_cmd_completer (struct cmd_list_element *ignore,
3024+ completion_tracker &tracker,
3025+ const char *text, const char */*word*/)
3026+{
3027+ frame_apply_completer (tracker, text);
3028+}
3029+
3030+/* Completer for the "frame apply COUNT" command. */
3031+
3032+static void
3033+frame_apply_cmd_completer (struct cmd_list_element *ignore,
3034+ completion_tracker &tracker,
3035+ const char *text, const char */*word*/)
3036+{
3037+ const char *cmd = text;
3038+
3039+ int count = get_number_trailer (&cmd, 0);
3040+ if (count == 0)
3041+ return;
3042+
3043+ /* Check if we're past a valid COUNT already. */
3044+ if (cmd > text && !isspace (cmd[-1]))
3045+ return;
3046+
3047+ /* We're past COUNT, advance word point. */
3048+ tracker.advance_custom_word_point_by (cmd - text);
3049+ text = cmd;
3050+
3051+ frame_apply_completer (tracker, text);
3052+}
3053+
29123054 /* Implementation of the "frame apply level" command. */
29133055
29143056 static void
@@ -3095,44 +3237,62 @@ A single numerical argument specifies the frame to select."),
30953237
30963238 add_com_alias ("f", "frame", class_stack, 1);
30973239
3098-#define FRAME_APPLY_FLAGS_HELP "\
3240+#define FRAME_APPLY_OPTION_HELP "\
30993241 Prints the frame location information followed by COMMAND output.\n\
3100-FLAG arguments are -q (quiet), -c (continue), -s (silent).\n\
3101-Flag -q disables printing the frame location information.\n\
3102-By default, if a COMMAND raises an error, frame apply is aborted.\n\
3103-Flag -c indicates to print the error and continue.\n\
3104-Flag -s indicates to silently ignore a COMMAND that raises an error\n\
3105-or produces no output."
3106-
3107- add_prefix_cmd ("apply", class_stack, frame_apply_command,
3108- _("Apply a command to a number of frames.\n\
3109-Usage: frame apply COUNT [FLAG]... COMMAND\n\
3242+\n\
3243+By default, an error raised during the execution of COMMAND\n\
3244+aborts \"frame apply\".\n\
3245+\n\
3246+Options:\n\
3247+%OPTIONS%"
3248+
3249+ const auto frame_apply_opts
3250+ = make_frame_apply_options_def_group (nullptr, nullptr);
3251+
3252+ static std::string frame_apply_cmd_help = gdb::option::build_help (N_("\
3253+Apply a command to a number of frames.\n\
3254+Usage: frame apply COUNT [OPTION]... COMMAND\n\
31103255 With a negative COUNT argument, applies the command on outermost -COUNT frames.\n"
3111-FRAME_APPLY_FLAGS_HELP),
3112- &frame_apply_cmd_list, "frame apply ", 1, &frame_cmd_list);
3256+ FRAME_APPLY_OPTION_HELP),
3257+ frame_apply_opts);
31133258
3114- add_cmd ("all", class_stack, frame_apply_all_command,
3115- _("\
3259+ cmd = add_prefix_cmd ("apply", class_stack, frame_apply_command,
3260+ frame_apply_cmd_help.c_str (),
3261+ &frame_apply_cmd_list, "frame apply ", 1,
3262+ &frame_cmd_list);
3263+ set_cmd_completer_handle_brkchars (cmd, frame_apply_cmd_completer);
3264+
3265+ static std::string frame_apply_all_cmd_help = gdb::option::build_help (N_("\
31163266 Apply a command to all frames.\n\
31173267 \n\
3118-Usage: frame apply all [FLAG]... COMMAND\n"
3119-FRAME_APPLY_FLAGS_HELP),
3120- &frame_apply_cmd_list);
3268+Usage: frame apply all [OPTION]... COMMAND\n"
3269+ FRAME_APPLY_OPTION_HELP),
3270+ frame_apply_opts);
31213271
3122- add_cmd ("level", class_stack, frame_apply_level_command,
3123- _("\
3272+ cmd = add_cmd ("all", class_stack, frame_apply_all_command,
3273+ frame_apply_all_cmd_help.c_str (),
3274+ &frame_apply_cmd_list);
3275+ set_cmd_completer_handle_brkchars (cmd, frame_apply_all_cmd_completer);
3276+
3277+ static std::string frame_apply_level_cmd_help = gdb::option::build_help (N_("\
31243278 Apply a command to a list of frames.\n\
31253279 \n\
3126-Usage: frame apply level LEVEL... [FLAG]... COMMAND\n\
3127-ID is a space-separated list of LEVELs of frames to apply COMMAND on.\n"
3128-FRAME_APPLY_FLAGS_HELP),
3280+Usage: frame apply level LEVEL... [OPTION]... COMMAND\n\
3281+LEVEL is a space-separated list of levels of frames to apply COMMAND on.\n"
3282+ FRAME_APPLY_OPTION_HELP),
3283+ frame_apply_opts);
3284+
3285+ cmd = add_cmd ("level", class_stack, frame_apply_level_command,
3286+ frame_apply_level_cmd_help.c_str (),
31293287 &frame_apply_cmd_list);
3288+ set_cmd_completer_handle_brkchars (cmd, frame_apply_level_cmd_completer);
31303289
3131- add_com ("faas", class_stack, faas_command, _("\
3290+ cmd = add_com ("faas", class_stack, faas_command, _("\
31323291 Apply a command to all frames (ignoring errors and empty output).\n\
3133-Usage: faas COMMAND\n\
3134-shortcut for 'frame apply all -s COMMAND'"));
3135-
3292+Usage: faas [OPTION]... COMMAND\n\
3293+shortcut for 'frame apply all -s [OPTION]... COMMAND'\n\
3294+See \"help frame apply all\" for available options."));
3295+ set_cmd_completer_handle_brkchars (cmd, frame_apply_all_cmd_completer);
31363296
31373297 add_prefix_cmd ("frame", class_stack,
31383298 &frame_cmd.base_command, _("\
--- a/gdb/stack.h
+++ b/gdb/stack.h
@@ -52,4 +52,9 @@ struct symtab* get_last_displayed_symtab (void);
5252 int get_last_displayed_line (void);
5353 symtab_and_line get_last_displayed_sal ();
5454
55+/* Completer for the "frame apply all" command. */
56+void frame_apply_all_cmd_completer (struct cmd_list_element *ignore,
57+ completion_tracker &tracker,
58+ const char *text, const char */*word*/);
59+
5560 #endif /* #ifndef STACK_H */
--- a/gdb/testsuite/gdb.base/options.exp
+++ b/gdb/testsuite/gdb.base/options.exp
@@ -25,6 +25,9 @@
2525 # - print
2626 # - compile print
2727 # - backtrace
28+# - frame apply
29+# - faas
30+# - tfaas
2831
2932 load_lib completion-support.exp
3033
@@ -295,6 +298,79 @@ proc_with_prefix test-backtrace {} {
295298 "backtrace (1 + xxx1"
296299 }
297300
301+# Basic option-machinery + "frame apply" command integration tests.
302+proc_with_prefix test-frame-apply {} {
303+ test_gdb_complete_unique "frame apply all" "frame apply all"
304+
305+ gdb_test "frame apply level 0-" \
306+ "Please specify a command to apply on the selected frames"
307+ test_gdb_complete_none "frame apply level 0-"
308+
309+ foreach cmd {
310+ "frame apply all"
311+ "frame apply 1"
312+ "frame apply level 0"
313+ "faas"
314+ "tfaas"
315+ } {
316+ test_gdb_completion_offers_commands "$cmd "
317+
318+ # tfaas is silent on command error by design. This procedure
319+ # hides that aspect. EXPECTED_RE is only considered when not
320+ # testing with "faas"/"tfaas".
321+ proc test_error_cmd {cmd arg expected_re} {
322+ if {$cmd == "tfaas"} {
323+ gdb_test_no_output "$cmd$arg"
324+ } else {
325+ gdb_test "$cmd$arg" $expected_re
326+ }
327+ }
328+ # Same, but for tests where both "faas" and "tfaas" are
329+ # expected to be silent.
330+ proc test_error_cmd2 {cmd arg expected_re} {
331+ if {$cmd == "tfaas" || $cmd == "faas"} {
332+ gdb_test_no_output "$cmd$arg"
333+ } else {
334+ gdb_test "$cmd$arg" $expected_re
335+ }
336+ }
337+
338+ test_error_cmd $cmd " -" "Ambiguous option at: -"
339+ test_gdb_complete_multiple "$cmd " "-" "" {
340+ "-c"
341+ "-past-entry"
342+ "-past-main"
343+ "-q"
344+ "-s"
345+ }
346+
347+ with_test_prefix "no-trailing-space" {
348+ test_error_cmd $cmd " --" \
349+ "Please specify a command to apply on the selected frames"
350+ test_gdb_complete_unique "$cmd --" "$cmd --"
351+ }
352+
353+ with_test_prefix "trailing-space" {
354+ test_error_cmd $cmd " -- " \
355+ "Please specify a command to apply on the selected frames"
356+ test_gdb_completion_offers_commands "$cmd -- "
357+ }
358+
359+ # '-' is a valid TUI command.
360+ test_error_cmd2 $cmd " -- -" \
361+ "Cannot enable the TUI when output is not a terminal"
362+ test_gdb_complete_unique \
363+ "$cmd -- -" \
364+ "$cmd -- -"
365+
366+ test_error_cmd2 $cmd " -foo" \
367+ "Undefined command: \"-foo\". Try \"help\"\\."
368+ test_gdb_complete_none "$cmd -foo"
369+
370+ test_gdb_completion_offers_commands "$cmd -s "
371+ }
372+}
373+
298374 # Miscellaneous tests.
299375 proc_with_prefix test-misc {variant} {
300376 global all_options
@@ -731,13 +807,28 @@ foreach_with_prefix cmd {
731807 test-enum $cmd
732808 }
733809
734-# Run the print integration tests.
735-test-print ""
810+# Run the print integration tests, both as "standalone", and under
811+# "frame apply". The latter checks that the "frame apply ... COMMAND"
812+# commands recurse the completion machinery for COMMAND completion
813+# correctly.
814+foreach prefix {
815+ ""
816+ "frame apply all "
817+ "frame apply 1 "
818+ "frame apply level 0 "
819+} {
820+ test-print $prefix
821+}
736822
737-# Same for "compile print".
823+# Same for "compile print". Not really a wrapper prefix command like
824+# "frame apply", but similar enough that we test pretty much the same
825+# things.
738826 if ![skip_compile_feature_tests] {
739827 test-print "compile "
740828 }
741829
742830 # Basic "backtrace" integration tests.
743831 test-backtrace
832+
833+# Basic "frame apply" integration tests.
834+test-frame-apply
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -46,6 +46,7 @@
4646 #include <algorithm>
4747 #include "common/gdb_optional.h"
4848 #include "inline-frame.h"
49+#include "stack.h"
4950
5051 /* Definition of struct thread_info exported to gdbthread.h. */
5152
@@ -1653,7 +1654,7 @@ static void
16531654 tfaas_command (const char *cmd, int from_tty)
16541655 {
16551656 std::string expanded
1656- = std::string ("thread apply all -s frame apply all -s ") + cmd;
1657+ = std::string ("thread apply all -s -- frame apply all -s ") + cmd;
16571658 execute_command (expanded.c_str (), from_tty);
16581659 }
16591660
@@ -1938,6 +1939,7 @@ void
19381939 _initialize_thread (void)
19391940 {
19401941 static struct cmd_list_element *thread_apply_list = NULL;
1942+ cmd_list_element *c;
19411943
19421944 add_info ("threads", info_threads_command,
19431945 _("Display currently known threads.\n\
@@ -1983,10 +1985,12 @@ Apply a command to all threads (ignoring errors and empty output).\n\
19831985 Usage: taas COMMAND\n\
19841986 shortcut for 'thread apply all -s COMMAND'"));
19851987
1986- add_com ("tfaas", class_run, tfaas_command, _("\
1988+ c = add_com ("tfaas", class_run, tfaas_command, _("\
19871989 Apply a command to all frames of all threads (ignoring errors and empty output).\n\
1988-Usage: tfaas COMMAND\n\
1989-shortcut for 'thread apply all -s frame apply all -s COMMAND'"));
1990+Usage: tfaas [OPTION]... COMMAND\n\
1991+shortcut for 'thread apply all -s -- frame apply all -s [OPTION]... COMMAND'\n\
1992+See \"help frame apply all\" for available options."));
1993+ set_cmd_completer_handle_brkchars (c, frame_apply_all_cmd_completer);
19901994
19911995 add_cmd ("name", class_run, thread_name_command,
19921996 _("Set the current thread's name.\n\