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 212 mi_parse_free (struct mi_parse *parse) 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 230 mi_parse_cleanup (void *arg) 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) 287 throw_error (UNDEFINED_COMMAND_ERROR, 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 405 mi_parse_print_values (const char *name) 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\""), 419 mi_no_values, mi_all_values, mi_simple_values); 420 } 421