VirtualBox

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

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

DBGC: Hacking the command parsing code.

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