Changeset 5668 in vbox
- Timestamp:
- Nov 11, 2007 4:36:28 AM (17 years ago)
- svn:sync-xref-src-repo-rev:
- 26012
- Location:
- trunk/src/VBox/Debugger
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGCInternal.h
r5666 r5668 1 1 /** $Id$ */ 2 2 /** @file 3 * DBGC - Debugger Console .3 * DBGC - Debugger Console, Internal Header File. 4 4 */ 5 5 … … 16 16 */ 17 17 18 19 /** @page pg_dbgc DBGC - The Debug Console 20 * 21 * The debugger console is a first attempt to make some interactive 22 * debugging facilities for the VirtualBox backend (i.e. the VM). At a later 23 * stage we'll make a fancy gui around this, but for the present a telnet (or 24 * serial terminal) will have to suffice. 25 * 26 * The debugger is only built into the VM with debug builds or when 27 * VBOX_WITH_DEBUGGER is defined. There might be need for \#ifdef'ing on this 28 * define to enable special debugger hooks, but the general approach is to 29 * make generic interfaces. The individual components also can register 30 * external commands, and such code must be within \#ifdef. 31 * 32 * 33 * @section sec_dbgc_op Operation (intentions) 34 * 35 * The console will process commands in a manner similar to the OS/2 and 36 * windows kernel debuggers. This means ';' is a command separator and 37 * that when possible we'll use the same command names as these two uses. 38 * 39 * 40 * @subsection sec_dbg_op_numbers Numbers 41 * 42 * Numbers are hexadecimal unless specified with a prefix indicating 43 * elsewise. Prefixes: 44 * - '0x' - hexadecimal. 45 * - '0i' - decimal 46 * - '0t' - octal. 47 * - '0y' - binary. 48 * 49 * 50 * @subsection sec_dbg_op_address Addressing modes 51 * 52 * - Default is flat. For compatability '%' also means flat. 53 * - Segmented addresses are specified selector:offset. 54 * - Physical addresses are specified using '%%'. 55 * - The default target for the addressing is the guest context, the '#' 56 * will override this and set it to the host. 57 * 58 * 59 * @subsection sec_dbg_op_evalution Evaluation 60 * 61 * As time permits support will be implemented support for a subset of the C 62 * binary operators, starting with '+', '-', '*' and '/'. Support for variables 63 * are provided thru commands 'set' and 'unset' and the unary operator '$'. The 64 * unary '@' operator will indicate function calls. The debugger needs a set of 65 * memory read functions, but we might later extend this to allow registration of 66 * external functions too. 67 * 68 * A special command '?' will then be added which evalutates a given expression 69 * and prints it in all the different formats. 70 * 71 * 72 * @subsection sec_dbg_op_registers Registers 73 * 74 * Registers are addressed using their name. Some registers which have several fields 75 * (like gdtr) will have separate names indicating the different fields. The default 76 * register set is the guest one. To access the hypervisor register one have to 77 * prefix the register names with '.'. 78 * 79 * 80 * @subsection sec_dbg_op_commands Commands 81 * 82 * The commands are all lowercase, case sensitive, and starting with a letter. We will 83 * later add some special commands ('?' for evaulation) and perhaps command classes ('.', '!') 84 * 85 * 86 * @section sec_dbg_tasks Tasks 87 * 88 * To implement DBGT and instrument VMM for basic state inspection and log 89 * viewing, the follwing task must be executed: 90 * 91 * -# Basic threading layer in RT. 92 * -# Basic tcpip server abstration in RT. 93 * -# Write DBGC. 94 * -# Write DBCTCP. 95 * -# Integrate with VMM and the rest. 96 * -# Start writing DBGF (VMM). 97 */ 98 99 18 #ifndef ___DBGCInternal_h 19 #define ___DBGCInternal_h 100 20 101 21 … … 103 23 * Header Files * 104 24 *******************************************************************************/ 105 #define LOG_GROUP LOG_GROUP_DBGC106 25 #include <VBox/dbg.h> 107 26 #include <VBox/dbgf.h> … … 114 33 #include <VBox/param.h> 115 34 #include <VBox/err.h> 116 #include <VBox/log.h> 117 118 #include <iprt/alloc.h> 119 #include <iprt/alloca.h> 120 #include <iprt/string.h> 121 #include <iprt/assert.h> 122 #include <iprt/ctype.h> 123 124 #include <stdlib.h> 125 #include <stdio.h> 126 35 36 37 /******************************************************************************* 38 * Defined Constants And Macros * 39 *******************************************************************************/ 127 40 /* to err.h! */ 128 41 #define VERR_DBGC_QUIT (-11999) … … 160 73 161 74 162 163 /*******************************************************************************164 * Defined Constants And Macros *165 *******************************************************************************/166 /** Makes a DBGC variable type pair.167 * Typically used by binary operators. */168 #define BINARY_TYPE_PAIR(type1, type2) (type1 | (type2 << 16))169 170 171 75 /******************************************************************************* 172 76 * Structures and Typedefs * … … 433 337 * Internal Functions * 434 338 *******************************************************************************/ 435 static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 436 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 437 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 438 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 439 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 440 static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 441 static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 442 static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 443 static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 444 static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 445 static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 446 static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 447 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 448 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 449 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 450 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 451 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 452 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 453 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 454 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 455 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 456 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 457 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 458 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 459 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 460 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 461 462 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 463 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 464 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 465 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 466 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 467 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 468 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 469 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 470 static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 471 static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 472 static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 473 static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 474 static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 475 static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 476 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 477 static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 478 static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 479 480 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 481 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 482 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 483 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 484 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 485 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 486 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 487 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 488 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 489 490 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 491 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 492 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 493 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 494 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 495 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 496 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 497 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 498 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 499 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 500 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 501 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 502 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 503 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 504 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 505 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 506 507 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult); 508 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue); 509 339 #if 0 510 340 static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat); 511 341 static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb); … … 525 355 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult); 526 356 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd); 357 #endif 527 358 528 359 … … 530 361 * Global Variables * 531 362 *******************************************************************************/ 532 /**533 * Pointer to head of the list of external commands.534 */535 static PDBGCEXTCMDS g_pExtCmdsHead; /** @todo rw protect g_pExtCmdsHead! */536 /** Locks the g_pExtCmdsHead list for reading. */537 #define DBGCEXTCMDS_LOCK_RD() do { } while (0)538 /** Locks the g_pExtCmdsHead list for writing. */539 #define DBGCEXTCMDS_LOCK_WR() do { } while (0)540 /** UnLocks the g_pExtCmdsHead list after reading. */541 #define DBGCEXTCMDS_UNLOCK_RD() do { } while (0)542 /** UnLocks the g_pExtCmdsHead list after writing. */543 #define DBGCEXTCMDS_UNLOCK_WR() do { } while (0)544 545 546 /** One argument of any kind. */547 static const DBGCVARDESC g_aArgAny[] =548 {549 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */550 { 0, 1, DBGCVAR_CAT_ANY, 0, "var", "Any type of argument." },551 };552 553 /** Multiple string arguments (min 1). */554 static const DBGCVARDESC g_aArgMultiStr[] =555 {556 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */557 { 1, ~0, DBGCVAR_CAT_STRING, 0, "strings", "One or more strings." },558 };559 560 /** Filename string. */561 static const DBGCVARDESC g_aArgFilename[] =562 {563 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */564 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },565 };566 567 568 /** 'br' arguments. */569 static const DBGCVARDESC g_aArgBrkREM[] =570 {571 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */572 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },573 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },574 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },575 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },576 };577 578 579 /** 'dg', 'dga', 'dl', 'dla' arguments. */580 static const DBGCVARDESC g_aArgDumpDT[] =581 {582 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */583 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "sel", "Selector or selector range." },584 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Far address which selector should be dumped." },585 };586 587 588 /** 'di', 'dia' arguments. */589 static const DBGCVARDESC g_aArgDumpIDT[] =590 {591 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */592 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "int", "The interrupt vector or interrupt vector range." },593 };594 595 596 /** 'dpd*' arguments. */597 static const DBGCVARDESC g_aArgDumpPD[] =598 {599 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */600 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "index", "Index into the page directory." },601 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from. Range is applied to the page directory." },602 };603 604 605 /** 'dpda' arguments. */606 static const DBGCVARDESC g_aArgDumpPDAddr[] =607 {608 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */609 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page directory entry to start dumping from." },610 };611 612 613 /** 'dpt?' arguments. */614 static const DBGCVARDESC g_aArgDumpPT[] =615 {616 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */617 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from." },618 };619 620 621 /** 'dpta' arguments. */622 static const DBGCVARDESC g_aArgDumpPTAddr[] =623 {624 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */625 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page table entry to start dumping from." },626 };627 628 629 /** 'dt' arguments. */630 static const DBGCVARDESC g_aArgDumpTSS[] =631 {632 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */633 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "tss", "TSS selector number." },634 { 0, 1, DBGCVAR_CAT_POINTER, 0, "tss:ign|addr", "TSS address. If the selector is a TSS selector, the offset will be ignored." }635 };636 637 638 /** 'help' arguments. */639 static const DBGCVARDESC g_aArgHelp[] =640 {641 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */642 { 0, ~0, DBGCVAR_CAT_STRING, 0, "cmd/op", "Zero or more command or operator names." },643 };644 645 646 /** 'info' arguments. */647 static const DBGCVARDESC g_aArgInfo[] =648 {649 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */650 { 1, 1, DBGCVAR_CAT_STRING, 0, "info", "The name of the info to display." },651 { 0, 1, DBGCVAR_CAT_STRING, 0, "args", "String arguments to the handler." },652 };653 654 655 /** loadsyms arguments. */656 static const DBGCVARDESC g_aArgLoadSyms[] =657 {658 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */659 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },660 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "delta", "Delta to add to the loaded symbols. (optional)" },661 { 0, 1, DBGCVAR_CAT_STRING, 0, "module name", "Module name." },662 { 0, 1, DBGCVAR_CAT_POINTER, DBGCVD_FLAGS_DEP_PREV, "module address", "Module address." },663 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "module size", "The module size. (optional)" },664 };665 666 667 /** log arguments. */668 static const DBGCVARDESC g_aArgLog[] =669 {670 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */671 { 1, 1, DBGCVAR_CAT_STRING, 0, "groups", "Group modifier string (quote it!)." }672 };673 674 675 /** logdest arguments. */676 static const DBGCVARDESC g_aArgLogDest[] =677 {678 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */679 { 1, 1, DBGCVAR_CAT_STRING, 0, "dests", "Destination modifier string (quote it!)." }680 };681 682 683 /** logflags arguments. */684 static const DBGCVARDESC g_aArgLogFlags[] =685 {686 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */687 { 1, 1, DBGCVAR_CAT_STRING, 0, "flags", "Flag modifier string (quote it!)." }688 };689 690 691 /** 'set' arguments */692 static const DBGCVARDESC g_aArgSet[] =693 {694 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */695 { 1, 1, DBGCVAR_CAT_STRING, 0, "var", "Variable name." },696 { 1, 1, DBGCVAR_CAT_ANY, 0, "value", "Value to assign to the variable." },697 };698 699 700 701 702 703 363 /** Command descriptors for the basic commands. */ 704 static const DBGCCMD g_aCmds[] = 705 { 706 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */ 707 { "br", 1, 4, &g_aArgBrkREM[0], ELEMENTS(g_aArgBrkREM), NULL, 0, dbgcCmdBrkREM, "<address> [passes [max passes]] [cmds]", 708 "Sets a recompiler specific breakpoint." }, 709 { "bye", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." }, 710 { "dg", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT)." }, 711 { "dga", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT) including not-present entries." }, 712 { "di", 0, ~0, &g_aArgDumpIDT[0], ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT)." }, 713 { "dia", 0, ~0, &g_aArgDumpIDT[0], ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT) including not-present entries." }, 714 { "dl", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT)." }, 715 { "dla", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT) including not-present entries." }, 716 { "dpd", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the default context." }, 717 { "dpda", 0, 1, &g_aArgDumpPDAddr[0],ELEMENTS(g_aArgDumpPDAddr),NULL, 0, dbgcCmdDumpPageDir, "[addr]", "Dumps specified page directory." }, 718 { "dpdb", 1, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDirBoth, "[addr] [index]", "Dumps page directory entries of the guest and the hypervisor. " }, 719 { "dpdg", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the guest." }, 720 { "dpdh", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the hypervisor. " }, 721 { "dpt", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the default context." }, 722 { "dpta", 1, 1, &g_aArgDumpPTAddr[0],ELEMENTS(g_aArgDumpPTAddr), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps specified page table." }, 723 { "dptb", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTableBoth,"<addr>", "Dumps page table entries of the guest and the hypervisor." }, 724 { "dptg", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the guest." }, 725 { "dpth", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the hypervisor." }, 726 { "dt", 0, 1, &g_aArgDumpTSS[0], ELEMENTS(g_aArgDumpTSS), NULL, 0, dbgcCmdDumpTSS, "[tss|tss:ign|addr]", "Dump the task state segment (TSS)." }, 727 { "echo", 1, ~0, &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr), NULL, 0, dbgcCmdEcho, "<str1> [str2..[strN]]", "Displays the strings separated by one blank space and the last one followed by a newline." }, 728 { "exit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." }, 729 { "format", 1, 1, &g_aArgAny[0], ELEMENTS(g_aArgAny), NULL, 0, dbgcCmdFormat, "", "Evaluates an expression and formats it." }, 730 { "harakiri", 0, 0, NULL, 0, NULL, 0, dbgcCmdHarakiri, "", "Kills debugger process." }, 731 { "help", 0, ~0, &g_aArgHelp[0], ELEMENTS(g_aArgHelp), NULL, 0, dbgcCmdHelp, "[cmd/op [..]]", "Display help. For help about info items try 'info help'." }, 732 { "info", 1, 2, &g_aArgInfo[0], ELEMENTS(g_aArgInfo), NULL, 0, dbgcCmdInfo, "<info> [args]", "Display info register in the DBGF. For a list of info items try 'info help'." }, 733 { "loadsyms", 1, 5, &g_aArgLoadSyms[0], ELEMENTS(g_aArgLoadSyms), NULL, 0, dbgcCmdLoadSyms, "<filename> [delta] [module] [module address]", "Loads symbols from a text file. Optionally giving a delta and a module." }, 734 { "loadvars", 1, 1, &g_aArgFilename[0], ELEMENTS(g_aArgFilename), NULL, 0, dbgcCmdLoadVars, "<filename>", "Load variables from file. One per line, same as the args to the set command." }, 735 { "log", 1, 1, &g_aArgLog[0], ELEMENTS(g_aArgLog), NULL, 0, dbgcCmdLog, "<group string>", "Modifies the logging group settings (VBOX_LOG)" }, 736 { "logdest", 1, 1, &g_aArgLogDest[0], ELEMENTS(g_aArgLogDest), NULL, 0, dbgcCmdLogDest, "<dest string>", "Modifies the logging destination (VBOX_LOG_DEST)." }, 737 { "logflags", 1, 1, &g_aArgLogFlags[0], ELEMENTS(g_aArgLogFlags), NULL, 0, dbgcCmdLogFlags, "<flags string>", "Modifies the logging flags (VBOX_LOG_FLAGS)." }, 738 { "quit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." }, 739 { "runscript", 1, 1, &g_aArgFilename[0], ELEMENTS(g_aArgFilename), NULL, 0, dbgcCmdRunScript, "<filename>", "Runs the command listed in the script. Lines starting with '#' (after removing blanks) are comment. blank lines are ignored. Stops on failure." }, 740 { "set", 2, 2, &g_aArgSet[0], ELEMENTS(g_aArgSet), NULL, 0, dbgcCmdSet, "<var> <value>", "Sets a global variable." }, 741 { "showvars", 0, 0, NULL, 0, NULL, 0, dbgcCmdShowVars, "", "List all the defined variables." }, 742 { "stop", 0, 0, NULL, 0, NULL, 0, dbgcCmdStop, "", "Stop execution." }, 743 { "unset", 1, ~0, &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr), NULL, 0, dbgcCmdUnset, "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." }, 744 }; 745 746 747 /** 'ba' arguments. */ 748 static const DBGCVARDESC g_aArgBrkAcc[] = 749 { 750 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 751 { 1, 1, DBGCVAR_CAT_STRING, 0, "access", "The access type: x=execute, rw=read/write (alias r), w=write, i=not implemented." }, 752 { 1, 1, DBGCVAR_CAT_NUMBER, 0, "size", "The access size: 1, 2, 4, or 8. 'x' access requires 1, and 8 requires amd64 long mode." }, 753 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." }, 754 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" }, 755 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" }, 756 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" }, 757 }; 758 759 760 /** 'bc', 'bd', 'be' arguments. */ 761 static const DBGCVARDESC g_aArgBrks[] = 762 { 763 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 764 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "#bp", "Breakpoint number." }, 765 { 0, 1, DBGCVAR_CAT_STRING, 0, "all", "All breakpoints." }, 766 }; 767 768 769 /** 'bp' arguments. */ 770 static const DBGCVARDESC g_aArgBrkSet[] = 771 { 772 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 773 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." }, 774 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" }, 775 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" }, 776 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" }, 777 }; 778 779 780 /** 'd?' arguments. */ 781 static const DBGCVARDESC g_aArgDumpMem[] = 782 { 783 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 784 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start dumping memory." }, 785 }; 786 787 788 /** 'ln' arguments. */ 789 static const DBGCVARDESC g_aArgListNear[] = 790 { 791 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 792 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Address of the symbol to look up." }, 793 { 0, ~0, DBGCVAR_CAT_SYMBOL, 0, "symbol", "Symbol to lookup." }, 794 }; 795 796 /** 'ln' return. */ 797 static const DBGCVARDESC g_RetListNear = 798 { 799 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "The last resolved symbol/address with adjusted range." 800 }; 801 802 803 /** 'ls' arguments. */ 804 static const DBGCVARDESC g_aArgListSource[] = 805 { 806 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 807 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start looking for source lines." }, 808 }; 809 810 811 /** 'm' argument. */ 812 static const DBGCVARDESC g_aArgMemoryInfo[] = 813 { 814 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 815 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Pointer to obtain info about." }, 816 }; 817 818 819 /** 'r' arguments. */ 820 static const DBGCVARDESC g_aArgReg[] = 821 { 822 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 823 { 0, 1, DBGCVAR_CAT_SYMBOL, 0, "register", "Register to show or set." }, 824 { 0, 1, DBGCVAR_CAT_NUMBER_NO_RANGE, DBGCVD_FLAGS_DEP_PREV, "value", "New register value." }, 825 }; 826 827 828 /** 's' arguments. */ 829 static const DBGCVARDESC g_aArgSearchMem[] = 830 { 831 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 832 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "range", "Register to show or set." }, 833 { 1, ~0, DBGCVAR_CAT_ANY, 0, "pattern", "Pattern to search for." }, 834 }; 835 836 837 /** 'u' arguments. */ 838 static const DBGCVARDESC g_aArgUnassemble[] = 839 { 840 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 841 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start disassembling." }, 842 }; 843 844 364 extern const DBGCCMD g_aCmds[]; 845 365 /** Command descriptors for the CodeView / WinDbg emulation. 846 366 * The emulation isn't attempting to be identical, only somewhat similar. 847 367 */ 848 static const DBGCCMD g_aCmdsCodeView[] = 849 { 850 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */ 851 { "ba", 3, 6, &g_aArgBrkAcc[0], RT_ELEMENTS(g_aArgBrkAcc), NULL, 0, dbgcCmdBrkAccess, "<access> <size> <address> [passes [max passes]] [cmds]", 852 "Sets a data access breakpoint." }, 853 { "bc", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkClear, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." }, 854 { "bd", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkDisable, "all | <bp#> [bp# []]", "Disables a set of breakpoints." }, 855 { "be", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkEnable, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." }, 856 { "bl", 0, 0, NULL, 0, NULL, 0, dbgcCmdBrkList, "", "Lists all the breakpoints." }, 857 { "bp", 1, 4, &g_aArgBrkSet[0], RT_ELEMENTS(g_aArgBrkSet), NULL, 0, dbgcCmdBrkSet, "<address> [passes [max passes]] [cmds]", 858 "Sets a breakpoint (int 3)." }, 859 { "d", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory using last element size." }, 860 { "da", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory as ascii string." }, 861 { "db", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in bytes." }, 862 { "dd", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in double words." }, 863 { "dq", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in quad words." }, 864 { "dw", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in words." }, 865 { "g", 0, 0, NULL, 0, NULL, 0, dbgcCmdGo, "", "Continue execution." }, 866 { "k", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack." }, 867 { "kg", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack - guest." }, 868 { "kh", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack - hypervisor." }, 869 { "ln", 0, ~0, &g_aArgListNear[0], RT_ELEMENTS(g_aArgListNear), &g_RetListNear, 0, dbgcCmdListNear, "[addr/sym [..]]", "List symbols near to the address. Default address is CS:EIP." }, 870 { "ls", 0, 1, &g_aArgListSource[0],RT_ELEMENTS(g_aArgListSource),NULL, 0, dbgcCmdListSource, "[addr]", "Source." }, 871 { "m", 1, 1, &g_aArgMemoryInfo[0],RT_ELEMENTS(g_aArgMemoryInfo),NULL, 0, dbgcCmdMemoryInfo, "<addr>", "Display information about that piece of memory." }, 872 { "r", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdReg, "[reg [newval]]", "Show or set register(s) - active reg set." }, 873 { "rg", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegGuest, "[reg [newval]]", "Show or set register(s) - guest reg set." }, 874 { "rh", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegHyper, "[reg [newval]]", "Show or set register(s) - hypervisor reg set." }, 875 { "rt", 0, 0, NULL, 0, NULL, 0, dbgcCmdRegTerse, "", "Toggles terse / verbose register info." }, 876 //{ "s", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Continue last search." }, 877 { "sa", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for an ascii string." }, 878 { "sb", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for one or more bytes." }, 879 { "sd", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for one or more double words." }, 880 { "sq", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for one or more quad words." }, 881 { "su", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for an unicode string." }, 882 { "sw", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for one or more words." }, 883 { "t", 0, 0, NULL, 0, NULL, 0, dbgcCmdTrace, "", "Instruction trace (step into)." }, 884 { "u", 0, 1, &g_aArgUnassemble[0],RT_ELEMENTS(g_aArgUnassemble),NULL, 0, dbgcCmdUnassemble, "[addr]", "Unassemble." }, 885 }; 886 887 888 /** Operators. */ 889 static const DBGCOP g_aOps[] = 890 { 891 /* szName is initialized as a 4 char array because of M$C elsewise optimizing it away in /Ox mode (the 'const char' vs 'char' problem). */ 892 /* szName, cchName, fBinary, iPrecedence, pfnHandlerUnary, pfnHandlerBitwise */ 893 { {'-'}, 1, false, 1, dbgcOpMinus, NULL, "Unary minus." }, 894 { {'+'}, 1, false, 1, dbgcOpPluss, NULL, "Unary pluss." }, 895 { {'!'}, 1, false, 1, dbgcOpBooleanNot, NULL, "Boolean not." }, 896 { {'~'}, 1, false, 1, dbgcOpBitwiseNot, NULL, "Bitwise complement." }, 897 { {':'}, 1, true, 2, NULL, dbgcOpAddrFar, "Far pointer." }, 898 { {'%'}, 1, false, 3, dbgcOpAddrFlat, NULL, "Flat address." }, 899 { {'%','%'}, 2, false, 3, dbgcOpAddrPhys, NULL, "Physical address." }, 900 { {'#'}, 1, false, 3, dbgcOpAddrHost, NULL, "Flat host address." }, 901 { {'#','%','%'}, 3, false, 3, dbgcOpAddrHostPhys, NULL, "Physical host address." }, 902 { {'$'}, 1, false, 3, dbgcOpVar, NULL, "Reference a variable." }, 903 { {'*'}, 1, true, 10, NULL, dbgcOpMult, "Multiplication." }, 904 { {'/'}, 1, true, 11, NULL, dbgcOpDiv, "Division." }, 905 { {'%'}, 1, true, 12, NULL, dbgcOpMod, "Modulus." }, 906 { {'+'}, 1, true, 13, NULL, dbgcOpAdd, "Addition." }, 907 { {'-'}, 1, true, 14, NULL, dbgcOpSub, "Subtraction." }, 908 { {'<','<'}, 2, true, 15, NULL, dbgcOpBitwiseShiftLeft, "Bitwise left shift." }, 909 { {'>','>'}, 2, true, 16, NULL, dbgcOpBitwiseShiftRight, "Bitwise right shift." }, 910 { {'&'}, 1, true, 17, NULL, dbgcOpBitwiseAnd, "Bitwise and." }, 911 { {'^'}, 1, true, 18, NULL, dbgcOpBitwiseXor, "Bitwise exclusiv or." }, 912 { {'|'}, 1, true, 19, NULL, dbgcOpBitwiseOr, "Bitwise inclusive or." }, 913 { {'&','&'}, 2, true, 20, NULL, dbgcOpBooleanAnd, "Boolean and." }, 914 { {'|','|'}, 2, true, 21, NULL, dbgcOpBooleanOr, "Boolean or." }, 915 { {'L'}, 1, true, 22, NULL, dbgcOpRangeLength, "Range elements." }, 916 { {'L','B'}, 2, true, 23, NULL, dbgcOpRangeLengthBytes, "Range bytes." }, 917 { {'T'}, 1, true, 24, NULL, dbgcOpRangeTo, "Range to." } 918 }; 919 920 /** Bitmap where set bits indicates the characters the may start an operator name. */ 921 static uint32_t g_bmOperatorChars[256 / (4*8)]; 922 923 /** Register symbol uUser value. 924 * @{ 925 */ 926 /** If set the register set is the hypervisor and not the guest one. */ 927 #define SYMREG_FLAGS_HYPER RT_BIT(20) 928 /** If set a far conversion of the value will use the high 16 bit for the selector. 929 * If clear the low 16 bit will be used. */ 930 #define SYMREG_FLAGS_HIGH_SEL RT_BIT(21) 931 /** The shift value to calc the size of a register symbol from the uUser value. */ 932 #define SYMREG_SIZE_SHIFT (24) 933 /** Get the offset */ 934 #define SYMREG_OFFSET(uUser) (uUser & ((1 << 20) - 1)) 935 /** Get the size. */ 936 #define SYMREG_SIZE(uUser) ((uUser >> SYMREG_SIZE_SHIFT) & 0xff) 937 /** 1 byte. */ 938 #define SYMREG_SIZE_1 ( 1 << SYMREG_SIZE_SHIFT) 939 /** 2 byte. */ 940 #define SYMREG_SIZE_2 ( 2 << SYMREG_SIZE_SHIFT) 941 /** 4 byte. */ 942 #define SYMREG_SIZE_4 ( 4 << SYMREG_SIZE_SHIFT) 943 /** 6 byte. */ 944 #define SYMREG_SIZE_6 ( 6 << SYMREG_SIZE_SHIFT) 945 /** 8 byte. */ 946 #define SYMREG_SIZE_8 ( 8 << SYMREG_SIZE_SHIFT) 947 /** 12 byte. */ 948 #define SYMREG_SIZE_12 (12 << SYMREG_SIZE_SHIFT) 949 /** 16 byte. */ 950 #define SYMREG_SIZE_16 (16 << SYMREG_SIZE_SHIFT) 951 /** @} */ 952 953 /** Builtin Symbols. 954 * ASSUMES little endian register representation! 955 */ 956 static const DBGCSYM g_aSyms[] = 957 { 958 { "eax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_4 }, 959 { "ax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_2 }, 960 { "al", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_1 }, 961 { "ah", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) + 1 | SYMREG_SIZE_1 }, 962 963 { "ebx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_4 }, 964 { "bx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_2 }, 965 { "bl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_1 }, 966 { "bh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) + 1 | SYMREG_SIZE_1 }, 967 968 { "ecx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_4 }, 969 { "cx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_2 }, 970 { "cl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_1 }, 971 { "ch", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) + 1 | SYMREG_SIZE_1 }, 972 973 { "edx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_4 }, 974 { "dx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_2 }, 975 { "dl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_1 }, 976 { "dh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) + 1 | SYMREG_SIZE_1 }, 977 978 { "edi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_4 }, 979 { "di", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_2 }, 980 981 { "esi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_4 }, 982 { "si", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_2 }, 983 984 { "ebp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_4 }, 985 { "bp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_2 }, 986 987 { "esp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_4 }, 988 { "sp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_2 }, 989 990 { "eip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_4 }, 991 { "ip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_2 }, 992 993 { "efl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 }, 994 { "eflags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 }, 995 { "fl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 }, 996 { "flags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 }, 997 998 { "cs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cs) | SYMREG_SIZE_2 }, 999 { "ds", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ds) | SYMREG_SIZE_2 }, 1000 { "es", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, es) | SYMREG_SIZE_2 }, 1001 { "fs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, fs) | SYMREG_SIZE_2 }, 1002 { "gs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gs) | SYMREG_SIZE_2 }, 1003 { "ss", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ss) | SYMREG_SIZE_2 }, 1004 1005 { "cr0", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr0) | SYMREG_SIZE_4 }, 1006 { "cr2", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr2) | SYMREG_SIZE_4 }, 1007 { "cr3", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr3) | SYMREG_SIZE_4 }, 1008 { "cr4", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr4) | SYMREG_SIZE_4 }, 1009 1010 { "tr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, tr) | SYMREG_SIZE_2 }, 1011 { "ldtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ldtr) | SYMREG_SIZE_2 }, 1012 1013 { "gdtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr) | SYMREG_SIZE_6 }, 1014 { "gdtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2 }, 1015 { "gdtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 }, 1016 1017 { "idtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr) | SYMREG_SIZE_6 }, 1018 { "idtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2 }, 1019 { "idtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 }, 1020 1021 /* hypervisor */ 1022 1023 {".eax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1024 {".ax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1025 {".al", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 1026 {".ah", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 1027 1028 {".ebx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1029 {".bx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1030 {".bl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 1031 {".bh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 1032 1033 {".ecx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1034 {".cx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1035 {".cl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 1036 {".ch", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 1037 1038 {".edx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1039 {".dx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1040 {".dl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 1041 {".dh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 1042 1043 {".edi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1044 {".di", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1045 1046 {".esi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1047 {".si", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1048 1049 {".ebp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1050 {".bp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1051 1052 {".esp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1053 {".sp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1054 1055 {".eip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1056 {".ip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1057 1058 {".efl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1059 {".eflags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1060 {".fl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1061 {".flags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1062 1063 {".cs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cs) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1064 {".ds", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ds) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1065 {".es", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, es) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1066 {".fs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, fs) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1067 {".gs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gs) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1068 {".ss", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ss) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1069 1070 {".cr0", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr0) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1071 {".cr2", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr2) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1072 {".cr3", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr3) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1073 {".cr4", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr4) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1074 1075 {".tr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, tr) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1076 {".ldtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ldtr) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 1077 1078 {".gdtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr) | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER }, 1079 {".gdtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER }, 1080 {".gdtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1081 1082 {".idtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr) | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER }, 1083 {".idtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER }, 1084 {".idtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 1085 1086 }; 1087 1088 1089 /** 1090 * Prints full command help. 1091 */ 1092 static int dbgcPrintHelp(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, bool fExternal) 1093 { 1094 int rc; 1095 1096 /* the command */ 1097 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1098 "%s%-*s %-30s %s", 1099 fExternal ? "." : "", 1100 fExternal ? 10 : 11, 1101 pCmd->pszCmd, 1102 pCmd->pszSyntax, 1103 pCmd->pszDescription); 1104 if (!pCmd->cArgsMin && pCmd->cArgsMin == pCmd->cArgsMax) 1105 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <no args>\n"); 1106 else if (pCmd->cArgsMin == pCmd->cArgsMax) 1107 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u args>\n", pCmd->cArgsMin); 1108 else if (pCmd->cArgsMax == ~0U) 1109 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+ args>\n", pCmd->cArgsMin); 1110 else 1111 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u to %u args>\n", pCmd->cArgsMin, pCmd->cArgsMax); 1112 1113 /* argument descriptions. */ 1114 for (unsigned i = 0; i < pCmd->cArgDescs; i++) 1115 { 1116 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1117 " %-12s %s", 1118 pCmd->paArgDescs[i].pszName, 1119 pCmd->paArgDescs[i].pszDescription); 1120 if (!pCmd->paArgDescs[i].cTimesMin) 1121 { 1122 if (pCmd->paArgDescs[i].cTimesMax == ~0U) 1123 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional+>\n"); 1124 else 1125 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional-%u>\n", pCmd->paArgDescs[i].cTimesMax); 1126 } 1127 else 1128 { 1129 if (pCmd->paArgDescs[i].cTimesMax == ~0U) 1130 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+>\n", pCmd->paArgDescs[i].cTimesMin); 1131 else 1132 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u-%u>\n", pCmd->paArgDescs[i].cTimesMin, pCmd->paArgDescs[i].cTimesMax); 1133 } 1134 } 1135 return rc; 1136 } 1137 1138 1139 /** 1140 * The 'help' command. 1141 * 1142 * @returns VBox status. 1143 * @param pCmd Pointer to the command descriptor (as registered). 1144 * @param pCmdHlp Pointer to command helper functions. 1145 * @param pVM Pointer to the current VM (if any). 1146 * @param paArgs Pointer to (readonly) array of arguments. 1147 * @param cArgs Number of arguments in the array. 1148 */ 1149 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1150 { 1151 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1152 int rc = VINF_SUCCESS; 1153 unsigned i; 1154 1155 if (!cArgs) 1156 { 1157 /* 1158 * All the stuff. 1159 */ 1160 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1161 "VirtualBox Debugger\n" 1162 "-------------------\n" 1163 "\n" 1164 "Commands and Functions:\n"); 1165 for (i = 0; i < ELEMENTS(g_aCmds); i++) 1166 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1167 "%-11s %-30s %s\n", 1168 g_aCmds[i].pszCmd, 1169 g_aCmds[i].pszSyntax, 1170 g_aCmds[i].pszDescription); 1171 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1172 "\n" 1173 "Emulation: %s\n", pDbgc->pszEmulation); 1174 PCDBGCCMD pCmd = pDbgc->paEmulationCmds; 1175 for (i = 0; i < pDbgc->cEmulationCmds; i++, pCmd++) 1176 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1177 "%-11s %-30s %s\n", 1178 pCmd->pszCmd, 1179 pCmd->pszSyntax, 1180 pCmd->pszDescription); 1181 1182 if (g_pExtCmdsHead) 1183 { 1184 DBGCEXTCMDS_LOCK_RD(); 1185 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1186 "\n" 1187 "External Commands and Functions:\n"); 1188 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext) 1189 for (i = 0; i < pExtCmd->cCmds; i++) 1190 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1191 ".%-10s %-30s %s\n", 1192 pExtCmd->paCmds[i].pszCmd, 1193 pExtCmd->paCmds[i].pszSyntax, 1194 pExtCmd->paCmds[i].pszDescription); 1195 DBGCEXTCMDS_UNLOCK_RD(); 1196 } 1197 1198 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1199 "\n" 1200 "Operators:\n"); 1201 unsigned iPrecedence = 0; 1202 unsigned cLeft = ELEMENTS(g_aOps); 1203 while (cLeft > 0) 1204 { 1205 for (i = 0; i < ELEMENTS(g_aOps); i++) 1206 if (g_aOps[i].iPrecedence == iPrecedence) 1207 { 1208 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1209 "%-10s %s %s\n", 1210 g_aOps[i].szName, 1211 g_aOps[i].fBinary ? "Binary" : "Unary ", 1212 g_aOps[i].pszDescription); 1213 cLeft--; 1214 } 1215 iPrecedence++; 1216 } 1217 } 1218 else 1219 { 1220 /* 1221 * Search for the arguments (strings). 1222 */ 1223 for (unsigned iArg = 0; iArg < cArgs; iArg++) 1224 { 1225 Assert(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING); 1226 bool fFound = false; 1227 1228 /* lookup in the emulation command list first */ 1229 for (i = 0; i < pDbgc->cEmulationCmds; i++) 1230 if (!strcmp(pDbgc->paEmulationCmds[i].pszCmd, paArgs[iArg].u.pszString)) 1231 { 1232 rc = dbgcPrintHelp(pCmdHlp, &pDbgc->paEmulationCmds[i], false); 1233 fFound = true; 1234 break; 1235 } 1236 1237 /* lookup in the command list (even when found in the emulation) */ 1238 for (i = 0; i < ELEMENTS(g_aCmds); i++) 1239 if (!strcmp(g_aCmds[i].pszCmd, paArgs[iArg].u.pszString)) 1240 { 1241 rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], false); 1242 fFound = true; 1243 break; 1244 } 1245 1246 /* external commands */ 1247 if ( !fFound 1248 && g_pExtCmdsHead 1249 && paArgs[iArg].u.pszString[0] == '.') 1250 { 1251 DBGCEXTCMDS_LOCK_RD(); 1252 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext) 1253 for (i = 0; i < pExtCmd->cCmds; i++) 1254 if (!strcmp(pExtCmd->paCmds[i].pszCmd, paArgs[iArg].u.pszString + 1)) 1255 { 1256 rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], true); 1257 fFound = true; 1258 break; 1259 } 1260 DBGCEXTCMDS_UNLOCK_RD(); 1261 } 1262 1263 /* operators */ 1264 if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName)) 1265 { 1266 for (i = 0; i < ELEMENTS(g_aOps); i++) 1267 if (!strcmp(g_aOps[i].szName, paArgs[iArg].u.pszString)) 1268 { 1269 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1270 "%-10s %s %s\n", 1271 g_aOps[i].szName, 1272 g_aOps[i].fBinary ? "Binary" : "Unary ", 1273 g_aOps[i].pszDescription); 1274 fFound = true; 1275 break; 1276 } 1277 } 1278 1279 /* found? */ 1280 if (!fFound) 1281 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1282 "error: '%s' was not found!\n", 1283 paArgs[iArg].u.pszString); 1284 } /* foreach argument */ 1285 } 1286 1287 NOREF(pCmd); 1288 NOREF(pVM); 1289 NOREF(pResult); 1290 return rc; 1291 } 1292 1293 1294 /** 1295 * The 'quit', 'exit' and 'bye' commands. 1296 * 1297 * @returns VBox status. 1298 * @param pCmd Pointer to the command descriptor (as registered). 1299 * @param pCmdHlp Pointer to command helper functions. 1300 * @param pVM Pointer to the current VM (if any). 1301 * @param paArgs Pointer to (readonly) array of arguments. 1302 * @param cArgs Number of arguments in the array. 1303 */ 1304 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1305 { 1306 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Quitting console...\n"); 1307 NOREF(pCmd); 1308 NOREF(pVM); 1309 NOREF(paArgs); 1310 NOREF(cArgs); 1311 NOREF(pResult); 1312 return VERR_DBGC_QUIT; 1313 } 1314 1315 1316 /** 1317 * The 'go' command. 1318 * 1319 * @returns VBox status. 1320 * @param pCmd Pointer to the command descriptor (as registered). 1321 * @param pCmdHlp Pointer to command helper functions. 1322 * @param pVM Pointer to the current VM (if any). 1323 * @param paArgs Pointer to (readonly) array of arguments. 1324 * @param cArgs Number of arguments in the array. 1325 */ 1326 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1327 { 1328 /* 1329 * Check if the VM is halted or not before trying to resume it. 1330 */ 1331 if (!DBGFR3IsHalted(pVM)) 1332 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already running...\n"); 1333 else 1334 { 1335 int rc = DBGFR3Resume(pVM); 1336 if (VBOX_FAILURE(rc)) 1337 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Resume()."); 1338 } 1339 1340 NOREF(pCmd); 1341 NOREF(paArgs); 1342 NOREF(cArgs); 1343 NOREF(pResult); 1344 return 0; 1345 } 1346 1347 /** 1348 * The 'stop' command. 1349 * 1350 * @returns VBox status. 1351 * @param pCmd Pointer to the command descriptor (as registered). 1352 * @param pCmdHlp Pointer to command helper functions. 1353 * @param pVM Pointer to the current VM (if any). 1354 * @param paArgs Pointer to (readonly) array of arguments. 1355 * @param cArgs Number of arguments in the array. 1356 */ 1357 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1358 { 1359 /* 1360 * Check if the VM is halted or not before trying to halt it. 1361 */ 1362 int rc; 1363 if (DBGFR3IsHalted(pVM)) 1364 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already halted...\n"); 1365 else 1366 { 1367 rc = DBGFR3Halt(pVM); 1368 if (VBOX_SUCCESS(rc)) 1369 rc = VWRN_DBGC_CMD_PENDING; 1370 else 1371 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt()."); 1372 } 1373 1374 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult); 1375 return rc; 1376 } 1377 1378 1379 /** 1380 * The 'ba' command. 1381 * 1382 * @returns VBox status. 1383 * @param pCmd Pointer to the command descriptor (as registered). 1384 * @param pCmdHlp Pointer to command helper functions. 1385 * @param pVM Pointer to the current VM (if any). 1386 * @param paArgs Pointer to (readonly) array of arguments. 1387 * @param cArgs Number of arguments in the array. 1388 */ 1389 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/) 1390 { 1391 /* 1392 * Interpret access type. 1393 */ 1394 if ( !strchr("xrwi", paArgs[0].u.pszString[0]) 1395 || paArgs[0].u.pszString[1]) 1396 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access type '%s' for '%s'. Valid types are 'e', 'r', 'w' and 'i'.\n", 1397 paArgs[0].u.pszString, pCmd->pszCmd); 1398 uint8_t fType = 0; 1399 switch (paArgs[0].u.pszString[0]) 1400 { 1401 case 'x': fType = X86_DR7_RW_EO; break; 1402 case 'r': fType = X86_DR7_RW_RW; break; 1403 case 'w': fType = X86_DR7_RW_WO; break; 1404 case 'i': fType = X86_DR7_RW_IO; break; 1405 } 1406 1407 /* 1408 * Validate size. 1409 */ 1410 if (fType == X86_DR7_RW_EO && paArgs[1].u.u64Number != 1) 1411 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 'x' access type requires size 1!\n", 1412 paArgs[1].u.u64Number, pCmd->pszCmd); 1413 switch (paArgs[1].u.u64Number) 1414 { 1415 case 1: 1416 case 2: 1417 case 4: 1418 break; 1419 /*case 8: - later*/ 1420 default: 1421 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 1, 2 or 4!\n", 1422 paArgs[1].u.u64Number, pCmd->pszCmd); 1423 } 1424 uint8_t cb = (uint8_t)paArgs[1].u.u64Number; 1425 1426 /* 1427 * Convert the pointer to a DBGF address. 1428 */ 1429 DBGFADDRESS Address; 1430 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[2], &Address); 1431 if (VBOX_FAILURE(rc)) 1432 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[2], rc); 1433 1434 /* 1435 * Pick out the optional arguments. 1436 */ 1437 uint64_t iHitTrigger = 0; 1438 uint64_t iHitDisable = ~0; 1439 const char *pszCmds = NULL; 1440 unsigned iArg = 3; 1441 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 1442 { 1443 iHitTrigger = paArgs[iArg].u.u64Number; 1444 iArg++; 1445 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 1446 { 1447 iHitDisable = paArgs[iArg].u.u64Number; 1448 iArg++; 1449 } 1450 } 1451 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING) 1452 { 1453 pszCmds = paArgs[iArg].u.pszString; 1454 iArg++; 1455 } 1456 1457 /* 1458 * Try set the breakpoint. 1459 */ 1460 RTUINT iBp; 1461 rc = DBGFR3BpSetReg(pVM, &Address, iHitTrigger, iHitDisable, fType, cb, &iBp); 1462 if (VBOX_SUCCESS(rc)) 1463 { 1464 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1465 rc = dbgcBpAdd(pDbgc, iBp, pszCmds); 1466 if (VBOX_SUCCESS(rc)) 1467 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set access breakpoint %u at %VGv\n", iBp, Address.FlatPtr); 1468 if (rc == VERR_DBGC_BP_EXISTS) 1469 { 1470 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds); 1471 if (VBOX_SUCCESS(rc)) 1472 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated access breakpoint %u at %VGv\n", iBp, Address.FlatPtr); 1473 } 1474 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp); 1475 AssertRC(rc2); 1476 } 1477 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set access breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc); 1478 } 1479 1480 1481 /** 1482 * The 'bc' command. 1483 * 1484 * @returns VBox status. 1485 * @param pCmd Pointer to the command descriptor (as registered). 1486 * @param pCmdHlp Pointer to command helper functions. 1487 * @param pVM Pointer to the current VM (if any). 1488 * @param paArgs Pointer to (readonly) array of arguments. 1489 * @param cArgs Number of arguments in the array. 1490 */ 1491 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/) 1492 { 1493 /* 1494 * Enumerate the arguments. 1495 */ 1496 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1497 int rc = VINF_SUCCESS; 1498 for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++) 1499 { 1500 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 1501 { 1502 /* one */ 1503 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number; 1504 if (iBp != paArgs[iArg].u.u64Number) 1505 { 1506 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number); 1507 break; 1508 } 1509 int rc2 = DBGFR3BpClear(pVM, iBp); 1510 if (VBOX_FAILURE(rc2)) 1511 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp); 1512 if (VBOX_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND) 1513 dbgcBpDelete(pDbgc, iBp); 1514 } 1515 else if (!strcmp(paArgs[iArg].u.pszString, "all")) 1516 { 1517 /* all */ 1518 PDBGCBP pBp = pDbgc->pFirstBp; 1519 while (pBp) 1520 { 1521 RTUINT iBp = pBp->iBp; 1522 pBp = pBp->pNext; 1523 1524 int rc2 = DBGFR3BpClear(pVM, iBp); 1525 if (VBOX_FAILURE(rc2)) 1526 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp); 1527 if (VBOX_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND) 1528 dbgcBpDelete(pDbgc, iBp); 1529 } 1530 } 1531 else 1532 { 1533 /* invalid parameter */ 1534 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd); 1535 break; 1536 } 1537 } 1538 return rc; 1539 } 1540 1541 1542 /** 1543 * The 'bd' command. 1544 * 1545 * @returns VBox status. 1546 * @param pCmd Pointer to the command descriptor (as registered). 1547 * @param pCmdHlp Pointer to command helper functions. 1548 * @param pVM Pointer to the current VM (if any). 1549 * @param paArgs Pointer to (readonly) array of arguments. 1550 * @param cArgs Number of arguments in the array. 1551 */ 1552 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/) 1553 { 1554 /* 1555 * Enumerate the arguments. 1556 */ 1557 int rc = VINF_SUCCESS; 1558 for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++) 1559 { 1560 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 1561 { 1562 /* one */ 1563 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number; 1564 if (iBp != paArgs[iArg].u.u64Number) 1565 { 1566 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number); 1567 break; 1568 } 1569 rc = DBGFR3BpDisable(pVM, iBp); 1570 if (VBOX_FAILURE(rc)) 1571 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", iBp); 1572 } 1573 else if (!strcmp(paArgs[iArg].u.pszString, "all")) 1574 { 1575 /* all */ 1576 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1577 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext) 1578 { 1579 rc = DBGFR3BpDisable(pVM, pBp->iBp); 1580 if (VBOX_FAILURE(rc)) 1581 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", pBp->iBp); 1582 } 1583 } 1584 else 1585 { 1586 /* invalid parameter */ 1587 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd); 1588 break; 1589 } 1590 } 1591 return rc; 1592 } 1593 1594 1595 /** 1596 * The 'be' command. 1597 * 1598 * @returns VBox status. 1599 * @param pCmd Pointer to the command descriptor (as registered). 1600 * @param pCmdHlp Pointer to command helper functions. 1601 * @param pVM Pointer to the current VM (if any). 1602 * @param paArgs Pointer to (readonly) array of arguments. 1603 * @param cArgs Number of arguments in the array. 1604 */ 1605 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/) 1606 { 1607 /* 1608 * Enumerate the arguments. 1609 */ 1610 int rc = VINF_SUCCESS; 1611 for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++) 1612 { 1613 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 1614 { 1615 /* one */ 1616 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number; 1617 if (iBp != paArgs[iArg].u.u64Number) 1618 { 1619 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number); 1620 break; 1621 } 1622 rc = DBGFR3BpEnable(pVM, iBp); 1623 if (VBOX_FAILURE(rc)) 1624 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", iBp); 1625 } 1626 else if (!strcmp(paArgs[iArg].u.pszString, "all")) 1627 { 1628 /* all */ 1629 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1630 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext) 1631 { 1632 rc = DBGFR3BpEnable(pVM, pBp->iBp); 1633 if (VBOX_FAILURE(rc)) 1634 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", pBp->iBp); 1635 } 1636 } 1637 else 1638 { 1639 /* invalid parameter */ 1640 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd); 1641 break; 1642 } 1643 } 1644 return rc; 1645 } 1646 1647 1648 /** 1649 * Breakpoint enumeration callback function. 1650 * 1651 * @returns VBox status code. Any failure will stop the enumeration. 1652 * @param pVM The VM handle. 1653 * @param pvUser The user argument. 1654 * @param pBp Pointer to the breakpoint information. (readonly) 1655 */ 1656 static DECLCALLBACK(int) dbgcEnumBreakpointsCallback(PVM pVM, void *pvUser, PCDBGFBP pBp) 1657 { 1658 PDBGC pDbgc = (PDBGC)pvUser; 1659 PDBGCBP pDbgcBp = dbgcBpGet(pDbgc, pBp->iBp); 1660 1661 /* 1662 * BP type and size. 1663 */ 1664 char chType; 1665 char cb = 1; 1666 switch (pBp->enmType) 1667 { 1668 case DBGFBPTYPE_INT3: 1669 chType = 'p'; 1670 break; 1671 case DBGFBPTYPE_REG: 1672 switch (pBp->u.Reg.fType) 1673 { 1674 case X86_DR7_RW_EO: chType = 'x'; break; 1675 case X86_DR7_RW_WO: chType = 'w'; break; 1676 case X86_DR7_RW_IO: chType = 'i'; break; 1677 case X86_DR7_RW_RW: chType = 'r'; break; 1678 default: chType = '?'; break; 1679 1680 } 1681 cb = pBp->u.Reg.cb; 1682 break; 1683 case DBGFBPTYPE_REM: 1684 chType = 'r'; 1685 break; 1686 default: 1687 chType = '?'; 1688 break; 1689 } 1690 1691 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%2u %c %d %c %VGv %04RX64 (%04RX64 to ", 1692 pBp->iBp, pBp->fEnabled ? 'e' : 'd', cb, chType, 1693 pBp->GCPtr, pBp->cHits, pBp->iHitTrigger); 1694 if (pBp->iHitDisable == ~(uint64_t)0) 1695 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "~0) "); 1696 else 1697 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%04RX64)"); 1698 1699 /* 1700 * Try resolve the address. 1701 */ 1702 DBGFSYMBOL Sym; 1703 RTGCINTPTR off; 1704 int rc = DBGFR3SymbolByAddr(pVM, pBp->GCPtr, &off, &Sym); 1705 if (VBOX_SUCCESS(rc)) 1706 { 1707 if (!off) 1708 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s", Sym.szName); 1709 else if (off > 0) 1710 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%VGv", Sym.szName, off); 1711 else 1712 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%VGv", Sym.szName, -off); 1713 } 1714 1715 /* 1716 * The commands. 1717 */ 1718 if (pDbgcBp) 1719 { 1720 if (pDbgcBp->cchCmd) 1721 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n cmds: '%s'\n", 1722 pDbgcBp->szCmd); 1723 else 1724 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n"); 1725 } 1726 else 1727 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " [unknown bp]\n"); 1728 1729 return VINF_SUCCESS; 1730 } 1731 1732 1733 /** 1734 * The 'bl' command. 1735 * 1736 * @returns VBox status. 1737 * @param pCmd Pointer to the command descriptor (as registered). 1738 * @param pCmdHlp Pointer to command helper functions. 1739 * @param pVM Pointer to the current VM (if any). 1740 * @param paArgs Pointer to (readonly) array of arguments. 1741 * @param cArgs Number of arguments in the array. 1742 */ 1743 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/) 1744 { 1745 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1746 1747 /* 1748 * Enumerate the breakpoints. 1749 */ 1750 int rc = DBGFR3BpEnum(pVM, dbgcEnumBreakpointsCallback, pDbgc); 1751 if (VBOX_FAILURE(rc)) 1752 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnum failed.\n"); 1753 return rc; 1754 } 1755 1756 1757 /** 1758 * The 'bp' command. 1759 * 1760 * @returns VBox status. 1761 * @param pCmd Pointer to the command descriptor (as registered). 1762 * @param pCmdHlp Pointer to command helper functions. 1763 * @param pVM Pointer to the current VM (if any). 1764 * @param paArgs Pointer to (readonly) array of arguments. 1765 * @param cArgs Number of arguments in the array. 1766 */ 1767 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/) 1768 { 1769 /* 1770 * Convert the pointer to a DBGF address. 1771 */ 1772 DBGFADDRESS Address; 1773 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address); 1774 if (VBOX_FAILURE(rc)) 1775 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc); 1776 1777 /* 1778 * Pick out the optional arguments. 1779 */ 1780 uint64_t iHitTrigger = 0; 1781 uint64_t iHitDisable = ~0; 1782 const char *pszCmds = NULL; 1783 unsigned iArg = 1; 1784 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 1785 { 1786 iHitTrigger = paArgs[iArg].u.u64Number; 1787 iArg++; 1788 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 1789 { 1790 iHitDisable = paArgs[iArg].u.u64Number; 1791 iArg++; 1792 } 1793 } 1794 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING) 1795 { 1796 pszCmds = paArgs[iArg].u.pszString; 1797 iArg++; 1798 } 1799 1800 /* 1801 * Try set the breakpoint. 1802 */ 1803 RTUINT iBp; 1804 rc = DBGFR3BpSet(pVM, &Address, iHitTrigger, iHitDisable, &iBp); 1805 if (VBOX_SUCCESS(rc)) 1806 { 1807 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1808 rc = dbgcBpAdd(pDbgc, iBp, pszCmds); 1809 if (VBOX_SUCCESS(rc)) 1810 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set breakpoint %u at %VGv\n", iBp, Address.FlatPtr); 1811 if (rc == VERR_DBGC_BP_EXISTS) 1812 { 1813 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds); 1814 if (VBOX_SUCCESS(rc)) 1815 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated breakpoint %u at %VGv\n", iBp, Address.FlatPtr); 1816 } 1817 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp); 1818 AssertRC(rc2); 1819 } 1820 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc); 1821 } 1822 1823 1824 /** 1825 * The 'br' command. 1826 * 1827 * @returns VBox status. 1828 * @param pCmd Pointer to the command descriptor (as registered). 1829 * @param pCmdHlp Pointer to command helper functions. 1830 * @param pVM Pointer to the current VM (if any). 1831 * @param paArgs Pointer to (readonly) array of arguments. 1832 * @param cArgs Number of arguments in the array. 1833 */ 1834 static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/) 1835 { 1836 /* 1837 * Convert the pointer to a DBGF address. 1838 */ 1839 DBGFADDRESS Address; 1840 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address); 1841 if (VBOX_FAILURE(rc)) 1842 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc); 1843 1844 /* 1845 * Pick out the optional arguments. 1846 */ 1847 uint64_t iHitTrigger = 0; 1848 uint64_t iHitDisable = ~0; 1849 const char *pszCmds = NULL; 1850 unsigned iArg = 1; 1851 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 1852 { 1853 iHitTrigger = paArgs[iArg].u.u64Number; 1854 iArg++; 1855 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 1856 { 1857 iHitDisable = paArgs[iArg].u.u64Number; 1858 iArg++; 1859 } 1860 } 1861 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING) 1862 { 1863 pszCmds = paArgs[iArg].u.pszString; 1864 iArg++; 1865 } 1866 1867 /* 1868 * Try set the breakpoint. 1869 */ 1870 RTUINT iBp; 1871 rc = DBGFR3BpSetREM(pVM, &Address, iHitTrigger, iHitDisable, &iBp); 1872 if (VBOX_SUCCESS(rc)) 1873 { 1874 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1875 rc = dbgcBpAdd(pDbgc, iBp, pszCmds); 1876 if (VBOX_SUCCESS(rc)) 1877 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set REM breakpoint %u at %VGv\n", iBp, Address.FlatPtr); 1878 if (rc == VERR_DBGC_BP_EXISTS) 1879 { 1880 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds); 1881 if (VBOX_SUCCESS(rc)) 1882 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated REM breakpoint %u at %VGv\n", iBp, Address.FlatPtr); 1883 } 1884 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp); 1885 AssertRC(rc2); 1886 } 1887 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set REM breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc); 1888 } 1889 1890 1891 /** 1892 * The 'u' command. 1893 * 1894 * @returns VBox status. 1895 * @param pCmd Pointer to the command descriptor (as registered). 1896 * @param pCmdHlp Pointer to command helper functions. 1897 * @param pVM Pointer to the current VM (if any). 1898 * @param paArgs Pointer to (readonly) array of arguments. 1899 * @param cArgs Number of arguments in the array. 1900 */ 1901 static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1902 { 1903 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1904 1905 /* 1906 * Validate input. 1907 */ 1908 if ( cArgs > 1 1909 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType))) 1910 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n"); 1911 if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType)) 1912 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n"); 1913 if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType)) 1914 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n"); 1915 1916 /* 1917 * Find address. 1918 */ 1919 unsigned fFlags = DBGF_DISAS_FLAGS_NO_ADDRESS; 1920 if (!cArgs) 1921 { 1922 if (!DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType)) 1923 { 1924 pDbgc->DisasmPos.enmType = DBGCVAR_TYPE_GC_FAR; 1925 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVM) : CPUMGetHyperEIP(pVM); 1926 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVM) : CPUMGetHyperCS(pVM); 1927 if (pDbgc->fRegCtxGuest) 1928 fFlags |= DBGF_DISAS_FLAGS_CURRENT_GUEST; 1929 else 1930 fFlags |= DBGF_DISAS_FLAGS_CURRENT_HYPER; 1931 } 1932 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_NONE; 1933 } 1934 else 1935 pDbgc->DisasmPos = paArgs[0]; 1936 1937 /* 1938 * Range. 1939 */ 1940 switch (pDbgc->DisasmPos.enmRangeType) 1941 { 1942 case DBGCVAR_RANGE_NONE: 1943 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_ELEMENTS; 1944 pDbgc->DisasmPos.u64Range = 10; 1945 break; 1946 1947 case DBGCVAR_RANGE_ELEMENTS: 1948 if (pDbgc->DisasmPos.u64Range > 2048) 1949 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n"); 1950 break; 1951 1952 case DBGCVAR_RANGE_BYTES: 1953 if (pDbgc->DisasmPos.u64Range > 65536) 1954 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n"); 1955 break; 1956 1957 default: 1958 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DisasmPos.enmRangeType); 1959 } 1960 1961 /* 1962 * Convert physical and host addresses to guest addresses. 1963 */ 1964 int rc; 1965 switch (pDbgc->DisasmPos.enmType) 1966 { 1967 case DBGCVAR_TYPE_GC_FLAT: 1968 case DBGCVAR_TYPE_GC_FAR: 1969 break; 1970 case DBGCVAR_TYPE_GC_PHYS: 1971 case DBGCVAR_TYPE_HC_FLAT: 1972 case DBGCVAR_TYPE_HC_PHYS: 1973 case DBGCVAR_TYPE_HC_FAR: 1974 { 1975 DBGCVAR VarTmp; 1976 rc = pCmdHlp->pfnEval(pCmdHlp, &VarTmp, "%%(%Dv)", &pDbgc->DisasmPos); 1977 if (VBOX_FAILURE(rc)) 1978 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: failed to evaluate '%%(%Dv)' -> %Vrc .\n", pDbgc->DisasmPos, rc); 1979 pDbgc->DisasmPos = VarTmp; 1980 break; 1981 } 1982 default: AssertFailed(); break; 1983 } 1984 1985 /* 1986 * Print address. 1987 * todo: Change to list near. 1988 */ 1989 #if 0 1990 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DisasmPos); 1991 if (VBOX_FAILURE(rc)) 1992 return rc; 368 extern const DBGCCMD g_aCmdsCodeView[]; 369 1993 370 #endif 1994 1995 /*1996 * Do the disassembling.1997 */1998 unsigned cTries = 32;1999 int iRangeLeft = (int)pDbgc->DisasmPos.u64Range;2000 if (iRangeLeft == 0) /* klugde for 'r'. */2001 iRangeLeft = -1;2002 for (;;)2003 {2004 /*2005 * Disassemble the instruction.2006 */2007 char szDis[256];2008 uint32_t cbInstr = 1;2009 if (pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FLAT)2010 rc = DBGFR3DisasInstrEx(pVM, DBGF_SEL_FLAT, pDbgc->DisasmPos.u.GCFlat, fFlags, &szDis[0], sizeof(szDis), &cbInstr);2011 else2012 rc = DBGFR3DisasInstrEx(pVM, pDbgc->DisasmPos.u.GCFar.sel, pDbgc->DisasmPos.u.GCFar.off, fFlags, &szDis[0], sizeof(szDis), &cbInstr);2013 if (VBOX_SUCCESS(rc))2014 {2015 /* print it */2016 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-16DV %s\n", &pDbgc->DisasmPos, &szDis[0]);2017 if (VBOX_FAILURE(rc))2018 return rc;2019 }2020 else2021 {2022 /* bitch. */2023 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to disassemble instruction, skipping one byte.\n");2024 if (VBOX_FAILURE(rc))2025 return rc;2026 if (cTries-- > 0)2027 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Too many disassembly failures. Giving up.\n");2028 cbInstr = 1;2029 }2030 2031 /* advance */2032 if (iRangeLeft < 0) /* 'r' */2033 break;2034 if (pDbgc->DisasmPos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)2035 iRangeLeft--;2036 else2037 iRangeLeft -= cbInstr;2038 rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->DisasmPos, "(%Dv) + %x", &pDbgc->DisasmPos, cbInstr);2039 if (VBOX_FAILURE(rc))2040 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DisasmPos, cbInstr);2041 if (iRangeLeft <= 0)2042 break;2043 fFlags &= ~(DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_CURRENT_HYPER);2044 }2045 2046 NOREF(pCmd); NOREF(pResult);2047 return 0;2048 }2049 2050 2051 /**2052 * The 'ls' command.2053 *2054 * @returns VBox status.2055 * @param pCmd Pointer to the command descriptor (as registered).2056 * @param pCmdHlp Pointer to command helper functions.2057 * @param pVM Pointer to the current VM (if any).2058 * @param paArgs Pointer to (readonly) array of arguments.2059 * @param cArgs Number of arguments in the array.2060 */2061 static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2062 {2063 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2064 2065 /*2066 * Validate input.2067 */2068 if ( cArgs > 12069 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))2070 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");2071 if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))2072 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n");2073 if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType))2074 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n");2075 2076 /*2077 * Find address.2078 */2079 if (!cArgs)2080 {2081 if (!DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))2082 {2083 pDbgc->SourcePos.enmType = DBGCVAR_TYPE_GC_FAR;2084 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVM) : CPUMGetHyperEIP(pVM);2085 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVM) : CPUMGetHyperCS(pVM);2086 }2087 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_NONE;2088 }2089 else2090 pDbgc->SourcePos = paArgs[0];2091 2092 /*2093 * Ensure the the source address is flat GC.2094 */2095 switch (pDbgc->SourcePos.enmType)2096 {2097 case DBGCVAR_TYPE_GC_FLAT:2098 break;2099 case DBGCVAR_TYPE_GC_PHYS:2100 case DBGCVAR_TYPE_GC_FAR:2101 case DBGCVAR_TYPE_HC_FLAT:2102 case DBGCVAR_TYPE_HC_PHYS:2103 case DBGCVAR_TYPE_HC_FAR:2104 {2105 int rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->SourcePos, "%%(%Dv)", &pDbgc->SourcePos);2106 if (VBOX_FAILURE(rc))2107 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid address or address type. (rc=%d)\n", rc);2108 break;2109 }2110 default: AssertFailed(); break;2111 }2112 2113 /*2114 * Range.2115 */2116 switch (pDbgc->SourcePos.enmRangeType)2117 {2118 case DBGCVAR_RANGE_NONE:2119 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_ELEMENTS;2120 pDbgc->SourcePos.u64Range = 10;2121 break;2122 2123 case DBGCVAR_RANGE_ELEMENTS:2124 if (pDbgc->SourcePos.u64Range > 2048)2125 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n");2126 break;2127 2128 case DBGCVAR_RANGE_BYTES:2129 if (pDbgc->SourcePos.u64Range > 65536)2130 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");2131 break;2132 2133 default:2134 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->SourcePos.enmRangeType);2135 }2136 2137 /*2138 * Do the disassembling.2139 */2140 bool fFirst = 1;2141 DBGFLINE LinePrev = { 0, 0, "" };2142 int iRangeLeft = (int)pDbgc->SourcePos.u64Range;2143 if (iRangeLeft == 0) /* klugde for 'r'. */2144 iRangeLeft = -1;2145 for (;;)2146 {2147 /*2148 * Get line info.2149 */2150 DBGFLINE Line;2151 RTGCINTPTR off;2152 int rc = DBGFR3LineByAddr(pVM, pDbgc->SourcePos.u.GCFlat, &off, &Line);2153 if (VBOX_FAILURE(rc))2154 return VINF_SUCCESS;2155 2156 unsigned cLines = 0;2157 if (memcmp(&Line, &LinePrev, sizeof(Line)))2158 {2159 /*2160 * Print filenamename2161 */2162 if (!fFirst && strcmp(Line.szFilename, LinePrev.szFilename))2163 fFirst = true;2164 if (fFirst)2165 {2166 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "[%s @ %d]\n", Line.szFilename, Line.uLineNo);2167 if (VBOX_FAILURE(rc))2168 return rc;2169 }2170 2171 /*2172 * Try open the file and read the line.2173 */2174 FILE *phFile = fopen(Line.szFilename, "r");2175 if (phFile)2176 {2177 /* Skip ahead to the desired line. */2178 char szLine[4096];2179 unsigned cBefore = fFirst ? RT_MIN(2, Line.uLineNo - 1) : Line.uLineNo - LinePrev.uLineNo - 1;2180 if (cBefore > 7)2181 cBefore = 0;2182 unsigned cLeft = Line.uLineNo - cBefore;2183 while (cLeft > 0)2184 {2185 szLine[0] = '\0';2186 if (!fgets(szLine, sizeof(szLine), phFile))2187 break;2188 cLeft--;2189 }2190 if (!cLeft)2191 {2192 /* print the before lines */2193 for (;;)2194 {2195 size_t cch = strlen(szLine);2196 while (cch > 0 && (szLine[cch - 1] == '\r' || szLine[cch - 1] == '\n' || isspace(szLine[cch - 1])) )2197 szLine[--cch] = '\0';2198 if (cBefore-- <= 0)2199 break;2200 2201 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %4d: %s\n", Line.uLineNo - cBefore - 1, szLine);2202 szLine[0] = '\0';2203 fgets(szLine, sizeof(szLine), phFile);2204 cLines++;2205 }2206 /* print the actual line */2207 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08llx %4d: %s\n", Line.Address, Line.uLineNo, szLine);2208 }2209 fclose(phFile);2210 if (VBOX_FAILURE(rc))2211 return rc;2212 fFirst = false;2213 }2214 else2215 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Warning: couldn't open source file '%s'\n", Line.szFilename);2216 2217 LinePrev = Line;2218 }2219 2220 2221 /*2222 * Advance2223 */2224 if (iRangeLeft < 0) /* 'r' */2225 break;2226 if (pDbgc->SourcePos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)2227 iRangeLeft -= cLines;2228 else2229 iRangeLeft -= 1;2230 rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->SourcePos, "(%Dv) + %x", &pDbgc->SourcePos, 1);2231 if (VBOX_FAILURE(rc))2232 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->SourcePos, 1);2233 if (iRangeLeft <= 0)2234 break;2235 }2236 2237 NOREF(pCmd); NOREF(pResult);2238 return 0;2239 }2240 2241 2242 /**2243 * The 'r' command.2244 *2245 * @returns VBox status.2246 * @param pCmd Pointer to the command descriptor (as registered).2247 * @param pCmdHlp Pointer to command helper functions.2248 * @param pVM Pointer to the current VM (if any).2249 * @param paArgs Pointer to (readonly) array of arguments.2250 * @param cArgs Number of arguments in the array.2251 */2252 static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2253 {2254 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2255 2256 if (pDbgc->fRegCtxGuest)2257 return dbgcCmdRegGuest(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);2258 else2259 return dbgcCmdRegHyper(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);2260 }2261 2262 2263 /**2264 * Common worker for the dbgcCmdReg*() commands.2265 *2266 * @returns VBox status.2267 * @param pCmd Pointer to the command descriptor (as registered).2268 * @param pCmdHlp Pointer to command helper functions.2269 * @param pVM Pointer to the current VM (if any).2270 * @param paArgs Pointer to (readonly) array of arguments.2271 * @param cArgs Number of arguments in the array.2272 * @param pszPrefix The symbol prefix.2273 */2274 static DECLCALLBACK(int) dbgcCmdRegCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult, const char *pszPrefix)2275 {2276 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2277 2278 /*2279 * cArgs == 0: Show all2280 */2281 if (cArgs == 0)2282 {2283 /*2284 * Get register context.2285 */2286 int rc;2287 PCPUMCTX pCtx;2288 PCCPUMCTXCORE pCtxCore;2289 if (!*pszPrefix)2290 {2291 rc = CPUMQueryGuestCtxPtr(pVM, &pCtx);2292 pCtxCore = CPUMGetGuestCtxCore(pVM);2293 }2294 else2295 {2296 rc = CPUMQueryHyperCtxPtr(pVM, &pCtx);2297 pCtxCore = CPUMGetHyperCtxCore(pVM);2298 }2299 if (VBOX_FAILURE(rc))2300 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Getting register context\n");2301 2302 /*2303 * Format the flags.2304 */2305 static struct2306 {2307 const char *pszSet; const char *pszClear; uint32_t fFlag;2308 } aFlags[] =2309 {2310 { "vip",NULL, X86_EFL_VIP },2311 { "vif",NULL, X86_EFL_VIF },2312 { "ac", NULL, X86_EFL_AC },2313 { "vm", NULL, X86_EFL_VM },2314 { "rf", NULL, X86_EFL_RF },2315 { "nt", NULL, X86_EFL_NT },2316 { "ov", "nv", X86_EFL_OF },2317 { "dn", "up", X86_EFL_DF },2318 { "ei", "di", X86_EFL_IF },2319 { "tf", NULL, X86_EFL_TF },2320 { "nt", "pl", X86_EFL_SF },2321 { "nz", "zr", X86_EFL_ZF },2322 { "ac", "na", X86_EFL_AF },2323 { "po", "pe", X86_EFL_PF },2324 { "cy", "nc", X86_EFL_CF },2325 };2326 char szEFlags[80];2327 char *psz = szEFlags;2328 uint32_t efl = pCtxCore->eflags.u32;2329 for (unsigned i = 0; i < ELEMENTS(aFlags); i++)2330 {2331 const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;2332 if (pszAdd)2333 {2334 strcpy(psz, pszAdd);2335 psz += strlen(pszAdd);2336 *psz++ = ' ';2337 }2338 }2339 psz[-1] = '\0';2340 2341 2342 /*2343 * Format the registers.2344 */2345 if (pDbgc->fRegTerse)2346 {2347 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,2348 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"2349 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"2350 "%scs=%04x %sds=%04x %ses=%04x %sfs=%04x %sgs=%04x %sss=%04x %seflags=%08x\n",2351 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,2352 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 34 : 31, szEFlags,2353 pszPrefix, (RTSEL)pCtxCore->cs, pszPrefix, (RTSEL)pCtxCore->ds, pszPrefix, (RTSEL)pCtxCore->es,2354 pszPrefix, (RTSEL)pCtxCore->fs, pszPrefix, (RTSEL)pCtxCore->gs, pszPrefix, (RTSEL)pCtxCore->ss, pszPrefix, efl);2355 }2356 else2357 {2358 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,2359 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"2360 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"2361 "%scs={%04x base=%08x limit=%08x flags=%08x} %sdr0=%08x %sdr1=%08x\n"2362 "%sds={%04x base=%08x limit=%08x flags=%08x} %sdr2=%08x %sdr3=%08x\n"2363 "%ses={%04x base=%08x limit=%08x flags=%08x} %sdr4=%08x %sdr5=%08x\n"2364 "%sfs={%04x base=%08x limit=%08x flags=%08x} %sdr6=%08x %sdr7=%08x\n"2365 "%sgs={%04x base=%08x limit=%08x flags=%08x} %scr0=%08x %scr2=%08x\n"2366 "%sss={%04x base=%08x limit=%08x flags=%08x} %scr3=%08x %scr4=%08x\n"2367 "%sgdtr=%08x:%04x %sidtr=%08x:%04x %seflags=%08x\n"2368 "%sldtr={%04x base=%08x limit=%08x flags=%08x}\n"2369 "%str ={%04x base=%08x limit=%08x flags=%08x}\n"2370 "%sSysEnter={cs=%04llx eip=%08llx esp=%08llx}\n"2371 "%sFCW=%04x %sFSW=%04x %sFTW=%04x\n"2372 ,2373 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,2374 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,2375 pszPrefix, (RTSEL)pCtxCore->cs, pCtx->csHid.u32Base, pCtx->csHid.u32Limit, pCtx->csHid.Attr.u, pszPrefix, pCtx->dr0, pszPrefix, pCtx->dr1,2376 pszPrefix, (RTSEL)pCtxCore->ds, pCtx->dsHid.u32Base, pCtx->dsHid.u32Limit, pCtx->dsHid.Attr.u, pszPrefix, pCtx->dr2, pszPrefix, pCtx->dr3,2377 pszPrefix, (RTSEL)pCtxCore->es, pCtx->esHid.u32Base, pCtx->esHid.u32Limit, pCtx->esHid.Attr.u, pszPrefix, pCtx->dr4, pszPrefix, pCtx->dr5,2378 pszPrefix, (RTSEL)pCtxCore->fs, pCtx->fsHid.u32Base, pCtx->fsHid.u32Limit, pCtx->fsHid.Attr.u, pszPrefix, pCtx->dr6, pszPrefix, pCtx->dr7,2379 pszPrefix, (RTSEL)pCtxCore->gs, pCtx->gsHid.u32Base, pCtx->gsHid.u32Limit, pCtx->gsHid.Attr.u, pszPrefix, pCtx->cr0, pszPrefix, pCtx->cr2,2380 pszPrefix, (RTSEL)pCtxCore->ss, pCtx->ssHid.u32Base, pCtx->ssHid.u32Limit, pCtx->ssHid.Attr.u, pszPrefix, pCtx->cr3, pszPrefix, pCtx->cr4,2381 pszPrefix, pCtx->gdtr.pGdt,pCtx->gdtr.cbGdt, pszPrefix, pCtx->idtr.pIdt, pCtx->idtr.cbIdt, pszPrefix, pCtxCore->eflags,2382 pszPrefix, (RTSEL)pCtx->ldtr, pCtx->ldtrHid.u32Base, pCtx->ldtrHid.u32Limit, pCtx->ldtrHid.Attr.u,2383 pszPrefix, (RTSEL)pCtx->tr, pCtx->trHid.u32Base, pCtx->trHid.u32Limit, pCtx->trHid.Attr.u,2384 pszPrefix, pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp,2385 pszPrefix, pCtx->fpu.FCW, pszPrefix, pCtx->fpu.FSW, pszPrefix, pCtx->fpu.FTW);2386 }2387 2388 /*2389 * Disassemble one instruction at cs:eip.2390 */2391 return pCmdHlp->pfnExec(pCmdHlp, "u %04x:%08x L 0", pCtx->cs, pCtx->eip);2392 }2393 2394 /*2395 * cArgs == 1: Show the register.2396 * cArgs == 2: Modify the register.2397 */2398 if ( cArgs == 12399 || cArgs == 2)2400 {2401 /* locate the register symbol. */2402 const char *pszReg = paArgs[0].u.pszString;2403 if ( *pszPrefix2404 && pszReg[0] != *pszPrefix)2405 {2406 /* prepend the prefix. */2407 char *psz = (char *)alloca(strlen(pszReg) + 2);2408 psz[0] = *pszPrefix;2409 strcpy(psz + 1, paArgs[0].u.pszString);2410 pszReg = psz;2411 }2412 PCDBGCSYM pSym = dbgcLookupRegisterSymbol(pDbgc, pszReg);2413 if (!pSym)2414 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER /* VERR_DBGC_INVALID_REGISTER */, "Invalid register name '%s'.\n", pszReg);2415 2416 /* show the register */2417 if (cArgs == 1)2418 {2419 DBGCVAR Var;2420 memset(&Var, 0, sizeof(Var));2421 int rc = pSym->pfnGet(pSym, pCmdHlp, DBGCVAR_TYPE_NUMBER, &Var);2422 if (VBOX_FAILURE(rc))2423 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed getting value for register '%s'.\n", pszReg);2424 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s=%Dv\n", pszReg, &Var);2425 }2426 2427 /* change the register */2428 int rc = pSym->pfnSet(pSym, pCmdHlp, &paArgs[1]);2429 if (VBOX_FAILURE(rc))2430 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed setting value for register '%s'.\n", pszReg);2431 return VINF_SUCCESS;2432 }2433 2434 2435 NOREF(pCmd); NOREF(paArgs); NOREF(pResult);2436 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Huh? cArgs=%d Expected 0, 1 or 2!\n", cArgs);2437 }2438 2439 2440 /**2441 * The 'rg' command.2442 *2443 * @returns VBox status.2444 * @param pCmd Pointer to the command descriptor (as registered).2445 * @param pCmdHlp Pointer to command helper functions.2446 * @param pVM Pointer to the current VM (if any).2447 * @param paArgs Pointer to (readonly) array of arguments.2448 * @param cArgs Number of arguments in the array.2449 */2450 static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2451 {2452 return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, "");2453 }2454 2455 2456 /**2457 * The 'rh' command.2458 *2459 * @returns VBox status.2460 * @param pCmd Pointer to the command descriptor (as registered).2461 * @param pCmdHlp Pointer to command helper functions.2462 * @param pVM Pointer to the current VM (if any).2463 * @param paArgs Pointer to (readonly) array of arguments.2464 * @param cArgs Number of arguments in the array.2465 */2466 static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2467 {2468 return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, ".");2469 }2470 2471 2472 /**2473 * The 'rt' command.2474 *2475 * @returns VBox status.2476 * @param pCmd Pointer to the command descriptor (as registered).2477 * @param pCmdHlp Pointer to command helper functions.2478 * @param pVM Pointer to the current VM (if any).2479 * @param paArgs Pointer to (readonly) array of arguments.2480 * @param cArgs Number of arguments in the array.2481 */2482 static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2483 {2484 NOREF(pCmd); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);2485 2486 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2487 pDbgc->fRegTerse = !pDbgc->fRegTerse;2488 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, pDbgc->fRegTerse ? "info: Terse register info.\n" : "info: Verbose register info.\n");2489 }2490 2491 2492 /**2493 * The 't' command.2494 *2495 * @returns VBox status.2496 * @param pCmd Pointer to the command descriptor (as registered).2497 * @param pCmdHlp Pointer to command helper functions.2498 * @param pVM Pointer to the current VM (if any).2499 * @param paArgs Pointer to (readonly) array of arguments.2500 * @param cArgs Number of arguments in the array.2501 */2502 static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2503 {2504 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2505 2506 int rc = DBGFR3Step(pVM);2507 if (VBOX_SUCCESS(rc))2508 pDbgc->fReady = false;2509 else2510 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to single step VM %p\n", pDbgc->pVM);2511 2512 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);2513 return rc;2514 }2515 2516 2517 /**2518 * The 'k', 'kg' and 'kh' commands.2519 *2520 * @returns VBox status.2521 * @param pCmd Pointer to the command descriptor (as registered).2522 * @param pCmdHlp Pointer to command helper functions.2523 * @param pVM Pointer to the current VM (if any).2524 * @param paArgs Pointer to (readonly) array of arguments.2525 * @param cArgs Number of arguments in the array.2526 */2527 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2528 {2529 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2530 2531 /*2532 * Figure which context we're called for.2533 */2534 bool fGuest = pCmd->pszCmd[1] == 'g'2535 || (!pCmd->pszCmd[1] && pDbgc->fRegCtxGuest);2536 2537 2538 DBGFSTACKFRAME Frame;2539 memset(&Frame, 0, sizeof(Frame));2540 int rc;2541 if (fGuest)2542 rc = DBGFR3StackWalkBeginGuest(pVM, &Frame);2543 else2544 rc = DBGFR3StackWalkBeginHyper(pVM, &Frame);2545 if (VBOX_FAILURE(rc))2546 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to begin stack walk, rc=%Vrc\n", rc);2547 2548 /*2549 * Print header.2550 * 12345678 12345678 0023:87654321 12345678 87654321 12345678 87654321 symbol2551 */2552 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");2553 if (VBOX_FAILURE(rc))2554 return rc;2555 do2556 {2557 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",2558 (uint32_t)Frame.AddrFrame.off,2559 (uint32_t)Frame.AddrReturnFrame.off,2560 (uint32_t)Frame.AddrReturnPC.Sel,2561 (uint32_t)Frame.AddrReturnPC.off,2562 Frame.Args.au32[0],2563 Frame.Args.au32[1],2564 Frame.Args.au32[2],2565 Frame.Args.au32[3]);2566 if (VBOX_FAILURE(rc))2567 return rc;2568 if (!Frame.pSymPC)2569 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %RTsel:%08RGv", Frame.AddrPC.Sel, Frame.AddrPC.off);2570 else2571 {2572 RTGCINTPTR offDisp = Frame.AddrPC.FlatPtr - Frame.pSymPC->Value; /** @todo this isn't 100% correct for segemnted stuff. */2573 if (offDisp > 0)2574 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s+%llx", Frame.pSymPC->szName, (int64_t)offDisp);2575 else if (offDisp < 0)2576 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s-%llx", Frame.pSymPC->szName, -(int64_t)offDisp);2577 else2578 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s", Frame.pSymPC->szName);2579 }2580 if (VBOX_SUCCESS(rc) && Frame.pLinePC)2581 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " [%s @ 0i%d]", Frame.pLinePC->szFilename, Frame.pLinePC->uLineNo);2582 if (VBOX_SUCCESS(rc))2583 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");2584 if (VBOX_FAILURE(rc))2585 return rc;2586 2587 /* next */2588 rc = DBGFR3StackWalkNext(pVM, &Frame);2589 } while (VBOX_SUCCESS(rc));2590 2591 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);2592 return VINF_SUCCESS;2593 }2594 2595 2596 static int dbgcCmdDumpDTWorker64(PDBGCCMDHLP /*pCmdHlp*/, PCX86DESC64 /*pDesc*/, unsigned /*iEntry*/, bool /* fHyper */, bool * /*fDblEntry*/)2597 {2598 /* GUEST64 */2599 return VINF_SUCCESS;2600 }2601 2602 2603 /**2604 * Wroker function that displays one descriptor entry (GDT, LDT, IDT).2605 *2606 * @returns pfnPrintf status code.2607 * @param pCmdHlp The DBGC command helpers.2608 * @param pDesc The descriptor to display.2609 * @param iEntry The descriptor entry number.2610 * @param fHyper Whether the selector belongs to the hypervisor or not.2611 */2612 static int dbgcCmdDumpDTWorker32(PDBGCCMDHLP pCmdHlp, PCX86DESC pDesc, unsigned iEntry, bool fHyper)2613 {2614 int rc;2615 2616 const char *pszHyper = fHyper ? " HYPER" : "";2617 const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP";2618 if (pDesc->Gen.u1DescType)2619 {2620 static const char * const s_apszTypes[] =2621 {2622 "DataRO", /* 0 Read-Only */2623 "DataRO", /* 1 Read-Only - Accessed */2624 "DataRW", /* 2 Read/Write */2625 "DataRW", /* 3 Read/Write - Accessed */2626 "DownRO", /* 4 Expand-down, Read-Only */2627 "DownRO", /* 5 Expand-down, Read-Only - Accessed */2628 "DownRW", /* 6 Expand-down, Read/Write */2629 "DownRO", /* 7 Expand-down, Read/Write - Accessed */2630 "CodeEO", /* 8 Execute-Only */2631 "CodeEO", /* 9 Execute-Only - Accessed */2632 "CodeER", /* A Execute/Readable */2633 "CodeER", /* B Execute/Readable - Accessed */2634 "ConfE0", /* C Conforming, Execute-Only */2635 "ConfE0", /* D Conforming, Execute-Only - Accessed */2636 "ConfER", /* E Conforming, Execute/Readable */2637 "ConfER" /* F Conforming, Execute/Readable - Accessed */2638 };2639 const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA";2640 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";2641 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";2642 uint32_t u32Base = pDesc->Gen.u16BaseLow2643 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)2644 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);2645 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);2646 if (pDesc->Gen.u1Granularity)2647 cbLimit <<= PAGE_SHIFT;2648 2649 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n",2650 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,2651 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig,2652 pDesc->Gen.u1Available, pDesc->Gen.u1Reserved, pszHyper);2653 }2654 else2655 {2656 static const char * const s_apszTypes[] =2657 {2658 "Ill-0 ", /* 0 0000 Reserved (Illegal) */2659 "Tss16A", /* 1 0001 Available 16-bit TSS */2660 "LDT ", /* 2 0010 LDT */2661 "Tss16B", /* 3 0011 Busy 16-bit TSS */2662 "Call16", /* 4 0100 16-bit Call Gate */2663 "TaskG ", /* 5 0101 Task Gate */2664 "Int16 ", /* 6 0110 16-bit Interrupt Gate */2665 "Trap16", /* 7 0111 16-bit Trap Gate */2666 "Ill-8 ", /* 8 1000 Reserved (Illegal) */2667 "Tss32A", /* 9 1001 Available 32-bit TSS */2668 "Ill-A ", /* A 1010 Reserved (Illegal) */2669 "Tss32B", /* B 1011 Busy 32-bit TSS */2670 "Call32", /* C 1100 32-bit Call Gate */2671 "Ill-D ", /* D 1101 Reserved (Illegal) */2672 "Int32 ", /* E 1110 32-bit Interrupt Gate */2673 "Trap32" /* F 1111 32-bit Trap Gate */2674 };2675 switch (pDesc->Gen.u4Type)2676 {2677 /* raw */2678 case X86_SEL_TYPE_SYS_UNDEFINED:2679 case X86_SEL_TYPE_SYS_UNDEFINED2:2680 case X86_SEL_TYPE_SYS_UNDEFINED4:2681 case X86_SEL_TYPE_SYS_UNDEFINED3:2682 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s %.8Rhxs DPL=%d %s%s\n",2683 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc,2684 pDesc->Gen.u2Dpl, pszPresent, pszHyper);2685 break;2686 2687 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:2688 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:2689 case X86_SEL_TYPE_SYS_286_TSS_BUSY:2690 case X86_SEL_TYPE_SYS_386_TSS_BUSY:2691 case X86_SEL_TYPE_SYS_LDT:2692 {2693 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";2694 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB";2695 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";2696 uint32_t u32Base = pDesc->Gen.u16BaseLow2697 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)2698 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);2699 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);2700 if (pDesc->Gen.u1Granularity)2701 cbLimit <<= PAGE_SHIFT;2702 2703 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n",2704 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,2705 pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszGranularity, pszBig,2706 pDesc->Gen.u1Available, pDesc->Gen.u1Reserved | (pDesc->Gen.u1DefBig << 1),2707 pszHyper);2708 break;2709 }2710 2711 case X86_SEL_TYPE_SYS_TASK_GATE:2712 {2713 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s TSS=%04x DPL=%d %s%s\n",2714 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc->au16[1],2715 pDesc->Gen.u2Dpl, pszPresent, pszHyper);2716 break;2717 }2718 2719 case X86_SEL_TYPE_SYS_286_CALL_GATE:2720 case X86_SEL_TYPE_SYS_386_CALL_GATE:2721 {2722 unsigned cParams = pDesc->au8[0] & 0x1f;2723 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC";2724 RTSEL sel = pDesc->au16[1];2725 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);2726 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x DPL=%d %s %s=%d%s\n",2727 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,2728 pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper);2729 break;2730 }2731 2732 case X86_SEL_TYPE_SYS_286_INT_GATE:2733 case X86_SEL_TYPE_SYS_386_INT_GATE:2734 case X86_SEL_TYPE_SYS_286_TRAP_GATE:2735 case X86_SEL_TYPE_SYS_386_TRAP_GATE:2736 {2737 RTSEL sel = pDesc->au16[1];2738 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);2739 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x DPL=%d %s%s\n",2740 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,2741 pDesc->Gen.u2Dpl, pszPresent, pszHyper);2742 break;2743 }2744 2745 /* impossible, just it's necessary to keep gcc happy. */2746 default:2747 return VINF_SUCCESS;2748 }2749 }2750 return rc;2751 }2752 2753 2754 /**2755 * The 'dg', 'dga', 'dl' and 'dla' commands.2756 *2757 * @returns VBox status.2758 * @param pCmd Pointer to the command descriptor (as registered).2759 * @param pCmdHlp Pointer to command helper functions.2760 * @param pVM Pointer to the current VM (if any).2761 * @param paArgs Pointer to (readonly) array of arguments.2762 * @param cArgs Number of arguments in the array.2763 */2764 static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2765 {2766 /*2767 * Validate input.2768 */2769 if (!pVM)2770 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");2771 2772 /*2773 * Get the CPU mode, check which command variation this is2774 * and fix a default parameter if needed.2775 */2776 CPUMMODE enmMode = CPUMGetGuestMode(pVM);2777 bool fGdt = pCmd->pszCmd[1] == 'g';2778 bool fAll = pCmd->pszCmd[2] == 'a';2779 2780 DBGCVAR Var;2781 if (!cArgs)2782 {2783 cArgs = 1;2784 paArgs = &Var;2785 Var.enmType = DBGCVAR_TYPE_NUMBER;2786 Var.u.u64Number = fGdt ? 0 : 4;2787 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;2788 Var.u64Range = 1024;2789 }2790 2791 /*2792 * Process the arguments.2793 */2794 for (unsigned i = 0; i < cArgs; i++)2795 {2796 /*2797 * Retrive the selector value from the argument.2798 * The parser may confuse pointers and numbers if more than one2799 * argument is given, that that into account.2800 */2801 /* check that what've got makes sense as we don't trust the parser yet. */2802 if ( paArgs[i].enmType != DBGCVAR_TYPE_NUMBER2803 && !DBGCVAR_ISPOINTER(paArgs[i].enmType))2804 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number or pointer type but %d.\n", i, paArgs[i].enmType);2805 uint64_t u64;2806 unsigned cSels = 1;2807 switch (paArgs[i].enmType)2808 {2809 case DBGCVAR_TYPE_NUMBER:2810 u64 = paArgs[i].u.u64Number;2811 if (paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE)2812 cSels = RT_MIN(paArgs[i].u64Range, 1024);2813 break;2814 case DBGCVAR_TYPE_GC_FAR: u64 = paArgs[i].u.GCFar.sel; break;2815 case DBGCVAR_TYPE_GC_FLAT: u64 = paArgs[i].u.GCFlat; break;2816 case DBGCVAR_TYPE_GC_PHYS: u64 = paArgs[i].u.GCPhys; break;2817 case DBGCVAR_TYPE_HC_FAR: u64 = paArgs[i].u.HCFar.sel; break;2818 case DBGCVAR_TYPE_HC_FLAT: u64 = (uintptr_t)paArgs[i].u.pvHCFlat; break;2819 case DBGCVAR_TYPE_HC_PHYS: u64 = paArgs[i].u.HCPhys; break;2820 default: u64 = _64K; break;2821 }2822 if (u64 < _64K)2823 {2824 unsigned Sel = (RTSEL)u64;2825 2826 /*2827 * Dump the specified range.2828 */2829 bool fSingle = cSels == 1;2830 while ( cSels-- > 02831 && Sel < _64K)2832 {2833 SELMSELINFO SelInfo;2834 int rc = SELMR3GetSelectorInfo(pVM, Sel, &SelInfo);2835 if (RT_SUCCESS(rc))2836 {2837 if (SelInfo.fRealMode)2838 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x RealM Bas=%04x Lim=%04x\n",2839 Sel, (unsigned)SelInfo.GCPtrBase, (unsigned)SelInfo.cbLimit);2840 else if (fAll || fSingle || SelInfo.Raw.Gen.u1Present)2841 {2842 if (enmMode == CPUMMODE_PROTECTED)2843 rc = dbgcCmdDumpDTWorker32(pCmdHlp, (PX86DESC)&SelInfo.Raw, Sel, SelInfo.fHyper);2844 else2845 {2846 bool fDblSkip = false;2847 rc = dbgcCmdDumpDTWorker64(pCmdHlp, (PX86DESC64)&SelInfo.Raw, Sel, SelInfo.fHyper, &fDblSkip);2848 if (fDblSkip)2849 Sel += 4;2850 }2851 }2852 }2853 else2854 {2855 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %Vrc\n", Sel, rc);2856 if (!fAll)2857 return rc;2858 }2859 if (RT_FAILURE(rc))2860 return rc;2861 2862 /* next */2863 Sel += 4;2864 }2865 }2866 else2867 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds\n", u64);2868 }2869 2870 NOREF(pResult);2871 return VINF_SUCCESS;2872 }2873 2874 2875 /**2876 * The 'di' and 'dia' commands.2877 *2878 * @returns VBox status.2879 * @param pCmd Pointer to the command descriptor (as registered).2880 * @param pCmdHlp Pointer to command helper functions.2881 * @param pVM Pointer to the current VM (if any).2882 * @param paArgs Pointer to (readonly) array of arguments.2883 * @param cArgs Number of arguments in the array.2884 */2885 static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2886 {2887 /*2888 * Validate input.2889 */2890 if (!pVM)2891 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");2892 2893 /*2894 * Establish some stuff like the current IDTR and CPU mode,2895 * and fix a default parameter.2896 */2897 uint16_t cbLimit;2898 RTGCUINTPTR GCPtrBase = CPUMGetGuestIDTR(pVM, &cbLimit);2899 CPUMMODE enmMode = CPUMGetGuestMode(pVM);2900 unsigned cbEntry;2901 switch (enmMode)2902 {2903 case CPUMMODE_REAL: cbEntry = sizeof(RTFAR16); break;2904 case CPUMMODE_PROTECTED: cbEntry = sizeof(X86DESC); break;2905 case CPUMMODE_LONG: cbEntry = sizeof(X86DESC64); break;2906 default:2907 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid CPU mode %d.\n", enmMode);2908 }2909 2910 bool fAll = pCmd->pszCmd[2] == 'a';2911 DBGCVAR Var;2912 if (!cArgs)2913 {2914 cArgs = 1;2915 paArgs = &Var;2916 Var.enmType = DBGCVAR_TYPE_NUMBER;2917 Var.u.u64Number = 0;2918 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;2919 Var.u64Range = 256;2920 }2921 2922 /*2923 * Process the arguments.2924 */2925 for (unsigned i = 0; i < cArgs; i++)2926 {2927 /* check that what've got makes sense as we don't trust the parser yet. */2928 if (paArgs[i].enmType != DBGCVAR_TYPE_NUMBER)2929 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number type but %d.\n", i, paArgs[i].enmType);2930 if (paArgs[i].u.u64Number < 256)2931 {2932 RTGCUINTPTR iInt = (RTGCUINTPTR)paArgs[i].u.u64Number;2933 unsigned cInts = paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE2934 ? paArgs[i].u64Range2935 : 1;2936 bool fSingle = cInts == 1;2937 while ( cInts-- > 02938 && iInt < 256)2939 {2940 /*2941 * Try read it.2942 */2943 union2944 {2945 RTFAR16 Real;2946 X86DESC Prot;2947 X86DESC64 Long;2948 } u;2949 if (iInt * cbEntry + (cbEntry - 1) > cbLimit)2950 {2951 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x not within the IDT\n", (unsigned)iInt);2952 if (!fAll && !fSingle)2953 return VINF_SUCCESS;2954 }2955 DBGCVAR AddrVar;2956 AddrVar.enmType = DBGCVAR_TYPE_GC_FLAT;2957 AddrVar.u.GCFlat = GCPtrBase + iInt * cbEntry;2958 AddrVar.enmRangeType = DBGCVAR_RANGE_NONE;2959 int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &u, cbEntry, &AddrVar, NULL);2960 if (VBOX_FAILURE(rc))2961 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading IDT entry %#04x.\n", (unsigned)iInt);2962 2963 /*2964 * Display it.2965 */2966 switch (enmMode)2967 {2968 case CPUMMODE_REAL:2969 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %RTfp16\n", (unsigned)iInt, u.Real);2970 /** @todo resolve 16:16 IDTE to a symbol */2971 break;2972 case CPUMMODE_PROTECTED:2973 if (fAll || fSingle || u.Prot.Gen.u1Present)2974 rc = dbgcCmdDumpDTWorker32(pCmdHlp, &u.Prot, iInt, false);2975 break;2976 case CPUMMODE_LONG:2977 if (fAll || fSingle || u.Long.Gen.u1Present)2978 rc = dbgcCmdDumpDTWorker64(pCmdHlp, &u.Long, iInt, false, NULL);2979 break;2980 default: break; /* to shut up gcc */2981 }2982 if (RT_FAILURE(rc))2983 return rc;2984 2985 /* next */2986 iInt++;2987 }2988 }2989 else2990 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds (max 256)\n", paArgs[i].u.u64Number);2991 }2992 2993 NOREF(pResult);2994 return VINF_SUCCESS;2995 }2996 2997 2998 /**2999 * The 'da', 'dq', 'dd', 'dw' and 'db' commands.3000 *3001 * @returns VBox status.3002 * @param pCmd Pointer to the command descriptor (as registered).3003 * @param pCmdHlp Pointer to command helper functions.3004 * @param pVM Pointer to the current VM (if any).3005 * @param paArgs Pointer to (readonly) array of arguments.3006 * @param cArgs Number of arguments in the array.3007 */3008 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3009 {3010 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3011 3012 /*3013 * Validate input.3014 */3015 if ( cArgs > 13016 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))3017 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");3018 if (!pVM)3019 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");3020 3021 /*3022 * Figure out the element size.3023 */3024 unsigned cbElement;3025 bool fAscii = false;3026 switch (pCmd->pszCmd[1])3027 {3028 default:3029 case 'b': cbElement = 1; break;3030 case 'w': cbElement = 2; break;3031 case 'd': cbElement = 4; break;3032 case 'q': cbElement = 8; break;3033 case 'a':3034 cbElement = 1;3035 fAscii = true;3036 break;3037 case '\0':3038 fAscii = !!(pDbgc->cbDumpElement & 0x80000000);3039 cbElement = pDbgc->cbDumpElement & 0x7fffffff;3040 if (!cbElement)3041 cbElement = 1;3042 break;3043 }3044 3045 /*3046 * Find address.3047 */3048 if (!cArgs)3049 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_NONE;3050 else3051 pDbgc->DumpPos = paArgs[0];3052 3053 /*3054 * Range.3055 */3056 switch (pDbgc->DumpPos.enmRangeType)3057 {3058 case DBGCVAR_RANGE_NONE:3059 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;3060 pDbgc->DumpPos.u64Range = 0x60;3061 break;3062 3063 case DBGCVAR_RANGE_ELEMENTS:3064 if (pDbgc->DumpPos.u64Range > 2048)3065 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many elements requested. Max is 2048 elements.\n");3066 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;3067 pDbgc->DumpPos.u64Range = (cbElement ? cbElement : 1) * pDbgc->DumpPos.u64Range;3068 break;3069 3070 case DBGCVAR_RANGE_BYTES:3071 if (pDbgc->DumpPos.u64Range > 65536)3072 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");3073 break;3074 3075 default:3076 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DumpPos.enmRangeType);3077 }3078 3079 /*3080 * Do the dumping.3081 */3082 pDbgc->cbDumpElement = cbElement | (fAscii << 31);3083 int cbLeft = (int)pDbgc->DumpPos.u64Range;3084 uint8_t u8Prev = '\0';3085 for (;;)3086 {3087 /*3088 * Read memory.3089 */3090 char achBuffer[16];3091 size_t cbReq = RT_MIN((int)sizeof(achBuffer), cbLeft);3092 size_t cb = RT_MIN((int)sizeof(achBuffer), cbLeft);3093 int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &achBuffer, cbReq, &pDbgc->DumpPos, &cb);3094 if (VBOX_FAILURE(rc))3095 {3096 if (u8Prev && u8Prev != '\n')3097 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");3098 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &pDbgc->DumpPos);3099 }3100 3101 /*3102 * Display it.3103 */3104 memset(&achBuffer[cb], 0, sizeof(achBuffer) - cb);3105 if (!fAscii)3106 {3107 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:", &pDbgc->DumpPos);3108 unsigned i;3109 for (i = 0; i < cb; i += cbElement)3110 {3111 const char *pszSpace = " ";3112 if (cbElement <= 2 && i == 8 && !fAscii)3113 pszSpace = "-";3114 switch (cbElement)3115 {3116 case 1: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%02x", pszSpace, *(uint8_t *)&achBuffer[i]); break;3117 case 2: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%04x", pszSpace, *(uint16_t *)&achBuffer[i]); break;3118 case 4: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%08x", pszSpace, *(uint32_t *)&achBuffer[i]); break;3119 case 8: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%016llx", pszSpace, *(uint64_t *)&achBuffer[i]); break;3120 }3121 }3122 3123 /* chars column */3124 if (pDbgc->cbDumpElement == 1)3125 {3126 while (i++ < sizeof(achBuffer))3127 pCmdHlp->pfnPrintf(pCmdHlp, NULL, " ");3128 pCmdHlp->pfnPrintf(pCmdHlp, NULL, " ");3129 for (i = 0; i < cb; i += cbElement)3130 {3131 uint8_t u8 = *(uint8_t *)&achBuffer[i];3132 if (isprint(u8) && u8 < 127)3133 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);3134 else3135 pCmdHlp->pfnPrintf(pCmdHlp, NULL, ".");3136 }3137 }3138 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");3139 }3140 else3141 {3142 /*3143 * We print up to the first zero and stop there.3144 * Only printables + '\t' and '\n' are printed.3145 */3146 if (!u8Prev)3147 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DumpPos);3148 uint8_t u8 = '\0';3149 unsigned i;3150 for (i = 0; i < cb; i++)3151 {3152 u8Prev = u8;3153 u8 = *(uint8_t *)&achBuffer[i];3154 if ( u8 < 1273155 && ( isprint(u8)3156 || u8 == '\t'3157 || u8 == '\n'))3158 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);3159 else if (!u8)3160 break;3161 else3162 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\\x%x", u8);3163 }3164 if (u8 == '\0')3165 cb = cbLeft = i + 1;3166 if (cbLeft - cb <= 0 && u8Prev != '\n')3167 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");3168 }3169 3170 /*3171 * Advance3172 */3173 cbLeft -= (int)cb;3174 rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->DumpPos, "(%Dv) + %x", &pDbgc->DumpPos, cb);3175 if (VBOX_FAILURE(rc))3176 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DumpPos, cb);3177 if (cbLeft <= 0)3178 break;3179 }3180 3181 NOREF(pCmd); NOREF(pResult);3182 return VINF_SUCCESS;3183 }3184 3185 3186 /**3187 * Best guess at which paging mode currently applies to the guest3188 * paging structures.3189 *3190 * This have to come up with a decent answer even when the guest3191 * is in non-paged protected mode or real mode.3192 *3193 * @returns cr3.3194 * @param pDbgc The DBGC instance.3195 * @param pfPAE Where to store the page address extension indicator.3196 * @param pfLME Where to store the long mode enabled indicator.3197 * @param pfPSE Where to store the page size extension indicator.3198 * @param pfPGE Where to store the page global enabled indicator.3199 * @param pfNXE Where to store the no-execution enabled inidicator.3200 */3201 static RTGCPHYS dbgcGetGuestPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)3202 {3203 RTGCUINTREG cr4 = CPUMGetGuestCR4(pDbgc->pVM);3204 *pfPSE = !!(cr4 & X86_CR4_PSE);3205 *pfPGE = !!(cr4 & X86_CR4_PGE);3206 *pfPAE = !!(cr4 & X86_CR4_PAE);3207 *pfLME = CPUMGetGuestMode(pDbgc->pVM) == CPUMMODE_LONG;3208 *pfNXE = false; /* GUEST64 GUESTNX */3209 return CPUMGetGuestCR3(pDbgc->pVM);3210 }3211 3212 3213 /**3214 * Determin the shadow paging mode.3215 *3216 * @returns cr3.3217 * @param pDbgc The DBGC instance.3218 * @param pfPAE Where to store the page address extension indicator.3219 * @param pfLME Where to store the long mode enabled indicator.3220 * @param pfPSE Where to store the page size extension indicator.3221 * @param pfPGE Where to store the page global enabled indicator.3222 * @param pfNXE Where to store the no-execution enabled inidicator.3223 */3224 static RTHCPHYS dbgcGetShadowPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)3225 {3226 *pfPSE = true;3227 *pfPGE = false;3228 switch (PGMGetShadowMode(pDbgc->pVM))3229 {3230 default:3231 case PGMMODE_32_BIT:3232 *pfPAE = *pfLME = *pfNXE = false;3233 break;3234 case PGMMODE_PAE:3235 *pfLME = *pfNXE = false;3236 *pfPAE = true;3237 break;3238 case PGMMODE_PAE_NX:3239 *pfLME = false;3240 *pfPAE = *pfNXE = true;3241 break;3242 case PGMMODE_AMD64:3243 *pfNXE = false;3244 *pfPAE = *pfLME = true;3245 break;3246 case PGMMODE_AMD64_NX:3247 *pfPAE = *pfLME = *pfNXE = true;3248 break;3249 }3250 return PGMGetHyperCR3(pDbgc->pVM);3251 }3252 3253 3254 /**3255 * The 'dpd', 'dpda', 'dpdb', 'dpdg' and 'dpdh' commands.3256 *3257 * @returns VBox status.3258 * @param pCmd Pointer to the command descriptor (as registered).3259 * @param pCmdHlp Pointer to command helper functions.3260 * @param pVM Pointer to the current VM (if any).3261 * @param paArgs Pointer to (readonly) array of arguments.3262 * @param cArgs Number of arguments in the array.3263 */3264 static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3265 {3266 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3267 3268 /*3269 * Validate input.3270 */3271 if ( cArgs > 13272 || (cArgs == 1 && pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))3273 || (cArgs == 1 && pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))3274 )3275 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");3276 if (!pVM)3277 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");3278 3279 /*3280 * Guest or shadow page directories? Get the paging parameters.3281 */3282 bool fGuest = pCmd->pszCmd[3] != 'h';3283 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')3284 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER3285 ? pDbgc->fRegCtxGuest3286 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);3287 3288 bool fPAE, fLME, fPSE, fPGE, fNXE;3289 uint64_t cr3 = fGuest3290 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)3291 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);3292 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);3293 3294 /*3295 * Setup default arugment if none was specified.3296 * Fix address / index confusion.3297 */3298 DBGCVAR VarDefault;3299 if (!cArgs)3300 {3301 if (pCmd->pszCmd[3] == 'a')3302 {3303 if (fLME || fPAE)3304 return DBGCCmdHlpPrintf(pCmdHlp, "Default argument for 'dpda' hasn't been fully implemented yet. Try with an address or use one of the other commands.\n");3305 if (fGuest)3306 DBGCVAR_INIT_GC_PHYS(&VarDefault, cr3);3307 else3308 DBGCVAR_INIT_HC_PHYS(&VarDefault, cr3);3309 }3310 else3311 DBGCVAR_INIT_GC_FLAT(&VarDefault, 0);3312 paArgs = &VarDefault;3313 cArgs = 1;3314 }3315 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER)3316 {3317 Assert(pCmd->pszCmd[3] != 'a');3318 VarDefault = paArgs[0];3319 if (VarDefault.u.u64Number <= 1024)3320 {3321 if (fPAE)3322 return DBGCCmdHlpPrintf(pCmdHlp, "PDE indexing is only implemented for 32-bit paging.\n");3323 if (VarDefault.u.u64Number >= PAGE_SIZE / cbEntry)3324 return DBGCCmdHlpPrintf(pCmdHlp, "PDE index is out of range [0..%d].\n", PAGE_SIZE / cbEntry - 1);3325 VarDefault.u.u64Number <<= X86_PD_SHIFT;3326 }3327 VarDefault.enmType = DBGCVAR_TYPE_GC_FLAT;3328 paArgs = &VarDefault;3329 }3330 3331 /*3332 * Locate the PDE to start displaying at.3333 *3334 * The 'dpda' command takes the address of a PDE, while the others are guest3335 * virtual address which PDEs should be displayed. So, 'dpda' is rather simple3336 * while the others require us to do all the tedious walking thru the paging3337 * hierarchy to find the intended PDE.3338 */3339 unsigned iEntry = ~0U; /* The page directory index. ~0U for 'dpta'. */3340 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PDE (iEntry != ~0U). */3341 DBGCVAR VarPDEAddr; /* The address of the current PDE. */3342 unsigned cEntries; /* The number of entries to display. */3343 unsigned cEntriesMax; /* The max number of entries to display. */3344 int rc;3345 if (pCmd->pszCmd[3] == 'a')3346 {3347 VarPDEAddr = paArgs[0];3348 switch (VarPDEAddr.enmRangeType)3349 {3350 case DBGCVAR_RANGE_BYTES: cEntries = VarPDEAddr.u64Range / cbEntry; break;3351 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPDEAddr.u64Range; break;3352 default: cEntries = 10; break;3353 }3354 cEntriesMax = PAGE_SIZE / cbEntry;3355 }3356 else3357 {3358 /*3359 * Determin the range.3360 */3361 switch (paArgs[0].enmRangeType)3362 {3363 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break;3364 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break;3365 default: cEntries = 10; break;3366 }3367 3368 /*3369 * Normalize the input address, it must be a flat GC address.3370 */3371 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);3372 if (VBOX_FAILURE(rc))3373 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);3374 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)3375 {3376 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;3377 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;3378 }3379 if (fPAE)3380 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_PAE_SHIFT) - 1);3381 else3382 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_SHIFT) - 1);3383 3384 /*3385 * Do the paging walk until we get to the page directory.3386 */3387 DBGCVAR VarCur;3388 if (fGuest)3389 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);3390 else3391 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);3392 if (fLME)3393 {3394 /* Page Map Level 4 Lookup. */3395 /* Check if it's a valid address first? */3396 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;3397 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);3398 X86PML4E Pml4e;3399 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);3400 if (VBOX_FAILURE(rc))3401 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);3402 if (!Pml4e.n.u1Present)3403 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);3404 3405 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;3406 Assert(fPAE);3407 }3408 if (fPAE)3409 {3410 /* Page directory pointer table. */3411 X86PDPE Pdpe;3412 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK) * sizeof(Pdpe);3413 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);3414 if (VBOX_FAILURE(rc))3415 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);3416 if (!Pdpe.n.u1Present)3417 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);3418 3419 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;3420 VarPDEAddr = VarCur;3421 VarPDEAddr.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;3422 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDEPAE);3423 }3424 else3425 {3426 /* 32-bit legacy - CR3 == page directory. */3427 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK;3428 VarPDEAddr = VarCur;3429 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDE);3430 }3431 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;3432 iEntry /= cbEntry;3433 }3434 3435 /* adjust cEntries */3436 cEntries = RT_MAX(1, cEntries);3437 cEntries = RT_MIN(cEntries, cEntriesMax);3438 3439 /*3440 * The display loop.3441 */3442 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (index %#x):\n" : "%DV:\n",3443 &VarPDEAddr, iEntry);3444 do3445 {3446 /*3447 * Read.3448 */3449 X86PDEPAE Pde;3450 Pde.u = 0;3451 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, cbEntry, &VarPDEAddr, NULL);3452 if (VBOX_FAILURE(rc))3453 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarPDEAddr);3454 3455 /*3456 * Display.3457 */3458 if (iEntry != ~0U)3459 {3460 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);3461 iEntry++;3462 }3463 if (fPSE && Pde.b.u1Size)3464 DBGCCmdHlpPrintf(pCmdHlp,3465 fPAE3466 ? "%016llx big phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"3467 : "%08llx big phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",3468 Pde.u,3469 Pde.u & X86_PDE_PAE_PG_MASK,3470 Pde.b.u1Present ? "p " : "np",3471 Pde.b.u1Write ? "w" : "r",3472 Pde.b.u1User ? "u" : "s",3473 Pde.b.u1Accessed ? "a " : "na",3474 Pde.b.u1Dirty ? "d " : "nd",3475 Pde.b.u3Available,3476 Pde.b.u1Global ? (fPGE ? "g" : "G") : " ",3477 Pde.b.u1WriteThru ? "pwt" : " ",3478 Pde.b.u1CacheDisable ? "pcd" : " ",3479 Pde.b.u1PAT ? "pat" : "",3480 Pde.b.u1NoExecute ? (fNXE ? "nx" : "NX") : " ");3481 else3482 DBGCCmdHlpPrintf(pCmdHlp,3483 fPAE3484 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s"3485 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s",3486 Pde.u,3487 Pde.u & X86_PDE_PAE_PG_MASK,3488 Pde.n.u1Present ? "p " : "np",3489 Pde.n.u1Write ? "w" : "r",3490 Pde.n.u1User ? "u" : "s",3491 Pde.n.u1Accessed ? "a " : "na",3492 Pde.u & RT_BIT(6) ? "6 " : " ",3493 Pde.n.u3Available,3494 Pde.u & RT_BIT(8) ? "8" : " ",3495 Pde.n.u1WriteThru ? "pwt" : " ",3496 Pde.n.u1CacheDisable ? "pcd" : " ",3497 Pde.u & RT_BIT(7) ? "7" : "",3498 Pde.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " ");3499 if (Pde.u & UINT64_C(0x7fff000000000000))3500 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pde.u & UINT64_C(0x7fff000000000000)));3501 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");3502 if (VBOX_FAILURE(rc))3503 return rc;3504 3505 /*3506 * Advance.3507 */3508 VarPDEAddr.u.u64Number += cbEntry;3509 if (iEntry != ~0U)3510 VarGCPtr.u.GCFlat += 1 << (fPAE ? X86_PD_PAE_SHIFT : X86_PD_SHIFT);3511 } while (cEntries-- > 0);3512 3513 NOREF(pResult);3514 return VINF_SUCCESS;3515 }3516 3517 3518 /**3519 * The 'dpdb' command.3520 *3521 * @returns VBox status.3522 * @param pCmd Pointer to the command descriptor (as registered).3523 * @param pCmdHlp Pointer to command helper functions.3524 * @param pVM Pointer to the current VM (if any).3525 * @param paArgs Pointer to (readonly) array of arguments.3526 * @param cArgs Number of arguments in the array.3527 */3528 static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3529 {3530 if (!pVM)3531 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");3532 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);3533 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);3534 if (VBOX_FAILURE(rc1))3535 return rc1;3536 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);3537 return rc2;3538 }3539 3540 3541 /**3542 * The 'dpg*' commands.3543 *3544 * @returns VBox status.3545 * @param pCmd Pointer to the command descriptor (as registered).3546 * @param pCmdHlp Pointer to command helper functions.3547 * @param pVM Pointer to the current VM (if any).3548 * @param paArgs Pointer to (readonly) array of arguments.3549 * @param cArgs Number of arguments in the array.3550 */3551 static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3552 {3553 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3554 3555 /*3556 * Validate input.3557 */3558 if ( cArgs != 13559 || (pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))3560 || (pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))3561 )3562 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");3563 if (!pVM)3564 return DBGCCmdHlpPrintf(pCmdHlp, "error: No VM.\n");3565 3566 /*3567 * Guest or shadow page tables? Get the paging parameters.3568 */3569 bool fGuest = pCmd->pszCmd[3] != 'h';3570 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')3571 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER3572 ? pDbgc->fRegCtxGuest3573 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);3574 3575 bool fPAE, fLME, fPSE, fPGE, fNXE;3576 uint64_t cr3 = fGuest3577 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)3578 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);3579 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);3580 3581 /*3582 * Locate the PTE to start displaying at.3583 *3584 * The 'dpta' command takes the address of a PTE, while the others are guest3585 * virtual address which PTEs should be displayed. So, 'pdta' is rather simple3586 * while the others require us to do all the tedious walking thru the paging3587 * hierarchy to find the intended PTE.3588 */3589 unsigned iEntry = ~0U; /* The page table index. ~0U for 'dpta'. */3590 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PTE (iEntry != ~0U). */3591 DBGCVAR VarPTEAddr; /* The address of the current PTE. */3592 unsigned cEntries; /* The number of entries to display. */3593 unsigned cEntriesMax; /* The max number of entries to display. */3594 int rc;3595 if (pCmd->pszCmd[3] == 'a')3596 {3597 VarPTEAddr = paArgs[0];3598 switch (VarPTEAddr.enmRangeType)3599 {3600 case DBGCVAR_RANGE_BYTES: cEntries = VarPTEAddr.u64Range / cbEntry; break;3601 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPTEAddr.u64Range; break;3602 default: cEntries = 10; break;3603 }3604 cEntriesMax = PAGE_SIZE / cbEntry;3605 }3606 else3607 {3608 /*3609 * Determin the range.3610 */3611 switch (paArgs[0].enmRangeType)3612 {3613 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break;3614 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break;3615 default: cEntries = 10; break;3616 }3617 3618 /*3619 * Normalize the input address, it must be a flat GC address.3620 */3621 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);3622 if (VBOX_FAILURE(rc))3623 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);3624 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)3625 {3626 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;3627 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;3628 }3629 VarGCPtr.u.GCFlat &= ~(RTGCPTR)PAGE_OFFSET_MASK;3630 3631 /*3632 * Do the paging walk until we get to the page table.3633 */3634 DBGCVAR VarCur;3635 if (fGuest)3636 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);3637 else3638 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);3639 if (fLME)3640 {3641 /* Page Map Level 4 Lookup. */3642 /* Check if it's a valid address first? */3643 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;3644 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);3645 X86PML4E Pml4e;3646 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);3647 if (VBOX_FAILURE(rc))3648 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);3649 if (!Pml4e.n.u1Present)3650 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);3651 3652 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;3653 Assert(fPAE);3654 }3655 if (fPAE)3656 {3657 /* Page directory pointer table. */3658 X86PDPE Pdpe;3659 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK) * sizeof(Pdpe);3660 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);3661 if (VBOX_FAILURE(rc))3662 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);3663 if (!Pdpe.n.u1Present)3664 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);3665 3666 VarCur.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;3667 3668 /* Page directory (PAE). */3669 X86PDEPAE Pde;3670 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK) * sizeof(Pde);3671 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);3672 if (VBOX_FAILURE(rc))3673 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);3674 if (!Pde.n.u1Present)3675 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);3676 if (fPSE && Pde.n.u1Size)3677 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);3678 3679 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;3680 VarPTEAddr = VarCur;3681 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PAE_PG_MASK;3682 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTEPAE);3683 }3684 else3685 {3686 /* Page directory (legacy). */3687 X86PDE Pde;3688 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK) * sizeof(Pde);3689 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);3690 if (VBOX_FAILURE(rc))3691 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);3692 if (!Pde.n.u1Present)3693 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);3694 if (fPSE && Pde.n.u1Size)3695 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);3696 3697 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_SHIFT) & X86_PT_MASK;3698 VarPTEAddr = VarCur;3699 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PG_MASK;3700 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTE);3701 }3702 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;3703 iEntry /= cbEntry;3704 }3705 3706 /* adjust cEntries */3707 cEntries = RT_MAX(1, cEntries);3708 cEntries = RT_MIN(cEntries, cEntriesMax);3709 3710 /*3711 * The display loop.3712 */3713 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n",3714 &VarPTEAddr, &VarGCPtr, iEntry);3715 do3716 {3717 /*3718 * Read.3719 */3720 X86PTEPAE Pte;3721 Pte.u = 0;3722 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pte, cbEntry, &VarPTEAddr, NULL);3723 if (VBOX_FAILURE(rc))3724 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PTE memory at %DV.\n", &VarPTEAddr);3725 3726 /*3727 * Display.3728 */3729 if (iEntry != ~0U)3730 {3731 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);3732 iEntry++;3733 }3734 DBGCCmdHlpPrintf(pCmdHlp,3735 fPAE3736 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"3737 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",3738 Pte.u,3739 Pte.u & X86_PTE_PAE_PG_MASK,3740 Pte.n.u1Present ? "p " : "np",3741 Pte.n.u1Write ? "w" : "r",3742 Pte.n.u1User ? "u" : "s",3743 Pte.n.u1Accessed ? "a " : "na",3744 Pte.n.u1Dirty ? "d " : "nd",3745 Pte.n.u3Available,3746 Pte.n.u1Global ? (fPGE ? "g" : "G") : " ",3747 Pte.n.u1WriteThru ? "pwt" : " ",3748 Pte.n.u1CacheDisable ? "pcd" : " ",3749 Pte.n.u1PAT ? "pat" : " ",3750 Pte.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " "3751 );3752 if (Pte.u & UINT64_C(0x7fff000000000000))3753 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pte.u & UINT64_C(0x7fff000000000000)));3754 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");3755 if (VBOX_FAILURE(rc))3756 return rc;3757 3758 /*3759 * Advance.3760 */3761 VarPTEAddr.u.u64Number += cbEntry;3762 if (iEntry != ~0U)3763 VarGCPtr.u.GCFlat += PAGE_SIZE;3764 } while (cEntries-- > 0);3765 3766 NOREF(pResult);3767 return VINF_SUCCESS;3768 }3769 3770 3771 /**3772 * The 'dptb' command.3773 *3774 * @returns VBox status.3775 * @param pCmd Pointer to the command descriptor (as registered).3776 * @param pCmdHlp Pointer to command helper functions.3777 * @param pVM Pointer to the current VM (if any).3778 * @param paArgs Pointer to (readonly) array of arguments.3779 * @param cArgs Number of arguments in the array.3780 */3781 static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3782 {3783 if (!pVM)3784 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");3785 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);3786 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);3787 if (VBOX_FAILURE(rc1))3788 return rc1;3789 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);3790 return rc2;3791 }3792 3793 3794 /**3795 * The 'dt' command.3796 *3797 * @returns VBox status.3798 * @param pCmd Pointer to the command descriptor (as registered).3799 * @param pCmdHlp Pointer to command helper functions.3800 * @param pVM Pointer to the current VM (if any).3801 * @param paArgs Pointer to (readonly) array of arguments.3802 * @param cArgs Number of arguments in the array.3803 */3804 static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM /*pVM*/, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)3805 {3806 /*3807 * We can get a TSS selector (number), a far pointer using a TSS selector, or some kind of TSS pointer.3808 */3809 3810 /** @todo */3811 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dt is not implemented yet, feel free to do it. \n");3812 }3813 3814 3815 /**3816 * The 'm' command.3817 *3818 * @returns VBox status.3819 * @param pCmd Pointer to the command descriptor (as registered).3820 * @param pCmdHlp Pointer to command helper functions.3821 * @param pVM Pointer to the current VM (if any).3822 * @param paArgs Pointer to (readonly) array of arguments.3823 * @param cArgs Number of arguments in the array.3824 */3825 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3826 {3827 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Address: %DV\n", &paArgs[0]);3828 if (!pVM)3829 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");3830 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);3831 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);3832 int rc3 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);3833 int rc4 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);3834 if (VBOX_FAILURE(rc1))3835 return rc1;3836 if (VBOX_FAILURE(rc2))3837 return rc2;3838 if (VBOX_FAILURE(rc3))3839 return rc3;3840 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);3841 return rc4;3842 }3843 3844 3845 /**3846 * The 'echo' command.3847 *3848 * @returns VBox status.3849 * @param pCmd Pointer to the command descriptor (as registered).3850 * @param pCmdHlp Pointer to command helper functions.3851 * @param pVM Pointer to the current VM (if any).3852 * @param paArgs Pointer to (readonly) array of arguments.3853 * @param cArgs Number of arguments in the array.3854 */3855 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3856 {3857 /*3858 * Loop thru the arguments and print them with one space between.3859 */3860 int rc = 0;3861 for (unsigned i = 0; i < cArgs; i++)3862 {3863 if (paArgs[i].enmType == DBGCVAR_TYPE_STRING)3864 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString);3865 else3866 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>");3867 if (VBOX_FAILURE(rc))3868 return rc;3869 }3870 NOREF(pCmd); NOREF(pResult); NOREF(pVM);3871 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");3872 }3873 3874 3875 /**3876 * The 'runscript' command.3877 *3878 * @returns VBox status.3879 * @param pCmd Pointer to the command descriptor (as registered).3880 * @param pCmdHlp Pointer to command helper functions.3881 * @param pVM Pointer to the current VM (if any).3882 * @param paArgs Pointer to (readonly) array of arguments.3883 * @param cArgs Number of arguments in the array.3884 */3885 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3886 {3887 /* check that the parser did what it's supposed to do. */3888 if ( cArgs != 13889 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)3890 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");3891 3892 /*3893 * Try open the script.3894 */3895 const char *pszFilename = paArgs[0].u.pszString;3896 FILE *pFile = fopen(pszFilename, "r");3897 if (!pFile)3898 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename);3899 3900 /*3901 * Execute it line by line.3902 */3903 int rc = 0;3904 unsigned iLine = 0;3905 char szLine[8192];3906 while (fgets(szLine, sizeof(szLine), pFile))3907 {3908 /* check that the line isn't too long. */3909 char *pszEnd = strchr(szLine, '\0');3910 if (pszEnd == &szLine[sizeof(szLine) - 1])3911 {3912 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine);3913 break;3914 }3915 iLine++;3916 3917 /* strip leading blanks and check for comment / blank line. */3918 char *psz = RTStrStripL(szLine);3919 if ( *psz == '\0'3920 || *psz == '\n'3921 || *psz == '#')3922 continue;3923 3924 /* strip trailing blanks and check for empty line (\r case). */3925 while ( pszEnd > psz3926 && isspace(pszEnd[-1])) /* isspace includes \n and \r normally. */3927 *--pszEnd = '\0';3928 3929 /** @todo check for Control-C / Cancel at this point... */3930 3931 /*3932 * Execute the command.3933 *3934 * This is a bit wasteful with scratch space btw., can fix it later.3935 * The whole return code crap should be fixed too, so that it's possible3936 * to know whether a command succeeded (VBOX_SUCCESS()) or failed, and3937 * more importantly why it failed.3938 */3939 rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz);3940 if (VBOX_FAILURE(rc))3941 {3942 if (rc == VERR_BUFFER_OVERFLOW)3943 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);3944 break;3945 }3946 if (rc == VWRN_DBGC_CMD_PENDING)3947 {3948 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);3949 break;3950 }3951 }3952 3953 fclose(pFile);3954 3955 NOREF(pCmd); NOREF(pResult); NOREF(pVM);3956 return rc;3957 }3958 3959 3960 /**3961 * The 's' command.3962 *3963 * @returns VBox status.3964 * @param pCmd Pointer to the command descriptor (as registered).3965 * @param pCmdHlp Pointer to command helper functions.3966 * @param pVM Pointer to the current VM (if any).3967 * @param paArgs Pointer to (readonly) array of arguments.3968 * @param cArgs Number of arguments in the array.3969 */3970 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3971 {3972 /* check that the parser did what it's supposed to do. */3973 if ( cArgs != 13974 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)3975 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");3976 return -1;3977 }3978 3979 3980 3981 /**3982 * Print formatted string.3983 *3984 * @param pHlp Pointer to this structure.3985 * @param pszFormat The format string.3986 * @param ... Arguments.3987 */3988 static DECLCALLBACK(void) dbgcCmdInfo_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)3989 {3990 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);3991 va_list args;3992 va_start(args, pszFormat);3993 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);3994 va_end(args);3995 }3996 3997 3998 /**3999 * Print formatted string.4000 *4001 * @param pHlp Pointer to this structure.4002 * @param pszFormat The format string.4003 * @param args Argument list.4004 */4005 static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)4006 {4007 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);4008 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);4009 }4010 4011 4012 /**4013 * The 'info' command.4014 *4015 * @returns VBox status.4016 * @param pCmd Pointer to the command descriptor (as registered).4017 * @param pCmdHlp Pointer to command helper functions.4018 * @param pVM Pointer to the current VM (if any).4019 * @param paArgs Pointer to (readonly) array of arguments.4020 * @param cArgs Number of arguments in the array.4021 */4022 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4023 {4024 /*4025 * Validate input.4026 */4027 if ( cArgs < 14028 || cArgs > 24029 || paArgs[0].enmType != DBGCVAR_TYPE_STRING4030 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)4031 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");4032 if (!pVM)4033 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");4034 4035 /*4036 * Dump it.4037 */4038 struct4039 {4040 DBGFINFOHLP Hlp;4041 PDBGCCMDHLP pCmdHlp;4042 } Hlp = { { dbgcCmdInfo_Printf, dbgcCmdInfo_PrintfV }, pCmdHlp };4043 int rc = DBGFR3Info(pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp);4044 if (VBOX_FAILURE(rc))4045 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");4046 4047 NOREF(pCmd); NOREF(pResult);4048 return 0;4049 }4050 4051 4052 /**4053 * The 'log' command.4054 *4055 * @returns VBox status.4056 * @param pCmd Pointer to the command descriptor (as registered).4057 * @param pCmdHlp Pointer to command helper functions.4058 * @param pVM Pointer to the current VM (if any).4059 * @param paArgs Pointer to (readonly) array of arguments.4060 * @param cArgs Number of arguments in the array.4061 */4062 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4063 {4064 int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);4065 if (VBOX_SUCCESS(rc))4066 return VINF_SUCCESS;4067 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);4068 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);4069 }4070 4071 4072 /**4073 * The 'logdest' command.4074 *4075 * @returns VBox status.4076 * @param pCmd Pointer to the command descriptor (as registered).4077 * @param pCmdHlp Pointer to command helper functions.4078 * @param pVM Pointer to the current VM (if any).4079 * @param paArgs Pointer to (readonly) array of arguments.4080 * @param cArgs Number of arguments in the array.4081 */4082 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4083 {4084 int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);4085 if (VBOX_SUCCESS(rc))4086 return VINF_SUCCESS;4087 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);4088 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);4089 }4090 4091 4092 /**4093 * The 'logflags' command.4094 *4095 * @returns VBox status.4096 * @param pCmd Pointer to the command descriptor (as registered).4097 * @param pCmdHlp Pointer to command helper functions.4098 * @param pVM Pointer to the current VM (if any).4099 * @param paArgs Pointer to (readonly) array of arguments.4100 * @param cArgs Number of arguments in the array.4101 */4102 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4103 {4104 int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);4105 if (VBOX_SUCCESS(rc))4106 return VINF_SUCCESS;4107 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);4108 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);4109 }4110 4111 4112 /**4113 * The 'format' command.4114 *4115 * @returns VBox status.4116 * @param pCmd Pointer to the command descriptor (as registered).4117 * @param pCmdHlp Pointer to command helper functions.4118 * @param pVM Pointer to the current VM (if any).4119 * @param paArgs Pointer to (readonly) array of arguments.4120 * @param cArgs Number of arguments in the array.4121 */4122 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4123 {4124 LogFlow(("dbgcCmdFormat\n"));4125 static const char *apszRangeDesc[] =4126 {4127 "none", "bytes", "elements"4128 };4129 int rc;4130 4131 for (unsigned iArg = 0; iArg < cArgs; iArg++)4132 {4133 switch (paArgs[iArg].enmType)4134 {4135 case DBGCVAR_TYPE_UNKNOWN:4136 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4137 "Unknown variable type!\n");4138 break;4139 case DBGCVAR_TYPE_GC_FLAT:4140 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)4141 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4142 "Guest flat address: %%%08x range %lld %s\n",4143 paArgs[iArg].u.GCFlat,4144 paArgs[iArg].u64Range,4145 apszRangeDesc[paArgs[iArg].enmRangeType]);4146 else4147 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4148 "Guest flat address: %%%08x\n",4149 paArgs[iArg].u.GCFlat);4150 break;4151 case DBGCVAR_TYPE_GC_FAR:4152 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)4153 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4154 "Guest far address: %04x:%08x range %lld %s\n",4155 paArgs[iArg].u.GCFar.sel,4156 paArgs[iArg].u.GCFar.off,4157 paArgs[iArg].u64Range,4158 apszRangeDesc[paArgs[iArg].enmRangeType]);4159 else4160 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4161 "Guest far address: %04x:%08x\n",4162 paArgs[iArg].u.GCFar.sel,4163 paArgs[iArg].u.GCFar.off);4164 break;4165 case DBGCVAR_TYPE_GC_PHYS:4166 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)4167 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4168 "Guest physical address: %%%%%08x range %lld %s\n",4169 paArgs[iArg].u.GCPhys,4170 paArgs[iArg].u64Range,4171 apszRangeDesc[paArgs[iArg].enmRangeType]);4172 else4173 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4174 "Guest physical address: %%%%%08x\n",4175 paArgs[iArg].u.GCPhys);4176 break;4177 case DBGCVAR_TYPE_HC_FLAT:4178 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)4179 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4180 "Host flat address: %%%08x range %lld %s\n",4181 paArgs[iArg].u.pvHCFlat,4182 paArgs[iArg].u64Range,4183 apszRangeDesc[paArgs[iArg].enmRangeType]);4184 else4185 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4186 "Host flat address: %%%08x\n",4187 paArgs[iArg].u.pvHCFlat);4188 break;4189 case DBGCVAR_TYPE_HC_FAR:4190 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)4191 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4192 "Host far address: %04x:%08x range %lld %s\n",4193 paArgs[iArg].u.HCFar.sel,4194 paArgs[iArg].u.HCFar.off,4195 paArgs[iArg].u64Range,4196 apszRangeDesc[paArgs[iArg].enmRangeType]);4197 else4198 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4199 "Host far address: %04x:%08x\n",4200 paArgs[iArg].u.HCFar.sel,4201 paArgs[iArg].u.HCFar.off);4202 break;4203 case DBGCVAR_TYPE_HC_PHYS:4204 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)4205 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4206 "Host physical address: %VHp range %lld %s\n",4207 paArgs[iArg].u.HCPhys,4208 paArgs[iArg].u64Range,4209 apszRangeDesc[paArgs[iArg].enmRangeType]);4210 else4211 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4212 "Host physical address: %VHp\n",4213 paArgs[iArg].u.HCPhys);4214 break;4215 4216 case DBGCVAR_TYPE_STRING:4217 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4218 "String, %lld bytes long: %s\n",4219 paArgs[iArg].u64Range,4220 paArgs[iArg].u.pszString);4221 break;4222 4223 case DBGCVAR_TYPE_NUMBER:4224 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)4225 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4226 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",4227 paArgs[iArg].u.u64Number,4228 paArgs[iArg].u.u64Number,4229 paArgs[iArg].u.u64Number,4230 paArgs[iArg].u64Range,4231 apszRangeDesc[paArgs[iArg].enmRangeType]);4232 else4233 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4234 "Number: hex %llx dec 0i%lld oct 0t%llo\n",4235 paArgs[iArg].u.u64Number,4236 paArgs[iArg].u.u64Number,4237 paArgs[iArg].u.u64Number);4238 break;4239 4240 default:4241 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,4242 "Invalid argument type %d\n",4243 paArgs[iArg].enmType);4244 break;4245 }4246 } /* arg loop */4247 4248 NOREF(pCmd); NOREF(pVM); NOREF(pResult);4249 return 0;4250 }4251 4252 4253 /**4254 * List near symbol.4255 *4256 * @returns VBox status code.4257 * @param pCmdHlp Pointer to command helper functions.4258 * @param pVM Pointer to the current VM (if any).4259 * @param pArg Pointer to the address or symbol to lookup.4260 */4261 static int dbgcDoListNear(PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR pArg, PDBGCVAR pResult)4262 {4263 dbgcVarSetGCFlat(pResult, 0);4264 4265 DBGFSYMBOL Symbol;4266 int rc;4267 if (pArg->enmType == DBGCVAR_TYPE_SYMBOL)4268 {4269 /*4270 * Lookup the symbol address.4271 */4272 rc = DBGFR3SymbolByName(pVM, pArg->u.pszString, &Symbol);4273 if (VBOX_FAILURE(rc))4274 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByName(, %s,)\n", pArg->u.pszString);4275 4276 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%VGv %s\n", (RTGCUINTPTR)Symbol.Value, Symbol.szName); /** @todo remove the RTUINGCPTR cast once DBGF got correct interfaces! */4277 dbgcVarSetGCFlatByteRange(pResult, Symbol.Value, Symbol.cb);4278 }4279 else4280 {4281 /*4282 * Convert it to a flat GC address and lookup that address.4283 */4284 DBGCVAR AddrVar;4285 rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%DV)", pArg);4286 if (VBOX_FAILURE(rc))4287 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%DV)\n", pArg);4288 4289 dbgcVarSetVar(pResult, &AddrVar);4290 4291 RTGCINTPTR offDisp = 0;4292 rc = DBGFR3SymbolByAddr(pVM, AddrVar.u.GCFlat, &offDisp, &Symbol);4293 if (VBOX_FAILURE(rc))4294 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByAddr(, %VGv,,)\n", AddrVar.u.GCFlat);4295 4296 if (!offDisp)4297 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s", &AddrVar, Symbol.szName);4298 else if (offDisp > 0)4299 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s + %RGv", &AddrVar, Symbol.szName, offDisp);4300 else4301 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s - %RGv", &AddrVar, Symbol.szName, -offDisp);4302 if ((RTGCINTPTR)Symbol.cb > -offDisp)4303 {4304 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " LB %RGv\n", Symbol.cb + offDisp);4305 dbgcVarSetByteRange(pResult, Symbol.cb + offDisp);4306 }4307 else4308 {4309 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");4310 dbgcVarSetNoRange(pResult);4311 }4312 }4313 4314 return rc;4315 }4316 4317 4318 /**4319 * The 'ln' (listnear) command.4320 *4321 * @returns VBox status.4322 * @param pCmd Pointer to the command descriptor (as registered).4323 * @param pCmdHlp Pointer to command helper functions.4324 * @param pVM Pointer to the current VM (if any).4325 * @param paArgs Pointer to (readonly) array of arguments.4326 * @param cArgs Number of arguments in the array.4327 */4328 static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4329 {4330 dbgcVarSetGCFlat(pResult, 0);4331 if (!cArgs)4332 {4333 /*4334 * Current cs:eip symbol.4335 */4336 DBGCVAR AddrVar;4337 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(cs:eip)");4338 if (VBOX_FAILURE(rc))4339 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(cs:eip)\n");4340 return dbgcDoListNear(pCmdHlp, pVM, &AddrVar, pResult);4341 }4342 4343 /*4344 * Iterate arguments.4345 */4346 for (unsigned iArg = 0; iArg < cArgs; iArg++)4347 {4348 int rc = dbgcDoListNear(pCmdHlp, pVM, &paArgs[iArg], pResult);4349 if (VBOX_FAILURE(rc))4350 return rc;4351 }4352 4353 NOREF(pCmd); NOREF(pResult);4354 return VINF_SUCCESS;4355 }4356 4357 4358 /**4359 * The 'loadsyms' command.4360 *4361 * @returns VBox status.4362 * @param pCmd Pointer to the command descriptor (as registered).4363 * @param pCmdHlp Pointer to command helper functions.4364 * @param pVM Pointer to the current VM (if any).4365 * @param paArgs Pointer to (readonly) array of arguments.4366 * @param cArgs Number of arguments in the array.4367 */4368 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4369 {4370 /*4371 * Validate the parsing and make sense of the input.4372 * This is a mess as usual because we don't trust the parser yet.4373 */4374 if ( cArgs < 14375 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)4376 {4377 AssertMsgFailed(("Parse error, first argument required to be string!\n"));4378 return VERR_PARSE_INCORRECT_ARG_TYPE;4379 }4380 DBGCVAR AddrVar;4381 RTGCUINTPTR Delta = 0;4382 const char *pszModule = NULL;4383 RTGCUINTPTR ModuleAddress = 0;4384 unsigned cbModule = 0;4385 if (cArgs > 1)4386 {4387 unsigned iArg = 1;4388 if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)4389 {4390 Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;4391 iArg++;4392 }4393 if (iArg < cArgs)4394 {4395 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)4396 {4397 AssertMsgFailed(("Parse error, module argument required to be string!\n"));4398 return VERR_PARSE_INCORRECT_ARG_TYPE;4399 }4400 pszModule = paArgs[iArg].u.pszString;4401 iArg++;4402 if (iArg < cArgs)4403 {4404 if (DBGCVAR_ISPOINTER(paArgs[iArg].enmType))4405 {4406 AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));4407 return VERR_PARSE_INCORRECT_ARG_TYPE;4408 }4409 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);4410 if (VBOX_FAILURE(rc))4411 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);4412 ModuleAddress = paArgs[iArg].u.GCFlat;4413 iArg++;4414 if (iArg < cArgs)4415 {4416 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)4417 {4418 AssertMsgFailed(("Parse error, module argument required to be an interger!\n"));4419 return VERR_PARSE_INCORRECT_ARG_TYPE;4420 }4421 cbModule = (unsigned)paArgs[iArg].u.u64Number;4422 iArg++;4423 if (iArg < cArgs)4424 {4425 AssertMsgFailed(("Parse error, too many arguments!\n"));4426 return VERR_PARSE_TOO_MANY_ARGUMENTS;4427 }4428 }4429 }4430 }4431 }4432 4433 /*4434 * Call the debug info manager about this loading...4435 */4436 int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);4437 if (VBOX_FAILURE(rc))4438 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %VGv, '%s', %VGv, 0)\n",4439 paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);4440 4441 NOREF(pCmd); NOREF(pResult);4442 return VINF_SUCCESS;4443 }4444 4445 4446 /**4447 * The 'set' command.4448 *4449 * @returns VBox status.4450 * @param pCmd Pointer to the command descriptor (as registered).4451 * @param pCmdHlp Pointer to command helper functions.4452 * @param pVM Pointer to the current VM (if any).4453 * @param paArgs Pointer to (readonly) array of arguments.4454 * @param cArgs Number of arguments in the array.4455 */4456 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4457 {4458 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4459 4460 /* parse sanity check. */4461 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));4462 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)4463 return VERR_PARSE_INCORRECT_ARG_TYPE;4464 4465 4466 /*4467 * A variable must start with an alpha chars and only contain alpha numerical chars.4468 */4469 const char *pszVar = paArgs[0].u.pszString;4470 if (!isalpha(*pszVar) || *pszVar == '_')4471 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,4472 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);4473 4474 while (isalnum(*pszVar) || *pszVar == '_')4475 *pszVar++;4476 if (*pszVar)4477 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,4478 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);4479 4480 4481 /*4482 * Calc variable size.4483 */4484 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);4485 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)4486 cbVar += 1 + (size_t)paArgs[1].u64Range;4487 4488 /*4489 * Look for existing one.4490 */4491 pszVar = paArgs[0].u.pszString;4492 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)4493 {4494 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))4495 {4496 /*4497 * Update existing variable.4498 */4499 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);4500 if (!pv)4501 return VERR_PARSE_NO_MEMORY;4502 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;4503 4504 pVar->Var = paArgs[1];4505 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);4506 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)4507 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);4508 return 0;4509 }4510 }4511 4512 /*4513 * Allocate another.4514 */4515 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);4516 4517 pVar->Var = paArgs[1];4518 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);4519 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)4520 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);4521 4522 /* need to reallocate the pointer array too? */4523 if (!(pDbgc->cVars % 0x20))4524 {4525 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));4526 if (!pv)4527 {4528 RTMemFree(pVar);4529 return VERR_PARSE_NO_MEMORY;4530 }4531 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;4532 }4533 pDbgc->papVars[pDbgc->cVars++] = pVar;4534 4535 NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult);4536 return 0;4537 }4538 4539 4540 /**4541 * The 'unset' command.4542 *4543 * @returns VBox status.4544 * @param pCmd Pointer to the command descriptor (as registered).4545 * @param pCmdHlp Pointer to command helper functions.4546 * @param pVM Pointer to the current VM (if any).4547 * @param paArgs Pointer to (readonly) array of arguments.4548 * @param cArgs Number of arguments in the array.4549 */4550 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4551 {4552 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4553 4554 /*4555 * Don't trust the parser.4556 */4557 for (unsigned i = 0; i < cArgs; i++)4558 if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)4559 {4560 AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));4561 return VERR_PARSE_INCORRECT_ARG_TYPE;4562 }4563 4564 /*4565 * Iterate the variables and unset them.4566 */4567 for (unsigned iArg = 0; iArg < cArgs; iArg++)4568 {4569 const char *pszVar = paArgs[iArg].u.pszString;4570 4571 /*4572 * Look up the variable.4573 */4574 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)4575 {4576 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))4577 {4578 /*4579 * Shuffle the array removing this entry.4580 */4581 void *pvFree = pDbgc->papVars[iVar];4582 if (iVar + 1 < pDbgc->cVars)4583 memmove(&pDbgc->papVars[iVar],4584 &pDbgc->papVars[iVar + 1],4585 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));4586 pDbgc->papVars[--pDbgc->cVars] = NULL;4587 4588 RTMemFree(pvFree);4589 }4590 } /* lookup */4591 } /* arg loop */4592 4593 NOREF(pCmd); NOREF(pVM); NOREF(pResult);4594 return 0;4595 }4596 4597 4598 /**4599 * The 'loadvars' command.4600 *4601 * @returns VBox status.4602 * @param pCmd Pointer to the command descriptor (as registered).4603 * @param pCmdHlp Pointer to command helper functions.4604 * @param pVM Pointer to the current VM (if any).4605 * @param paArgs Pointer to (readonly) array of arguments.4606 * @param cArgs Number of arguments in the array.4607 */4608 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4609 {4610 /*4611 * Don't trust the parser.4612 */4613 if ( cArgs != 14614 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)4615 {4616 AssertMsgFailed(("Expected one string exactly!\n"));4617 return VERR_PARSE_INCORRECT_ARG_TYPE;4618 }4619 4620 /*4621 * Iterate the variables and unset them.4622 */4623 FILE *pFile = fopen(paArgs[0].u.pszString, "r");4624 if (pFile)4625 {4626 char szLine[4096];4627 while (fgets(szLine, sizeof(szLine), pFile))4628 {4629 /* Strip it. */4630 char *psz = szLine;4631 while (isblank(*psz))4632 psz++;4633 int i = (int)strlen(psz) - 1;4634 while (i >= 0 && isspace(psz[i]))4635 psz[i--] ='\0';4636 /* Execute it if not comment or empty line. */4637 if ( *psz != '\0'4638 && *psz != '#'4639 && *psz != ';')4640 {4641 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);4642 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);4643 }4644 }4645 fclose(pFile);4646 }4647 else4648 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);4649 4650 NOREF(pCmd); NOREF(pVM); NOREF(pResult);4651 return 0;4652 }4653 4654 4655 /**4656 * The 'showvars' command.4657 *4658 * @returns VBox status.4659 * @param pCmd Pointer to the command descriptor (as registered).4660 * @param pCmdHlp Pointer to command helper functions.4661 * @param pVM Pointer to the current VM (if any).4662 * @param paArgs Pointer to (readonly) array of arguments.4663 * @param cArgs Number of arguments in the array.4664 */4665 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4666 {4667 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4668 4669 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)4670 {4671 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);4672 if (!rc)4673 rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL);4674 if (rc)4675 return rc;4676 }4677 4678 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);4679 return 0;4680 }4681 4682 4683 /**4684 * The 'harakiri' command.4685 *4686 * @returns VBox status.4687 * @param pCmd Pointer to the command descriptor (as registered).4688 * @param pCmdHlp Pointer to command helper functions.4689 * @param pVM Pointer to the current VM (if any).4690 * @param paArgs Pointer to (readonly) array of arguments.4691 * @param cArgs Number of arguments in the array.4692 */4693 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4694 {4695 Log(("dbgcCmdHarakiri\n"));4696 for (;;)4697 exit(126);4698 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);4699 }4700 4701 4702 4703 4704 4705 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4706 //4707 //4708 // B u l t i n S y m b o l s4709 //4710 //4711 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4712 4713 4714 4715 /**4716 * Get builtin register symbol.4717 *4718 * The uUser is special for these symbol descriptors. See the SYMREG_* \#defines.4719 *4720 * @returns 0 on success.4721 * @returns VBox evaluation / parsing error code on failure.4722 * The caller does the bitching.4723 * @param pSymDesc Pointer to the symbol descriptor.4724 * @param pCmdHlp Pointer to the command callback structure.4725 * @param enmType The result type.4726 * @param pResult Where to store the result.4727 */4728 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult)4729 {4730 LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));4731 4732 /*4733 * pVM is required.4734 */4735 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4736 Assert(pDbgc->pVM);4737 4738 /*4739 * Get the right CPU context.4740 */4741 PCPUMCTX pCtx;4742 int rc;4743 if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))4744 rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);4745 else4746 rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);4747 if (VBOX_FAILURE(rc))4748 return rc;4749 4750 /*4751 * Get the value.4752 */4753 void *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);4754 uint64_t u64;4755 switch (SYMREG_SIZE(pSymDesc->uUser))4756 {4757 case 1: u64 = *(uint8_t *)pvValue; break;4758 case 2: u64 = *(uint16_t *)pvValue; break;4759 case 4: u64 = *(uint32_t *)pvValue; break;4760 case 6: u64 = *(uint32_t *)pvValue | ((uint64_t)*(uint16_t *)((char *)pvValue + sizeof(uint32_t)) << 32); break;4761 case 8: u64 = *(uint64_t *)pvValue; break;4762 default:4763 return VERR_PARSE_NOT_IMPLEMENTED;4764 }4765 4766 /*4767 * Construct the desired result.4768 */4769 if (enmType == DBGCVAR_TYPE_ANY)4770 enmType = DBGCVAR_TYPE_NUMBER;4771 pResult->pDesc = NULL;4772 pResult->pNext = NULL;4773 pResult->enmType = enmType;4774 pResult->enmRangeType = DBGCVAR_RANGE_NONE;4775 pResult->u64Range = 0;4776 4777 switch (enmType)4778 {4779 case DBGCVAR_TYPE_GC_FLAT:4780 pResult->u.GCFlat = (RTGCPTR)u64;4781 break;4782 4783 case DBGCVAR_TYPE_GC_FAR:4784 switch (SYMREG_SIZE(pSymDesc->uUser))4785 {4786 case 4:4787 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))4788 {4789 pResult->u.GCFar.off = (uint16_t)u64;4790 pResult->u.GCFar.sel = (uint16_t)(u64 >> 16);4791 }4792 else4793 {4794 pResult->u.GCFar.sel = (uint16_t)u64;4795 pResult->u.GCFar.off = (uint16_t)(u64 >> 16);4796 }4797 break;4798 case 6:4799 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))4800 {4801 pResult->u.GCFar.off = (uint32_t)u64;4802 pResult->u.GCFar.sel = (uint16_t)(u64 >> 32);4803 }4804 else4805 {4806 pResult->u.GCFar.sel = (uint32_t)u64;4807 pResult->u.GCFar.off = (uint16_t)(u64 >> 32);4808 }4809 break;4810 4811 default:4812 return VERR_PARSE_BAD_RESULT_TYPE;4813 }4814 break;4815 4816 case DBGCVAR_TYPE_GC_PHYS:4817 pResult->u.GCPhys = (RTGCPHYS)u64;4818 break;4819 4820 case DBGCVAR_TYPE_HC_FLAT:4821 pResult->u.pvHCFlat = (void *)(uintptr_t)u64;4822 break;4823 4824 case DBGCVAR_TYPE_HC_FAR:4825 switch (SYMREG_SIZE(pSymDesc->uUser))4826 {4827 case 4:4828 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))4829 {4830 pResult->u.HCFar.off = (uint16_t)u64;4831 pResult->u.HCFar.sel = (uint16_t)(u64 >> 16);4832 }4833 else4834 {4835 pResult->u.HCFar.sel = (uint16_t)u64;4836 pResult->u.HCFar.off = (uint16_t)(u64 >> 16);4837 }4838 break;4839 case 6:4840 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))4841 {4842 pResult->u.HCFar.off = (uint32_t)u64;4843 pResult->u.HCFar.sel = (uint16_t)(u64 >> 32);4844 }4845 else4846 {4847 pResult->u.HCFar.sel = (uint32_t)u64;4848 pResult->u.HCFar.off = (uint16_t)(u64 >> 32);4849 }4850 break;4851 4852 default:4853 return VERR_PARSE_BAD_RESULT_TYPE;4854 }4855 break;4856 4857 case DBGCVAR_TYPE_HC_PHYS:4858 pResult->u.GCPhys = (RTGCPHYS)u64;4859 break;4860 4861 case DBGCVAR_TYPE_NUMBER:4862 pResult->u.u64Number = u64;4863 break;4864 4865 case DBGCVAR_TYPE_STRING:4866 case DBGCVAR_TYPE_UNKNOWN:4867 default:4868 return VERR_PARSE_BAD_RESULT_TYPE;4869 4870 }4871 4872 return 0;4873 }4874 4875 4876 /**4877 * Set builtin register symbol.4878 *4879 * The uUser is special for these symbol descriptors. See the SYMREG_* #defines.4880 *4881 * @returns 0 on success.4882 * @returns VBox evaluation / parsing error code on failure.4883 * The caller does the bitching.4884 * @param pSymDesc Pointer to the symbol descriptor.4885 * @param pCmdHlp Pointer to the command callback structure.4886 * @param pValue The value to assign the symbol.4887 */4888 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue)4889 {4890 LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));4891 4892 /*4893 * pVM is required.4894 */4895 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4896 Assert(pDbgc->pVM);4897 4898 /*4899 * Get the right CPU context.4900 */4901 PCPUMCTX pCtx;4902 int rc;4903 if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))4904 rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);4905 else4906 rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);4907 if (VBOX_FAILURE(rc))4908 return rc;4909 4910 /*4911 * Check the new value.4912 */4913 if (pValue->enmType != DBGCVAR_TYPE_NUMBER)4914 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;4915 4916 /*4917 * Set the value.4918 */4919 void *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);4920 switch (SYMREG_SIZE(pSymDesc->uUser))4921 {4922 case 1:4923 *(uint8_t *)pvValue = (uint8_t)pValue->u.u64Number;4924 break;4925 case 2:4926 *(uint16_t *)pvValue = (uint16_t)pValue->u.u64Number;4927 break;4928 case 4:4929 *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;4930 break;4931 case 6:4932 *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;4933 ((uint16_t *)pvValue)[3] = (uint16_t)(pValue->u.u64Number >> 32);4934 break;4935 case 8:4936 *(uint64_t *)pvValue = pValue->u.u64Number;4937 break;4938 default:4939 return VERR_PARSE_NOT_IMPLEMENTED;4940 }4941 4942 return VINF_SUCCESS;4943 }4944 4945 4946 4947 4948 4949 4950 4951 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4952 //4953 //4954 // O p e r a t o r s4955 //4956 //4957 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4958 4959 4960 /**4961 * Minus (unary).4962 *4963 * @returns 0 on success.4964 * @returns VBox evaluation / parsing error code on failure.4965 * The caller does the bitching.4966 * @param pDbgc Debugger console instance data.4967 * @param pArg The argument.4968 * @param pResult Where to store the result.4969 */4970 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)4971 {4972 // LogFlow(("dbgcOpMinus\n"));4973 *pResult = *pArg;4974 switch (pArg->enmType)4975 {4976 case DBGCVAR_TYPE_GC_FLAT:4977 pResult->u.GCFlat = -(RTGCINTPTR)pResult->u.GCFlat;4978 break;4979 case DBGCVAR_TYPE_GC_FAR:4980 pResult->u.GCFar.off = -(int32_t)pResult->u.GCFar.off;4981 break;4982 case DBGCVAR_TYPE_GC_PHYS:4983 pResult->u.GCPhys = (RTGCPHYS) -(int64_t)pResult->u.GCPhys;4984 break;4985 case DBGCVAR_TYPE_HC_FLAT:4986 pResult->u.pvHCFlat = (void *) -(intptr_t)pResult->u.pvHCFlat;4987 break;4988 case DBGCVAR_TYPE_HC_FAR:4989 pResult->u.HCFar.off = -(int32_t)pResult->u.HCFar.off;4990 break;4991 case DBGCVAR_TYPE_HC_PHYS:4992 pResult->u.HCPhys = (RTHCPHYS) -(int64_t)pResult->u.HCPhys;4993 break;4994 case DBGCVAR_TYPE_NUMBER:4995 pResult->u.u64Number = -(int64_t)pResult->u.u64Number;4996 break;4997 4998 case DBGCVAR_TYPE_UNKNOWN:4999 case DBGCVAR_TYPE_STRING:5000 default:5001 return VERR_PARSE_INCORRECT_ARG_TYPE;5002 }5003 NOREF(pDbgc);5004 return 0;5005 }5006 5007 5008 /**5009 * Pluss (unary).5010 *5011 * @returns 0 on success.5012 * @returns VBox evaluation / parsing error code on failure.5013 * The caller does the bitching.5014 * @param pDbgc Debugger console instance data.5015 * @param pArg The argument.5016 * @param pResult Where to store the result.5017 */5018 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5019 {5020 // LogFlow(("dbgcOpPluss\n"));5021 *pResult = *pArg;5022 switch (pArg->enmType)5023 {5024 case DBGCVAR_TYPE_GC_FLAT:5025 case DBGCVAR_TYPE_GC_FAR:5026 case DBGCVAR_TYPE_GC_PHYS:5027 case DBGCVAR_TYPE_HC_FLAT:5028 case DBGCVAR_TYPE_HC_FAR:5029 case DBGCVAR_TYPE_HC_PHYS:5030 case DBGCVAR_TYPE_NUMBER:5031 break;5032 5033 case DBGCVAR_TYPE_UNKNOWN:5034 case DBGCVAR_TYPE_STRING:5035 default:5036 return VERR_PARSE_INCORRECT_ARG_TYPE;5037 }5038 NOREF(pDbgc);5039 return 0;5040 }5041 5042 5043 /**5044 * Boolean not (unary).5045 *5046 * @returns 0 on success.5047 * @returns VBox evaluation / parsing error code on failure.5048 * The caller does the bitching.5049 * @param pDbgc Debugger console instance data.5050 * @param pArg The argument.5051 * @param pResult Where to store the result.5052 */5053 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5054 {5055 // LogFlow(("dbgcOpBooleanNot\n"));5056 *pResult = *pArg;5057 switch (pArg->enmType)5058 {5059 case DBGCVAR_TYPE_GC_FLAT:5060 pResult->u.u64Number = !pResult->u.GCFlat;5061 break;5062 case DBGCVAR_TYPE_GC_FAR:5063 pResult->u.u64Number = !pResult->u.GCFar.off && pResult->u.GCFar.sel <= 3;5064 break;5065 case DBGCVAR_TYPE_GC_PHYS:5066 pResult->u.u64Number = !pResult->u.GCPhys;5067 break;5068 case DBGCVAR_TYPE_HC_FLAT:5069 pResult->u.u64Number = !pResult->u.pvHCFlat;5070 break;5071 case DBGCVAR_TYPE_HC_FAR:5072 pResult->u.u64Number = !pResult->u.HCFar.off && pResult->u.HCFar.sel <= 3;5073 break;5074 case DBGCVAR_TYPE_HC_PHYS:5075 pResult->u.u64Number = !pResult->u.HCPhys;5076 break;5077 case DBGCVAR_TYPE_NUMBER:5078 pResult->u.u64Number = !pResult->u.u64Number;5079 break;5080 case DBGCVAR_TYPE_STRING:5081 pResult->u.u64Number = !pResult->u64Range;5082 break;5083 5084 case DBGCVAR_TYPE_UNKNOWN:5085 default:5086 return VERR_PARSE_INCORRECT_ARG_TYPE;5087 }5088 pResult->enmType = DBGCVAR_TYPE_NUMBER;5089 NOREF(pDbgc);5090 return 0;5091 }5092 5093 5094 /**5095 * Bitwise not (unary).5096 *5097 * @returns 0 on success.5098 * @returns VBox evaluation / parsing error code on failure.5099 * The caller does the bitching.5100 * @param pDbgc Debugger console instance data.5101 * @param pArg The argument.5102 * @param pResult Where to store the result.5103 */5104 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5105 {5106 // LogFlow(("dbgcOpBitwiseNot\n"));5107 *pResult = *pArg;5108 switch (pArg->enmType)5109 {5110 case DBGCVAR_TYPE_GC_FLAT:5111 pResult->u.GCFlat = ~pResult->u.GCFlat;5112 break;5113 case DBGCVAR_TYPE_GC_FAR:5114 pResult->u.GCFar.off = ~pResult->u.GCFar.off;5115 break;5116 case DBGCVAR_TYPE_GC_PHYS:5117 pResult->u.GCPhys = ~pResult->u.GCPhys;5118 break;5119 case DBGCVAR_TYPE_HC_FLAT:5120 pResult->u.pvHCFlat = (void *)~(uintptr_t)pResult->u.pvHCFlat;5121 break;5122 case DBGCVAR_TYPE_HC_FAR:5123 pResult->u.HCFar.off= ~pResult->u.HCFar.off;5124 break;5125 case DBGCVAR_TYPE_HC_PHYS:5126 pResult->u.HCPhys = ~pResult->u.HCPhys;5127 break;5128 case DBGCVAR_TYPE_NUMBER:5129 pResult->u.u64Number = ~pResult->u.u64Number;5130 break;5131 5132 case DBGCVAR_TYPE_UNKNOWN:5133 case DBGCVAR_TYPE_STRING:5134 default:5135 return VERR_PARSE_INCORRECT_ARG_TYPE;5136 }5137 NOREF(pDbgc);5138 return 0;5139 }5140 5141 5142 /**5143 * Reference variable (unary).5144 *5145 * @returns 0 on success.5146 * @returns VBox evaluation / parsing error code on failure.5147 * The caller does the bitching.5148 * @param pDbgc Debugger console instance data.5149 * @param pArg The argument.5150 * @param pResult Where to store the result.5151 */5152 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5153 {5154 // LogFlow(("dbgcOpVar: %s\n", pArg->u.pszString));5155 /*5156 * Parse sanity.5157 */5158 if (pArg->enmType != DBGCVAR_TYPE_STRING)5159 return VERR_PARSE_INCORRECT_ARG_TYPE;5160 5161 /*5162 * Lookup the variable.5163 */5164 const char *pszVar = pArg->u.pszString;5165 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)5166 {5167 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))5168 {5169 *pResult = pDbgc->papVars[iVar]->Var;5170 return 0;5171 }5172 }5173 5174 return VERR_PARSE_VARIABLE_NOT_FOUND;5175 }5176 5177 5178 /**5179 * Flat address (unary).5180 *5181 * @returns VINF_SUCCESS on success.5182 * @returns VBox evaluation / parsing error code on failure.5183 * The caller does the bitching.5184 * @param pDbgc Debugger console instance data.5185 * @param pArg The argument.5186 * @param pResult Where to store the result.5187 */5188 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5189 {5190 // LogFlow(("dbgcOpAddrFlat\n"));5191 int rc;5192 *pResult = *pArg;5193 5194 switch (pArg->enmType)5195 {5196 case DBGCVAR_TYPE_GC_FLAT:5197 return VINF_SUCCESS;5198 5199 case DBGCVAR_TYPE_GC_FAR:5200 {5201 Assert(pDbgc->pVM);5202 DBGFADDRESS Address;5203 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);5204 if (VBOX_SUCCESS(rc))5205 {5206 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;5207 pResult->u.GCFlat = Address.FlatPtr;5208 return VINF_SUCCESS;5209 }5210 return VERR_PARSE_CONVERSION_FAILED;5211 }5212 5213 case DBGCVAR_TYPE_GC_PHYS:5214 //rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure.5215 return VERR_PARSE_INCORRECT_ARG_TYPE;5216 5217 case DBGCVAR_TYPE_HC_FLAT:5218 return VINF_SUCCESS;5219 5220 case DBGCVAR_TYPE_HC_FAR:5221 return VERR_PARSE_INCORRECT_ARG_TYPE;5222 5223 case DBGCVAR_TYPE_HC_PHYS:5224 Assert(pDbgc->pVM);5225 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;5226 rc = MMR3HCPhys2HCVirt(pDbgc->pVM, pResult->u.HCPhys, &pResult->u.pvHCFlat);5227 if (VBOX_SUCCESS(rc))5228 return VINF_SUCCESS;5229 return VERR_PARSE_CONVERSION_FAILED;5230 5231 case DBGCVAR_TYPE_NUMBER:5232 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;5233 pResult->u.GCFlat = (RTGCPTR)pResult->u.u64Number;5234 return VINF_SUCCESS;5235 5236 case DBGCVAR_TYPE_STRING:5237 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, pResult);5238 5239 case DBGCVAR_TYPE_UNKNOWN:5240 default:5241 return VERR_PARSE_INCORRECT_ARG_TYPE;5242 }5243 }5244 5245 5246 /**5247 * Physical address (unary).5248 *5249 * @returns 0 on success.5250 * @returns VBox evaluation / parsing error code on failure.5251 * The caller does the bitching.5252 * @param pDbgc Debugger console instance data.5253 * @param pArg The argument.5254 * @param pResult Where to store the result.5255 */5256 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5257 {5258 // LogFlow(("dbgcOpAddrPhys\n"));5259 int rc;5260 5261 *pResult = *pArg;5262 switch (pArg->enmType)5263 {5264 case DBGCVAR_TYPE_GC_FLAT:5265 Assert(pDbgc->pVM);5266 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;5267 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.GCPhys);5268 if (VBOX_SUCCESS(rc))5269 return 0;5270 /** @todo more memory types! */5271 return VERR_PARSE_CONVERSION_FAILED;5272 5273 case DBGCVAR_TYPE_GC_FAR:5274 {5275 Assert(pDbgc->pVM);5276 DBGFADDRESS Address;5277 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);5278 if (VBOX_SUCCESS(rc))5279 {5280 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;5281 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.GCPhys);5282 if (VBOX_SUCCESS(rc))5283 return 0;5284 /** @todo more memory types! */5285 }5286 return VERR_PARSE_CONVERSION_FAILED;5287 }5288 5289 case DBGCVAR_TYPE_GC_PHYS:5290 return 0;5291 5292 case DBGCVAR_TYPE_HC_FLAT:5293 Assert(pDbgc->pVM);5294 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;5295 rc = PGMR3DbgHCPtr2GCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.GCPhys);5296 if (VBOX_SUCCESS(rc))5297 return 0;5298 /** @todo more memory types! */5299 return VERR_PARSE_CONVERSION_FAILED;5300 5301 case DBGCVAR_TYPE_HC_FAR:5302 return VERR_PARSE_INCORRECT_ARG_TYPE;5303 5304 case DBGCVAR_TYPE_HC_PHYS:5305 return 0;5306 5307 case DBGCVAR_TYPE_NUMBER:5308 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;5309 pResult->u.GCPhys = (RTGCPHYS)pResult->u.u64Number;5310 return 0;5311 5312 case DBGCVAR_TYPE_STRING:5313 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_PHYS, pResult);5314 5315 case DBGCVAR_TYPE_UNKNOWN:5316 default:5317 return VERR_PARSE_INCORRECT_ARG_TYPE;5318 }5319 return 0;5320 }5321 5322 5323 /**5324 * Physical host address (unary).5325 *5326 * @returns 0 on success.5327 * @returns VBox evaluation / parsing error code on failure.5328 * The caller does the bitching.5329 * @param pDbgc Debugger console instance data.5330 * @param pArg The argument.5331 * @param pResult Where to store the result.5332 */5333 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5334 {5335 // LogFlow(("dbgcOpAddrPhys\n"));5336 int rc;5337 5338 *pResult = *pArg;5339 switch (pArg->enmType)5340 {5341 case DBGCVAR_TYPE_GC_FLAT:5342 Assert(pDbgc->pVM);5343 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5344 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);5345 if (VBOX_SUCCESS(rc))5346 return 0;5347 /** @todo more memory types. */5348 return VERR_PARSE_CONVERSION_FAILED;5349 5350 case DBGCVAR_TYPE_GC_FAR:5351 {5352 Assert(pDbgc->pVM);5353 DBGFADDRESS Address;5354 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);5355 if (VBOX_SUCCESS(rc))5356 {5357 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5358 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.HCPhys);5359 if (VBOX_SUCCESS(rc))5360 return 0;5361 /** @todo more memory types. */5362 }5363 return VERR_PARSE_CONVERSION_FAILED;5364 }5365 5366 case DBGCVAR_TYPE_GC_PHYS:5367 Assert(pDbgc->pVM);5368 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5369 rc = PGMPhysGCPhys2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);5370 if (VBOX_SUCCESS(rc))5371 return 0;5372 return VERR_PARSE_CONVERSION_FAILED;5373 5374 case DBGCVAR_TYPE_HC_FLAT:5375 Assert(pDbgc->pVM);5376 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5377 rc = PGMR3DbgHCPtr2HCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.HCPhys);5378 if (VBOX_SUCCESS(rc))5379 return 0;5380 /** @todo more memory types! */5381 return VERR_PARSE_CONVERSION_FAILED;5382 5383 case DBGCVAR_TYPE_HC_FAR:5384 return VERR_PARSE_INCORRECT_ARG_TYPE;5385 5386 case DBGCVAR_TYPE_HC_PHYS:5387 return 0;5388 5389 case DBGCVAR_TYPE_NUMBER:5390 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5391 pResult->u.HCPhys = (RTGCPHYS)pResult->u.u64Number;5392 return 0;5393 5394 case DBGCVAR_TYPE_STRING:5395 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_PHYS, pResult);5396 5397 case DBGCVAR_TYPE_UNKNOWN:5398 default:5399 return VERR_PARSE_INCORRECT_ARG_TYPE;5400 }5401 return 0;5402 }5403 5404 5405 /**5406 * Host address (unary).5407 *5408 * @returns 0 on success.5409 * @returns VBox evaluation / parsing error code on failure.5410 * The caller does the bitching.5411 * @param pDbgc Debugger console instance data.5412 * @param pArg The argument.5413 * @param pResult Where to store the result.5414 */5415 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5416 {5417 // LogFlow(("dbgcOpAddrHost\n"));5418 int rc;5419 5420 *pResult = *pArg;5421 switch (pArg->enmType)5422 {5423 case DBGCVAR_TYPE_GC_FLAT:5424 Assert(pDbgc->pVM);5425 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;5426 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.pvHCFlat);5427 if (VBOX_SUCCESS(rc))5428 return 0;5429 /** @todo more memory types. */5430 return VERR_PARSE_CONVERSION_FAILED;5431 5432 case DBGCVAR_TYPE_GC_FAR:5433 {5434 Assert(pDbgc->pVM);5435 DBGFADDRESS Address;5436 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);5437 if (VBOX_SUCCESS(rc))5438 {5439 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;5440 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, Address.FlatPtr, &pResult->u.pvHCFlat);5441 if (VBOX_SUCCESS(rc))5442 return 0;5443 /** @todo more memory types. */5444 }5445 return VERR_PARSE_CONVERSION_FAILED;5446 }5447 5448 case DBGCVAR_TYPE_GC_PHYS:5449 Assert(pDbgc->pVM);5450 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;5451 rc = PGMPhysGCPhys2HCPtr(pDbgc->pVM, pArg->u.GCPhys, 1, &pResult->u.pvHCFlat);5452 if (VBOX_SUCCESS(rc))5453 return 0;5454 return VERR_PARSE_CONVERSION_FAILED;5455 5456 case DBGCVAR_TYPE_HC_FLAT:5457 return 0;5458 5459 case DBGCVAR_TYPE_HC_FAR:5460 case DBGCVAR_TYPE_HC_PHYS:5461 /** @todo !*/5462 return VERR_PARSE_CONVERSION_FAILED;5463 5464 case DBGCVAR_TYPE_NUMBER:5465 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;5466 pResult->u.pvHCFlat = (void *)(uintptr_t)pResult->u.u64Number;5467 return 0;5468 5469 case DBGCVAR_TYPE_STRING:5470 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_FLAT, pResult);5471 5472 case DBGCVAR_TYPE_UNKNOWN:5473 default:5474 return VERR_PARSE_INCORRECT_ARG_TYPE;5475 }5476 }5477 5478 /**5479 * Bitwise not (unary).5480 *5481 * @returns 0 on success.5482 * @returns VBox evaluation / parsing error code on failure.5483 * The caller does the bitching.5484 * @param pDbgc Debugger console instance data.5485 * @param pArg The argument.5486 * @param pResult Where to store the result.5487 */5488 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5489 {5490 // LogFlow(("dbgcOpAddrFar\n"));5491 int rc;5492 5493 switch (pArg1->enmType)5494 {5495 case DBGCVAR_TYPE_STRING:5496 rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);5497 if (VBOX_FAILURE(rc))5498 return rc;5499 break;5500 case DBGCVAR_TYPE_NUMBER:5501 *pResult = *pArg1;5502 break;5503 5504 case DBGCVAR_TYPE_GC_FLAT:5505 case DBGCVAR_TYPE_GC_FAR:5506 case DBGCVAR_TYPE_GC_PHYS:5507 case DBGCVAR_TYPE_HC_FLAT:5508 case DBGCVAR_TYPE_HC_FAR:5509 case DBGCVAR_TYPE_HC_PHYS:5510 case DBGCVAR_TYPE_UNKNOWN:5511 default:5512 return VERR_PARSE_INCORRECT_ARG_TYPE;5513 }5514 pResult->u.GCFar.sel = (RTSEL)pResult->u.u64Number;5515 5516 /* common code for the two types we support. */5517 switch (pArg2->enmType)5518 {5519 case DBGCVAR_TYPE_GC_FLAT:5520 pResult->u.GCFar.off = pArg2->u.GCFlat;5521 pResult->enmType = DBGCVAR_TYPE_GC_FAR;5522 break;5523 5524 case DBGCVAR_TYPE_HC_FLAT:5525 pResult->u.HCFar.off = pArg2->u.GCFlat;5526 pResult->enmType = DBGCVAR_TYPE_GC_FAR;5527 break;5528 5529 case DBGCVAR_TYPE_NUMBER:5530 pResult->u.GCFar.off = (RTGCPTR)pArg2->u.u64Number;5531 pResult->enmType = DBGCVAR_TYPE_GC_FAR;5532 break;5533 5534 case DBGCVAR_TYPE_STRING:5535 {5536 DBGCVAR Var;5537 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);5538 if (VBOX_FAILURE(rc))5539 return rc;5540 pResult->u.GCFar.off = (RTGCPTR)Var.u.u64Number;5541 pResult->enmType = DBGCVAR_TYPE_GC_FAR;5542 break;5543 }5544 5545 case DBGCVAR_TYPE_GC_FAR:5546 case DBGCVAR_TYPE_GC_PHYS:5547 case DBGCVAR_TYPE_HC_FAR:5548 case DBGCVAR_TYPE_HC_PHYS:5549 case DBGCVAR_TYPE_UNKNOWN:5550 default:5551 return VERR_PARSE_INCORRECT_ARG_TYPE;5552 }5553 return 0;5554 5555 }5556 5557 5558 /**5559 * Multiplication operator (binary).5560 *5561 * @returns 0 on success.5562 * @returns VBox evaluation / parsing error code on failure.5563 * The caller does the bitching.5564 * @param pDbgc Debugger console instance data.5565 * @param pArg1 The first argument.5566 * @param pArg2 The 2nd argument.5567 * @param pResult Where to store the result.5568 */5569 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5570 {5571 // LogFlow(("dbgcOpMult\n"));5572 int rc;5573 5574 /*5575 * Switch the factors so we preserve pointers, far pointers are considered more5576 * important that physical and flat pointers.5577 */5578 if ( DBGCVAR_ISPOINTER(pArg2->enmType)5579 && ( !DBGCVAR_ISPOINTER(pArg1->enmType)5580 || ( DBGCVAR_IS_FAR_PTR(pArg2->enmType)5581 && !DBGCVAR_IS_FAR_PTR(pArg1->enmType))))5582 {5583 PCDBGCVAR pTmp = pArg1;5584 pArg2 = pArg1;5585 pArg1 = pTmp;5586 }5587 5588 /*5589 * Convert the 2nd number into a number we use multiply the first with.5590 */5591 DBGCVAR Factor2 = *pArg2;5592 if ( Factor2.enmType == DBGCVAR_TYPE_STRING5593 || Factor2.enmType == DBGCVAR_TYPE_SYMBOL)5594 {5595 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Factor2);5596 if (VBOX_FAILURE(rc))5597 return rc;5598 }5599 uint64_t u64Factor;5600 switch (Factor2.enmType)5601 {5602 case DBGCVAR_TYPE_GC_FLAT: u64Factor = Factor2.u.GCFlat; break;5603 case DBGCVAR_TYPE_GC_FAR: u64Factor = Factor2.u.GCFar.off; break;5604 case DBGCVAR_TYPE_GC_PHYS: u64Factor = Factor2.u.GCPhys; break;5605 case DBGCVAR_TYPE_HC_FLAT: u64Factor = (uintptr_t)Factor2.u.pvHCFlat; break;5606 case DBGCVAR_TYPE_HC_FAR: u64Factor = Factor2.u.HCFar.off; break;5607 case DBGCVAR_TYPE_HC_PHYS: u64Factor = Factor2.u.HCPhys; break;5608 case DBGCVAR_TYPE_NUMBER: u64Factor = Factor2.u.u64Number; break;5609 default:5610 return VERR_PARSE_INCORRECT_ARG_TYPE;5611 }5612 5613 /*5614 * Fix symbols in the 1st factor.5615 */5616 *pResult = *pArg1;5617 if ( pResult->enmType == DBGCVAR_TYPE_STRING5618 || pResult->enmType == DBGCVAR_TYPE_SYMBOL)5619 {5620 rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);5621 if (VBOX_FAILURE(rc))5622 return rc;5623 }5624 5625 /*5626 * Do the multiplication.5627 */5628 switch (pArg1->enmType)5629 {5630 case DBGCVAR_TYPE_GC_FLAT: pResult->u.GCFlat *= u64Factor; break;5631 case DBGCVAR_TYPE_GC_FAR: pResult->u.GCFar.off *= u64Factor; break;5632 case DBGCVAR_TYPE_GC_PHYS: pResult->u.GCPhys *= u64Factor; break;5633 case DBGCVAR_TYPE_HC_FLAT:5634 pResult->u.pvHCFlat = (void *)(uintptr_t)((uintptr_t)pResult->u.pvHCFlat * u64Factor);5635 break;5636 case DBGCVAR_TYPE_HC_FAR: pResult->u.HCFar.off *= u64Factor; break;5637 case DBGCVAR_TYPE_HC_PHYS: pResult->u.HCPhys *= u64Factor; break;5638 case DBGCVAR_TYPE_NUMBER: pResult->u.u64Number *= u64Factor; break;5639 default:5640 return VERR_PARSE_INCORRECT_ARG_TYPE;5641 }5642 return 0;5643 }5644 5645 5646 /**5647 * Division operator (binary).5648 *5649 * @returns 0 on success.5650 * @returns VBox evaluation / parsing error code on failure.5651 * The caller does the bitching.5652 * @param pDbgc Debugger console instance data.5653 * @param pArg1 The first argument.5654 * @param pArg2 The 2nd argument.5655 * @param pResult Where to store the result.5656 */5657 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5658 {5659 LogFlow(("dbgcOpDiv\n"));5660 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5661 return -1;5662 }5663 5664 5665 /**5666 * Modulus operator (binary).5667 *5668 * @returns 0 on success.5669 * @returns VBox evaluation / parsing error code on failure.5670 * The caller does the bitching.5671 * @param pDbgc Debugger console instance data.5672 * @param pArg1 The first argument.5673 * @param pArg2 The 2nd argument.5674 * @param pResult Where to store the result.5675 */5676 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5677 {5678 LogFlow(("dbgcOpMod\n"));5679 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5680 return -1;5681 }5682 5683 5684 /**5685 * Addition operator (binary).5686 *5687 * @returns 0 on success.5688 * @returns VBox evaluation / parsing error code on failure.5689 * The caller does the bitching.5690 * @param pDbgc Debugger console instance data.5691 * @param pArg1 The first argument.5692 * @param pArg2 The 2nd argument.5693 * @param pResult Where to store the result.5694 */5695 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5696 {5697 // LogFlow(("dbgcOpAdd\n"));5698 5699 /*5700 * An addition operation will return (when possible) the left side type in the5701 * expression. We make an omission for numbers, where we'll take the right side5702 * type instead. An expression where only the left hand side is a string we'll5703 * use the right hand type assuming that the string is a symbol.5704 */5705 if ( (pArg1->enmType == DBGCVAR_TYPE_NUMBER && pArg2->enmType != DBGCVAR_TYPE_STRING)5706 || (pArg1->enmType == DBGCVAR_TYPE_STRING && pArg2->enmType != DBGCVAR_TYPE_STRING))5707 {5708 PCDBGCVAR pTmp = pArg2;5709 pArg2 = pArg1;5710 pArg1 = pTmp;5711 }5712 DBGCVAR Sym1, Sym2;5713 if (pArg1->enmType == DBGCVAR_TYPE_STRING)5714 {5715 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);5716 if (VBOX_FAILURE(rc))5717 return rc;5718 pArg1 = &Sym1;5719 5720 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);5721 if (VBOX_FAILURE(rc))5722 return rc;5723 pArg2 = &Sym2;5724 }5725 5726 int rc;5727 DBGCVAR Var;5728 DBGCVAR Var2;5729 switch (pArg1->enmType)5730 {5731 /*5732 * GC Flat5733 */5734 case DBGCVAR_TYPE_GC_FLAT:5735 switch (pArg2->enmType)5736 {5737 case DBGCVAR_TYPE_HC_FLAT:5738 case DBGCVAR_TYPE_HC_FAR:5739 case DBGCVAR_TYPE_HC_PHYS:5740 return VERR_PARSE_INVALID_OPERATION;5741 default:5742 *pResult = *pArg1;5743 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);5744 if (VBOX_FAILURE(rc))5745 return rc;5746 pResult->u.GCFlat += pArg2->u.GCFlat;5747 break;5748 }5749 break;5750 5751 /*5752 * GC Far5753 */5754 case DBGCVAR_TYPE_GC_FAR:5755 switch (pArg2->enmType)5756 {5757 case DBGCVAR_TYPE_HC_FLAT:5758 case DBGCVAR_TYPE_HC_FAR:5759 case DBGCVAR_TYPE_HC_PHYS:5760 return VERR_PARSE_INVALID_OPERATION;5761 case DBGCVAR_TYPE_NUMBER:5762 *pResult = *pArg1;5763 pResult->u.GCFar.off += (RTGCPTR)pArg2->u.u64Number;5764 break;5765 default:5766 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);5767 if (VBOX_FAILURE(rc))5768 return rc;5769 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);5770 if (VBOX_FAILURE(rc))5771 return rc;5772 pResult->u.GCFlat += pArg2->u.GCFlat;5773 break;5774 }5775 break;5776 5777 /*5778 * GC Phys5779 */5780 case DBGCVAR_TYPE_GC_PHYS:5781 switch (pArg2->enmType)5782 {5783 case DBGCVAR_TYPE_HC_FLAT:5784 case DBGCVAR_TYPE_HC_FAR:5785 case DBGCVAR_TYPE_HC_PHYS:5786 return VERR_PARSE_INVALID_OPERATION;5787 default:5788 *pResult = *pArg1;5789 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);5790 if (VBOX_FAILURE(rc))5791 return rc;5792 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)5793 return VERR_PARSE_INVALID_OPERATION;5794 pResult->u.GCPhys += Var.u.GCPhys;5795 break;5796 }5797 break;5798 5799 /*5800 * HC Flat5801 */5802 case DBGCVAR_TYPE_HC_FLAT:5803 *pResult = *pArg1;5804 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);5805 if (VBOX_FAILURE(rc))5806 return rc;5807 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);5808 if (VBOX_FAILURE(rc))5809 return rc;5810 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;5811 break;5812 5813 /*5814 * HC Far5815 */5816 case DBGCVAR_TYPE_HC_FAR:5817 switch (pArg2->enmType)5818 {5819 case DBGCVAR_TYPE_NUMBER:5820 *pResult = *pArg1;5821 pResult->u.HCFar.off += (uintptr_t)pArg2->u.u64Number;5822 break;5823 5824 default:5825 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);5826 if (VBOX_FAILURE(rc))5827 return rc;5828 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);5829 if (VBOX_FAILURE(rc))5830 return rc;5831 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);5832 if (VBOX_FAILURE(rc))5833 return rc;5834 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;5835 break;5836 }5837 break;5838 5839 /*5840 * HC Phys5841 */5842 case DBGCVAR_TYPE_HC_PHYS:5843 *pResult = *pArg1;5844 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);5845 if (VBOX_FAILURE(rc))5846 return rc;5847 pResult->u.HCPhys += Var.u.HCPhys;5848 break;5849 5850 /*5851 * Numbers (see start of function)5852 */5853 case DBGCVAR_TYPE_NUMBER:5854 *pResult = *pArg1;5855 switch (pArg2->enmType)5856 {5857 case DBGCVAR_TYPE_SYMBOL:5858 case DBGCVAR_TYPE_STRING:5859 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);5860 if (VBOX_FAILURE(rc))5861 return rc;5862 case DBGCVAR_TYPE_NUMBER:5863 pResult->u.u64Number += pArg2->u.u64Number;5864 break;5865 default:5866 return VERR_PARSE_INVALID_OPERATION;5867 }5868 break;5869 5870 default:5871 return VERR_PARSE_INVALID_OPERATION;5872 5873 }5874 return 0;5875 }5876 5877 5878 /**5879 * Subtration operator (binary).5880 *5881 * @returns 0 on success.5882 * @returns VBox evaluation / parsing error code on failure.5883 * The caller does the bitching.5884 * @param pDbgc Debugger console instance data.5885 * @param pArg1 The first argument.5886 * @param pArg2 The 2nd argument.5887 * @param pResult Where to store the result.5888 */5889 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5890 {5891 // LogFlow(("dbgcOpSub\n"));5892 5893 /*5894 * An subtraction operation will return the left side type in the expression.5895 * However, if the left hand side is a number and the right hand a pointer of5896 * some kind we'll convert the left hand side to the same type as the right hand.5897 * Any strings will be attempted resolved as symbols.5898 */5899 DBGCVAR Sym1, Sym2;5900 if ( pArg2->enmType == DBGCVAR_TYPE_STRING5901 && ( pArg1->enmType == DBGCVAR_TYPE_NUMBER5902 || pArg1->enmType == DBGCVAR_TYPE_STRING))5903 {5904 int rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);5905 if (VBOX_FAILURE(rc))5906 return rc;5907 pArg2 = &Sym2;5908 }5909 5910 if (pArg1->enmType == DBGCVAR_TYPE_STRING)5911 {5912 DBGCVARTYPE enmType;5913 switch (pArg2->enmType)5914 {5915 case DBGCVAR_TYPE_NUMBER:5916 enmType = DBGCVAR_TYPE_ANY;5917 break;5918 case DBGCVAR_TYPE_GC_FLAT:5919 case DBGCVAR_TYPE_GC_PHYS:5920 case DBGCVAR_TYPE_HC_FLAT:5921 case DBGCVAR_TYPE_HC_PHYS:5922 enmType = pArg2->enmType;5923 break;5924 case DBGCVAR_TYPE_GC_FAR:5925 enmType = DBGCVAR_TYPE_GC_FLAT;5926 break;5927 case DBGCVAR_TYPE_HC_FAR:5928 enmType = DBGCVAR_TYPE_HC_FLAT;5929 break;5930 5931 default:5932 case DBGCVAR_TYPE_STRING:5933 AssertMsgFailed(("Can't happen\n"));5934 enmType = DBGCVAR_TYPE_STRING;5935 break;5936 }5937 if (enmType != DBGCVAR_TYPE_STRING)5938 {5939 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);5940 if (VBOX_FAILURE(rc))5941 return rc;5942 pArg1 = &Sym1;5943 }5944 }5945 else if (pArg1->enmType == DBGCVAR_TYPE_NUMBER)5946 {5947 PFNDBGCOPUNARY pOp = NULL;5948 switch (pArg2->enmType)5949 {5950 case DBGCVAR_TYPE_GC_FAR:5951 case DBGCVAR_TYPE_GC_FLAT:5952 pOp = dbgcOpAddrFlat;5953 break;5954 case DBGCVAR_TYPE_GC_PHYS:5955 pOp = dbgcOpAddrPhys;5956 break;5957 case DBGCVAR_TYPE_HC_FAR:5958 case DBGCVAR_TYPE_HC_FLAT:5959 pOp = dbgcOpAddrHost;5960 break;5961 case DBGCVAR_TYPE_HC_PHYS:5962 pOp = dbgcOpAddrHostPhys;5963 break;5964 case DBGCVAR_TYPE_NUMBER:5965 break;5966 default:5967 case DBGCVAR_TYPE_STRING:5968 AssertMsgFailed(("Can't happen\n"));5969 break;5970 }5971 if (pOp)5972 {5973 int rc = pOp(pDbgc, pArg1, &Sym1);5974 if (VBOX_FAILURE(rc))5975 return rc;5976 pArg1 = &Sym1;5977 }5978 }5979 5980 5981 /*5982 * Normal processing.5983 */5984 int rc;5985 DBGCVAR Var;5986 DBGCVAR Var2;5987 switch (pArg1->enmType)5988 {5989 /*5990 * GC Flat5991 */5992 case DBGCVAR_TYPE_GC_FLAT:5993 switch (pArg2->enmType)5994 {5995 case DBGCVAR_TYPE_HC_FLAT:5996 case DBGCVAR_TYPE_HC_FAR:5997 case DBGCVAR_TYPE_HC_PHYS:5998 return VERR_PARSE_INVALID_OPERATION;5999 default:6000 *pResult = *pArg1;6001 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);6002 if (VBOX_FAILURE(rc))6003 return rc;6004 pResult->u.GCFlat -= pArg2->u.GCFlat;6005 break;6006 }6007 break;6008 6009 /*6010 * GC Far6011 */6012 case DBGCVAR_TYPE_GC_FAR:6013 switch (pArg2->enmType)6014 {6015 case DBGCVAR_TYPE_HC_FLAT:6016 case DBGCVAR_TYPE_HC_FAR:6017 case DBGCVAR_TYPE_HC_PHYS:6018 return VERR_PARSE_INVALID_OPERATION;6019 case DBGCVAR_TYPE_NUMBER:6020 *pResult = *pArg1;6021 pResult->u.GCFar.off -= (RTGCPTR)pArg2->u.u64Number;6022 break;6023 default:6024 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);6025 if (VBOX_FAILURE(rc))6026 return rc;6027 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);6028 if (VBOX_FAILURE(rc))6029 return rc;6030 pResult->u.GCFlat -= pArg2->u.GCFlat;6031 break;6032 }6033 break;6034 6035 /*6036 * GC Phys6037 */6038 case DBGCVAR_TYPE_GC_PHYS:6039 switch (pArg2->enmType)6040 {6041 case DBGCVAR_TYPE_HC_FLAT:6042 case DBGCVAR_TYPE_HC_FAR:6043 case DBGCVAR_TYPE_HC_PHYS:6044 return VERR_PARSE_INVALID_OPERATION;6045 default:6046 *pResult = *pArg1;6047 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);6048 if (VBOX_FAILURE(rc))6049 return rc;6050 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)6051 return VERR_PARSE_INVALID_OPERATION;6052 pResult->u.GCPhys -= Var.u.GCPhys;6053 break;6054 }6055 break;6056 6057 /*6058 * HC Flat6059 */6060 case DBGCVAR_TYPE_HC_FLAT:6061 *pResult = *pArg1;6062 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);6063 if (VBOX_FAILURE(rc))6064 return rc;6065 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);6066 if (VBOX_FAILURE(rc))6067 return rc;6068 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;6069 break;6070 6071 /*6072 * HC Far6073 */6074 case DBGCVAR_TYPE_HC_FAR:6075 switch (pArg2->enmType)6076 {6077 case DBGCVAR_TYPE_NUMBER:6078 *pResult = *pArg1;6079 pResult->u.HCFar.off -= (uintptr_t)pArg2->u.u64Number;6080 break;6081 6082 default:6083 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);6084 if (VBOX_FAILURE(rc))6085 return rc;6086 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);6087 if (VBOX_FAILURE(rc))6088 return rc;6089 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);6090 if (VBOX_FAILURE(rc))6091 return rc;6092 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;6093 break;6094 }6095 break;6096 6097 /*6098 * HC Phys6099 */6100 case DBGCVAR_TYPE_HC_PHYS:6101 *pResult = *pArg1;6102 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);6103 if (VBOX_FAILURE(rc))6104 return rc;6105 pResult->u.HCPhys -= Var.u.HCPhys;6106 break;6107 6108 /*6109 * Numbers (see start of function)6110 */6111 case DBGCVAR_TYPE_NUMBER:6112 *pResult = *pArg1;6113 switch (pArg2->enmType)6114 {6115 case DBGCVAR_TYPE_SYMBOL:6116 case DBGCVAR_TYPE_STRING:6117 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);6118 if (VBOX_FAILURE(rc))6119 return rc;6120 case DBGCVAR_TYPE_NUMBER:6121 pResult->u.u64Number -= pArg2->u.u64Number;6122 break;6123 default:6124 return VERR_PARSE_INVALID_OPERATION;6125 }6126 break;6127 6128 default:6129 return VERR_PARSE_INVALID_OPERATION;6130 6131 }6132 return 0;6133 }6134 6135 6136 /**6137 * Bitwise shift left operator (binary).6138 *6139 * @returns 0 on success.6140 * @returns VBox evaluation / parsing error code on failure.6141 * The caller does the bitching.6142 * @param pDbgc Debugger console instance data.6143 * @param pArg1 The first argument.6144 * @param pArg2 The 2nd argument.6145 * @param pResult Where to store the result.6146 */6147 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6148 {6149 LogFlow(("dbgcOpBitwiseShiftLeft\n"));6150 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);6151 return -1;6152 }6153 6154 6155 /**6156 * Bitwise shift right operator (binary).6157 *6158 * @returns 0 on success.6159 * @returns VBox evaluation / parsing error code on failure.6160 * The caller does the bitching.6161 * @param pDbgc Debugger console instance data.6162 * @param pArg1 The first argument.6163 * @param pArg2 The 2nd argument.6164 * @param pResult Where to store the result.6165 */6166 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6167 {6168 LogFlow(("dbgcOpBitwiseShiftRight\n"));6169 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);6170 return -1;6171 }6172 6173 6174 /**6175 * Bitwise and operator (binary).6176 *6177 * @returns 0 on success.6178 * @returns VBox evaluation / parsing error code on failure.6179 * The caller does the bitching.6180 * @param pDbgc Debugger console instance data.6181 * @param pArg1 The first argument.6182 * @param pArg2 The 2nd argument.6183 * @param pResult Where to store the result.6184 */6185 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6186 {6187 LogFlow(("dbgcOpBitwiseAnd\n"));6188 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);6189 return -1;6190 }6191 6192 6193 /**6194 * Bitwise exclusive or operator (binary).6195 *6196 * @returns 0 on success.6197 * @returns VBox evaluation / parsing error code on failure.6198 * The caller does the bitching.6199 * @param pDbgc Debugger console instance data.6200 * @param pArg1 The first argument.6201 * @param pArg2 The 2nd argument.6202 * @param pResult Where to store the result.6203 */6204 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6205 {6206 LogFlow(("dbgcOpBitwiseXor\n"));6207 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);6208 return -1;6209 }6210 6211 6212 /**6213 * Bitwise inclusive or operator (binary).6214 *6215 * @returns 0 on success.6216 * @returns VBox evaluation / parsing error code on failure.6217 * The caller does the bitching.6218 * @param pDbgc Debugger console instance data.6219 * @param pArg1 The first argument.6220 * @param pArg2 The 2nd argument.6221 * @param pResult Where to store the result.6222 */6223 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6224 {6225 LogFlow(("dbgcOpBitwiseOr\n"));6226 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);6227 return -1;6228 }6229 6230 6231 /**6232 * Boolean and operator (binary).6233 *6234 * @returns 0 on success.6235 * @returns VBox evaluation / parsing error code on failure.6236 * The caller does the bitching.6237 * @param pDbgc Debugger console instance data.6238 * @param pArg1 The first argument.6239 * @param pArg2 The 2nd argument.6240 * @param pResult Where to store the result.6241 */6242 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6243 {6244 LogFlow(("dbgcOpBooleanAnd\n"));6245 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);6246 return -1;6247 }6248 6249 6250 /**6251 * Boolean or operator (binary).6252 *6253 * @returns 0 on success.6254 * @returns VBox evaluation / parsing error code on failure.6255 * The caller does the bitching.6256 * @param pDbgc Debugger console instance data.6257 * @param pArg1 The first argument.6258 * @param pArg2 The 2nd argument.6259 * @param pResult Where to store the result.6260 */6261 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6262 {6263 LogFlow(("dbgcOpBooleanOr\n"));6264 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);6265 return -1;6266 }6267 6268 6269 /**6270 * Range to operator (binary).6271 *6272 * @returns 0 on success.6273 * @returns VBox evaluation / parsing error code on failure.6274 * The caller does the bitching.6275 * @param pDbgc Debugger console instance data.6276 * @param pArg1 The first argument.6277 * @param pArg2 The 2nd argument.6278 * @param pResult Where to store the result.6279 */6280 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6281 {6282 // LogFlow(("dbgcOpRangeLength\n"));6283 /*6284 * Make result. Strings needs to be resolved into symbols.6285 */6286 if (pArg1->enmType == DBGCVAR_TYPE_STRING)6287 {6288 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);6289 if (VBOX_FAILURE(rc))6290 return rc;6291 }6292 else6293 *pResult = *pArg1;6294 6295 /*6296 * Convert 2nd argument to element count.6297 */6298 pResult->enmRangeType = DBGCVAR_RANGE_ELEMENTS;6299 switch (pArg2->enmType)6300 {6301 case DBGCVAR_TYPE_NUMBER:6302 pResult->u64Range = pArg2->u.u64Number;6303 break;6304 6305 case DBGCVAR_TYPE_STRING:6306 {6307 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);6308 if (VBOX_FAILURE(rc))6309 return rc;6310 pResult->u64Range = pArg2->u.u64Number;6311 break;6312 }6313 6314 default:6315 return VERR_PARSE_INVALID_OPERATION;6316 }6317 6318 return VINF_SUCCESS;6319 }6320 6321 6322 /**6323 * Range to operator (binary).6324 *6325 * @returns 0 on success.6326 * @returns VBox evaluation / parsing error code on failure.6327 * The caller does the bitching.6328 * @param pDbgc Debugger console instance data.6329 * @param pArg1 The first argument.6330 * @param pArg2 The 2nd argument.6331 * @param pResult Where to store the result.6332 */6333 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6334 {6335 // LogFlow(("dbgcOpRangeLengthBytes\n"));6336 int rc = dbgcOpRangeLength(pDbgc, pArg1, pArg2, pResult);6337 if (VBOX_SUCCESS(rc))6338 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;6339 return rc;6340 }6341 6342 6343 /**6344 * Range to operator (binary).6345 *6346 * @returns 0 on success.6347 * @returns VBox evaluation / parsing error code on failure.6348 * The caller does the bitching.6349 * @param pDbgc Debugger console instance data.6350 * @param pArg1 The first argument.6351 * @param pArg2 The 2nd argument.6352 * @param pResult Where to store the result.6353 */6354 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6355 {6356 // LogFlow(("dbgcOpRangeTo\n"));6357 /*6358 * Calc number of bytes between the two args.6359 */6360 DBGCVAR Diff;6361 int rc = dbgcOpSub(pDbgc, pArg2, pArg1, &Diff);6362 if (VBOX_FAILURE(rc))6363 return rc;6364 6365 /*6366 * Use the diff as the range of Arg1.6367 */6368 *pResult = *pArg1;6369 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;6370 switch (Diff.enmType)6371 {6372 case DBGCVAR_TYPE_GC_FLAT:6373 pResult->u64Range = (RTGCUINTPTR)Diff.u.GCFlat;6374 break;6375 case DBGCVAR_TYPE_GC_PHYS:6376 pResult->u64Range = Diff.u.GCPhys;6377 break;6378 case DBGCVAR_TYPE_HC_FLAT:6379 pResult->u64Range = (uintptr_t)Diff.u.pvHCFlat;6380 break;6381 case DBGCVAR_TYPE_HC_PHYS:6382 pResult->u64Range = Diff.u.HCPhys;6383 break;6384 case DBGCVAR_TYPE_NUMBER:6385 pResult->u64Range = Diff.u.u64Number;6386 break;6387 6388 case DBGCVAR_TYPE_GC_FAR:6389 case DBGCVAR_TYPE_STRING:6390 case DBGCVAR_TYPE_HC_FAR:6391 default:6392 AssertMsgFailed(("Impossible!\n"));6393 return VERR_PARSE_INVALID_OPERATION;6394 }6395 6396 return 0;6397 }6398 6399 6400 6401 6402 6403 /**6404 * Output callback.6405 *6406 * @returns number of bytes written.6407 * @param pvArg User argument.6408 * @param pachChars Pointer to an array of utf-8 characters.6409 * @param cbChars Number of bytes in the character array pointed to by pachChars.6410 */6411 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)6412 {6413 PDBGC pDbgc = (PDBGC)pvArg;6414 if (cbChars)6415 {6416 int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);6417 if (VBOX_FAILURE(rc))6418 {6419 pDbgc->rcOutput = rc;6420 cbChars = 0;6421 }6422 }6423 6424 return cbChars;6425 }6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//6436 //6437 //6438 // C a l l b a c k H e l p e r s6439 //6440 //6441 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//6442 6443 6444 6445 /**6446 * Command helper for writing text to the debug console.6447 *6448 * @returns VBox status.6449 * @param pCmdHlp Pointer to the command callback structure.6450 * @param pvBuf What to write.6451 * @param cbBuf Number of bytes to write.6452 * @param pcbWritten Where to store the number of bytes actually written.6453 * If NULL the entire buffer must be successfully written.6454 */6455 static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)6456 {6457 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6458 return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);6459 }6460 6461 6462 /**6463 * Command helper for writing formatted text to the debug console.6464 *6465 * @returns VBox status.6466 * @param pCmdHlp Pointer to the command callback structure.6467 * @param pcb Where to store the number of bytes written.6468 * @param pszFormat The format string.6469 * This is using the log formatter, so it's format extensions can be used.6470 * @param ... Arguments specified in the format string.6471 */6472 static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)6473 {6474 /*6475 * Do the formatting and output.6476 */6477 va_list args;6478 va_start(args, pszFormat);6479 int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);6480 va_end(args);6481 6482 return rc;6483 }6484 6485 /**6486 * Callback to format non-standard format specifiers.6487 *6488 * @returns The number of bytes formatted.6489 * @param pvArg Formatter argument.6490 * @param pfnOutput Pointer to output function.6491 * @param pvArgOutput Argument for the output function.6492 * @param ppszFormat Pointer to the format string pointer. Advance this till the char6493 * after the format specifier.6494 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.6495 * @param cchWidth Format Width. -1 if not specified.6496 * @param cchPrecision Format Precision. -1 if not specified.6497 * @param fFlags Flags (RTSTR_NTFS_*).6498 * @param chArgSize The argument size specifier, 'l' or 'L'.6499 */6500 static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,6501 const char **ppszFormat, va_list *pArgs, int cchWidth,6502 int cchPrecision, unsigned fFlags, char chArgSize)6503 {6504 NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);6505 if (**ppszFormat != 'D')6506 {6507 (*ppszFormat)++;6508 return 0;6509 }6510 6511 (*ppszFormat)++;6512 switch (**ppszFormat)6513 {6514 /*6515 * Print variable without range.6516 * The argument is a const pointer to the variable.6517 */6518 case 'V':6519 {6520 (*ppszFormat)++;6521 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);6522 switch (pVar->enmType)6523 {6524 case DBGCVAR_TYPE_GC_FLAT:6525 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);6526 case DBGCVAR_TYPE_GC_FAR:6527 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);6528 case DBGCVAR_TYPE_GC_PHYS:6529 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);6530 case DBGCVAR_TYPE_HC_FLAT:6531 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);6532 case DBGCVAR_TYPE_HC_FAR:6533 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);6534 case DBGCVAR_TYPE_HC_PHYS:6535 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);6536 case DBGCVAR_TYPE_STRING:6537 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);6538 case DBGCVAR_TYPE_NUMBER:6539 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);6540 6541 case DBGCVAR_TYPE_UNKNOWN:6542 default:6543 return pfnOutput(pvArgOutput, "??", 2);6544 }6545 }6546 6547 /*6548 * Print variable with range.6549 * The argument is a const pointer to the variable.6550 */6551 case 'v':6552 {6553 (*ppszFormat)++;6554 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);6555 6556 char szRange[32];6557 switch (pVar->enmRangeType)6558 {6559 case DBGCVAR_RANGE_NONE:6560 szRange[0] = '\0';6561 break;6562 case DBGCVAR_RANGE_ELEMENTS:6563 RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);6564 break;6565 case DBGCVAR_RANGE_BYTES:6566 RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);6567 break;6568 }6569 6570 switch (pVar->enmType)6571 {6572 case DBGCVAR_TYPE_GC_FLAT:6573 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);6574 case DBGCVAR_TYPE_GC_FAR:6575 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);6576 case DBGCVAR_TYPE_GC_PHYS:6577 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);6578 case DBGCVAR_TYPE_HC_FLAT:6579 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);6580 case DBGCVAR_TYPE_HC_FAR:6581 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);6582 case DBGCVAR_TYPE_HC_PHYS:6583 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);6584 case DBGCVAR_TYPE_STRING:6585 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);6586 case DBGCVAR_TYPE_NUMBER:6587 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);6588 6589 case DBGCVAR_TYPE_UNKNOWN:6590 default:6591 return pfnOutput(pvArgOutput, "??", 2);6592 }6593 }6594 6595 default:6596 AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));6597 return 0;6598 }6599 }6600 6601 6602 /**6603 * Command helper for writing formatted text to the debug console.6604 *6605 * @returns VBox status.6606 * @param pCmdHlp Pointer to the command callback structure.6607 * @param pcb Where to store the number of bytes written.6608 * @param pszFormat The format string.6609 * This is using the log formatter, so it's format extensions can be used.6610 * @param args Arguments specified in the format string.6611 */6612 static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)6613 {6614 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6615 6616 /*6617 * Do the formatting and output.6618 */6619 pDbgc->rcOutput = 0;6620 size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);6621 6622 if (pcbWritten)6623 *pcbWritten = cb;6624 6625 return pDbgc->rcOutput;6626 }6627 6628 6629 /**6630 * Reports an error from a DBGF call.6631 *6632 * @returns VBox status code appropriate to return from a command.6633 * @param pCmdHlp Pointer to command helpers.6634 * @param rc The VBox status code returned by a DBGF call.6635 * @param pszFormat Format string for additional messages. Can be NULL.6636 * @param ... Format arguments, optional.6637 */6638 static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)6639 {6640 switch (rc)6641 {6642 case VINF_SUCCESS:6643 break;6644 6645 default:6646 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");6647 if (VBOX_SUCCESS(rc) && pszFormat)6648 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);6649 break;6650 }6651 return rc;6652 }6653 6654 6655 /**6656 * Reports an error from a DBGF call.6657 *6658 * @returns VBox status code appropriate to return from a command.6659 * @param pCmdHlp Pointer to command helpers.6660 * @param rc The VBox status code returned by a DBGF call.6661 * @param pszFormat Format string for additional messages. Can be NULL.6662 * @param ... Format arguments, optional.6663 */6664 static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)6665 {6666 va_list args;6667 va_start(args, pszFormat);6668 int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);6669 va_end(args);6670 return rcRet;6671 }6672 6673 6674 /**6675 * Command helper for reading memory specified by a DBGC variable.6676 *6677 * @returns VBox status code appropriate to return from a command.6678 * @param pCmdHlp Pointer to the command callback structure.6679 * @param pVM VM handle if GC or physical HC address.6680 * @param pvBuffer Where to store the read data.6681 * @param cbRead Number of bytes to read.6682 * @param pVarPointer DBGC variable specifying where to start reading.6683 * @param pcbRead Where to store the number of bytes actually read.6684 * This optional, but it's useful when read GC virtual memory where a6685 * page in the requested range might not be present.6686 * If not specified not-present failure or end of a HC physical page6687 * will cause failure.6688 */6689 static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)6690 {6691 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6692 6693 /*6694 * Dummy check.6695 */6696 if (cbRead == 0)6697 {6698 if (*pcbRead)6699 *pcbRead = 0;6700 return VINF_SUCCESS;6701 }6702 6703 /*6704 * Convert Far addresses getting size and the correct base address.6705 * Getting and checking the size is what makes this messy and slow.6706 */6707 DBGCVAR Var = *pVarPointer;6708 switch (pVarPointer->enmType)6709 {6710 case DBGCVAR_TYPE_GC_FAR:6711 {6712 /* Use DBGFR3AddrFromSelOff for the conversion. */6713 Assert(pDbgc->pVM);6714 DBGFADDRESS Address;6715 int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);6716 if (VBOX_FAILURE(rc))6717 return rc;6718 6719 /* don't bother with flat selectors (for now). */6720 if (!DBGFADDRESS_IS_FLAT(&Address))6721 {6722 SELMSELINFO SelInfo;6723 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);6724 if (VBOX_SUCCESS(rc))6725 {6726 RTGCUINTPTR cb; /* -1 byte */6727 if (SELMSelInfoIsExpandDown(&SelInfo))6728 {6729 if ( !SelInfo.Raw.Gen.u1Granularity6730 && Address.off > UINT16_C(0xffff))6731 return VERR_OUT_OF_SELECTOR_BOUNDS;6732 if (Address.off <= SelInfo.cbLimit)6733 return VERR_OUT_OF_SELECTOR_BOUNDS;6734 cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;6735 }6736 else6737 {6738 if (Address.off > SelInfo.cbLimit)6739 return VERR_OUT_OF_SELECTOR_BOUNDS;6740 cb = SelInfo.cbLimit - Address.off;6741 }6742 if (cbRead - 1 > cb)6743 {6744 if (!pcbRead)6745 return VERR_OUT_OF_SELECTOR_BOUNDS;6746 cbRead = cb + 1;6747 }6748 }6749 6750 Var.enmType = DBGCVAR_TYPE_GC_FLAT;6751 Var.u.GCFlat = Address.FlatPtr;6752 }6753 break;6754 }6755 6756 case DBGCVAR_TYPE_GC_FLAT:6757 case DBGCVAR_TYPE_GC_PHYS:6758 case DBGCVAR_TYPE_HC_FLAT:6759 case DBGCVAR_TYPE_HC_PHYS:6760 break;6761 6762 case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */6763 default:6764 return VERR_NOT_IMPLEMENTED;6765 }6766 6767 6768 6769 /*6770 * Copy page by page.6771 */6772 size_t cbLeft = cbRead;6773 for (;;)6774 {6775 /*6776 * Calc read size.6777 */6778 size_t cb = RT_MIN(PAGE_SIZE, cbLeft);6779 switch (pVarPointer->enmType)6780 {6781 case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;6782 case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;6783 case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;6784 case DBGCVAR_TYPE_HC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - ((size_t)Var.u.HCPhys & PAGE_OFFSET_MASK)); break; /* size_t: MSC has braindead loss of data warnings! */6785 default: break;6786 }6787 6788 /*6789 * Perform read.6790 */6791 int rc;6792 switch (Var.enmType)6793 {6794 case DBGCVAR_TYPE_GC_FLAT:6795 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);6796 break;6797 case DBGCVAR_TYPE_GC_PHYS:6798 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);6799 break;6800 6801 case DBGCVAR_TYPE_HC_PHYS:6802 case DBGCVAR_TYPE_HC_FLAT:6803 case DBGCVAR_TYPE_HC_FAR:6804 {6805 DBGCVAR Var2;6806 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);6807 if (VBOX_SUCCESS(rc))6808 {6809 /** @todo protect this!!! */6810 memcpy(pvBuffer, Var2.u.pvHCFlat, cb);6811 rc = 0;6812 }6813 else6814 rc = VERR_INVALID_POINTER;6815 break;6816 }6817 6818 default:6819 rc = VERR_PARSE_INCORRECT_ARG_TYPE;6820 }6821 6822 /*6823 * Check for failure.6824 */6825 if (VBOX_FAILURE(rc))6826 {6827 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)6828 return VINF_SUCCESS;6829 return rc;6830 }6831 6832 /*6833 * Next.6834 */6835 cbLeft -= cb;6836 if (!cbLeft)6837 break;6838 pvBuffer = (char *)pvBuffer + cb;6839 rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);6840 if (VBOX_FAILURE(rc))6841 {6842 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)6843 return VINF_SUCCESS;6844 return rc;6845 }6846 }6847 6848 /*6849 * Done6850 */6851 if (pcbRead)6852 *pcbRead = cbRead;6853 return 0;6854 }6855 6856 /**6857 * Command helper for writing memory specified by a DBGC variable.6858 *6859 * @returns VBox status code appropriate to return from a command.6860 * @param pCmdHlp Pointer to the command callback structure.6861 * @param pVM VM handle if GC or physical HC address.6862 * @param pvBuffer What to write.6863 * @param cbWrite Number of bytes to write.6864 * @param pVarPointer DBGC variable specifying where to start reading.6865 * @param pcbWritten Where to store the number of bytes written.6866 * This is optional. If NULL be aware that some of the buffer6867 * might have been written to the specified address.6868 */6869 static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)6870 {6871 NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);6872 return VERR_NOT_IMPLEMENTED;6873 }6874 6875 6876 /**6877 * Evaluates an expression.6878 * (Hopefully the parser and functions are fully reentrant.)6879 *6880 * @returns VBox status code appropriate to return from a command.6881 * @param pCmdHlp Pointer to the command callback structure.6882 * @param pResult Where to store the result.6883 * @param pszExpr The expression. Format string with the format DBGC extensions.6884 * @param ... Format arguments.6885 */6886 static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)6887 {6888 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6889 6890 /*6891 * Format the expression.6892 */6893 char szExprFormatted[2048];6894 va_list args;6895 va_start(args, pszExpr);6896 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);6897 va_end(args);6898 /* ignore overflows. */6899 6900 return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);6901 }6902 6903 6904 /**6905 * Executes one command expression.6906 * (Hopefully the parser and functions are fully reentrant.)6907 *6908 * @returns VBox status code appropriate to return from a command.6909 * @param pCmdHlp Pointer to the command callback structure.6910 * @param pszExpr The expression. Format string with the format DBGC extensions.6911 * @param ... Format arguments.6912 */6913 static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)6914 {6915 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6916 /* Save the scratch state. */6917 char *pszScratch = pDbgc->pszScratch;6918 unsigned iArg = pDbgc->iArg;6919 6920 /*6921 * Format the expression.6922 */6923 va_list args;6924 va_start(args, pszExpr);6925 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);6926 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);6927 va_end(args);6928 if (cb >= cbScratch)6929 return VERR_BUFFER_OVERFLOW;6930 6931 /*6932 * Execute the command.6933 * We save and restore the arg index and scratch buffer pointer.6934 */6935 pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;6936 int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);6937 6938 /* Restore the scratch state. */6939 pDbgc->iArg = iArg;6940 pDbgc->pszScratch = pszScratch;6941 6942 return rc;6943 }6944 6945 6946 /**6947 * Converts a DBGC variable to a DBGF address structure.6948 *6949 * @returns VBox status code.6950 * @param pCmdHlp Pointer to the command callback structure.6951 * @param pVar The variable to convert.6952 * @param pAddress The target address.6953 */6954 static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)6955 {6956 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6957 return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);6958 }6959 6960 6961 /**6962 * Converts a DBGC variable to a boolean.6963 *6964 * @returns VBox status code.6965 * @param pCmdHlp Pointer to the command callback structure.6966 * @param pVar The variable to convert.6967 * @param pf Where to store the boolean.6968 */6969 static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)6970 {6971 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6972 NOREF(pDbgc);6973 6974 switch (pVar->enmType)6975 {6976 case DBGCVAR_TYPE_STRING:6977 /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */6978 if ( !strcmp(pVar->u.pszString, "true")6979 || !strcmp(pVar->u.pszString, "True")6980 || !strcmp(pVar->u.pszString, "TRUE")6981 || !strcmp(pVar->u.pszString, "on")6982 || !strcmp(pVar->u.pszString, "On")6983 || !strcmp(pVar->u.pszString, "oN")6984 || !strcmp(pVar->u.pszString, "ON")6985 || !strcmp(pVar->u.pszString, "enabled")6986 || !strcmp(pVar->u.pszString, "Enabled")6987 || !strcmp(pVar->u.pszString, "DISABLED"))6988 {6989 *pf = true;6990 return VINF_SUCCESS;6991 }6992 if ( !strcmp(pVar->u.pszString, "false")6993 || !strcmp(pVar->u.pszString, "False")6994 || !strcmp(pVar->u.pszString, "FALSE")6995 || !strcmp(pVar->u.pszString, "off")6996 || !strcmp(pVar->u.pszString, "Off")6997 || !strcmp(pVar->u.pszString, "OFF")6998 || !strcmp(pVar->u.pszString, "disabled")6999 || !strcmp(pVar->u.pszString, "Disabled")7000 || !strcmp(pVar->u.pszString, "DISABLED"))7001 {7002 *pf = false;7003 return VINF_SUCCESS;7004 }7005 return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */7006 7007 case DBGCVAR_TYPE_GC_FLAT:7008 case DBGCVAR_TYPE_GC_PHYS:7009 case DBGCVAR_TYPE_HC_FLAT:7010 case DBGCVAR_TYPE_HC_PHYS:7011 case DBGCVAR_TYPE_NUMBER:7012 *pf = pVar->u.u64Number != 0;7013 return VINF_SUCCESS;7014 7015 case DBGCVAR_TYPE_HC_FAR:7016 case DBGCVAR_TYPE_GC_FAR:7017 case DBGCVAR_TYPE_SYMBOL:7018 default:7019 return VERR_PARSE_INCORRECT_ARG_TYPE;7020 }7021 }7022 7023 7024 7025 7026 7027 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//7028 //7029 //7030 // V a r i a b l e M a n i p u l a t i o n7031 //7032 //7033 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//7034 7035 7036 7037 /** @todo move me!*/7038 static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)7039 {7040 if (pVar)7041 {7042 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;7043 pVar->u.GCFlat = GCFlat;7044 pVar->enmRangeType = DBGCVAR_RANGE_NONE;7045 pVar->u64Range = 0;7046 }7047 }7048 7049 7050 /** @todo move me!*/7051 static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)7052 {7053 if (pVar)7054 {7055 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;7056 pVar->u.GCFlat = GCFlat;7057 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;7058 pVar->u64Range = cb;7059 }7060 }7061 7062 7063 /** @todo move me!*/7064 static void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)7065 {7066 if (pVar)7067 {7068 if (pVar2)7069 *pVar = *pVar2;7070 else7071 {7072 pVar->enmType = DBGCVAR_TYPE_UNKNOWN;7073 memset(&pVar->u, 0, sizeof(pVar->u));7074 pVar->enmRangeType = DBGCVAR_RANGE_NONE;7075 pVar->u64Range = 0;7076 }7077 }7078 }7079 7080 7081 /** @todo move me!*/7082 static void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)7083 {7084 if (pVar)7085 {7086 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;7087 pVar->u64Range = cb;7088 }7089 }7090 7091 7092 /** @todo move me!*/7093 static void dbgcVarSetNoRange(PDBGCVAR pVar)7094 {7095 if (pVar)7096 {7097 pVar->enmRangeType = DBGCVAR_RANGE_NONE;7098 pVar->u64Range = 0;7099 }7100 }7101 7102 7103 /**7104 * Converts a DBGC variable to a DBGF address.7105 *7106 * @returns VBox status code.7107 * @param pDbgc The DBGC instance.7108 * @param pVar The variable.7109 * @param pAddress Where to store the address.7110 */7111 static int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)7112 {7113 AssertReturn(pVar, VERR_INVALID_PARAMETER);7114 switch (pVar->enmType)7115 {7116 case DBGCVAR_TYPE_GC_FLAT:7117 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);7118 return VINF_SUCCESS;7119 7120 case DBGCVAR_TYPE_NUMBER:7121 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);7122 return VINF_SUCCESS;7123 7124 case DBGCVAR_TYPE_GC_FAR:7125 return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);7126 7127 case DBGCVAR_TYPE_STRING:7128 case DBGCVAR_TYPE_SYMBOL:7129 {7130 DBGCVAR Var;7131 int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);7132 if (VBOX_FAILURE(rc))7133 return rc;7134 return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);7135 }7136 7137 case DBGCVAR_TYPE_GC_PHYS:7138 case DBGCVAR_TYPE_HC_FLAT:7139 case DBGCVAR_TYPE_HC_FAR:7140 case DBGCVAR_TYPE_HC_PHYS:7141 default:7142 return VERR_PARSE_CONVERSION_FAILED;7143 }7144 }7145 7146 7147 7148 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//7149 //7150 //7151 // B r e a k p o i n t M a n a g e m e n t7152 //7153 //7154 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//7155 7156 7157 /**7158 * Adds a breakpoint to the DBGC breakpoint list.7159 */7160 static int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)7161 {7162 /*7163 * Check if it already exists.7164 */7165 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);7166 if (pBp)7167 return VERR_DBGC_BP_EXISTS;7168 7169 /*7170 * Add the breakpoint.7171 */7172 if (pszCmd)7173 pszCmd = RTStrStripL(pszCmd);7174 size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;7175 pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));7176 if (!pBp)7177 return VERR_NO_MEMORY;7178 if (cchCmd)7179 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);7180 else7181 pBp->szCmd[0] = '\0';7182 pBp->cchCmd = cchCmd;7183 pBp->iBp = iBp;7184 pBp->pNext = pDbgc->pFirstBp;7185 pDbgc->pFirstBp = pBp;7186 7187 return VINF_SUCCESS;7188 }7189 7190 /**7191 * Updates the a breakpoint.7192 *7193 * @returns VBox status code.7194 * @param pDbgc The DBGC instance.7195 * @param iBp The breakpoint to update.7196 * @param pszCmd The new command.7197 */7198 static int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)7199 {7200 /*7201 * Find the breakpoint.7202 */7203 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);7204 if (!pBp)7205 return VERR_DBGC_BP_NOT_FOUND;7206 7207 /*7208 * Do we need to reallocate?7209 */7210 if (pszCmd)7211 pszCmd = RTStrStripL(pszCmd);7212 if (!pszCmd || !*pszCmd)7213 pBp->szCmd[0] = '\0';7214 else7215 {7216 size_t cchCmd = strlen(pszCmd);7217 if (strlen(pBp->szCmd) >= cchCmd)7218 {7219 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);7220 pBp->cchCmd = cchCmd;7221 }7222 else7223 {7224 /*7225 * Yes, let's do it the simple way...7226 */7227 int rc = dbgcBpDelete(pDbgc, iBp);7228 AssertRC(rc);7229 return dbgcBpAdd(pDbgc, iBp, pszCmd);7230 }7231 }7232 return VINF_SUCCESS;7233 }7234 7235 7236 /**7237 * Deletes a breakpoint.7238 *7239 * @returns VBox status code.7240 * @param pDbgc The DBGC instance.7241 * @param iBp The breakpoint to delete.7242 */7243 static int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)7244 {7245 /*7246 * Search thru the list, when found unlink and free it.7247 */7248 PDBGCBP pBpPrev = NULL;7249 PDBGCBP pBp = pDbgc->pFirstBp;7250 for (; pBp; pBp = pBp->pNext)7251 {7252 if (pBp->iBp == iBp)7253 {7254 if (pBpPrev)7255 pBpPrev->pNext = pBp->pNext;7256 else7257 pDbgc->pFirstBp = pBp->pNext;7258 RTMemFree(pBp);7259 return VINF_SUCCESS;7260 }7261 pBpPrev = pBp;7262 }7263 7264 return VERR_DBGC_BP_NOT_FOUND;7265 }7266 7267 7268 /**7269 * Get a breakpoint.7270 *7271 * @returns Pointer to the breakpoint.7272 * @returns NULL if the breakpoint wasn't found.7273 * @param pDbgc The DBGC instance.7274 * @param iBp The breakpoint to get.7275 */7276 static PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)7277 {7278 /*7279 * Enumerate the list.7280 */7281 PDBGCBP pBp = pDbgc->pFirstBp;7282 for (; pBp; pBp = pBp->pNext)7283 if (pBp->iBp == iBp)7284 return pBp;7285 return NULL;7286 }7287 7288 7289 /**7290 * Executes the command of a breakpoint.7291 *7292 * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.7293 * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.7294 * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.7295 * @returns VBox status code from dbgcProcessCommand() other wise.7296 * @param pDbgc The DBGC instance.7297 * @param iBp The breakpoint to execute.7298 */7299 static int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)7300 {7301 /*7302 * Find the breakpoint.7303 */7304 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);7305 if (!pBp)7306 return VERR_DBGC_BP_NOT_FOUND;7307 7308 /*7309 * Anything to do?7310 */7311 if (!pBp->cchCmd)7312 return VINF_DBGC_BP_NO_COMMAND;7313 7314 /*7315 * Execute the command.7316 * This means copying it to the scratch buffer and process it as if it7317 * were user input. We must save and restore the state of the scratch buffer.7318 */7319 /* Save the scratch state. */7320 char *pszScratch = pDbgc->pszScratch;7321 unsigned iArg = pDbgc->iArg;7322 7323 /* Copy the command to the scratch buffer. */7324 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);7325 if (pBp->cchCmd >= cbScratch)7326 return VERR_BUFFER_OVERFLOW;7327 memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);7328 7329 /* Execute the command. */7330 pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;7331 int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);7332 7333 /* Restore the scratch state. */7334 pDbgc->iArg = iArg;7335 pDbgc->pszScratch = pszScratch;7336 7337 return rc;7338 }7339 7340 7341 7342 7343 7344 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//7345 //7346 //7347 // I n p u t , p a r s i n g a n d l o g g i n g7348 //7349 //7350 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//7351 7352 7353 7354 /**7355 * Prints any log lines from the log buffer.7356 *7357 * The caller must not call function this unless pDbgc->fLog is set.7358 *7359 * @returns VBox status. (output related)7360 * @param pDbgc Debugger console instance data.7361 */7362 static int dbgcProcessLog(PDBGC pDbgc)7363 {7364 /** @todo */7365 NOREF(pDbgc);7366 return 0;7367 }7368 7369 7370 7371 /**7372 * Handle input buffer overflow.7373 *7374 * Will read any available input looking for a '\n' to reset the buffer on.7375 *7376 * @returns VBox status.7377 * @param pDbgc Debugger console instance data.7378 */7379 static int dbgcInputOverflow(PDBGC pDbgc)7380 {7381 /*7382 * Assert overflow status and reset the input buffer.7383 */7384 if (!pDbgc->fInputOverflow)7385 {7386 pDbgc->fInputOverflow = true;7387 pDbgc->iRead = pDbgc->iWrite = 0;7388 pDbgc->cInputLines = 0;7389 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");7390 }7391 7392 /*7393 * Eat input till no more or there is a '\n'.7394 * When finding a '\n' we'll continue normal processing.7395 */7396 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))7397 {7398 size_t cbRead;7399 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);7400 if (VBOX_FAILURE(rc))7401 return rc;7402 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);7403 if (psz)7404 {7405 pDbgc->fInputOverflow = false;7406 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;7407 pDbgc->iWrite = (unsigned)cbRead;7408 pDbgc->cInputLines = 0;7409 break;7410 }7411 }7412 7413 return 0;7414 }7415 7416 7417 7418 /**7419 * Read input and do some preprocessing.7420 *7421 * @returns VBox status.7422 * In addition to the iWrite and achInput, cInputLines is maintained.7423 * In case of an input overflow the fInputOverflow flag will be set.7424 * @param pDbgc Debugger console instance data.7425 */7426 static int dbgcInputRead(PDBGC pDbgc)7427 {7428 /*7429 * We have ready input.7430 * Read it till we don't have any or we have a full input buffer.7431 */7432 int rc = 0;7433 do7434 {7435 /*7436 * More available buffer space?7437 */7438 size_t cbLeft;7439 if (pDbgc->iWrite > pDbgc->iRead)7440 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);7441 else7442 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;7443 if (!cbLeft)7444 {7445 /* overflow? */7446 if (!pDbgc->cInputLines)7447 rc = dbgcInputOverflow(pDbgc);7448 break;7449 }7450 7451 /*7452 * Read one char and interpret it.7453 */7454 char achRead[128];7455 size_t cbRead;7456 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);7457 if (VBOX_FAILURE(rc))7458 return rc;7459 char *psz = &achRead[0];7460 while (cbRead-- > 0)7461 {7462 char ch = *psz++;7463 switch (ch)7464 {7465 /*7466 * Ignore.7467 */7468 case '\0':7469 case '\r':7470 case '\a':7471 break;7472 7473 /*7474 * Backspace.7475 */7476 case '\b':7477 Log2(("DBGC: backspace\n"));7478 if (pDbgc->iRead != pDbgc->iWrite)7479 {7480 unsigned iWriteUndo = pDbgc->iWrite;7481 if (pDbgc->iWrite)7482 pDbgc->iWrite--;7483 else7484 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;7485 7486 if (pDbgc->achInput[pDbgc->iWrite] == '\n')7487 pDbgc->iWrite = iWriteUndo;7488 }7489 break;7490 7491 /*7492 * Add char to buffer.7493 */7494 case '\t':7495 case '\n':7496 case ';':7497 switch (ch)7498 {7499 case '\t': ch = ' '; break;7500 case '\n': pDbgc->cInputLines++; break;7501 }7502 default:7503 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));7504 pDbgc->achInput[pDbgc->iWrite] = ch;7505 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))7506 pDbgc->iWrite = 0;7507 break;7508 }7509 }7510 7511 /* Terminate it to make it easier to read in the debugger. */7512 pDbgc->achInput[pDbgc->iWrite] = '\0';7513 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));7514 7515 return rc;7516 }7517 7518 7519 /**7520 * Finds a builtin symbol.7521 * @returns Pointer to symbol descriptor on success.7522 * @returns NULL on failure.7523 * @param pDbgc The debug console instance.7524 * @param pszSymbol The symbol name.7525 */7526 static PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)7527 {7528 for (unsigned iSym = 0; iSym < ELEMENTS(g_aSyms); iSym++)7529 if (!strcmp(pszSymbol, g_aSyms[iSym].pszName))7530 return &g_aSyms[iSym];7531 7532 /** @todo externally registered symbols. */7533 NOREF(pDbgc);7534 return NULL;7535 }7536 7537 7538 /**7539 * Resolves a symbol (or tries to do so at least).7540 *7541 * @returns 0 on success.7542 * @returns VBox status on failure.7543 * @param pDbgc The debug console instance.7544 * @param pszSymbol The symbol name.7545 * @param enmType The result type.7546 * @param pResult Where to store the result.7547 */7548 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)7549 {7550 /*7551 * Builtin?7552 */7553 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);7554 if (pSymDesc)7555 {7556 if (!pSymDesc->pfnGet)7557 return VERR_PARSE_WRITEONLY_SYMBOL;7558 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);7559 }7560 7561 7562 /*7563 * Ask PDM.7564 */7565 /** @todo resolve symbols using PDM. */7566 7567 7568 /*7569 * Ask the debug info manager.7570 */7571 DBGFSYMBOL Symbol;7572 int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);7573 if (VBOX_SUCCESS(rc))7574 {7575 /*7576 * Default return is a flat gc address.7577 */7578 memset(pResult, 0, sizeof(*pResult));7579 pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;7580 pResult->u64Range = Symbol.cb;7581 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;7582 pResult->u.GCFlat = Symbol.Value;7583 DBGCVAR VarTmp;7584 switch (enmType)7585 {7586 /* nothing to do. */7587 case DBGCVAR_TYPE_GC_FLAT:7588 case DBGCVAR_TYPE_GC_FAR:7589 case DBGCVAR_TYPE_ANY:7590 return VINF_SUCCESS;7591 7592 /* simply make it numeric. */7593 case DBGCVAR_TYPE_NUMBER:7594 pResult->enmType = DBGCVAR_TYPE_NUMBER;7595 pResult->u.u64Number = Symbol.Value;7596 return VINF_SUCCESS;7597 7598 /* cast it. */7599 7600 case DBGCVAR_TYPE_GC_PHYS:7601 VarTmp = *pResult;7602 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);7603 7604 case DBGCVAR_TYPE_HC_FAR:7605 case DBGCVAR_TYPE_HC_FLAT:7606 VarTmp = *pResult;7607 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);7608 7609 case DBGCVAR_TYPE_HC_PHYS:7610 VarTmp = *pResult;7611 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);7612 7613 default:7614 AssertMsgFailed(("Internal error enmType=%d\n", enmType));7615 return VERR_INVALID_PARAMETER;7616 }7617 }7618 7619 return VERR_PARSE_NOT_IMPLEMENTED;7620 }7621 7622 7623 7624 /**7625 * Finds a routine.7626 *7627 * @returns Pointer to the command descriptor.7628 * If the request was for an external command, the caller is responsible for7629 * unlocking the external command list.7630 * @returns NULL if not found.7631 * @param pDbgc The debug console instance.7632 * @param pachName Pointer to the routine string (not terminated).7633 * @param cchName Length of the routine name.7634 * @param fExternal Whether or not the routine is external.7635 */7636 static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)7637 {7638 if (!fExternal)7639 {7640 /* emulation first, so commands can be overloaded (info ++). */7641 PCDBGCCMD pCmd = pDbgc->paEmulationCmds;7642 unsigned cLeft = pDbgc->cEmulationCmds;7643 while (cLeft-- > 0)7644 {7645 if ( !strncmp(pachName, pCmd->pszCmd, cchName)7646 && !pCmd->pszCmd[cchName])7647 return pCmd;7648 pCmd++;7649 }7650 7651 for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)7652 {7653 if ( !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)7654 && !g_aCmds[iCmd].pszCmd[cchName])7655 return &g_aCmds[iCmd];7656 }7657 }7658 else7659 {7660 DBGCEXTCMDS_LOCK_RD();7661 for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)7662 {7663 for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)7664 {7665 if ( !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)7666 && !pExtCmds->paCmds[iCmd].pszCmd[cchName])7667 return &pExtCmds->paCmds[iCmd];7668 }7669 }7670 DBGCEXTCMDS_UNLOCK_RD();7671 }7672 7673 NOREF(pDbgc);7674 return NULL;7675 }7676 7677 7678 /**7679 * Searches for an operator descriptor which matches the start of7680 * the expression given us.7681 *7682 * @returns Pointer to the operator on success.7683 * @param pDbgc The debug console instance.7684 * @param pszExpr Pointer to the expression string which might start with an operator.7685 * @param fPreferBinary Whether to favour binary or unary operators.7686 * Caller must assert that it's the disired type! Both types will still7687 * be returned, this is only for resolving duplicates.7688 * @param chPrev The previous char. Some operators requires a blank in front of it.7689 */7690 static PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)7691 {7692 PCDBGCOP pOp = NULL;7693 for (unsigned iOp = 0; iOp < ELEMENTS(g_aOps); iOp++)7694 {7695 if ( g_aOps[iOp].szName[0] == pszExpr[0]7696 && (!g_aOps[iOp].szName[1] || g_aOps[iOp].szName[1] == pszExpr[1])7697 && (!g_aOps[iOp].szName[2] || g_aOps[iOp].szName[2] == pszExpr[2]))7698 {7699 /*7700 * Check that we don't mistake it for some other operator which have more chars.7701 */7702 unsigned j;7703 for (j = iOp + 1; j < ELEMENTS(g_aOps); j++)7704 if ( g_aOps[j].cchName > g_aOps[iOp].cchName7705 && g_aOps[j].szName[0] == pszExpr[0]7706 && (!g_aOps[j].szName[1] || g_aOps[j].szName[1] == pszExpr[1])7707 && (!g_aOps[j].szName[2] || g_aOps[j].szName[2] == pszExpr[2]) )7708 break;7709 if (j < ELEMENTS(g_aOps))7710 continue; /* we'll catch it later. (for theoretical +,++,+++ cases.) */7711 pOp = &g_aOps[iOp];7712 7713 /*7714 * Prefered type?7715 */7716 if (g_aOps[iOp].fBinary == fPreferBinary)7717 break;7718 }7719 }7720 7721 if (pOp)7722 Log2(("dbgcOperatorLookup: pOp=%p %s\n", pOp, pOp->szName));7723 NOREF(pDbgc); NOREF(chPrev);7724 return pOp;7725 }7726 7727 7728 /**7729 * Initalizes g_bmOperatorChars.7730 */7731 static void dbgcInitOpCharBitMap(void)7732 {7733 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));7734 for (unsigned iOp = 0; iOp < RT_ELEMENTS(g_aOps); iOp++)7735 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);7736 }7737 7738 7739 /**7740 * Checks whether the character may be the start of an operator.7741 *7742 * @returns true/false.7743 * @param ch The character.7744 */7745 DECLINLINE(bool) dbgcIsOpChar(char ch)7746 {7747 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);7748 }7749 7750 7751 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)7752 {7753 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));7754 7755 /*7756 * Removing any quoting and escapings.7757 */7758 char ch = *pszExpr;7759 if (ch == '"' || ch == '\'' || ch == '`')7760 {7761 if (pszExpr[--cchExpr] != ch)7762 return VERR_PARSE_UNBALANCED_QUOTE;7763 cchExpr--;7764 pszExpr++;7765 7766 /** @todo string unescaping. */7767 }7768 pszExpr[cchExpr] = '\0';7769 7770 /*7771 * Make the argument.7772 */7773 pArg->pDesc = NULL;7774 pArg->pNext = NULL;7775 pArg->enmType = DBGCVAR_TYPE_STRING;7776 pArg->u.pszString = pszExpr;7777 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;7778 pArg->u64Range = cchExpr;7779 7780 NOREF(pDbgc);7781 return 0;7782 }7783 7784 7785 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)7786 {7787 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));7788 /*7789 * Convert to number.7790 */7791 uint64_t u64 = 0;7792 char ch;7793 while ((ch = *pszExpr) != '\0')7794 {7795 uint64_t u64Prev = u64;7796 unsigned u = ch - '0';7797 if (u < 10 && u < uBase)7798 u64 = u64 * uBase + u;7799 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)7800 u64 = u64 * uBase + u;7801 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)7802 u64 = u64 * uBase + u;7803 else7804 return VERR_PARSE_INVALID_NUMBER;7805 7806 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */7807 if (u64Prev != u64 / uBase)7808 return VERR_PARSE_NUMBER_TOO_BIG;7809 7810 /* next */7811 pszExpr++;7812 }7813 7814 /*7815 * Initialize the argument.7816 */7817 pArg->pDesc = NULL;7818 pArg->pNext = NULL;7819 pArg->enmType = DBGCVAR_TYPE_NUMBER;7820 pArg->u.u64Number = u64;7821 pArg->enmRangeType = DBGCVAR_RANGE_NONE;7822 pArg->u64Range = 0;7823 7824 return 0;7825 }7826 7827 7828 /**7829 * Match variable and variable descriptor, promoting the variable if necessary.7830 *7831 * @returns VBox status code.7832 * @param pDbgc Debug console instanace.7833 * @param pVar Variable.7834 * @param pVarDesc Variable descriptor.7835 */7836 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)7837 {7838 /*7839 * (If match or promoted to match, return, else break.)7840 */7841 switch (pVarDesc->enmCategory)7842 {7843 /*7844 * Anything goes7845 */7846 case DBGCVAR_CAT_ANY:7847 return VINF_SUCCESS;7848 7849 /*7850 * Pointer with and without range.7851 * We can try resolve strings and symbols as symbols and7852 * promote numbers to flat GC pointers.7853 */7854 case DBGCVAR_CAT_POINTER_NO_RANGE:7855 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7856 return VERR_PARSE_NO_RANGE_ALLOWED;7857 /* fallthru */7858 case DBGCVAR_CAT_POINTER:7859 switch (pVar->enmType)7860 {7861 case DBGCVAR_TYPE_GC_FLAT:7862 case DBGCVAR_TYPE_GC_FAR:7863 case DBGCVAR_TYPE_GC_PHYS:7864 case DBGCVAR_TYPE_HC_FLAT:7865 case DBGCVAR_TYPE_HC_FAR:7866 case DBGCVAR_TYPE_HC_PHYS:7867 return VINF_SUCCESS;7868 7869 case DBGCVAR_TYPE_SYMBOL:7870 case DBGCVAR_TYPE_STRING:7871 {7872 DBGCVAR Var;7873 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);7874 if (VBOX_SUCCESS(rc))7875 {7876 /* deal with range */7877 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7878 {7879 Var.enmRangeType = pVar->enmRangeType;7880 Var.u64Range = pVar->u64Range;7881 }7882 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)7883 Var.enmRangeType = DBGCVAR_RANGE_NONE;7884 *pVar = Var;7885 return rc;7886 }7887 break;7888 }7889 7890 case DBGCVAR_TYPE_NUMBER:7891 {7892 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;7893 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;7894 pVar->u.GCFlat = GCPtr;7895 return VINF_SUCCESS;7896 }7897 7898 default:7899 break;7900 }7901 break;7902 7903 /*7904 * GC pointer with and without range.7905 * We can try resolve strings and symbols as symbols and7906 * promote numbers to flat GC pointers.7907 */7908 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:7909 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7910 return VERR_PARSE_NO_RANGE_ALLOWED;7911 /* fallthru */7912 case DBGCVAR_CAT_GC_POINTER:7913 switch (pVar->enmType)7914 {7915 case DBGCVAR_TYPE_GC_FLAT:7916 case DBGCVAR_TYPE_GC_FAR:7917 case DBGCVAR_TYPE_GC_PHYS:7918 return VINF_SUCCESS;7919 7920 case DBGCVAR_TYPE_HC_FLAT:7921 case DBGCVAR_TYPE_HC_FAR:7922 case DBGCVAR_TYPE_HC_PHYS:7923 return VERR_PARSE_CONVERSION_FAILED;7924 7925 case DBGCVAR_TYPE_SYMBOL:7926 case DBGCVAR_TYPE_STRING:7927 {7928 DBGCVAR Var;7929 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);7930 if (VBOX_SUCCESS(rc))7931 {7932 /* deal with range */7933 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7934 {7935 Var.enmRangeType = pVar->enmRangeType;7936 Var.u64Range = pVar->u64Range;7937 }7938 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)7939 Var.enmRangeType = DBGCVAR_RANGE_NONE;7940 *pVar = Var;7941 return rc;7942 }7943 break;7944 }7945 7946 case DBGCVAR_TYPE_NUMBER:7947 {7948 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;7949 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;7950 pVar->u.GCFlat = GCPtr;7951 return VINF_SUCCESS;7952 }7953 7954 default:7955 break;7956 }7957 break;7958 7959 /*7960 * Number with or without a range.7961 * Numbers can be resolved from symbols, but we cannot demote a pointer7962 * to a number.7963 */7964 case DBGCVAR_CAT_NUMBER_NO_RANGE:7965 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7966 return VERR_PARSE_NO_RANGE_ALLOWED;7967 /* fallthru */7968 case DBGCVAR_CAT_NUMBER:7969 switch (pVar->enmType)7970 {7971 case DBGCVAR_TYPE_NUMBER:7972 return VINF_SUCCESS;7973 7974 case DBGCVAR_TYPE_SYMBOL:7975 case DBGCVAR_TYPE_STRING:7976 {7977 DBGCVAR Var;7978 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);7979 if (VBOX_SUCCESS(rc))7980 {7981 *pVar = Var;7982 return rc;7983 }7984 break;7985 }7986 default:7987 break;7988 }7989 break;7990 7991 /*7992 * Strings can easily be made from symbols (and of course strings).7993 * We could consider reformatting the addresses and numbers into strings later...7994 */7995 case DBGCVAR_CAT_STRING:7996 switch (pVar->enmType)7997 {7998 case DBGCVAR_TYPE_SYMBOL:7999 pVar->enmType = DBGCVAR_TYPE_STRING;8000 /* fallthru */8001 case DBGCVAR_TYPE_STRING:8002 return VINF_SUCCESS;8003 default:8004 break;8005 }8006 break;8007 8008 /*8009 * Symol is pretty much the same thing as a string (at least until we actually implement it).8010 */8011 case DBGCVAR_CAT_SYMBOL:8012 switch (pVar->enmType)8013 {8014 case DBGCVAR_TYPE_STRING:8015 pVar->enmType = DBGCVAR_TYPE_SYMBOL;8016 /* fallthru */8017 case DBGCVAR_TYPE_SYMBOL:8018 return VINF_SUCCESS;8019 default:8020 break;8021 }8022 break;8023 8024 /*8025 * Anything else is illegal.8026 */8027 default:8028 AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));8029 break;8030 }8031 8032 return VERR_PARSE_NO_ARGUMENT_MATCH;8033 }8034 8035 8036 /**8037 * Matches a set of variables with a description set.8038 *8039 * This is typically used for routine arguments before a call. The effects in8040 * addition to the validation, is that some variables might be propagated to8041 * other types in order to match the description. The following transformations8042 * are supported:8043 * - String reinterpreted as a symbol and resolved to a number or pointer.8044 * - Number to a pointer.8045 * - Pointer to a number.8046 * @returns 0 on success with paVars.8047 * @returns VBox error code for match errors.8048 */8049 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,8050 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,8051 PDBGCVAR paVars, unsigned cVars)8052 {8053 /*8054 * Just do basic min / max checks first.8055 */8056 if (cVars < cVarsMin)8057 return VERR_PARSE_TOO_FEW_ARGUMENTS;8058 if (cVars > cVarsMax)8059 return VERR_PARSE_TOO_MANY_ARGUMENTS;8060 8061 /*8062 * Match the descriptors and actual variables.8063 */8064 PCDBGCVARDESC pPrevDesc = NULL;8065 unsigned cCurDesc = 0;8066 unsigned iVar = 0;8067 unsigned iVarDesc = 0;8068 while (iVar < cVars)8069 {8070 /* walk the descriptors */8071 if (iVarDesc >= cVarDescs)8072 return VERR_PARSE_TOO_MANY_ARGUMENTS;8073 if ( ( paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV8074 && &paVarDescs[iVarDesc - 1] != pPrevDesc)8075 || cCurDesc >= paVarDescs[iVarDesc].cTimesMax)8076 {8077 iVarDesc++;8078 if (iVarDesc >= cVarDescs)8079 return VERR_PARSE_TOO_MANY_ARGUMENTS;8080 cCurDesc = 0;8081 }8082 8083 /*8084 * Skip thru optional arguments until we find something which matches8085 * or can easily be promoted to what the descriptor want.8086 */8087 for (;;)8088 {8089 int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);8090 if (VBOX_SUCCESS(rc))8091 {8092 paVars[iVar].pDesc = &paVarDescs[iVarDesc];8093 cCurDesc++;8094 break;8095 }8096 8097 /* can we advance? */8098 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)8099 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;8100 if (++iVarDesc >= cVarDescs)8101 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;8102 cCurDesc = 0;8103 }8104 8105 /* next var */8106 iVar++;8107 }8108 8109 /*8110 * Check that the rest of the descriptors are optional.8111 */8112 while (iVarDesc < cVarDescs)8113 {8114 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)8115 return VERR_PARSE_TOO_FEW_ARGUMENTS;8116 cCurDesc = 0;8117 8118 /* next */8119 iVarDesc++;8120 }8121 8122 return 0;8123 }8124 8125 8126 /**8127 * Evaluates one argument with respect to unary operators.8128 *8129 * @returns 0 on success. pResult contains the result.8130 * @returns VBox error code on parse or other evaluation error.8131 *8132 * @param pDbgc Debugger console instance data.8133 * @param pszExpr The expression string.8134 * @param pResult Where to store the result of the expression evaluation.8135 */8136 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)8137 {8138 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));8139 8140 /*8141 * The state of the expression is now such that it will start by zero or more8142 * unary operators and being followed by an expression of some kind.8143 * The expression is either plain or in parenthesis.8144 *8145 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)8146 * ASSUME: unary operators are all of equal precedence.8147 */8148 int rc = 0;8149 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');8150 if (pOp)8151 {8152 /* binary operators means syntax error. */8153 if (pOp->fBinary)8154 return VERR_PARSE_UNEXPECTED_OPERATOR;8155 8156 /*8157 * If the next expression (the one following the unary operator) is in a8158 * parenthesis a full eval is needed. If not the unary eval will suffice.8159 */8160 /* calc and strip next expr. */8161 char *pszExpr2 = pszExpr + pOp->cchName;8162 while (isblank(*pszExpr2))8163 pszExpr2++;8164 8165 if (!*pszExpr2)8166 rc = VERR_PARSE_EMPTY_ARGUMENT;8167 else8168 {8169 DBGCVAR Arg;8170 if (*pszExpr2 == '(')8171 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);8172 else8173 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);8174 if (VBOX_SUCCESS(rc))8175 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);8176 }8177 }8178 else8179 {8180 /*8181 * Didn't find any operators, so it we have to check if this can be an8182 * function call before assuming numeric or string expression.8183 *8184 * (ASSUMPTIONS:)8185 * A function name only contains alphanumerical chars and it can not start8186 * with a numerical character.8187 * Immediately following the name is a parenthesis which must over8188 * the remaining part of the expression.8189 */8190 bool fExternal = *pszExpr == '.';8191 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;8192 char *pszFunEnd = NULL;8193 if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))8194 {8195 pszFunEnd = pszExpr + 1;8196 while (*pszFunEnd != '(' && isalnum(*pszFunEnd))8197 pszFunEnd++;8198 if (*pszFunEnd != '(')8199 pszFunEnd = NULL;8200 }8201 8202 if (pszFunEnd)8203 {8204 /*8205 * Ok, it's a function call.8206 */8207 if (fExternal)8208 pszExpr++, cchExpr--;8209 PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);8210 if (!pFun)8211 return VERR_PARSE_FUNCTION_NOT_FOUND;8212 if (!pFun->pResultDesc)8213 return VERR_PARSE_NOT_A_FUNCTION;8214 8215 /*8216 * Parse the expression in parenthesis.8217 */8218 cchExpr -= pszFunEnd - pszExpr;8219 pszExpr = pszFunEnd;8220 /** @todo implement multiple arguments. */8221 DBGCVAR Arg;8222 rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);8223 if (!rc)8224 {8225 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);8226 if (!rc)8227 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);8228 }8229 else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)8230 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);8231 }8232 else8233 {8234 /*8235 * Didn't find any operators, so it must be a plain expression.8236 * This might be numeric or a string expression.8237 */8238 char ch = pszExpr[0];8239 char ch2 = pszExpr[1];8240 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))8241 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);8242 else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))8243 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);8244 else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))8245 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);8246 /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.8247 //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))8248 // rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);8249 else8250 {8251 /*8252 * Hexadecimal number or a string?8253 */8254 char *psz = pszExpr;8255 while (isxdigit(*psz))8256 psz++;8257 if (!*psz)8258 rc = dbgcEvalSubNum(pszExpr, 16, pResult);8259 else if ((*psz == 'h' || *psz == 'H') && !psz[1])8260 {8261 *psz = '\0';8262 rc = dbgcEvalSubNum(pszExpr, 16, pResult);8263 }8264 else8265 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);8266 }8267 }8268 }8269 8270 return rc;8271 }8272 8273 8274 /**8275 * Evaluates one argument.8276 *8277 * @returns 0 on success. pResult contains the result.8278 * @returns VBox error code on parse or other evaluation error.8279 *8280 * @param pDbgc Debugger console instance data.8281 * @param pszExpr The expression string.8282 * @param pResult Where to store the result of the expression evaluation.8283 */8284 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)8285 {8286 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));8287 /*8288 * First we need to remove blanks in both ends.8289 * ASSUMES: There is no quoting unless the entire expression is a string.8290 */8291 8292 /* stripping. */8293 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))8294 pszExpr[--cchExpr] = '\0';8295 while (isblank(*pszExpr))8296 pszExpr++, cchExpr--;8297 if (!*pszExpr)8298 return VERR_PARSE_EMPTY_ARGUMENT;8299 8300 /* it there is any kind of quoting in the expression, it's string meat. */8301 if (strpbrk(pszExpr, "\"'`"))8302 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);8303 8304 /*8305 * Check if there are any parenthesis which needs removing.8306 */8307 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')8308 {8309 do8310 {8311 unsigned cPar = 1;8312 char *psz = pszExpr + 1;8313 char ch;8314 while ((ch = *psz) != '\0')8315 {8316 if (ch == '(')8317 cPar++;8318 else if (ch == ')')8319 {8320 if (cPar <= 0)8321 return VERR_PARSE_UNBALANCED_PARENTHESIS;8322 cPar--;8323 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */8324 break;8325 }8326 /* next */8327 psz++;8328 }8329 if (ch)8330 break;8331 8332 /* remove the parenthesis. */8333 pszExpr++;8334 cchExpr -= 2;8335 pszExpr[cchExpr] = '\0';8336 8337 /* strip blanks. */8338 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))8339 pszExpr[--cchExpr] = '\0';8340 while (isblank(*pszExpr))8341 pszExpr++, cchExpr--;8342 if (!*pszExpr)8343 return VERR_PARSE_EMPTY_ARGUMENT;8344 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');8345 }8346 8347 /* tabs to spaces. */8348 char *psz = pszExpr;8349 while ((psz = strchr(psz, '\t')) != NULL)8350 *psz = ' ';8351 8352 /*8353 * Now, we need to look for the binary operator with the lowest precedence.8354 *8355 * If there are no operators we're left with a simple expression which we8356 * evaluate with respect to unary operators8357 */8358 char *pszOpSplit = NULL;8359 PCDBGCOP pOpSplit = NULL;8360 unsigned cBinaryOps = 0;8361 unsigned cPar = 0;8362 char ch;8363 char chPrev = ' ';8364 bool fBinary = false;8365 psz = pszExpr;8366 8367 while ((ch = *psz) != '\0')8368 {8369 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));8370 /*8371 * Parenthesis.8372 */8373 if (ch == '(')8374 {8375 cPar++;8376 fBinary = false;8377 }8378 else if (ch == ')')8379 {8380 if (cPar <= 0)8381 return VERR_PARSE_UNBALANCED_PARENTHESIS;8382 cPar--;8383 fBinary = true;8384 }8385 /*8386 * Potential operator.8387 */8388 else if (cPar == 0 && !isblank(ch))8389 {8390 PCDBGCOP pOp = dbgcIsOpChar(ch)8391 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)8392 : NULL;8393 if (pOp)8394 {8395 /* If not the right kind of operator we've got a syntax error. */8396 if (pOp->fBinary != fBinary)8397 return VERR_PARSE_UNEXPECTED_OPERATOR;8398 8399 /*8400 * Update the parse state and skip the operator.8401 */8402 if (!pOpSplit)8403 {8404 pOpSplit = pOp;8405 pszOpSplit = psz;8406 cBinaryOps = fBinary;8407 }8408 else if (fBinary)8409 {8410 cBinaryOps++;8411 if (pOp->iPrecedence >= pOpSplit->iPrecedence)8412 {8413 pOpSplit = pOp;8414 pszOpSplit = psz;8415 }8416 }8417 8418 psz += pOp->cchName - 1;8419 fBinary = false;8420 }8421 else8422 fBinary = true;8423 }8424 8425 /* next */8426 psz++;8427 chPrev = ch;8428 } /* parse loop. */8429 8430 8431 /*8432 * Either we found an operator to divide the expression by8433 * or we didn't find any. In the first case it's divide and8434 * conquer. In the latter it's a single expression which8435 * needs dealing with its unary operators if any.8436 */8437 int rc;8438 if ( cBinaryOps8439 && pOpSplit->fBinary)8440 {8441 /* process 1st sub expression. */8442 *pszOpSplit = '\0';8443 DBGCVAR Arg1;8444 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);8445 if (VBOX_SUCCESS(rc))8446 {8447 /* process 2nd sub expression. */8448 char *psz2 = pszOpSplit + pOpSplit->cchName;8449 DBGCVAR Arg2;8450 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);8451 if (VBOX_SUCCESS(rc))8452 /* apply the operator. */8453 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);8454 }8455 }8456 else if (cBinaryOps)8457 {8458 /* process sub expression. */8459 pszOpSplit += pOpSplit->cchName;8460 DBGCVAR Arg;8461 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);8462 if (VBOX_SUCCESS(rc))8463 /* apply the operator. */8464 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);8465 }8466 else8467 /* plain expression or using unary operators perhaps with paratheses. */8468 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);8469 8470 return rc;8471 }8472 8473 8474 /**8475 * Parses the arguments of one command.8476 *8477 * @returns 0 on success.8478 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.8479 * @param pDbgc Debugger console instance data.8480 * @param pCmd Pointer to the command descriptor.8481 * @param pszArg Pointer to the arguments to parse.8482 * @param paArgs Where to store the parsed arguments.8483 * @param cArgs Size of the paArgs array.8484 * @param pcArgs Where to store the number of arguments.8485 * In the event of an error this is used to store the index of the offending argument.8486 */8487 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)8488 {8489 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));8490 /*8491 * Check if we have any argument and if the command takes any.8492 */8493 *pcArgs = 0;8494 /* strip leading blanks. */8495 while (*pszArgs && isblank(*pszArgs))8496 pszArgs++;8497 if (!*pszArgs)8498 {8499 if (!pCmd->cArgsMin)8500 return 0;8501 return VERR_PARSE_TOO_FEW_ARGUMENTS;8502 }8503 /** @todo fixme - foo() doesn't work. */8504 if (!pCmd->cArgsMax)8505 return VERR_PARSE_TOO_MANY_ARGUMENTS;8506 8507 /*8508 * This is a hack, it's "temporary" and should go away "when" the parser is8509 * modified to match arguments while parsing.8510 */8511 if ( pCmd->cArgsMax == 18512 && pCmd->cArgsMin == 18513 && pCmd->cArgDescs == 18514 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING8515 && cArgs >= 1)8516 {8517 *pcArgs = 1;8518 RTStrStripR(pszArgs);8519 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);8520 }8521 8522 8523 /*8524 * The parse loop.8525 */8526 PDBGCVAR pArg0 = &paArgs[0];8527 PDBGCVAR pArg = pArg0;8528 *pcArgs = 0;8529 do8530 {8531 /*8532 * Can we have another argument?8533 */8534 if (*pcArgs >= pCmd->cArgsMax)8535 return VERR_PARSE_TOO_MANY_ARGUMENTS;8536 if (pArg >= &paArgs[cArgs])8537 return VERR_PARSE_ARGUMENT_OVERFLOW;8538 8539 /*8540 * Find the end of the argument.8541 */8542 int cPar = 0;8543 char chQuote = '\0';8544 char *pszEnd = NULL;8545 char *psz = pszArgs;8546 char ch;8547 bool fBinary = false;8548 for (;;)8549 {8550 /*8551 * Check for the end.8552 */8553 if ((ch = *psz) == '\0')8554 {8555 if (chQuote)8556 return VERR_PARSE_UNBALANCED_QUOTE;8557 if (cPar)8558 return VERR_PARSE_UNBALANCED_PARENTHESIS;8559 pszEnd = psz;8560 break;8561 }8562 /*8563 * When quoted we ignore everything but the quotation char.8564 * We use the REXX way of escaping the quotation char, i.e. double occurence.8565 */8566 else if (ch == '\'' || ch == '"' || ch == '`')8567 {8568 if (chQuote)8569 {8570 /* end quote? */8571 if (ch == chQuote)8572 {8573 if (psz[1] == ch)8574 psz++; /* skip the escaped quote char */8575 else8576 chQuote = '\0'; /* end of quoted string. */8577 }8578 }8579 else8580 chQuote = ch; /* open new quote */8581 }8582 /*8583 * Parenthesis can of course be nested.8584 */8585 else if (ch == '(')8586 {8587 cPar++;8588 fBinary = false;8589 }8590 else if (ch == ')')8591 {8592 if (!cPar)8593 return VERR_PARSE_UNBALANCED_PARENTHESIS;8594 cPar--;8595 fBinary = true;8596 }8597 else if (!chQuote && !cPar)8598 {8599 /*8600 * Encountering blanks may mean the end of it all. A binary operator8601 * will force continued parsing.8602 */8603 if (isblank(*psz))8604 {8605 pszEnd = psz++; /* just in case. */8606 while (isblank(*psz))8607 psz++;8608 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');8609 if (!pOp || pOp->fBinary != fBinary)8610 break; /* the end. */8611 psz += pOp->cchName;8612 while (isblank(*psz)) /* skip blanks so we don't get here again */8613 psz++;8614 fBinary = false;8615 continue;8616 }8617 8618 /*8619 * Look for operators without a space up front.8620 */8621 if (dbgcIsOpChar(*psz))8622 {8623 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');8624 if (pOp)8625 {8626 if (pOp->fBinary != fBinary)8627 {8628 pszEnd = psz;8629 /** @todo this is a parsing error really. */8630 break; /* the end. */8631 }8632 psz += pOp->cchName;8633 while (isblank(*psz)) /* skip blanks so we don't get here again */8634 psz++;8635 fBinary = false;8636 continue;8637 }8638 }8639 fBinary = true;8640 }8641 8642 /* next char */8643 psz++;8644 }8645 *pszEnd = '\0';8646 /* (psz = next char to process) */8647 8648 /*8649 * Parse and evaluate the argument.8650 */8651 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);8652 if (VBOX_FAILURE(rc))8653 return rc;8654 8655 /*8656 * Next.8657 */8658 pArg++;8659 (*pcArgs)++;8660 pszArgs = psz;8661 while (*pszArgs && isblank(*pszArgs))8662 pszArgs++;8663 } while (*pszArgs);8664 8665 /*8666 * Match the arguments.8667 */8668 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);8669 }8670 8671 8672 /**8673 * Process one command.8674 *8675 * @returns VBox status code. Any error indicates the termination of the console session.8676 * @param pDbgc Debugger console instance data.8677 * @param pszCmd Pointer to the command.8678 * @param cchCmd Length of the command.8679 */8680 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)8681 {8682 char *pszCmdInput = pszCmd;8683 8684 /*8685 * Skip blanks.8686 */8687 while (isblank(*pszCmd))8688 pszCmd++, cchCmd--;8689 8690 /* external command? */8691 bool fExternal = *pszCmd == '.';8692 if (fExternal)8693 pszCmd++, cchCmd--;8694 8695 /*8696 * Find arguments.8697 */8698 char *pszArgs = pszCmd;8699 while (isalnum(*pszArgs))8700 pszArgs++;8701 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))8702 {8703 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);8704 return 0;8705 }8706 8707 /*8708 * Find the command.8709 */8710 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);8711 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))8712 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);8713 8714 /*8715 * Parse arguments (if any).8716 */8717 unsigned cArgs;8718 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);8719 8720 /*8721 * Execute the command.8722 */8723 if (!rc)8724 {8725 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);8726 }8727 else8728 {8729 /* report parse / eval error. */8730 switch (rc)8731 {8732 case VERR_PARSE_TOO_FEW_ARGUMENTS:8733 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8734 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);8735 break;8736 case VERR_PARSE_TOO_MANY_ARGUMENTS:8737 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8738 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);8739 break;8740 case VERR_PARSE_ARGUMENT_OVERFLOW:8741 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8742 "Syntax error: Too many arguments.\n");8743 break;8744 case VERR_PARSE_UNBALANCED_QUOTE:8745 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8746 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);8747 break;8748 case VERR_PARSE_UNBALANCED_PARENTHESIS:8749 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8750 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);8751 break;8752 case VERR_PARSE_EMPTY_ARGUMENT:8753 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8754 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);8755 break;8756 case VERR_PARSE_UNEXPECTED_OPERATOR:8757 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8758 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);8759 break;8760 case VERR_PARSE_INVALID_NUMBER:8761 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8762 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);8763 break;8764 case VERR_PARSE_NUMBER_TOO_BIG:8765 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8766 "Error: Numeric overflow (argument %d).\n", cArgs);8767 break;8768 case VERR_PARSE_INVALID_OPERATION:8769 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8770 "Error: Invalid operation attempted (argument %d).\n", cArgs);8771 break;8772 case VERR_PARSE_FUNCTION_NOT_FOUND:8773 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8774 "Error: Function not found (argument %d).\n", cArgs);8775 break;8776 case VERR_PARSE_NOT_A_FUNCTION:8777 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8778 "Error: The function specified is not a function (argument %d).\n", cArgs);8779 break;8780 case VERR_PARSE_NO_MEMORY:8781 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8782 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);8783 break;8784 case VERR_PARSE_INCORRECT_ARG_TYPE:8785 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8786 "Error: Incorrect argument type (argument %d?).\n", cArgs);8787 break;8788 case VERR_PARSE_VARIABLE_NOT_FOUND:8789 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8790 "Error: An undefined variable was referenced (argument %d).\n", cArgs);8791 break;8792 case VERR_PARSE_CONVERSION_FAILED:8793 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8794 "Error: A conversion between two types failed (argument %d).\n", cArgs);8795 break;8796 case VERR_PARSE_NOT_IMPLEMENTED:8797 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8798 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);8799 break;8800 case VERR_PARSE_BAD_RESULT_TYPE:8801 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8802 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);8803 break;8804 case VERR_PARSE_WRITEONLY_SYMBOL:8805 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8806 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);8807 break;8808 8809 default:8810 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8811 "Error: Unknown error %d!\n", rc);8812 return rc;8813 }8814 8815 /*8816 * Parse errors are non fatal.8817 */8818 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)8819 rc = 0;8820 }8821 8822 return rc;8823 }8824 8825 8826 /**8827 * Process all commands current in the buffer.8828 *8829 * @returns VBox status code. Any error indicates the termination of the console session.8830 * @param pDbgc Debugger console instance data.8831 */8832 static int dbgcProcessCommands(PDBGC pDbgc)8833 {8834 int rc = 0;8835 while (pDbgc->cInputLines)8836 {8837 /*8838 * Empty the log buffer if we're hooking the log.8839 */8840 if (pDbgc->fLog)8841 {8842 rc = dbgcProcessLog(pDbgc);8843 if (VBOX_FAILURE(rc))8844 break;8845 }8846 8847 if (pDbgc->iRead == pDbgc->iWrite)8848 {8849 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));8850 pDbgc->cInputLines = 0;8851 return 0;8852 }8853 8854 /*8855 * Copy the command to the parse buffer.8856 */8857 char ch;8858 char *psz = &pDbgc->achInput[pDbgc->iRead];8859 char *pszTrg = &pDbgc->achScratch[0];8860 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )8861 {8862 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])8863 psz = &pDbgc->achInput[0];8864 8865 if (psz == &pDbgc->achInput[pDbgc->iWrite])8866 {8867 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));8868 pDbgc->cInputLines = 0;8869 return 0;8870 }8871 8872 pszTrg++;8873 }8874 *pszTrg = '\0';8875 8876 /*8877 * Advance the buffer.8878 */8879 pDbgc->iRead = psz - &pDbgc->achInput[0];8880 if (ch == '\n')8881 pDbgc->cInputLines--;8882 8883 /*8884 * Parse and execute this command.8885 */8886 pDbgc->pszScratch = psz;8887 pDbgc->iArg = 0;8888 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);8889 if (rc)8890 break;8891 }8892 8893 return rc;8894 }8895 8896 8897 /**8898 * Reads input, parses it and executes commands on '\n'.8899 *8900 * @returns VBox status.8901 * @param pDbgc Debugger console instance data.8902 */8903 static int dbgcProcessInput(PDBGC pDbgc)8904 {8905 /*8906 * We know there's input ready, so let's read it first.8907 */8908 int rc = dbgcInputRead(pDbgc);8909 if (VBOX_FAILURE(rc))8910 return rc;8911 8912 /*8913 * Now execute any ready commands.8914 */8915 if (pDbgc->cInputLines)8916 {8917 /** @todo this fReady stuff is broken. */8918 pDbgc->fReady = false;8919 rc = dbgcProcessCommands(pDbgc);8920 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)8921 pDbgc->fReady = true;8922 if ( VBOX_SUCCESS(rc)8923 && pDbgc->iRead == pDbgc->iWrite8924 && pDbgc->fReady)8925 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");8926 }8927 8928 return rc;8929 }8930 8931 8932 /**8933 * Gets the event context identifier string.8934 * @returns Read only string.8935 * @param enmCtx The context.8936 */8937 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)8938 {8939 switch (enmCtx)8940 {8941 case DBGFEVENTCTX_RAW: return "raw";8942 case DBGFEVENTCTX_REM: return "rem";8943 case DBGFEVENTCTX_HWACCL: return "hwaccl";8944 case DBGFEVENTCTX_HYPER: return "hyper";8945 case DBGFEVENTCTX_OTHER: return "other";8946 8947 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";8948 default:8949 AssertMsgFailed(("enmCtx=%d\n", enmCtx));8950 return "!Unknown Event Ctx!";8951 }8952 }8953 8954 8955 /**8956 * Processes debugger events.8957 *8958 * @returns VBox status.8959 * @param pDbgc DBGC Instance data.8960 * @param pEvent Pointer to event data.8961 */8962 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)8963 {8964 /*8965 * Flush log first.8966 */8967 if (pDbgc->fLog)8968 {8969 int rc = dbgcProcessLog(pDbgc);8970 if (VBOX_FAILURE(rc))8971 return rc;8972 }8973 8974 /*8975 * Process the event.8976 */8977 pDbgc->pszScratch = &pDbgc->achInput[0];8978 pDbgc->iArg = 0;8979 bool fPrintPrompt = true;8980 int rc = VINF_SUCCESS;8981 switch (pEvent->enmType)8982 {8983 /*8984 * The first part is events we have initiated with commands.8985 */8986 case DBGFEVENT_HALT_DONE:8987 {8988 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",8989 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));8990 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */8991 if (VBOX_SUCCESS(rc))8992 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");8993 break;8994 }8995 8996 8997 /*8998 * The second part is events which can occur at any time.8999 */9000 case DBGFEVENT_FATAL_ERROR:9001 {9002 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",9003 dbgcGetEventCtx(pEvent->enmCtx));9004 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */9005 if (VBOX_SUCCESS(rc))9006 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");9007 break;9008 }9009 9010 case DBGFEVENT_BREAKPOINT:9011 case DBGFEVENT_BREAKPOINT_HYPER:9012 {9013 bool fRegCtxGuest = pDbgc->fRegCtxGuest;9014 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;9015 9016 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);9017 switch (rc)9018 {9019 case VERR_DBGC_BP_NOT_FOUND:9020 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",9021 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));9022 break;9023 9024 case VINF_DBGC_BP_NO_COMMAND:9025 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",9026 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));9027 break;9028 9029 case VINF_BUFFER_OVERFLOW:9030 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",9031 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));9032 break;9033 9034 default:9035 break;9036 }9037 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))9038 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");9039 else9040 pDbgc->fRegCtxGuest = fRegCtxGuest;9041 break;9042 }9043 9044 case DBGFEVENT_STEPPED:9045 case DBGFEVENT_STEPPED_HYPER:9046 {9047 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;9048 9049 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));9050 if (VBOX_SUCCESS(rc))9051 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");9052 break;9053 }9054 9055 case DBGFEVENT_ASSERTION_HYPER:9056 {9057 pDbgc->fRegCtxGuest = false;9058 9059 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,9060 "\ndbgf event: Hypervisor Assertion! (%s)\n"9061 "%s"9062 "%s"9063 "\n",9064 dbgcGetEventCtx(pEvent->enmCtx),9065 pEvent->u.Assert.pszMsg1,9066 pEvent->u.Assert.pszMsg2);9067 if (VBOX_SUCCESS(rc))9068 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");9069 break;9070 }9071 9072 case DBGFEVENT_DEV_STOP:9073 {9074 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,9075 "\n"9076 "dbgf event: DBGFSTOP (%s)\n"9077 "File: %s\n"9078 "Line: %d\n"9079 "Function: %s\n",9080 dbgcGetEventCtx(pEvent->enmCtx),9081 pEvent->u.Src.pszFile,9082 pEvent->u.Src.uLine,9083 pEvent->u.Src.pszFunction);9084 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)9085 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,9086 "Message: %s\n",9087 pEvent->u.Src.pszMessage);9088 if (VBOX_SUCCESS(rc))9089 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");9090 break;9091 }9092 9093 9094 case DBGFEVENT_INVALID_COMMAND:9095 {9096 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");9097 fPrintPrompt = !pDbgc->fReady;9098 break;9099 }9100 9101 case DBGFEVENT_TERMINATING:9102 {9103 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");9104 rc = VERR_GENERAL_FAILURE;9105 break;9106 }9107 9108 9109 default:9110 {9111 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);9112 fPrintPrompt = !pDbgc->fReady;9113 break;9114 }9115 }9116 9117 /*9118 * Prompt, anyone?9119 */9120 if (fPrintPrompt && VBOX_SUCCESS(rc))9121 {9122 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");9123 }9124 9125 return rc;9126 }9127 9128 9129 9130 9131 9132 /**9133 * Make a console instance.9134 *9135 * This will not return until either an 'exit' command is issued or a error code9136 * indicating connection loss is encountered.9137 *9138 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.9139 * @returns The VBox status code causing the console termination.9140 *9141 * @param pVM VM Handle.9142 * @param pBack Pointer to the backend structure. This must contain9143 * a full set of function pointers to service the console.9144 * @param fFlags Reserved, must be zero.9145 * @remark A forced termination of the console is easiest done by forcing the9146 * callbacks to return fatal failures.9147 */9148 DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)9149 {9150 /*9151 * Validate input.9152 */9153 AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);9154 AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);9155 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);9156 9157 /*9158 * Allocate and initialize instance data9159 */9160 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));9161 if (!pDbgc)9162 return VERR_NO_MEMORY;9163 9164 pDbgc->CmdHlp.pfnWrite = dbgcHlpWrite;9165 pDbgc->CmdHlp.pfnPrintfV = dbgcHlpPrintfV;9166 pDbgc->CmdHlp.pfnPrintf = dbgcHlpPrintf;9167 pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;9168 pDbgc->CmdHlp.pfnVBoxError = dbgcHlpVBoxError;9169 pDbgc->CmdHlp.pfnMemRead = dbgcHlpMemRead;9170 pDbgc->CmdHlp.pfnMemWrite = dbgcHlpMemWrite;9171 pDbgc->CmdHlp.pfnEval = dbgcHlpEval;9172 pDbgc->CmdHlp.pfnExec = dbgcHlpExec;9173 pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;9174 pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;9175 pDbgc->pBack = pBack;9176 pDbgc->pVM = NULL;9177 pDbgc->pszEmulation = "CodeView/WinDbg";9178 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];9179 pDbgc->cEmulationCmds = RT_ELEMENTS(g_aCmdsCodeView);9180 //pDbgc->fLog = false;9181 pDbgc->fRegCtxGuest = true;9182 pDbgc->fRegTerse = true;9183 //pDbgc->DisasmPos = {0};9184 //pDbgc->SourcePos = {0};9185 //pDbgc->DumpPos = {0};9186 //pDbgc->cbDumpElement = 0;9187 //pDbgc->cVars = 0;9188 //pDbgc->paVars = NULL;9189 //pDbgc->pFirstBp = NULL;9190 //pDbgc->uInputZero = 0;9191 //pDbgc->iRead = 0;9192 //pDbgc->iWrite = 0;9193 //pDbgc->cInputLines = 0;9194 //pDbgc->fInputOverflow = false;9195 pDbgc->fReady = true;9196 pDbgc->pszScratch = &pDbgc->achScratch[0];9197 //pDbgc->iArg = 0;9198 //pDbgc->rcOutput = 0;9199 9200 dbgcInitOpCharBitMap();9201 9202 /*9203 * Print welcome message.9204 */9205 int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,9206 "Welcome to the VirtualBox Debugger!\n");9207 if (VBOX_FAILURE(rc))9208 goto l_failure;9209 9210 /*9211 * Attach to the VM.9212 */9213 rc = DBGFR3Attach(pVM);9214 if (VBOX_FAILURE(rc))9215 {9216 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);9217 goto l_failure;9218 }9219 pDbgc->pVM = pVM;9220 9221 /*9222 * Print commandline and auto select result.9223 */9224 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,9225 "Current VM is %08x\n" /** @todo get and print the VM name! */9226 "VBoxDbg> ",9227 pDbgc->pVM);9228 if (VBOX_FAILURE(rc))9229 goto l_failure;9230 9231 /*9232 * Main Debugger Loop.9233 *9234 * This loop will either block on waiting for input or on waiting on9235 * debug events. If we're forwarding the log we cannot wait for long9236 * before we must flush the log.9237 */9238 for (rc = 0;;)9239 {9240 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))9241 {9242 /*9243 * Wait for a debug event.9244 */9245 PCDBGFEVENT pEvent;9246 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);9247 if (VBOX_SUCCESS(rc))9248 {9249 rc = dbgcProcessEvent(pDbgc, pEvent);9250 if (VBOX_FAILURE(rc))9251 break;9252 }9253 else if (rc != VERR_TIMEOUT)9254 break;9255 9256 /*9257 * Check for input.9258 */9259 if (pBack->pfnInput(pDbgc->pBack, 0))9260 {9261 rc = dbgcProcessInput(pDbgc);9262 if (VBOX_FAILURE(rc))9263 break;9264 }9265 }9266 else9267 {9268 /*9269 * Wait for input. If Logging is enabled we'll only wait very briefly.9270 */9271 if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))9272 {9273 rc = dbgcProcessInput(pDbgc);9274 if (VBOX_FAILURE(rc))9275 break;9276 }9277 }9278 9279 /*9280 * Forward log output.9281 */9282 if (pDbgc->fLog)9283 {9284 rc = dbgcProcessLog(pDbgc);9285 if (VBOX_FAILURE(rc))9286 break;9287 }9288 }9289 9290 9291 l_failure:9292 /*9293 * Cleanup console debugger session.9294 */9295 /* Disable log hook. */9296 if (pDbgc->fLog)9297 {9298 9299 }9300 9301 /* Detach from the VM. */9302 if (pDbgc->pVM)9303 DBGFR3Detach(pDbgc->pVM);9304 9305 /* finally, free the instance memory. */9306 RTMemFree(pDbgc);9307 9308 return rc;9309 }9310 9311 9312 9313 /**9314 * Register one or more external commands.9315 *9316 * @returns VBox status.9317 * @param paCommands Pointer to an array of command descriptors.9318 * The commands must be unique. It's not possible9319 * to register the same commands more than once.9320 * @param cCommands Number of commands.9321 */9322 DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)9323 {9324 /*9325 * Lock the list.9326 */9327 DBGCEXTCMDS_LOCK_WR();9328 PDBGCEXTCMDS pCur = g_pExtCmdsHead;9329 while (pCur)9330 {9331 if (paCommands == pCur->paCmds)9332 {9333 DBGCEXTCMDS_UNLOCK_WR();9334 AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));9335 return VWRN_DBGC_ALREADY_REGISTERED;9336 }9337 pCur = pCur->pNext;9338 }9339 9340 /*9341 * Allocate new chunk.9342 */9343 int rc = 0;9344 pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));9345 if (pCur)9346 {9347 pCur->cCmds = cCommands;9348 pCur->paCmds = paCommands;9349 pCur->pNext = g_pExtCmdsHead;9350 g_pExtCmdsHead = pCur;9351 }9352 else9353 rc = VERR_NO_MEMORY;9354 DBGCEXTCMDS_UNLOCK_WR();9355 9356 return rc;9357 }9358 9359 9360 /**9361 * Deregister one or more external commands previously registered by9362 * DBGCRegisterCommands().9363 *9364 * @returns VBox status.9365 * @param paCommands Pointer to an array of command descriptors9366 * as given to DBGCRegisterCommands().9367 * @param cCommands Number of commands.9368 */9369 DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)9370 {9371 /*9372 * Lock the list.9373 */9374 DBGCEXTCMDS_LOCK_WR();9375 PDBGCEXTCMDS pPrev = NULL;9376 PDBGCEXTCMDS pCur = g_pExtCmdsHead;9377 while (pCur)9378 {9379 if (paCommands == pCur->paCmds)9380 {9381 if (pPrev)9382 pPrev->pNext = pCur->pNext;9383 else9384 g_pExtCmdsHead = pCur->pNext;9385 DBGCEXTCMDS_UNLOCK_WR();9386 9387 RTMemFree(pCur);9388 return VINF_SUCCESS;9389 }9390 pPrev = pCur;9391 pCur = pCur->pNext;9392 }9393 DBGCEXTCMDS_UNLOCK_WR();9394 9395 NOREF(cCommands);9396 return VERR_DBGC_COMMANDS_NOT_REGISTERED;9397 }9398 -
trunk/src/VBox/Debugger/DBGConsole.cpp
r5666 r5668 125 125 #include <stdio.h> 126 126 127 /* to err.h! */ 128 #define VERR_DBGC_QUIT (-11999) 129 #define VERR_PARSE_FIRST (-11000) 130 #define VERR_PARSE_TOO_FEW_ARGUMENTS (VERR_PARSE_FIRST - 0) 131 #define VERR_PARSE_TOO_MANY_ARGUMENTS (VERR_PARSE_FIRST - 1) 132 #define VERR_PARSE_ARGUMENT_OVERFLOW (VERR_PARSE_FIRST - 2) 133 #define VERR_PARSE_ARGUMENT_TYPE_MISMATCH (VERR_PARSE_FIRST - 3) 134 #define VERR_PARSE_NO_RANGE_ALLOWED (VERR_PARSE_FIRST - 4) 135 #define VERR_PARSE_UNBALANCED_QUOTE (VERR_PARSE_FIRST - 5) 136 #define VERR_PARSE_UNBALANCED_PARENTHESIS (VERR_PARSE_FIRST - 6) 137 #define VERR_PARSE_EMPTY_ARGUMENT (VERR_PARSE_FIRST - 7) 138 #define VERR_PARSE_UNEXPECTED_OPERATOR (VERR_PARSE_FIRST - 8) 139 #define VERR_PARSE_INVALID_NUMBER (VERR_PARSE_FIRST - 9) 140 #define VERR_PARSE_NUMBER_TOO_BIG (VERR_PARSE_FIRST - 10) 141 #define VERR_PARSE_INVALID_OPERATION (VERR_PARSE_FIRST - 11) 142 #define VERR_PARSE_FUNCTION_NOT_FOUND (VERR_PARSE_FIRST - 12) 143 #define VERR_PARSE_NOT_A_FUNCTION (VERR_PARSE_FIRST - 13) 144 #define VERR_PARSE_NO_MEMORY (VERR_PARSE_FIRST - 14) 145 #define VERR_PARSE_INCORRECT_ARG_TYPE (VERR_PARSE_FIRST - 15) 146 #define VERR_PARSE_VARIABLE_NOT_FOUND (VERR_PARSE_FIRST - 16) 147 #define VERR_PARSE_CONVERSION_FAILED (VERR_PARSE_FIRST - 17) 148 #define VERR_PARSE_NOT_IMPLEMENTED (VERR_PARSE_FIRST - 18) 149 #define VERR_PARSE_BAD_RESULT_TYPE (VERR_PARSE_FIRST - 19) 150 #define VERR_PARSE_WRITEONLY_SYMBOL (VERR_PARSE_FIRST - 20) 151 #define VERR_PARSE_NO_ARGUMENT_MATCH (VERR_PARSE_FIRST - 21) 152 #define VERR_PARSE_LAST (VERR_PARSE_FIRST - 30) 153 154 #define VWRN_DBGC_CMD_PENDING 12000 155 #define VWRN_DBGC_ALREADY_REGISTERED 12001 156 #define VERR_DBGC_COMMANDS_NOT_REGISTERED (-12002) 157 #define VERR_DBGC_BP_NOT_FOUND (-12003) 158 #define VERR_DBGC_BP_EXISTS (-12004) 159 #define VINF_DBGC_BP_NO_COMMAND 12005 160 161 162 163 /******************************************************************************* 164 * Defined Constants And Macros * 165 *******************************************************************************/ 166 /** Makes a DBGC variable type pair. 167 * Typically used by binary operators. */ 168 #define BINARY_TYPE_PAIR(type1, type2) (type1 | (type2 << 16)) 169 170 171 /******************************************************************************* 172 * Structures and Typedefs * 173 *******************************************************************************/ 174 175 /** 176 * Debugger console per breakpoint data. 177 */ 178 typedef struct DBGCBP 179 { 180 /** Pointer to the next breakpoint in the list. */ 181 struct DBGCBP *pNext; 182 /** The breakpoint identifier. */ 183 RTUINT iBp; 184 /** The size of the command. */ 185 size_t cchCmd; 186 /** The command to execute when the breakpoint is hit. */ 187 char szCmd[1]; 188 } DBGCBP; 189 /** Pointer to a breakpoint. */ 190 typedef DBGCBP *PDBGCBP; 191 192 193 /** 194 * Named variable. 195 * 196 * Always allocated from heap in one signle block. 197 */ 198 typedef struct DBGCNAMEDVAR 199 { 200 /** The variable. */ 201 DBGCVAR Var; 202 /** It's name. */ 203 char szName[1]; 204 } DBGCNAMEDVAR; 205 /** Pointer to named variable. */ 206 typedef DBGCNAMEDVAR *PDBGCNAMEDVAR; 207 208 209 /** 210 * Debugger console status 211 */ 212 typedef enum DBGCSTATUS 213 { 214 /** Normal status, .*/ 215 DBGC_HALTED 216 217 } DBGCSTATUS; 218 219 220 /** 221 * Debugger console instance data. 222 */ 223 typedef struct DBGC 224 { 225 /** Command helpers. */ 226 DBGCCMDHLP CmdHlp; 227 /** Pointer to backend callback structure. */ 228 PDBGCBACK pBack; 229 230 /** Pointer to the current VM. */ 231 PVM pVM; 232 /** The current debugger emulation. */ 233 const char *pszEmulation; 234 /** Pointer to the command and functions for the current debugger emulation. */ 235 PCDBGCCMD paEmulationCmds; 236 /** The number of commands paEmulationCmds points to. */ 237 unsigned cEmulationCmds; 238 /** Log indicator. (If set we're writing the log to the console.) */ 239 bool fLog; 240 241 /** Indicates whether we're in guest (true) or hypervisor (false) register context. */ 242 bool fRegCtxGuest; 243 /** Indicates whether the register are terse or sparse. */ 244 bool fRegTerse; 245 246 /** Current dissassembler position. */ 247 DBGCVAR DisasmPos; 248 /** Current source position. (flat GC) */ 249 DBGCVAR SourcePos; 250 /** Current memory dump position. */ 251 DBGCVAR DumpPos; 252 /** Size of the previous dump element. */ 253 unsigned cbDumpElement; 254 255 /** Number of variables in papVars. */ 256 unsigned cVars; 257 /** Array of global variables. 258 * Global variables can be referenced using the $ operator and set 259 * and unset using command with those names. */ 260 PDBGCNAMEDVAR *papVars; 261 262 /** The list of breakpoints. (singly linked) */ 263 PDBGCBP pFirstBp; 264 265 /** @name Parsing and Execution 266 * @{ */ 267 268 /** Input buffer. */ 269 char achInput[2048]; 270 /** To ease debugging. */ 271 unsigned uInputZero; 272 /** Write index in the input buffer. */ 273 unsigned iWrite; 274 /** Read index in the input buffer. */ 275 unsigned iRead; 276 /** The number of lines in the buffer. */ 277 unsigned cInputLines; 278 /** Indicates that we have a buffer overflow condition. 279 * This means that input is ignored up to the next newline. */ 280 bool fInputOverflow; 281 /** Indicates whether or we're ready for input. */ 282 bool fReady; 283 284 /** Scratch buffer position. */ 285 char *pszScratch; 286 /** Scratch buffer. */ 287 char achScratch[16384]; 288 /** Argument array position. */ 289 unsigned iArg; 290 /** Array of argument variables. */ 291 DBGCVAR aArgs[100]; 292 293 /** rc from last dbgcHlpPrintfV(). */ 294 int rcOutput; 295 296 /** @} */ 297 } DBGC; 298 /** Pointer to debugger console instance data. */ 299 typedef DBGC *PDBGC; 300 301 /** Converts a Command Helper pointer to a pointer to DBGC instance data. */ 302 #define DBGC_CMDHLP2DBGC(pCmdHlp) ( (PDBGC)((uintptr_t)(pCmdHlp) - RT_OFFSETOF(DBGC, CmdHlp)) ) 303 304 305 /** 306 * Chunk of external commands. 307 */ 308 typedef struct DBGCEXTCMDS 309 { 310 /** Number of commands descriptors. */ 311 unsigned cCmds; 312 /** Pointer to array of command descriptors. */ 313 PCDBGCCMD paCmds; 314 /** Pointer to the next chunk. */ 315 struct DBGCEXTCMDS *pNext; 316 } DBGCEXTCMDS; 317 /** Pointer to chunk of external commands. */ 318 typedef DBGCEXTCMDS *PDBGCEXTCMDS; 319 320 321 322 /** 323 * Unary operator handler function. 324 * 325 * @returns 0 on success. 326 * @returns VBox evaluation / parsing error code on failure. 327 * The caller does the bitching. 328 * @param pDbgc Debugger console instance data. 329 * @param pArg The argument. 330 * @param pResult Where to store the result. 331 */ 332 typedef DECLCALLBACK(int) FNDBGCOPUNARY(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 333 /** Pointer to a unary operator handler function. */ 334 typedef FNDBGCOPUNARY *PFNDBGCOPUNARY; 335 336 337 /** 338 * Binary operator handler function. 339 * 340 * @returns 0 on success. 341 * @returns VBox evaluation / parsing error code on failure. 342 * The caller does the bitching. 343 * @param pDbgc Debugger console instance data. 344 * @param pArg1 The first argument. 345 * @param pArg2 The 2nd argument. 346 * @param pResult Where to store the result. 347 */ 348 typedef DECLCALLBACK(int) FNDBGCOPBINARY(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 349 /** Pointer to a binary operator handler function. */ 350 typedef FNDBGCOPBINARY *PFNDBGCOPBINARY; 351 352 353 /** 354 * Operator descriptor. 355 */ 356 typedef struct DBGCOP 357 { 358 /** Operator mnemonic. */ 359 char szName[4]; 360 /** Length of name. */ 361 const unsigned cchName; 362 /** Whether or not this is a binary operator. 363 * Unary operators are evaluated right-to-left while binary are left-to-right. */ 364 bool fBinary; 365 /** Precedence level. */ 366 unsigned iPrecedence; 367 /** Unary operator handler. */ 368 PFNDBGCOPUNARY pfnHandlerUnary; 369 /** Binary operator handler. */ 370 PFNDBGCOPBINARY pfnHandlerBinary; 371 /** Operator description. */ 372 const char *pszDescription; 373 } DBGCOP; 374 /** Pointer to an operator descriptor. */ 375 typedef DBGCOP *PDBGCOP; 376 /** Pointer to a const operator descriptor. */ 377 typedef const DBGCOP *PCDBGCOP; 378 379 380 381 /** Pointer to symbol descriptor. */ 382 typedef struct DBGCSYM *PDBGCSYM; 383 /** Pointer to const symbol descriptor. */ 384 typedef const struct DBGCSYM *PCDBGCSYM; 385 386 /** 387 * Get builtin symbol. 388 * 389 * @returns 0 on success. 390 * @returns VBox evaluation / parsing error code on failure. 391 * The caller does the bitching. 392 * @param pSymDesc Pointer to the symbol descriptor. 393 * @param pCmdHlp Pointer to the command callback structure. 394 * @param enmType The result type. 395 * @param pResult Where to store the result. 396 */ 397 typedef DECLCALLBACK(int) FNDBGCSYMGET(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult); 398 /** Pointer to get function for a builtin symbol. */ 399 typedef FNDBGCSYMGET *PFNDBGCSYMGET; 400 401 /** 402 * Set builtin symbol. 403 * 404 * @returns 0 on success. 405 * @returns VBox evaluation / parsing error code on failure. 406 * The caller does the bitching. 407 * @param pSymDesc Pointer to the symbol descriptor. 408 * @param pCmdHlp Pointer to the command callback structure. 409 * @param pValue The value to assign the symbol. 410 */ 411 typedef DECLCALLBACK(int) FNDBGCSYMSET(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue); 412 /** Pointer to set function for a builtin symbol. */ 413 typedef FNDBGCSYMSET *PFNDBGCSYMSET; 414 415 416 /** 417 * Symbol description (for builtin symbols). 418 */ 419 typedef struct DBGCSYM 420 { 421 /** Symbol name. */ 422 const char *pszName; 423 /** Get function. */ 424 PFNDBGCSYMGET pfnGet; 425 /** Set function. (NULL if readonly) */ 426 PFNDBGCSYMSET pfnSet; 427 /** User data. */ 428 unsigned uUser; 429 } DBGCSYM; 127 #include "DBGCInternal.h" 430 128 431 129
Note:
See TracChangeset
for help on using the changeset viewer.