3 * DBGC - Debugger Console, command evaluator.
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 /*******************************************************************************
20 *******************************************************************************/
21 #define LOG_GROUP LOG_GROUP_DBGC
27 #include <iprt/assert.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 /*******************************************************************************
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
);
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]);
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
);
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]);
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
))
102 char *psz
= pDbgc
->pszScratch
;
103 pDbgc
->pszScratch
+= cbRequested
;
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);
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
;
141 if (!memchr(pachExpr
, chQuote
, cchExpr
))
142 memcpy(pszCopy
, pachExpr
, cchExpr
);
147 while (offSrc
< cchExpr
)
149 char const ch
= pachExpr
[offSrc
++];
152 if (pachExpr
[offSrc
] != ch
)
153 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP
;
156 pszCopy
[offDst
++] = ch
;
161 memcpy(pszCopy
, pachExpr
, cchExpr
);
162 pszCopy
[cchExpr
] = '\0';
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
;
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.
187 return VERR_DBGC_PARSE_INVALID_NUMBER
;
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
;
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
;
216 * Initialize the argument.
220 pArg
->enmType
= DBGCVAR_TYPE_NUMBER
;
221 pArg
->u
.u64Number
= u64
;
222 pArg
->enmRangeType
= DBGCVAR_RANGE_NONE
;
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
,
242 char const ch
= pszExpr
[0];
243 char const ch2
= pszExpr
[1];
246 if (ch
== '0' && (ch2
== 'x' || ch2
== 'X'))
247 return dbgcEvalSubNum(pszExpr
+ 2, cchExpr
- 2, 16, pResult
);
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
);
270 while (off
< cchExpr
&& (RT_C_IS_XDIGIT(pszExpr
[off
]) || pszExpr
[off
] == '`'))
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.
280 bool fStripRange
= false;
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;
292 AssertFailedReturn(VERR_DBGC_PARSE_NOT_IMPLEMENTED
);
295 char const chQuote
= *pszExpr
;
297 return VERR_DBGC_PARSE_INVALID_NUMBER
;
301 if (pszExpr
[cchExpr
- 1] != chQuote
)
302 return VERR_DBGC_PARSE_UNBALANCED_QUOTE
;
303 pszExpr
[cchExpr
- 1] = '\0';
307 int rc
= dbgcSymbolGet(pDbgc
, pszExpr
, enmType
, pResult
);
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
;
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];
338 if (ch
== '0' && (ch2
== 'x' || ch2
== 'X'))
340 while (RT_C_IS_XDIGIT(pszExpr
[off
]) || pszExpr
[off
] == '`')
343 return dbgcEvalSubNum(pszExpr
+ 2, cchExpr
- 2, 16, pResult
);
344 return dbgcEvalSubString(pDbgc
, pszExpr
, cchExpr
, pResult
);
348 if (RT_C_IS_XDIGIT(*pszExpr
) && (pszExpr
[cchExpr
- 1] == 'h' || pszExpr
[cchExpr
- 1] == 'H'))
351 while (off
< cchExpr
&& (RT_C_IS_XDIGIT(pszExpr
[off
]) || pszExpr
[off
] == '`'))
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
] == '`')
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
] == '`')
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
] == '`')
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
394 while (RT_C_IS_XDIGIT(pszExpr
[off
]) || pszExpr
[off
] == '`')
397 return dbgcEvalSubNum(pszExpr
, cchExpr
, 16, pResult
);
398 return dbgcEvalSubString(pDbgc
, pszExpr
, cchExpr
, pResult
);
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
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
);
424 return VERR_DBGC_PARSE_FUNCTION_NOT_FOUND
;
427 * Parse the arguments.
431 pszArgs
[cchArgs
] = '\0';
432 int rc
= dbgcProcessArguments(pDbgc
, pFunc
->pszFuncNm
,
433 pFunc
->cArgsMin
, pFunc
->cArgsMax
, pFunc
->paArgDescs
, pFunc
->cArgDescs
,
434 pszArgs
, &iArg
, &cArgs
);
436 rc
= pFunc
->pfnHandler(pFunc
, &pDbgc
->CmdHlp
, pDbgc
->pVM
, &pDbgc
->aArgs
[iArg
], cArgs
, pResult
);
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, ' ');
469 /* binary operators means syntax error. */
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
))
485 if (*pszExpr2
== '(')
486 rc
= dbgcEvalSub(pDbgc
, pszExpr2
, cchExpr
- (pszExpr2
- pszExpr
), pOp
->enmCatArg1
, &Arg
);
488 rc
= dbgcEvalSubUnary(pDbgc
, pszExpr2
, cchExpr
- (pszExpr2
- pszExpr
), pOp
->enmCatArg1
, &Arg
);
490 rc
= dbgcCheckAndTypePromoteArgument(pDbgc
, pOp
->enmCatArg1
, &Arg
);
492 rc
= pOp
->pfnHandlerUnary(pDbgc
, &Arg
, enmCategory
, pResult
);
495 rc
= VERR_DBGC_PARSE_EMPTY_ARGUMENT
;
500 * Could this be a function call?
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
))
516 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.
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.
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
--;
588 return VERR_DBGC_PARSE_EMPTY_ARGUMENT
;
591 * Check if there are any parenthesis which needs removing.
593 if (pszExpr
[0] == '(' && pszExpr
[cchExpr
- 1] == ')')
598 char *psz
= pszExpr
+ 1;
600 while ((ch
= *psz
) != '\0')
607 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS
;
609 if (cPar
== 0 && psz
[1]) /* If not at end, there's nothing to do. */
618 /* remove the parenthesis. */
621 pszExpr
[cchExpr
] = '\0';
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
--;
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;
643 unsigned cchWord
= 0;
646 bool fBinary
= false;
650 while ((ch
= *psz
) != '\0')
659 if (psz
[1] == chQuote
)
661 psz
++; /* escaped quote */
674 else if (ch
== '"' || ch
== '\'')
676 if (fBinary
|| cchWord
)
677 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP
;
685 if (!cPar
&& fBinary
&& !cchWord
)
686 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP
;
694 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS
;
700 * Potential operator.
702 else if (cPar
== 0 && !RT_C_IS_BLANK(ch
))
704 PCDBGCOP pOp
= dbgcIsOpChar(ch
)
705 ? dbgcOperatorLookup(pDbgc
, psz
, fBinary
, chPrev
)
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.
720 cBinaryOps
= fBinary
;
725 if (pOp
->iPrecedence
>= pOpSplit
->iPrecedence
)
732 psz
+= pOp
->cchName
- 1;
736 else if (fBinary
&& !cchWord
)
737 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP
;
744 else if (cPar
== 0 && RT_C_IS_BLANK(ch
))
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
763 && pOpSplit
->fBinary
)
765 /* process 1st sub expression. */
768 rc
= dbgcEvalSub(pDbgc
, pszExpr
, pszOpSplit
- pszExpr
, pOpSplit
->enmCatArg1
, &Arg1
);
771 /* process 2nd sub expression. */
772 char *psz2
= pszOpSplit
+ pOpSplit
->cchName
;
774 rc
= dbgcEvalSub(pDbgc
, psz2
, cchExpr
- (psz2
- pszExpr
), pOpSplit
->enmCatArg2
, &Arg2
);
776 rc
= dbgcCheckAndTypePromoteArgument(pDbgc
, pOpSplit
->enmCatArg1
, &Arg1
);
778 rc
= dbgcCheckAndTypePromoteArgument(pDbgc
, pOpSplit
->enmCatArg2
, &Arg2
);
780 rc
= pOpSplit
->pfnHandlerBinary(pDbgc
, &Arg1
, &Arg2
, pResult
);
785 /* process sub expression. */
786 pszOpSplit
+= pOpSplit
->cchName
;
788 rc
= dbgcEvalSub(pDbgc
, pszOpSplit
, cchExpr
- (pszOpSplit
- pszExpr
), pOpSplit
->enmCatArg1
, &Arg
);
790 rc
= dbgcCheckAndTypePromoteArgument(pDbgc
, pOpSplit
->enmCatArg1
, &Arg
);
792 rc
= pOpSplit
->pfnHandlerUnary(pDbgc
, &Arg
, enmCategory
, pResult
);
795 /* plain expression, qutoed string, or using unary operators perhaps with parentheses. */
796 rc
= dbgcEvalSubUnary(pDbgc
, pszExpr
, cchExpr
, enmCategory
, pResult
);
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
)
818 case DBGCVAR_CAT_ANY
:
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
;
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
:
842 case DBGCVAR_TYPE_SYMBOL
:
843 case DBGCVAR_TYPE_STRING
:
846 int rc
= dbgcSymbolGet(pDbgc
, pArg
->u
.pszString
, DBGCVAR_TYPE_GC_FLAT
, &Var
);
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
;
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
;
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
;
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
:
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
:
902 int rc
= dbgcSymbolGet(pDbgc
, pArg
->u
.pszString
, DBGCVAR_TYPE_GC_FLAT
, &Var
);
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
;
918 case DBGCVAR_TYPE_NUMBER
:
920 RTGCPTR GCPtr
= (RTGCPTR
)pArg
->u
.u64Number
;
921 pArg
->enmType
= DBGCVAR_TYPE_GC_FLAT
;
922 pArg
->u
.GCFlat
= GCPtr
;
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
936 case DBGCVAR_CAT_NUMBER_NO_RANGE
:
937 if (pArg
->enmRangeType
!= DBGCVAR_RANGE_NONE
)
938 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED
;
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
:
953 case DBGCVAR_TYPE_SYMBOL
:
954 case DBGCVAR_TYPE_STRING
:
957 int rc
= dbgcSymbolGet(pDbgc
, pArg
->u
.pszString
, DBGCVAR_TYPE_NUMBER
, &Var
);
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
;
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
;
991 case DBGCVAR_TYPE_SYMBOL
:
992 if (enmCategory
== DBGCVAR_CAT_STRING
)
993 pArg
->enmType
= DBGCVAR_TYPE_STRING
;
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
);
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
;
1060 /* strip leading blanks. */
1061 while (*pszArgs
&& RT_C_IS_BLANK(*pszArgs
))
1066 return VINF_SUCCESS
;
1067 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS
;
1070 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS
;
1075 PDBGCVAR pArg
= &pDbgc
->aArgs
[pDbgc
->iArg
];
1076 PCDBGCVARDESC pPrevDesc
= NULL
;
1077 unsigned cCurDesc
= 0;
1079 unsigned iVarDesc
= 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
)
1097 if (iVarDesc
>= cVarDescs
)
1098 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS
;
1103 * Find the end of the argument. This is just rough splitting,
1104 * dbgcEvalSub will do stricter syntax checking later on.
1107 char chQuote
= '\0';
1108 char *pszEnd
= NULL
;
1109 char *psz
= pszArgs
;
1111 bool fBinary
= false;
1115 * Check for the end.
1117 if ((ch
= *psz
) == '\0')
1120 return VERR_DBGC_PARSE_UNBALANCED_QUOTE
;
1122 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS
;
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.
1134 if (psz
[1] == chQuote
)
1135 psz
++; /* skip the escaped quote char */
1138 chQuote
= '\0'; /* end of quoted string. */
1143 else if (ch
== '\'' || ch
== '"')
1146 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP
;
1150 * Parenthesis can of course be nested.
1160 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS
;
1167 * Encountering a comma is a definite end of parameter.
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
))
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 */
1203 * Look for operators without a space up front.
1205 if (dbgcIsOpChar(ch
))
1207 PCDBGCOP pOp
= dbgcOperatorLookup(pDbgc
, psz
, fBinary
, ' ');
1210 if (pOp
->fBinary
!= fBinary
)
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 */
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.
1239 char *pszArgsCopy
= (char *)RTMemDup(pszArgs
, cchArgs
+ 1);
1241 return VERR_DBGC_PARSE_NO_MEMORY
;
1243 int rc
= dbgcEvalSub(pDbgc
, pszArgs
, cchArgs
, paVarDescs
[iVarDesc
].enmCategory
, pArg
);
1245 rc
= dbgcCheckAndTypePromoteArgument(pDbgc
, paVarDescs
[iVarDesc
].enmCategory
, pArg
);
1248 pArg
->pDesc
= pPrevDesc
= &paVarDescs
[iVarDesc
];
1250 RTMemFree(pszArgsCopy
);
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
1264 /* Try advance to the next descriptor. */
1265 if (paVarDescs
[iVarDesc
].cTimesMin
> cCurDesc
)
1269 while ( iVarDesc
< cVarDescs
1270 && (paVarDescs
[iVarDesc
].fFlags
& DBGCVD_FLAGS_DEP_PREV
))
1272 if (iVarDesc
>= cVarDescs
)
1285 while (*pszArgs
&& RT_C_IS_BLANK(*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
;
1297 while (iVarDesc
< cVarDescs
)
1299 if (paVarDescs
[iVarDesc
].cTimesMin
)
1300 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS
;
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
;
1326 while (RT_C_IS_BLANK(*pszCmd
))
1329 /* external command? */
1330 bool const fExternal
= *pszCmd
== '.';
1337 char *pszArgs
= pszCmd
;
1338 while (RT_C_IS_ALNUM(*pszArgs
) || *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
;
1350 PCDBGCCMD pCmd
= dbgcCommandLookup(pDbgc
, pszCmd
, pszArgs
- pszCmd
, fExternal
);
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).
1362 int rc
= dbgcProcessArguments(pDbgc
, pCmd
->pszCmd
,
1363 pCmd
->cArgsMin
, pCmd
->cArgsMax
, pCmd
->paArgDescs
, pCmd
->cArgDescs
,
1364 pszArgs
, &iArg
, &cArgs
);
1367 AssertMsg(rc
== VINF_SUCCESS
, ("%Rrc\n", rc
));
1370 * Execute the command.
1373 rc
= pCmd
->pfnHandler(pCmd
, &pDbgc
->CmdHlp
, pDbgc
->pVM
, &pDbgc
->aArgs
[iArg
], cArgs
);
1376 if (rc
== VERR_DBGC_COMMAND_FAILED
)
1384 /* report parse / eval error. */
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
);
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
);
1395 case VERR_DBGC_PARSE_ARGUMENT_OVERFLOW
:
1396 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1397 "Syntax error: Too many arguments.\n");
1399 case VERR_DBGC_PARSE_UNBALANCED_QUOTE
:
1400 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1401 "Syntax error: Unbalanced quote (argument %d).\n", cArgs
);
1403 case VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS
:
1404 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1405 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs
);
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
);
1411 case VERR_DBGC_PARSE_UNEXPECTED_OPERATOR
:
1412 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1413 "Syntax error: Invalid operator usage (argument %d).\n", cArgs
);
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
);
1419 case VERR_DBGC_PARSE_NUMBER_TOO_BIG
:
1420 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1421 "Error: Numeric overflow (argument %d).\n", cArgs
);
1423 case VERR_DBGC_PARSE_INVALID_OPERATION
:
1424 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1425 "Error: Invalid operation attempted (argument %d).\n", cArgs
);
1427 case VERR_DBGC_PARSE_FUNCTION_NOT_FOUND
:
1428 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1429 "Error: Function not found (argument %d).\n", cArgs
);
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
);
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
);
1439 case VERR_DBGC_PARSE_INCORRECT_ARG_TYPE
:
1440 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1441 "Error: Incorrect argument type (argument %d?).\n", cArgs
);
1443 case VERR_DBGC_PARSE_VARIABLE_NOT_FOUND
:
1444 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1445 "Error: An undefined variable was referenced (argument %d).\n", cArgs
);
1447 case VERR_DBGC_PARSE_CONVERSION_FAILED
:
1448 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
,
1449 "Error: A conversion between two types failed (argument %d).\n", cArgs
);
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
);
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
);
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
);
1464 case VERR_DBGC_COMMAND_FAILED
:
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
);
1473 rc
= DBGCCmdHlpPrintf(&pDbgc
->CmdHlp
, "Error: Unknown error %d (%#x)!\n", rc
, rc
);