GDB (API)
|
00001 /* MI Command Set - MI parser. 00002 00003 Copyright (C) 2000-2013 Free Software Foundation, Inc. 00004 00005 Contributed by Cygnus Solutions (a Red Hat company). 00006 00007 This file is part of GDB. 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 3 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00021 00022 #include "defs.h" 00023 #include "mi-cmds.h" 00024 #include "mi-parse.h" 00025 #include "charset.h" 00026 00027 #include <ctype.h> 00028 #include "gdb_string.h" 00029 #include "cli/cli-utils.h" 00030 00031 static const char mi_no_values[] = "--no-values"; 00032 static const char mi_simple_values[] = "--simple-values"; 00033 static const char mi_all_values[] = "--all-values"; 00034 00035 /* Like parse_escape, but leave the results as a host char, not a 00036 target char. */ 00037 00038 static int 00039 mi_parse_escape (const char **string_ptr) 00040 { 00041 int c = *(*string_ptr)++; 00042 00043 switch (c) 00044 { 00045 case '\n': 00046 return -2; 00047 case 0: 00048 (*string_ptr)--; 00049 return 0; 00050 00051 case '0': 00052 case '1': 00053 case '2': 00054 case '3': 00055 case '4': 00056 case '5': 00057 case '6': 00058 case '7': 00059 { 00060 int i = host_hex_value (c); 00061 int count = 0; 00062 00063 while (++count < 3) 00064 { 00065 c = (**string_ptr); 00066 if (isdigit (c) && c != '8' && c != '9') 00067 { 00068 (*string_ptr)++; 00069 i *= 8; 00070 i += host_hex_value (c); 00071 } 00072 else 00073 { 00074 break; 00075 } 00076 } 00077 return i; 00078 } 00079 00080 case 'a': 00081 c = '\a'; 00082 break; 00083 case 'b': 00084 c = '\b'; 00085 break; 00086 case 'f': 00087 c = '\f'; 00088 break; 00089 case 'n': 00090 c = '\n'; 00091 break; 00092 case 'r': 00093 c = '\r'; 00094 break; 00095 case 't': 00096 c = '\t'; 00097 break; 00098 case 'v': 00099 c = '\v'; 00100 break; 00101 00102 default: 00103 break; 00104 } 00105 00106 return c; 00107 } 00108 00109 static void 00110 mi_parse_argv (const char *args, struct mi_parse *parse) 00111 { 00112 const char *chp = args; 00113 int argc = 0; 00114 char **argv = xmalloc ((argc + 1) * sizeof (char *)); 00115 00116 argv[argc] = NULL; 00117 while (1) 00118 { 00119 char *arg; 00120 00121 /* Skip leading white space. */ 00122 chp = skip_spaces_const (chp); 00123 /* Three possibilities: EOF, quoted string, or other text. */ 00124 switch (*chp) 00125 { 00126 case '\0': 00127 parse->argv = argv; 00128 parse->argc = argc; 00129 return; 00130 case '"': 00131 { 00132 /* A quoted string. */ 00133 int len; 00134 const char *start = chp + 1; 00135 00136 /* Determine the buffer size. */ 00137 chp = start; 00138 len = 0; 00139 while (*chp != '\0' && *chp != '"') 00140 { 00141 if (*chp == '\\') 00142 { 00143 chp++; 00144 if (mi_parse_escape (&chp) <= 0) 00145 { 00146 /* Do not allow split lines or "\000". */ 00147 freeargv (argv); 00148 return; 00149 } 00150 } 00151 else 00152 chp++; 00153 len++; 00154 } 00155 /* Insist on a closing quote. */ 00156 if (*chp != '"') 00157 { 00158 freeargv (argv); 00159 return; 00160 } 00161 /* Insist on trailing white space. */ 00162 if (chp[1] != '\0' && !isspace (chp[1])) 00163 { 00164 freeargv (argv); 00165 return; 00166 } 00167 /* Create the buffer and copy characters in. */ 00168 arg = xmalloc ((len + 1) * sizeof (char)); 00169 chp = start; 00170 len = 0; 00171 while (*chp != '\0' && *chp != '"') 00172 { 00173 if (*chp == '\\') 00174 { 00175 chp++; 00176 arg[len] = mi_parse_escape (&chp); 00177 } 00178 else 00179 arg[len] = *chp++; 00180 len++; 00181 } 00182 arg[len] = '\0'; 00183 chp++; /* That closing quote. */ 00184 break; 00185 } 00186 default: 00187 { 00188 /* An unquoted string. Accumulate all non-blank 00189 characters into a buffer. */ 00190 int len; 00191 const char *start = chp; 00192 00193 while (*chp != '\0' && !isspace (*chp)) 00194 { 00195 chp++; 00196 } 00197 len = chp - start; 00198 arg = xmalloc ((len + 1) * sizeof (char)); 00199 strncpy (arg, start, len); 00200 arg[len] = '\0'; 00201 break; 00202 } 00203 } 00204 /* Append arg to argv. */ 00205 argv = xrealloc (argv, (argc + 2) * sizeof (char *)); 00206 argv[argc++] = arg; 00207 argv[argc] = NULL; 00208 } 00209 } 00210 00211 void 00212 mi_parse_free (struct mi_parse *parse) 00213 { 00214 if (parse == NULL) 00215 return; 00216 if (parse->command != NULL) 00217 xfree (parse->command); 00218 if (parse->token != NULL) 00219 xfree (parse->token); 00220 if (parse->args != NULL) 00221 xfree (parse->args); 00222 if (parse->argv != NULL) 00223 freeargv (parse->argv); 00224 xfree (parse); 00225 } 00226 00227 /* A cleanup that calls mi_parse_free. */ 00228 00229 static void 00230 mi_parse_cleanup (void *arg) 00231 { 00232 mi_parse_free (arg); 00233 } 00234 00235 struct mi_parse * 00236 mi_parse (const char *cmd, char **token) 00237 { 00238 const char *chp; 00239 struct mi_parse *parse = XMALLOC (struct mi_parse); 00240 struct cleanup *cleanup; 00241 00242 memset (parse, 0, sizeof (*parse)); 00243 parse->all = 0; 00244 parse->thread_group = -1; 00245 parse->thread = -1; 00246 parse->frame = -1; 00247 00248 cleanup = make_cleanup (mi_parse_cleanup, parse); 00249 00250 /* Before starting, skip leading white space. */ 00251 cmd = skip_spaces_const (cmd); 00252 00253 /* Find/skip any token and then extract it. */ 00254 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++) 00255 ; 00256 *token = xmalloc (chp - cmd + 1); 00257 memcpy (*token, cmd, (chp - cmd)); 00258 (*token)[chp - cmd] = '\0'; 00259 00260 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */ 00261 if (*chp != '-') 00262 { 00263 chp = skip_spaces_const (chp); 00264 parse->command = xstrdup (chp); 00265 parse->op = CLI_COMMAND; 00266 00267 discard_cleanups (cleanup); 00268 00269 return parse; 00270 } 00271 00272 /* Extract the command. */ 00273 { 00274 const char *tmp = chp + 1; /* discard ``-'' */ 00275 00276 for (; *chp && !isspace (*chp); chp++) 00277 ; 00278 parse->command = xmalloc (chp - tmp + 1); 00279 memcpy (parse->command, tmp, chp - tmp); 00280 parse->command[chp - tmp] = '\0'; 00281 } 00282 00283 /* Find the command in the MI table. */ 00284 parse->cmd = mi_lookup (parse->command); 00285 if (parse->cmd == NULL) 00286 error (_("Undefined MI command: %s"), parse->command); 00287 00288 /* Skip white space following the command. */ 00289 chp = skip_spaces_const (chp); 00290 00291 /* Parse the --thread and --frame options, if present. At present, 00292 some important commands, like '-break-*' are implemented by 00293 forwarding to the CLI layer directly. We want to parse --thread 00294 and --frame here, so as not to leave those option in the string 00295 that will be passed to CLI. */ 00296 for (;;) 00297 { 00298 const char *option; 00299 size_t as = sizeof ("--all ") - 1; 00300 size_t tgs = sizeof ("--thread-group ") - 1; 00301 size_t ts = sizeof ("--thread ") - 1; 00302 size_t fs = sizeof ("--frame ") - 1; 00303 00304 if (strncmp (chp, "--all ", as) == 0) 00305 { 00306 parse->all = 1; 00307 chp += as; 00308 } 00309 /* See if --all is the last token in the input. */ 00310 if (strcmp (chp, "--all") == 0) 00311 { 00312 parse->all = 1; 00313 chp += strlen (chp); 00314 } 00315 if (strncmp (chp, "--thread-group ", tgs) == 0) 00316 { 00317 char *endp; 00318 00319 option = "--thread-group"; 00320 if (parse->thread_group != -1) 00321 error (_("Duplicate '--thread-group' option")); 00322 chp += tgs; 00323 if (*chp != 'i') 00324 error (_("Invalid thread group id")); 00325 chp += 1; 00326 parse->thread_group = strtol (chp, &endp, 10); 00327 chp = endp; 00328 } 00329 else if (strncmp (chp, "--thread ", ts) == 0) 00330 { 00331 char *endp; 00332 00333 option = "--thread"; 00334 if (parse->thread != -1) 00335 error (_("Duplicate '--thread' option")); 00336 chp += ts; 00337 parse->thread = strtol (chp, &endp, 10); 00338 chp = endp; 00339 } 00340 else if (strncmp (chp, "--frame ", fs) == 0) 00341 { 00342 char *endp; 00343 00344 option = "--frame"; 00345 if (parse->frame != -1) 00346 error (_("Duplicate '--frame' option")); 00347 chp += fs; 00348 parse->frame = strtol (chp, &endp, 10); 00349 chp = endp; 00350 } 00351 else 00352 break; 00353 00354 if (*chp != '\0' && !isspace (*chp)) 00355 error (_("Invalid value for the '%s' option"), option); 00356 chp = skip_spaces_const (chp); 00357 } 00358 00359 /* For new argv commands, attempt to return the parsed argument 00360 list. */ 00361 if (parse->cmd->argv_func != NULL) 00362 { 00363 mi_parse_argv (chp, parse); 00364 if (parse->argv == NULL) 00365 error (_("Problem parsing arguments: %s %s"), parse->command, chp); 00366 } 00367 00368 /* FIXME: DELETE THIS */ 00369 /* For CLI commands, also return the remainder of the 00370 command line as a single string. */ 00371 if (parse->cmd->cli.cmd != NULL) 00372 parse->args = xstrdup (chp); 00373 00374 discard_cleanups (cleanup); 00375 00376 /* Fully parsed, flag as an MI command. */ 00377 parse->op = MI_COMMAND; 00378 return parse; 00379 } 00380 00381 enum print_values 00382 mi_parse_print_values (const char *name) 00383 { 00384 if (strcmp (name, "0") == 0 00385 || strcmp (name, mi_no_values) == 0) 00386 return PRINT_NO_VALUES; 00387 else if (strcmp (name, "1") == 0 00388 || strcmp (name, mi_all_values) == 0) 00389 return PRINT_ALL_VALUES; 00390 else if (strcmp (name, "2") == 0 00391 || strcmp (name, mi_simple_values) == 0) 00392 return PRINT_SIMPLE_VALUES; 00393 else 00394 error (_("Unknown value for PRINT_VALUES: must be: \ 00395 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""), 00396 mi_no_values, mi_all_values, mi_simple_values); 00397 }