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