1 /* Handle set and show GDB commands.
2 
3    Copyright (C) 2000-2024 Free Software Foundation, Inc.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17 
18 #include "readline/tilde.h"
19 #include "value.h"
20 #include <ctype.h>
21 #include "arch-utils.h"
22 #include "observable.h"
23 #include "interps.h"
24 
25 #include "ui-out.h"
26 
27 #include "cli/cli-decode.h"
28 #include "cli/cli-cmds.h"
29 #include "cli/cli-setshow.h"
30 #include "cli/cli-utils.h"
31 
32 /* Return true if the change of command parameter should be notified.  */
33 
34 static bool
notify_command_param_changed_p(bool param_changed,struct cmd_list_element * c)35 notify_command_param_changed_p (bool param_changed, struct cmd_list_element *c)
36 {
37   if (!param_changed)
38     return false;
39 
40   return c->theclass != class_maintenance && c->theclass != class_obscure;
41 }
42 
43 
44 static enum auto_boolean
parse_auto_binary_operation(const char * arg)45 parse_auto_binary_operation (const char *arg)
46 {
47   if (arg != NULL && *arg != '\0')
48     {
49       int length = strlen (arg);
50 
51       while (isspace (arg[length - 1]) && length > 0)
52           length--;
53 
54       /* Note that "o" is ambiguous.  */
55 
56       if ((length == 2 && strncmp (arg, "on", length) == 0)
57             || strncmp (arg, "1", length) == 0
58             || strncmp (arg, "yes", length) == 0
59             || strncmp (arg, "enable", length) == 0)
60           return AUTO_BOOLEAN_TRUE;
61       else if ((length >= 2 && strncmp (arg, "off", length) == 0)
62                  || strncmp (arg, "0", length) == 0
63                  || strncmp (arg, "no", length) == 0
64                  || strncmp (arg, "disable", length) == 0)
65           return AUTO_BOOLEAN_FALSE;
66       else if (strncmp (arg, "auto", length) == 0
67                  || (length > 1 && strncmp (arg, "-1", length) == 0))
68           return AUTO_BOOLEAN_AUTO;
69     }
70   error (_("\"on\", \"off\" or \"auto\" expected."));
71   return AUTO_BOOLEAN_AUTO; /* Pacify GCC.  */
72 }
73 
74 /* See cli-setshow.h.  */
75 
76 int
parse_cli_boolean_value(const char ** arg)77 parse_cli_boolean_value (const char **arg)
78 {
79   const char *p = skip_to_space (*arg);
80   size_t length = p - *arg;
81 
82   /* Note that "o" is ambiguous.  */
83 
84   if ((length == 2 && strncmp (*arg, "on", length) == 0)
85       || strncmp (*arg, "1", length) == 0
86       || strncmp (*arg, "yes", length) == 0
87       || strncmp (*arg, "enable", length) == 0)
88     {
89       *arg = skip_spaces (*arg + length);
90       return 1;
91     }
92   else if ((length >= 2 && strncmp (*arg, "off", length) == 0)
93              || strncmp (*arg, "0", length) == 0
94              || strncmp (*arg, "no", length) == 0
95              || strncmp (*arg, "disable", length) == 0)
96     {
97       *arg = skip_spaces (*arg + length);
98       return 0;
99     }
100   else
101     return -1;
102 }
103 
104 /* See cli-setshow.h.  */
105 
106 int
parse_cli_boolean_value(const char * arg)107 parse_cli_boolean_value (const char *arg)
108 {
109   if (!arg || !*arg)
110     return 1;
111 
112   int b = parse_cli_boolean_value (&arg);
113   if (b >= 0 && *arg != '\0')
114     return -1;
115 
116   return b;
117 }
118 
119 
120 static void
deprecated_show_value_hack(struct ui_file * ignore_file,int ignore_from_tty,struct cmd_list_element * c,const char * value)121 deprecated_show_value_hack (struct ui_file *ignore_file,
122                                   int ignore_from_tty,
123                                   struct cmd_list_element *c,
124                                   const char *value)
125 {
126   /* If there's no command or value, don't try to print it out.  */
127   if (c == NULL || value == NULL)
128     return;
129 
130   /* Print doc minus "Show " at start.  Tell print_doc_line that
131      this is for a 'show value' prefix.  */
132   print_doc_line (gdb_stdout, c->doc + 5, true);
133 
134   gdb_assert (c->var.has_value ());
135 
136   switch (c->var->type ())
137     {
138     case var_string:
139     case var_string_noescape:
140     case var_optional_filename:
141     case var_filename:
142     case var_enum:
143       gdb_printf ((" is \"%s\".\n"), value);
144       break;
145 
146     default:
147       gdb_printf ((" is %s.\n"), value);
148       break;
149     }
150 }
151 
152 /* Returns true and the value in VAL if ARG is an accepted literal.  */
153 
154 static bool
get_literal_val(LONGEST & val,const literal_def * extra_literals,const char ** arg,bool expression)155 get_literal_val (LONGEST &val, const literal_def *extra_literals,
156                      const char **arg, bool expression)
157 {
158   *arg = skip_spaces (*arg);
159 
160   const char *unl_start = *arg;
161 
162   const char *p = skip_to_space (*arg);
163 
164   size_t len = p - *arg;
165 
166   if (len > 0 && extra_literals != nullptr)
167     for (const literal_def *l = extra_literals;
168            l->literal != nullptr;
169            l++)
170       if (strncmp (l->literal, *arg, len) == 0)
171           {
172             *arg += len;
173 
174             /* If parsing an expression (i.e., parsing for a "set" command),
175                anything after the literal is junk.  For options, anything
176                after the literal might be a command argument or another
177                option.  */
178             if (expression)
179               {
180                 const char *after = skip_spaces (*arg);
181                 if (*after != '\0')
182                     error (_("Junk after \"%.*s\": %s"),
183                            (int) len, unl_start, after);
184               }
185 
186             val = l->use;
187             return true;
188           }
189 
190   return false;
191 }
192 
193 /* See cli-setshow.h.  */
194 
195 LONGEST
parse_cli_var_integer(var_types var_type,const literal_def * extra_literals,const char ** arg,bool expression)196 parse_cli_var_integer (var_types var_type, const literal_def *extra_literals,
197                            const char **arg, bool expression)
198 {
199   LONGEST val;
200 
201   if (*arg == nullptr || **arg == '\0')
202     {
203       if (extra_literals == nullptr)
204           error_no_arg (_("integer to set it to"));
205       else
206           {
207             std::string buffer = "";
208             size_t count = 0;
209 
210             for (const literal_def *l = extra_literals;
211                  l->literal != nullptr;
212                  l++, count++)
213               {
214                 if (count != 0)
215                     buffer += ", ";
216                 buffer = buffer + '"' + l->literal + '"';
217               }
218             if (count > 1)
219               error_no_arg
220                 (string_printf (_("integer to set it to, or one of: %s"),
221                                     buffer.c_str ()).c_str ());
222             else
223               error_no_arg
224                 (string_printf (_("integer to set it to, or %s"),
225                                     buffer.c_str ()).c_str ());
226           }
227     }
228 
229   if (!get_literal_val (val, extra_literals, arg, expression))
230     {
231       if (expression)
232           val = parse_and_eval_long (*arg);
233       else
234           val = get_ulongest (arg);
235 
236       enum tribool allowed = TRIBOOL_UNKNOWN;
237       if (extra_literals != nullptr)
238           {
239             for (const literal_def *l = extra_literals;
240                  l->literal != nullptr;
241                  l++)
242               if (l->val.has_value () && val == *l->val)
243                 {
244                     allowed = TRIBOOL_TRUE;
245                     val = l->use;
246                     break;
247                 }
248               else if (val == l->use)
249                 allowed = TRIBOOL_FALSE;
250           }
251 
252       if (allowed == TRIBOOL_UNKNOWN)
253           {
254             if (val > UINT_MAX || val < INT_MIN
255                 || (var_type == var_uinteger && val < 0)
256                 || (var_type == var_integer && val > INT_MAX)
257                 || (var_type == var_pinteger && val < 0)
258                 || (var_type == var_pinteger && val > INT_MAX))
259               allowed = TRIBOOL_FALSE;
260           }
261       if (allowed == TRIBOOL_FALSE)
262           error (_("integer %s out of range"), plongest (val));
263     }
264 
265   return val;
266 }
267 
268 /* See cli-setshow.h.  */
269 
270 const char *
parse_cli_var_enum(const char ** args,const char * const * enums)271 parse_cli_var_enum (const char **args, const char *const *enums)
272 {
273   /* If no argument was supplied, print an informative error
274      message.  */
275   if (args == NULL || *args == NULL || **args == '\0')
276     {
277       std::string msg;
278 
279       for (size_t i = 0; enums[i]; i++)
280           {
281             if (i != 0)
282               msg += ", ";
283             msg += enums[i];
284           }
285       error (_("Requires an argument. Valid arguments are %s."),
286                msg.c_str ());
287     }
288 
289   const char *p = skip_to_space (*args);
290   size_t len = p - *args;
291 
292   int nmatches = 0;
293   const char *match = NULL;
294   for (size_t i = 0; enums[i]; i++)
295     if (strncmp (*args, enums[i], len) == 0)
296       {
297           if (enums[i][len] == '\0')
298             {
299               match = enums[i];
300               nmatches = 1;
301               break; /* Exact match.  */
302             }
303           else
304             {
305               match = enums[i];
306               nmatches++;
307             }
308       }
309 
310   if (nmatches == 0)
311     error (_("Undefined item: \"%.*s\"."), (int) len, *args);
312 
313   if (nmatches > 1)
314     error (_("Ambiguous item \"%.*s\"."), (int) len, *args);
315 
316   *args += len;
317   return match;
318 }
319 
320 /* Do a "set" command.  ARG is NULL if no argument, or the
321    text of the argument, and FROM_TTY is nonzero if this command is
322    being entered directly by the user (i.e. these are just like any
323    other command).  C is the command list element for the command.  */
324 
325 void
do_set_command(const char * arg,int from_tty,struct cmd_list_element * c)326 do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
327 {
328   /* A flag to indicate the option is changed or not.  */
329   bool option_changed = false;
330 
331   gdb_assert (c->type == set_cmd);
332 
333   if (arg == NULL)
334     arg = "";
335 
336   gdb_assert (c->var.has_value ());
337 
338   switch (c->var->type ())
339     {
340     case var_string:
341       {
342           std::string newobj;
343           const char *p;
344           int ch;
345 
346           newobj.reserve (strlen (arg));
347           p = arg;
348           while ((ch = *p++) != '\000')
349             {
350               if (ch == '\\')
351                 {
352                     /* \ at end of argument is used after spaces
353                        so they won't be lost.  */
354                     /* This is obsolete now that we no longer strip
355                        trailing whitespace and actually, the backslash
356                        didn't get here in my test, readline or
357                        something did something funky with a backslash
358                        right before a newline.  */
359                     if (*p == 0)
360                       break;
361                     ch = parse_escape (get_current_arch (), &p);
362                     if (ch == 0)
363                       break;  /* C loses */
364                     else if (ch > 0)
365                       newobj.push_back (ch);
366                 }
367               else
368                 newobj.push_back (ch);
369             }
370           newobj.shrink_to_fit ();
371 
372           option_changed = c->var->set<std::string> (std::move (newobj));
373       }
374       break;
375     case var_string_noescape:
376       option_changed = c->var->set<std::string> (std::string (arg));
377       break;
378     case var_filename:
379       if (*arg == '\0')
380           error_no_arg (_("filename to set it to."));
381       [[fallthrough]];
382     case var_optional_filename:
383       {
384           char *val = NULL;
385 
386           if (*arg != '\0')
387             {
388               /* Clear trailing whitespace of filename.  */
389               const char *ptr = arg + strlen (arg) - 1;
390 
391               while (ptr >= arg && (*ptr == ' ' || *ptr == '\t'))
392                 ptr--;
393               gdb::unique_xmalloc_ptr<char> copy
394                 = make_unique_xstrndup (arg, ptr + 1 - arg);
395 
396               val = tilde_expand (copy.get ());
397             }
398           else
399             val = xstrdup ("");
400 
401           option_changed
402             = c->var->set<std::string> (std::string (val));
403           xfree (val);
404       }
405       break;
406     case var_boolean:
407       {
408           int val = parse_cli_boolean_value (arg);
409 
410           if (val < 0)
411             error (_("\"on\" or \"off\" expected."));
412 
413           option_changed = c->var->set<bool> (val);
414       }
415       break;
416     case var_auto_boolean:
417       option_changed = c->var->set<enum auto_boolean> (parse_auto_binary_operation (arg));
418       break;
419     case var_uinteger:
420       option_changed
421           = c->var->set<unsigned int> (parse_cli_var_integer (c->var->type (),
422                                                                           c->var->
423                                                                           extra_literals (),
424                                                                           &arg, true));
425       break;
426     case var_integer:
427     case var_pinteger:
428       option_changed
429           = c->var->set<int> (parse_cli_var_integer (c->var->type (),
430                                                                c->var->extra_literals (),
431                                                                &arg, true));
432       break;
433     case var_enum:
434       {
435           const char *end_arg = arg;
436           const char *match = parse_cli_var_enum (&end_arg, c->enums);
437 
438           int len = end_arg - arg;
439           const char *after = skip_spaces (end_arg);
440           if (*after != '\0')
441             error (_("Junk after item \"%.*s\": %s"), len, arg, after);
442 
443           option_changed = c->var->set<const char *> (match);
444       }
445       break;
446     default:
447       error (_("gdb internal error: bad var_type in do_setshow_command"));
448     }
449 
450   c->func (NULL, from_tty, c);
451 
452   if (notify_command_param_changed_p (option_changed, c))
453     {
454       char *name, *cp;
455       struct cmd_list_element **cmds;
456       struct cmd_list_element *p;
457       int i;
458       int length = 0;
459 
460       /* Compute the whole multi-word command options.  If user types command
461            'set foo bar baz on', c->name is 'baz', and GDB can't pass "bar" to
462            command option change notification, because it is confusing.  We can
463            trace back through field 'prefix' to compute the whole options,
464            and pass "foo bar baz" to notification.  */
465 
466       for (i = 0, p = c; p != NULL; i++)
467           {
468             length += strlen (p->name);
469             length++;
470 
471             p = p->prefix;
472           }
473       cp = name = (char *) xmalloc (length);
474       cmds = XNEWVEC (struct cmd_list_element *, i);
475 
476       /* Track back through filed 'prefix' and cache them in CMDS.  */
477       for (i = 0, p = c; p != NULL; i++)
478           {
479             cmds[i] = p;
480             p = p->prefix;
481           }
482 
483       /* Don't trigger any observer notification if subcommands is not
484            setlist.  */
485       i--;
486       if (cmds[i]->subcommands != &setlist)
487           {
488             xfree (cmds);
489             xfree (name);
490 
491             return;
492           }
493       /* Traverse them in the reversed order, and copy their names into
494            NAME.  */
495       for (i--; i >= 0; i--)
496           {
497             memcpy (cp, cmds[i]->name, strlen (cmds[i]->name));
498             cp += strlen (cmds[i]->name);
499 
500             if (i != 0)
501               {
502                 cp[0] = ' ';
503                 cp++;
504               }
505           }
506       cp[0] = 0;
507 
508       xfree (cmds);
509 
510       switch (c->var->type ())
511           {
512           case var_string:
513           case var_string_noescape:
514           case var_filename:
515           case var_optional_filename:
516             interps_notify_param_changed
517               (name, c->var->get<std::string> ().c_str ());
518             break;
519           case var_enum:
520             interps_notify_param_changed
521               (name, c->var->get<const char *> ());
522             break;
523           case var_boolean:
524             {
525               const char *opt = c->var->get<bool> () ? "on" : "off";
526 
527               interps_notify_param_changed (name, opt);
528             }
529             break;
530           case var_auto_boolean:
531             {
532               const char *s
533                 = auto_boolean_enums[c->var->get<enum auto_boolean> ()];
534 
535               interps_notify_param_changed (name, s);
536             }
537             break;
538           case var_uinteger:
539             {
540               char s[64];
541 
542               xsnprintf (s, sizeof s, "%u", c->var->get<unsigned int> ());
543               interps_notify_param_changed (name, s);
544             }
545             break;
546           case var_integer:
547           case var_pinteger:
548             {
549               char s[64];
550 
551               xsnprintf (s, sizeof s, "%d", c->var->get<int> ());
552               interps_notify_param_changed (name, s);
553             }
554             break;
555           }
556       xfree (name);
557     }
558 }
559 
560 /* See cli/cli-setshow.h.  */
561 
562 std::string
get_setshow_command_value_string(const setting & var)563 get_setshow_command_value_string (const setting &var)
564 {
565   string_file stb;
566 
567   switch (var.type ())
568     {
569     case var_string:
570       {
571           std::string value = var.get<std::string> ();
572           if (!value.empty ())
573             stb.putstr (value.c_str (), '"');
574       }
575       break;
576     case var_string_noescape:
577     case var_optional_filename:
578     case var_filename:
579       stb.puts (var.get<std::string> ().c_str ());
580       break;
581     case var_enum:
582       {
583           const char *value = var.get<const char *> ();
584           if (value != nullptr)
585             stb.puts (value);
586       }
587       break;
588     case var_boolean:
589       stb.puts (var.get<bool> () ? "on" : "off");
590       break;
591     case var_auto_boolean:
592       switch (var.get<enum auto_boolean> ())
593           {
594           case AUTO_BOOLEAN_TRUE:
595             stb.puts ("on");
596             break;
597           case AUTO_BOOLEAN_FALSE:
598             stb.puts ("off");
599             break;
600           case AUTO_BOOLEAN_AUTO:
601             stb.puts ("auto");
602             break;
603           default:
604             gdb_assert_not_reached ("invalid var_auto_boolean");
605             break;
606           }
607       break;
608     case var_uinteger:
609     case var_integer:
610     case var_pinteger:
611       {
612           bool printed = false;
613           const LONGEST value
614             = (var.type () == var_uinteger
615                ? static_cast<LONGEST> (var.get<unsigned int> ())
616                : static_cast<LONGEST> (var.get<int> ()));
617 
618           if (var.extra_literals () != nullptr)
619             for (const literal_def *l = var.extra_literals ();
620                  l->literal != nullptr;
621                  l++)
622               if (value == l->use)
623                 {
624                     stb.puts (l->literal);
625                     printed = true;
626                     break;
627                 }
628           if (!printed)
629             {
630               if (var.type () == var_uinteger)
631                 stb.printf ("%u", static_cast<unsigned int> (value));
632               else
633                 stb.printf ("%d", static_cast<int> (value));
634             }
635       }
636       break;
637     default:
638       gdb_assert_not_reached ("bad var_type");
639     }
640 
641   return stb.release ();
642 }
643 
644 
645 /* Do a "show" command.  ARG is NULL if no argument, or the
646    text of the argument, and FROM_TTY is nonzero if this command is
647    being entered directly by the user (i.e. these are just like any
648    other command).  C is the command list element for the command.  */
649 
650 void
do_show_command(const char * arg,int from_tty,struct cmd_list_element * c)651 do_show_command (const char *arg, int from_tty, struct cmd_list_element *c)
652 {
653   struct ui_out *uiout = current_uiout;
654 
655   gdb_assert (c->type == show_cmd);
656   gdb_assert (c->var.has_value ());
657 
658   std::string val = get_setshow_command_value_string (*c->var);
659 
660   /* FIXME: cagney/2005-02-10: There should be MI and CLI specific
661      versions of code to print the value out.  */
662 
663   if (uiout->is_mi_like_p ())
664     uiout->field_string ("value", val);
665   else
666     {
667       if (c->show_value_func != NULL)
668           c->show_value_func (gdb_stdout, from_tty, c, val.c_str ());
669       else
670           deprecated_show_value_hack (gdb_stdout, from_tty, c, val.c_str ());
671     }
672 
673   c->func (NULL, from_tty, c);
674 }
675 
676 /* Show all the settings in a list of show commands.  */
677 
678 void
cmd_show_list(struct cmd_list_element * list,int from_tty)679 cmd_show_list (struct cmd_list_element *list, int from_tty)
680 {
681   struct ui_out *uiout = current_uiout;
682 
683   ui_out_emit_tuple tuple_emitter (uiout, "showlist");
684   for (; list != NULL; list = list->next)
685     {
686       /* We skip show command aliases to avoid showing duplicated values.  */
687 
688       /* If we find a prefix, run its list, prefixing our output by its
689            prefix (with "show " skipped).  */
690       if (list->is_prefix () && !list->is_alias ())
691           {
692             ui_out_emit_tuple optionlist_emitter (uiout, "optionlist");
693             std::string prefixname = list->prefixname ();
694             const char *new_prefix = strstr (prefixname.c_str (), "show ") + 5;
695 
696             if (uiout->is_mi_like_p ())
697               uiout->field_string ("prefix", new_prefix);
698             cmd_show_list (*list->subcommands, from_tty);
699           }
700       else if (list->theclass != no_set_class && !list->is_alias ())
701           {
702             ui_out_emit_tuple option_emitter (uiout, "option");
703 
704             if (list->prefix != nullptr)
705               {
706                 /* If we find a prefix, output it (with "show " skipped).  */
707                 std::string prefixname = list->prefix->prefixname ();
708                 prefixname = (!list->prefix->is_prefix () ? ""
709                                   : strstr (prefixname.c_str (), "show ") + 5);
710                 uiout->text (prefixname);
711               }
712             uiout->field_string ("name", list->name);
713             uiout->text (":  ");
714             if (list->type == show_cmd)
715               do_show_command (NULL, from_tty, list);
716             else
717               cmd_func (list, NULL, from_tty);
718           }
719     }
720 }
721 
722 
723