VirtualBox

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

Last change on this file since 31510 was 31510, checked in by vboxsync, 14 years ago

The debugger is back in the OSE.

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