VirtualBox

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

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

DBGF,CPUM,DBGC: Use DBGFReg in the debugger, stop accessing CPUMCTX structures directly when messing with registers.

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