Allow display of negative offsets in print_address_symbolic()
[external/binutils.git] / gdb / maint-test-options.c
1 /* Maintenance commands for testing the options framework.
2
3    Copyright (C) 2019 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 "cli/cli-option.h"
23
24 /* This file defines three "maintenance test-options" subcommands to
25    exercise TAB-completion and option processing:
26
27     (gdb) maint test-options require-delimiter
28     (gdb) maint test-options unknown-is-error
29     (gdb) maint test-options unknown-is-operand
30
31    And a fourth one to help with TAB-completion testing.
32
33     (gdb) maint show test-options-completion-result
34
35    Each of the test-options subcommands exercise
36    gdb::option::process_options with a different enum
37    process_options_mode value.  Examples for commands they model:
38
39    - "print" and "compile print", are like "require-delimiter",
40       because they accept random expressions as argument.
41
42    - "backtrace" and "frame/thread apply" are like
43      "unknown-is-operand", because "-" is a valid command.
44
45    - "compile file" and "compile code" are like "unknown-is-error".
46
47    These commands allow exercising all aspects of option processing
48    without having to pick some existing command.  That should be more
49    stable going forward than relying on an existing user command,
50    since if we picked say "print", that command or its options could
51    change in future, and then we'd be left with having to pick some
52    other command or option to exercise some non-command-specific
53    option processing detail.  Also, actual user commands have side
54    effects that we're not interested in when we're focusing on unit
55    testing the options machinery.  BTW, a maintenance command is used
56    as a sort of unit test driver instead of actual "maint selftest"
57    unit tests, since we need to go all the way via gdb including
58    readline, for proper testing of TAB completion.
59
60    These maintenance commands support options of all the different
61    available kinds of commands (boolean, enum, flag, string, uinteger):
62
63     (gdb) maint test-options require-delimiter -[TAB]
64     -bool      -enum      -flag      -string     -uinteger   -xx1       -xx2
65
66     (gdb) maint test-options require-delimiter -bool o[TAB]
67     off  on
68     (gdb) maint test-options require-delimiter -enum [TAB]
69     xxx  yyy  zzz
70     (gdb) maint test-options require-delimiter -uinteger [TAB]
71     NUMBER     unlimited
72
73    '-xx1' and '-xx2' are flag options too.  They exist in order to
74    test ambiguous option names, like '-xx'.
75
76   Invoking the commands makes them print out the options parsed:
77
78    (gdb) maint test-options unknown-is-error -flag -enum yyy cmdarg
79    -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint 0 -zuint-unl 0 -- cmdarg
80
81    (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg
82    -flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint 0  -zuint-unl 0 -- -flag -enum yyy cmdarg
83    (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg --
84    Unrecognized option at: cmdarg --
85    (gdb) maint test-options require-delimiter -flag -enum yyy -- cmdarg
86    -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint 0 -zuint-unl 0 -- cmdarg
87
88   The "maint show test-options-completion-result" command exists in
89   order to do something similar for completion:
90
91    (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy OPERAND[TAB]
92    (gdb) maint show test-options-completion-result
93    0 OPERAND
94
95    (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy[TAB]
96    (gdb) maint show test-options-completion-result
97    1
98
99    (gdb) maint test-options require-dash -unknown[TAB]
100    (gdb) maint show test-options-completion-result
101    1
102
103   Here, "1" means the completion function processed the whole input
104   line, and that the command shouldn't do anything with the arguments,
105   since there are no operands.  While "0" indicates that there are
106   operands after options.  The text after "0" is the operands.
107
108   This level of detail is particularly important because getting the
109   completion function's entry point to return back to the caller the
110   right pointer into the operand is quite tricky in several
111   scenarios.  */
112
113 /* Enum values for the "maintenance test-options" commands.  */
114 const char test_options_enum_values_xxx[] = "xxx";
115 const char test_options_enum_values_yyy[] = "yyy";
116 const char test_options_enum_values_zzz[] = "zzz";
117 static const char *const test_options_enum_values_choices[] =
118 {
119   test_options_enum_values_xxx,
120   test_options_enum_values_yyy,
121   test_options_enum_values_zzz,
122   NULL
123 };
124
125 /* Option data for the "maintenance test-options" commands.  */
126
127 struct test_options_opts
128 {
129   int flag_opt = 0;
130   int xx1_opt = 0;
131   int xx2_opt = 0;
132   int boolean_opt = 0;
133   const char *enum_opt = test_options_enum_values_xxx;
134   unsigned int uint_opt = 0;
135   int zuint_unl_opt = 0;
136   char *string_opt = nullptr;
137
138   test_options_opts () = default;
139
140   DISABLE_COPY_AND_ASSIGN (test_options_opts);
141
142   ~test_options_opts ()
143   {
144     xfree (string_opt);
145   }
146
147   /* Dump the options to FILE.  ARGS is the remainder unprocessed
148      arguments.  */
149   void dump (ui_file *file, const char *args) const
150   {
151     fprintf_unfiltered (file,
152                         _("-flag %d -xx1 %d -xx2 %d -bool %d "
153                           "-enum %s -uint %s -zuint-unl %s -string '%s' -- %s\n"),
154                         flag_opt,
155                         xx1_opt,
156                         xx2_opt,
157                         boolean_opt,
158                         enum_opt,
159                         (uint_opt == UINT_MAX
160                          ? "unlimited"
161                          : pulongest (uint_opt)),
162                         (zuint_unl_opt == -1
163                          ? "unlimited"
164                          : plongest (zuint_unl_opt)),
165                         (string_opt != nullptr
166                          ? string_opt
167                          : ""),
168                         args);
169   }
170 };
171
172 /* Option definitions for the "maintenance test-options" commands.  */
173
174 static const gdb::option::option_def test_options_option_defs[] = {
175
176   /* A flag option.  */
177   gdb::option::flag_option_def<test_options_opts> {
178     "flag",
179     [] (test_options_opts *opts) { return &opts->flag_opt; },
180     N_("A flag option."),
181   },
182
183   /* A couple flags with similar names, for "ambiguous option names"
184      testing.  */
185   gdb::option::flag_option_def<test_options_opts> {
186     "xx1",
187     [] (test_options_opts *opts) { return &opts->xx1_opt; },
188     N_("A flag option."),
189   },
190   gdb::option::flag_option_def<test_options_opts> {
191     "xx2",
192     [] (test_options_opts *opts) { return &opts->xx2_opt; },
193     N_("A flag option."),
194   },
195
196   /* A boolean option.  */
197   gdb::option::boolean_option_def<test_options_opts> {
198     "bool",
199     [] (test_options_opts *opts) { return &opts->boolean_opt; },
200     nullptr, /* show_cmd_cb */
201     N_("A boolean option."),
202   },
203
204   /* An enum option.  */
205   gdb::option::enum_option_def<test_options_opts> {
206     "enum",
207     test_options_enum_values_choices,
208     [] (test_options_opts *opts) { return &opts->enum_opt; },
209     nullptr, /* show_cmd_cb */
210     N_("An enum option."),
211   },
212
213   /* A uinteger option.  */
214   gdb::option::uinteger_option_def<test_options_opts> {
215     "uinteger",
216     [] (test_options_opts *opts) { return &opts->uint_opt; },
217     nullptr, /* show_cmd_cb */
218     N_("A uinteger option."),
219     nullptr, /* show_doc */
220     N_("A help doc that spawns\nmultiple lines."),
221   },
222
223   /* A zuinteger_unlimited option.  */
224   gdb::option::zuinteger_unlimited_option_def<test_options_opts> {
225     "zuinteger-unlimited",
226     [] (test_options_opts *opts) { return &opts->zuint_unl_opt; },
227     nullptr, /* show_cmd_cb */
228     N_("A zuinteger-unlimited option."),
229     nullptr, /* show_doc */
230     nullptr, /* help_doc */
231   },
232
233   /* A string option.  */
234   gdb::option::string_option_def<test_options_opts> {
235     "string",
236     [] (test_options_opts *opts) { return &opts->string_opt; },
237     nullptr, /* show_cmd_cb */
238     N_("A string option."),
239   },
240 };
241
242 /* Create an option_def_group for the test_options_opts options, with
243    OPTS as context.  */
244
245 static inline gdb::option::option_def_group
246 make_test_options_options_def_group (test_options_opts *opts)
247 {
248   return {{test_options_option_defs}, opts};
249 }
250
251 /* Implementation of the "maintenance test-options
252    require-delimiter/unknown-is-error/unknown-is-operand" commands.
253    Each of the commands maps to a different enum process_options_mode
254    enumerator.  The test strategy is simply processing the options in
255    a number of scenarios, and printing back the parsed result.  */
256
257 static void
258 maintenance_test_options_command_mode (const char *args,
259                                        gdb::option::process_options_mode mode)
260 {
261   test_options_opts opts;
262
263   gdb::option::process_options (&args, mode,
264                                 make_test_options_options_def_group (&opts));
265
266   if (args == nullptr)
267     args = "";
268   else
269     args = skip_spaces (args);
270
271   opts.dump (gdb_stdout, args);
272 }
273
274 /* Variable used by the "maintenance show
275    test-options-completion-result" command.  This variable is stored
276    by the completer of the "maint test-options" subcommands.
277
278    If the completer returned false, this includes the text at the word
279    point after gdb::option::complete_options returns.  If true, then
280    this includes a dump of the processed options.  */
281 static std::string maintenance_test_options_command_completion_text;
282
283 /* The "maintenance show test-options-completion-result" command.  */
284
285 static void
286 maintenance_show_test_options_completion_result (const char *args,
287                                                  int from_tty)
288 {
289   puts_filtered (maintenance_test_options_command_completion_text.c_str ());
290 }
291
292 /* Save the completion result in the global variables read by the
293    "maintenance test-options require-delimiter" command.  */
294
295 static void
296 save_completion_result (const test_options_opts &opts, bool res,
297                         const char *text)
298 {
299   if (res)
300     {
301       string_file stream;
302
303       stream.puts ("1 ");
304       opts.dump (&stream, text);
305       maintenance_test_options_command_completion_text
306         = std::move (stream.string ());
307     }
308   else
309     {
310       maintenance_test_options_command_completion_text
311         = string_printf ("0 %s\n", text);
312     }
313 }
314
315 /* Implementation of completer for the "maintenance test-options
316    require-delimiter/unknown-is-error/unknown-is-operand" commands.
317    Each of the commands maps to a different enum process_options_mode
318    enumerator.  */
319
320 static void
321 maintenance_test_options_completer_mode (completion_tracker &tracker,
322                                          const char *text,
323                                          gdb::option::process_options_mode mode)
324 {
325   test_options_opts opts;
326
327   try
328     {
329       bool res = (gdb::option::complete_options
330                   (tracker, &text, mode,
331                    make_test_options_options_def_group (&opts)));
332
333       save_completion_result (opts, res, text);
334     }
335   catch (const gdb_exception_error &ex)
336     {
337       save_completion_result (opts, true, text);
338       throw;
339     }
340 }
341
342 /* Implementation of the "maintenance test-options require-delimiter"
343    command.  */
344
345 static void
346 maintenance_test_options_require_delimiter_command (const char *args,
347                                                     int from_tty)
348 {
349   maintenance_test_options_command_mode
350     (args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
351 }
352
353 /* Implementation of the "maintenance test-options
354    unknown-is-error" command.  */
355
356 static void
357 maintenance_test_options_unknown_is_error_command (const char *args,
358                                                    int from_tty)
359 {
360   maintenance_test_options_command_mode
361     (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
362 }
363
364 /* Implementation of the "maintenance test-options
365    unknown-is-operand" command.  */
366
367 static void
368 maintenance_test_options_unknown_is_operand_command (const char *args,
369                                                      int from_tty)
370 {
371   maintenance_test_options_command_mode
372     (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
373 }
374
375 /* Completer for the "maintenance test-options require-delimiter"
376    command.  */
377
378 static void
379 maintenance_test_options_require_delimiter_command_completer
380   (cmd_list_element *ignore, completion_tracker &tracker,
381    const char *text, const char *word)
382 {
383   maintenance_test_options_completer_mode
384     (tracker, text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
385 }
386
387 /* Completer for the "maintenance test-options unknown-is-error"
388    command.  */
389
390 static void
391 maintenance_test_options_unknown_is_error_command_completer
392   (cmd_list_element *ignore, completion_tracker &tracker,
393    const char *text, const char *word)
394 {
395   maintenance_test_options_completer_mode
396     (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
397 }
398
399 /* Completer for the "maintenance test-options unknown-is-operand"
400    command.  */
401
402 static void
403 maintenance_test_options_unknown_is_operand_command_completer
404   (cmd_list_element *ignore, completion_tracker &tracker,
405    const char *text, const char *word)
406 {
407   maintenance_test_options_completer_mode
408     (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
409 }
410
411 /* Command list for maint test-options.  */
412 struct cmd_list_element *maintenance_test_options_list;
413
414 /* The "maintenance test-options" prefix command.  */
415
416 static void
417 maintenance_test_options_command (const char *arg, int from_tty)
418 {
419   printf_unfiltered
420     (_("\"maintenance test-options\" must be followed "
421        "by the name of a subcommand.\n"));
422   help_list (maintenance_test_options_list, "maintenance test-options ",
423              all_commands, gdb_stdout);
424 }
425
426 \f
427 void
428 _initialize_maint_test_options ()
429 {
430   cmd_list_element *cmd;
431
432   add_prefix_cmd ("test-options", no_class, maintenance_test_options_command,
433                   _("\
434 Generic command for testing the options infrastructure."),
435                   &maintenance_test_options_list,
436                   "maintenance test-options ", 0,
437                   &maintenancelist);
438
439   const auto def_group = make_test_options_options_def_group (nullptr);
440
441   static const std::string help_require_delim_str
442     = gdb::option::build_help (_("\
443 Command used for testing options processing.\n\
444 Usage: maint test-options require-delimiter [[OPTION]... --] [OPERAND]...\n\
445 \n\
446 Options:\n\
447 \n\
448 %OPTIONS%\n\
449 If you specify any command option, you must use a double dash (\"--\")\n\
450 to mark the end of option processing."),
451                                def_group);
452
453   static const std::string help_unknown_is_error_str
454     = gdb::option::build_help (_("\
455 Command used for testing options processing.\n\
456 Usage: maint test-options unknown-is-error [OPTION]... [OPERAND]...\n\
457 \n\
458 Options:\n\
459 \n\
460 %OPTIONS%"),
461                                def_group);
462
463   static const std::string help_unknown_is_operand_str
464     = gdb::option::build_help (_("\
465 Command used for testing options processing.\n\
466 Usage: maint test-options unknown-is-operand [OPTION]... [OPERAND]...\n\
467 \n\
468 Options:\n\
469 \n\
470 %OPTIONS%"),
471                                def_group);
472
473   cmd = add_cmd ("require-delimiter", class_maintenance,
474                  maintenance_test_options_require_delimiter_command,
475                  help_require_delim_str.c_str (),
476                  &maintenance_test_options_list);
477   set_cmd_completer_handle_brkchars
478     (cmd, maintenance_test_options_require_delimiter_command_completer);
479
480   cmd = add_cmd ("unknown-is-error", class_maintenance,
481                  maintenance_test_options_unknown_is_error_command,
482                  help_unknown_is_error_str.c_str (),
483                  &maintenance_test_options_list);
484   set_cmd_completer_handle_brkchars
485     (cmd, maintenance_test_options_unknown_is_error_command_completer);
486
487   cmd = add_cmd ("unknown-is-operand", class_maintenance,
488                  maintenance_test_options_unknown_is_operand_command,
489                  help_unknown_is_operand_str.c_str (),
490                  &maintenance_test_options_list);
491   set_cmd_completer_handle_brkchars
492     (cmd, maintenance_test_options_unknown_is_operand_command_completer);
493
494   add_cmd ("test-options-completion-result", class_maintenance,
495            maintenance_show_test_options_completion_result,
496            _("\
497 Show maintenance test-options completion result.\n\
498 Shows the results of completing\n\
499 \"maint test-options require-delimiter\",\n\
500 \"maint test-options unknown-is-error\", or\n\
501 \"maint test-options unknown-is-operand\"."),
502            &maintenance_show_cmdlist);
503 }