mi-parse.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /* MI Command Set - MI parser.
  2. Copyright (C) 2000-2022 Free Software Foundation, Inc.
  3. Contributed by Cygnus Solutions (a Red Hat company).
  4. This file is part of GDB.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. #include "defs.h"
  16. #include "mi-cmds.h"
  17. #include "mi-parse.h"
  18. #include "charset.h"
  19. #include <ctype.h>
  20. #include "cli/cli-utils.h"
  21. #include "language.h"
  22. static const char mi_no_values[] = "--no-values";
  23. static const char mi_simple_values[] = "--simple-values";
  24. static const char mi_all_values[] = "--all-values";
  25. /* Like parse_escape, but leave the results as a host char, not a
  26. target char. */
  27. static int
  28. mi_parse_escape (const char **string_ptr)
  29. {
  30. int c = *(*string_ptr)++;
  31. switch (c)
  32. {
  33. case '\n':
  34. return -2;
  35. case 0:
  36. (*string_ptr)--;
  37. return 0;
  38. case '0':
  39. case '1':
  40. case '2':
  41. case '3':
  42. case '4':
  43. case '5':
  44. case '6':
  45. case '7':
  46. {
  47. int i = fromhex (c);
  48. int count = 0;
  49. while (++count < 3)
  50. {
  51. c = (**string_ptr);
  52. if (isdigit (c) && c != '8' && c != '9')
  53. {
  54. (*string_ptr)++;
  55. i *= 8;
  56. i += fromhex (c);
  57. }
  58. else
  59. {
  60. break;
  61. }
  62. }
  63. return i;
  64. }
  65. case 'a':
  66. c = '\a';
  67. break;
  68. case 'b':
  69. c = '\b';
  70. break;
  71. case 'f':
  72. c = '\f';
  73. break;
  74. case 'n':
  75. c = '\n';
  76. break;
  77. case 'r':
  78. c = '\r';
  79. break;
  80. case 't':
  81. c = '\t';
  82. break;
  83. case 'v':
  84. c = '\v';
  85. break;
  86. default:
  87. break;
  88. }
  89. return c;
  90. }
  91. void
  92. mi_parse_argv (const char *args, struct mi_parse *parse)
  93. {
  94. const char *chp = args;
  95. int argc = 0;
  96. char **argv = XNEWVEC (char *, argc + 1);
  97. argv[argc] = NULL;
  98. while (1)
  99. {
  100. char *arg;
  101. /* Skip leading white space. */
  102. chp = skip_spaces (chp);
  103. /* Three possibilities: EOF, quoted string, or other text. */
  104. switch (*chp)
  105. {
  106. case '\0':
  107. parse->argv = argv;
  108. parse->argc = argc;
  109. return;
  110. case '"':
  111. {
  112. /* A quoted string. */
  113. int len;
  114. const char *start = chp + 1;
  115. /* Determine the buffer size. */
  116. chp = start;
  117. len = 0;
  118. while (*chp != '\0' && *chp != '"')
  119. {
  120. if (*chp == '\\')
  121. {
  122. chp++;
  123. if (mi_parse_escape (&chp) <= 0)
  124. {
  125. /* Do not allow split lines or "\000". */
  126. freeargv (argv);
  127. return;
  128. }
  129. }
  130. else
  131. chp++;
  132. len++;
  133. }
  134. /* Insist on a closing quote. */
  135. if (*chp != '"')
  136. {
  137. freeargv (argv);
  138. return;
  139. }
  140. /* Insist on trailing white space. */
  141. if (chp[1] != '\0' && !isspace (chp[1]))
  142. {
  143. freeargv (argv);
  144. return;
  145. }
  146. /* Create the buffer and copy characters in. */
  147. arg = XNEWVEC (char, len + 1);
  148. chp = start;
  149. len = 0;
  150. while (*chp != '\0' && *chp != '"')
  151. {
  152. if (*chp == '\\')
  153. {
  154. chp++;
  155. arg[len] = mi_parse_escape (&chp);
  156. }
  157. else
  158. arg[len] = *chp++;
  159. len++;
  160. }
  161. arg[len] = '\0';
  162. chp++; /* That closing quote. */
  163. break;
  164. }
  165. default:
  166. {
  167. /* An unquoted string. Accumulate all non-blank
  168. characters into a buffer. */
  169. int len;
  170. const char *start = chp;
  171. while (*chp != '\0' && !isspace (*chp))
  172. {
  173. chp++;
  174. }
  175. len = chp - start;
  176. arg = XNEWVEC (char, len + 1);
  177. strncpy (arg, start, len);
  178. arg[len] = '\0';
  179. break;
  180. }
  181. }
  182. /* Append arg to argv. */
  183. argv = XRESIZEVEC (char *, argv, argc + 2);
  184. argv[argc++] = arg;
  185. argv[argc] = NULL;
  186. }
  187. }
  188. mi_parse::mi_parse ()
  189. : op (MI_COMMAND),
  190. command (NULL),
  191. token (NULL),
  192. cmd (NULL),
  193. cmd_start (NULL),
  194. args (NULL),
  195. argv (NULL),
  196. argc (0),
  197. all (0),
  198. thread_group (-1),
  199. thread (-1),
  200. frame (-1),
  201. language (language_unknown)
  202. {
  203. }
  204. mi_parse::~mi_parse ()
  205. {
  206. xfree (command);
  207. xfree (token);
  208. xfree (args);
  209. freeargv (argv);
  210. }
  211. std::unique_ptr<struct mi_parse>
  212. mi_parse (const char *cmd, char **token)
  213. {
  214. const char *chp;
  215. std::unique_ptr<struct mi_parse> parse (new struct mi_parse);
  216. /* Before starting, skip leading white space. */
  217. cmd = skip_spaces (cmd);
  218. /* Find/skip any token and then extract it. */
  219. for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
  220. ;
  221. *token = (char *) xmalloc (chp - cmd + 1);
  222. memcpy (*token, cmd, (chp - cmd));
  223. (*token)[chp - cmd] = '\0';
  224. /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
  225. if (*chp != '-')
  226. {
  227. chp = skip_spaces (chp);
  228. parse->command = xstrdup (chp);
  229. parse->op = CLI_COMMAND;
  230. return parse;
  231. }
  232. /* Extract the command. */
  233. {
  234. const char *tmp = chp + 1; /* discard ``-'' */
  235. for (; *chp && !isspace (*chp); chp++)
  236. ;
  237. parse->command = (char *) xmalloc (chp - tmp + 1);
  238. memcpy (parse->command, tmp, chp - tmp);
  239. parse->command[chp - tmp] = '\0';
  240. }
  241. /* Find the command in the MI table. */
  242. parse->cmd = mi_cmd_lookup (parse->command);
  243. if (parse->cmd == NULL)
  244. throw_error (UNDEFINED_COMMAND_ERROR,
  245. _("Undefined MI command: %s"), parse->command);
  246. /* Skip white space following the command. */
  247. chp = skip_spaces (chp);
  248. /* Parse the --thread and --frame options, if present. At present,
  249. some important commands, like '-break-*' are implemented by
  250. forwarding to the CLI layer directly. We want to parse --thread
  251. and --frame here, so as not to leave those option in the string
  252. that will be passed to CLI.
  253. Same for the --language option. */
  254. for (;;)
  255. {
  256. const char *option;
  257. size_t as = sizeof ("--all ") - 1;
  258. size_t tgs = sizeof ("--thread-group ") - 1;
  259. size_t ts = sizeof ("--thread ") - 1;
  260. size_t fs = sizeof ("--frame ") - 1;
  261. size_t ls = sizeof ("--language ") - 1;
  262. if (strncmp (chp, "--all ", as) == 0)
  263. {
  264. parse->all = 1;
  265. chp += as;
  266. }
  267. /* See if --all is the last token in the input. */
  268. if (strcmp (chp, "--all") == 0)
  269. {
  270. parse->all = 1;
  271. chp += strlen (chp);
  272. }
  273. if (strncmp (chp, "--thread-group ", tgs) == 0)
  274. {
  275. char *endp;
  276. option = "--thread-group";
  277. if (parse->thread_group != -1)
  278. error (_("Duplicate '--thread-group' option"));
  279. chp += tgs;
  280. if (*chp != 'i')
  281. error (_("Invalid thread group id"));
  282. chp += 1;
  283. parse->thread_group = strtol (chp, &endp, 10);
  284. chp = endp;
  285. }
  286. else if (strncmp (chp, "--thread ", ts) == 0)
  287. {
  288. char *endp;
  289. option = "--thread";
  290. if (parse->thread != -1)
  291. error (_("Duplicate '--thread' option"));
  292. chp += ts;
  293. parse->thread = strtol (chp, &endp, 10);
  294. chp = endp;
  295. }
  296. else if (strncmp (chp, "--frame ", fs) == 0)
  297. {
  298. char *endp;
  299. option = "--frame";
  300. if (parse->frame != -1)
  301. error (_("Duplicate '--frame' option"));
  302. chp += fs;
  303. parse->frame = strtol (chp, &endp, 10);
  304. chp = endp;
  305. }
  306. else if (strncmp (chp, "--language ", ls) == 0)
  307. {
  308. option = "--language";
  309. chp += ls;
  310. std::string lang_name = extract_arg (&chp);
  311. parse->language = language_enum (lang_name.c_str ());
  312. if (parse->language == language_unknown
  313. || parse->language == language_auto)
  314. error (_("Invalid --language argument: %s"), lang_name.c_str ());
  315. }
  316. else
  317. break;
  318. if (*chp != '\0' && !isspace (*chp))
  319. error (_("Invalid value for the '%s' option"), option);
  320. chp = skip_spaces (chp);
  321. }
  322. /* Save the rest of the arguments for the command. */
  323. parse->args = xstrdup (chp);
  324. /* Fully parsed, flag as an MI command. */
  325. parse->op = MI_COMMAND;
  326. return parse;
  327. }
  328. enum print_values
  329. mi_parse_print_values (const char *name)
  330. {
  331. if (strcmp (name, "0") == 0
  332. || strcmp (name, mi_no_values) == 0)
  333. return PRINT_NO_VALUES;
  334. else if (strcmp (name, "1") == 0
  335. || strcmp (name, mi_all_values) == 0)
  336. return PRINT_ALL_VALUES;
  337. else if (strcmp (name, "2") == 0
  338. || strcmp (name, mi_simple_values) == 0)
  339. return PRINT_SIMPLE_VALUES;
  340. else
  341. error (_("Unknown value for PRINT_VALUES: must be: \
  342. 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
  343. mi_no_values, mi_all_values, mi_simple_values);
  344. }