GDB (xrefs)
mi-parse.c
Go to the documentation of this file.
1 /* MI Command Set - MI parser.
2 
3  Copyright (C) 2000-2015 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 = xmalloc ((argc + 1) * sizeof (char *));
115 
116  argv[argc] = NULL;
117  while (1)
118  {
119  char *arg;
120 
121  /* Skip leading white space. */
122  chp = skip_spaces_const (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 = xmalloc ((len + 1) * sizeof (char));
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 = xmalloc ((len + 1) * sizeof (char));
199  strncpy (arg, start, len);
200  arg[len] = '\0';
201  break;
202  }
203  }
204  /* Append arg to argv. */
205  argv = xrealloc (argv, (argc + 2) * sizeof (char *));
206  argv[argc++] = arg;
207  argv[argc] = NULL;
208  }
209 }
210 
211 void
213 {
214  if (parse == NULL)
215  return;
216  if (parse->command != NULL)
217  xfree (parse->command);
218  if (parse->token != NULL)
219  xfree (parse->token);
220  if (parse->args != NULL)
221  xfree (parse->args);
222  if (parse->argv != NULL)
223  freeargv (parse->argv);
224  xfree (parse);
225 }
226 
227 /* A cleanup that calls mi_parse_free. */
228 
229 static void
231 {
232  mi_parse_free (arg);
233 }
234 
235 struct mi_parse *
236 mi_parse (const char *cmd, char **token)
237 {
238  const char *chp;
239  struct mi_parse *parse = XNEW (struct mi_parse);
240  struct cleanup *cleanup;
241 
242  memset (parse, 0, sizeof (*parse));
243  parse->all = 0;
244  parse->thread_group = -1;
245  parse->thread = -1;
246  parse->frame = -1;
247  parse->language = language_unknown;
248 
249  cleanup = make_cleanup (mi_parse_cleanup, parse);
250 
251  /* Before starting, skip leading white space. */
252  cmd = skip_spaces_const (cmd);
253 
254  /* Find/skip any token and then extract it. */
255  for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
256  ;
257  *token = xmalloc (chp - cmd + 1);
258  memcpy (*token, cmd, (chp - cmd));
259  (*token)[chp - cmd] = '\0';
260 
261  /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
262  if (*chp != '-')
263  {
264  chp = skip_spaces_const (chp);
265  parse->command = xstrdup (chp);
266  parse->op = CLI_COMMAND;
267 
268  discard_cleanups (cleanup);
269 
270  return parse;
271  }
272 
273  /* Extract the command. */
274  {
275  const char *tmp = chp + 1; /* discard ``-'' */
276 
277  for (; *chp && !isspace (*chp); chp++)
278  ;
279  parse->command = xmalloc (chp - tmp + 1);
280  memcpy (parse->command, tmp, chp - tmp);
281  parse->command[chp - tmp] = '\0';
282  }
283 
284  /* Find the command in the MI table. */
285  parse->cmd = mi_lookup (parse->command);
286  if (parse->cmd == NULL)
288  _("Undefined MI command: %s"), parse->command);
289 
290  /* Skip white space following the command. */
291  chp = skip_spaces_const (chp);
292 
293  /* Parse the --thread and --frame options, if present. At present,
294  some important commands, like '-break-*' are implemented by
295  forwarding to the CLI layer directly. We want to parse --thread
296  and --frame here, so as not to leave those option in the string
297  that will be passed to CLI.
298 
299  Same for the --language option. */
300 
301  for (;;)
302  {
303  const char *option;
304  size_t as = sizeof ("--all ") - 1;
305  size_t tgs = sizeof ("--thread-group ") - 1;
306  size_t ts = sizeof ("--thread ") - 1;
307  size_t fs = sizeof ("--frame ") - 1;
308  size_t ls = sizeof ("--language ") - 1;
309 
310  if (strncmp (chp, "--all ", as) == 0)
311  {
312  parse->all = 1;
313  chp += as;
314  }
315  /* See if --all is the last token in the input. */
316  if (strcmp (chp, "--all") == 0)
317  {
318  parse->all = 1;
319  chp += strlen (chp);
320  }
321  if (strncmp (chp, "--thread-group ", tgs) == 0)
322  {
323  char *endp;
324 
325  option = "--thread-group";
326  if (parse->thread_group != -1)
327  error (_("Duplicate '--thread-group' option"));
328  chp += tgs;
329  if (*chp != 'i')
330  error (_("Invalid thread group id"));
331  chp += 1;
332  parse->thread_group = strtol (chp, &endp, 10);
333  chp = endp;
334  }
335  else if (strncmp (chp, "--thread ", ts) == 0)
336  {
337  char *endp;
338 
339  option = "--thread";
340  if (parse->thread != -1)
341  error (_("Duplicate '--thread' option"));
342  chp += ts;
343  parse->thread = strtol (chp, &endp, 10);
344  chp = endp;
345  }
346  else if (strncmp (chp, "--frame ", fs) == 0)
347  {
348  char *endp;
349 
350  option = "--frame";
351  if (parse->frame != -1)
352  error (_("Duplicate '--frame' option"));
353  chp += fs;
354  parse->frame = strtol (chp, &endp, 10);
355  chp = endp;
356  }
357  else if (strncmp (chp, "--language ", ls) == 0)
358  {
359  char *lang_name;
360  struct cleanup *old_chain;
361 
362  option = "--language";
363  chp += ls;
364  lang_name = extract_arg_const (&chp);
365  old_chain = make_cleanup (xfree, lang_name);
366 
367  parse->language = language_enum (lang_name);
368  if (parse->language == language_unknown
369  || parse->language == language_auto)
370  error (_("Invalid --language argument: %s"), lang_name);
371 
372  do_cleanups (old_chain);
373  }
374  else
375  break;
376 
377  if (*chp != '\0' && !isspace (*chp))
378  error (_("Invalid value for the '%s' option"), option);
379  chp = skip_spaces_const (chp);
380  }
381 
382  /* For new argv commands, attempt to return the parsed argument
383  list. */
384  if (parse->cmd->argv_func != NULL)
385  {
386  mi_parse_argv (chp, parse);
387  if (parse->argv == NULL)
388  error (_("Problem parsing arguments: %s %s"), parse->command, chp);
389  }
390 
391  /* FIXME: DELETE THIS */
392  /* For CLI commands, also return the remainder of the
393  command line as a single string. */
394  if (parse->cmd->cli.cmd != NULL)
395  parse->args = xstrdup (chp);
396 
397  discard_cleanups (cleanup);
398 
399  /* Fully parsed, flag as an MI command. */
400  parse->op = MI_COMMAND;
401  return parse;
402 }
403 
404 enum print_values
406 {
407  if (strcmp (name, "0") == 0
408  || strcmp (name, mi_no_values) == 0)
409  return PRINT_NO_VALUES;
410  else if (strcmp (name, "1") == 0
411  || strcmp (name, mi_all_values) == 0)
412  return PRINT_ALL_VALUES;
413  else if (strcmp (name, "2") == 0
414  || strcmp (name, mi_simple_values) == 0)
415  return PRINT_SIMPLE_VALUES;
416  else
417  error (_("Unknown value for PRINT_VALUES: must be: \
418 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
420 }
enum language language_enum(char *str)
Definition: language.c:457
void xfree(void *)
Definition: common-utils.c:97
static int parse(struct parser_state *ps)
Definition: ada-lang.c:13721
const struct mi_cmd * cmd
Definition: mi-parse.h:44
char ** argv
Definition: mi-parse.h:47
struct mi_cli cli
Definition: mi-cmds.h:142
static void mi_parse_argv(const char *args, struct mi_parse *parse)
Definition: mi-parse.c:110
Definition: c-exp.c:4859
#define _(String)
Definition: gdb_locale.h:40
static const char mi_simple_values[]
Definition: mi-parse.c:32
static void mi_parse_cleanup(void *arg)
Definition: mi-parse.c:230
enum mi_command_type op
Definition: mi-parse.h:41
const char *const name
Definition: aarch64-tdep.c:68
char * command
Definition: mi-parse.h:42
struct mi_parse * mi_parse(const char *cmd, char **token)
Definition: mi-parse.c:236
const char * skip_spaces_const(const char *chp)
Definition: common-utils.c:271
int argc
Definition: mi-parse.h:48
struct cleanup * make_cleanup(make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:117
int host_hex_value(char c)
Definition: charset.c:453
static int mi_parse_escape(const char **string_ptr)
Definition: mi-parse.c:39
void * xmalloc(YYSIZE_T)
struct mi_cmd * mi_lookup(const char *command)
Definition: mi-cmds.c:194
PTR xrealloc(PTR ptr, size_t size)
Definition: common-utils.c:51
char * token
Definition: mi-parse.h:43
int thread_group
Definition: mi-parse.h:50
void discard_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:213
void mi_parse_free(struct mi_parse *parse)
Definition: mi-parse.c:212
int frame
Definition: mi-parse.h:52
mi_cmd_argv_ftype * argv_func
Definition: mi-cmds.h:144
char * extract_arg_const(const char **arg)
Definition: cli-utils.c:239
const char * cmd
Definition: mi-cmds.h:132
enum language language
Definition: mi-parse.h:56
static const char mi_no_values[]
Definition: mi-parse.c:31
void * arg
Definition: cleanups.c:43
int thread
Definition: mi-parse.h:51
static const char mi_all_values[]
Definition: mi-parse.c:33
int all
Definition: mi-parse.h:49
enum print_values mi_parse_print_values(const char *name)
Definition: mi-parse.c:405
void error(const char *fmt,...)
Definition: errors.c:38
print_values
Definition: mi-cmds.h:25
char * args
Definition: mi-parse.h:46
void throw_error(enum errors error, const char *fmt,...)
void do_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:175
const ULONGEST const LONGEST len
Definition: target.h:309