VirtualBox

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

Last change on this file since 8216 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

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