tools/*: remove bcc and as86 as they are no longer required to compile the system...
[virtualbox.git] / src / VBox / Debugger / DBGCEval.cpp
blob12ee80142bd4bb8c7de68a1eb5b2dca277918afc
1 /* $Id$ */
2 /** @file
3 * DBGC - Debugger Console, command evaluator.
4 */
6 /*
7 * Copyright (C) 2006-2012 Oracle Corporation
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. 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.
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>
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>
32 #include "DBGCInternal.h"
34 /** Rewrite in progress. */
35 #define BETTER_ARGUMENT_MATCHING
38 /*******************************************************************************
39 * Global Variables *
40 *******************************************************************************/
41 /** Bitmap where set bits indicates the characters the may start an operator name. */
42 static uint32_t g_bmOperatorChars[256 / (4*8)];
45 /*******************************************************************************
46 * Internal Functions *
47 *******************************************************************************/
48 static int dbgcCheckAndTypePromoteArgument(PDBGC pDbgc, DBGCVARCAT enmCategory, PDBGCVAR pArg);
49 static int dbgcProcessArguments(PDBGC pDbgc, const char *pszCmdOrFunc,
50 uint32_t const cArgsMin, uint32_t const cArgsMax,
51 PCDBGCVARDESC const paVarDescs, uint32_t const cVarDescs,
52 char *pszArgs, unsigned *piArg, unsigned *pcArgs);
56 /**
57 * Initializes g_bmOperatorChars.
59 void dbgcEvalInit(void)
61 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
62 for (unsigned iOp = 0; iOp < g_cDbgcOps; iOp++)
63 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aDbgcOps[iOp].szName[0]);
67 /**
68 * Checks whether the character may be the start of an operator.
70 * @returns true/false.
71 * @param ch The character.
73 DECLINLINE(bool) dbgcIsOpChar(char ch)
75 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
79 /**
80 * Returns the amount of free scratch space.
82 * @returns Number of unallocated bytes.
83 * @param pDbgc The DBGC instance.
85 size_t dbgcGetFreeScratchSpace(PDBGC pDbgc)
87 return sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
91 /**
92 * Allocates a string from the scratch space.
94 * @returns Pointer to the allocated string buffer, NULL if out of space.
95 * @param pDbgc The DBGC instance.
96 * @param cbRequested The number of bytes to allocate.
98 char *dbgcAllocStringScatch(PDBGC pDbgc, size_t cbRequested)
100 if (cbRequested > dbgcGetFreeScratchSpace(pDbgc))
101 return NULL;
102 char *psz = pDbgc->pszScratch;
103 pDbgc->pszScratch += cbRequested;
104 return psz;
109 * Evals an expression into a string or symbol (single quotes).
111 * The string memory is allocated from the scratch buffer.
113 * @returns VBox status code.
114 * @param pDbgc The DBGC instance.
115 * @param pachExpr The string/symbol expression.
116 * @param cchExpr The length of the expression.
117 * @param pArg Where to return the string.
119 static int dbgcEvalSubString(PDBGC pDbgc, const char *pachExpr, size_t cchExpr, PDBGCVAR pArg)
121 Log2(("dbgcEvalSubString: cchExpr=%d pachExpr=%.*s\n", cchExpr, cchExpr, pachExpr));
124 * Allocate scratch space for the string.
126 char *pszCopy = dbgcAllocStringScatch(pDbgc, cchExpr + 1);
127 if (!pszCopy)
128 return VERR_DBGC_PARSE_NO_SCRATCH;
131 * Removing any quoting and escapings.
133 char const chQuote = *pachExpr;
134 if (chQuote == '"' || chQuote == '\'')
136 if (pachExpr[--cchExpr] != chQuote)
137 return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
139 cchExpr--;
140 pachExpr++;
141 if (!memchr(pachExpr, chQuote, cchExpr))
142 memcpy(pszCopy, pachExpr, cchExpr);
143 else
145 size_t offSrc = 0;
146 size_t offDst = 0;
147 while (offSrc < cchExpr)
149 char const ch = pachExpr[offSrc++];
150 if (ch == chQuote)
152 if (pachExpr[offSrc] != ch)
153 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
154 offSrc++;
156 pszCopy[offDst++] = ch;
160 else
161 memcpy(pszCopy, pachExpr, cchExpr);
162 pszCopy[cchExpr] = '\0';
165 * Make the argument.
167 pArg->pDesc = NULL;
168 pArg->pNext = NULL;
169 pArg->enmType = chQuote == '"' ? DBGCVAR_TYPE_STRING : DBGCVAR_TYPE_SYMBOL;
170 pArg->u.pszString = pszCopy;
171 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;
172 pArg->u64Range = cchExpr;
174 NOREF(pDbgc);
175 return VINF_SUCCESS;
179 static int dbgcEvalSubNum(const char *pachExpr, size_t cchExpr, unsigned uBase, PDBGCVAR pArg)
181 Log2(("dbgcEvalSubNum: uBase=%d pachExpr=%.*s\n", uBase, cchExpr, pachExpr));
184 * Empty expressions cannot be valid numbers.
186 if (!cchExpr)
187 return VERR_DBGC_PARSE_INVALID_NUMBER;
190 * Convert to number.
192 uint64_t u64 = 0;
193 while (cchExpr-- > 0)
195 char const ch = *pachExpr;
196 uint64_t u64Prev = u64;
197 unsigned u = ch - '0';
198 if (u < 10 && u < uBase)
199 u64 = u64 * uBase + u;
200 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
201 u64 = u64 * uBase + u;
202 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
203 u64 = u64 * uBase + u;
204 else
205 return VERR_DBGC_PARSE_INVALID_NUMBER;
207 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
208 if (u64Prev != u64 / uBase)
209 return VERR_DBGC_PARSE_NUMBER_TOO_BIG;
211 /* next */
212 pachExpr++;
216 * Initialize the argument.
218 pArg->pDesc = NULL;
219 pArg->pNext = NULL;
220 pArg->enmType = DBGCVAR_TYPE_NUMBER;
221 pArg->u.u64Number = u64;
222 pArg->enmRangeType = DBGCVAR_RANGE_NONE;
223 pArg->u64Range = 0;
225 return VINF_SUCCESS;
230 * dbgcEvalSubUnary worker that handles simple numeric or pointer expressions.
232 * @returns VBox status code. pResult contains the result on success.
233 * @param pDbgc Debugger console instance data.
234 * @param pszExpr The expression string.
235 * @param cchExpr The length of the expression.
236 * @param enmCategory The desired type category (for range / no range).
237 * @param pResult Where to store the result of the expression evaluation.
239 static int dbgcEvalSubNumericOrPointer(PDBGC pDbgc, char *pszExpr, size_t cchExpr, DBGCVARCAT enmCategory,
240 PDBGCVAR pResult)
242 char const ch = pszExpr[0];
243 char const ch2 = pszExpr[1];
245 /* 0x<hex digits> */
246 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
247 return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 16, pResult);
249 /* <hex digits>h */
250 if (RT_C_IS_XDIGIT(*pszExpr) && (pszExpr[cchExpr - 1] == 'h' || pszExpr[cchExpr - 1] == 'H'))
252 pszExpr[cchExpr] = '\0';
253 return dbgcEvalSubNum(pszExpr, cchExpr - 1, 16, pResult);
256 /* 0i<decimal digits> */
257 if (ch == '0' && ch2 == 'i')
258 return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 10, pResult);
260 /* 0t<octal digits> */
261 if (ch == '0' && ch2 == 't')
262 return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 8, pResult);
264 /* 0y<binary digits> */
265 if (ch == '0' && ch2 == 'y')
266 return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 10, pResult);
268 /* Hex number? */
269 unsigned off = 0;
270 while (off < cchExpr && (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`'))
271 off++;
272 if (off == cchExpr)
273 return dbgcEvalSubNum(pszExpr, cchExpr, 16, pResult);
276 * Some kind of symbol? Rejected double quoted strings, only unquoted
277 * and single quoted strings will be considered as symbols.
279 DBGCVARTYPE enmType;
280 bool fStripRange = false;
281 switch (enmCategory)
283 case DBGCVAR_CAT_POINTER_NUMBER: enmType = DBGCVAR_TYPE_NUMBER; break;
284 case DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE: enmType = DBGCVAR_TYPE_NUMBER; fStripRange = true; break;
285 case DBGCVAR_CAT_POINTER: enmType = DBGCVAR_TYPE_NUMBER; break;
286 case DBGCVAR_CAT_POINTER_NO_RANGE: enmType = DBGCVAR_TYPE_NUMBER; fStripRange = true; break;
287 case DBGCVAR_CAT_GC_POINTER: enmType = DBGCVAR_TYPE_GC_FLAT; break;
288 case DBGCVAR_CAT_GC_POINTER_NO_RANGE: enmType = DBGCVAR_TYPE_GC_FLAT; fStripRange = true; break;
289 case DBGCVAR_CAT_NUMBER: enmType = DBGCVAR_TYPE_NUMBER; break;
290 case DBGCVAR_CAT_NUMBER_NO_RANGE: enmType = DBGCVAR_TYPE_NUMBER; fStripRange = true; break;
291 default:
292 AssertFailedReturn(VERR_DBGC_PARSE_NOT_IMPLEMENTED);
295 char const chQuote = *pszExpr;
296 if (chQuote == '"')
297 return VERR_DBGC_PARSE_INVALID_NUMBER;
299 if (chQuote == '\'')
301 if (pszExpr[cchExpr - 1] != chQuote)
302 return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
303 pszExpr[cchExpr - 1] = '\0';
304 pszExpr++;
307 int rc = dbgcSymbolGet(pDbgc, pszExpr, enmType, pResult);
308 if (RT_SUCCESS(rc))
310 if (fStripRange)
312 pResult->enmRangeType = DBGCVAR_RANGE_NONE;
313 pResult->u64Range = 0;
316 else if (rc == VERR_DBGC_PARSE_NOT_IMPLEMENTED)
317 rc = VERR_DBGC_PARSE_INVALID_NUMBER;
318 return rc;
323 * dbgcEvalSubUnary worker that handles simple DBGCVAR_CAT_ANY expressions.
325 * @returns VBox status code. pResult contains the result on success.
326 * @param pDbgc Debugger console instance data.
327 * @param pszExpr The expression string.
328 * @param cchExpr The length of the expression.
329 * @param pResult Where to store the result of the expression evaluation.
331 static int dbgcEvalSubUnaryAny(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
333 char const ch = pszExpr[0];
334 char const ch2 = pszExpr[1];
335 unsigned off = 2;
337 /* 0x<hex digits> */
338 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
340 while (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`')
341 off++;
342 if (off == cchExpr)
343 return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 16, pResult);
344 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
347 /* <hex digits>h */
348 if (RT_C_IS_XDIGIT(*pszExpr) && (pszExpr[cchExpr - 1] == 'h' || pszExpr[cchExpr - 1] == 'H'))
350 cchExpr--;
351 while (off < cchExpr && (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`'))
352 off++;
353 if (off == cchExpr)
355 pszExpr[cchExpr] = '\0';
356 return dbgcEvalSubNum(pszExpr, cchExpr, 16, pResult);
358 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr + 1, pResult);
361 /* 0n<decimal digits> or 0i<decimal digits> */
362 if (ch == '0' && (ch2 == 'n' || ch2 == 'i'))
364 while (RT_C_IS_DIGIT(pszExpr[off]) || pszExpr[off] == '`')
365 off++;
366 if (off == cchExpr)
367 return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 10, pResult);
368 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
371 /* 0t<octal digits> */
372 if (ch == '0' && ch2 == 't')
374 while (RT_C_IS_ODIGIT(pszExpr[off]) || pszExpr[off] == '`')
375 off++;
376 if (off == cchExpr)
377 return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 8, pResult);
378 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
381 /* 0y<binary digits> */
382 if (ch == '0' && ch2 == 'y')
384 while (pszExpr[off] == '0' || pszExpr[off] == '1' || pszExpr[off] == '`')
385 off++;
386 if (off == cchExpr)
387 return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 10, pResult);
388 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
391 /* Ok, no prefix of suffix. Is it a hex number after all? If not it must
392 be a string. */
393 off = 0;
394 while (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`')
395 off++;
396 if (off == cchExpr)
397 return dbgcEvalSubNum(pszExpr, cchExpr, 16, pResult);
398 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
403 * Handles a call.
405 * @returns VBox status code. pResult contains the result on success.
406 * @param pDbgc The DBGC instance.
407 * @param pszFuncNm The function name.
408 * @param cchFuncNm The length of the function name.
409 * @param fExternal Whether it's an external name.
410 * @param pszArgs The start of the arguments (after parenthesis).
411 * @param cchArgs The length for the argument (exclusing
412 * parentesis).
413 * @param enmCategory The desired category of the result (ignored).
414 * @param pResult The result.
416 static int dbgcEvalSubCall(PDBGC pDbgc, char *pszFuncNm, size_t cchFuncNm, bool fExternal, char *pszArgs, size_t cchArgs,
417 DBGCVARCAT enmCategory, PDBGCVAR pResult)
420 * Lookup the function.
422 PCDBGCFUNC pFunc = dbgcFunctionLookup(pDbgc, pszFuncNm, cchFuncNm, fExternal);
423 if (!pFunc)
424 return VERR_DBGC_PARSE_FUNCTION_NOT_FOUND;
427 * Parse the arguments.
429 unsigned cArgs;
430 unsigned iArg;
431 pszArgs[cchArgs] = '\0';
432 int rc = dbgcProcessArguments(pDbgc, pFunc->pszFuncNm,
433 pFunc->cArgsMin, pFunc->cArgsMax, pFunc->paArgDescs, pFunc->cArgDescs,
434 pszArgs, &iArg, &cArgs);
435 if (RT_SUCCESS(rc))
436 rc = pFunc->pfnHandler(pFunc, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[iArg], cArgs, pResult);
437 pDbgc->iArg = iArg;
438 return rc;
443 * Evaluates one argument with respect to unary operators.
445 * @returns VBox status code. pResult contains the result on success.
447 * @param pDbgc Debugger console instance data.
448 * @param pszExpr The expression string.
449 * @param cchExpr The length of the expression.
450 * @param enmCategory The target category for the result.
451 * @param pResult Where to store the result of the expression evaluation.
453 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, DBGCVARCAT enmCategory, PDBGCVAR pResult)
455 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
458 * The state of the expression is now such that it will start by zero or more
459 * unary operators and being followed by an expression of some kind.
460 * The expression is either plain or in parenthesis.
462 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
463 * ASSUME: unary operators are all of equal precedence.
465 int rc = VINF_SUCCESS;
466 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
467 if (pOp)
469 /* binary operators means syntax error. */
470 if (pOp->fBinary)
471 return VERR_DBGC_PARSE_UNEXPECTED_OPERATOR;
474 * If the next expression (the one following the unary operator) is in a
475 * parenthesis a full eval is needed. If not the unary eval will suffice.
477 /* calc and strip next expr. */
478 char *pszExpr2 = pszExpr + pOp->cchName;
479 while (RT_C_IS_BLANK(*pszExpr2))
480 pszExpr2++;
482 if (*pszExpr2)
484 DBGCVAR Arg;
485 if (*pszExpr2 == '(')
486 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), pOp->enmCatArg1, &Arg);
487 else
488 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), pOp->enmCatArg1, &Arg);
489 if (RT_SUCCESS(rc))
490 rc = dbgcCheckAndTypePromoteArgument(pDbgc, pOp->enmCatArg1, &Arg);
491 if (RT_SUCCESS(rc))
492 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, enmCategory, pResult);
494 else
495 rc = VERR_DBGC_PARSE_EMPTY_ARGUMENT;
496 return rc;
500 * Could this be a function call?
502 * ASSUMPTIONS:
503 * - A function name only contains alphanumerical chars and it can not
504 * start with a numerical character.
505 * - Immediately following the name is a parenthesis which must cover
506 * the remaining part of the expression.
508 bool fExternal = *pszExpr == '.';
509 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;
510 char *pszFunEnd = NULL;
511 if (pszExpr[cchExpr - 1] == ')' && RT_C_IS_ALPHA(*pszFun))
513 pszFunEnd = pszExpr + 1;
514 while (*pszFunEnd != '(' && RT_C_IS_ALNUM(*pszFunEnd))
515 pszFunEnd++;
516 if (*pszFunEnd != '(')
517 pszFunEnd = NULL;
519 if (pszFunEnd)
521 size_t cchFunNm = pszFunEnd - pszFun;
522 return dbgcEvalSubCall(pDbgc, pszFun, cchFunNm, fExternal, pszFunEnd + 1, cchExpr - cchFunNm - fExternal - 2,
523 enmCategory, pResult);
527 * Assuming plain expression.
528 * Didn't find any operators, so it must be a plain expression.
529 * Go by desired category first, then if anythings go, try guess.
531 switch (enmCategory)
533 case DBGCVAR_CAT_ANY:
534 return dbgcEvalSubUnaryAny(pDbgc, pszExpr, cchExpr, pResult);
536 case DBGCVAR_CAT_POINTER_NUMBER:
537 case DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE:
538 case DBGCVAR_CAT_POINTER:
539 case DBGCVAR_CAT_POINTER_NO_RANGE:
540 case DBGCVAR_CAT_GC_POINTER:
541 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
542 case DBGCVAR_CAT_NUMBER:
543 case DBGCVAR_CAT_NUMBER_NO_RANGE:
544 /* Pointers will be promoted later. */
545 return dbgcEvalSubNumericOrPointer(pDbgc, pszExpr, cchExpr, enmCategory, pResult);
547 case DBGCVAR_CAT_STRING:
548 case DBGCVAR_CAT_SYMBOL:
549 /* Symbols will be promoted later. */
550 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
552 case DBGCVAR_CAT_OPTION:
553 case DBGCVAR_CAT_OPTION_STRING:
554 case DBGCVAR_CAT_OPTION_NUMBER:
555 return VERR_DBGC_PARSE_NOT_IMPLEMENTED;
558 AssertMsgFailed(("enmCategory=%d\n", enmCategory));
559 return VERR_NOT_IMPLEMENTED;
564 * Evaluates one argument.
566 * @returns VBox status code.
568 * @param pDbgc Debugger console instance data.
569 * @param pszExpr The expression string.
570 * @param enmCategory The target category for the result.
571 * @param pResult Where to store the result of the expression evaluation.
573 int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, DBGCVARCAT enmCategory, PDBGCVAR pResult)
575 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
578 * First we need to remove blanks in both ends.
579 * ASSUMES: There is no quoting unless the entire expression is a string.
582 /* stripping. */
583 while (cchExpr > 0 && RT_C_IS_BLANK(pszExpr[cchExpr - 1]))
584 pszExpr[--cchExpr] = '\0';
585 while (RT_C_IS_BLANK(*pszExpr))
586 pszExpr++, cchExpr--;
587 if (!*pszExpr)
588 return VERR_DBGC_PARSE_EMPTY_ARGUMENT;
591 * Check if there are any parenthesis which needs removing.
593 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
597 unsigned cPar = 1;
598 char *psz = pszExpr + 1;
599 char ch;
600 while ((ch = *psz) != '\0')
602 if (ch == '(')
603 cPar++;
604 else if (ch == ')')
606 if (cPar <= 0)
607 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
608 cPar--;
609 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
610 break;
612 /* next */
613 psz++;
615 if (ch)
616 break;
618 /* remove the parenthesis. */
619 pszExpr++;
620 cchExpr -= 2;
621 pszExpr[cchExpr] = '\0';
623 /* strip blanks. */
624 while (cchExpr > 0 && RT_C_IS_BLANK(pszExpr[cchExpr - 1]))
625 pszExpr[--cchExpr] = '\0';
626 while (RT_C_IS_BLANK(*pszExpr))
627 pszExpr++, cchExpr--;
628 if (!*pszExpr)
629 return VERR_DBGC_PARSE_EMPTY_ARGUMENT;
630 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
634 * Now, we need to look for the binary operator with the lowest precedence.
636 * If there are no operators we're left with a simple expression which we
637 * evaluate with respect to unary operators
639 char *pszOpSplit = NULL;
640 PCDBGCOP pOpSplit = NULL;
641 unsigned cBinaryOps = 0;
642 unsigned cPar = 0;
643 unsigned cchWord = 0;
644 char chQuote = '\0';
645 char chPrev = ' ';
646 bool fBinary = false;
647 char *psz = pszExpr;
648 char ch;
650 while ((ch = *psz) != '\0')
653 * String quoting.
655 if (chQuote)
657 if (ch == chQuote)
659 if (psz[1] == chQuote)
661 psz++; /* escaped quote */
662 cchWord++;
664 else
666 chQuote = '\0';
667 fBinary = true;
668 cchWord = 0;
671 else
672 cchWord++;
674 else if (ch == '"' || ch == '\'')
676 if (fBinary || cchWord)
677 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
678 chQuote = ch;
681 * Parentheses.
683 else if (ch == '(')
685 if (!cPar && fBinary && !cchWord)
686 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
687 cPar++;
688 fBinary = false;
689 cchWord = 0;
691 else if (ch == ')')
693 if (cPar <= 0)
694 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
695 cPar--;
696 fBinary = true;
697 cchWord = 0;
700 * Potential operator.
702 else if (cPar == 0 && !RT_C_IS_BLANK(ch))
704 PCDBGCOP pOp = dbgcIsOpChar(ch)
705 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
706 : NULL;
707 if (pOp)
709 /* If not the right kind of operator we've got a syntax error. */
710 if (pOp->fBinary != fBinary)
711 return VERR_DBGC_PARSE_UNEXPECTED_OPERATOR;
714 * Update the parse state and skip the operator.
716 if (!pOpSplit)
718 pOpSplit = pOp;
719 pszOpSplit = psz;
720 cBinaryOps = fBinary;
722 else if (fBinary)
724 cBinaryOps++;
725 if (pOp->iPrecedence >= pOpSplit->iPrecedence)
727 pOpSplit = pOp;
728 pszOpSplit = psz;
732 psz += pOp->cchName - 1;
733 fBinary = false;
734 cchWord = 0;
736 else if (fBinary && !cchWord)
737 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
738 else
740 fBinary = true;
741 cchWord++;
744 else if (cPar == 0 && RT_C_IS_BLANK(ch))
745 cchWord++;
747 /* next */
748 psz++;
749 chPrev = ch;
750 } /* parse loop. */
752 if (chQuote)
753 return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
756 * Either we found an operator to divide the expression by or we didn't
757 * find any. In the first case it's divide and conquer. In the latter
758 * it's a single expression which needs dealing with its unary operators
759 * if any.
761 int rc;
762 if ( cBinaryOps
763 && pOpSplit->fBinary)
765 /* process 1st sub expression. */
766 *pszOpSplit = '\0';
767 DBGCVAR Arg1;
768 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, pOpSplit->enmCatArg1, &Arg1);
769 if (RT_SUCCESS(rc))
771 /* process 2nd sub expression. */
772 char *psz2 = pszOpSplit + pOpSplit->cchName;
773 DBGCVAR Arg2;
774 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), pOpSplit->enmCatArg2, &Arg2);
775 if (RT_SUCCESS(rc))
776 rc = dbgcCheckAndTypePromoteArgument(pDbgc, pOpSplit->enmCatArg1, &Arg1);
777 if (RT_SUCCESS(rc))
778 rc = dbgcCheckAndTypePromoteArgument(pDbgc, pOpSplit->enmCatArg2, &Arg2);
779 if (RT_SUCCESS(rc))
780 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
783 else if (cBinaryOps)
785 /* process sub expression. */
786 pszOpSplit += pOpSplit->cchName;
787 DBGCVAR Arg;
788 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), pOpSplit->enmCatArg1, &Arg);
789 if (RT_SUCCESS(rc))
790 rc = dbgcCheckAndTypePromoteArgument(pDbgc, pOpSplit->enmCatArg1, &Arg);
791 if (RT_SUCCESS(rc))
792 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, enmCategory, pResult);
794 else
795 /* plain expression, qutoed string, or using unary operators perhaps with parentheses. */
796 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, enmCategory, pResult);
798 return rc;
803 * Worker for dbgcProcessArguments that performs type checking and promoptions.
805 * @returns VBox status code.
807 * @param pDbgc Debugger console instance data.
808 * @param enmCategory The target category for the result.
809 * @param pArg The argument to check and promote.
811 static int dbgcCheckAndTypePromoteArgument(PDBGC pDbgc, DBGCVARCAT enmCategory, PDBGCVAR pArg)
813 switch (enmCategory)
816 * Anything goes
818 case DBGCVAR_CAT_ANY:
819 return VINF_SUCCESS;
822 * Pointer with and without range.
823 * We can try resolve strings and symbols as symbols and promote
824 * numbers to flat GC pointers.
826 case DBGCVAR_CAT_POINTER_NO_RANGE:
827 case DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE:
828 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
829 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED;
830 /* fallthru */
831 case DBGCVAR_CAT_POINTER:
832 case DBGCVAR_CAT_POINTER_NUMBER:
833 switch (pArg->enmType)
835 case DBGCVAR_TYPE_GC_FLAT:
836 case DBGCVAR_TYPE_GC_FAR:
837 case DBGCVAR_TYPE_GC_PHYS:
838 case DBGCVAR_TYPE_HC_FLAT:
839 case DBGCVAR_TYPE_HC_PHYS:
840 return VINF_SUCCESS;
842 case DBGCVAR_TYPE_SYMBOL:
843 case DBGCVAR_TYPE_STRING:
845 DBGCVAR Var;
846 int rc = dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
847 if (RT_SUCCESS(rc))
849 /* deal with range */
850 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
852 Var.enmRangeType = pArg->enmRangeType;
853 Var.u64Range = pArg->u64Range;
855 else if (enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
856 Var.enmRangeType = DBGCVAR_RANGE_NONE;
857 *pArg = Var;
859 return rc;
862 case DBGCVAR_TYPE_NUMBER:
863 if ( enmCategory != DBGCVAR_CAT_POINTER_NUMBER
864 && enmCategory != DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE)
866 RTGCPTR GCPtr = (RTGCPTR)pArg->u.u64Number;
867 pArg->enmType = DBGCVAR_TYPE_GC_FLAT;
868 pArg->u.GCFlat = GCPtr;
870 return VINF_SUCCESS;
872 default:
873 AssertMsgFailedReturn(("Invalid type %d\n"), VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
875 break; /* (not reached) */
878 * GC pointer with and without range.
879 * We can try resolve strings and symbols as symbols and
880 * promote numbers to flat GC pointers.
882 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
883 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
884 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED;
885 /* fallthru */
886 case DBGCVAR_CAT_GC_POINTER:
887 switch (pArg->enmType)
889 case DBGCVAR_TYPE_GC_FLAT:
890 case DBGCVAR_TYPE_GC_FAR:
891 case DBGCVAR_TYPE_GC_PHYS:
892 return VINF_SUCCESS;
894 case DBGCVAR_TYPE_HC_FLAT:
895 case DBGCVAR_TYPE_HC_PHYS:
896 return VERR_DBGC_PARSE_CONVERSION_FAILED;
898 case DBGCVAR_TYPE_SYMBOL:
899 case DBGCVAR_TYPE_STRING:
901 DBGCVAR Var;
902 int rc = dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
903 if (RT_SUCCESS(rc))
905 /* deal with range */
906 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
908 Var.enmRangeType = pArg->enmRangeType;
909 Var.u64Range = pArg->u64Range;
911 else if (enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
912 Var.enmRangeType = DBGCVAR_RANGE_NONE;
913 *pArg = Var;
915 return rc;
918 case DBGCVAR_TYPE_NUMBER:
920 RTGCPTR GCPtr = (RTGCPTR)pArg->u.u64Number;
921 pArg->enmType = DBGCVAR_TYPE_GC_FLAT;
922 pArg->u.GCFlat = GCPtr;
923 return VINF_SUCCESS;
926 default:
927 AssertMsgFailedReturn(("Invalid type %d\n"), VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
929 break; /* (not reached) */
932 * Number with or without a range.
933 * Numbers can be resolved from symbols, but we cannot demote a pointer
934 * to a number.
936 case DBGCVAR_CAT_NUMBER_NO_RANGE:
937 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
938 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED;
939 /* fallthru */
940 case DBGCVAR_CAT_NUMBER:
941 switch (pArg->enmType)
943 case DBGCVAR_TYPE_GC_FLAT:
944 case DBGCVAR_TYPE_GC_FAR:
945 case DBGCVAR_TYPE_GC_PHYS:
946 case DBGCVAR_TYPE_HC_FLAT:
947 case DBGCVAR_TYPE_HC_PHYS:
948 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
950 case DBGCVAR_TYPE_NUMBER:
951 return VINF_SUCCESS;
953 case DBGCVAR_TYPE_SYMBOL:
954 case DBGCVAR_TYPE_STRING:
956 DBGCVAR Var;
957 int rc = dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
958 if (RT_SUCCESS(rc))
960 /* deal with range */
961 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
963 Var.enmRangeType = pArg->enmRangeType;
964 Var.u64Range = pArg->u64Range;
966 else if (enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
967 Var.enmRangeType = DBGCVAR_RANGE_NONE;
968 *pArg = Var;
970 return rc;
973 default:
974 AssertMsgFailedReturn(("Invalid type %d\n"), VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
976 break; /* (not reached) */
979 * Symbols and strings are basically the same thing for the time being.
981 case DBGCVAR_CAT_STRING:
982 case DBGCVAR_CAT_SYMBOL:
984 switch (pArg->enmType)
986 case DBGCVAR_TYPE_STRING:
987 if (enmCategory == DBGCVAR_CAT_SYMBOL)
988 pArg->enmType = DBGCVAR_TYPE_SYMBOL;
989 return VINF_SUCCESS;
991 case DBGCVAR_TYPE_SYMBOL:
992 if (enmCategory == DBGCVAR_CAT_STRING)
993 pArg->enmType = DBGCVAR_TYPE_STRING;
994 return VINF_SUCCESS;
995 default:
996 break;
999 /* Stringify numeric and pointer values. */
1000 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
1001 size_t cch = pDbgc->CmdHlp.pfnStrPrintf(&pDbgc->CmdHlp, pDbgc->pszScratch, cbScratch, "%Dv", pArg);
1002 if (cch + 1 >= cbScratch)
1003 return VERR_DBGC_PARSE_NO_SCRATCH;
1005 pArg->enmType = enmCategory == DBGCVAR_CAT_STRING ? DBGCVAR_TYPE_STRING : DBGCVAR_TYPE_SYMBOL;
1006 pArg->u.pszString = pDbgc->pszScratch;
1007 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;
1008 pArg->u64Range = cch;
1010 pDbgc->pszScratch += cch + 1;
1011 return VINF_SUCCESS;
1015 * These are not yet implemented.
1017 case DBGCVAR_CAT_OPTION:
1018 case DBGCVAR_CAT_OPTION_STRING:
1019 case DBGCVAR_CAT_OPTION_NUMBER:
1020 AssertMsgFailedReturn(("Not implemented enmCategory=%d\n", enmCategory), VERR_DBGC_PARSE_NOT_IMPLEMENTED);
1022 default:
1023 AssertMsgFailedReturn(("Bad enmCategory=%d\n", enmCategory), VERR_DBGC_PARSE_NOT_IMPLEMENTED);
1029 * Parses the arguments of one command.
1031 * @returns VBox statuc code. On parser errors the index of the troublesome
1032 * argument is indicated by *pcArg.
1034 * @param pDbgc Debugger console instance data.
1035 * @param pszCmdOrFunc The name of the function or command. (For logging.)
1036 * @param cArgsMin See DBGCCMD::cArgsMin and DBGCFUNC::cArgsMin.
1037 * @param cArgsMax See DBGCCMD::cArgsMax and DBGCFUNC::cArgsMax.
1038 * @param paVarDescs See DBGCCMD::paVarDescs and DBGCFUNC::paVarDescs.
1039 * @param cVarDescs See DBGCCMD::cVarDescs and DBGCFUNC::cVarDescs.
1040 * @param pszArg Pointer to the arguments to parse.
1041 * @param piArg Where to return the index of the first argument in
1042 * DBGC::aArgs. Always set. Caller must restore DBGC::iArg
1043 * to this value when done, even on failure.
1044 * @param pcArgs Where to store the number of arguments. In the event
1045 * of an error this is (ab)used to store the index of the
1046 * offending argument.
1048 static int dbgcProcessArguments(PDBGC pDbgc, const char *pszCmdOrFunc,
1049 uint32_t const cArgsMin, uint32_t const cArgsMax,
1050 PCDBGCVARDESC const paVarDescs, uint32_t const cVarDescs,
1051 char *pszArgs, unsigned *piArg, unsigned *pcArgs)
1053 Log2(("dbgcProcessArguments: pszCmdOrFunc=%s pszArgs='%s'\n", pszCmdOrFunc, pszArgs));
1056 * Check if we have any argument and if the command takes any.
1058 *piArg = pDbgc->iArg;
1059 *pcArgs = 0;
1060 /* strip leading blanks. */
1061 while (*pszArgs && RT_C_IS_BLANK(*pszArgs))
1062 pszArgs++;
1063 if (!*pszArgs)
1065 if (!cArgsMin)
1066 return VINF_SUCCESS;
1067 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS;
1069 if (!cArgsMax)
1070 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
1073 * The parse loop.
1075 PDBGCVAR pArg = &pDbgc->aArgs[pDbgc->iArg];
1076 PCDBGCVARDESC pPrevDesc = NULL;
1077 unsigned cCurDesc = 0;
1078 unsigned iVar = 0;
1079 unsigned iVarDesc = 0;
1080 *pcArgs = 0;
1084 * Can we have another argument?
1086 if (*pcArgs >= cArgsMax)
1087 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
1088 if (pDbgc->iArg >= RT_ELEMENTS(pDbgc->aArgs))
1089 return VERR_DBGC_PARSE_ARGUMENT_OVERFLOW;
1090 if (iVarDesc >= cVarDescs)
1091 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
1093 /* Walk argument descriptors. */
1094 if (cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
1096 iVarDesc++;
1097 if (iVarDesc >= cVarDescs)
1098 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
1099 cCurDesc = 0;
1103 * Find the end of the argument. This is just rough splitting,
1104 * dbgcEvalSub will do stricter syntax checking later on.
1106 int cPar = 0;
1107 char chQuote = '\0';
1108 char *pszEnd = NULL;
1109 char *psz = pszArgs;
1110 char ch;
1111 bool fBinary = false;
1112 for (;;)
1115 * Check for the end.
1117 if ((ch = *psz) == '\0')
1119 if (chQuote)
1120 return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
1121 if (cPar)
1122 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
1123 pszEnd = psz;
1124 break;
1127 * When quoted we ignore everything but the quotation char.
1128 * We use the REXX way of escaping the quotation char, i.e. double occurrence.
1130 else if (chQuote)
1132 if (ch == chQuote)
1134 if (psz[1] == chQuote)
1135 psz++; /* skip the escaped quote char */
1136 else
1138 chQuote = '\0'; /* end of quoted string. */
1139 fBinary = true;
1143 else if (ch == '\'' || ch == '"')
1145 if (fBinary)
1146 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
1147 chQuote = ch;
1150 * Parenthesis can of course be nested.
1152 else if (ch == '(')
1154 cPar++;
1155 fBinary = false;
1157 else if (ch == ')')
1159 if (!cPar)
1160 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
1161 cPar--;
1162 fBinary = true;
1164 else if (!cPar)
1167 * Encountering a comma is a definite end of parameter.
1169 if (ch == ',')
1171 pszEnd = psz++;
1172 break;
1176 * Encountering blanks may mean the end of it all. A binary
1177 * operator will force continued parsing.
1179 if (RT_C_IS_BLANK(ch))
1181 pszEnd = psz++; /* in case it's the end. */
1182 while (RT_C_IS_BLANK(*psz))
1183 psz++;
1185 if (*psz == ',')
1187 psz++;
1188 break;
1191 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1192 if (!pOp || pOp->fBinary != fBinary)
1193 break; /* the end. */
1195 psz += pOp->cchName;
1196 while (RT_C_IS_BLANK(*psz)) /* skip blanks so we don't get here again */
1197 psz++;
1198 fBinary = false;
1199 continue;
1203 * Look for operators without a space up front.
1205 if (dbgcIsOpChar(ch))
1207 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1208 if (pOp)
1210 if (pOp->fBinary != fBinary)
1212 pszEnd = psz;
1213 /** @todo this is a parsing error really. */
1214 break; /* the end. */
1216 psz += pOp->cchName;
1217 while (RT_C_IS_BLANK(*psz)) /* skip blanks so we don't get here again */
1218 psz++;
1219 fBinary = false;
1220 continue;
1223 fBinary = true;
1226 /* next char */
1227 psz++;
1229 *pszEnd = '\0';
1230 /* (psz = next char to process) */
1231 size_t cchArgs = strlen(pszArgs);
1234 * Try optional arguments until we find something which matches
1235 * or can easily be promoted to what the descriptor want.
1237 for (;;)
1239 char *pszArgsCopy = (char *)RTMemDup(pszArgs, cchArgs + 1);
1240 if (!pszArgsCopy)
1241 return VERR_DBGC_PARSE_NO_MEMORY;
1243 int rc = dbgcEvalSub(pDbgc, pszArgs, cchArgs, paVarDescs[iVarDesc].enmCategory, pArg);
1244 if (RT_SUCCESS(rc))
1245 rc = dbgcCheckAndTypePromoteArgument(pDbgc, paVarDescs[iVarDesc].enmCategory, pArg);
1246 if (RT_SUCCESS(rc))
1248 pArg->pDesc = pPrevDesc = &paVarDescs[iVarDesc];
1249 cCurDesc++;
1250 RTMemFree(pszArgsCopy);
1251 break;
1254 memcpy(pszArgs, pszArgsCopy, cchArgs + 1);
1255 RTMemFree(pszArgsCopy);
1257 /* Continue searching optional descriptors? */
1258 if ( rc != VERR_DBGC_PARSE_INCORRECT_ARG_TYPE
1259 && rc != VERR_DBGC_PARSE_INVALID_NUMBER
1260 && rc != VERR_DBGC_PARSE_NO_RANGE_ALLOWED
1262 return rc;
1264 /* Try advance to the next descriptor. */
1265 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
1266 return rc;
1267 iVarDesc++;
1268 if (!cCurDesc)
1269 while ( iVarDesc < cVarDescs
1270 && (paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV))
1271 iVarDesc++;
1272 if (iVarDesc >= cVarDescs)
1273 return rc;
1274 cCurDesc = 0;
1278 * Next argument.
1280 iVar++;
1281 pArg++;
1282 pDbgc->iArg++;
1283 *pcArgs += 1;
1284 pszArgs = psz;
1285 while (*pszArgs && RT_C_IS_BLANK(*pszArgs))
1286 pszArgs++;
1287 } while (*pszArgs);
1290 * Check that the rest of the argument descriptors indicate optional args.
1292 if (iVarDesc < cVarDescs)
1294 if (cCurDesc < paVarDescs[iVarDesc].cTimesMin)
1295 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS;
1296 iVarDesc++;
1297 while (iVarDesc < cVarDescs)
1299 if (paVarDescs[iVarDesc].cTimesMin)
1300 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS;
1301 iVarDesc++;
1305 return VINF_SUCCESS;
1310 * Evaluate one command.
1312 * @returns VBox status code. This is also stored in DBGC::rcCmd.
1314 * @param pDbgc Debugger console instance data.
1315 * @param pszCmd Pointer to the command.
1316 * @param cchCmd Length of the command.
1317 * @param fNoExecute Indicates that no commands should actually be executed.
1319 int dbgcEvalCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd, bool fNoExecute)
1321 char *pszCmdInput = pszCmd;
1324 * Skip blanks.
1326 while (RT_C_IS_BLANK(*pszCmd))
1327 pszCmd++, cchCmd--;
1329 /* external command? */
1330 bool const fExternal = *pszCmd == '.';
1331 if (fExternal)
1332 pszCmd++, cchCmd--;
1335 * Find arguments.
1337 char *pszArgs = pszCmd;
1338 while (RT_C_IS_ALNUM(*pszArgs) || *pszArgs == '_')
1339 pszArgs++;
1340 if ( (*pszArgs && !RT_C_IS_BLANK(*pszArgs))
1341 || !RT_C_IS_ALPHA(*pszCmd))
1343 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Syntax error: Invalid command '%s'!\n", pszCmdInput);
1344 return pDbgc->rcCmd = VERR_DBGC_PARSE_INVALD_COMMAND_NAME;
1348 * Find the command.
1350 PCDBGCCMD pCmd = dbgcCommandLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
1351 if (!pCmd)
1353 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Syntax error: Unknown command '%s'!\n", pszCmdInput);
1354 return pDbgc->rcCmd = VERR_DBGC_PARSE_COMMAND_NOT_FOUND;
1358 * Parse arguments (if any).
1360 unsigned iArg;
1361 unsigned cArgs;
1362 int rc = dbgcProcessArguments(pDbgc, pCmd->pszCmd,
1363 pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs,
1364 pszArgs, &iArg, &cArgs);
1365 if (RT_SUCCESS(rc))
1367 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1370 * Execute the command.
1372 if (!fNoExecute)
1373 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[iArg], cArgs);
1374 pDbgc->rcCmd = rc;
1375 pDbgc->iArg = iArg;
1376 if (rc == VERR_DBGC_COMMAND_FAILED)
1377 rc = VINF_SUCCESS;
1379 else
1381 pDbgc->rcCmd = rc;
1382 pDbgc->iArg = iArg;
1384 /* report parse / eval error. */
1385 switch (rc)
1387 case VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS:
1388 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1389 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
1390 break;
1391 case VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS:
1392 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1393 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
1394 break;
1395 case VERR_DBGC_PARSE_ARGUMENT_OVERFLOW:
1396 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1397 "Syntax error: Too many arguments.\n");
1398 break;
1399 case VERR_DBGC_PARSE_UNBALANCED_QUOTE:
1400 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1401 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
1402 break;
1403 case VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS:
1404 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1405 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
1406 break;
1407 case VERR_DBGC_PARSE_EMPTY_ARGUMENT:
1408 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1409 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
1410 break;
1411 case VERR_DBGC_PARSE_UNEXPECTED_OPERATOR:
1412 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1413 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
1414 break;
1415 case VERR_DBGC_PARSE_INVALID_NUMBER:
1416 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1417 "Syntax error: Invalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
1418 break;
1419 case VERR_DBGC_PARSE_NUMBER_TOO_BIG:
1420 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1421 "Error: Numeric overflow (argument %d).\n", cArgs);
1422 break;
1423 case VERR_DBGC_PARSE_INVALID_OPERATION:
1424 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1425 "Error: Invalid operation attempted (argument %d).\n", cArgs);
1426 break;
1427 case VERR_DBGC_PARSE_FUNCTION_NOT_FOUND:
1428 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1429 "Error: Function not found (argument %d).\n", cArgs);
1430 break;
1431 case VERR_DBGC_PARSE_NOT_A_FUNCTION:
1432 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1433 "Error: The function specified is not a function (argument %d).\n", cArgs);
1434 break;
1435 case VERR_DBGC_PARSE_NO_MEMORY:
1436 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1437 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
1438 break;
1439 case VERR_DBGC_PARSE_INCORRECT_ARG_TYPE:
1440 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1441 "Error: Incorrect argument type (argument %d?).\n", cArgs);
1442 break;
1443 case VERR_DBGC_PARSE_VARIABLE_NOT_FOUND:
1444 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1445 "Error: An undefined variable was referenced (argument %d).\n", cArgs);
1446 break;
1447 case VERR_DBGC_PARSE_CONVERSION_FAILED:
1448 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1449 "Error: A conversion between two types failed (argument %d).\n", cArgs);
1450 break;
1451 case VERR_DBGC_PARSE_NOT_IMPLEMENTED:
1452 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1453 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
1454 break;
1455 case VERR_DBGC_PARSE_BAD_RESULT_TYPE:
1456 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1457 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
1458 break;
1459 case VERR_DBGC_PARSE_WRITEONLY_SYMBOL:
1460 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1461 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
1462 break;
1464 case VERR_DBGC_COMMAND_FAILED:
1465 break;
1467 default:
1469 PCRTSTATUSMSG pErr = RTErrGet(rc);
1470 if (strncmp(pErr->pszDefine, RT_STR_TUPLE("Unknown Status")))
1471 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Error: %s (%d) - %s\n", pErr->pszDefine, rc, pErr->pszMsgFull);
1472 else
1473 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Error: Unknown error %d (%#x)!\n", rc, rc);
1474 break;
1479 return rc;