VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGConsole.cpp@ 5730

Last change on this file since 5730 was 5686, checked in by vboxsync, 17 years ago

Got the DBGC parser testcase framework going. enough fun for now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.1 KB
Line 
1/** $Id: DBGConsole.cpp 5686 2007-11-11 12:22:14Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_dbgc DBGC - The Debug Console
20 *
21 * The debugger console is an early attempt to make some interactive
22 * debugging facilities for the VirtualBox VMM. It was initially only
23 * accessible thru a telnet session on debug builds. Later it was hastily
24 * built into the VBoxDbg module with a very simple Qt wrapper around it.
25 *
26 * The debugger is optional and presently not built into release builds
27 * of VirtualBox. It is therefore necessary to enclose code related to it
28 * in \#ifdef VBOX_WITH_DEBUGGER blocks. This is mandatory for components
29 * that register extenral commands.
30 *
31 *
32 * @section sec_dbgc_op Operation (intentions)
33 *
34 * The console will process commands in a manner similar to the OS/2 and
35 * windows kernel debuggers. This means ';' is a command separator and
36 * that when possible we'll use the same command names as these two uses.
37 *
38 *
39 * @subsection sec_dbg_op_numbers Numbers
40 *
41 * Numbers are hexadecimal unless specified with a prefix indicating
42 * elsewise. Prefixes:
43 * - '0x' - hexadecimal.
44 * - '0i' - decimal
45 * - '0t' - octal.
46 * - '0y' - binary.
47 *
48 * Some of the prefixes are a bit uncommon, the reason for this that
49 * the typical binary prefix '0b' can also be a hexadecimal value since
50 * no prefix or suffix is required for such values. Ditto for '0d' and
51 * '0' for decimal and octal.
52 *
53 *
54 * @subsection sec_dbg_op_address Addressing modes
55 *
56 * - Default is flat. For compatability '%' also means flat.
57 * - Segmented addresses are specified selector:offset.
58 * - Physical addresses are specified using '%%'.
59 * - The default target for the addressing is the guest context, the '#'
60 * will override this and set it to the host.
61 * Note that several operations won't work on host addresses.
62 *
63 * The '%', '%%' and '#' prefixes is implemented as unary operators, while ':'
64 * is a binary operator. Operator precedence takes care of evaluation order.
65 *
66 *
67 * @subsection sec_dbg_op_evalution Evaluation
68 *
69 * Most unary and binary C operators are supported, check the help text for
70 * details. However, some of these are not yet implemented because this is
71 * tiresome and annoying work. So, if something is missing and you need it
72 * you implement it or complain to bird. (Ditto for missing functions.)
73 *
74 * Simple variable support is provided thru the 'set' and 'unset' commands and
75 * the unary '$' operator.
76 *
77 * The unary '@' operator will indicate function calls. Commands and functions
78 * are the same thing, except that functions has a return type.
79 *
80 *
81 * @subsection sec_dbg_op_registers Registers
82 *
83 * Registers are addressed using their name. Some registers which have several fields
84 * (like gdtr) will have separate names indicating the different fields. The default
85 * register set is the guest one. To access the hypervisor register one have to
86 * prefix the register names with '.'.
87 *
88 * The registers are implemented as built-in symbols. For making gdb guys more at
89 * home it is possible to access them with the '$' operator, i.e. as a variable.
90 *
91 *
92 * @subsection sec_dbg_op_commands Commands and Functions
93 *
94 * Commands and functions are the same thing, except that functions may return a
95 * value. So, functions may be used as commands. The command/function handlers
96 * can detect whether they are invoked as a command or function by checking whether
97 * there is a return variable or not.
98 *
99 * The command/function names are all lowercase, case sensitive, and starting
100 * with a letter. Operator characters are not permitted in the names of course.
101 * Space is allowed, but must be flagged so the parser can check for multiple
102 * spaces and tabs. (This feature is for 'dump xyz' and for emulating the
103 * gdb 'info abc'.)
104 *
105 * The '.' prefix indicates the set of external commands. External commands are
106 * command registered by VMM components.
107 *
108 *
109 * @section sec_dbgc_logging Logging
110 *
111 * The idea is to be able to pass thru debug and release logs to the console
112 * if the user so wishes. This feature requires some kind of hook into the
113 * logger instance and while this was sketched it hasn't yet been implemented
114 * (dbgcProcessLog and DBGC::fLog).
115 *
116 *
117 *
118 * @section sec_dbgc_linking Linking and API
119 *
120 * The DBGC code is linked into the VBoxVMM module. (At present it is also
121 * linked into VBoxDbg, but this is obviously very wrong.)
122 *
123 * A COM object will be created for the DBGC so it can be operated remotely
124 * without using TCP. VBoxDbg is the intended audience for this usage. Some
125 * questions about callbacks (for output) and security (you may wish to
126 * restrict users from debugging a VM) needs to be answered first though.
127 */
128
129
130/*******************************************************************************
131* Header Files *
132*******************************************************************************/
133#define LOG_GROUP LOG_GROUP_DBGC
134#include <VBox/dbg.h>
135#include <VBox/dbgf.h>
136#include <VBox/vm.h>
137#include <VBox/vmm.h>
138#include <VBox/mm.h>
139#include <VBox/pgm.h>
140#include <VBox/selm.h>
141#include <VBox/dis.h>
142#include <VBox/param.h>
143#include <VBox/err.h>
144#include <VBox/log.h>
145
146#include <iprt/alloc.h>
147#include <iprt/alloca.h>
148#include <iprt/string.h>
149#include <iprt/assert.h>
150#include <iprt/ctype.h>
151
152#include <stdlib.h>
153#include <stdio.h>
154
155#include "DBGCInternal.h"
156
157
158/*******************************************************************************
159* Global Variables *
160*******************************************************************************/
161/** Bitmap where set bits indicates the characters the may start an operator name. */
162static uint32_t g_bmOperatorChars[256 / (4*8)];
163
164
165/*******************************************************************************
166* Internal Functions *
167*******************************************************************************/
168static int dbgcProcessLog(PDBGC pDbgc);
169
170
171
172/**
173 * Initalizes g_bmOperatorChars.
174 */
175static void dbgcInitOpCharBitMap(void)
176{
177 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
178 for (unsigned iOp = 0; iOp < g_cOps; iOp++)
179 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
180}
181
182
183/**
184 * Checks whether the character may be the start of an operator.
185 *
186 * @returns true/false.
187 * @param ch The character.
188 */
189DECLINLINE(bool) dbgcIsOpChar(char ch)
190{
191 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
192}
193
194
195/**
196 * Resolves a symbol (or tries to do so at least).
197 *
198 * @returns 0 on success.
199 * @returns VBox status on failure.
200 * @param pDbgc The debug console instance.
201 * @param pszSymbol The symbol name.
202 * @param enmType The result type.
203 * @param pResult Where to store the result.
204 */
205int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
206{
207 /*
208 * Builtin?
209 */
210 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
211 if (pSymDesc)
212 {
213 if (!pSymDesc->pfnGet)
214 return VERR_PARSE_WRITEONLY_SYMBOL;
215 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
216 }
217
218
219 /*
220 * Ask PDM.
221 */
222 /** @todo resolve symbols using PDM. */
223
224
225 /*
226 * Ask the debug info manager.
227 */
228 DBGFSYMBOL Symbol;
229 int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
230 if (VBOX_SUCCESS(rc))
231 {
232 /*
233 * Default return is a flat gc address.
234 */
235 memset(pResult, 0, sizeof(*pResult));
236 pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
237 pResult->u64Range = Symbol.cb;
238 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
239 pResult->u.GCFlat = Symbol.Value;
240 DBGCVAR VarTmp;
241 switch (enmType)
242 {
243 /* nothing to do. */
244 case DBGCVAR_TYPE_GC_FLAT:
245 case DBGCVAR_TYPE_GC_FAR:
246 case DBGCVAR_TYPE_ANY:
247 return VINF_SUCCESS;
248
249 /* simply make it numeric. */
250 case DBGCVAR_TYPE_NUMBER:
251 pResult->enmType = DBGCVAR_TYPE_NUMBER;
252 pResult->u.u64Number = Symbol.Value;
253 return VINF_SUCCESS;
254
255 /* cast it. */
256
257 case DBGCVAR_TYPE_GC_PHYS:
258 VarTmp = *pResult;
259 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
260
261 case DBGCVAR_TYPE_HC_FAR:
262 case DBGCVAR_TYPE_HC_FLAT:
263 VarTmp = *pResult;
264 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
265
266 case DBGCVAR_TYPE_HC_PHYS:
267 VarTmp = *pResult;
268 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
269
270 default:
271 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
272 return VERR_INVALID_PARAMETER;
273 }
274 }
275
276 return VERR_PARSE_NOT_IMPLEMENTED;
277}
278
279
280static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
281{
282 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
283
284 /*
285 * Removing any quoting and escapings.
286 */
287 char ch = *pszExpr;
288 if (ch == '"' || ch == '\'' || ch == '`')
289 {
290 if (pszExpr[--cchExpr] != ch)
291 return VERR_PARSE_UNBALANCED_QUOTE;
292 cchExpr--;
293 pszExpr++;
294
295 /** @todo string unescaping. */
296 }
297 pszExpr[cchExpr] = '\0';
298
299 /*
300 * Make the argument.
301 */
302 pArg->pDesc = NULL;
303 pArg->pNext = NULL;
304 pArg->enmType = DBGCVAR_TYPE_STRING;
305 pArg->u.pszString = pszExpr;
306 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;
307 pArg->u64Range = cchExpr;
308
309 NOREF(pDbgc);
310 return 0;
311}
312
313
314static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
315{
316 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
317 /*
318 * Convert to number.
319 */
320 uint64_t u64 = 0;
321 char ch;
322 while ((ch = *pszExpr) != '\0')
323 {
324 uint64_t u64Prev = u64;
325 unsigned u = ch - '0';
326 if (u < 10 && u < uBase)
327 u64 = u64 * uBase + u;
328 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
329 u64 = u64 * uBase + u;
330 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
331 u64 = u64 * uBase + u;
332 else
333 return VERR_PARSE_INVALID_NUMBER;
334
335 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
336 if (u64Prev != u64 / uBase)
337 return VERR_PARSE_NUMBER_TOO_BIG;
338
339 /* next */
340 pszExpr++;
341 }
342
343 /*
344 * Initialize the argument.
345 */
346 pArg->pDesc = NULL;
347 pArg->pNext = NULL;
348 pArg->enmType = DBGCVAR_TYPE_NUMBER;
349 pArg->u.u64Number = u64;
350 pArg->enmRangeType = DBGCVAR_RANGE_NONE;
351 pArg->u64Range = 0;
352
353 return 0;
354}
355
356
357/**
358 * Match variable and variable descriptor, promoting the variable if necessary.
359 *
360 * @returns VBox status code.
361 * @param pDbgc Debug console instanace.
362 * @param pVar Variable.
363 * @param pVarDesc Variable descriptor.
364 */
365static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
366{
367 /*
368 * (If match or promoted to match, return, else break.)
369 */
370 switch (pVarDesc->enmCategory)
371 {
372 /*
373 * Anything goes
374 */
375 case DBGCVAR_CAT_ANY:
376 return VINF_SUCCESS;
377
378 /*
379 * Pointer with and without range.
380 * We can try resolve strings and symbols as symbols and
381 * promote numbers to flat GC pointers.
382 */
383 case DBGCVAR_CAT_POINTER_NO_RANGE:
384 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
385 return VERR_PARSE_NO_RANGE_ALLOWED;
386 /* fallthru */
387 case DBGCVAR_CAT_POINTER:
388 switch (pVar->enmType)
389 {
390 case DBGCVAR_TYPE_GC_FLAT:
391 case DBGCVAR_TYPE_GC_FAR:
392 case DBGCVAR_TYPE_GC_PHYS:
393 case DBGCVAR_TYPE_HC_FLAT:
394 case DBGCVAR_TYPE_HC_FAR:
395 case DBGCVAR_TYPE_HC_PHYS:
396 return VINF_SUCCESS;
397
398 case DBGCVAR_TYPE_SYMBOL:
399 case DBGCVAR_TYPE_STRING:
400 {
401 DBGCVAR Var;
402 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
403 if (VBOX_SUCCESS(rc))
404 {
405 /* deal with range */
406 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
407 {
408 Var.enmRangeType = pVar->enmRangeType;
409 Var.u64Range = pVar->u64Range;
410 }
411 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
412 Var.enmRangeType = DBGCVAR_RANGE_NONE;
413 *pVar = Var;
414 return rc;
415 }
416 break;
417 }
418
419 case DBGCVAR_TYPE_NUMBER:
420 {
421 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
422 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
423 pVar->u.GCFlat = GCPtr;
424 return VINF_SUCCESS;
425 }
426
427 default:
428 break;
429 }
430 break;
431
432 /*
433 * GC pointer with and without range.
434 * We can try resolve strings and symbols as symbols and
435 * promote numbers to flat GC pointers.
436 */
437 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
438 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
439 return VERR_PARSE_NO_RANGE_ALLOWED;
440 /* fallthru */
441 case DBGCVAR_CAT_GC_POINTER:
442 switch (pVar->enmType)
443 {
444 case DBGCVAR_TYPE_GC_FLAT:
445 case DBGCVAR_TYPE_GC_FAR:
446 case DBGCVAR_TYPE_GC_PHYS:
447 return VINF_SUCCESS;
448
449 case DBGCVAR_TYPE_HC_FLAT:
450 case DBGCVAR_TYPE_HC_FAR:
451 case DBGCVAR_TYPE_HC_PHYS:
452 return VERR_PARSE_CONVERSION_FAILED;
453
454 case DBGCVAR_TYPE_SYMBOL:
455 case DBGCVAR_TYPE_STRING:
456 {
457 DBGCVAR Var;
458 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
459 if (VBOX_SUCCESS(rc))
460 {
461 /* deal with range */
462 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
463 {
464 Var.enmRangeType = pVar->enmRangeType;
465 Var.u64Range = pVar->u64Range;
466 }
467 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
468 Var.enmRangeType = DBGCVAR_RANGE_NONE;
469 *pVar = Var;
470 return rc;
471 }
472 break;
473 }
474
475 case DBGCVAR_TYPE_NUMBER:
476 {
477 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
478 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
479 pVar->u.GCFlat = GCPtr;
480 return VINF_SUCCESS;
481 }
482
483 default:
484 break;
485 }
486 break;
487
488 /*
489 * Number with or without a range.
490 * Numbers can be resolved from symbols, but we cannot demote a pointer
491 * to a number.
492 */
493 case DBGCVAR_CAT_NUMBER_NO_RANGE:
494 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
495 return VERR_PARSE_NO_RANGE_ALLOWED;
496 /* fallthru */
497 case DBGCVAR_CAT_NUMBER:
498 switch (pVar->enmType)
499 {
500 case DBGCVAR_TYPE_NUMBER:
501 return VINF_SUCCESS;
502
503 case DBGCVAR_TYPE_SYMBOL:
504 case DBGCVAR_TYPE_STRING:
505 {
506 DBGCVAR Var;
507 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
508 if (VBOX_SUCCESS(rc))
509 {
510 *pVar = Var;
511 return rc;
512 }
513 break;
514 }
515 default:
516 break;
517 }
518 break;
519
520 /*
521 * Strings can easily be made from symbols (and of course strings).
522 * We could consider reformatting the addresses and numbers into strings later...
523 */
524 case DBGCVAR_CAT_STRING:
525 switch (pVar->enmType)
526 {
527 case DBGCVAR_TYPE_SYMBOL:
528 pVar->enmType = DBGCVAR_TYPE_STRING;
529 /* fallthru */
530 case DBGCVAR_TYPE_STRING:
531 return VINF_SUCCESS;
532 default:
533 break;
534 }
535 break;
536
537 /*
538 * Symol is pretty much the same thing as a string (at least until we actually implement it).
539 */
540 case DBGCVAR_CAT_SYMBOL:
541 switch (pVar->enmType)
542 {
543 case DBGCVAR_TYPE_STRING:
544 pVar->enmType = DBGCVAR_TYPE_SYMBOL;
545 /* fallthru */
546 case DBGCVAR_TYPE_SYMBOL:
547 return VINF_SUCCESS;
548 default:
549 break;
550 }
551 break;
552
553 /*
554 * Anything else is illegal.
555 */
556 default:
557 AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
558 break;
559 }
560
561 return VERR_PARSE_NO_ARGUMENT_MATCH;
562}
563
564
565/**
566 * Matches a set of variables with a description set.
567 *
568 * This is typically used for routine arguments before a call. The effects in
569 * addition to the validation, is that some variables might be propagated to
570 * other types in order to match the description. The following transformations
571 * are supported:
572 * - String reinterpreted as a symbol and resolved to a number or pointer.
573 * - Number to a pointer.
574 * - Pointer to a number.
575 * @returns 0 on success with paVars.
576 * @returns VBox error code for match errors.
577 */
578static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
579 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
580 PDBGCVAR paVars, unsigned cVars)
581{
582 /*
583 * Just do basic min / max checks first.
584 */
585 if (cVars < cVarsMin)
586 return VERR_PARSE_TOO_FEW_ARGUMENTS;
587 if (cVars > cVarsMax)
588 return VERR_PARSE_TOO_MANY_ARGUMENTS;
589
590 /*
591 * Match the descriptors and actual variables.
592 */
593 PCDBGCVARDESC pPrevDesc = NULL;
594 unsigned cCurDesc = 0;
595 unsigned iVar = 0;
596 unsigned iVarDesc = 0;
597 while (iVar < cVars)
598 {
599 /* walk the descriptors */
600 if (iVarDesc >= cVarDescs)
601 return VERR_PARSE_TOO_MANY_ARGUMENTS;
602 if ( ( paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
603 && &paVarDescs[iVarDesc - 1] != pPrevDesc)
604 || cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
605 {
606 iVarDesc++;
607 if (iVarDesc >= cVarDescs)
608 return VERR_PARSE_TOO_MANY_ARGUMENTS;
609 cCurDesc = 0;
610 }
611
612 /*
613 * Skip thru optional arguments until we find something which matches
614 * or can easily be promoted to what the descriptor want.
615 */
616 for (;;)
617 {
618 int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
619 if (VBOX_SUCCESS(rc))
620 {
621 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
622 cCurDesc++;
623 break;
624 }
625
626 /* can we advance? */
627 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
628 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
629 if (++iVarDesc >= cVarDescs)
630 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
631 cCurDesc = 0;
632 }
633
634 /* next var */
635 iVar++;
636 }
637
638 /*
639 * Check that the rest of the descriptors are optional.
640 */
641 while (iVarDesc < cVarDescs)
642 {
643 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
644 return VERR_PARSE_TOO_FEW_ARGUMENTS;
645 cCurDesc = 0;
646
647 /* next */
648 iVarDesc++;
649 }
650
651 return 0;
652}
653
654
655/**
656 * Evaluates one argument with respect to unary operators.
657 *
658 * @returns 0 on success. pResult contains the result.
659 * @returns VBox error code on parse or other evaluation error.
660 *
661 * @param pDbgc Debugger console instance data.
662 * @param pszExpr The expression string.
663 * @param pResult Where to store the result of the expression evaluation.
664 */
665static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
666{
667 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
668
669 /*
670 * The state of the expression is now such that it will start by zero or more
671 * unary operators and being followed by an expression of some kind.
672 * The expression is either plain or in parenthesis.
673 *
674 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
675 * ASSUME: unary operators are all of equal precedence.
676 */
677 int rc = 0;
678 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
679 if (pOp)
680 {
681 /* binary operators means syntax error. */
682 if (pOp->fBinary)
683 return VERR_PARSE_UNEXPECTED_OPERATOR;
684
685 /*
686 * If the next expression (the one following the unary operator) is in a
687 * parenthesis a full eval is needed. If not the unary eval will suffice.
688 */
689 /* calc and strip next expr. */
690 char *pszExpr2 = pszExpr + pOp->cchName;
691 while (isblank(*pszExpr2))
692 pszExpr2++;
693
694 if (!*pszExpr2)
695 rc = VERR_PARSE_EMPTY_ARGUMENT;
696 else
697 {
698 DBGCVAR Arg;
699 if (*pszExpr2 == '(')
700 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
701 else
702 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
703 if (VBOX_SUCCESS(rc))
704 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
705 }
706 }
707 else
708 {
709 /*
710 * Didn't find any operators, so it we have to check if this can be an
711 * function call before assuming numeric or string expression.
712 *
713 * (ASSUMPTIONS:)
714 * A function name only contains alphanumerical chars and it can not start
715 * with a numerical character.
716 * Immediately following the name is a parenthesis which must over
717 * the remaining part of the expression.
718 */
719 bool fExternal = *pszExpr == '.';
720 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;
721 char *pszFunEnd = NULL;
722 if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
723 {
724 pszFunEnd = pszExpr + 1;
725 while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
726 pszFunEnd++;
727 if (*pszFunEnd != '(')
728 pszFunEnd = NULL;
729 }
730
731 if (pszFunEnd)
732 {
733 /*
734 * Ok, it's a function call.
735 */
736 if (fExternal)
737 pszExpr++, cchExpr--;
738 PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
739 if (!pFun)
740 return VERR_PARSE_FUNCTION_NOT_FOUND;
741 if (!pFun->pResultDesc)
742 return VERR_PARSE_NOT_A_FUNCTION;
743
744 /*
745 * Parse the expression in parenthesis.
746 */
747 cchExpr -= pszFunEnd - pszExpr;
748 pszExpr = pszFunEnd;
749 /** @todo implement multiple arguments. */
750 DBGCVAR Arg;
751 rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
752 if (!rc)
753 {
754 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
755 if (!rc)
756 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
757 }
758 else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
759 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
760 }
761 else
762 {
763 /*
764 * Didn't find any operators, so it must be a plain expression.
765 * This might be numeric or a string expression.
766 */
767 char ch = pszExpr[0];
768 char ch2 = pszExpr[1];
769 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
770 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
771 else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
772 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
773 else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
774 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
775 /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.
776 //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
777 // rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
778 else
779 {
780 /*
781 * Hexadecimal number or a string?
782 */
783 char *psz = pszExpr;
784 while (isxdigit(*psz))
785 psz++;
786 if (!*psz)
787 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
788 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
789 {
790 *psz = '\0';
791 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
792 }
793 else
794 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
795 }
796 }
797 }
798
799 return rc;
800}
801
802
803/**
804 * Evaluates one argument.
805 *
806 * @returns 0 on success. pResult contains the result.
807 * @returns VBox error code on parse or other evaluation error.
808 *
809 * @param pDbgc Debugger console instance data.
810 * @param pszExpr The expression string.
811 * @param pResult Where to store the result of the expression evaluation.
812 */
813int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
814{
815 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
816 /*
817 * First we need to remove blanks in both ends.
818 * ASSUMES: There is no quoting unless the entire expression is a string.
819 */
820
821 /* stripping. */
822 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
823 pszExpr[--cchExpr] = '\0';
824 while (isblank(*pszExpr))
825 pszExpr++, cchExpr--;
826 if (!*pszExpr)
827 return VERR_PARSE_EMPTY_ARGUMENT;
828
829 /* it there is any kind of quoting in the expression, it's string meat. */
830 if (strpbrk(pszExpr, "\"'`"))
831 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
832
833 /*
834 * Check if there are any parenthesis which needs removing.
835 */
836 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
837 {
838 do
839 {
840 unsigned cPar = 1;
841 char *psz = pszExpr + 1;
842 char ch;
843 while ((ch = *psz) != '\0')
844 {
845 if (ch == '(')
846 cPar++;
847 else if (ch == ')')
848 {
849 if (cPar <= 0)
850 return VERR_PARSE_UNBALANCED_PARENTHESIS;
851 cPar--;
852 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
853 break;
854 }
855 /* next */
856 psz++;
857 }
858 if (ch)
859 break;
860
861 /* remove the parenthesis. */
862 pszExpr++;
863 cchExpr -= 2;
864 pszExpr[cchExpr] = '\0';
865
866 /* strip blanks. */
867 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
868 pszExpr[--cchExpr] = '\0';
869 while (isblank(*pszExpr))
870 pszExpr++, cchExpr--;
871 if (!*pszExpr)
872 return VERR_PARSE_EMPTY_ARGUMENT;
873 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
874 }
875
876 /* tabs to spaces. */
877 char *psz = pszExpr;
878 while ((psz = strchr(psz, '\t')) != NULL)
879 *psz = ' ';
880
881 /*
882 * Now, we need to look for the binary operator with the lowest precedence.
883 *
884 * If there are no operators we're left with a simple expression which we
885 * evaluate with respect to unary operators
886 */
887 char *pszOpSplit = NULL;
888 PCDBGCOP pOpSplit = NULL;
889 unsigned cBinaryOps = 0;
890 unsigned cPar = 0;
891 char ch;
892 char chPrev = ' ';
893 bool fBinary = false;
894 psz = pszExpr;
895
896 while ((ch = *psz) != '\0')
897 {
898 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
899 /*
900 * Parenthesis.
901 */
902 if (ch == '(')
903 {
904 cPar++;
905 fBinary = false;
906 }
907 else if (ch == ')')
908 {
909 if (cPar <= 0)
910 return VERR_PARSE_UNBALANCED_PARENTHESIS;
911 cPar--;
912 fBinary = true;
913 }
914 /*
915 * Potential operator.
916 */
917 else if (cPar == 0 && !isblank(ch))
918 {
919 PCDBGCOP pOp = dbgcIsOpChar(ch)
920 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
921 : NULL;
922 if (pOp)
923 {
924 /* If not the right kind of operator we've got a syntax error. */
925 if (pOp->fBinary != fBinary)
926 return VERR_PARSE_UNEXPECTED_OPERATOR;
927
928 /*
929 * Update the parse state and skip the operator.
930 */
931 if (!pOpSplit)
932 {
933 pOpSplit = pOp;
934 pszOpSplit = psz;
935 cBinaryOps = fBinary;
936 }
937 else if (fBinary)
938 {
939 cBinaryOps++;
940 if (pOp->iPrecedence >= pOpSplit->iPrecedence)
941 {
942 pOpSplit = pOp;
943 pszOpSplit = psz;
944 }
945 }
946
947 psz += pOp->cchName - 1;
948 fBinary = false;
949 }
950 else
951 fBinary = true;
952 }
953
954 /* next */
955 psz++;
956 chPrev = ch;
957 } /* parse loop. */
958
959
960 /*
961 * Either we found an operator to divide the expression by
962 * or we didn't find any. In the first case it's divide and
963 * conquer. In the latter it's a single expression which
964 * needs dealing with its unary operators if any.
965 */
966 int rc;
967 if ( cBinaryOps
968 && pOpSplit->fBinary)
969 {
970 /* process 1st sub expression. */
971 *pszOpSplit = '\0';
972 DBGCVAR Arg1;
973 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
974 if (VBOX_SUCCESS(rc))
975 {
976 /* process 2nd sub expression. */
977 char *psz2 = pszOpSplit + pOpSplit->cchName;
978 DBGCVAR Arg2;
979 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
980 if (VBOX_SUCCESS(rc))
981 /* apply the operator. */
982 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
983 }
984 }
985 else if (cBinaryOps)
986 {
987 /* process sub expression. */
988 pszOpSplit += pOpSplit->cchName;
989 DBGCVAR Arg;
990 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
991 if (VBOX_SUCCESS(rc))
992 /* apply the operator. */
993 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
994 }
995 else
996 /* plain expression or using unary operators perhaps with paratheses. */
997 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
998
999 return rc;
1000}
1001
1002
1003/**
1004 * Parses the arguments of one command.
1005 *
1006 * @returns 0 on success.
1007 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
1008 * @param pDbgc Debugger console instance data.
1009 * @param pCmd Pointer to the command descriptor.
1010 * @param pszArg Pointer to the arguments to parse.
1011 * @param paArgs Where to store the parsed arguments.
1012 * @param cArgs Size of the paArgs array.
1013 * @param pcArgs Where to store the number of arguments.
1014 * In the event of an error this is used to store the index of the offending argument.
1015 */
1016static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
1017{
1018 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
1019 /*
1020 * Check if we have any argument and if the command takes any.
1021 */
1022 *pcArgs = 0;
1023 /* strip leading blanks. */
1024 while (*pszArgs && isblank(*pszArgs))
1025 pszArgs++;
1026 if (!*pszArgs)
1027 {
1028 if (!pCmd->cArgsMin)
1029 return 0;
1030 return VERR_PARSE_TOO_FEW_ARGUMENTS;
1031 }
1032 /** @todo fixme - foo() doesn't work. */
1033 if (!pCmd->cArgsMax)
1034 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1035
1036 /*
1037 * This is a hack, it's "temporary" and should go away "when" the parser is
1038 * modified to match arguments while parsing.
1039 */
1040 if ( pCmd->cArgsMax == 1
1041 && pCmd->cArgsMin == 1
1042 && pCmd->cArgDescs == 1
1043 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
1044 && cArgs >= 1)
1045 {
1046 *pcArgs = 1;
1047 RTStrStripR(pszArgs);
1048 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
1049 }
1050
1051
1052 /*
1053 * The parse loop.
1054 */
1055 PDBGCVAR pArg0 = &paArgs[0];
1056 PDBGCVAR pArg = pArg0;
1057 *pcArgs = 0;
1058 do
1059 {
1060 /*
1061 * Can we have another argument?
1062 */
1063 if (*pcArgs >= pCmd->cArgsMax)
1064 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1065 if (pArg >= &paArgs[cArgs])
1066 return VERR_PARSE_ARGUMENT_OVERFLOW;
1067
1068 /*
1069 * Find the end of the argument.
1070 */
1071 int cPar = 0;
1072 char chQuote = '\0';
1073 char *pszEnd = NULL;
1074 char *psz = pszArgs;
1075 char ch;
1076 bool fBinary = false;
1077 for (;;)
1078 {
1079 /*
1080 * Check for the end.
1081 */
1082 if ((ch = *psz) == '\0')
1083 {
1084 if (chQuote)
1085 return VERR_PARSE_UNBALANCED_QUOTE;
1086 if (cPar)
1087 return VERR_PARSE_UNBALANCED_PARENTHESIS;
1088 pszEnd = psz;
1089 break;
1090 }
1091 /*
1092 * When quoted we ignore everything but the quotation char.
1093 * We use the REXX way of escaping the quotation char, i.e. double occurence.
1094 */
1095 else if (ch == '\'' || ch == '"' || ch == '`')
1096 {
1097 if (chQuote)
1098 {
1099 /* end quote? */
1100 if (ch == chQuote)
1101 {
1102 if (psz[1] == ch)
1103 psz++; /* skip the escaped quote char */
1104 else
1105 chQuote = '\0'; /* end of quoted string. */
1106 }
1107 }
1108 else
1109 chQuote = ch; /* open new quote */
1110 }
1111 /*
1112 * Parenthesis can of course be nested.
1113 */
1114 else if (ch == '(')
1115 {
1116 cPar++;
1117 fBinary = false;
1118 }
1119 else if (ch == ')')
1120 {
1121 if (!cPar)
1122 return VERR_PARSE_UNBALANCED_PARENTHESIS;
1123 cPar--;
1124 fBinary = true;
1125 }
1126 else if (!chQuote && !cPar)
1127 {
1128 /*
1129 * Encountering blanks may mean the end of it all. A binary operator
1130 * will force continued parsing.
1131 */
1132 if (isblank(*psz))
1133 {
1134 pszEnd = psz++; /* just in case. */
1135 while (isblank(*psz))
1136 psz++;
1137 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1138 if (!pOp || pOp->fBinary != fBinary)
1139 break; /* the end. */
1140 psz += pOp->cchName;
1141 while (isblank(*psz)) /* skip blanks so we don't get here again */
1142 psz++;
1143 fBinary = false;
1144 continue;
1145 }
1146
1147 /*
1148 * Look for operators without a space up front.
1149 */
1150 if (dbgcIsOpChar(*psz))
1151 {
1152 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
1153 if (pOp)
1154 {
1155 if (pOp->fBinary != fBinary)
1156 {
1157 pszEnd = psz;
1158 /** @todo this is a parsing error really. */
1159 break; /* the end. */
1160 }
1161 psz += pOp->cchName;
1162 while (isblank(*psz)) /* skip blanks so we don't get here again */
1163 psz++;
1164 fBinary = false;
1165 continue;
1166 }
1167 }
1168 fBinary = true;
1169 }
1170
1171 /* next char */
1172 psz++;
1173 }
1174 *pszEnd = '\0';
1175 /* (psz = next char to process) */
1176
1177 /*
1178 * Parse and evaluate the argument.
1179 */
1180 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
1181 if (VBOX_FAILURE(rc))
1182 return rc;
1183
1184 /*
1185 * Next.
1186 */
1187 pArg++;
1188 (*pcArgs)++;
1189 pszArgs = psz;
1190 while (*pszArgs && isblank(*pszArgs))
1191 pszArgs++;
1192 } while (*pszArgs);
1193
1194 /*
1195 * Match the arguments.
1196 */
1197 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
1198}
1199
1200
1201/**
1202 * Process one command.
1203 *
1204 * @returns VBox status code. Any error indicates the termination of the console session.
1205 * @param pDbgc Debugger console instance data.
1206 * @param pszCmd Pointer to the command.
1207 * @param cchCmd Length of the command.
1208 * @param fNoExecute Indicates that no commands should actually be executed.
1209 */
1210int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd, bool fNoExecute)
1211{
1212 char *pszCmdInput = pszCmd;
1213
1214 /*
1215 * Skip blanks.
1216 */
1217 while (isblank(*pszCmd))
1218 pszCmd++, cchCmd--;
1219
1220 /* external command? */
1221 bool fExternal = *pszCmd == '.';
1222 if (fExternal)
1223 pszCmd++, cchCmd--;
1224
1225 /*
1226 * Find arguments.
1227 */
1228 char *pszArgs = pszCmd;
1229 while (isalnum(*pszArgs))
1230 pszArgs++;
1231 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
1232 {
1233 pDbgc->rcCmd = VINF_PARSE_INVALD_COMMAND_NAME;
1234 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
1235 return 0;
1236 }
1237
1238 /*
1239 * Find the command.
1240 */
1241 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
1242 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
1243 {
1244 pDbgc->rcCmd = VINF_PARSE_COMMAND_NOT_FOUND;
1245 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
1246 }
1247
1248 /*
1249 * Parse arguments (if any).
1250 */
1251 unsigned cArgs;
1252 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
1253
1254 /*
1255 * Execute the command.
1256 */
1257 if (!rc)
1258 {
1259 if (!fNoExecute)
1260 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
1261 pDbgc->rcCmd = rc;
1262 }
1263 else
1264 {
1265 pDbgc->rcCmd = rc;
1266
1267 /* report parse / eval error. */
1268 switch (rc)
1269 {
1270 case VERR_PARSE_TOO_FEW_ARGUMENTS:
1271 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1272 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
1273 break;
1274 case VERR_PARSE_TOO_MANY_ARGUMENTS:
1275 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1276 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
1277 break;
1278 case VERR_PARSE_ARGUMENT_OVERFLOW:
1279 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1280 "Syntax error: Too many arguments.\n");
1281 break;
1282 case VERR_PARSE_UNBALANCED_QUOTE:
1283 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1284 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
1285 break;
1286 case VERR_PARSE_UNBALANCED_PARENTHESIS:
1287 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1288 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
1289 break;
1290 case VERR_PARSE_EMPTY_ARGUMENT:
1291 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1292 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
1293 break;
1294 case VERR_PARSE_UNEXPECTED_OPERATOR:
1295 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1296 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
1297 break;
1298 case VERR_PARSE_INVALID_NUMBER:
1299 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1300 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
1301 break;
1302 case VERR_PARSE_NUMBER_TOO_BIG:
1303 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1304 "Error: Numeric overflow (argument %d).\n", cArgs);
1305 break;
1306 case VERR_PARSE_INVALID_OPERATION:
1307 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1308 "Error: Invalid operation attempted (argument %d).\n", cArgs);
1309 break;
1310 case VERR_PARSE_FUNCTION_NOT_FOUND:
1311 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1312 "Error: Function not found (argument %d).\n", cArgs);
1313 break;
1314 case VERR_PARSE_NOT_A_FUNCTION:
1315 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1316 "Error: The function specified is not a function (argument %d).\n", cArgs);
1317 break;
1318 case VERR_PARSE_NO_MEMORY:
1319 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1320 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
1321 break;
1322 case VERR_PARSE_INCORRECT_ARG_TYPE:
1323 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1324 "Error: Incorrect argument type (argument %d?).\n", cArgs);
1325 break;
1326 case VERR_PARSE_VARIABLE_NOT_FOUND:
1327 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1328 "Error: An undefined variable was referenced (argument %d).\n", cArgs);
1329 break;
1330 case VERR_PARSE_CONVERSION_FAILED:
1331 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1332 "Error: A conversion between two types failed (argument %d).\n", cArgs);
1333 break;
1334 case VERR_PARSE_NOT_IMPLEMENTED:
1335 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1336 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
1337 break;
1338 case VERR_PARSE_BAD_RESULT_TYPE:
1339 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1340 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
1341 break;
1342 case VERR_PARSE_WRITEONLY_SYMBOL:
1343 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1344 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
1345 break;
1346
1347 default:
1348 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1349 "Error: Unknown error %d!\n", rc);
1350 return rc;
1351 }
1352
1353 /*
1354 * Parse errors are non fatal.
1355 */
1356 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
1357 rc = 0;
1358 }
1359
1360 return rc;
1361}
1362
1363
1364/**
1365 * Process all commands currently in the buffer.
1366 *
1367 * @returns VBox status code. Any error indicates the termination of the console session.
1368 * @param pDbgc Debugger console instance data.
1369 * @param fNoExecute Indicates that no commands should actually be executed.
1370 */
1371static int dbgcProcessCommands(PDBGC pDbgc, bool fNoExecute)
1372{
1373 int rc = 0;
1374 while (pDbgc->cInputLines)
1375 {
1376 /*
1377 * Empty the log buffer if we're hooking the log.
1378 */
1379 if (pDbgc->fLog)
1380 {
1381 rc = dbgcProcessLog(pDbgc);
1382 if (VBOX_FAILURE(rc))
1383 break;
1384 }
1385
1386 if (pDbgc->iRead == pDbgc->iWrite)
1387 {
1388 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
1389 pDbgc->cInputLines = 0;
1390 return 0;
1391 }
1392
1393 /*
1394 * Copy the command to the parse buffer.
1395 */
1396 char ch;
1397 char *psz = &pDbgc->achInput[pDbgc->iRead];
1398 char *pszTrg = &pDbgc->achScratch[0];
1399 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
1400 {
1401 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
1402 psz = &pDbgc->achInput[0];
1403
1404 if (psz == &pDbgc->achInput[pDbgc->iWrite])
1405 {
1406 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
1407 pDbgc->cInputLines = 0;
1408 return 0;
1409 }
1410
1411 pszTrg++;
1412 }
1413 *pszTrg = '\0';
1414
1415 /*
1416 * Advance the buffer.
1417 */
1418 pDbgc->iRead = psz - &pDbgc->achInput[0];
1419 if (ch == '\n')
1420 pDbgc->cInputLines--;
1421
1422 /*
1423 * Parse and execute this command.
1424 */
1425 pDbgc->pszScratch = psz;
1426 pDbgc->iArg = 0;
1427 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1, fNoExecute);
1428 if (rc)
1429 break;
1430 }
1431
1432 return rc;
1433}
1434
1435
1436/**
1437 * Handle input buffer overflow.
1438 *
1439 * Will read any available input looking for a '\n' to reset the buffer on.
1440 *
1441 * @returns VBox status.
1442 * @param pDbgc Debugger console instance data.
1443 */
1444static int dbgcInputOverflow(PDBGC pDbgc)
1445{
1446 /*
1447 * Assert overflow status and reset the input buffer.
1448 */
1449 if (!pDbgc->fInputOverflow)
1450 {
1451 pDbgc->fInputOverflow = true;
1452 pDbgc->iRead = pDbgc->iWrite = 0;
1453 pDbgc->cInputLines = 0;
1454 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
1455 }
1456
1457 /*
1458 * Eat input till no more or there is a '\n'.
1459 * When finding a '\n' we'll continue normal processing.
1460 */
1461 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
1462 {
1463 size_t cbRead;
1464 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
1465 if (VBOX_FAILURE(rc))
1466 return rc;
1467 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
1468 if (psz)
1469 {
1470 pDbgc->fInputOverflow = false;
1471 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
1472 pDbgc->iWrite = (unsigned)cbRead;
1473 pDbgc->cInputLines = 0;
1474 break;
1475 }
1476 }
1477
1478 return 0;
1479}
1480
1481
1482/**
1483 * Read input and do some preprocessing.
1484 *
1485 * @returns VBox status.
1486 * In addition to the iWrite and achInput, cInputLines is maintained.
1487 * In case of an input overflow the fInputOverflow flag will be set.
1488 * @param pDbgc Debugger console instance data.
1489 */
1490static int dbgcInputRead(PDBGC pDbgc)
1491{
1492 /*
1493 * We have ready input.
1494 * Read it till we don't have any or we have a full input buffer.
1495 */
1496 int rc = 0;
1497 do
1498 {
1499 /*
1500 * More available buffer space?
1501 */
1502 size_t cbLeft;
1503 if (pDbgc->iWrite > pDbgc->iRead)
1504 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
1505 else
1506 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
1507 if (!cbLeft)
1508 {
1509 /* overflow? */
1510 if (!pDbgc->cInputLines)
1511 rc = dbgcInputOverflow(pDbgc);
1512 break;
1513 }
1514
1515 /*
1516 * Read one char and interpret it.
1517 */
1518 char achRead[128];
1519 size_t cbRead;
1520 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
1521 if (VBOX_FAILURE(rc))
1522 return rc;
1523 char *psz = &achRead[0];
1524 while (cbRead-- > 0)
1525 {
1526 char ch = *psz++;
1527 switch (ch)
1528 {
1529 /*
1530 * Ignore.
1531 */
1532 case '\0':
1533 case '\r':
1534 case '\a':
1535 break;
1536
1537 /*
1538 * Backspace.
1539 */
1540 case '\b':
1541 Log2(("DBGC: backspace\n"));
1542 if (pDbgc->iRead != pDbgc->iWrite)
1543 {
1544 unsigned iWriteUndo = pDbgc->iWrite;
1545 if (pDbgc->iWrite)
1546 pDbgc->iWrite--;
1547 else
1548 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
1549
1550 if (pDbgc->achInput[pDbgc->iWrite] == '\n')
1551 pDbgc->iWrite = iWriteUndo;
1552 }
1553 break;
1554
1555 /*
1556 * Add char to buffer.
1557 */
1558 case '\t':
1559 case '\n':
1560 case ';':
1561 switch (ch)
1562 {
1563 case '\t': ch = ' '; break;
1564 case '\n': pDbgc->cInputLines++; break;
1565 }
1566 default:
1567 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
1568 pDbgc->achInput[pDbgc->iWrite] = ch;
1569 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
1570 pDbgc->iWrite = 0;
1571 break;
1572 }
1573 }
1574
1575 /* Terminate it to make it easier to read in the debugger. */
1576 pDbgc->achInput[pDbgc->iWrite] = '\0';
1577 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
1578
1579 return rc;
1580}
1581
1582
1583/**
1584 * Reads input, parses it and executes commands on '\n'.
1585 *
1586 * @returns VBox status.
1587 * @param pDbgc Debugger console instance data.
1588 * @param fNoExecute Indicates that no commands should actually be executed.
1589 */
1590int dbgcProcessInput(PDBGC pDbgc, bool fNoExecute)
1591{
1592 /*
1593 * We know there's input ready, so let's read it first.
1594 */
1595 int rc = dbgcInputRead(pDbgc);
1596 if (VBOX_FAILURE(rc))
1597 return rc;
1598
1599 /*
1600 * Now execute any ready commands.
1601 */
1602 if (pDbgc->cInputLines)
1603 {
1604 /** @todo this fReady stuff is broken. */
1605 pDbgc->fReady = false;
1606 rc = dbgcProcessCommands(pDbgc, fNoExecute);
1607 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
1608 pDbgc->fReady = true;
1609 if ( VBOX_SUCCESS(rc)
1610 && pDbgc->iRead == pDbgc->iWrite
1611 && pDbgc->fReady)
1612 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
1613 }
1614
1615 return rc;
1616}
1617
1618
1619/**
1620 * Gets the event context identifier string.
1621 * @returns Read only string.
1622 * @param enmCtx The context.
1623 */
1624static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
1625{
1626 switch (enmCtx)
1627 {
1628 case DBGFEVENTCTX_RAW: return "raw";
1629 case DBGFEVENTCTX_REM: return "rem";
1630 case DBGFEVENTCTX_HWACCL: return "hwaccl";
1631 case DBGFEVENTCTX_HYPER: return "hyper";
1632 case DBGFEVENTCTX_OTHER: return "other";
1633
1634 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
1635 default:
1636 AssertMsgFailed(("enmCtx=%d\n", enmCtx));
1637 return "!Unknown Event Ctx!";
1638 }
1639}
1640
1641
1642/**
1643 * Processes debugger events.
1644 *
1645 * @returns VBox status.
1646 * @param pDbgc DBGC Instance data.
1647 * @param pEvent Pointer to event data.
1648 */
1649static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
1650{
1651 /*
1652 * Flush log first.
1653 */
1654 if (pDbgc->fLog)
1655 {
1656 int rc = dbgcProcessLog(pDbgc);
1657 if (VBOX_FAILURE(rc))
1658 return rc;
1659 }
1660
1661 /*
1662 * Process the event.
1663 */
1664 pDbgc->pszScratch = &pDbgc->achInput[0];
1665 pDbgc->iArg = 0;
1666 bool fPrintPrompt = true;
1667 int rc = VINF_SUCCESS;
1668 switch (pEvent->enmType)
1669 {
1670 /*
1671 * The first part is events we have initiated with commands.
1672 */
1673 case DBGFEVENT_HALT_DONE:
1674 {
1675 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
1676 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
1677 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
1678 if (VBOX_SUCCESS(rc))
1679 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
1680 break;
1681 }
1682
1683
1684 /*
1685 * The second part is events which can occur at any time.
1686 */
1687 case DBGFEVENT_FATAL_ERROR:
1688 {
1689 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
1690 dbgcGetEventCtx(pEvent->enmCtx));
1691 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
1692 if (VBOX_SUCCESS(rc))
1693 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
1694 break;
1695 }
1696
1697 case DBGFEVENT_BREAKPOINT:
1698 case DBGFEVENT_BREAKPOINT_HYPER:
1699 {
1700 bool fRegCtxGuest = pDbgc->fRegCtxGuest;
1701 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
1702
1703 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
1704 switch (rc)
1705 {
1706 case VERR_DBGC_BP_NOT_FOUND:
1707 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
1708 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
1709 break;
1710
1711 case VINF_DBGC_BP_NO_COMMAND:
1712 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
1713 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
1714 break;
1715
1716 case VINF_BUFFER_OVERFLOW:
1717 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
1718 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
1719 break;
1720
1721 default:
1722 break;
1723 }
1724 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
1725 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
1726 else
1727 pDbgc->fRegCtxGuest = fRegCtxGuest;
1728 break;
1729 }
1730
1731 case DBGFEVENT_STEPPED:
1732 case DBGFEVENT_STEPPED_HYPER:
1733 {
1734 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
1735
1736 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
1737 if (VBOX_SUCCESS(rc))
1738 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
1739 break;
1740 }
1741
1742 case DBGFEVENT_ASSERTION_HYPER:
1743 {
1744 pDbgc->fRegCtxGuest = false;
1745
1746 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1747 "\ndbgf event: Hypervisor Assertion! (%s)\n"
1748 "%s"
1749 "%s"
1750 "\n",
1751 dbgcGetEventCtx(pEvent->enmCtx),
1752 pEvent->u.Assert.pszMsg1,
1753 pEvent->u.Assert.pszMsg2);
1754 if (VBOX_SUCCESS(rc))
1755 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
1756 break;
1757 }
1758
1759 case DBGFEVENT_DEV_STOP:
1760 {
1761 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1762 "\n"
1763 "dbgf event: DBGFSTOP (%s)\n"
1764 "File: %s\n"
1765 "Line: %d\n"
1766 "Function: %s\n",
1767 dbgcGetEventCtx(pEvent->enmCtx),
1768 pEvent->u.Src.pszFile,
1769 pEvent->u.Src.uLine,
1770 pEvent->u.Src.pszFunction);
1771 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
1772 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
1773 "Message: %s\n",
1774 pEvent->u.Src.pszMessage);
1775 if (VBOX_SUCCESS(rc))
1776 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
1777 break;
1778 }
1779
1780
1781 case DBGFEVENT_INVALID_COMMAND:
1782 {
1783 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
1784 fPrintPrompt = !pDbgc->fReady;
1785 break;
1786 }
1787
1788 case DBGFEVENT_TERMINATING:
1789 {
1790 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
1791 rc = VERR_GENERAL_FAILURE;
1792 break;
1793 }
1794
1795
1796 default:
1797 {
1798 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
1799 fPrintPrompt = !pDbgc->fReady;
1800 break;
1801 }
1802 }
1803
1804 /*
1805 * Prompt, anyone?
1806 */
1807 if (fPrintPrompt && VBOX_SUCCESS(rc))
1808 {
1809 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
1810 }
1811
1812 return rc;
1813}
1814
1815
1816/**
1817 * Prints any log lines from the log buffer.
1818 *
1819 * The caller must not call function this unless pDbgc->fLog is set.
1820 *
1821 * @returns VBox status. (output related)
1822 * @param pDbgc Debugger console instance data.
1823 */
1824static int dbgcProcessLog(PDBGC pDbgc)
1825{
1826 /** @todo */
1827 NOREF(pDbgc);
1828 return 0;
1829}
1830
1831
1832/**
1833 * Run the debugger console.
1834 *
1835 * @returns VBox status.
1836 * @param pDbgc Pointer to the debugger console instance data.
1837 */
1838int dbgcRun(PDBGC pDbgc)
1839{
1840 /*
1841 * Main Debugger Loop.
1842 *
1843 * This loop will either block on waiting for input or on waiting on
1844 * debug events. If we're forwarding the log we cannot wait for long
1845 * before we must flush the log.
1846 */
1847 int rc = VINF_SUCCESS;
1848 for (;;)
1849 {
1850 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
1851 {
1852 /*
1853 * Wait for a debug event.
1854 */
1855 PCDBGFEVENT pEvent;
1856 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
1857 if (VBOX_SUCCESS(rc))
1858 {
1859 rc = dbgcProcessEvent(pDbgc, pEvent);
1860 if (VBOX_FAILURE(rc))
1861 break;
1862 }
1863 else if (rc != VERR_TIMEOUT)
1864 break;
1865
1866 /*
1867 * Check for input.
1868 */
1869 if (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
1870 {
1871 rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
1872 if (VBOX_FAILURE(rc))
1873 break;
1874 }
1875 }
1876 else
1877 {
1878 /*
1879 * Wait for input. If Logging is enabled we'll only wait very briefly.
1880 */
1881 if (pDbgc->pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
1882 {
1883 rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
1884 if (VBOX_FAILURE(rc))
1885 break;
1886 }
1887 }
1888
1889 /*
1890 * Forward log output.
1891 */
1892 if (pDbgc->fLog)
1893 {
1894 rc = dbgcProcessLog(pDbgc);
1895 if (VBOX_FAILURE(rc))
1896 break;
1897 }
1898 }
1899
1900 return rc;
1901}
1902
1903
1904/**
1905 * Creates a a new instance.
1906 *
1907 * @returns VBox status code.
1908 * @param ppDbgc Where to store the pointer to the instance data.
1909 * @param pBack Pointer to the backend.
1910 * @param fFlags The flags.
1911 */
1912int dbgcCreate(PDBGC *ppDbgc, PDBGCBACK pBack, unsigned fFlags)
1913{
1914 /*
1915 * Validate input.
1916 */
1917 AssertPtrReturn(pBack, VERR_INVALID_POINTER);
1918 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
1919
1920 /*
1921 * Allocate and initialize.
1922 */
1923 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
1924 if (!pDbgc)
1925 return VERR_NO_MEMORY;
1926
1927 dbgcInitCmdHlp(pDbgc);
1928 pDbgc->pBack = pBack;
1929 pDbgc->pVM = NULL;
1930 pDbgc->pszEmulation = "CodeView/WinDbg";
1931 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];
1932 pDbgc->cEmulationCmds = g_cCmdsCodeView;
1933 //pDbgc->fLog = false;
1934 pDbgc->fRegCtxGuest = true;
1935 pDbgc->fRegTerse = true;
1936 //pDbgc->DisasmPos = {0};
1937 //pDbgc->SourcePos = {0};
1938 //pDbgc->DumpPos = {0};
1939 //pDbgc->cbDumpElement = 0;
1940 //pDbgc->cVars = 0;
1941 //pDbgc->paVars = NULL;
1942 //pDbgc->pFirstBp = NULL;
1943 //pDbgc->uInputZero = 0;
1944 //pDbgc->iRead = 0;
1945 //pDbgc->iWrite = 0;
1946 //pDbgc->cInputLines = 0;
1947 //pDbgc->fInputOverflow = false;
1948 pDbgc->fReady = true;
1949 pDbgc->pszScratch = &pDbgc->achScratch[0];
1950 //pDbgc->iArg = 0;
1951 //pDbgc->rcOutput = 0;
1952 //pDbgc->rcCmd = 0;
1953
1954 dbgcInitOpCharBitMap();
1955
1956 *ppDbgc = pDbgc;
1957 return VINF_SUCCESS;
1958}
1959
1960/**
1961 * Destroys a DBGC instance created by dbgcCreate.
1962 *
1963 * @param pDbgc Pointer to the debugger console instance data.
1964 */
1965void dbgcDestroy(PDBGC pDbgc)
1966{
1967 AssertPtr(pDbgc);
1968
1969 /* Disable log hook. */
1970 if (pDbgc->fLog)
1971 {
1972
1973 }
1974
1975 /* Detach from the VM. */
1976 if (pDbgc->pVM)
1977 DBGFR3Detach(pDbgc->pVM);
1978
1979 /* finally, free the instance memory. */
1980 RTMemFree(pDbgc);
1981}
1982
1983
1984/**
1985 * Make a console instance.
1986 *
1987 * This will not return until either an 'exit' command is issued or a error code
1988 * indicating connection loss is encountered.
1989 *
1990 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
1991 * @returns The VBox status code causing the console termination.
1992 *
1993 * @param pVM VM Handle.
1994 * @param pBack Pointer to the backend structure. This must contain
1995 * a full set of function pointers to service the console.
1996 * @param fFlags Reserved, must be zero.
1997 * @remark A forced termination of the console is easiest done by forcing the
1998 * callbacks to return fatal failures.
1999 */
2000DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
2001{
2002 /*
2003 * Validate input.
2004 */
2005 AssertPtrNullReturn(pVM, VERR_INVALID_POINTER);
2006
2007 /*
2008 * Allocate and initialize instance data
2009 */
2010 PDBGC pDbgc;
2011 int rc = dbgcCreate(&pDbgc, pBack, fFlags);
2012 if (RT_FAILURE(rc))
2013 return rc;
2014
2015 /*
2016 * Print welcome message.
2017 */
2018 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2019 "Welcome to the VirtualBox Debugger!\n");
2020
2021 /*
2022 * Attach to the specified VM.
2023 */
2024 if (RT_SUCCESS(rc) && pVM)
2025 {
2026 rc = DBGFR3Attach(pVM);
2027 if (RT_SUCCESS(rc))
2028 {
2029 pDbgc->pVM = pVM;
2030 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2031 "Current VM is %08x\n" /** @todo get and print the VM name! */
2032 "VBoxDbg> ",
2033 pDbgc->pVM);
2034 }
2035 else
2036 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
2037 }
2038 else
2039 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2040 "VBoxDbg> ");
2041
2042 /*
2043 * Run the main loop.
2044 */
2045 if (RT_SUCCESS(rc))
2046 rc = dbgcRun(pDbgc);
2047
2048 /*
2049 * Cleanup console debugger session.
2050 */
2051 dbgcDestroy(pDbgc);
2052 return rc;
2053}
2054
Note: See TracBrowser for help on using the repository browser.

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