arm, objdump: print obsolote warning when 26-bit set in instructions
[binutils-gdb.git] / gdb / mi / mi-parse.c
blob8804c98d7b4b41371496a74c2b53c09328f5c6c0
1 /* MI Command Set - MI parser.
3 Copyright (C) 2000-2024 Free Software Foundation, Inc.
5 Contributed by Cygnus Solutions (a Red Hat company).
7 This file is part of GDB.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "mi-cmds.h"
23 #include "mi-parse.h"
24 #include "charset.h"
26 #include <ctype.h>
27 #include "cli/cli-utils.h"
28 #include "language.h"
30 static const char mi_no_values[] = "--no-values";
31 static const char mi_simple_values[] = "--simple-values";
32 static const char mi_all_values[] = "--all-values";
34 /* Like parse_escape, but leave the results as a host char, not a
35 target char. */
37 static int
38 mi_parse_escape (const char **string_ptr)
40 int c = *(*string_ptr)++;
42 switch (c)
44 case '\n':
45 return -2;
46 case 0:
47 (*string_ptr)--;
48 return 0;
50 case '0':
51 case '1':
52 case '2':
53 case '3':
54 case '4':
55 case '5':
56 case '6':
57 case '7':
59 int i = fromhex (c);
60 int count = 0;
62 while (++count < 3)
64 c = (**string_ptr);
65 if (isdigit (c) && c != '8' && c != '9')
67 (*string_ptr)++;
68 i *= 8;
69 i += fromhex (c);
71 else
73 break;
76 return i;
79 case 'a':
80 c = '\a';
81 break;
82 case 'b':
83 c = '\b';
84 break;
85 case 'f':
86 c = '\f';
87 break;
88 case 'n':
89 c = '\n';
90 break;
91 case 'r':
92 c = '\r';
93 break;
94 case 't':
95 c = '\t';
96 break;
97 case 'v':
98 c = '\v';
99 break;
101 default:
102 break;
105 return c;
108 void
109 mi_parse::parse_argv ()
111 /* If arguments were already computed (or were supplied at
112 construction), then there's no need to re-compute them. */
113 if (argv != nullptr)
114 return;
116 const char *chp = m_args.c_str ();
117 int argc = 0;
118 char **argv = XNEWVEC (char *, argc + 1);
120 argv[argc] = NULL;
121 while (1)
123 char *arg;
125 /* Skip leading white space. */
126 chp = skip_spaces (chp);
127 /* Three possibilities: EOF, quoted string, or other text. */
128 switch (*chp)
130 case '\0':
131 this->argv = argv;
132 this->argc = argc;
133 return;
134 case '"':
136 /* A quoted string. */
137 int len;
138 const char *start = chp + 1;
140 /* Determine the buffer size. */
141 chp = start;
142 len = 0;
143 while (*chp != '\0' && *chp != '"')
145 if (*chp == '\\')
147 chp++;
148 if (mi_parse_escape (&chp) <= 0)
150 /* Do not allow split lines or "\000". */
151 freeargv (argv);
152 return;
155 else
156 chp++;
157 len++;
159 /* Insist on a closing quote. */
160 if (*chp != '"')
162 freeargv (argv);
163 return;
165 /* Insist on trailing white space. */
166 if (chp[1] != '\0' && !isspace (chp[1]))
168 freeargv (argv);
169 return;
171 /* Create the buffer and copy characters in. */
172 arg = XNEWVEC (char, len + 1);
173 chp = start;
174 len = 0;
175 while (*chp != '\0' && *chp != '"')
177 if (*chp == '\\')
179 chp++;
180 arg[len] = mi_parse_escape (&chp);
182 else
183 arg[len] = *chp++;
184 len++;
186 arg[len] = '\0';
187 chp++; /* That closing quote. */
188 break;
190 default:
192 /* An unquoted string. Accumulate all non-blank
193 characters into a buffer. */
194 int len;
195 const char *start = chp;
197 while (*chp != '\0' && !isspace (*chp))
199 chp++;
201 len = chp - start;
202 arg = XNEWVEC (char, len + 1);
203 strncpy (arg, start, len);
204 arg[len] = '\0';
205 break;
208 /* Append arg to argv. */
209 argv = XRESIZEVEC (char *, argv, argc + 2);
210 argv[argc++] = arg;
211 argv[argc] = NULL;
215 mi_parse::~mi_parse ()
217 freeargv (argv);
220 /* See mi-parse.h. */
222 const char *
223 mi_parse::args ()
225 /* If args were already computed, or if there is no pre-computed
226 argv, just return the args. */
227 if (!m_args.empty () || argv == nullptr)
228 return m_args.c_str ();
230 /* Compute args from argv. */
231 for (int i = 0; i < argc; ++i)
233 if (!m_args.empty ())
234 m_args += " ";
235 m_args += argv[i];
238 return m_args.c_str ();
241 /* See mi-parse.h. */
243 void
244 mi_parse::set_thread_group (const char *arg, char **endp)
246 if (thread_group != -1)
247 error (_("Duplicate '--thread-group' option"));
248 if (*arg != 'i')
249 error (_("Invalid thread group id"));
250 arg += 1;
251 thread_group = strtol (arg, endp, 10);
254 /* See mi-parse.h. */
256 void
257 mi_parse::set_thread (const char *arg, char **endp)
259 if (thread != -1)
260 error (_("Duplicate '--thread' option"));
261 thread = strtol (arg, endp, 10);
264 /* See mi-parse.h. */
266 void
267 mi_parse::set_frame (const char *arg, char **endp)
269 if (frame != -1)
270 error (_("Duplicate '--frame' option"));
271 frame = strtol (arg, endp, 10);
274 /* See mi-parse.h. */
276 void
277 mi_parse::set_language (const char *arg, const char **endp)
279 std::string lang_name = extract_arg (&arg);
281 language = language_enum (lang_name.c_str ());
282 if (language == language_unknown)
283 error (_("Invalid --language argument: %s"), lang_name.c_str ());
285 if (endp != nullptr)
286 *endp = arg;
289 /* See mi-parse.h. */
291 mi_parse::mi_parse (const char *cmd, std::string *token)
293 const char *chp;
295 /* Before starting, skip leading white space. */
296 cmd = skip_spaces (cmd);
298 /* Find/skip any token and then extract it. */
299 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
301 *token = std::string (cmd, chp - cmd);
303 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
304 if (*chp != '-')
306 chp = skip_spaces (chp);
307 this->command = make_unique_xstrdup (chp);
308 this->op = CLI_COMMAND;
310 return;
313 /* Extract the command. */
315 const char *tmp = chp + 1; /* discard ``-'' */
317 for (; *chp && !isspace (*chp); chp++)
319 this->command = make_unique_xstrndup (tmp, chp - tmp);
322 /* Find the command in the MI table. */
323 this->cmd = mi_cmd_lookup (this->command.get ());
324 if (this->cmd == NULL)
325 throw_error (UNDEFINED_COMMAND_ERROR,
326 _("Undefined MI command: %s"), this->command.get ());
328 /* Skip white space following the command. */
329 chp = skip_spaces (chp);
331 /* Parse the --thread and --frame options, if present. At present,
332 some important commands, like '-break-*' are implemented by
333 forwarding to the CLI layer directly. We want to parse --thread
334 and --frame here, so as not to leave those option in the string
335 that will be passed to CLI.
337 Same for the --language option. */
339 for (;;)
341 const char *option;
342 size_t as = sizeof ("--all ") - 1;
343 size_t tgs = sizeof ("--thread-group ") - 1;
344 size_t ts = sizeof ("--thread ") - 1;
345 size_t fs = sizeof ("--frame ") - 1;
346 size_t ls = sizeof ("--language ") - 1;
348 if (strncmp (chp, "--all ", as) == 0)
350 this->all = 1;
351 chp += as;
353 /* See if --all is the last token in the input. */
354 if (strcmp (chp, "--all") == 0)
356 this->all = 1;
357 chp += strlen (chp);
359 if (strncmp (chp, "--thread-group ", tgs) == 0)
361 char *endp;
363 option = "--thread-group";
364 chp += tgs;
365 this->set_thread_group (chp, &endp);
366 chp = endp;
368 else if (strncmp (chp, "--thread ", ts) == 0)
370 char *endp;
372 option = "--thread";
373 chp += ts;
374 this->set_thread (chp, &endp);
375 chp = endp;
377 else if (strncmp (chp, "--frame ", fs) == 0)
379 char *endp;
381 option = "--frame";
382 chp += fs;
383 this->set_frame (chp, &endp);
384 chp = endp;
386 else if (strncmp (chp, "--language ", ls) == 0)
388 option = "--language";
389 chp += ls;
390 this->set_language (chp, &chp);
392 else
393 break;
395 if (*chp != '\0' && !isspace (*chp))
396 error (_("Invalid value for the '%s' option"), option);
397 chp = skip_spaces (chp);
400 /* Save the rest of the arguments for the command. */
401 this->m_args = chp;
403 /* Fully parsed, flag as an MI command. */
404 this->op = MI_COMMAND;
407 /* See mi-parse.h. */
409 mi_parse::mi_parse (gdb::unique_xmalloc_ptr<char> command,
410 std::vector<gdb::unique_xmalloc_ptr<char>> args)
412 this->command = std::move (command);
413 this->token = "";
415 if (this->command.get ()[0] != '-')
416 throw_error (UNDEFINED_COMMAND_ERROR,
417 _("MI command '%s' does not start with '-'"),
418 this->command.get ());
420 /* Find the command in the MI table. */
421 this->cmd = mi_cmd_lookup (this->command.get () + 1);
422 if (this->cmd == NULL)
423 throw_error (UNDEFINED_COMMAND_ERROR,
424 _("Undefined MI command: %s"), this->command.get ());
426 /* This over-allocates slightly, but it seems unimportant. */
427 this->argv = XCNEWVEC (char *, args.size () + 1);
429 for (size_t i = 0; i < args.size (); ++i)
431 const char *chp = args[i].get ();
433 /* See if --all is the last token in the input. */
434 if (strcmp (chp, "--all") == 0)
436 this->all = 1;
438 else if (strcmp (chp, "--thread-group") == 0)
440 ++i;
441 if (i == args.size ())
442 error ("No argument to '--thread-group'");
443 this->set_thread_group (args[i].get (), nullptr);
445 else if (strcmp (chp, "--thread") == 0)
447 ++i;
448 if (i == args.size ())
449 error ("No argument to '--thread'");
450 this->set_thread (args[i].get (), nullptr);
452 else if (strcmp (chp, "--frame") == 0)
454 ++i;
455 if (i == args.size ())
456 error ("No argument to '--frame'");
457 this->set_frame (args[i].get (), nullptr);
459 else if (strcmp (chp, "--language") == 0)
461 ++i;
462 if (i == args.size ())
463 error ("No argument to '--language'");
464 this->set_language (args[i].get (), nullptr);
466 else
467 this->argv[this->argc++] = args[i].release ();
470 /* Fully parsed, flag as an MI command. */
471 this->op = MI_COMMAND;
474 enum print_values
475 mi_parse_print_values (const char *name)
477 if (strcmp (name, "0") == 0
478 || strcmp (name, mi_no_values) == 0)
479 return PRINT_NO_VALUES;
480 else if (strcmp (name, "1") == 0
481 || strcmp (name, mi_all_values) == 0)
482 return PRINT_ALL_VALUES;
483 else if (strcmp (name, "2") == 0
484 || strcmp (name, mi_simple_values) == 0)
485 return PRINT_SIMPLE_VALUES;
486 else
487 error (_("Unknown value for PRINT_VALUES: must be: \
488 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
489 mi_no_values, mi_all_values, mi_simple_values);