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