]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/mi/mi-parse.c
gdb, gdbserver, gdbsupport: remove includes of early headers
[thirdparty/binutils-gdb.git] / gdb / mi / mi-parse.c
CommitLineData
fb40c209 1/* MI Command Set - MI parser.
349c5d5f 2
1d506c26 3 Copyright (C) 2000-2024 Free Software Foundation, Inc.
349c5d5f 4
ab91fdd5 5 Contributed by Cygnus Solutions (a Red Hat company).
fb40c209
AC
6
7 This file is part of GDB.
8
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
a9762ec7 11 the Free Software Foundation; either version 3 of the License, or
fb40c209
AC
12 (at your option) any later version.
13
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.
18
19 You should have received a copy of the GNU General Public License
a9762ec7 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
fb40c209 21
fb40c209
AC
22#include "mi-cmds.h"
23#include "mi-parse.h"
f870a310 24#include "charset.h"
fb40c209
AC
25
26#include <ctype.h>
529480d0 27#include "cli/cli-utils.h"
403cb6b1 28#include "language.h"
fb40c209 29
44d100c3
TT
30static const char mi_no_values[] = "--no-values";
31static const char mi_simple_values[] = "--simple-values";
32static const char mi_all_values[] = "--all-values";
87967e27 33
f870a310
TT
34/* Like parse_escape, but leave the results as a host char, not a
35 target char. */
36
37static int
ee047554 38mi_parse_escape (const char **string_ptr)
f870a310
TT
39{
40 int c = *(*string_ptr)++;
102040f0 41
f870a310
TT
42 switch (c)
43 {
44 case '\n':
45 return -2;
46 case 0:
47 (*string_ptr)--;
48 return 0;
49
50 case '0':
51 case '1':
52 case '2':
53 case '3':
54 case '4':
55 case '5':
56 case '6':
57 case '7':
58 {
2b531492 59 int i = fromhex (c);
f870a310 60 int count = 0;
102040f0 61
f870a310
TT
62 while (++count < 3)
63 {
64 c = (**string_ptr);
65 if (isdigit (c) && c != '8' && c != '9')
66 {
67 (*string_ptr)++;
68 i *= 8;
2b531492 69 i += fromhex (c);
f870a310
TT
70 }
71 else
72 {
73 break;
74 }
75 }
76 return i;
77 }
78
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;
100
101 default:
102 break;
103 }
104
105 return c;
106}
107
1f6c8c33 108void
7df1df79 109mi_parse::parse_argv ()
fb40c209 110{
e7a2797e
TT
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;
115
fde3f93a 116 const char *chp = m_args.c_str ();
fb40c209 117 int argc = 0;
8d749320 118 char **argv = XNEWVEC (char *, argc + 1);
102040f0 119
fb40c209
AC
120 argv[argc] = NULL;
121 while (1)
122 {
123 char *arg;
102040f0 124
2b03b41d 125 /* Skip leading white space. */
f1735a53 126 chp = skip_spaces (chp);
fb40c209
AC
127 /* Three possibilities: EOF, quoted string, or other text. */
128 switch (*chp)
129 {
130 case '\0':
7df1df79
TT
131 this->argv = argv;
132 this->argc = argc;
fb40c209
AC
133 return;
134 case '"':
135 {
2b03b41d 136 /* A quoted string. */
fb40c209 137 int len;
ee047554 138 const char *start = chp + 1;
102040f0 139
2b03b41d 140 /* Determine the buffer size. */
fb40c209
AC
141 chp = start;
142 len = 0;
143 while (*chp != '\0' && *chp != '"')
144 {
145 if (*chp == '\\')
146 {
147 chp++;
f870a310 148 if (mi_parse_escape (&chp) <= 0)
fb40c209 149 {
2b03b41d 150 /* Do not allow split lines or "\000". */
fb40c209
AC
151 freeargv (argv);
152 return;
153 }
154 }
155 else
156 chp++;
157 len++;
158 }
2b03b41d 159 /* Insist on a closing quote. */
fb40c209
AC
160 if (*chp != '"')
161 {
162 freeargv (argv);
163 return;
164 }
2b03b41d 165 /* Insist on trailing white space. */
fb40c209
AC
166 if (chp[1] != '\0' && !isspace (chp[1]))
167 {
168 freeargv (argv);
169 return;
170 }
2b03b41d 171 /* Create the buffer and copy characters in. */
224c3ddb 172 arg = XNEWVEC (char, len + 1);
fb40c209
AC
173 chp = start;
174 len = 0;
175 while (*chp != '\0' && *chp != '"')
176 {
177 if (*chp == '\\')
178 {
179 chp++;
f870a310 180 arg[len] = mi_parse_escape (&chp);
fb40c209
AC
181 }
182 else
183 arg[len] = *chp++;
184 len++;
185 }
186 arg[len] = '\0';
2b03b41d 187 chp++; /* That closing quote. */
fb40c209
AC
188 break;
189 }
190 default:
191 {
2b03b41d
SS
192 /* An unquoted string. Accumulate all non-blank
193 characters into a buffer. */
fb40c209 194 int len;
ee047554 195 const char *start = chp;
102040f0 196
fb40c209
AC
197 while (*chp != '\0' && !isspace (*chp))
198 {
199 chp++;
200 }
201 len = chp - start;
224c3ddb 202 arg = XNEWVEC (char, len + 1);
fb40c209
AC
203 strncpy (arg, start, len);
204 arg[len] = '\0';
205 break;
206 }
207 }
2b03b41d 208 /* Append arg to argv. */
224c3ddb 209 argv = XRESIZEVEC (char *, argv, argc + 2);
fb40c209
AC
210 argv[argc++] = arg;
211 argv[argc] = NULL;
212 }
213}
214
4d89769a 215mi_parse::~mi_parse ()
305aeedc 216{
4d89769a 217 freeargv (argv);
305aeedc 218}
fb40c209 219
6b2cb925
TT
220/* See mi-parse.h. */
221
e7a2797e
TT
222const char *
223mi_parse::args ()
224{
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 ();
229
230 /* Compute args from argv. */
231 for (int i = 0; i < argc; ++i)
232 {
233 if (!m_args.empty ())
234 m_args += " ";
235 m_args += argv[i];
236 }
237
238 return m_args.c_str ();
239}
240
241/* See mi-parse.h. */
242
6b2cb925
TT
243void
244mi_parse::set_thread_group (const char *arg, char **endp)
245{
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);
252}
253
254/* See mi-parse.h. */
255
256void
257mi_parse::set_thread (const char *arg, char **endp)
258{
259 if (thread != -1)
260 error (_("Duplicate '--thread' option"));
261 thread = strtol (arg, endp, 10);
262}
263
264/* See mi-parse.h. */
265
266void
267mi_parse::set_frame (const char *arg, char **endp)
268{
269 if (frame != -1)
270 error (_("Duplicate '--frame' option"));
271 frame = strtol (arg, endp, 10);
272}
273
274/* See mi-parse.h. */
275
276void
277mi_parse::set_language (const char *arg, const char **endp)
278{
279 std::string lang_name = extract_arg (&arg);
280
281 language = language_enum (lang_name.c_str ());
282 if (language == language_unknown)
283 error (_("Invalid --language argument: %s"), lang_name.c_str ());
284
285 if (endp != nullptr)
286 *endp = arg;
287}
288
951dbdfe
AB
289/* See mi-parse.h. */
290
291mi_parse::mi_parse (const char *cmd, std::string *token)
fb40c209 292{
ee047554 293 const char *chp;
102040f0 294
2b03b41d 295 /* Before starting, skip leading white space. */
f1735a53 296 cmd = skip_spaces (cmd);
fb40c209 297
2b03b41d 298 /* Find/skip any token and then extract it. */
fb40c209
AC
299 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
300 ;
550194db 301 *token = std::string (cmd, chp - cmd);
fb40c209 302
2b03b41d 303 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
fb40c209
AC
304 if (*chp != '-')
305 {
f1735a53 306 chp = skip_spaces (chp);
951dbdfe
AB
307 this->command = make_unique_xstrdup (chp);
308 this->op = CLI_COMMAND;
305aeedc 309
951dbdfe 310 return;
fb40c209
AC
311 }
312
2b03b41d 313 /* Extract the command. */
fb40c209 314 {
ee047554 315 const char *tmp = chp + 1; /* discard ``-'' */
102040f0 316
fb40c209
AC
317 for (; *chp && !isspace (*chp); chp++)
318 ;
951dbdfe 319 this->command = make_unique_xstrndup (tmp, chp - tmp);
fb40c209
AC
320 }
321
2b03b41d 322 /* Find the command in the MI table. */
951dbdfe
AB
323 this->cmd = mi_cmd_lookup (this->command.get ());
324 if (this->cmd == NULL)
2ea126fa 325 throw_error (UNDEFINED_COMMAND_ERROR,
951dbdfe 326 _("Undefined MI command: %s"), this->command.get ());
fb40c209 327
2b03b41d 328 /* Skip white space following the command. */
f1735a53 329 chp = skip_spaces (chp);
fb40c209 330
1e92afda 331 /* Parse the --thread and --frame options, if present. At present,
2b03b41d
SS
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
403cb6b1
JB
335 that will be passed to CLI.
336
337 Same for the --language option. */
338
1e92afda
VP
339 for (;;)
340 {
30a7f059 341 const char *option;
a79b8f6e
VP
342 size_t as = sizeof ("--all ") - 1;
343 size_t tgs = sizeof ("--thread-group ") - 1;
1e92afda
VP
344 size_t ts = sizeof ("--thread ") - 1;
345 size_t fs = sizeof ("--frame ") - 1;
403cb6b1 346 size_t ls = sizeof ("--language ") - 1;
102040f0 347
a79b8f6e
VP
348 if (strncmp (chp, "--all ", as) == 0)
349 {
951dbdfe 350 this->all = 1;
a79b8f6e
VP
351 chp += as;
352 }
353 /* See if --all is the last token in the input. */
354 if (strcmp (chp, "--all") == 0)
355 {
951dbdfe 356 this->all = 1;
dda83cd7
SM
357 chp += strlen (chp);
358 }
a79b8f6e
VP
359 if (strncmp (chp, "--thread-group ", tgs) == 0)
360 {
ee047554
KS
361 char *endp;
362
30a7f059 363 option = "--thread-group";
a79b8f6e 364 chp += tgs;
951dbdfe 365 this->set_thread_group (chp, &endp);
ee047554 366 chp = endp;
a79b8f6e 367 }
8e0e408a 368 else if (strncmp (chp, "--thread ", ts) == 0)
1e92afda 369 {
ee047554
KS
370 char *endp;
371
30a7f059 372 option = "--thread";
1e92afda 373 chp += ts;
951dbdfe 374 this->set_thread (chp, &endp);
ee047554 375 chp = endp;
1e92afda
VP
376 }
377 else if (strncmp (chp, "--frame ", fs) == 0)
378 {
ee047554
KS
379 char *endp;
380
30a7f059 381 option = "--frame";
1e92afda 382 chp += fs;
951dbdfe 383 this->set_frame (chp, &endp);
ee047554 384 chp = endp;
1e92afda 385 }
403cb6b1
JB
386 else if (strncmp (chp, "--language ", ls) == 0)
387 {
403cb6b1
JB
388 option = "--language";
389 chp += ls;
951dbdfe 390 this->set_language (chp, &chp);
403cb6b1 391 }
1e92afda
VP
392 else
393 break;
394
395 if (*chp != '\0' && !isspace (*chp))
30a7f059 396 error (_("Invalid value for the '%s' option"), option);
f1735a53 397 chp = skip_spaces (chp);
1e92afda
VP
398 }
399
1f6c8c33 400 /* Save the rest of the arguments for the command. */
951dbdfe 401 this->m_args = chp;
fb40c209 402
2b03b41d 403 /* Fully parsed, flag as an MI command. */
951dbdfe 404 this->op = MI_COMMAND;
fb40c209 405}
87967e27 406
e7a2797e
TT
407/* See mi-parse.h. */
408
951dbdfe
AB
409mi_parse::mi_parse (gdb::unique_xmalloc_ptr<char> command,
410 std::vector<gdb::unique_xmalloc_ptr<char>> args)
e7a2797e 411{
951dbdfe
AB
412 this->command = std::move (command);
413 this->token = "";
e7a2797e 414
951dbdfe 415 if (this->command.get ()[0] != '-')
e7a2797e
TT
416 throw_error (UNDEFINED_COMMAND_ERROR,
417 _("MI command '%s' does not start with '-'"),
951dbdfe 418 this->command.get ());
e7a2797e
TT
419
420 /* Find the command in the MI table. */
951dbdfe
AB
421 this->cmd = mi_cmd_lookup (this->command.get () + 1);
422 if (this->cmd == NULL)
e7a2797e 423 throw_error (UNDEFINED_COMMAND_ERROR,
951dbdfe 424 _("Undefined MI command: %s"), this->command.get ());
e7a2797e
TT
425
426 /* This over-allocates slightly, but it seems unimportant. */
951dbdfe 427 this->argv = XCNEWVEC (char *, args.size () + 1);
e7a2797e
TT
428
429 for (size_t i = 0; i < args.size (); ++i)
430 {
431 const char *chp = args[i].get ();
432
433 /* See if --all is the last token in the input. */
434 if (strcmp (chp, "--all") == 0)
435 {
951dbdfe 436 this->all = 1;
e7a2797e
TT
437 }
438 else if (strcmp (chp, "--thread-group") == 0)
439 {
440 ++i;
441 if (i == args.size ())
442 error ("No argument to '--thread-group'");
951dbdfe 443 this->set_thread_group (args[i].get (), nullptr);
e7a2797e
TT
444 }
445 else if (strcmp (chp, "--thread") == 0)
446 {
447 ++i;
448 if (i == args.size ())
449 error ("No argument to '--thread'");
951dbdfe 450 this->set_thread (args[i].get (), nullptr);
e7a2797e
TT
451 }
452 else if (strcmp (chp, "--frame") == 0)
453 {
454 ++i;
455 if (i == args.size ())
456 error ("No argument to '--frame'");
951dbdfe 457 this->set_frame (args[i].get (), nullptr);
e7a2797e
TT
458 }
459 else if (strcmp (chp, "--language") == 0)
460 {
461 ++i;
462 if (i == args.size ())
463 error ("No argument to '--language'");
951dbdfe 464 this->set_language (args[i].get (), nullptr);
e7a2797e
TT
465 }
466 else
951dbdfe 467 this->argv[this->argc++] = args[i].release ();
e7a2797e
TT
468 }
469
470 /* Fully parsed, flag as an MI command. */
951dbdfe 471 this->op = MI_COMMAND;
e7a2797e
TT
472}
473
87967e27
YQ
474enum print_values
475mi_parse_print_values (const char *name)
476{
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: \
4880 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
489 mi_no_values, mi_all_values, mi_simple_values);
490}