1 /* MI Command Set - MI parser. 2 3 Copyright (C) 2000-2017 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_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 = 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 211 mi_parse::mi_parse () 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), 224 language (language_unknown) 225 { 226 } 227 228 mi_parse::~mi_parse () 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 struct cleanup *cleanup; 241 242 std::unique_ptr<struct mi_parse> parse (new struct mi_parse); 243 244 /* Before starting, skip leading white space. */ 245 cmd = skip_spaces_const (cmd); 246 247 /* Find/skip any token and then extract it. */ 248 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++) 249 ; 250 *token = (char *) xmalloc (chp - cmd + 1); 251 memcpy (*token, cmd, (chp - cmd)); 252 (*token)[chp - cmd] = '\0'; 253 254 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */ 255 if (*chp != '-') 256 { 257 chp = skip_spaces_const (chp); 258 parse->command = xstrdup (chp); 259 parse->op = CLI_COMMAND; 260 261 return parse; 262 } 263 264 /* Extract the command. */ 265 { 266 const char *tmp = chp + 1; /* discard ``-'' */ 267 268 for (; *chp && !isspace (*chp); chp++) 269 ; 270 parse->command = (char *) xmalloc (chp - tmp + 1); 271 memcpy (parse->command, tmp, chp - tmp); 272 parse->command[chp - tmp] = '\0'; 273 } 274 275 /* Find the command in the MI table. */ 276 parse->cmd = mi_lookup (parse->command); 277 if (parse->cmd == NULL) 278 throw_error (UNDEFINED_COMMAND_ERROR, 279 _("Undefined MI command: %s"), parse->command); 280 281 /* Skip white space following the command. */ 282 chp = skip_spaces_const (chp); 283 284 /* Parse the --thread and --frame options, if present. At present, 285 some important commands, like '-break-*' are implemented by 286 forwarding to the CLI layer directly. We want to parse --thread 287 and --frame here, so as not to leave those option in the string 288 that will be passed to CLI. 289 290 Same for the --language option. */ 291 292 for (;;) 293 { 294 const char *option; 295 size_t as = sizeof ("--all ") - 1; 296 size_t tgs = sizeof ("--thread-group ") - 1; 297 size_t ts = sizeof ("--thread ") - 1; 298 size_t fs = sizeof ("--frame ") - 1; 299 size_t ls = sizeof ("--language ") - 1; 300 301 if (strncmp (chp, "--all ", as) == 0) 302 { 303 parse->all = 1; 304 chp += as; 305 } 306 /* See if --all is the last token in the input. */ 307 if (strcmp (chp, "--all") == 0) 308 { 309 parse->all = 1; 310 chp += strlen (chp); 311 } 312 if (strncmp (chp, "--thread-group ", tgs) == 0) 313 { 314 char *endp; 315 316 option = "--thread-group"; 317 if (parse->thread_group != -1) 318 error (_("Duplicate '--thread-group' option")); 319 chp += tgs; 320 if (*chp != 'i') 321 error (_("Invalid thread group id")); 322 chp += 1; 323 parse->thread_group = strtol (chp, &endp, 10); 324 chp = endp; 325 } 326 else if (strncmp (chp, "--thread ", ts) == 0) 327 { 328 char *endp; 329 330 option = "--thread"; 331 if (parse->thread != -1) 332 error (_("Duplicate '--thread' option")); 333 chp += ts; 334 parse->thread = strtol (chp, &endp, 10); 335 chp = endp; 336 } 337 else if (strncmp (chp, "--frame ", fs) == 0) 338 { 339 char *endp; 340 341 option = "--frame"; 342 if (parse->frame != -1) 343 error (_("Duplicate '--frame' option")); 344 chp += fs; 345 parse->frame = strtol (chp, &endp, 10); 346 chp = endp; 347 } 348 else if (strncmp (chp, "--language ", ls) == 0) 349 { 350 char *lang_name; 351 struct cleanup *old_chain; 352 353 option = "--language"; 354 chp += ls; 355 lang_name = extract_arg_const (&chp); 356 old_chain = make_cleanup (xfree, lang_name); 357 358 parse->language = language_enum (lang_name); 359 if (parse->language == language_unknown 360 || parse->language == language_auto) 361 error (_("Invalid --language argument: %s"), lang_name); 362 363 do_cleanups (old_chain); 364 } 365 else 366 break; 367 368 if (*chp != '\0' && !isspace (*chp)) 369 error (_("Invalid value for the '%s' option"), option); 370 chp = skip_spaces_const (chp); 371 } 372 373 /* For new argv commands, attempt to return the parsed argument 374 list. */ 375 if (parse->cmd->argv_func != NULL) 376 { 377 mi_parse_argv (chp, parse.get ()); 378 if (parse->argv == NULL) 379 error (_("Problem parsing arguments: %s %s"), parse->command, chp); 380 } 381 382 /* FIXME: DELETE THIS */ 383 /* For CLI commands, also return the remainder of the 384 command line as a single string. */ 385 if (parse->cmd->cli.cmd != NULL) 386 parse->args = xstrdup (chp); 387 388 /* Fully parsed, flag as an MI command. */ 389 parse->op = MI_COMMAND; 390 return parse; 391 } 392 393 enum print_values 394 mi_parse_print_values (const char *name) 395 { 396 if (strcmp (name, "0") == 0 397 || strcmp (name, mi_no_values) == 0) 398 return PRINT_NO_VALUES; 399 else if (strcmp (name, "1") == 0 400 || strcmp (name, mi_all_values) == 0) 401 return PRINT_ALL_VALUES; 402 else if (strcmp (name, "2") == 0 403 || strcmp (name, mi_simple_values) == 0) 404 return PRINT_SIMPLE_VALUES; 405 else 406 error (_("Unknown value for PRINT_VALUES: must be: \ 407 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""), 408 mi_no_values, mi_all_values, mi_simple_values); 409 } 410