VirtualBox

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

Last change on this file since 10596 was 9838, checked in by vboxsync, 17 years ago

Fix for parsing nonsense.

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