VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCEval.cpp@ 41561

Last change on this file since 41561 was 41561, checked in by vboxsync, 13 years ago

DBGC: Made the parse cope with functions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.2 KB
Line 
1/* $Id: DBGCEval.cpp 41561 2012-06-04 12:10:19Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, command evaluator.
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DBGC
22#include <VBox/dbg.h>
23#include <VBox/err.h>
24#include <VBox/log.h>
25
26#include <iprt/asm.h>
27#include <iprt/assert.h>
28#include <iprt/mem.h>
29#include <iprt/string.h>
30#include <iprt/ctype.h>
31
32#include "DBGCInternal.h"
33
34/** Rewrite in progress. */
35#define BETTER_ARGUMENT_MATCHING
36
37
38/*******************************************************************************
39* Global Variables *
40*******************************************************************************/
41/** Bitmap where set bits indicates the characters the may start an operator name. */
42static uint32_t g_bmOperatorChars[256 / (4*8)];
43
44
45/*******************************************************************************
46* Internal Functions *
47*******************************************************************************/
48static int dbgcProcessArguments(PDBGC pDbgc, const char *pszCmdOrFunc,
49 uint32_t const cArgsMin, uint32_t const cArgsMax,
50 PCDBGCVARDESC const paVarDescs, uint32_t const cVarDescs,
51 char *pszArgs, unsigned *piArg, unsigned *pcArgs);
52
53
54
55/**
56 * Initializes g_bmOperatorChars.
57 */
58void dbgcEvalInit(void)
59{
60 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
61 for (unsigned iOp = 0; iOp < g_cDbgcOps; iOp++)
62 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aDbgcOps[iOp].szName[0]);
63}
64
65
66/**
67 * Checks whether the character may be the start of an operator.
68 *
69 * @returns true/false.
70 * @param ch The character.
71 */
72DECLINLINE(bool) dbgcIsOpChar(char ch)
73{
74 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
75}
76
77
78
79static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
80{
81 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
82
83 /*
84 * Removing any quoting and escapings.
85 */
86 char ch = *pszExpr;
87 if (ch == '"' || ch == '\'')
88 {
89 if (pszExpr[--cchExpr] != ch)
90 return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
91 cchExpr--;
92 pszExpr++;
93
94 /** @todo string unescaping. */
95 }
96 pszExpr[cchExpr] = '\0';
97
98 /*
99 * Make the argument.
100 */
101 pArg->pDesc = NULL;
102 pArg->pNext = NULL;
103 pArg->enmType = DBGCVAR_TYPE_STRING;
104 pArg->u.pszString = pszExpr;
105 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;
106 pArg->u64Range = cchExpr;
107
108 NOREF(pDbgc);
109 return VINF_SUCCESS;
110}
111
112
113static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
114{
115 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
116 /*
117 * Convert to number.
118 */
119 uint64_t u64 = 0;
120 char ch;
121 while ((ch = *pszExpr) != '\0')
122 {
123 uint64_t u64Prev = u64;
124 unsigned u = ch - '0';
125 if (u < 10 && u < uBase)
126 u64 = u64 * uBase + u;
127 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
128 u64 = u64 * uBase + u;
129 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
130 u64 = u64 * uBase + u;
131 else
132 return VERR_DBGC_PARSE_INVALID_NUMBER;
133
134 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
135 if (u64Prev != u64 / uBase)
136 return VERR_DBGC_PARSE_NUMBER_TOO_BIG;
137
138 /* next */
139 pszExpr++;
140 }
141
142 /*
143 * Initialize the argument.
144 */
145 pArg->pDesc = NULL;
146 pArg->pNext = NULL;
147 pArg->enmType = DBGCVAR_TYPE_NUMBER;
148 pArg->u.u64Number = u64;
149 pArg->enmRangeType = DBGCVAR_RANGE_NONE;
150 pArg->u64Range = 0;
151
152 return VINF_SUCCESS;
153}
154
155
156/**
157 * dbgcEvalSubUnary worker that handles simple numeric or pointer expressions.
158 *
159 * @returns VBox status code. pResult contains the result on success.
160 * @param pDbgc Debugger console instance data.
161 * @param pszExpr The expression string.
162 * @param cchExpr The length of the expression.
163 * @param enmCategory The desired type category (for range / no range).
164 * @param pResult Where to store the result of the expression evaluation.
165 */
166static int dbgcEvalSubNumericOrPointer(PDBGC pDbgc, char *pszExpr, size_t cchExpr, DBGCVARCAT enmCategory,
167 PDBGCVAR pResult)
168{
169 char const ch = pszExpr[0];
170 char const ch2 = pszExpr[1];
171
172 /* 0x<hex digits> */
173 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
174 return dbgcEvalSubNum(pszExpr + 2, 16, pResult);
175
176 /* <hex digits>h */
177 if (RT_C_IS_XDIGIT(*pszExpr) && (pszExpr[cchExpr - 1] == 'h' || pszExpr[cchExpr - 1] == 'H'))
178 {
179 pszExpr[cchExpr] = '\0';
180 return dbgcEvalSubNum(pszExpr, 16, pResult);
181 }
182
183 /* 0i<decimal digits> */
184 if (ch == '0' && ch2 == 'i')
185 return dbgcEvalSubNum(pszExpr + 2, 10, pResult);
186
187 /* 0t<octal digits> */
188 if (ch == '0' && ch2 == 't')
189 return dbgcEvalSubNum(pszExpr + 2, 8, pResult);
190
191 /* 0y<binary digits> */
192 if (ch == '0' && ch2 == 'y')
193 return dbgcEvalSubNum(pszExpr + 2, 10, pResult);
194
195 /* Hex number? */
196 unsigned off = 0;
197 while (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`')
198 off++;
199 if (off == cchExpr)
200 return dbgcEvalSubNum(pszExpr, 16, pResult);
201
202 /*
203 * Some kind of symbol?
204 */
205 DBGCVARTYPE enmType;
206 bool fStripRange = false;
207 switch (enmCategory)
208 {
209 case DBGCVAR_CAT_POINTER_NUMBER: enmType = DBGCVAR_TYPE_NUMBER; break;
210 case DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE: enmType = DBGCVAR_TYPE_NUMBER; fStripRange = true; break;
211 case DBGCVAR_CAT_POINTER: enmType = DBGCVAR_TYPE_NUMBER; break;
212 case DBGCVAR_CAT_POINTER_NO_RANGE: enmType = DBGCVAR_TYPE_NUMBER; fStripRange = true; break;
213 case DBGCVAR_CAT_GC_POINTER: enmType = DBGCVAR_TYPE_GC_FLAT; break;
214 case DBGCVAR_CAT_GC_POINTER_NO_RANGE: enmType = DBGCVAR_TYPE_GC_FLAT; fStripRange = true; break;
215 case DBGCVAR_CAT_NUMBER: enmType = DBGCVAR_TYPE_NUMBER; break;
216 case DBGCVAR_CAT_NUMBER_NO_RANGE: enmType = DBGCVAR_TYPE_NUMBER; fStripRange = true; break;
217 default:
218 AssertFailedReturn(VERR_DBGC_PARSE_NOT_IMPLEMENTED);
219 }
220
221 if ( (*pszExpr == '"' || *pszExpr == '\'')
222 && pszExpr[cchExpr - 1] == *pszExpr)
223 {
224 pszExpr[cchExpr - 1] = '\0';
225 pszExpr++;
226 }
227
228 int rc = dbgcSymbolGet(pDbgc, pszExpr, enmType, pResult);
229 if (RT_SUCCESS(rc))
230 {
231 if (fStripRange)
232 {
233 pResult->enmRangeType = DBGCVAR_RANGE_NONE;
234 pResult->u64Range = 0;
235 }
236 }
237 else if (rc == VERR_DBGC_PARSE_NOT_IMPLEMENTED)
238 rc = VERR_DBGC_PARSE_INVALID_NUMBER;
239 return rc;
240}
241
242
243/**
244 * dbgcEvalSubUnary worker that handles simple DBGCVAR_CAT_ANY expressions.
245 *
246 * @returns VBox status code. pResult contains the result on success.
247 * @param pDbgc Debugger console instance data.
248 * @param pszExpr The expression string.
249 * @param cchExpr The length of the expression.
250 * @param pResult Where to store the result of the expression evaluation.
251 */
252static int dbgcEvalSubUnaryAny(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
253{
254 char const ch = pszExpr[0];
255 char const ch2 = pszExpr[1];
256 unsigned off = 2;
257
258 /* 0x<hex digits> */
259 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
260 {
261 while (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`')
262 off++;
263 if (off == cchExpr)
264 return dbgcEvalSubNum(pszExpr + 2, 16, pResult);
265 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
266 }
267
268 /* <hex digits>h */
269 if (RT_C_IS_XDIGIT(*pszExpr) && (pszExpr[cchExpr - 1] == 'h' || pszExpr[cchExpr - 1] == 'H'))
270 {
271 cchExpr--;
272 while (off < cchExpr && (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`'))
273 off++;
274 if (off == cchExpr)
275 {
276 pszExpr[cchExpr] = '\0';
277 return dbgcEvalSubNum(pszExpr, 16, pResult);
278 }
279 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr + 1, pResult);
280 }
281
282 /* 0i<decimal digits> */
283 if (ch == '0' && ch2 == 'i')
284 {
285 while (RT_C_IS_DIGIT(pszExpr[off]) || pszExpr[off] == '`')
286 off++;
287 if (off == cchExpr)
288 return dbgcEvalSubNum(pszExpr + 2, 10, pResult);
289 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
290 }
291
292 /* 0t<octal digits> */
293 if (ch == '0' && ch2 == 't')
294 {
295 while (RT_C_IS_ODIGIT(pszExpr[off]) || pszExpr[off] == '`')
296 off++;
297 if (off == cchExpr)
298 return dbgcEvalSubNum(pszExpr + 2, 8, pResult);
299 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
300 }
301
302 /* 0y<binary digits> */
303 if (ch == '0' && ch2 == 'y')
304 {
305 while (pszExpr[off] == '0' || pszExpr[off] == '1' || pszExpr[off] == '`')
306 off++;
307 if (off == cchExpr)
308 return dbgcEvalSubNum(pszExpr + 2, 10, pResult);
309 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
310 }
311
312 /* Ok, no prefix of suffix. Is it a hex number after all? If not it must
313 be a string. */
314 off = 0;
315 while (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`')
316 off++;
317 if (off == cchExpr)
318 return dbgcEvalSubNum(pszExpr, 16, pResult);
319 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
320}
321
322
323static int dbgcEvalSubCall(PDBGC pDbgc, char *pszFuncNm, size_t cchFuncNm, bool fExternal, char *pszArgs, size_t cchArgs,
324 DBGCVARCAT enmCategory, PDBGCVAR pResult)
325{
326 /*
327 * Lookup the function.
328 */
329 PCDBGCFUNC pFunc = dbgcFunctionLookup(pDbgc, pszFuncNm, cchFuncNm, fExternal);
330 if (!pFunc)
331 return VERR_DBGC_PARSE_FUNCTION_NOT_FOUND;
332
333 /*
334 * Parse the arguments.
335 */
336 unsigned cArgs;
337 unsigned iArg;
338 pszArgs[cchArgs] = '\0';
339 int rc = dbgcProcessArguments(pDbgc, pFunc->pszFuncNm,
340 pFunc->cArgsMin, pFunc->cArgsMax, pFunc->paArgDescs, pFunc->cArgDescs,
341 pszArgs, &iArg, &cArgs);
342 if (RT_SUCCESS(rc))
343 rc = pFunc->pfnHandler(pFunc, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[iArg], cArgs, pResult);
344 pDbgc->iArg = iArg;
345 return rc;
346}
347
348
349/**
350 * Evaluates one argument with respect to unary operators.
351 *
352 * @returns VBox status code. pResult contains the result on success.
353 *
354 * @param pDbgc Debugger console instance data.
355 * @param pszExpr The expression string.
356 * @param cchExpr The length of the expression.
357 * @param enmCategory The target category for the result.
358 * @param pResult Where to store the result of the expression evaluation.
359 */
360static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, DBGCVARCAT enmCategory, PDBGCVAR pResult)
361{
362 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
363
364 /*
365 * The state of the expression is now such that it will start by zero or more
366 * unary operators and being followed by an expression of some kind.
367 * The expression is either plain or in parenthesis.
368 *
369 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
370 * ASSUME: unary operators are all of equal precedence.
371 */
372 int rc = VINF_SUCCESS;
373 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
374 if (pOp)
375 {
376 /* binary operators means syntax error. */
377 if (pOp->fBinary)
378 return VERR_DBGC_PARSE_UNEXPECTED_OPERATOR;
379
380 /*
381 * If the next expression (the one following the unary operator) is in a
382 * parenthesis a full eval is needed. If not the unary eval will suffice.
383 */
384 /* calc and strip next expr. */
385 char *pszExpr2 = pszExpr + pOp->cchName;
386 while (RT_C_IS_BLANK(*pszExpr2))
387 pszExpr2++;
388
389 if (*pszExpr2)
390 {
391 DBGCVAR Arg;
392 if (*pszExpr2 == '(')
393 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), pOp->enmCatArg1, &Arg);
394 else
395 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), pOp->enmCatArg1, &Arg);
396 if (RT_SUCCESS(rc))
397 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, enmCategory, pResult);
398 }
399 else
400 rc = VERR_DBGC_PARSE_EMPTY_ARGUMENT;
401 return rc;
402 }
403
404 /*
405 * Could this be a function call?
406 *
407 * ASSUMPTIONS:
408 * - A function name only contains alphanumerical chars and it can not
409 * start with a numerical character.
410 * - Immediately following the name is a parenthesis which must cover
411 * the remaining part of the expression.
412 */
413 bool fExternal = *pszExpr == '.';
414 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;
415 char *pszFunEnd = NULL;
416 if (pszExpr[cchExpr - 1] == ')' && RT_C_IS_ALPHA(*pszFun))
417 {
418 pszFunEnd = pszExpr + 1;
419 while (*pszFunEnd != '(' && RT_C_IS_ALNUM(*pszFunEnd))
420 pszFunEnd++;
421 if (*pszFunEnd != '(')
422 pszFunEnd = NULL;
423 }
424 if (pszFunEnd)
425 {
426 size_t cchFunNm = pszFunEnd - pszFun;
427 return dbgcEvalSubCall(pDbgc, pszFun, cchFunNm, fExternal, pszFunEnd + 1, cchExpr - cchFunNm - fExternal - 2,
428 enmCategory, pResult);
429 }
430
431 /*
432 * Assuming plain expression.
433 * Didn't find any operators, so it must be a plain expression.
434 * Go by desired category first, then if anythings go, try guess.
435 */
436 switch (enmCategory)
437 {
438 case DBGCVAR_CAT_ANY:
439 return dbgcEvalSubUnaryAny(pDbgc, pszExpr, cchExpr, pResult);
440
441 case DBGCVAR_CAT_POINTER_NUMBER:
442 case DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE:
443 case DBGCVAR_CAT_POINTER:
444 case DBGCVAR_CAT_POINTER_NO_RANGE:
445 case DBGCVAR_CAT_GC_POINTER:
446 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
447 case DBGCVAR_CAT_NUMBER:
448 case DBGCVAR_CAT_NUMBER_NO_RANGE:
449 /* Pointers will be promoted later. */
450 return dbgcEvalSubNumericOrPointer(pDbgc, pszExpr, cchExpr, enmCategory, pResult);
451
452 case DBGCVAR_CAT_STRING:
453 case DBGCVAR_CAT_SYMBOL:
454 /* Symbols will be promoted later. */
455 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
456
457 case DBGCVAR_CAT_OPTION:
458 case DBGCVAR_CAT_OPTION_STRING:
459 case DBGCVAR_CAT_OPTION_NUMBER:
460 return VERR_DBGC_PARSE_NOT_IMPLEMENTED;
461 }
462
463 AssertMsgFailed(("enmCategory=%d\n", enmCategory));
464 rc = VERR_NOT_IMPLEMENTED;
465
466 return rc;
467}
468
469
470/**
471 * Evaluates one argument.
472 *
473 * @returns VBox status code.
474 *
475 * @param pDbgc Debugger console instance data.
476 * @param pszExpr The expression string.
477 * @param enmCategory The target category for the result.
478 * @param pResult Where to store the result of the expression evaluation.
479 */
480int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, DBGCVARCAT enmCategory, PDBGCVAR pResult)
481{
482 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
483
484 /*
485 * First we need to remove blanks in both ends.
486 * ASSUMES: There is no quoting unless the entire expression is a string.
487 */
488
489 /* stripping. */
490 while (cchExpr > 0 && RT_C_IS_BLANK(pszExpr[cchExpr - 1]))
491 pszExpr[--cchExpr] = '\0';
492 while (RT_C_IS_BLANK(*pszExpr))
493 pszExpr++, cchExpr--;
494 if (!*pszExpr)
495 return VERR_DBGC_PARSE_EMPTY_ARGUMENT;
496
497 /*
498 * Check if there are any parenthesis which needs removing.
499 */
500 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
501 {
502 do
503 {
504 unsigned cPar = 1;
505 char *psz = pszExpr + 1;
506 char ch;
507 while ((ch = *psz) != '\0')
508 {
509 if (ch == '(')
510 cPar++;
511 else if (ch == ')')
512 {
513 if (cPar <= 0)
514 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
515 cPar--;
516 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
517 break;
518 }
519 /* next */
520 psz++;
521 }
522 if (ch)
523 break;
524
525 /* remove the parenthesis. */
526 pszExpr++;
527 cchExpr -= 2;
528 pszExpr[cchExpr] = '\0';
529
530 /* strip blanks. */
531 while (cchExpr > 0 && RT_C_IS_BLANK(pszExpr[cchExpr - 1]))
532 pszExpr[--cchExpr] = '\0';
533 while (RT_C_IS_BLANK(*pszExpr))
534 pszExpr++, cchExpr--;
535 if (!*pszExpr)
536 return VERR_DBGC_PARSE_EMPTY_ARGUMENT;
537 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
538 }
539
540#if 0 /* why was this needed? It'll screw up strings. */
541 /* tabs to spaces */
542 char *psz = pszExpr;
543 while ((psz = strchr(psz, '\t')) != NULL)
544 *psz = ' ';
545#endif
546
547 /*
548 * Now, we need to look for the binary operator with the lowest precedence.
549 *
550 * If there are no operators we're left with a simple expression which we
551 * evaluate with respect to unary operators
552 */
553 char *pszOpSplit = NULL;
554 PCDBGCOP pOpSplit = NULL;
555 unsigned cBinaryOps = 0;
556 unsigned cPar = 0;
557 unsigned cchWord = 0;
558 char chQuote = '\0';
559 char chPrev = ' ';
560 bool fBinary = false;
561 char *psz = pszExpr;
562 char ch;
563
564 while ((ch = *psz) != '\0')
565 {
566 /*
567 * String quoting.
568 */
569 if (chQuote)
570 {
571 if (ch == chQuote)
572 {
573 if (psz[1] == chQuote)
574 {
575 psz++; /* escaped quote */
576 cchWord++;
577 }
578 else
579 {
580 chQuote = '\0';
581 fBinary = true;
582 cchWord = 0;
583 }
584 }
585 else
586 cchWord++;
587 }
588 else if (ch == '"' || ch == '\'')
589 {
590 if (fBinary || cchWord)
591 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
592 chQuote = ch;
593 }
594 /*
595 * Parentheses.
596 */
597 else if (ch == '(')
598 {
599 if (!cPar && fBinary && !cchWord)
600 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
601 cPar++;
602 fBinary = false;
603 cchWord = 0;
604 }
605 else if (ch == ')')
606 {
607 if (cPar <= 0)
608 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
609 cPar--;
610 fBinary = true;
611 cchWord = 0;
612 }
613 /*
614 * Potential operator.
615 */
616 else if (cPar == 0 && !RT_C_IS_BLANK(ch))
617 {
618 PCDBGCOP pOp = dbgcIsOpChar(ch)
619 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
620 : NULL;
621 if (pOp)
622 {
623 /* If not the right kind of operator we've got a syntax error. */
624 if (pOp->fBinary != fBinary)
625 return VERR_DBGC_PARSE_UNEXPECTED_OPERATOR;
626
627 /*
628 * Update the parse state and skip the operator.
629 */
630 if (!pOpSplit)
631 {
632 pOpSplit = pOp;
633 pszOpSplit = psz;
634 cBinaryOps = fBinary;
635 }
636 else if (fBinary)
637 {
638 cBinaryOps++;
639 if (pOp->iPrecedence >= pOpSplit->iPrecedence)
640 {
641 pOpSplit = pOp;
642 pszOpSplit = psz;
643 }
644 }
645
646 psz += pOp->cchName - 1;
647 fBinary = false;
648 cchWord = 0;
649 }
650 else if (fBinary && !cchWord)
651 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
652 else
653 {
654 fBinary = true;
655 cchWord++;
656 }
657 }
658 else if (cPar == 0 && RT_C_IS_BLANK(ch))
659 cchWord++;
660
661 /* next */
662 psz++;
663 chPrev = ch;
664 } /* parse loop. */
665
666 if (chQuote)
667 return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
668
669 /*
670 * Either we found an operator to divide the expression by
671 * or we didn't find any. In the first case it's divide and
672 * conquer. In the latter it's a single expression which
673 * needs dealing with its unary operators if any.
674 */
675 int rc;
676 if ( cBinaryOps
677 && pOpSplit->fBinary)
678 {
679 /* process 1st sub expression. */
680 *pszOpSplit = '\0';
681 DBGCVAR Arg1;
682 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, pOpSplit->enmCatArg1, &Arg1);
683 if (RT_SUCCESS(rc))
684 {
685 /* process 2nd sub expression. */
686 char *psz2 = pszOpSplit + pOpSplit->cchName;
687 DBGCVAR Arg2;
688 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), pOpSplit->enmCatArg2, &Arg2);
689 if (RT_SUCCESS(rc))
690 /* apply the operator. */
691 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
692 }
693 }
694 else if (cBinaryOps)
695 {
696 /* process sub expression. */
697 pszOpSplit += pOpSplit->cchName;
698 DBGCVAR Arg;
699 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), pOpSplit->enmCatArg1, &Arg);
700 if (RT_SUCCESS(rc))
701 /* apply the operator. */
702 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, enmCategory, pResult);
703 }
704 else
705 /* plain expression, qutoed string, or using unary operators perhaps with parentheses. */
706 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, enmCategory, pResult);
707
708 return rc;
709}
710
711
712/**
713 * Worker for dbgcProcessArguments that performs type checking and promoptions.
714 *
715 * @returns VBox status code.
716 *
717 * @param pDbgc Debugger console instance data.
718 * @param enmCategory The target category for the result.
719 * @param pArg The argument to check and promote.
720 */
721static int dbgcCheckAndTypePromoteArgument(PDBGC pDbgc, DBGCVARCAT enmCategory, PDBGCVAR pArg)
722{
723 switch (enmCategory)
724 {
725 /*
726 * Anything goes
727 */
728 case DBGCVAR_CAT_ANY:
729 return VINF_SUCCESS;
730
731 /*
732 * Pointer with and without range.
733 * We can try resolve strings and symbols as symbols and promote
734 * numbers to flat GC pointers.
735 */
736 case DBGCVAR_CAT_POINTER_NO_RANGE:
737 case DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE:
738 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
739 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED;
740 /* fallthru */
741 case DBGCVAR_CAT_POINTER:
742 case DBGCVAR_CAT_POINTER_NUMBER:
743 switch (pArg->enmType)
744 {
745 case DBGCVAR_TYPE_GC_FLAT:
746 case DBGCVAR_TYPE_GC_FAR:
747 case DBGCVAR_TYPE_GC_PHYS:
748 case DBGCVAR_TYPE_HC_FLAT:
749 case DBGCVAR_TYPE_HC_PHYS:
750 return VINF_SUCCESS;
751
752 case DBGCVAR_TYPE_SYMBOL:
753 case DBGCVAR_TYPE_STRING:
754 {
755 DBGCVAR Var;
756 int rc = dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
757 if (RT_SUCCESS(rc))
758 {
759 /* deal with range */
760 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
761 {
762 Var.enmRangeType = pArg->enmRangeType;
763 Var.u64Range = pArg->u64Range;
764 }
765 else if (enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
766 Var.enmRangeType = DBGCVAR_RANGE_NONE;
767 *pArg = Var;
768 }
769 return rc;
770 }
771
772 case DBGCVAR_TYPE_NUMBER:
773 if ( enmCategory != DBGCVAR_CAT_POINTER_NUMBER
774 && enmCategory != DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE)
775 {
776 RTGCPTR GCPtr = (RTGCPTR)pArg->u.u64Number;
777 pArg->enmType = DBGCVAR_TYPE_GC_FLAT;
778 pArg->u.GCFlat = GCPtr;
779 }
780 return VINF_SUCCESS;
781
782 default:
783 AssertMsgFailedReturn(("Invalid type %d\n"), VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
784 }
785 break; /* (not reached) */
786
787 /*
788 * GC pointer with and without range.
789 * We can try resolve strings and symbols as symbols and
790 * promote numbers to flat GC pointers.
791 */
792 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
793 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
794 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED;
795 /* fallthru */
796 case DBGCVAR_CAT_GC_POINTER:
797 switch (pArg->enmType)
798 {
799 case DBGCVAR_TYPE_GC_FLAT:
800 case DBGCVAR_TYPE_GC_FAR:
801 case DBGCVAR_TYPE_GC_PHYS:
802 return VINF_SUCCESS;
803
804 case DBGCVAR_TYPE_HC_FLAT:
805 case DBGCVAR_TYPE_HC_PHYS:
806 return VERR_DBGC_PARSE_CONVERSION_FAILED;
807
808 case DBGCVAR_TYPE_SYMBOL:
809 case DBGCVAR_TYPE_STRING:
810 {
811 DBGCVAR Var;
812 int rc = dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
813 if (RT_SUCCESS(rc))
814 {
815 /* deal with range */
816 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
817 {
818 Var.enmRangeType = pArg->enmRangeType;
819 Var.u64Range = pArg->u64Range;
820 }
821 else if (enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
822 Var.enmRangeType = DBGCVAR_RANGE_NONE;
823 *pArg = Var;
824 }
825 return rc;
826 }
827
828 case DBGCVAR_TYPE_NUMBER:
829 {
830 RTGCPTR GCPtr = (RTGCPTR)pArg->u.u64Number;
831 pArg->enmType = DBGCVAR_TYPE_GC_FLAT;
832 pArg->u.GCFlat = GCPtr;
833 return VINF_SUCCESS;
834 }
835
836 default:
837 AssertMsgFailedReturn(("Invalid type %d\n"), VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
838 }
839 break; /* (not reached) */
840
841 /*
842 * Number with or without a range.
843 * Numbers can be resolved from symbols, but we cannot demote a pointer
844 * to a number.
845 */
846 case DBGCVAR_CAT_NUMBER_NO_RANGE:
847 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
848 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED;
849 /* fallthru */
850 case DBGCVAR_CAT_NUMBER:
851 switch (pArg->enmType)
852 {
853 case DBGCVAR_TYPE_GC_FLAT:
854 case DBGCVAR_TYPE_GC_FAR:
855 case DBGCVAR_TYPE_GC_PHYS:
856 case DBGCVAR_TYPE_HC_FLAT:
857 case DBGCVAR_TYPE_HC_PHYS:
858 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
859
860 case DBGCVAR_TYPE_NUMBER:
861 return VINF_SUCCESS;
862
863 case DBGCVAR_TYPE_SYMBOL:
864 case DBGCVAR_TYPE_STRING:
865 {
866 DBGCVAR Var;
867 int rc = dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
868 if (RT_SUCCESS(rc))
869 {
870 /* deal with range */
871 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
872 {
873 Var.enmRangeType = pArg->enmRangeType;
874 Var.u64Range = pArg->u64Range;
875 }
876 else if (enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
877 Var.enmRangeType = DBGCVAR_RANGE_NONE;
878 *pArg = Var;
879 }
880 return rc;
881 }
882
883 default:
884 AssertMsgFailedReturn(("Invalid type %d\n"), VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
885 }
886 break; /* (not reached) */
887
888 /*
889 * Symbols and strings are basically the same thing for the time being.
890 */
891 case DBGCVAR_CAT_STRING:
892 case DBGCVAR_CAT_SYMBOL:
893 {
894 switch (pArg->enmType)
895 {
896 case DBGCVAR_TYPE_STRING:
897 if (enmCategory == DBGCVAR_CAT_SYMBOL)
898 pArg->enmType = DBGCVAR_TYPE_SYMBOL;
899 return VINF_SUCCESS;
900
901 case DBGCVAR_TYPE_SYMBOL:
902 if (enmCategory == DBGCVAR_CAT_STRING)
903 pArg->enmType = DBGCVAR_TYPE_STRING;
904 return VINF_SUCCESS;
905 default:
906 break;
907 }
908
909 /* Stringify numeric and poitner values. */
910 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
911 size_t cch = pDbgc->CmdHlp.pfnStrPrintf(&pDbgc->CmdHlp, pDbgc->pszScratch, cbScratch, "%Dv", pArg);
912 if (cch + 1 >= cbScratch)
913 return VERR_DBGC_PARSE_NO_SCRATCH;
914
915 pArg->enmType = enmCategory == DBGCVAR_CAT_STRING ? DBGCVAR_TYPE_STRING : DBGCVAR_TYPE_SYMBOL;
916 pArg->u.pszString = pDbgc->pszScratch;
917 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;
918 pArg->u64Range = cch;
919
920 pDbgc->pszScratch += cch + 1;
921 return VINF_SUCCESS;
922 }
923
924 /*
925 * These are not yet implemented.
926 */
927 case DBGCVAR_CAT_OPTION:
928 case DBGCVAR_CAT_OPTION_STRING:
929 case DBGCVAR_CAT_OPTION_NUMBER:
930 AssertMsgFailedReturn(("Not implemented enmCategory=%d\n", enmCategory), VERR_DBGC_PARSE_NOT_IMPLEMENTED);
931
932 default:
933 AssertMsgFailedReturn(("Bad enmCategory=%d\n", enmCategory), VERR_DBGC_PARSE_NOT_IMPLEMENTED);
934 }
935}
936
937
938/**
939 * Parses the arguments of one command.
940 *
941 * @returns VBox statuc code. On parser errors the index of the troublesome
942 * argument is indicated by *pcArg.
943 *
944 * @param pDbgc Debugger console instance data.
945 * @param pszCmdOrFunc The name of the function or command. (For logging.)
946 * @param cArgsMin See DBGCCMD::cArgsMin and DBGCFUNC::cArgsMin.
947 * @param cArgsMax See DBGCCMD::cArgsMax and DBGCFUNC::cArgsMax.
948 * @param paVarDescs See DBGCCMD::paVarDescs and DBGCFUNC::paVarDescs.
949 * @param cVarDescs See DBGCCMD::cVarDescs and DBGCFUNC::cVarDescs.
950 * @param pszArg Pointer to the arguments to parse.
951 * @param piArg Where to return the index of the first argument in
952 * DBGC::aArgs. Always set. Caller must restore DBGC::iArg
953 * to this value when done, even on failure.
954 * @param pcArgs Where to store the number of arguments. In the event
955 * of an error this is (ab)used to store the index of the
956 * offending argument.
957 */
958static int dbgcProcessArguments(PDBGC pDbgc, const char *pszCmdOrFunc,
959 uint32_t const cArgsMin, uint32_t const cArgsMax,
960 PCDBGCVARDESC const paVarDescs, uint32_t const cVarDescs,
961 char *pszArgs, unsigned *piArg, unsigned *pcArgs)
962{
963 Log2(("dbgcProcessArguments: pszCmdOrFunc=%s pszArgs='%s'\n", pszCmdOrFunc, pszArgs));
964
965 /*
966 * Check if we have any argument and if the command takes any.
967 */
968 *piArg = pDbgc->iArg;
969 *pcArgs = 0;
970 /* strip leading blanks. */
971 while (*pszArgs && RT_C_IS_BLANK(*pszArgs))
972 pszArgs++;
973 if (!*pszArgs)
974 {
975 if (!cArgsMin)
976 return VINF_SUCCESS;
977 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS;
978 }
979 if (!cArgsMax)
980 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
981
982 /*
983 * The parse loop.
984 */
985 PDBGCVAR pArg = &pDbgc->aArgs[pDbgc->iArg];
986 PCDBGCVARDESC pPrevDesc = NULL;
987 unsigned cCurDesc = 0;
988 unsigned iVar = 0;
989 unsigned iVarDesc = 0;
990 *pcArgs = 0;
991 do
992 {
993 /*
994 * Can we have another argument?
995 */
996 if (*pcArgs >= cArgsMax)
997 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
998 if (pDbgc->iArg >= RT_ELEMENTS(pDbgc->aArgs))
999 return VERR_DBGC_PARSE_ARGUMENT_OVERFLOW;
1000 if (iVarDesc >= cVarDescs)
1001 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
1002
1003 /* Walk argument descriptors. */
1004 if (cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
1005 {
1006 iVarDesc++;
1007 if (iVarDesc >= cVarDescs)
1008 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
1009 cCurDesc = 0;
1010 }
1011
1012 /*
1013 * Find the end of the argument. This is just rough splitting,
1014 * dbgcEvalSub will do stricter syntax checking later on.
1015 */
1016 int cPar = 0;
1017 char chQuote = '\0';
1018 char *pszEnd = NULL;
1019 char *psz = pszArgs;
1020 char ch;
1021 bool fBinary = false;
1022 for (;;)
1023 {
1024 /*
1025 * Check for the end.
1026 */
1027 if ((ch = *psz) == '\0')
1028 {
1029 if (chQuote)
1030 return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
1031 if (cPar)
1032 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
1033 pszEnd = psz;
1034 break;
1035 }
1036 /*
1037 * When quoted we ignore everything but the quotation char.
1038 * We use the REXX way of escaping the quotation char, i.e. double occurrence.
1039 */
1040 else if (chQuote)
1041 {
1042 if (ch == chQuote)
1043 {
1044 if (psz[1] == chQuote)
1045 psz++; /* skip the escaped quote char */
1046 else
1047 {
1048 chQuote = '\0'; /* end of quoted string. */
1049 fBinary = true;
1050 }
1051 }
1052 }
1053 else if (ch == '\'' || ch == '"')
1054 {
1055 if (fBinary)
1056 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
1057 chQuote = ch;
1058 }
1059 /*
1060 * Parenthesis can of course be nested.
1061 */
1062 else if (ch == '(')
1063 {
1064 cPar++;
1065 fBinary = false;
1066 }
1067 else if (ch == ')')
1068 {
1069 if (!cPar)
1070 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
1071 cPar--;
1072 fBinary = true;
1073 }
1074 else if (!cPar)
1075 {
1076 /*
1077 * Encountering a comma is a definite end of parameter.
1078 */
1079 if (ch == ',')
1080 {
1081 pszEnd = psz++;
1082 break;
1083 }
1084
1085 /*
1086 * Encountering blanks may mean the end of it all. A binary
1087 * operator will force continued parsing.
1088 */
1089 if (RT_C_IS_BLANK(ch))
1090 {
1091 pszEnd = psz++; /* in case it's the end. */
1092 while (RT_C_IS_BLANK(*psz))
1093 psz++;
1094
1095 if (*psz == ',')
1096 {
1097 psz++;
1098 break;
1099 }
1100
1101 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1102 if (!pOp || pOp->fBinary != fBinary)
1103 break; /* the end. */
1104
1105 psz += pOp->cchName;
1106 while (RT_C_IS_BLANK(*psz)) /* skip blanks so we don't get here again */
1107 psz++;
1108 fBinary = false;
1109 continue;
1110 }
1111
1112 /*
1113 * Look for operators without a space up front.
1114 */
1115 if (dbgcIsOpChar(ch))
1116 {
1117 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1118 if (pOp)
1119 {
1120 if (pOp->fBinary != fBinary)
1121 {
1122 pszEnd = psz;
1123 /** @todo this is a parsing error really. */
1124 break; /* the end. */
1125 }
1126 psz += pOp->cchName;
1127 while (RT_C_IS_BLANK(*psz)) /* skip blanks so we don't get here again */
1128 psz++;
1129 fBinary = false;
1130 continue;
1131 }
1132 }
1133 fBinary = true;
1134 }
1135
1136 /* next char */
1137 psz++;
1138 }
1139 *pszEnd = '\0';
1140 /* (psz = next char to process) */
1141 size_t cchArgs = strlen(pszArgs);
1142
1143 /*
1144 * Try optional arguments until we find something which matches
1145 * or can easily be promoted to what the descriptor want.
1146 */
1147 for (;;)
1148 {
1149 char *pszArgsCopy = (char *)RTMemDup(pszArgs, cchArgs + 1);
1150 if (!pszArgsCopy)
1151 return VERR_DBGC_PARSE_NO_MEMORY;
1152
1153 int rc = dbgcEvalSub(pDbgc, pszArgs, cchArgs, paVarDescs[iVarDesc].enmCategory, pArg);
1154 if (RT_SUCCESS(rc))
1155 rc = dbgcCheckAndTypePromoteArgument(pDbgc, paVarDescs[iVarDesc].enmCategory, pArg);
1156 if (RT_SUCCESS(rc))
1157 {
1158 pArg->pDesc = pPrevDesc = &paVarDescs[iVarDesc];
1159 cCurDesc++;
1160 RTMemFree(pszArgsCopy);
1161 break;
1162 }
1163
1164 memcpy(pszArgs, pszArgsCopy, cchArgs + 1);
1165 RTMemFree(pszArgsCopy);
1166
1167 /* Continue searching optional descriptors? */
1168 if ( rc != VERR_DBGC_PARSE_INCORRECT_ARG_TYPE
1169 && rc != VERR_DBGC_PARSE_INVALID_NUMBER
1170 && rc != VERR_DBGC_PARSE_NO_RANGE_ALLOWED
1171 )
1172 return rc;
1173
1174 /* Try advance to the next descriptor. */
1175 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
1176 return rc;
1177 iVarDesc++;
1178 if (!cCurDesc)
1179 while ( iVarDesc < cVarDescs
1180 && (paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV))
1181 iVarDesc++;
1182 if (iVarDesc >= cVarDescs)
1183 return rc;
1184 cCurDesc = 0;
1185 }
1186
1187 /*
1188 * Next argument.
1189 */
1190 iVar++;
1191 pArg++;
1192 pDbgc->iArg++;
1193 *pcArgs += 1;
1194 pszArgs = psz;
1195 while (*pszArgs && RT_C_IS_BLANK(*pszArgs))
1196 pszArgs++;
1197 } while (*pszArgs);
1198
1199 /*
1200 * Check that the rest of the argument descriptors indicate optional args.
1201 */
1202 if (iVarDesc < cVarDescs)
1203 {
1204 if (cCurDesc < paVarDescs[iVarDesc].cTimesMin)
1205 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS;
1206 iVarDesc++;
1207 while (iVarDesc < cVarDescs)
1208 {
1209 if (paVarDescs[iVarDesc].cTimesMin)
1210 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS;
1211 iVarDesc++;
1212 }
1213 }
1214
1215 return VINF_SUCCESS;
1216}
1217
1218
1219/**
1220 * Evaluate one command.
1221 *
1222 * @returns VBox status code. This is also stored in DBGC::rcCmd.
1223 *
1224 * @param pDbgc Debugger console instance data.
1225 * @param pszCmd Pointer to the command.
1226 * @param cchCmd Length of the command.
1227 * @param fNoExecute Indicates that no commands should actually be executed.
1228 *
1229 * @todo Change pszCmd into argc/argv?
1230 */
1231int dbgcEvalCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd, bool fNoExecute)
1232{
1233 char *pszCmdInput = pszCmd;
1234
1235 /*
1236 * Skip blanks.
1237 */
1238 while (RT_C_IS_BLANK(*pszCmd))
1239 pszCmd++, cchCmd--;
1240
1241 /* external command? */
1242 bool const fExternal = *pszCmd == '.';
1243 if (fExternal)
1244 pszCmd++, cchCmd--;
1245
1246 /*
1247 * Find arguments.
1248 */
1249 char *pszArgs = pszCmd;
1250 while (RT_C_IS_ALNUM(*pszArgs))
1251 pszArgs++;
1252 if (*pszArgs && (!RT_C_IS_BLANK(*pszArgs) || pszArgs == pszCmd))
1253 {
1254 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Syntax error: Invalid command '%s'!\n", pszCmdInput);
1255 return pDbgc->rcCmd = VERR_DBGC_PARSE_INVALD_COMMAND_NAME;
1256 }
1257
1258 /*
1259 * Find the command.
1260 */
1261 PCDBGCCMD pCmd = dbgcCommandLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
1262 if (!pCmd)
1263 {
1264 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Syntax error: Unknown command '%s'!\n", pszCmdInput);
1265 return pDbgc->rcCmd = VERR_DBGC_PARSE_COMMAND_NOT_FOUND;
1266 }
1267
1268 /*
1269 * Parse arguments (if any).
1270 */
1271 unsigned iArg;
1272 unsigned cArgs;
1273 int rc = dbgcProcessArguments(pDbgc, pCmd->pszCmd,
1274 pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs,
1275 pszArgs, &iArg, &cArgs);
1276 if (RT_SUCCESS(rc))
1277 {
1278 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1279
1280 /*
1281 * Execute the command.
1282 */
1283 if (!fNoExecute)
1284 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[iArg], cArgs);
1285 pDbgc->rcCmd = rc;
1286 pDbgc->iArg = iArg;
1287 if (rc == VERR_DBGC_COMMAND_FAILED)
1288 rc = VINF_SUCCESS;
1289 }
1290 else
1291 {
1292 pDbgc->rcCmd = rc;
1293 pDbgc->iArg = iArg;
1294
1295 /* report parse / eval error. */
1296 switch (rc)
1297 {
1298 case VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS:
1299 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1300 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
1301 break;
1302 case VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS:
1303 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1304 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
1305 break;
1306 case VERR_DBGC_PARSE_ARGUMENT_OVERFLOW:
1307 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1308 "Syntax error: Too many arguments.\n");
1309 break;
1310 case VERR_DBGC_PARSE_UNBALANCED_QUOTE:
1311 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1312 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
1313 break;
1314 case VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS:
1315 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1316 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
1317 break;
1318 case VERR_DBGC_PARSE_EMPTY_ARGUMENT:
1319 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1320 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
1321 break;
1322 case VERR_DBGC_PARSE_UNEXPECTED_OPERATOR:
1323 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1324 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
1325 break;
1326 case VERR_DBGC_PARSE_INVALID_NUMBER:
1327 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1328 "Syntax error: Invalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
1329 break;
1330 case VERR_DBGC_PARSE_NUMBER_TOO_BIG:
1331 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1332 "Error: Numeric overflow (argument %d).\n", cArgs);
1333 break;
1334 case VERR_DBGC_PARSE_INVALID_OPERATION:
1335 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1336 "Error: Invalid operation attempted (argument %d).\n", cArgs);
1337 break;
1338 case VERR_DBGC_PARSE_FUNCTION_NOT_FOUND:
1339 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1340 "Error: Function not found (argument %d).\n", cArgs);
1341 break;
1342 case VERR_DBGC_PARSE_NOT_A_FUNCTION:
1343 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1344 "Error: The function specified is not a function (argument %d).\n", cArgs);
1345 break;
1346 case VERR_DBGC_PARSE_NO_MEMORY:
1347 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1348 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
1349 break;
1350 case VERR_DBGC_PARSE_INCORRECT_ARG_TYPE:
1351 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1352 "Error: Incorrect argument type (argument %d?).\n", cArgs);
1353 break;
1354 case VERR_DBGC_PARSE_VARIABLE_NOT_FOUND:
1355 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1356 "Error: An undefined variable was referenced (argument %d).\n", cArgs);
1357 break;
1358 case VERR_DBGC_PARSE_CONVERSION_FAILED:
1359 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1360 "Error: A conversion between two types failed (argument %d).\n", cArgs);
1361 break;
1362 case VERR_DBGC_PARSE_NOT_IMPLEMENTED:
1363 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1364 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
1365 break;
1366 case VERR_DBGC_PARSE_BAD_RESULT_TYPE:
1367 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1368 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
1369 break;
1370 case VERR_DBGC_PARSE_WRITEONLY_SYMBOL:
1371 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1372 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
1373 break;
1374
1375 case VERR_DBGC_COMMAND_FAILED:
1376 break;
1377
1378 default:
1379 {
1380 PCRTSTATUSMSG pErr = RTErrGet(rc);
1381 if (strncmp(pErr->pszDefine, RT_STR_TUPLE("Unknown Status")))
1382 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Error: %s (%d) - %s\n", pErr->pszDefine, rc, pErr->pszMsgFull);
1383 else
1384 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Error: Unknown error %d (%#x)!\n", rc, rc);
1385 break;
1386 }
1387 }
1388 }
1389
1390 return rc;
1391}
1392
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette