VirtualBox

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

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

DBGC: More parser fixes, added comma (,) as a argument separator (in addition to space and tab). Not entirely perfect yet for trailing, but who cares.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.1 KB
Line 
1/* $Id: DBGCEval.cpp 41559 2012-06-04 00:57:02Z 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 unsigned cchWord = 0;
552 char chQuote = '\0';
553 char chPrev = ' ';
554 bool fBinary = false;
555 char *psz = pszExpr;
556 char ch;
557
558 while ((ch = *psz) != '\0')
559 {
560 /*
561 * String quoting.
562 */
563 if (chQuote)
564 {
565 if (ch == chQuote)
566 {
567 if (psz[1] == chQuote)
568 {
569 psz++; /* escaped quote */
570 cchWord++;
571 }
572 else
573 {
574 chQuote = '\0';
575 fBinary = true;
576 cchWord = 0;
577 }
578 }
579 else
580 cchWord++;
581 }
582 else if (ch == '"' || ch == '\'')
583 {
584 if (fBinary || cchWord)
585 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
586 chQuote = ch;
587 }
588 /*
589 * Parentheses.
590 */
591 else if (ch == '(')
592 {
593 if (!cPar && (fBinary || cchWord)) /** @todo function call */
594 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
595 cPar++;
596 fBinary = false;
597 cchWord = 0;
598 }
599 else if (ch == ')')
600 {
601 if (cPar <= 0)
602 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
603 cPar--;
604 fBinary = true;
605 cchWord = 0;
606 }
607 /*
608 * Potential operator.
609 */
610 else if (cPar == 0 && !RT_C_IS_BLANK(ch))
611 {
612 PCDBGCOP pOp = dbgcIsOpChar(ch)
613 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
614 : NULL;
615 if (pOp)
616 {
617 /* If not the right kind of operator we've got a syntax error. */
618 if (pOp->fBinary != fBinary)
619 return VERR_DBGC_PARSE_UNEXPECTED_OPERATOR;
620
621 /*
622 * Update the parse state and skip the operator.
623 */
624 if (!pOpSplit)
625 {
626 pOpSplit = pOp;
627 pszOpSplit = psz;
628 cBinaryOps = fBinary;
629 }
630 else if (fBinary)
631 {
632 cBinaryOps++;
633 if (pOp->iPrecedence >= pOpSplit->iPrecedence)
634 {
635 pOpSplit = pOp;
636 pszOpSplit = psz;
637 }
638 }
639
640 psz += pOp->cchName - 1;
641 fBinary = false;
642 cchWord = 0;
643 }
644 else if (fBinary && !cchWord)
645 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
646 else
647 {
648 fBinary = true;
649 cchWord++;
650 }
651 }
652 else if (cPar == 0 && RT_C_IS_BLANK(ch))
653 cchWord++;
654
655 /* next */
656 psz++;
657 chPrev = ch;
658 } /* parse loop. */
659
660 if (chQuote)
661 return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
662
663 /*
664 * Either we found an operator to divide the expression by
665 * or we didn't find any. In the first case it's divide and
666 * conquer. In the latter it's a single expression which
667 * needs dealing with its unary operators if any.
668 */
669 int rc;
670 if ( cBinaryOps
671 && pOpSplit->fBinary)
672 {
673 /* process 1st sub expression. */
674 *pszOpSplit = '\0';
675 DBGCVAR Arg1;
676 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, pOpSplit->enmCatArg1, &Arg1);
677 if (RT_SUCCESS(rc))
678 {
679 /* process 2nd sub expression. */
680 char *psz2 = pszOpSplit + pOpSplit->cchName;
681 DBGCVAR Arg2;
682 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), pOpSplit->enmCatArg2, &Arg2);
683 if (RT_SUCCESS(rc))
684 /* apply the operator. */
685 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
686 }
687 }
688 else if (cBinaryOps)
689 {
690 /* process sub expression. */
691 pszOpSplit += pOpSplit->cchName;
692 DBGCVAR Arg;
693 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), pOpSplit->enmCatArg1, &Arg);
694 if (RT_SUCCESS(rc))
695 /* apply the operator. */
696 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, enmCategory, pResult);
697 }
698 else
699 /* plain expression, qutoed string, or using unary operators perhaps with parentheses. */
700 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, enmCategory, pResult);
701
702 return rc;
703}
704
705
706/**
707 * Worker for dbgcProcessArguments that performs type checking and promoptions.
708 *
709 * @returns VBox status code.
710 *
711 * @param pDbgc Debugger console instance data.
712 * @param enmCategory The target category for the result.
713 * @param pArg The argument to check and promote.
714 */
715static int dbgcCheckAndTypePromoteArgument(PDBGC pDbgc, DBGCVARCAT enmCategory, PDBGCVAR pArg)
716{
717 switch (enmCategory)
718 {
719 /*
720 * Anything goes
721 */
722 case DBGCVAR_CAT_ANY:
723 return VINF_SUCCESS;
724
725 /*
726 * Pointer with and without range.
727 * We can try resolve strings and symbols as symbols and promote
728 * numbers to flat GC pointers.
729 */
730 case DBGCVAR_CAT_POINTER_NO_RANGE:
731 case DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE:
732 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
733 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED;
734 /* fallthru */
735 case DBGCVAR_CAT_POINTER:
736 case DBGCVAR_CAT_POINTER_NUMBER:
737 switch (pArg->enmType)
738 {
739 case DBGCVAR_TYPE_GC_FLAT:
740 case DBGCVAR_TYPE_GC_FAR:
741 case DBGCVAR_TYPE_GC_PHYS:
742 case DBGCVAR_TYPE_HC_FLAT:
743 case DBGCVAR_TYPE_HC_PHYS:
744 return VINF_SUCCESS;
745
746 case DBGCVAR_TYPE_SYMBOL:
747 case DBGCVAR_TYPE_STRING:
748 {
749 DBGCVAR Var;
750 int rc = dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
751 if (RT_SUCCESS(rc))
752 {
753 /* deal with range */
754 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
755 {
756 Var.enmRangeType = pArg->enmRangeType;
757 Var.u64Range = pArg->u64Range;
758 }
759 else if (enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
760 Var.enmRangeType = DBGCVAR_RANGE_NONE;
761 *pArg = Var;
762 }
763 return rc;
764 }
765
766 case DBGCVAR_TYPE_NUMBER:
767 if ( enmCategory != DBGCVAR_CAT_POINTER_NUMBER
768 && enmCategory != DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE)
769 {
770 RTGCPTR GCPtr = (RTGCPTR)pArg->u.u64Number;
771 pArg->enmType = DBGCVAR_TYPE_GC_FLAT;
772 pArg->u.GCFlat = GCPtr;
773 }
774 return VINF_SUCCESS;
775
776 default:
777 AssertMsgFailedReturn(("Invalid type %d\n"), VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
778 }
779 break; /* (not reached) */
780
781 /*
782 * GC pointer with and without range.
783 * We can try resolve strings and symbols as symbols and
784 * promote numbers to flat GC pointers.
785 */
786 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
787 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
788 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED;
789 /* fallthru */
790 case DBGCVAR_CAT_GC_POINTER:
791 switch (pArg->enmType)
792 {
793 case DBGCVAR_TYPE_GC_FLAT:
794 case DBGCVAR_TYPE_GC_FAR:
795 case DBGCVAR_TYPE_GC_PHYS:
796 return VINF_SUCCESS;
797
798 case DBGCVAR_TYPE_HC_FLAT:
799 case DBGCVAR_TYPE_HC_PHYS:
800 return VERR_DBGC_PARSE_CONVERSION_FAILED;
801
802 case DBGCVAR_TYPE_SYMBOL:
803 case DBGCVAR_TYPE_STRING:
804 {
805 DBGCVAR Var;
806 int rc = dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
807 if (RT_SUCCESS(rc))
808 {
809 /* deal with range */
810 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
811 {
812 Var.enmRangeType = pArg->enmRangeType;
813 Var.u64Range = pArg->u64Range;
814 }
815 else if (enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
816 Var.enmRangeType = DBGCVAR_RANGE_NONE;
817 *pArg = Var;
818 }
819 return rc;
820 }
821
822 case DBGCVAR_TYPE_NUMBER:
823 {
824 RTGCPTR GCPtr = (RTGCPTR)pArg->u.u64Number;
825 pArg->enmType = DBGCVAR_TYPE_GC_FLAT;
826 pArg->u.GCFlat = GCPtr;
827 return VINF_SUCCESS;
828 }
829
830 default:
831 AssertMsgFailedReturn(("Invalid type %d\n"), VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
832 }
833 break; /* (not reached) */
834
835 /*
836 * Number with or without a range.
837 * Numbers can be resolved from symbols, but we cannot demote a pointer
838 * to a number.
839 */
840 case DBGCVAR_CAT_NUMBER_NO_RANGE:
841 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
842 return VERR_DBGC_PARSE_NO_RANGE_ALLOWED;
843 /* fallthru */
844 case DBGCVAR_CAT_NUMBER:
845 switch (pArg->enmType)
846 {
847 case DBGCVAR_TYPE_GC_FLAT:
848 case DBGCVAR_TYPE_GC_FAR:
849 case DBGCVAR_TYPE_GC_PHYS:
850 case DBGCVAR_TYPE_HC_FLAT:
851 case DBGCVAR_TYPE_HC_PHYS:
852 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
853
854 case DBGCVAR_TYPE_NUMBER:
855 return VINF_SUCCESS;
856
857 case DBGCVAR_TYPE_SYMBOL:
858 case DBGCVAR_TYPE_STRING:
859 {
860 DBGCVAR Var;
861 int rc = dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
862 if (RT_SUCCESS(rc))
863 {
864 /* deal with range */
865 if (pArg->enmRangeType != DBGCVAR_RANGE_NONE)
866 {
867 Var.enmRangeType = pArg->enmRangeType;
868 Var.u64Range = pArg->u64Range;
869 }
870 else if (enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
871 Var.enmRangeType = DBGCVAR_RANGE_NONE;
872 *pArg = Var;
873 }
874 return rc;
875 }
876
877 default:
878 AssertMsgFailedReturn(("Invalid type %d\n"), VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
879 }
880 break; /* (not reached) */
881
882 /*
883 * Symbols and strings are basically the same thing for the time being.
884 */
885 case DBGCVAR_CAT_STRING:
886 case DBGCVAR_CAT_SYMBOL:
887 {
888 switch (pArg->enmType)
889 {
890 case DBGCVAR_TYPE_STRING:
891 if (enmCategory == DBGCVAR_CAT_SYMBOL)
892 pArg->enmType = DBGCVAR_TYPE_SYMBOL;
893 return VINF_SUCCESS;
894
895 case DBGCVAR_TYPE_SYMBOL:
896 if (enmCategory == DBGCVAR_CAT_STRING)
897 pArg->enmType = DBGCVAR_TYPE_STRING;
898 return VINF_SUCCESS;
899 default:
900 break;
901 }
902
903 /* Stringify numeric and poitner values. */
904 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
905 size_t cch = pDbgc->CmdHlp.pfnStrPrintf(&pDbgc->CmdHlp, pDbgc->pszScratch, cbScratch, "%Dv", pArg);
906 if (cch + 1 >= cbScratch)
907 return VERR_DBGC_PARSE_NO_SCRATCH;
908
909 pArg->enmType = enmCategory == DBGCVAR_CAT_STRING ? DBGCVAR_TYPE_STRING : DBGCVAR_TYPE_SYMBOL;
910 pArg->u.pszString = pDbgc->pszScratch;
911 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;
912 pArg->u64Range = cch;
913
914 pDbgc->pszScratch += cch + 1;
915 return VINF_SUCCESS;
916 }
917
918 /*
919 * These are not yet implemented.
920 */
921 case DBGCVAR_CAT_OPTION:
922 case DBGCVAR_CAT_OPTION_STRING:
923 case DBGCVAR_CAT_OPTION_NUMBER:
924 AssertMsgFailedReturn(("Not implemented enmCategory=%d\n", enmCategory), VERR_DBGC_PARSE_NOT_IMPLEMENTED);
925
926 default:
927 AssertMsgFailedReturn(("Bad enmCategory=%d\n", enmCategory), VERR_DBGC_PARSE_NOT_IMPLEMENTED);
928 }
929}
930
931
932/**
933 * Parses the arguments of one command.
934 *
935 * @returns VBox statuc code. On parser errors the index of the troublesome
936 * argument is indicated by *pcArg.
937 *
938 * @param pDbgc Debugger console instance data.
939 * @param pCmd Pointer to the command descriptor.
940 * @param pszArg Pointer to the arguments to parse.
941 * @param paArgs Where to store the parsed arguments.
942 * @param cArgs Size of the paArgs array.
943 * @param pcArgs Where to store the number of arguments. In the event
944 * of an error this is (ab)used to store the index of the
945 * offending argument.
946 */
947static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
948{
949 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
950
951 /*
952 * Check if we have any argument and if the command takes any.
953 */
954 *pcArgs = 0;
955 /* strip leading blanks. */
956 while (*pszArgs && RT_C_IS_BLANK(*pszArgs))
957 pszArgs++;
958 if (!*pszArgs)
959 {
960 if (!pCmd->cArgsMin)
961 return VINF_SUCCESS;
962 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS;
963 }
964 /** @todo fixme - foo() doesn't work. */
965 if (!pCmd->cArgsMax)
966 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
967
968 /*
969 * The parse loop.
970 */
971 PDBGCVAR pArg0 = &paArgs[0];
972 PDBGCVAR pArg = pArg0;
973 PCDBGCVARDESC pPrevDesc = NULL;
974 PCDBGCVARDESC paVarDescs = pCmd->paArgDescs;
975 unsigned const cVarDescs = pCmd->cArgDescs;
976 unsigned cCurDesc = 0;
977 unsigned iVar = 0;
978 unsigned iVarDesc = 0;
979 *pcArgs = 0;
980 do
981 {
982 /*
983 * Can we have another argument?
984 */
985 if (*pcArgs >= pCmd->cArgsMax)
986 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
987 if (pArg >= &paArgs[cArgs])
988 return VERR_DBGC_PARSE_ARGUMENT_OVERFLOW;
989 if (iVarDesc >= cVarDescs)
990 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
991
992 /* Walk argument descriptors. */
993 if (cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
994 {
995 iVarDesc++;
996 if (iVarDesc >= cVarDescs)
997 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
998 cCurDesc = 0;
999 }
1000
1001 /*
1002 * Find the end of the argument. This is just rough splitting,
1003 * dbgcEvalSub will do stricter syntax checking later on.
1004 */
1005 int cPar = 0;
1006 char chQuote = '\0';
1007 char *pszEnd = NULL;
1008 char *psz = pszArgs;
1009 char ch;
1010 bool fBinary = false;
1011 for (;;)
1012 {
1013 /*
1014 * Check for the end.
1015 */
1016 if ((ch = *psz) == '\0')
1017 {
1018 if (chQuote)
1019 return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
1020 if (cPar)
1021 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
1022 pszEnd = psz;
1023 break;
1024 }
1025 /*
1026 * When quoted we ignore everything but the quotation char.
1027 * We use the REXX way of escaping the quotation char, i.e. double occurrence.
1028 */
1029 else if (chQuote)
1030 {
1031 if (ch == chQuote)
1032 {
1033 if (psz[1] == chQuote)
1034 psz++; /* skip the escaped quote char */
1035 else
1036 {
1037 chQuote = '\0'; /* end of quoted string. */
1038 fBinary = true;
1039 }
1040 }
1041 }
1042 else if (ch == '\'' || ch == '"')
1043 {
1044 if (fBinary)
1045 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
1046 chQuote = ch;
1047 }
1048 /*
1049 * Parenthesis can of course be nested.
1050 */
1051 else if (ch == '(')
1052 {
1053 if (!cPar && fBinary)
1054 return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
1055 cPar++;
1056 fBinary = false;
1057 }
1058 else if (ch == ')')
1059 {
1060 if (!cPar)
1061 return VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS;
1062 cPar--;
1063 fBinary = true;
1064 }
1065 else if (!cPar)
1066 {
1067 /*
1068 * Encountering a comma is a definite end of parameter.
1069 */
1070 if (ch == ',')
1071 {
1072 pszEnd = psz++;
1073 break;
1074 }
1075
1076 /*
1077 * Encountering blanks may mean the end of it all. A binary
1078 * operator will force continued parsing.
1079 */
1080 if (RT_C_IS_BLANK(ch))
1081 {
1082 pszEnd = psz++; /* in case it's the end. */
1083 while (RT_C_IS_BLANK(*psz))
1084 psz++;
1085
1086 if (*psz == ',')
1087 {
1088 psz++;
1089 break;
1090 }
1091
1092 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1093 if (!pOp || pOp->fBinary != fBinary)
1094 break; /* the end. */
1095
1096 psz += pOp->cchName;
1097 while (RT_C_IS_BLANK(*psz)) /* skip blanks so we don't get here again */
1098 psz++;
1099 fBinary = false;
1100 continue;
1101 }
1102
1103 /*
1104 * Look for operators without a space up front.
1105 */
1106 if (dbgcIsOpChar(ch))
1107 {
1108 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1109 if (pOp)
1110 {
1111 if (pOp->fBinary != fBinary)
1112 {
1113 pszEnd = psz;
1114 /** @todo this is a parsing error really. */
1115 break; /* the end. */
1116 }
1117 psz += pOp->cchName;
1118 while (RT_C_IS_BLANK(*psz)) /* skip blanks so we don't get here again */
1119 psz++;
1120 fBinary = false;
1121 continue;
1122 }
1123 }
1124 fBinary = true;
1125 }
1126
1127 /* next char */
1128 psz++;
1129 }
1130 *pszEnd = '\0';
1131 /* (psz = next char to process) */
1132 size_t cchArgs = strlen(pszArgs);
1133
1134 /*
1135 * Try optional arguments until we find something which matches
1136 * or can easily be promoted to what the descriptor want.
1137 */
1138 for (;;)
1139 {
1140 char *pszArgsCopy = (char *)RTMemDup(pszArgs, cchArgs + 1);
1141 if (!pszArgsCopy)
1142 return VERR_DBGC_PARSE_NO_MEMORY;
1143
1144 int rc = dbgcEvalSub(pDbgc, pszArgs, cchArgs, paVarDescs[iVarDesc].enmCategory, pArg);
1145 if (RT_SUCCESS(rc))
1146 rc = dbgcCheckAndTypePromoteArgument(pDbgc, paVarDescs[iVarDesc].enmCategory, pArg);
1147 if (RT_SUCCESS(rc))
1148 {
1149 pArg->pDesc = pPrevDesc = &paVarDescs[iVarDesc];
1150 cCurDesc++;
1151 RTMemFree(pszArgsCopy);
1152 break;
1153 }
1154
1155 memcpy(pszArgs, pszArgsCopy, cchArgs + 1);
1156 RTMemFree(pszArgsCopy);
1157
1158 /* Continue searching optional descriptors? */
1159 if ( rc != VERR_DBGC_PARSE_INCORRECT_ARG_TYPE
1160 && rc != VERR_DBGC_PARSE_INVALID_NUMBER
1161 && rc != VERR_DBGC_PARSE_NO_RANGE_ALLOWED
1162 )
1163 return rc;
1164
1165 /* Try advance to the next descriptor. */
1166 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
1167 return rc;
1168 iVarDesc++;
1169 if (!cCurDesc)
1170 while ( iVarDesc < cVarDescs
1171 && (paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV))
1172 iVarDesc++;
1173 if (iVarDesc >= cVarDescs)
1174 return rc;
1175 cCurDesc = 0;
1176 }
1177
1178 /*
1179 * Next argument.
1180 */
1181 iVar++;
1182 pArg++;
1183 (*pcArgs)++;
1184 pszArgs = psz;
1185 while (*pszArgs && RT_C_IS_BLANK(*pszArgs))
1186 pszArgs++;
1187 } while (*pszArgs);
1188
1189 /*
1190 * Check that the rest of the argument descriptors indicate optional args.
1191 */
1192 if (iVarDesc < cVarDescs)
1193 {
1194 if (cCurDesc < paVarDescs[iVarDesc].cTimesMin)
1195 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS;
1196 iVarDesc++;
1197 while (iVarDesc < cVarDescs)
1198 {
1199 if (paVarDescs[iVarDesc].cTimesMin)
1200 return VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS;
1201 iVarDesc++;
1202 }
1203 }
1204
1205 return VINF_SUCCESS;
1206}
1207
1208
1209/**
1210 * Evaluate one command.
1211 *
1212 * @returns VBox status code. This is also stored in DBGC::rcCmd.
1213 *
1214 * @param pDbgc Debugger console instance data.
1215 * @param pszCmd Pointer to the command.
1216 * @param cchCmd Length of the command.
1217 * @param fNoExecute Indicates that no commands should actually be executed.
1218 *
1219 * @todo Change pszCmd into argc/argv?
1220 */
1221int dbgcEvalCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd, bool fNoExecute)
1222{
1223 char *pszCmdInput = pszCmd;
1224
1225 /*
1226 * Skip blanks.
1227 */
1228 while (RT_C_IS_BLANK(*pszCmd))
1229 pszCmd++, cchCmd--;
1230
1231 /* external command? */
1232 bool const fExternal = *pszCmd == '.';
1233 if (fExternal)
1234 pszCmd++, cchCmd--;
1235
1236 /*
1237 * Find arguments.
1238 */
1239 char *pszArgs = pszCmd;
1240 while (RT_C_IS_ALNUM(*pszArgs))
1241 pszArgs++;
1242 if (*pszArgs && (!RT_C_IS_BLANK(*pszArgs) || pszArgs == pszCmd))
1243 {
1244 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Syntax error: Invalid command '%s'!\n", pszCmdInput);
1245 return pDbgc->rcCmd = VERR_DBGC_PARSE_INVALD_COMMAND_NAME;
1246 }
1247
1248 /*
1249 * Find the command.
1250 */
1251 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
1252 if (!pCmd)
1253 {
1254 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Syntax error: Unknown command '%s'!\n", pszCmdInput);
1255 return pDbgc->rcCmd = VERR_DBGC_PARSE_COMMAND_NOT_FOUND;
1256 }
1257
1258 /*
1259 * Parse arguments (if any).
1260 */
1261 unsigned cArgs;
1262 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg],
1263 RT_ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
1264 if (RT_SUCCESS(rc))
1265 {
1266 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1267
1268 /*
1269 * Execute the command.
1270 */
1271 if (!fNoExecute)
1272 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs);
1273 pDbgc->rcCmd = rc;
1274 if (rc == VERR_DBGC_COMMAND_FAILED)
1275 rc = VINF_SUCCESS;
1276 }
1277 else
1278 {
1279 pDbgc->rcCmd = rc;
1280
1281 /* report parse / eval error. */
1282 switch (rc)
1283 {
1284 case VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS:
1285 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1286 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
1287 break;
1288 case VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS:
1289 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1290 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
1291 break;
1292 case VERR_DBGC_PARSE_ARGUMENT_OVERFLOW:
1293 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1294 "Syntax error: Too many arguments.\n");
1295 break;
1296 case VERR_DBGC_PARSE_UNBALANCED_QUOTE:
1297 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1298 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
1299 break;
1300 case VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS:
1301 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1302 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
1303 break;
1304 case VERR_DBGC_PARSE_EMPTY_ARGUMENT:
1305 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1306 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
1307 break;
1308 case VERR_DBGC_PARSE_UNEXPECTED_OPERATOR:
1309 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1310 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
1311 break;
1312 case VERR_DBGC_PARSE_INVALID_NUMBER:
1313 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1314 "Syntax error: Invalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
1315 break;
1316 case VERR_DBGC_PARSE_NUMBER_TOO_BIG:
1317 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1318 "Error: Numeric overflow (argument %d).\n", cArgs);
1319 break;
1320 case VERR_DBGC_PARSE_INVALID_OPERATION:
1321 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1322 "Error: Invalid operation attempted (argument %d).\n", cArgs);
1323 break;
1324 case VERR_DBGC_PARSE_FUNCTION_NOT_FOUND:
1325 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1326 "Error: Function not found (argument %d).\n", cArgs);
1327 break;
1328 case VERR_DBGC_PARSE_NOT_A_FUNCTION:
1329 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1330 "Error: The function specified is not a function (argument %d).\n", cArgs);
1331 break;
1332 case VERR_DBGC_PARSE_NO_MEMORY:
1333 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1334 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
1335 break;
1336 case VERR_DBGC_PARSE_INCORRECT_ARG_TYPE:
1337 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1338 "Error: Incorrect argument type (argument %d?).\n", cArgs);
1339 break;
1340 case VERR_DBGC_PARSE_VARIABLE_NOT_FOUND:
1341 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1342 "Error: An undefined variable was referenced (argument %d).\n", cArgs);
1343 break;
1344 case VERR_DBGC_PARSE_CONVERSION_FAILED:
1345 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1346 "Error: A conversion between two types failed (argument %d).\n", cArgs);
1347 break;
1348 case VERR_DBGC_PARSE_NOT_IMPLEMENTED:
1349 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1350 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
1351 break;
1352 case VERR_DBGC_PARSE_BAD_RESULT_TYPE:
1353 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1354 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
1355 break;
1356 case VERR_DBGC_PARSE_WRITEONLY_SYMBOL:
1357 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp,
1358 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
1359 break;
1360
1361 case VERR_DBGC_COMMAND_FAILED:
1362 break;
1363
1364 default:
1365 {
1366 PCRTSTATUSMSG pErr = RTErrGet(rc);
1367 if (strncmp(pErr->pszDefine, RT_STR_TUPLE("Unknown Status")))
1368 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Error: %s (%d) - %s\n", pErr->pszDefine, rc, pErr->pszMsgFull);
1369 else
1370 rc = DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "Error: Unknown error %d (%#x)!\n", rc, rc);
1371 break;
1372 }
1373 }
1374 }
1375 return rc;
1376}
1377
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