Changeset 5677 in vbox
- Timestamp:
- Nov 11, 2007 5:54:53 AM (17 years ago)
- svn:sync-xref-src-repo-rev:
- 26021
- Location:
- trunk/src/VBox/Debugger
- Files:
-
- 2 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGCCmdWorkers.cpp
r5676 r5677 1 1 /** $Id$ */ 2 2 /** @file 3 * DBGC - Debugger Console .3 * DBGC - Debugger Console, Command Worker Routines. 4 4 */ 5 5 … … 15 15 * be useful, but WITHOUT ANY WARRANTY of any kind. 16 16 */ 17 18 19 /** @page pg_dbgc DBGC - The Debug Console20 *21 * The debugger console is a first attempt to make some interactive22 * debugging facilities for the VirtualBox backend (i.e. the VM). At a later23 * stage we'll make a fancy gui around this, but for the present a telnet (or24 * serial terminal) will have to suffice.25 *26 * The debugger is only built into the VM with debug builds or when27 * VBOX_WITH_DEBUGGER is defined. There might be need for \#ifdef'ing on this28 * define to enable special debugger hooks, but the general approach is to29 * make generic interfaces. The individual components also can register30 * 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 and36 * windows kernel debuggers. This means ';' is a command separator and37 * that when possible we'll use the same command names as these two uses.38 *39 *40 * @subsection sec_dbg_op_numbers Numbers41 *42 * Numbers are hexadecimal unless specified with a prefix indicating43 * elsewise. Prefixes:44 * - '0x' - hexadecimal.45 * - '0i' - decimal46 * - '0t' - octal.47 * - '0y' - binary.48 *49 *50 * @subsection sec_dbg_op_address Addressing modes51 *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 Evaluation60 *61 * As time permits support will be implemented support for a subset of the C62 * binary operators, starting with '+', '-', '*' and '/'. Support for variables63 * are provided thru commands 'set' and 'unset' and the unary operator '$'. The64 * unary '@' operator will indicate function calls. The debugger needs a set of65 * memory read functions, but we might later extend this to allow registration of66 * external functions too.67 *68 * A special command '?' will then be added which evalutates a given expression69 * and prints it in all the different formats.70 *71 *72 * @subsection sec_dbg_op_registers Registers73 *74 * Registers are addressed using their name. Some registers which have several fields75 * (like gdtr) will have separate names indicating the different fields. The default76 * register set is the guest one. To access the hypervisor register one have to77 * prefix the register names with '.'.78 *79 *80 * @subsection sec_dbg_op_commands Commands81 *82 * The commands are all lowercase, case sensitive, and starting with a letter. We will83 * later add some special commands ('?' for evaulation) and perhaps command classes ('.', '!')84 *85 *86 * @section sec_dbg_tasks Tasks87 *88 * To implement DBGT and instrument VMM for basic state inspection and log89 * 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 100 101 17 102 18 /******************************************************************************* … … 122 38 #include <iprt/ctype.h> 123 39 124 #include <stdlib.h>125 #include <stdio.h>126 127 40 #include "DBGCInternal.h" 128 129 130 /*******************************************************************************131 * Global Variables *132 *******************************************************************************/133 /** Bitmap where set bits indicates the characters the may start an operator name. */134 static uint32_t g_bmOperatorChars[256 / (4*8)];135 136 137 138 139 41 140 42 … … 453 355 } 454 356 455 456 457 458 459 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//460 //461 //462 // I n p u t , p a r s i n g a n d l o g g i n g463 //464 //465 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//466 467 468 469 /**470 * Prints any log lines from the log buffer.471 *472 * The caller must not call function this unless pDbgc->fLog is set.473 *474 * @returns VBox status. (output related)475 * @param pDbgc Debugger console instance data.476 */477 static int dbgcProcessLog(PDBGC pDbgc)478 {479 /** @todo */480 NOREF(pDbgc);481 return 0;482 }483 484 485 486 /**487 * Handle input buffer overflow.488 *489 * Will read any available input looking for a '\n' to reset the buffer on.490 *491 * @returns VBox status.492 * @param pDbgc Debugger console instance data.493 */494 static int dbgcInputOverflow(PDBGC pDbgc)495 {496 /*497 * Assert overflow status and reset the input buffer.498 */499 if (!pDbgc->fInputOverflow)500 {501 pDbgc->fInputOverflow = true;502 pDbgc->iRead = pDbgc->iWrite = 0;503 pDbgc->cInputLines = 0;504 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");505 }506 507 /*508 * Eat input till no more or there is a '\n'.509 * When finding a '\n' we'll continue normal processing.510 */511 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))512 {513 size_t cbRead;514 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);515 if (VBOX_FAILURE(rc))516 return rc;517 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);518 if (psz)519 {520 pDbgc->fInputOverflow = false;521 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;522 pDbgc->iWrite = (unsigned)cbRead;523 pDbgc->cInputLines = 0;524 break;525 }526 }527 528 return 0;529 }530 531 532 533 /**534 * Read input and do some preprocessing.535 *536 * @returns VBox status.537 * In addition to the iWrite and achInput, cInputLines is maintained.538 * In case of an input overflow the fInputOverflow flag will be set.539 * @param pDbgc Debugger console instance data.540 */541 static int dbgcInputRead(PDBGC pDbgc)542 {543 /*544 * We have ready input.545 * Read it till we don't have any or we have a full input buffer.546 */547 int rc = 0;548 do549 {550 /*551 * More available buffer space?552 */553 size_t cbLeft;554 if (pDbgc->iWrite > pDbgc->iRead)555 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);556 else557 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;558 if (!cbLeft)559 {560 /* overflow? */561 if (!pDbgc->cInputLines)562 rc = dbgcInputOverflow(pDbgc);563 break;564 }565 566 /*567 * Read one char and interpret it.568 */569 char achRead[128];570 size_t cbRead;571 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);572 if (VBOX_FAILURE(rc))573 return rc;574 char *psz = &achRead[0];575 while (cbRead-- > 0)576 {577 char ch = *psz++;578 switch (ch)579 {580 /*581 * Ignore.582 */583 case '\0':584 case '\r':585 case '\a':586 break;587 588 /*589 * Backspace.590 */591 case '\b':592 Log2(("DBGC: backspace\n"));593 if (pDbgc->iRead != pDbgc->iWrite)594 {595 unsigned iWriteUndo = pDbgc->iWrite;596 if (pDbgc->iWrite)597 pDbgc->iWrite--;598 else599 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;600 601 if (pDbgc->achInput[pDbgc->iWrite] == '\n')602 pDbgc->iWrite = iWriteUndo;603 }604 break;605 606 /*607 * Add char to buffer.608 */609 case '\t':610 case '\n':611 case ';':612 switch (ch)613 {614 case '\t': ch = ' '; break;615 case '\n': pDbgc->cInputLines++; break;616 }617 default:618 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));619 pDbgc->achInput[pDbgc->iWrite] = ch;620 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))621 pDbgc->iWrite = 0;622 break;623 }624 }625 626 /* Terminate it to make it easier to read in the debugger. */627 pDbgc->achInput[pDbgc->iWrite] = '\0';628 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));629 630 return rc;631 }632 633 634 635 /**636 * Resolves a symbol (or tries to do so at least).637 *638 * @returns 0 on success.639 * @returns VBox status on failure.640 * @param pDbgc The debug console instance.641 * @param pszSymbol The symbol name.642 * @param enmType The result type.643 * @param pResult Where to store the result.644 */645 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)646 {647 /*648 * Builtin?649 */650 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);651 if (pSymDesc)652 {653 if (!pSymDesc->pfnGet)654 return VERR_PARSE_WRITEONLY_SYMBOL;655 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);656 }657 658 659 /*660 * Ask PDM.661 */662 /** @todo resolve symbols using PDM. */663 664 665 /*666 * Ask the debug info manager.667 */668 DBGFSYMBOL Symbol;669 int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);670 if (VBOX_SUCCESS(rc))671 {672 /*673 * Default return is a flat gc address.674 */675 memset(pResult, 0, sizeof(*pResult));676 pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;677 pResult->u64Range = Symbol.cb;678 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;679 pResult->u.GCFlat = Symbol.Value;680 DBGCVAR VarTmp;681 switch (enmType)682 {683 /* nothing to do. */684 case DBGCVAR_TYPE_GC_FLAT:685 case DBGCVAR_TYPE_GC_FAR:686 case DBGCVAR_TYPE_ANY:687 return VINF_SUCCESS;688 689 /* simply make it numeric. */690 case DBGCVAR_TYPE_NUMBER:691 pResult->enmType = DBGCVAR_TYPE_NUMBER;692 pResult->u.u64Number = Symbol.Value;693 return VINF_SUCCESS;694 695 /* cast it. */696 697 case DBGCVAR_TYPE_GC_PHYS:698 VarTmp = *pResult;699 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);700 701 case DBGCVAR_TYPE_HC_FAR:702 case DBGCVAR_TYPE_HC_FLAT:703 VarTmp = *pResult;704 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);705 706 case DBGCVAR_TYPE_HC_PHYS:707 VarTmp = *pResult;708 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);709 710 default:711 AssertMsgFailed(("Internal error enmType=%d\n", enmType));712 return VERR_INVALID_PARAMETER;713 }714 }715 716 return VERR_PARSE_NOT_IMPLEMENTED;717 }718 719 720 /**721 * Initalizes g_bmOperatorChars.722 */723 static void dbgcInitOpCharBitMap(void)724 {725 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));726 for (unsigned iOp = 0; iOp < g_cOps; iOp++)727 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);728 }729 730 731 /**732 * Checks whether the character may be the start of an operator.733 *734 * @returns true/false.735 * @param ch The character.736 */737 DECLINLINE(bool) dbgcIsOpChar(char ch)738 {739 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);740 }741 742 743 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)744 {745 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));746 747 /*748 * Removing any quoting and escapings.749 */750 char ch = *pszExpr;751 if (ch == '"' || ch == '\'' || ch == '`')752 {753 if (pszExpr[--cchExpr] != ch)754 return VERR_PARSE_UNBALANCED_QUOTE;755 cchExpr--;756 pszExpr++;757 758 /** @todo string unescaping. */759 }760 pszExpr[cchExpr] = '\0';761 762 /*763 * Make the argument.764 */765 pArg->pDesc = NULL;766 pArg->pNext = NULL;767 pArg->enmType = DBGCVAR_TYPE_STRING;768 pArg->u.pszString = pszExpr;769 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;770 pArg->u64Range = cchExpr;771 772 NOREF(pDbgc);773 return 0;774 }775 776 777 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)778 {779 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));780 /*781 * Convert to number.782 */783 uint64_t u64 = 0;784 char ch;785 while ((ch = *pszExpr) != '\0')786 {787 uint64_t u64Prev = u64;788 unsigned u = ch - '0';789 if (u < 10 && u < uBase)790 u64 = u64 * uBase + u;791 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)792 u64 = u64 * uBase + u;793 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)794 u64 = u64 * uBase + u;795 else796 return VERR_PARSE_INVALID_NUMBER;797 798 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */799 if (u64Prev != u64 / uBase)800 return VERR_PARSE_NUMBER_TOO_BIG;801 802 /* next */803 pszExpr++;804 }805 806 /*807 * Initialize the argument.808 */809 pArg->pDesc = NULL;810 pArg->pNext = NULL;811 pArg->enmType = DBGCVAR_TYPE_NUMBER;812 pArg->u.u64Number = u64;813 pArg->enmRangeType = DBGCVAR_RANGE_NONE;814 pArg->u64Range = 0;815 816 return 0;817 }818 819 820 /**821 * Match variable and variable descriptor, promoting the variable if necessary.822 *823 * @returns VBox status code.824 * @param pDbgc Debug console instanace.825 * @param pVar Variable.826 * @param pVarDesc Variable descriptor.827 */828 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)829 {830 /*831 * (If match or promoted to match, return, else break.)832 */833 switch (pVarDesc->enmCategory)834 {835 /*836 * Anything goes837 */838 case DBGCVAR_CAT_ANY:839 return VINF_SUCCESS;840 841 /*842 * Pointer with and without range.843 * We can try resolve strings and symbols as symbols and844 * promote numbers to flat GC pointers.845 */846 case DBGCVAR_CAT_POINTER_NO_RANGE:847 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)848 return VERR_PARSE_NO_RANGE_ALLOWED;849 /* fallthru */850 case DBGCVAR_CAT_POINTER:851 switch (pVar->enmType)852 {853 case DBGCVAR_TYPE_GC_FLAT:854 case DBGCVAR_TYPE_GC_FAR:855 case DBGCVAR_TYPE_GC_PHYS:856 case DBGCVAR_TYPE_HC_FLAT:857 case DBGCVAR_TYPE_HC_FAR:858 case DBGCVAR_TYPE_HC_PHYS:859 return VINF_SUCCESS;860 861 case DBGCVAR_TYPE_SYMBOL:862 case DBGCVAR_TYPE_STRING:863 {864 DBGCVAR Var;865 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);866 if (VBOX_SUCCESS(rc))867 {868 /* deal with range */869 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)870 {871 Var.enmRangeType = pVar->enmRangeType;872 Var.u64Range = pVar->u64Range;873 }874 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)875 Var.enmRangeType = DBGCVAR_RANGE_NONE;876 *pVar = Var;877 return rc;878 }879 break;880 }881 882 case DBGCVAR_TYPE_NUMBER:883 {884 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;885 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;886 pVar->u.GCFlat = GCPtr;887 return VINF_SUCCESS;888 }889 890 default:891 break;892 }893 break;894 895 /*896 * GC pointer with and without range.897 * We can try resolve strings and symbols as symbols and898 * promote numbers to flat GC pointers.899 */900 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:901 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)902 return VERR_PARSE_NO_RANGE_ALLOWED;903 /* fallthru */904 case DBGCVAR_CAT_GC_POINTER:905 switch (pVar->enmType)906 {907 case DBGCVAR_TYPE_GC_FLAT:908 case DBGCVAR_TYPE_GC_FAR:909 case DBGCVAR_TYPE_GC_PHYS:910 return VINF_SUCCESS;911 912 case DBGCVAR_TYPE_HC_FLAT:913 case DBGCVAR_TYPE_HC_FAR:914 case DBGCVAR_TYPE_HC_PHYS:915 return VERR_PARSE_CONVERSION_FAILED;916 917 case DBGCVAR_TYPE_SYMBOL:918 case DBGCVAR_TYPE_STRING:919 {920 DBGCVAR Var;921 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);922 if (VBOX_SUCCESS(rc))923 {924 /* deal with range */925 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)926 {927 Var.enmRangeType = pVar->enmRangeType;928 Var.u64Range = pVar->u64Range;929 }930 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)931 Var.enmRangeType = DBGCVAR_RANGE_NONE;932 *pVar = Var;933 return rc;934 }935 break;936 }937 938 case DBGCVAR_TYPE_NUMBER:939 {940 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;941 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;942 pVar->u.GCFlat = GCPtr;943 return VINF_SUCCESS;944 }945 946 default:947 break;948 }949 break;950 951 /*952 * Number with or without a range.953 * Numbers can be resolved from symbols, but we cannot demote a pointer954 * to a number.955 */956 case DBGCVAR_CAT_NUMBER_NO_RANGE:957 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)958 return VERR_PARSE_NO_RANGE_ALLOWED;959 /* fallthru */960 case DBGCVAR_CAT_NUMBER:961 switch (pVar->enmType)962 {963 case DBGCVAR_TYPE_NUMBER:964 return VINF_SUCCESS;965 966 case DBGCVAR_TYPE_SYMBOL:967 case DBGCVAR_TYPE_STRING:968 {969 DBGCVAR Var;970 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);971 if (VBOX_SUCCESS(rc))972 {973 *pVar = Var;974 return rc;975 }976 break;977 }978 default:979 break;980 }981 break;982 983 /*984 * Strings can easily be made from symbols (and of course strings).985 * We could consider reformatting the addresses and numbers into strings later...986 */987 case DBGCVAR_CAT_STRING:988 switch (pVar->enmType)989 {990 case DBGCVAR_TYPE_SYMBOL:991 pVar->enmType = DBGCVAR_TYPE_STRING;992 /* fallthru */993 case DBGCVAR_TYPE_STRING:994 return VINF_SUCCESS;995 default:996 break;997 }998 break;999 1000 /*1001 * Symol is pretty much the same thing as a string (at least until we actually implement it).1002 */1003 case DBGCVAR_CAT_SYMBOL:1004 switch (pVar->enmType)1005 {1006 case DBGCVAR_TYPE_STRING:1007 pVar->enmType = DBGCVAR_TYPE_SYMBOL;1008 /* fallthru */1009 case DBGCVAR_TYPE_SYMBOL:1010 return VINF_SUCCESS;1011 default:1012 break;1013 }1014 break;1015 1016 /*1017 * Anything else is illegal.1018 */1019 default:1020 AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));1021 break;1022 }1023 1024 return VERR_PARSE_NO_ARGUMENT_MATCH;1025 }1026 1027 1028 /**1029 * Matches a set of variables with a description set.1030 *1031 * This is typically used for routine arguments before a call. The effects in1032 * addition to the validation, is that some variables might be propagated to1033 * other types in order to match the description. The following transformations1034 * are supported:1035 * - String reinterpreted as a symbol and resolved to a number or pointer.1036 * - Number to a pointer.1037 * - Pointer to a number.1038 * @returns 0 on success with paVars.1039 * @returns VBox error code for match errors.1040 */1041 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,1042 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,1043 PDBGCVAR paVars, unsigned cVars)1044 {1045 /*1046 * Just do basic min / max checks first.1047 */1048 if (cVars < cVarsMin)1049 return VERR_PARSE_TOO_FEW_ARGUMENTS;1050 if (cVars > cVarsMax)1051 return VERR_PARSE_TOO_MANY_ARGUMENTS;1052 1053 /*1054 * Match the descriptors and actual variables.1055 */1056 PCDBGCVARDESC pPrevDesc = NULL;1057 unsigned cCurDesc = 0;1058 unsigned iVar = 0;1059 unsigned iVarDesc = 0;1060 while (iVar < cVars)1061 {1062 /* walk the descriptors */1063 if (iVarDesc >= cVarDescs)1064 return VERR_PARSE_TOO_MANY_ARGUMENTS;1065 if ( ( paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV1066 && &paVarDescs[iVarDesc - 1] != pPrevDesc)1067 || cCurDesc >= paVarDescs[iVarDesc].cTimesMax)1068 {1069 iVarDesc++;1070 if (iVarDesc >= cVarDescs)1071 return VERR_PARSE_TOO_MANY_ARGUMENTS;1072 cCurDesc = 0;1073 }1074 1075 /*1076 * Skip thru optional arguments until we find something which matches1077 * or can easily be promoted to what the descriptor want.1078 */1079 for (;;)1080 {1081 int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);1082 if (VBOX_SUCCESS(rc))1083 {1084 paVars[iVar].pDesc = &paVarDescs[iVarDesc];1085 cCurDesc++;1086 break;1087 }1088 1089 /* can we advance? */1090 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)1091 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;1092 if (++iVarDesc >= cVarDescs)1093 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;1094 cCurDesc = 0;1095 }1096 1097 /* next var */1098 iVar++;1099 }1100 1101 /*1102 * Check that the rest of the descriptors are optional.1103 */1104 while (iVarDesc < cVarDescs)1105 {1106 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)1107 return VERR_PARSE_TOO_FEW_ARGUMENTS;1108 cCurDesc = 0;1109 1110 /* next */1111 iVarDesc++;1112 }1113 1114 return 0;1115 }1116 1117 1118 /**1119 * Evaluates one argument with respect to unary operators.1120 *1121 * @returns 0 on success. pResult contains the result.1122 * @returns VBox error code on parse or other evaluation error.1123 *1124 * @param pDbgc Debugger console instance data.1125 * @param pszExpr The expression string.1126 * @param pResult Where to store the result of the expression evaluation.1127 */1128 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)1129 {1130 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));1131 1132 /*1133 * The state of the expression is now such that it will start by zero or more1134 * unary operators and being followed by an expression of some kind.1135 * The expression is either plain or in parenthesis.1136 *1137 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)1138 * ASSUME: unary operators are all of equal precedence.1139 */1140 int rc = 0;1141 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');1142 if (pOp)1143 {1144 /* binary operators means syntax error. */1145 if (pOp->fBinary)1146 return VERR_PARSE_UNEXPECTED_OPERATOR;1147 1148 /*1149 * If the next expression (the one following the unary operator) is in a1150 * parenthesis a full eval is needed. If not the unary eval will suffice.1151 */1152 /* calc and strip next expr. */1153 char *pszExpr2 = pszExpr + pOp->cchName;1154 while (isblank(*pszExpr2))1155 pszExpr2++;1156 1157 if (!*pszExpr2)1158 rc = VERR_PARSE_EMPTY_ARGUMENT;1159 else1160 {1161 DBGCVAR Arg;1162 if (*pszExpr2 == '(')1163 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);1164 else1165 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);1166 if (VBOX_SUCCESS(rc))1167 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);1168 }1169 }1170 else1171 {1172 /*1173 * Didn't find any operators, so it we have to check if this can be an1174 * function call before assuming numeric or string expression.1175 *1176 * (ASSUMPTIONS:)1177 * A function name only contains alphanumerical chars and it can not start1178 * with a numerical character.1179 * Immediately following the name is a parenthesis which must over1180 * the remaining part of the expression.1181 */1182 bool fExternal = *pszExpr == '.';1183 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;1184 char *pszFunEnd = NULL;1185 if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))1186 {1187 pszFunEnd = pszExpr + 1;1188 while (*pszFunEnd != '(' && isalnum(*pszFunEnd))1189 pszFunEnd++;1190 if (*pszFunEnd != '(')1191 pszFunEnd = NULL;1192 }1193 1194 if (pszFunEnd)1195 {1196 /*1197 * Ok, it's a function call.1198 */1199 if (fExternal)1200 pszExpr++, cchExpr--;1201 PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);1202 if (!pFun)1203 return VERR_PARSE_FUNCTION_NOT_FOUND;1204 if (!pFun->pResultDesc)1205 return VERR_PARSE_NOT_A_FUNCTION;1206 1207 /*1208 * Parse the expression in parenthesis.1209 */1210 cchExpr -= pszFunEnd - pszExpr;1211 pszExpr = pszFunEnd;1212 /** @todo implement multiple arguments. */1213 DBGCVAR Arg;1214 rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);1215 if (!rc)1216 {1217 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);1218 if (!rc)1219 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);1220 }1221 else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)1222 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);1223 }1224 else1225 {1226 /*1227 * Didn't find any operators, so it must be a plain expression.1228 * This might be numeric or a string expression.1229 */1230 char ch = pszExpr[0];1231 char ch2 = pszExpr[1];1232 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))1233 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);1234 else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))1235 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);1236 else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))1237 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);1238 /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.1239 //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))1240 // rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);1241 else1242 {1243 /*1244 * Hexadecimal number or a string?1245 */1246 char *psz = pszExpr;1247 while (isxdigit(*psz))1248 psz++;1249 if (!*psz)1250 rc = dbgcEvalSubNum(pszExpr, 16, pResult);1251 else if ((*psz == 'h' || *psz == 'H') && !psz[1])1252 {1253 *psz = '\0';1254 rc = dbgcEvalSubNum(pszExpr, 16, pResult);1255 }1256 else1257 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);1258 }1259 }1260 }1261 1262 return rc;1263 }1264 1265 1266 /**1267 * Evaluates one argument.1268 *1269 * @returns 0 on success. pResult contains the result.1270 * @returns VBox error code on parse or other evaluation error.1271 *1272 * @param pDbgc Debugger console instance data.1273 * @param pszExpr The expression string.1274 * @param pResult Where to store the result of the expression evaluation.1275 */1276 int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)1277 {1278 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));1279 /*1280 * First we need to remove blanks in both ends.1281 * ASSUMES: There is no quoting unless the entire expression is a string.1282 */1283 1284 /* stripping. */1285 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))1286 pszExpr[--cchExpr] = '\0';1287 while (isblank(*pszExpr))1288 pszExpr++, cchExpr--;1289 if (!*pszExpr)1290 return VERR_PARSE_EMPTY_ARGUMENT;1291 1292 /* it there is any kind of quoting in the expression, it's string meat. */1293 if (strpbrk(pszExpr, "\"'`"))1294 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);1295 1296 /*1297 * Check if there are any parenthesis which needs removing.1298 */1299 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')1300 {1301 do1302 {1303 unsigned cPar = 1;1304 char *psz = pszExpr + 1;1305 char ch;1306 while ((ch = *psz) != '\0')1307 {1308 if (ch == '(')1309 cPar++;1310 else if (ch == ')')1311 {1312 if (cPar <= 0)1313 return VERR_PARSE_UNBALANCED_PARENTHESIS;1314 cPar--;1315 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */1316 break;1317 }1318 /* next */1319 psz++;1320 }1321 if (ch)1322 break;1323 1324 /* remove the parenthesis. */1325 pszExpr++;1326 cchExpr -= 2;1327 pszExpr[cchExpr] = '\0';1328 1329 /* strip blanks. */1330 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))1331 pszExpr[--cchExpr] = '\0';1332 while (isblank(*pszExpr))1333 pszExpr++, cchExpr--;1334 if (!*pszExpr)1335 return VERR_PARSE_EMPTY_ARGUMENT;1336 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');1337 }1338 1339 /* tabs to spaces. */1340 char *psz = pszExpr;1341 while ((psz = strchr(psz, '\t')) != NULL)1342 *psz = ' ';1343 1344 /*1345 * Now, we need to look for the binary operator with the lowest precedence.1346 *1347 * If there are no operators we're left with a simple expression which we1348 * evaluate with respect to unary operators1349 */1350 char *pszOpSplit = NULL;1351 PCDBGCOP pOpSplit = NULL;1352 unsigned cBinaryOps = 0;1353 unsigned cPar = 0;1354 char ch;1355 char chPrev = ' ';1356 bool fBinary = false;1357 psz = pszExpr;1358 1359 while ((ch = *psz) != '\0')1360 {1361 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));1362 /*1363 * Parenthesis.1364 */1365 if (ch == '(')1366 {1367 cPar++;1368 fBinary = false;1369 }1370 else if (ch == ')')1371 {1372 if (cPar <= 0)1373 return VERR_PARSE_UNBALANCED_PARENTHESIS;1374 cPar--;1375 fBinary = true;1376 }1377 /*1378 * Potential operator.1379 */1380 else if (cPar == 0 && !isblank(ch))1381 {1382 PCDBGCOP pOp = dbgcIsOpChar(ch)1383 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)1384 : NULL;1385 if (pOp)1386 {1387 /* If not the right kind of operator we've got a syntax error. */1388 if (pOp->fBinary != fBinary)1389 return VERR_PARSE_UNEXPECTED_OPERATOR;1390 1391 /*1392 * Update the parse state and skip the operator.1393 */1394 if (!pOpSplit)1395 {1396 pOpSplit = pOp;1397 pszOpSplit = psz;1398 cBinaryOps = fBinary;1399 }1400 else if (fBinary)1401 {1402 cBinaryOps++;1403 if (pOp->iPrecedence >= pOpSplit->iPrecedence)1404 {1405 pOpSplit = pOp;1406 pszOpSplit = psz;1407 }1408 }1409 1410 psz += pOp->cchName - 1;1411 fBinary = false;1412 }1413 else1414 fBinary = true;1415 }1416 1417 /* next */1418 psz++;1419 chPrev = ch;1420 } /* parse loop. */1421 1422 1423 /*1424 * Either we found an operator to divide the expression by1425 * or we didn't find any. In the first case it's divide and1426 * conquer. In the latter it's a single expression which1427 * needs dealing with its unary operators if any.1428 */1429 int rc;1430 if ( cBinaryOps1431 && pOpSplit->fBinary)1432 {1433 /* process 1st sub expression. */1434 *pszOpSplit = '\0';1435 DBGCVAR Arg1;1436 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);1437 if (VBOX_SUCCESS(rc))1438 {1439 /* process 2nd sub expression. */1440 char *psz2 = pszOpSplit + pOpSplit->cchName;1441 DBGCVAR Arg2;1442 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);1443 if (VBOX_SUCCESS(rc))1444 /* apply the operator. */1445 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);1446 }1447 }1448 else if (cBinaryOps)1449 {1450 /* process sub expression. */1451 pszOpSplit += pOpSplit->cchName;1452 DBGCVAR Arg;1453 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);1454 if (VBOX_SUCCESS(rc))1455 /* apply the operator. */1456 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);1457 }1458 else1459 /* plain expression or using unary operators perhaps with paratheses. */1460 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);1461 1462 return rc;1463 }1464 1465 1466 /**1467 * Parses the arguments of one command.1468 *1469 * @returns 0 on success.1470 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.1471 * @param pDbgc Debugger console instance data.1472 * @param pCmd Pointer to the command descriptor.1473 * @param pszArg Pointer to the arguments to parse.1474 * @param paArgs Where to store the parsed arguments.1475 * @param cArgs Size of the paArgs array.1476 * @param pcArgs Where to store the number of arguments.1477 * In the event of an error this is used to store the index of the offending argument.1478 */1479 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)1480 {1481 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));1482 /*1483 * Check if we have any argument and if the command takes any.1484 */1485 *pcArgs = 0;1486 /* strip leading blanks. */1487 while (*pszArgs && isblank(*pszArgs))1488 pszArgs++;1489 if (!*pszArgs)1490 {1491 if (!pCmd->cArgsMin)1492 return 0;1493 return VERR_PARSE_TOO_FEW_ARGUMENTS;1494 }1495 /** @todo fixme - foo() doesn't work. */1496 if (!pCmd->cArgsMax)1497 return VERR_PARSE_TOO_MANY_ARGUMENTS;1498 1499 /*1500 * This is a hack, it's "temporary" and should go away "when" the parser is1501 * modified to match arguments while parsing.1502 */1503 if ( pCmd->cArgsMax == 11504 && pCmd->cArgsMin == 11505 && pCmd->cArgDescs == 11506 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING1507 && cArgs >= 1)1508 {1509 *pcArgs = 1;1510 RTStrStripR(pszArgs);1511 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);1512 }1513 1514 1515 /*1516 * The parse loop.1517 */1518 PDBGCVAR pArg0 = &paArgs[0];1519 PDBGCVAR pArg = pArg0;1520 *pcArgs = 0;1521 do1522 {1523 /*1524 * Can we have another argument?1525 */1526 if (*pcArgs >= pCmd->cArgsMax)1527 return VERR_PARSE_TOO_MANY_ARGUMENTS;1528 if (pArg >= &paArgs[cArgs])1529 return VERR_PARSE_ARGUMENT_OVERFLOW;1530 1531 /*1532 * Find the end of the argument.1533 */1534 int cPar = 0;1535 char chQuote = '\0';1536 char *pszEnd = NULL;1537 char *psz = pszArgs;1538 char ch;1539 bool fBinary = false;1540 for (;;)1541 {1542 /*1543 * Check for the end.1544 */1545 if ((ch = *psz) == '\0')1546 {1547 if (chQuote)1548 return VERR_PARSE_UNBALANCED_QUOTE;1549 if (cPar)1550 return VERR_PARSE_UNBALANCED_PARENTHESIS;1551 pszEnd = psz;1552 break;1553 }1554 /*1555 * When quoted we ignore everything but the quotation char.1556 * We use the REXX way of escaping the quotation char, i.e. double occurence.1557 */1558 else if (ch == '\'' || ch == '"' || ch == '`')1559 {1560 if (chQuote)1561 {1562 /* end quote? */1563 if (ch == chQuote)1564 {1565 if (psz[1] == ch)1566 psz++; /* skip the escaped quote char */1567 else1568 chQuote = '\0'; /* end of quoted string. */1569 }1570 }1571 else1572 chQuote = ch; /* open new quote */1573 }1574 /*1575 * Parenthesis can of course be nested.1576 */1577 else if (ch == '(')1578 {1579 cPar++;1580 fBinary = false;1581 }1582 else if (ch == ')')1583 {1584 if (!cPar)1585 return VERR_PARSE_UNBALANCED_PARENTHESIS;1586 cPar--;1587 fBinary = true;1588 }1589 else if (!chQuote && !cPar)1590 {1591 /*1592 * Encountering blanks may mean the end of it all. A binary operator1593 * will force continued parsing.1594 */1595 if (isblank(*psz))1596 {1597 pszEnd = psz++; /* just in case. */1598 while (isblank(*psz))1599 psz++;1600 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');1601 if (!pOp || pOp->fBinary != fBinary)1602 break; /* the end. */1603 psz += pOp->cchName;1604 while (isblank(*psz)) /* skip blanks so we don't get here again */1605 psz++;1606 fBinary = false;1607 continue;1608 }1609 1610 /*1611 * Look for operators without a space up front.1612 */1613 if (dbgcIsOpChar(*psz))1614 {1615 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');1616 if (pOp)1617 {1618 if (pOp->fBinary != fBinary)1619 {1620 pszEnd = psz;1621 /** @todo this is a parsing error really. */1622 break; /* the end. */1623 }1624 psz += pOp->cchName;1625 while (isblank(*psz)) /* skip blanks so we don't get here again */1626 psz++;1627 fBinary = false;1628 continue;1629 }1630 }1631 fBinary = true;1632 }1633 1634 /* next char */1635 psz++;1636 }1637 *pszEnd = '\0';1638 /* (psz = next char to process) */1639 1640 /*1641 * Parse and evaluate the argument.1642 */1643 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);1644 if (VBOX_FAILURE(rc))1645 return rc;1646 1647 /*1648 * Next.1649 */1650 pArg++;1651 (*pcArgs)++;1652 pszArgs = psz;1653 while (*pszArgs && isblank(*pszArgs))1654 pszArgs++;1655 } while (*pszArgs);1656 1657 /*1658 * Match the arguments.1659 */1660 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);1661 }1662 1663 1664 /**1665 * Process one command.1666 *1667 * @returns VBox status code. Any error indicates the termination of the console session.1668 * @param pDbgc Debugger console instance data.1669 * @param pszCmd Pointer to the command.1670 * @param cchCmd Length of the command.1671 */1672 int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)1673 {1674 char *pszCmdInput = pszCmd;1675 1676 /*1677 * Skip blanks.1678 */1679 while (isblank(*pszCmd))1680 pszCmd++, cchCmd--;1681 1682 /* external command? */1683 bool fExternal = *pszCmd == '.';1684 if (fExternal)1685 pszCmd++, cchCmd--;1686 1687 /*1688 * Find arguments.1689 */1690 char *pszArgs = pszCmd;1691 while (isalnum(*pszArgs))1692 pszArgs++;1693 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))1694 {1695 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);1696 return 0;1697 }1698 1699 /*1700 * Find the command.1701 */1702 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);1703 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))1704 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);1705 1706 /*1707 * Parse arguments (if any).1708 */1709 unsigned cArgs;1710 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);1711 1712 /*1713 * Execute the command.1714 */1715 if (!rc)1716 {1717 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);1718 }1719 else1720 {1721 /* report parse / eval error. */1722 switch (rc)1723 {1724 case VERR_PARSE_TOO_FEW_ARGUMENTS:1725 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1726 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);1727 break;1728 case VERR_PARSE_TOO_MANY_ARGUMENTS:1729 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1730 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);1731 break;1732 case VERR_PARSE_ARGUMENT_OVERFLOW:1733 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1734 "Syntax error: Too many arguments.\n");1735 break;1736 case VERR_PARSE_UNBALANCED_QUOTE:1737 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1738 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);1739 break;1740 case VERR_PARSE_UNBALANCED_PARENTHESIS:1741 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1742 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);1743 break;1744 case VERR_PARSE_EMPTY_ARGUMENT:1745 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1746 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);1747 break;1748 case VERR_PARSE_UNEXPECTED_OPERATOR:1749 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1750 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);1751 break;1752 case VERR_PARSE_INVALID_NUMBER:1753 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1754 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);1755 break;1756 case VERR_PARSE_NUMBER_TOO_BIG:1757 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1758 "Error: Numeric overflow (argument %d).\n", cArgs);1759 break;1760 case VERR_PARSE_INVALID_OPERATION:1761 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1762 "Error: Invalid operation attempted (argument %d).\n", cArgs);1763 break;1764 case VERR_PARSE_FUNCTION_NOT_FOUND:1765 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1766 "Error: Function not found (argument %d).\n", cArgs);1767 break;1768 case VERR_PARSE_NOT_A_FUNCTION:1769 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1770 "Error: The function specified is not a function (argument %d).\n", cArgs);1771 break;1772 case VERR_PARSE_NO_MEMORY:1773 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1774 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);1775 break;1776 case VERR_PARSE_INCORRECT_ARG_TYPE:1777 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1778 "Error: Incorrect argument type (argument %d?).\n", cArgs);1779 break;1780 case VERR_PARSE_VARIABLE_NOT_FOUND:1781 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1782 "Error: An undefined variable was referenced (argument %d).\n", cArgs);1783 break;1784 case VERR_PARSE_CONVERSION_FAILED:1785 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1786 "Error: A conversion between two types failed (argument %d).\n", cArgs);1787 break;1788 case VERR_PARSE_NOT_IMPLEMENTED:1789 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1790 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);1791 break;1792 case VERR_PARSE_BAD_RESULT_TYPE:1793 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1794 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);1795 break;1796 case VERR_PARSE_WRITEONLY_SYMBOL:1797 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1798 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);1799 break;1800 1801 default:1802 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,1803 "Error: Unknown error %d!\n", rc);1804 return rc;1805 }1806 1807 /*1808 * Parse errors are non fatal.1809 */1810 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)1811 rc = 0;1812 }1813 1814 return rc;1815 }1816 1817 1818 /**1819 * Process all commands current in the buffer.1820 *1821 * @returns VBox status code. Any error indicates the termination of the console session.1822 * @param pDbgc Debugger console instance data.1823 */1824 static int dbgcProcessCommands(PDBGC pDbgc)1825 {1826 int rc = 0;1827 while (pDbgc->cInputLines)1828 {1829 /*1830 * Empty the log buffer if we're hooking the log.1831 */1832 if (pDbgc->fLog)1833 {1834 rc = dbgcProcessLog(pDbgc);1835 if (VBOX_FAILURE(rc))1836 break;1837 }1838 1839 if (pDbgc->iRead == pDbgc->iWrite)1840 {1841 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));1842 pDbgc->cInputLines = 0;1843 return 0;1844 }1845 1846 /*1847 * Copy the command to the parse buffer.1848 */1849 char ch;1850 char *psz = &pDbgc->achInput[pDbgc->iRead];1851 char *pszTrg = &pDbgc->achScratch[0];1852 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )1853 {1854 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])1855 psz = &pDbgc->achInput[0];1856 1857 if (psz == &pDbgc->achInput[pDbgc->iWrite])1858 {1859 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));1860 pDbgc->cInputLines = 0;1861 return 0;1862 }1863 1864 pszTrg++;1865 }1866 *pszTrg = '\0';1867 1868 /*1869 * Advance the buffer.1870 */1871 pDbgc->iRead = psz - &pDbgc->achInput[0];1872 if (ch == '\n')1873 pDbgc->cInputLines--;1874 1875 /*1876 * Parse and execute this command.1877 */1878 pDbgc->pszScratch = psz;1879 pDbgc->iArg = 0;1880 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);1881 if (rc)1882 break;1883 }1884 1885 return rc;1886 }1887 1888 1889 /**1890 * Reads input, parses it and executes commands on '\n'.1891 *1892 * @returns VBox status.1893 * @param pDbgc Debugger console instance data.1894 */1895 static int dbgcProcessInput(PDBGC pDbgc)1896 {1897 /*1898 * We know there's input ready, so let's read it first.1899 */1900 int rc = dbgcInputRead(pDbgc);1901 if (VBOX_FAILURE(rc))1902 return rc;1903 1904 /*1905 * Now execute any ready commands.1906 */1907 if (pDbgc->cInputLines)1908 {1909 /** @todo this fReady stuff is broken. */1910 pDbgc->fReady = false;1911 rc = dbgcProcessCommands(pDbgc);1912 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)1913 pDbgc->fReady = true;1914 if ( VBOX_SUCCESS(rc)1915 && pDbgc->iRead == pDbgc->iWrite1916 && pDbgc->fReady)1917 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");1918 }1919 1920 return rc;1921 }1922 1923 1924 /**1925 * Gets the event context identifier string.1926 * @returns Read only string.1927 * @param enmCtx The context.1928 */1929 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)1930 {1931 switch (enmCtx)1932 {1933 case DBGFEVENTCTX_RAW: return "raw";1934 case DBGFEVENTCTX_REM: return "rem";1935 case DBGFEVENTCTX_HWACCL: return "hwaccl";1936 case DBGFEVENTCTX_HYPER: return "hyper";1937 case DBGFEVENTCTX_OTHER: return "other";1938 1939 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";1940 default:1941 AssertMsgFailed(("enmCtx=%d\n", enmCtx));1942 return "!Unknown Event Ctx!";1943 }1944 }1945 1946 1947 /**1948 * Processes debugger events.1949 *1950 * @returns VBox status.1951 * @param pDbgc DBGC Instance data.1952 * @param pEvent Pointer to event data.1953 */1954 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)1955 {1956 /*1957 * Flush log first.1958 */1959 if (pDbgc->fLog)1960 {1961 int rc = dbgcProcessLog(pDbgc);1962 if (VBOX_FAILURE(rc))1963 return rc;1964 }1965 1966 /*1967 * Process the event.1968 */1969 pDbgc->pszScratch = &pDbgc->achInput[0];1970 pDbgc->iArg = 0;1971 bool fPrintPrompt = true;1972 int rc = VINF_SUCCESS;1973 switch (pEvent->enmType)1974 {1975 /*1976 * The first part is events we have initiated with commands.1977 */1978 case DBGFEVENT_HALT_DONE:1979 {1980 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",1981 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));1982 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */1983 if (VBOX_SUCCESS(rc))1984 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");1985 break;1986 }1987 1988 1989 /*1990 * The second part is events which can occur at any time.1991 */1992 case DBGFEVENT_FATAL_ERROR:1993 {1994 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",1995 dbgcGetEventCtx(pEvent->enmCtx));1996 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */1997 if (VBOX_SUCCESS(rc))1998 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");1999 break;2000 }2001 2002 case DBGFEVENT_BREAKPOINT:2003 case DBGFEVENT_BREAKPOINT_HYPER:2004 {2005 bool fRegCtxGuest = pDbgc->fRegCtxGuest;2006 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;2007 2008 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);2009 switch (rc)2010 {2011 case VERR_DBGC_BP_NOT_FOUND:2012 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",2013 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));2014 break;2015 2016 case VINF_DBGC_BP_NO_COMMAND:2017 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",2018 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));2019 break;2020 2021 case VINF_BUFFER_OVERFLOW:2022 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",2023 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));2024 break;2025 2026 default:2027 break;2028 }2029 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))2030 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");2031 else2032 pDbgc->fRegCtxGuest = fRegCtxGuest;2033 break;2034 }2035 2036 case DBGFEVENT_STEPPED:2037 case DBGFEVENT_STEPPED_HYPER:2038 {2039 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;2040 2041 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));2042 if (VBOX_SUCCESS(rc))2043 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");2044 break;2045 }2046 2047 case DBGFEVENT_ASSERTION_HYPER:2048 {2049 pDbgc->fRegCtxGuest = false;2050 2051 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,2052 "\ndbgf event: Hypervisor Assertion! (%s)\n"2053 "%s"2054 "%s"2055 "\n",2056 dbgcGetEventCtx(pEvent->enmCtx),2057 pEvent->u.Assert.pszMsg1,2058 pEvent->u.Assert.pszMsg2);2059 if (VBOX_SUCCESS(rc))2060 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");2061 break;2062 }2063 2064 case DBGFEVENT_DEV_STOP:2065 {2066 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,2067 "\n"2068 "dbgf event: DBGFSTOP (%s)\n"2069 "File: %s\n"2070 "Line: %d\n"2071 "Function: %s\n",2072 dbgcGetEventCtx(pEvent->enmCtx),2073 pEvent->u.Src.pszFile,2074 pEvent->u.Src.uLine,2075 pEvent->u.Src.pszFunction);2076 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)2077 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,2078 "Message: %s\n",2079 pEvent->u.Src.pszMessage);2080 if (VBOX_SUCCESS(rc))2081 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");2082 break;2083 }2084 2085 2086 case DBGFEVENT_INVALID_COMMAND:2087 {2088 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");2089 fPrintPrompt = !pDbgc->fReady;2090 break;2091 }2092 2093 case DBGFEVENT_TERMINATING:2094 {2095 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");2096 rc = VERR_GENERAL_FAILURE;2097 break;2098 }2099 2100 2101 default:2102 {2103 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);2104 fPrintPrompt = !pDbgc->fReady;2105 break;2106 }2107 }2108 2109 /*2110 * Prompt, anyone?2111 */2112 if (fPrintPrompt && VBOX_SUCCESS(rc))2113 {2114 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");2115 }2116 2117 return rc;2118 }2119 2120 2121 2122 2123 2124 /**2125 * Make a console instance.2126 *2127 * This will not return until either an 'exit' command is issued or a error code2128 * indicating connection loss is encountered.2129 *2130 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.2131 * @returns The VBox status code causing the console termination.2132 *2133 * @param pVM VM Handle.2134 * @param pBack Pointer to the backend structure. This must contain2135 * a full set of function pointers to service the console.2136 * @param fFlags Reserved, must be zero.2137 * @remark A forced termination of the console is easiest done by forcing the2138 * callbacks to return fatal failures.2139 */2140 DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)2141 {2142 /*2143 * Validate input.2144 */2145 AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);2146 AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);2147 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);2148 2149 /*2150 * Allocate and initialize instance data2151 */2152 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));2153 if (!pDbgc)2154 return VERR_NO_MEMORY;2155 2156 dbgcInitCmdHlp(pDbgc);2157 pDbgc->pBack = pBack;2158 pDbgc->pVM = NULL;2159 pDbgc->pszEmulation = "CodeView/WinDbg";2160 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];2161 pDbgc->cEmulationCmds = g_cCmdsCodeView;2162 //pDbgc->fLog = false;2163 pDbgc->fRegCtxGuest = true;2164 pDbgc->fRegTerse = true;2165 //pDbgc->DisasmPos = {0};2166 //pDbgc->SourcePos = {0};2167 //pDbgc->DumpPos = {0};2168 //pDbgc->cbDumpElement = 0;2169 //pDbgc->cVars = 0;2170 //pDbgc->paVars = NULL;2171 //pDbgc->pFirstBp = NULL;2172 //pDbgc->uInputZero = 0;2173 //pDbgc->iRead = 0;2174 //pDbgc->iWrite = 0;2175 //pDbgc->cInputLines = 0;2176 //pDbgc->fInputOverflow = false;2177 pDbgc->fReady = true;2178 pDbgc->pszScratch = &pDbgc->achScratch[0];2179 //pDbgc->iArg = 0;2180 //pDbgc->rcOutput = 0;2181 2182 dbgcInitOpCharBitMap();2183 2184 /*2185 * Print welcome message.2186 */2187 int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,2188 "Welcome to the VirtualBox Debugger!\n");2189 if (VBOX_FAILURE(rc))2190 goto l_failure;2191 2192 /*2193 * Attach to the VM.2194 */2195 rc = DBGFR3Attach(pVM);2196 if (VBOX_FAILURE(rc))2197 {2198 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);2199 goto l_failure;2200 }2201 pDbgc->pVM = pVM;2202 2203 /*2204 * Print commandline and auto select result.2205 */2206 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,2207 "Current VM is %08x\n" /** @todo get and print the VM name! */2208 "VBoxDbg> ",2209 pDbgc->pVM);2210 if (VBOX_FAILURE(rc))2211 goto l_failure;2212 2213 /*2214 * Main Debugger Loop.2215 *2216 * This loop will either block on waiting for input or on waiting on2217 * debug events. If we're forwarding the log we cannot wait for long2218 * before we must flush the log.2219 */2220 for (rc = 0;;)2221 {2222 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))2223 {2224 /*2225 * Wait for a debug event.2226 */2227 PCDBGFEVENT pEvent;2228 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);2229 if (VBOX_SUCCESS(rc))2230 {2231 rc = dbgcProcessEvent(pDbgc, pEvent);2232 if (VBOX_FAILURE(rc))2233 break;2234 }2235 else if (rc != VERR_TIMEOUT)2236 break;2237 2238 /*2239 * Check for input.2240 */2241 if (pBack->pfnInput(pDbgc->pBack, 0))2242 {2243 rc = dbgcProcessInput(pDbgc);2244 if (VBOX_FAILURE(rc))2245 break;2246 }2247 }2248 else2249 {2250 /*2251 * Wait for input. If Logging is enabled we'll only wait very briefly.2252 */2253 if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))2254 {2255 rc = dbgcProcessInput(pDbgc);2256 if (VBOX_FAILURE(rc))2257 break;2258 }2259 }2260 2261 /*2262 * Forward log output.2263 */2264 if (pDbgc->fLog)2265 {2266 rc = dbgcProcessLog(pDbgc);2267 if (VBOX_FAILURE(rc))2268 break;2269 }2270 }2271 2272 2273 l_failure:2274 /*2275 * Cleanup console debugger session.2276 */2277 /* Disable log hook. */2278 if (pDbgc->fLog)2279 {2280 2281 }2282 2283 /* Detach from the VM. */2284 if (pDbgc->pVM)2285 DBGFR3Detach(pDbgc->pVM);2286 2287 /* finally, free the instance memory. */2288 RTMemFree(pDbgc);2289 2290 return rc;2291 }2292 -
trunk/src/VBox/Debugger/DBGConsole.cpp
r5676 r5677 136 136 137 137 138 139 140 141 142 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 143 // 144 // 145 // V a r i a b l e M a n i p u l a t i o n 146 // 147 // 148 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 149 150 151 152 /** @todo move me!*/ 153 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat) 138 /** 139 * Initalizes g_bmOperatorChars. 140 */ 141 static void dbgcInitOpCharBitMap(void) 154 142 { 155 if (pVar) 156 { 157 pVar->enmType = DBGCVAR_TYPE_GC_FLAT; 158 pVar->u.GCFlat = GCFlat; 159 pVar->enmRangeType = DBGCVAR_RANGE_NONE; 160 pVar->u64Range = 0; 161 } 143 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars)); 144 for (unsigned iOp = 0; iOp < g_cOps; iOp++) 145 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]); 162 146 } 163 147 164 148 165 /** @todo move me!*/ 166 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb) 149 /** 150 * Checks whether the character may be the start of an operator. 151 * 152 * @returns true/false. 153 * @param ch The character. 154 */ 155 DECLINLINE(bool) dbgcIsOpChar(char ch) 167 156 { 168 if (pVar) 169 { 170 pVar->enmType = DBGCVAR_TYPE_GC_FLAT; 171 pVar->u.GCFlat = GCFlat; 172 pVar->enmRangeType = DBGCVAR_RANGE_BYTES; 173 pVar->u64Range = cb; 174 } 157 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch); 175 158 } 176 177 178 /** @todo move me!*/179 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)180 {181 if (pVar)182 {183 if (pVar2)184 *pVar = *pVar2;185 else186 {187 pVar->enmType = DBGCVAR_TYPE_UNKNOWN;188 memset(&pVar->u, 0, sizeof(pVar->u));189 pVar->enmRangeType = DBGCVAR_RANGE_NONE;190 pVar->u64Range = 0;191 }192 }193 }194 195 196 /** @todo move me!*/197 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)198 {199 if (pVar)200 {201 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;202 pVar->u64Range = cb;203 }204 }205 206 207 /** @todo move me!*/208 void dbgcVarSetNoRange(PDBGCVAR pVar)209 {210 if (pVar)211 {212 pVar->enmRangeType = DBGCVAR_RANGE_NONE;213 pVar->u64Range = 0;214 }215 }216 217 218 /**219 * Converts a DBGC variable to a DBGF address.220 *221 * @returns VBox status code.222 * @param pDbgc The DBGC instance.223 * @param pVar The variable.224 * @param pAddress Where to store the address.225 */226 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)227 {228 AssertReturn(pVar, VERR_INVALID_PARAMETER);229 switch (pVar->enmType)230 {231 case DBGCVAR_TYPE_GC_FLAT:232 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);233 return VINF_SUCCESS;234 235 case DBGCVAR_TYPE_NUMBER:236 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);237 return VINF_SUCCESS;238 239 case DBGCVAR_TYPE_GC_FAR:240 return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);241 242 case DBGCVAR_TYPE_STRING:243 case DBGCVAR_TYPE_SYMBOL:244 {245 DBGCVAR Var;246 int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);247 if (VBOX_FAILURE(rc))248 return rc;249 return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);250 }251 252 case DBGCVAR_TYPE_GC_PHYS:253 case DBGCVAR_TYPE_HC_FLAT:254 case DBGCVAR_TYPE_HC_FAR:255 case DBGCVAR_TYPE_HC_PHYS:256 default:257 return VERR_PARSE_CONVERSION_FAILED;258 }259 }260 261 262 263 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//264 //265 //266 // B r e a k p o i n t M a n a g e m e n t267 //268 //269 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//270 271 272 /**273 * Adds a breakpoint to the DBGC breakpoint list.274 */275 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)276 {277 /*278 * Check if it already exists.279 */280 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);281 if (pBp)282 return VERR_DBGC_BP_EXISTS;283 284 /*285 * Add the breakpoint.286 */287 if (pszCmd)288 pszCmd = RTStrStripL(pszCmd);289 size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;290 pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));291 if (!pBp)292 return VERR_NO_MEMORY;293 if (cchCmd)294 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);295 else296 pBp->szCmd[0] = '\0';297 pBp->cchCmd = cchCmd;298 pBp->iBp = iBp;299 pBp->pNext = pDbgc->pFirstBp;300 pDbgc->pFirstBp = pBp;301 302 return VINF_SUCCESS;303 }304 305 /**306 * Updates the a breakpoint.307 *308 * @returns VBox status code.309 * @param pDbgc The DBGC instance.310 * @param iBp The breakpoint to update.311 * @param pszCmd The new command.312 */313 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)314 {315 /*316 * Find the breakpoint.317 */318 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);319 if (!pBp)320 return VERR_DBGC_BP_NOT_FOUND;321 322 /*323 * Do we need to reallocate?324 */325 if (pszCmd)326 pszCmd = RTStrStripL(pszCmd);327 if (!pszCmd || !*pszCmd)328 pBp->szCmd[0] = '\0';329 else330 {331 size_t cchCmd = strlen(pszCmd);332 if (strlen(pBp->szCmd) >= cchCmd)333 {334 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);335 pBp->cchCmd = cchCmd;336 }337 else338 {339 /*340 * Yes, let's do it the simple way...341 */342 int rc = dbgcBpDelete(pDbgc, iBp);343 AssertRC(rc);344 return dbgcBpAdd(pDbgc, iBp, pszCmd);345 }346 }347 return VINF_SUCCESS;348 }349 350 351 /**352 * Deletes a breakpoint.353 *354 * @returns VBox status code.355 * @param pDbgc The DBGC instance.356 * @param iBp The breakpoint to delete.357 */358 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)359 {360 /*361 * Search thru the list, when found unlink and free it.362 */363 PDBGCBP pBpPrev = NULL;364 PDBGCBP pBp = pDbgc->pFirstBp;365 for (; pBp; pBp = pBp->pNext)366 {367 if (pBp->iBp == iBp)368 {369 if (pBpPrev)370 pBpPrev->pNext = pBp->pNext;371 else372 pDbgc->pFirstBp = pBp->pNext;373 RTMemFree(pBp);374 return VINF_SUCCESS;375 }376 pBpPrev = pBp;377 }378 379 return VERR_DBGC_BP_NOT_FOUND;380 }381 382 383 /**384 * Get a breakpoint.385 *386 * @returns Pointer to the breakpoint.387 * @returns NULL if the breakpoint wasn't found.388 * @param pDbgc The DBGC instance.389 * @param iBp The breakpoint to get.390 */391 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)392 {393 /*394 * Enumerate the list.395 */396 PDBGCBP pBp = pDbgc->pFirstBp;397 for (; pBp; pBp = pBp->pNext)398 if (pBp->iBp == iBp)399 return pBp;400 return NULL;401 }402 403 404 /**405 * Executes the command of a breakpoint.406 *407 * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.408 * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.409 * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.410 * @returns VBox status code from dbgcProcessCommand() other wise.411 * @param pDbgc The DBGC instance.412 * @param iBp The breakpoint to execute.413 */414 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)415 {416 /*417 * Find the breakpoint.418 */419 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);420 if (!pBp)421 return VERR_DBGC_BP_NOT_FOUND;422 423 /*424 * Anything to do?425 */426 if (!pBp->cchCmd)427 return VINF_DBGC_BP_NO_COMMAND;428 429 /*430 * Execute the command.431 * This means copying it to the scratch buffer and process it as if it432 * were user input. We must save and restore the state of the scratch buffer.433 */434 /* Save the scratch state. */435 char *pszScratch = pDbgc->pszScratch;436 unsigned iArg = pDbgc->iArg;437 438 /* Copy the command to the scratch buffer. */439 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);440 if (pBp->cchCmd >= cbScratch)441 return VERR_BUFFER_OVERFLOW;442 memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);443 444 /* Execute the command. */445 pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;446 int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);447 448 /* Restore the scratch state. */449 pDbgc->iArg = iArg;450 pDbgc->pszScratch = pszScratch;451 452 return rc;453 }454 455 456 457 458 459 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//460 //461 //462 // I n p u t , p a r s i n g a n d l o g g i n g463 //464 //465 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//466 467 159 468 160 … … 715 407 716 408 return VERR_PARSE_NOT_IMPLEMENTED; 717 }718 719 720 /**721 * Initalizes g_bmOperatorChars.722 */723 static void dbgcInitOpCharBitMap(void)724 {725 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));726 for (unsigned iOp = 0; iOp < g_cOps; iOp++)727 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);728 }729 730 731 /**732 * Checks whether the character may be the start of an operator.733 *734 * @returns true/false.735 * @param ch The character.736 */737 DECLINLINE(bool) dbgcIsOpChar(char ch)738 {739 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);740 409 } 741 410 -
trunk/src/VBox/Debugger/Makefile.kmk
r5676 r5677 38 38 DBGCBuiltInSymbols.cpp \ 39 39 DBGCCmdHlp.cpp \ 40 DBGCCmdWorkers.cpp \ 40 41 DBGCCommands.cpp \ 41 42 DBGCEmulateCodeView.cpp \ … … 104 105 DBGCBuiltInSymbols.cpp \ 105 106 DBGCCmdHlp.cpp \ 107 DBGCCmdWorkers.cpp \ 106 108 DBGCCommands.cpp \ 107 109 DBGCEmulateCodeView.cpp \
Note:
See TracChangeset
for help on using the changeset viewer.