VirtualBox

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

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

*: spelling fixes, thanks Timeless!

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

© 2023 Oracle
ContactPrivacy policyTerms of Use