GDB (xrefs)
mi-parse.c
Go to the documentation of this file.
1 /* MI Command Set - MI parser.
2 
3  Copyright (C) 2000-2018 Free Software Foundation, Inc.
4 
5  Contributed by Cygnus Solutions (a Red Hat company).
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
11  the Free Software Foundation; either version 3 of the License, or
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
20  along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 
22 #include "defs.h"
23 #include "mi-cmds.h"
24 #include "mi-parse.h"
25 #include "charset.h"
26 
27 #include <ctype.h>
28 #include "cli/cli-utils.h"
29 #include "language.h"
30 
31 static const char mi_no_values[] = "--no-values";
32 static const char mi_simple_values[] = "--simple-values";
33 static const char mi_all_values[] = "--all-values";
34 
35 /* Like parse_escape, but leave the results as a host char, not a
36  target char. */
37 
38 static int
39 mi_parse_escape (const char **string_ptr)
40 {
41  int c = *(*string_ptr)++;
42 
43  switch (c)
44  {
45  case '\n':
46  return -2;
47  case 0:
48  (*string_ptr)--;
49  return 0;
50 
51  case '0':
52  case '1':
53  case '2':
54  case '3':
55  case '4':
56  case '5':
57  case '6':
58  case '7':
59  {
60  int i = host_hex_value (c);
61  int count = 0;
62 
63  while (++count < 3)
64  {
65  c = (**string_ptr);
66  if (isdigit (c) && c != '8' && c != '9')
67  {
68  (*string_ptr)++;
69  i *= 8;
70  i += host_hex_value (c);
71  }
72  else
73  {
74  break;
75  }
76  }
77  return i;
78  }
79 
80  case 'a':
81  c = '\a';
82  break;
83  case 'b':
84  c = '\b';
85  break;
86  case 'f':
87  c = '\f';
88  break;
89  case 'n':
90  c = '\n';
91  break;
92  case 'r':
93  c = '\r';
94  break;
95  case 't':
96  c = '\t';
97  break;
98  case 'v':
99  c = '\v';
100  break;
101 
102  default:
103  break;
104  }
105 
106  return c;
107 }
108 
109 static void
110 mi_parse_argv (const char *args, struct mi_parse *parse)
111 {
112  const char *chp = args;
113  int argc = 0;
114  char **argv = XNEWVEC (char *, argc + 1);
115 
116  argv[argc] = NULL;
117  while (1)
118  {
119  char *arg;
120 
121  /* Skip leading white space. */
122  chp = skip_spaces (chp);
123  /* Three possibilities: EOF, quoted string, or other text. */
124  switch (*chp)
125  {
126  case '\0':
127  parse->argv = argv;
128  parse->argc = argc;
129  return;
130  case '"':
131  {
132  /* A quoted string. */
133  int len;
134  const char *start = chp + 1;
135 
136  /* Determine the buffer size. */
137  chp = start;
138  len = 0;
139  while (*chp != '\0' && *chp != '"')
140  {
141  if (*chp == '\\')
142  {
143  chp++;
144  if (mi_parse_escape (&chp) <= 0)
145  {
146  /* Do not allow split lines or "\000". */
147  freeargv (argv);
148  return;
149  }
150  }
151  else
152  chp++;
153  len++;
154  }
155  /* Insist on a closing quote. */
156  if (*chp != '"')
157  {
158  freeargv (argv);
159  return;
160  }
161  /* Insist on trailing white space. */
162  if (chp[1] != '\0' && !isspace (chp[1]))
163  {
164  freeargv (argv);
165  return;
166  }
167  /* Create the buffer and copy characters in. */
168  arg = XNEWVEC (char, len + 1);
169  chp = start;
170  len = 0;
171  while (*chp != '\0' && *chp != '"')
172  {
173  if (*chp == '\\')
174  {
175  chp++;
176  arg[len] = mi_parse_escape (&chp);
177  }
178  else
179  arg[len] = *chp++;
180  len++;
181  }
182  arg[len] = '\0';
183  chp++; /* That closing quote. */
184  break;
185  }
186  default:
187  {
188  /* An unquoted string. Accumulate all non-blank
189  characters into a buffer. */
190  int len;
191  const char *start = chp;
192 
193  while (*chp != '\0' && !isspace (*chp))
194  {
195  chp++;
196  }
197  len = chp - start;
198  arg = XNEWVEC (char, len + 1);
199  strncpy (arg, start, len);
200  arg[len] = '\0';
201  break;
202  }
203  }
204  /* Append arg to argv. */
205  argv = XRESIZEVEC (char *, argv, argc + 2);
206  argv[argc++] = arg;
207  argv[argc] = NULL;
208  }
209 }
210 
212  : op (MI_COMMAND),
213  command (NULL),
214  token (NULL),
215  cmd (NULL),
216  cmd_start (NULL),
217  args (NULL),
218  argv (NULL),
219  argc (0),
220  all (0),
221  thread_group (-1),
222  thread (-1),
223  frame (-1),
225 {
226 }
227 
229 {
230  xfree (command);
231  xfree (token);
232  xfree (args);
233  freeargv (argv);
234 }
235 
236 std::unique_ptr<struct mi_parse>
237 mi_parse (const char *cmd, char **token)
238 {
239  const char *chp;
240 
241  std::unique_ptr<struct mi_parse> parse (new struct mi_parse);
242 
243  /* Before starting, skip leading white space. */
244  cmd = skip_spaces (cmd);
245 
246  /* Find/skip any token and then extract it. */
247  for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
248  ;
249  *token = (char *) xmalloc (chp - cmd + 1);
250  memcpy (*token, cmd, (chp - cmd));
251  (*token)[chp - cmd] = '\0';
252 
253  /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
254  if (*chp != '-')
255  {
256  chp = skip_spaces (chp);
257  parse->command = xstrdup (chp);
258  parse->op = CLI_COMMAND;
259 
260  return parse;
261  }
262 
263  /* Extract the command. */
264  {
265  const char *tmp = chp + 1; /* discard ``-'' */
266 
267  for (; *chp && !isspace (*chp); chp++)
268  ;
269  parse->command = (char *) xmalloc (chp - tmp + 1);
270  memcpy (parse->command, tmp, chp - tmp);
271  parse->command[chp - tmp] = '\0';
272  }
273 
274  /* Find the command in the MI table. */
275  parse->cmd = mi_lookup (parse->command);
276  if (parse->cmd == NULL)
278  _("Undefined MI command: %s"), parse->command);
279 
280  /* Skip white space following the command. */
281  chp = skip_spaces (chp);
282 
283  /* Parse the --thread and --frame options, if present. At present,
284  some important commands, like '-break-*' are implemented by
285  forwarding to the CLI layer directly. We want to parse --thread
286  and --frame here, so as not to leave those option in the string
287  that will be passed to CLI.
288 
289  Same for the --language option. */
290 
291  for (;;)
292  {
293  const char *option;
294  size_t as = sizeof ("--all ") - 1;
295  size_t tgs = sizeof ("--thread-group ") - 1;
296  size_t ts = sizeof ("--thread ") - 1;
297  size_t fs = sizeof ("--frame ") - 1;
298  size_t ls = sizeof ("--language ") - 1;
299 
300  if (strncmp (chp, "--all ", as) == 0)
301  {
302  parse->all = 1;
303  chp += as;
304  }
305  /* See if --all is the last token in the input. */
306  if (strcmp (chp, "--all") == 0)
307  {
308  parse->all = 1;
309  chp += strlen (chp);
310  }
311  if (strncmp (chp, "--thread-group ", tgs) == 0)
312  {
313  char *endp;
314 
315  option = "--thread-group";
316  if (parse->thread_group != -1)
317  error (_("Duplicate '--thread-group' option"));
318  chp += tgs;
319  if (*chp != 'i')
320  error (_("Invalid thread group id"));
321  chp += 1;
322  parse->thread_group = strtol (chp, &endp, 10);
323  chp = endp;
324  }
325  else if (strncmp (chp, "--thread ", ts) == 0)
326  {
327  char *endp;
328 
329  option = "--thread";
330  if (parse->thread != -1)
331  error (_("Duplicate '--thread' option"));
332  chp += ts;
333  parse->thread = strtol (chp, &endp, 10);
334  chp = endp;
335  }
336  else if (strncmp (chp, "--frame ", fs) == 0)
337  {
338  char *endp;
339 
340  option = "--frame";
341  if (parse->frame != -1)
342  error (_("Duplicate '--frame' option"));
343  chp += fs;
344  parse->frame = strtol (chp, &endp, 10);
345  chp = endp;
346  }
347  else if (strncmp (chp, "--language ", ls) == 0)
348  {
349  option = "--language";
350  chp += ls;
351  std::string lang_name = extract_arg (&chp);
352 
353  parse->language = language_enum (lang_name.c_str ());
354  if (parse->language == language_unknown
355  || parse->language == language_auto)
356  error (_("Invalid --language argument: %s"), lang_name.c_str ());
357  }
358  else
359  break;
360 
361  if (*chp != '\0' && !isspace (*chp))
362  error (_("Invalid value for the '%s' option"), option);
363  chp = skip_spaces (chp);
364  }
365 
366  /* For new argv commands, attempt to return the parsed argument
367  list. */
368  if (parse->cmd->argv_func != NULL)
369  {
370  mi_parse_argv (chp, parse.get ());
371  if (parse->argv == NULL)
372  error (_("Problem parsing arguments: %s %s"), parse->command, chp);
373  }
374 
375  /* FIXME: DELETE THIS */
376  /* For CLI commands, also return the remainder of the
377  command line as a single string. */
378  if (parse->cmd->cli.cmd != NULL)
379  parse->args = xstrdup (chp);
380 
381  /* Fully parsed, flag as an MI command. */
382  parse->op = MI_COMMAND;
383  return parse;
384 }
385 
386 enum print_values
388 {
389  if (strcmp (name, "0") == 0
390  || strcmp (name, mi_no_values) == 0)
391  return PRINT_NO_VALUES;
392  else if (strcmp (name, "1") == 0
393  || strcmp (name, mi_all_values) == 0)
394  return PRINT_ALL_VALUES;
395  else if (strcmp (name, "2") == 0
396  || strcmp (name, mi_simple_values) == 0)
397  return PRINT_SIMPLE_VALUES;
398  else
399  error (_("Unknown value for PRINT_VALUES: must be: \
400 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
402 }
const char * string
Definition: signals.c:50
void xfree(void *)
~mi_parse()
Definition: mi-parse.c:228
static int parse(struct parser_state *ps)
Definition: ada-lang.c:14317
char ** argv
Definition: mi-parse.h:55
std::string extract_arg(const char **arg)
Definition: cli-utils.c:259
static void mi_parse_argv(const char *args, struct mi_parse *parse)
Definition: mi-parse.c:110
enum language language_enum(const char *str)
Definition: language.c:479
Definition: c-exp.c:4864
char * skip_spaces(char *chp)
Definition: common-utils.c:337
#define _(String)
Definition: gdb_locale.h:35
static const char mi_simple_values[]
Definition: mi-parse.c:32
const char *const name
Definition: aarch64-tdep.c:76
char * command
Definition: mi-parse.h:50
std::unique_ptr< struct mi_parse > mi_parse(const char *cmd, char **token)
Definition: mi-parse.c:237
int host_hex_value(char c)
Definition: charset.c:471
mi_parse()
Definition: mi-parse.c:211
static int mi_parse_escape(const char **string_ptr)
Definition: mi-parse.c:39
void * xmalloc(YYSIZE_T)
#define XRESIZEVEC(T, P, N)
Definition: poison.h:169
struct mi_cmd * mi_lookup(const char *command)
Definition: mi-cmds.c:197
#define XNEWVEC(T, N)
Definition: poison.h:145
language
Definition: defs.h:203
argv
Definition: __init__.py:63
static const char mi_no_values[]
Definition: mi-parse.c:31
static const char mi_all_values[]
Definition: mi-parse.c:33
enum print_values mi_parse_print_values(const char *name)
Definition: mi-parse.c:387
void error(const char *fmt,...)
Definition: errors.c:38
print_values
Definition: mi-cmds.h:25
char * args
Definition: mi-parse.h:54
void throw_error(enum errors error, const char *fmt,...)