VirtualBox

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

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

Debugger Console: Drop the HC_FAR type.

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