Changeset 5676 in vbox
- Timestamp:
- Nov 11, 2007 5:50:06 AM (17 years ago)
- Location:
- trunk/src/VBox/Debugger
- Files:
-
- 3 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGCCmdHlp.cpp
r5675 r5676 1 1 /** $Id$ */ 2 2 /** @file 3 * DBGC - Debugger Console .3 * DBGC - Debugger Console, Command Helpers. 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 * Internal Functions *132 *******************************************************************************/133 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);134 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);135 136 137 /*******************************************************************************138 * Global Variables *139 *******************************************************************************/140 /** Bitmap where set bits indicates the characters the may start an operator name. */141 static uint32_t g_bmOperatorChars[256 / (4*8)];142 143 144 145 146 147 148 149 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//150 //151 //152 // C a l l b a c k H e l p e r s153 //154 //155 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//156 41 157 42 … … 762 647 763 648 764 765 766 767 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 768 // 769 // 770 // V a r i a b l e M a n i p u l a t i o n 771 // 772 // 773 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 774 775 776 777 /** @todo move me!*/ 778 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat) 779 { 780 if (pVar) 781 { 782 pVar->enmType = DBGCVAR_TYPE_GC_FLAT; 783 pVar->u.GCFlat = GCFlat; 784 pVar->enmRangeType = DBGCVAR_RANGE_NONE; 785 pVar->u64Range = 0; 786 } 787 } 788 789 790 /** @todo move me!*/ 791 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb) 792 { 793 if (pVar) 794 { 795 pVar->enmType = DBGCVAR_TYPE_GC_FLAT; 796 pVar->u.GCFlat = GCFlat; 797 pVar->enmRangeType = DBGCVAR_RANGE_BYTES; 798 pVar->u64Range = cb; 799 } 800 } 801 802 803 /** @todo move me!*/ 804 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2) 805 { 806 if (pVar) 807 { 808 if (pVar2) 809 *pVar = *pVar2; 810 else 811 { 812 pVar->enmType = DBGCVAR_TYPE_UNKNOWN; 813 memset(&pVar->u, 0, sizeof(pVar->u)); 814 pVar->enmRangeType = DBGCVAR_RANGE_NONE; 815 pVar->u64Range = 0; 816 } 817 } 818 } 819 820 821 /** @todo move me!*/ 822 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb) 823 { 824 if (pVar) 825 { 826 pVar->enmRangeType = DBGCVAR_RANGE_BYTES; 827 pVar->u64Range = cb; 828 } 829 } 830 831 832 /** @todo move me!*/ 833 void dbgcVarSetNoRange(PDBGCVAR pVar) 834 { 835 if (pVar) 836 { 837 pVar->enmRangeType = DBGCVAR_RANGE_NONE; 838 pVar->u64Range = 0; 839 } 840 } 841 842 843 /** 844 * Converts a DBGC variable to a DBGF address. 845 * 846 * @returns VBox status code. 847 * @param pDbgc The DBGC instance. 848 * @param pVar The variable. 849 * @param pAddress Where to store the address. 850 */ 851 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress) 852 { 853 AssertReturn(pVar, VERR_INVALID_PARAMETER); 854 switch (pVar->enmType) 855 { 856 case DBGCVAR_TYPE_GC_FLAT: 857 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat); 858 return VINF_SUCCESS; 859 860 case DBGCVAR_TYPE_NUMBER: 861 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number); 862 return VINF_SUCCESS; 863 864 case DBGCVAR_TYPE_GC_FAR: 865 return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel); 866 867 case DBGCVAR_TYPE_STRING: 868 case DBGCVAR_TYPE_SYMBOL: 869 { 870 DBGCVAR Var; 871 int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar); 872 if (VBOX_FAILURE(rc)) 873 return rc; 874 return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress); 875 } 876 877 case DBGCVAR_TYPE_GC_PHYS: 878 case DBGCVAR_TYPE_HC_FLAT: 879 case DBGCVAR_TYPE_HC_FAR: 880 case DBGCVAR_TYPE_HC_PHYS: 881 default: 882 return VERR_PARSE_CONVERSION_FAILED; 883 } 884 } 885 886 887 888 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 889 // 890 // 891 // B r e a k p o i n t M a n a g e m e n t 892 // 893 // 894 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 895 896 897 /** 898 * Adds a breakpoint to the DBGC breakpoint list. 899 */ 900 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd) 901 { 902 /* 903 * Check if it already exists. 904 */ 905 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp); 906 if (pBp) 907 return VERR_DBGC_BP_EXISTS; 908 909 /* 910 * Add the breakpoint. 911 */ 912 if (pszCmd) 913 pszCmd = RTStrStripL(pszCmd); 914 size_t cchCmd = pszCmd ? strlen(pszCmd) : 0; 915 pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1])); 916 if (!pBp) 917 return VERR_NO_MEMORY; 918 if (cchCmd) 919 memcpy(pBp->szCmd, pszCmd, cchCmd + 1); 920 else 921 pBp->szCmd[0] = '\0'; 922 pBp->cchCmd = cchCmd; 923 pBp->iBp = iBp; 924 pBp->pNext = pDbgc->pFirstBp; 925 pDbgc->pFirstBp = pBp; 926 927 return VINF_SUCCESS; 928 } 929 930 /** 931 * Updates the a breakpoint. 932 * 933 * @returns VBox status code. 934 * @param pDbgc The DBGC instance. 935 * @param iBp The breakpoint to update. 936 * @param pszCmd The new command. 937 */ 938 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd) 939 { 940 /* 941 * Find the breakpoint. 942 */ 943 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp); 944 if (!pBp) 945 return VERR_DBGC_BP_NOT_FOUND; 946 947 /* 948 * Do we need to reallocate? 949 */ 950 if (pszCmd) 951 pszCmd = RTStrStripL(pszCmd); 952 if (!pszCmd || !*pszCmd) 953 pBp->szCmd[0] = '\0'; 954 else 955 { 956 size_t cchCmd = strlen(pszCmd); 957 if (strlen(pBp->szCmd) >= cchCmd) 958 { 959 memcpy(pBp->szCmd, pszCmd, cchCmd + 1); 960 pBp->cchCmd = cchCmd; 961 } 962 else 963 { 964 /* 965 * Yes, let's do it the simple way... 966 */ 967 int rc = dbgcBpDelete(pDbgc, iBp); 968 AssertRC(rc); 969 return dbgcBpAdd(pDbgc, iBp, pszCmd); 970 } 971 } 972 return VINF_SUCCESS; 973 } 974 975 976 /** 977 * Deletes a breakpoint. 978 * 979 * @returns VBox status code. 980 * @param pDbgc The DBGC instance. 981 * @param iBp The breakpoint to delete. 982 */ 983 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp) 984 { 985 /* 986 * Search thru the list, when found unlink and free it. 987 */ 988 PDBGCBP pBpPrev = NULL; 989 PDBGCBP pBp = pDbgc->pFirstBp; 990 for (; pBp; pBp = pBp->pNext) 991 { 992 if (pBp->iBp == iBp) 993 { 994 if (pBpPrev) 995 pBpPrev->pNext = pBp->pNext; 996 else 997 pDbgc->pFirstBp = pBp->pNext; 998 RTMemFree(pBp); 999 return VINF_SUCCESS; 1000 } 1001 pBpPrev = pBp; 1002 } 1003 1004 return VERR_DBGC_BP_NOT_FOUND; 1005 } 1006 1007 1008 /** 1009 * Get a breakpoint. 1010 * 1011 * @returns Pointer to the breakpoint. 1012 * @returns NULL if the breakpoint wasn't found. 1013 * @param pDbgc The DBGC instance. 1014 * @param iBp The breakpoint to get. 1015 */ 1016 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp) 1017 { 1018 /* 1019 * Enumerate the list. 1020 */ 1021 PDBGCBP pBp = pDbgc->pFirstBp; 1022 for (; pBp; pBp = pBp->pNext) 1023 if (pBp->iBp == iBp) 1024 return pBp; 1025 return NULL; 1026 } 1027 1028 1029 /** 1030 * Executes the command of a breakpoint. 1031 * 1032 * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint. 1033 * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found. 1034 * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command. 1035 * @returns VBox status code from dbgcProcessCommand() other wise. 1036 * @param pDbgc The DBGC instance. 1037 * @param iBp The breakpoint to execute. 1038 */ 1039 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp) 1040 { 1041 /* 1042 * Find the breakpoint. 1043 */ 1044 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp); 1045 if (!pBp) 1046 return VERR_DBGC_BP_NOT_FOUND; 1047 1048 /* 1049 * Anything to do? 1050 */ 1051 if (!pBp->cchCmd) 1052 return VINF_DBGC_BP_NO_COMMAND; 1053 1054 /* 1055 * Execute the command. 1056 * This means copying it to the scratch buffer and process it as if it 1057 * were user input. We must save and restore the state of the scratch buffer. 1058 */ 1059 /* Save the scratch state. */ 1060 char *pszScratch = pDbgc->pszScratch; 1061 unsigned iArg = pDbgc->iArg; 1062 1063 /* Copy the command to the scratch buffer. */ 1064 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]); 1065 if (pBp->cchCmd >= cbScratch) 1066 return VERR_BUFFER_OVERFLOW; 1067 memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1); 1068 1069 /* Execute the command. */ 1070 pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1; 1071 int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd); 1072 1073 /* Restore the scratch state. */ 1074 pDbgc->iArg = iArg; 1075 pDbgc->pszScratch = pszScratch; 1076 1077 return rc; 1078 } 1079 1080 1081 1082 1083 1084 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 1085 // 1086 // 1087 // I n p u t , p a r s i n g a n d l o g g i n g 1088 // 1089 // 1090 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 1091 1092 1093 1094 /** 1095 * Prints any log lines from the log buffer. 1096 * 1097 * The caller must not call function this unless pDbgc->fLog is set. 1098 * 1099 * @returns VBox status. (output related) 1100 * @param pDbgc Debugger console instance data. 1101 */ 1102 static int dbgcProcessLog(PDBGC pDbgc) 1103 { 1104 /** @todo */ 1105 NOREF(pDbgc); 1106 return 0; 1107 } 1108 1109 1110 1111 /** 1112 * Handle input buffer overflow. 1113 * 1114 * Will read any available input looking for a '\n' to reset the buffer on. 1115 * 1116 * @returns VBox status. 1117 * @param pDbgc Debugger console instance data. 1118 */ 1119 static int dbgcInputOverflow(PDBGC pDbgc) 1120 { 1121 /* 1122 * Assert overflow status and reset the input buffer. 1123 */ 1124 if (!pDbgc->fInputOverflow) 1125 { 1126 pDbgc->fInputOverflow = true; 1127 pDbgc->iRead = pDbgc->iWrite = 0; 1128 pDbgc->cInputLines = 0; 1129 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n"); 1130 } 1131 1132 /* 1133 * Eat input till no more or there is a '\n'. 1134 * When finding a '\n' we'll continue normal processing. 1135 */ 1136 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0)) 1137 { 1138 size_t cbRead; 1139 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead); 1140 if (VBOX_FAILURE(rc)) 1141 return rc; 1142 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead); 1143 if (psz) 1144 { 1145 pDbgc->fInputOverflow = false; 1146 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1; 1147 pDbgc->iWrite = (unsigned)cbRead; 1148 pDbgc->cInputLines = 0; 1149 break; 1150 } 1151 } 1152 1153 return 0; 1154 } 1155 1156 1157 1158 /** 1159 * Read input and do some preprocessing. 1160 * 1161 * @returns VBox status. 1162 * In addition to the iWrite and achInput, cInputLines is maintained. 1163 * In case of an input overflow the fInputOverflow flag will be set. 1164 * @param pDbgc Debugger console instance data. 1165 */ 1166 static int dbgcInputRead(PDBGC pDbgc) 1167 { 1168 /* 1169 * We have ready input. 1170 * Read it till we don't have any or we have a full input buffer. 1171 */ 1172 int rc = 0; 1173 do 1174 { 1175 /* 1176 * More available buffer space? 1177 */ 1178 size_t cbLeft; 1179 if (pDbgc->iWrite > pDbgc->iRead) 1180 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0); 1181 else 1182 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1; 1183 if (!cbLeft) 1184 { 1185 /* overflow? */ 1186 if (!pDbgc->cInputLines) 1187 rc = dbgcInputOverflow(pDbgc); 1188 break; 1189 } 1190 1191 /* 1192 * Read one char and interpret it. 1193 */ 1194 char achRead[128]; 1195 size_t cbRead; 1196 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead); 1197 if (VBOX_FAILURE(rc)) 1198 return rc; 1199 char *psz = &achRead[0]; 1200 while (cbRead-- > 0) 1201 { 1202 char ch = *psz++; 1203 switch (ch) 1204 { 1205 /* 1206 * Ignore. 1207 */ 1208 case '\0': 1209 case '\r': 1210 case '\a': 1211 break; 1212 1213 /* 1214 * Backspace. 1215 */ 1216 case '\b': 1217 Log2(("DBGC: backspace\n")); 1218 if (pDbgc->iRead != pDbgc->iWrite) 1219 { 1220 unsigned iWriteUndo = pDbgc->iWrite; 1221 if (pDbgc->iWrite) 1222 pDbgc->iWrite--; 1223 else 1224 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1; 1225 1226 if (pDbgc->achInput[pDbgc->iWrite] == '\n') 1227 pDbgc->iWrite = iWriteUndo; 1228 } 1229 break; 1230 1231 /* 1232 * Add char to buffer. 1233 */ 1234 case '\t': 1235 case '\n': 1236 case ';': 1237 switch (ch) 1238 { 1239 case '\t': ch = ' '; break; 1240 case '\n': pDbgc->cInputLines++; break; 1241 } 1242 default: 1243 Log2(("DBGC: ch=%02x\n", (unsigned char)ch)); 1244 pDbgc->achInput[pDbgc->iWrite] = ch; 1245 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput)) 1246 pDbgc->iWrite = 0; 1247 break; 1248 } 1249 } 1250 1251 /* Terminate it to make it easier to read in the debugger. */ 1252 pDbgc->achInput[pDbgc->iWrite] = '\0'; 1253 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0)); 1254 1255 return rc; 1256 } 1257 1258 1259 1260 /** 1261 * Resolves a symbol (or tries to do so at least). 1262 * 1263 * @returns 0 on success. 1264 * @returns VBox status on failure. 1265 * @param pDbgc The debug console instance. 1266 * @param pszSymbol The symbol name. 1267 * @param enmType The result type. 1268 * @param pResult Where to store the result. 1269 */ 1270 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult) 1271 { 1272 /* 1273 * Builtin? 1274 */ 1275 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol); 1276 if (pSymDesc) 1277 { 1278 if (!pSymDesc->pfnGet) 1279 return VERR_PARSE_WRITEONLY_SYMBOL; 1280 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult); 1281 } 1282 1283 1284 /* 1285 * Ask PDM. 1286 */ 1287 /** @todo resolve symbols using PDM. */ 1288 1289 1290 /* 1291 * Ask the debug info manager. 1292 */ 1293 DBGFSYMBOL Symbol; 1294 int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol); 1295 if (VBOX_SUCCESS(rc)) 1296 { 1297 /* 1298 * Default return is a flat gc address. 1299 */ 1300 memset(pResult, 0, sizeof(*pResult)); 1301 pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE; 1302 pResult->u64Range = Symbol.cb; 1303 pResult->enmType = DBGCVAR_TYPE_GC_FLAT; 1304 pResult->u.GCFlat = Symbol.Value; 1305 DBGCVAR VarTmp; 1306 switch (enmType) 1307 { 1308 /* nothing to do. */ 1309 case DBGCVAR_TYPE_GC_FLAT: 1310 case DBGCVAR_TYPE_GC_FAR: 1311 case DBGCVAR_TYPE_ANY: 1312 return VINF_SUCCESS; 1313 1314 /* simply make it numeric. */ 1315 case DBGCVAR_TYPE_NUMBER: 1316 pResult->enmType = DBGCVAR_TYPE_NUMBER; 1317 pResult->u.u64Number = Symbol.Value; 1318 return VINF_SUCCESS; 1319 1320 /* cast it. */ 1321 1322 case DBGCVAR_TYPE_GC_PHYS: 1323 VarTmp = *pResult; 1324 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult); 1325 1326 case DBGCVAR_TYPE_HC_FAR: 1327 case DBGCVAR_TYPE_HC_FLAT: 1328 VarTmp = *pResult; 1329 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult); 1330 1331 case DBGCVAR_TYPE_HC_PHYS: 1332 VarTmp = *pResult; 1333 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult); 1334 1335 default: 1336 AssertMsgFailed(("Internal error enmType=%d\n", enmType)); 1337 return VERR_INVALID_PARAMETER; 1338 } 1339 } 1340 1341 return VERR_PARSE_NOT_IMPLEMENTED; 1342 } 1343 1344 1345 /** 1346 * Initalizes g_bmOperatorChars. 1347 */ 1348 static void dbgcInitOpCharBitMap(void) 1349 { 1350 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars)); 1351 for (unsigned iOp = 0; iOp < g_cOps; iOp++) 1352 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]); 1353 } 1354 1355 1356 /** 1357 * Checks whether the character may be the start of an operator. 1358 * 1359 * @returns true/false. 1360 * @param ch The character. 1361 */ 1362 DECLINLINE(bool) dbgcIsOpChar(char ch) 1363 { 1364 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch); 1365 } 1366 1367 1368 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg) 1369 { 1370 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr)); 1371 1372 /* 1373 * Removing any quoting and escapings. 1374 */ 1375 char ch = *pszExpr; 1376 if (ch == '"' || ch == '\'' || ch == '`') 1377 { 1378 if (pszExpr[--cchExpr] != ch) 1379 return VERR_PARSE_UNBALANCED_QUOTE; 1380 cchExpr--; 1381 pszExpr++; 1382 1383 /** @todo string unescaping. */ 1384 } 1385 pszExpr[cchExpr] = '\0'; 1386 1387 /* 1388 * Make the argument. 1389 */ 1390 pArg->pDesc = NULL; 1391 pArg->pNext = NULL; 1392 pArg->enmType = DBGCVAR_TYPE_STRING; 1393 pArg->u.pszString = pszExpr; 1394 pArg->enmRangeType = DBGCVAR_RANGE_BYTES; 1395 pArg->u64Range = cchExpr; 1396 1397 NOREF(pDbgc); 1398 return 0; 1399 } 1400 1401 1402 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg) 1403 { 1404 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr)); 1405 /* 1406 * Convert to number. 1407 */ 1408 uint64_t u64 = 0; 1409 char ch; 1410 while ((ch = *pszExpr) != '\0') 1411 { 1412 uint64_t u64Prev = u64; 1413 unsigned u = ch - '0'; 1414 if (u < 10 && u < uBase) 1415 u64 = u64 * uBase + u; 1416 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase) 1417 u64 = u64 * uBase + u; 1418 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase) 1419 u64 = u64 * uBase + u; 1420 else 1421 return VERR_PARSE_INVALID_NUMBER; 1422 1423 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */ 1424 if (u64Prev != u64 / uBase) 1425 return VERR_PARSE_NUMBER_TOO_BIG; 1426 1427 /* next */ 1428 pszExpr++; 1429 } 1430 1431 /* 1432 * Initialize the argument. 1433 */ 1434 pArg->pDesc = NULL; 1435 pArg->pNext = NULL; 1436 pArg->enmType = DBGCVAR_TYPE_NUMBER; 1437 pArg->u.u64Number = u64; 1438 pArg->enmRangeType = DBGCVAR_RANGE_NONE; 1439 pArg->u64Range = 0; 1440 1441 return 0; 1442 } 1443 1444 1445 /** 1446 * Match variable and variable descriptor, promoting the variable if necessary. 1447 * 1448 * @returns VBox status code. 1449 * @param pDbgc Debug console instanace. 1450 * @param pVar Variable. 1451 * @param pVarDesc Variable descriptor. 1452 */ 1453 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc) 1454 { 1455 /* 1456 * (If match or promoted to match, return, else break.) 1457 */ 1458 switch (pVarDesc->enmCategory) 1459 { 1460 /* 1461 * Anything goes 1462 */ 1463 case DBGCVAR_CAT_ANY: 1464 return VINF_SUCCESS; 1465 1466 /* 1467 * Pointer with and without range. 1468 * We can try resolve strings and symbols as symbols and 1469 * promote numbers to flat GC pointers. 1470 */ 1471 case DBGCVAR_CAT_POINTER_NO_RANGE: 1472 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE) 1473 return VERR_PARSE_NO_RANGE_ALLOWED; 1474 /* fallthru */ 1475 case DBGCVAR_CAT_POINTER: 1476 switch (pVar->enmType) 1477 { 1478 case DBGCVAR_TYPE_GC_FLAT: 1479 case DBGCVAR_TYPE_GC_FAR: 1480 case DBGCVAR_TYPE_GC_PHYS: 1481 case DBGCVAR_TYPE_HC_FLAT: 1482 case DBGCVAR_TYPE_HC_FAR: 1483 case DBGCVAR_TYPE_HC_PHYS: 1484 return VINF_SUCCESS; 1485 1486 case DBGCVAR_TYPE_SYMBOL: 1487 case DBGCVAR_TYPE_STRING: 1488 { 1489 DBGCVAR Var; 1490 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var); 1491 if (VBOX_SUCCESS(rc)) 1492 { 1493 /* deal with range */ 1494 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE) 1495 { 1496 Var.enmRangeType = pVar->enmRangeType; 1497 Var.u64Range = pVar->u64Range; 1498 } 1499 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE) 1500 Var.enmRangeType = DBGCVAR_RANGE_NONE; 1501 *pVar = Var; 1502 return rc; 1503 } 1504 break; 1505 } 1506 1507 case DBGCVAR_TYPE_NUMBER: 1508 { 1509 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number; 1510 pVar->enmType = DBGCVAR_TYPE_GC_FLAT; 1511 pVar->u.GCFlat = GCPtr; 1512 return VINF_SUCCESS; 1513 } 1514 1515 default: 1516 break; 1517 } 1518 break; 1519 1520 /* 1521 * GC pointer with and without range. 1522 * We can try resolve strings and symbols as symbols and 1523 * promote numbers to flat GC pointers. 1524 */ 1525 case DBGCVAR_CAT_GC_POINTER_NO_RANGE: 1526 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE) 1527 return VERR_PARSE_NO_RANGE_ALLOWED; 1528 /* fallthru */ 1529 case DBGCVAR_CAT_GC_POINTER: 1530 switch (pVar->enmType) 1531 { 1532 case DBGCVAR_TYPE_GC_FLAT: 1533 case DBGCVAR_TYPE_GC_FAR: 1534 case DBGCVAR_TYPE_GC_PHYS: 1535 return VINF_SUCCESS; 1536 1537 case DBGCVAR_TYPE_HC_FLAT: 1538 case DBGCVAR_TYPE_HC_FAR: 1539 case DBGCVAR_TYPE_HC_PHYS: 1540 return VERR_PARSE_CONVERSION_FAILED; 1541 1542 case DBGCVAR_TYPE_SYMBOL: 1543 case DBGCVAR_TYPE_STRING: 1544 { 1545 DBGCVAR Var; 1546 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var); 1547 if (VBOX_SUCCESS(rc)) 1548 { 1549 /* deal with range */ 1550 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE) 1551 { 1552 Var.enmRangeType = pVar->enmRangeType; 1553 Var.u64Range = pVar->u64Range; 1554 } 1555 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE) 1556 Var.enmRangeType = DBGCVAR_RANGE_NONE; 1557 *pVar = Var; 1558 return rc; 1559 } 1560 break; 1561 } 1562 1563 case DBGCVAR_TYPE_NUMBER: 1564 { 1565 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number; 1566 pVar->enmType = DBGCVAR_TYPE_GC_FLAT; 1567 pVar->u.GCFlat = GCPtr; 1568 return VINF_SUCCESS; 1569 } 1570 1571 default: 1572 break; 1573 } 1574 break; 1575 1576 /* 1577 * Number with or without a range. 1578 * Numbers can be resolved from symbols, but we cannot demote a pointer 1579 * to a number. 1580 */ 1581 case DBGCVAR_CAT_NUMBER_NO_RANGE: 1582 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE) 1583 return VERR_PARSE_NO_RANGE_ALLOWED; 1584 /* fallthru */ 1585 case DBGCVAR_CAT_NUMBER: 1586 switch (pVar->enmType) 1587 { 1588 case DBGCVAR_TYPE_NUMBER: 1589 return VINF_SUCCESS; 1590 1591 case DBGCVAR_TYPE_SYMBOL: 1592 case DBGCVAR_TYPE_STRING: 1593 { 1594 DBGCVAR Var; 1595 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var); 1596 if (VBOX_SUCCESS(rc)) 1597 { 1598 *pVar = Var; 1599 return rc; 1600 } 1601 break; 1602 } 1603 default: 1604 break; 1605 } 1606 break; 1607 1608 /* 1609 * Strings can easily be made from symbols (and of course strings). 1610 * We could consider reformatting the addresses and numbers into strings later... 1611 */ 1612 case DBGCVAR_CAT_STRING: 1613 switch (pVar->enmType) 1614 { 1615 case DBGCVAR_TYPE_SYMBOL: 1616 pVar->enmType = DBGCVAR_TYPE_STRING; 1617 /* fallthru */ 1618 case DBGCVAR_TYPE_STRING: 1619 return VINF_SUCCESS; 1620 default: 1621 break; 1622 } 1623 break; 1624 1625 /* 1626 * Symol is pretty much the same thing as a string (at least until we actually implement it). 1627 */ 1628 case DBGCVAR_CAT_SYMBOL: 1629 switch (pVar->enmType) 1630 { 1631 case DBGCVAR_TYPE_STRING: 1632 pVar->enmType = DBGCVAR_TYPE_SYMBOL; 1633 /* fallthru */ 1634 case DBGCVAR_TYPE_SYMBOL: 1635 return VINF_SUCCESS; 1636 default: 1637 break; 1638 } 1639 break; 1640 1641 /* 1642 * Anything else is illegal. 1643 */ 1644 default: 1645 AssertMsgFailed(("enmCategory=%d\n", pVar->enmType)); 1646 break; 1647 } 1648 1649 return VERR_PARSE_NO_ARGUMENT_MATCH; 1650 } 1651 1652 1653 /** 1654 * Matches a set of variables with a description set. 1655 * 1656 * This is typically used for routine arguments before a call. The effects in 1657 * addition to the validation, is that some variables might be propagated to 1658 * other types in order to match the description. The following transformations 1659 * are supported: 1660 * - String reinterpreted as a symbol and resolved to a number or pointer. 1661 * - Number to a pointer. 1662 * - Pointer to a number. 1663 * @returns 0 on success with paVars. 1664 * @returns VBox error code for match errors. 1665 */ 1666 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax, 1667 PCDBGCVARDESC paVarDescs, unsigned cVarDescs, 1668 PDBGCVAR paVars, unsigned cVars) 1669 { 1670 /* 1671 * Just do basic min / max checks first. 1672 */ 1673 if (cVars < cVarsMin) 1674 return VERR_PARSE_TOO_FEW_ARGUMENTS; 1675 if (cVars > cVarsMax) 1676 return VERR_PARSE_TOO_MANY_ARGUMENTS; 1677 1678 /* 1679 * Match the descriptors and actual variables. 1680 */ 1681 PCDBGCVARDESC pPrevDesc = NULL; 1682 unsigned cCurDesc = 0; 1683 unsigned iVar = 0; 1684 unsigned iVarDesc = 0; 1685 while (iVar < cVars) 1686 { 1687 /* walk the descriptors */ 1688 if (iVarDesc >= cVarDescs) 1689 return VERR_PARSE_TOO_MANY_ARGUMENTS; 1690 if ( ( paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV 1691 && &paVarDescs[iVarDesc - 1] != pPrevDesc) 1692 || cCurDesc >= paVarDescs[iVarDesc].cTimesMax) 1693 { 1694 iVarDesc++; 1695 if (iVarDesc >= cVarDescs) 1696 return VERR_PARSE_TOO_MANY_ARGUMENTS; 1697 cCurDesc = 0; 1698 } 1699 1700 /* 1701 * Skip thru optional arguments until we find something which matches 1702 * or can easily be promoted to what the descriptor want. 1703 */ 1704 for (;;) 1705 { 1706 int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]); 1707 if (VBOX_SUCCESS(rc)) 1708 { 1709 paVars[iVar].pDesc = &paVarDescs[iVarDesc]; 1710 cCurDesc++; 1711 break; 1712 } 1713 1714 /* can we advance? */ 1715 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc) 1716 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH; 1717 if (++iVarDesc >= cVarDescs) 1718 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH; 1719 cCurDesc = 0; 1720 } 1721 1722 /* next var */ 1723 iVar++; 1724 } 1725 1726 /* 1727 * Check that the rest of the descriptors are optional. 1728 */ 1729 while (iVarDesc < cVarDescs) 1730 { 1731 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc) 1732 return VERR_PARSE_TOO_FEW_ARGUMENTS; 1733 cCurDesc = 0; 1734 1735 /* next */ 1736 iVarDesc++; 1737 } 1738 1739 return 0; 1740 } 1741 1742 1743 /** 1744 * Evaluates one argument with respect to unary operators. 1745 * 1746 * @returns 0 on success. pResult contains the result. 1747 * @returns VBox error code on parse or other evaluation error. 1748 * 1749 * @param pDbgc Debugger console instance data. 1750 * @param pszExpr The expression string. 1751 * @param pResult Where to store the result of the expression evaluation. 1752 */ 1753 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult) 1754 { 1755 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr)); 1756 1757 /* 1758 * The state of the expression is now such that it will start by zero or more 1759 * unary operators and being followed by an expression of some kind. 1760 * The expression is either plain or in parenthesis. 1761 * 1762 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-) 1763 * ASSUME: unary operators are all of equal precedence. 1764 */ 1765 int rc = 0; 1766 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' '); 1767 if (pOp) 1768 { 1769 /* binary operators means syntax error. */ 1770 if (pOp->fBinary) 1771 return VERR_PARSE_UNEXPECTED_OPERATOR; 1772 1773 /* 1774 * If the next expression (the one following the unary operator) is in a 1775 * parenthesis a full eval is needed. If not the unary eval will suffice. 1776 */ 1777 /* calc and strip next expr. */ 1778 char *pszExpr2 = pszExpr + pOp->cchName; 1779 while (isblank(*pszExpr2)) 1780 pszExpr2++; 1781 1782 if (!*pszExpr2) 1783 rc = VERR_PARSE_EMPTY_ARGUMENT; 1784 else 1785 { 1786 DBGCVAR Arg; 1787 if (*pszExpr2 == '(') 1788 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg); 1789 else 1790 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg); 1791 if (VBOX_SUCCESS(rc)) 1792 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult); 1793 } 1794 } 1795 else 1796 { 1797 /* 1798 * Didn't find any operators, so it we have to check if this can be an 1799 * function call before assuming numeric or string expression. 1800 * 1801 * (ASSUMPTIONS:) 1802 * A function name only contains alphanumerical chars and it can not start 1803 * with a numerical character. 1804 * Immediately following the name is a parenthesis which must over 1805 * the remaining part of the expression. 1806 */ 1807 bool fExternal = *pszExpr == '.'; 1808 char *pszFun = fExternal ? pszExpr + 1 : pszExpr; 1809 char *pszFunEnd = NULL; 1810 if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun)) 1811 { 1812 pszFunEnd = pszExpr + 1; 1813 while (*pszFunEnd != '(' && isalnum(*pszFunEnd)) 1814 pszFunEnd++; 1815 if (*pszFunEnd != '(') 1816 pszFunEnd = NULL; 1817 } 1818 1819 if (pszFunEnd) 1820 { 1821 /* 1822 * Ok, it's a function call. 1823 */ 1824 if (fExternal) 1825 pszExpr++, cchExpr--; 1826 PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal); 1827 if (!pFun) 1828 return VERR_PARSE_FUNCTION_NOT_FOUND; 1829 if (!pFun->pResultDesc) 1830 return VERR_PARSE_NOT_A_FUNCTION; 1831 1832 /* 1833 * Parse the expression in parenthesis. 1834 */ 1835 cchExpr -= pszFunEnd - pszExpr; 1836 pszExpr = pszFunEnd; 1837 /** @todo implement multiple arguments. */ 1838 DBGCVAR Arg; 1839 rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg); 1840 if (!rc) 1841 { 1842 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1); 1843 if (!rc) 1844 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult); 1845 } 1846 else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0) 1847 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult); 1848 } 1849 else 1850 { 1851 /* 1852 * Didn't find any operators, so it must be a plain expression. 1853 * This might be numeric or a string expression. 1854 */ 1855 char ch = pszExpr[0]; 1856 char ch2 = pszExpr[1]; 1857 if (ch == '0' && (ch2 == 'x' || ch2 == 'X')) 1858 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult); 1859 else if (ch == '0' && (ch2 == 'i' || ch2 == 'i')) 1860 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult); 1861 else if (ch == '0' && (ch2 == 't' || ch2 == 'T')) 1862 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult); 1863 /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff. 1864 //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b')) 1865 // rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult); 1866 else 1867 { 1868 /* 1869 * Hexadecimal number or a string? 1870 */ 1871 char *psz = pszExpr; 1872 while (isxdigit(*psz)) 1873 psz++; 1874 if (!*psz) 1875 rc = dbgcEvalSubNum(pszExpr, 16, pResult); 1876 else if ((*psz == 'h' || *psz == 'H') && !psz[1]) 1877 { 1878 *psz = '\0'; 1879 rc = dbgcEvalSubNum(pszExpr, 16, pResult); 1880 } 1881 else 1882 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult); 1883 } 1884 } 1885 } 1886 1887 return rc; 1888 } 1889 1890 1891 /** 1892 * Evaluates one argument. 1893 * 1894 * @returns 0 on success. pResult contains the result. 1895 * @returns VBox error code on parse or other evaluation error. 1896 * 1897 * @param pDbgc Debugger console instance data. 1898 * @param pszExpr The expression string. 1899 * @param pResult Where to store the result of the expression evaluation. 1900 */ 1901 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult) 1902 { 1903 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr)); 1904 /* 1905 * First we need to remove blanks in both ends. 1906 * ASSUMES: There is no quoting unless the entire expression is a string. 1907 */ 1908 1909 /* stripping. */ 1910 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1])) 1911 pszExpr[--cchExpr] = '\0'; 1912 while (isblank(*pszExpr)) 1913 pszExpr++, cchExpr--; 1914 if (!*pszExpr) 1915 return VERR_PARSE_EMPTY_ARGUMENT; 1916 1917 /* it there is any kind of quoting in the expression, it's string meat. */ 1918 if (strpbrk(pszExpr, "\"'`")) 1919 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult); 1920 1921 /* 1922 * Check if there are any parenthesis which needs removing. 1923 */ 1924 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')') 1925 { 1926 do 1927 { 1928 unsigned cPar = 1; 1929 char *psz = pszExpr + 1; 1930 char ch; 1931 while ((ch = *psz) != '\0') 1932 { 1933 if (ch == '(') 1934 cPar++; 1935 else if (ch == ')') 1936 { 1937 if (cPar <= 0) 1938 return VERR_PARSE_UNBALANCED_PARENTHESIS; 1939 cPar--; 1940 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */ 1941 break; 1942 } 1943 /* next */ 1944 psz++; 1945 } 1946 if (ch) 1947 break; 1948 1949 /* remove the parenthesis. */ 1950 pszExpr++; 1951 cchExpr -= 2; 1952 pszExpr[cchExpr] = '\0'; 1953 1954 /* strip blanks. */ 1955 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1])) 1956 pszExpr[--cchExpr] = '\0'; 1957 while (isblank(*pszExpr)) 1958 pszExpr++, cchExpr--; 1959 if (!*pszExpr) 1960 return VERR_PARSE_EMPTY_ARGUMENT; 1961 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')'); 1962 } 1963 1964 /* tabs to spaces. */ 1965 char *psz = pszExpr; 1966 while ((psz = strchr(psz, '\t')) != NULL) 1967 *psz = ' '; 1968 1969 /* 1970 * Now, we need to look for the binary operator with the lowest precedence. 1971 * 1972 * If there are no operators we're left with a simple expression which we 1973 * evaluate with respect to unary operators 1974 */ 1975 char *pszOpSplit = NULL; 1976 PCDBGCOP pOpSplit = NULL; 1977 unsigned cBinaryOps = 0; 1978 unsigned cPar = 0; 1979 char ch; 1980 char chPrev = ' '; 1981 bool fBinary = false; 1982 psz = pszExpr; 1983 1984 while ((ch = *psz) != '\0') 1985 { 1986 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary)); 1987 /* 1988 * Parenthesis. 1989 */ 1990 if (ch == '(') 1991 { 1992 cPar++; 1993 fBinary = false; 1994 } 1995 else if (ch == ')') 1996 { 1997 if (cPar <= 0) 1998 return VERR_PARSE_UNBALANCED_PARENTHESIS; 1999 cPar--; 2000 fBinary = true; 2001 } 2002 /* 2003 * Potential operator. 2004 */ 2005 else if (cPar == 0 && !isblank(ch)) 2006 { 2007 PCDBGCOP pOp = dbgcIsOpChar(ch) 2008 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev) 2009 : NULL; 2010 if (pOp) 2011 { 2012 /* If not the right kind of operator we've got a syntax error. */ 2013 if (pOp->fBinary != fBinary) 2014 return VERR_PARSE_UNEXPECTED_OPERATOR; 2015 2016 /* 2017 * Update the parse state and skip the operator. 2018 */ 2019 if (!pOpSplit) 2020 { 2021 pOpSplit = pOp; 2022 pszOpSplit = psz; 2023 cBinaryOps = fBinary; 2024 } 2025 else if (fBinary) 2026 { 2027 cBinaryOps++; 2028 if (pOp->iPrecedence >= pOpSplit->iPrecedence) 2029 { 2030 pOpSplit = pOp; 2031 pszOpSplit = psz; 2032 } 2033 } 2034 2035 psz += pOp->cchName - 1; 2036 fBinary = false; 2037 } 2038 else 2039 fBinary = true; 2040 } 2041 2042 /* next */ 2043 psz++; 2044 chPrev = ch; 2045 } /* parse loop. */ 2046 2047 2048 /* 2049 * Either we found an operator to divide the expression by 2050 * or we didn't find any. In the first case it's divide and 2051 * conquer. In the latter it's a single expression which 2052 * needs dealing with its unary operators if any. 2053 */ 2054 int rc; 2055 if ( cBinaryOps 2056 && pOpSplit->fBinary) 2057 { 2058 /* process 1st sub expression. */ 2059 *pszOpSplit = '\0'; 2060 DBGCVAR Arg1; 2061 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1); 2062 if (VBOX_SUCCESS(rc)) 2063 { 2064 /* process 2nd sub expression. */ 2065 char *psz2 = pszOpSplit + pOpSplit->cchName; 2066 DBGCVAR Arg2; 2067 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2); 2068 if (VBOX_SUCCESS(rc)) 2069 /* apply the operator. */ 2070 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult); 2071 } 2072 } 2073 else if (cBinaryOps) 2074 { 2075 /* process sub expression. */ 2076 pszOpSplit += pOpSplit->cchName; 2077 DBGCVAR Arg; 2078 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg); 2079 if (VBOX_SUCCESS(rc)) 2080 /* apply the operator. */ 2081 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult); 2082 } 2083 else 2084 /* plain expression or using unary operators perhaps with paratheses. */ 2085 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult); 2086 2087 return rc; 2088 } 2089 2090 2091 /** 2092 * Parses the arguments of one command. 2093 * 2094 * @returns 0 on success. 2095 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble. 2096 * @param pDbgc Debugger console instance data. 2097 * @param pCmd Pointer to the command descriptor. 2098 * @param pszArg Pointer to the arguments to parse. 2099 * @param paArgs Where to store the parsed arguments. 2100 * @param cArgs Size of the paArgs array. 2101 * @param pcArgs Where to store the number of arguments. 2102 * In the event of an error this is used to store the index of the offending argument. 2103 */ 2104 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs) 2105 { 2106 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs)); 2107 /* 2108 * Check if we have any argument and if the command takes any. 2109 */ 2110 *pcArgs = 0; 2111 /* strip leading blanks. */ 2112 while (*pszArgs && isblank(*pszArgs)) 2113 pszArgs++; 2114 if (!*pszArgs) 2115 { 2116 if (!pCmd->cArgsMin) 2117 return 0; 2118 return VERR_PARSE_TOO_FEW_ARGUMENTS; 2119 } 2120 /** @todo fixme - foo() doesn't work. */ 2121 if (!pCmd->cArgsMax) 2122 return VERR_PARSE_TOO_MANY_ARGUMENTS; 2123 2124 /* 2125 * This is a hack, it's "temporary" and should go away "when" the parser is 2126 * modified to match arguments while parsing. 2127 */ 2128 if ( pCmd->cArgsMax == 1 2129 && pCmd->cArgsMin == 1 2130 && pCmd->cArgDescs == 1 2131 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING 2132 && cArgs >= 1) 2133 { 2134 *pcArgs = 1; 2135 RTStrStripR(pszArgs); 2136 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]); 2137 } 2138 2139 2140 /* 2141 * The parse loop. 2142 */ 2143 PDBGCVAR pArg0 = &paArgs[0]; 2144 PDBGCVAR pArg = pArg0; 2145 *pcArgs = 0; 2146 do 2147 { 2148 /* 2149 * Can we have another argument? 2150 */ 2151 if (*pcArgs >= pCmd->cArgsMax) 2152 return VERR_PARSE_TOO_MANY_ARGUMENTS; 2153 if (pArg >= &paArgs[cArgs]) 2154 return VERR_PARSE_ARGUMENT_OVERFLOW; 2155 2156 /* 2157 * Find the end of the argument. 2158 */ 2159 int cPar = 0; 2160 char chQuote = '\0'; 2161 char *pszEnd = NULL; 2162 char *psz = pszArgs; 2163 char ch; 2164 bool fBinary = false; 2165 for (;;) 2166 { 2167 /* 2168 * Check for the end. 2169 */ 2170 if ((ch = *psz) == '\0') 2171 { 2172 if (chQuote) 2173 return VERR_PARSE_UNBALANCED_QUOTE; 2174 if (cPar) 2175 return VERR_PARSE_UNBALANCED_PARENTHESIS; 2176 pszEnd = psz; 2177 break; 2178 } 2179 /* 2180 * When quoted we ignore everything but the quotation char. 2181 * We use the REXX way of escaping the quotation char, i.e. double occurence. 2182 */ 2183 else if (ch == '\'' || ch == '"' || ch == '`') 2184 { 2185 if (chQuote) 2186 { 2187 /* end quote? */ 2188 if (ch == chQuote) 2189 { 2190 if (psz[1] == ch) 2191 psz++; /* skip the escaped quote char */ 2192 else 2193 chQuote = '\0'; /* end of quoted string. */ 2194 } 2195 } 2196 else 2197 chQuote = ch; /* open new quote */ 2198 } 2199 /* 2200 * Parenthesis can of course be nested. 2201 */ 2202 else if (ch == '(') 2203 { 2204 cPar++; 2205 fBinary = false; 2206 } 2207 else if (ch == ')') 2208 { 2209 if (!cPar) 2210 return VERR_PARSE_UNBALANCED_PARENTHESIS; 2211 cPar--; 2212 fBinary = true; 2213 } 2214 else if (!chQuote && !cPar) 2215 { 2216 /* 2217 * Encountering blanks may mean the end of it all. A binary operator 2218 * will force continued parsing. 2219 */ 2220 if (isblank(*psz)) 2221 { 2222 pszEnd = psz++; /* just in case. */ 2223 while (isblank(*psz)) 2224 psz++; 2225 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' '); 2226 if (!pOp || pOp->fBinary != fBinary) 2227 break; /* the end. */ 2228 psz += pOp->cchName; 2229 while (isblank(*psz)) /* skip blanks so we don't get here again */ 2230 psz++; 2231 fBinary = false; 2232 continue; 2233 } 2234 2235 /* 2236 * Look for operators without a space up front. 2237 */ 2238 if (dbgcIsOpChar(*psz)) 2239 { 2240 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' '); 2241 if (pOp) 2242 { 2243 if (pOp->fBinary != fBinary) 2244 { 2245 pszEnd = psz; 2246 /** @todo this is a parsing error really. */ 2247 break; /* the end. */ 2248 } 2249 psz += pOp->cchName; 2250 while (isblank(*psz)) /* skip blanks so we don't get here again */ 2251 psz++; 2252 fBinary = false; 2253 continue; 2254 } 2255 } 2256 fBinary = true; 2257 } 2258 2259 /* next char */ 2260 psz++; 2261 } 2262 *pszEnd = '\0'; 2263 /* (psz = next char to process) */ 2264 2265 /* 2266 * Parse and evaluate the argument. 2267 */ 2268 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg); 2269 if (VBOX_FAILURE(rc)) 2270 return rc; 2271 2272 /* 2273 * Next. 2274 */ 2275 pArg++; 2276 (*pcArgs)++; 2277 pszArgs = psz; 2278 while (*pszArgs && isblank(*pszArgs)) 2279 pszArgs++; 2280 } while (*pszArgs); 2281 2282 /* 2283 * Match the arguments. 2284 */ 2285 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0); 2286 } 2287 2288 2289 /** 2290 * Process one command. 2291 * 2292 * @returns VBox status code. Any error indicates the termination of the console session. 2293 * @param pDbgc Debugger console instance data. 2294 * @param pszCmd Pointer to the command. 2295 * @param cchCmd Length of the command. 2296 */ 2297 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd) 2298 { 2299 char *pszCmdInput = pszCmd; 2300 2301 /* 2302 * Skip blanks. 2303 */ 2304 while (isblank(*pszCmd)) 2305 pszCmd++, cchCmd--; 2306 2307 /* external command? */ 2308 bool fExternal = *pszCmd == '.'; 2309 if (fExternal) 2310 pszCmd++, cchCmd--; 2311 2312 /* 2313 * Find arguments. 2314 */ 2315 char *pszArgs = pszCmd; 2316 while (isalnum(*pszArgs)) 2317 pszArgs++; 2318 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd)) 2319 { 2320 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput); 2321 return 0; 2322 } 2323 2324 /* 2325 * Find the command. 2326 */ 2327 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal); 2328 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION)) 2329 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput); 2330 2331 /* 2332 * Parse arguments (if any). 2333 */ 2334 unsigned cArgs; 2335 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs); 2336 2337 /* 2338 * Execute the command. 2339 */ 2340 if (!rc) 2341 { 2342 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL); 2343 } 2344 else 2345 { 2346 /* report parse / eval error. */ 2347 switch (rc) 2348 { 2349 case VERR_PARSE_TOO_FEW_ARGUMENTS: 2350 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2351 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd); 2352 break; 2353 case VERR_PARSE_TOO_MANY_ARGUMENTS: 2354 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2355 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd); 2356 break; 2357 case VERR_PARSE_ARGUMENT_OVERFLOW: 2358 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2359 "Syntax error: Too many arguments.\n"); 2360 break; 2361 case VERR_PARSE_UNBALANCED_QUOTE: 2362 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2363 "Syntax error: Unbalanced quote (argument %d).\n", cArgs); 2364 break; 2365 case VERR_PARSE_UNBALANCED_PARENTHESIS: 2366 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2367 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs); 2368 break; 2369 case VERR_PARSE_EMPTY_ARGUMENT: 2370 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2371 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs); 2372 break; 2373 case VERR_PARSE_UNEXPECTED_OPERATOR: 2374 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2375 "Syntax error: Invalid operator usage (argument %d).\n", cArgs); 2376 break; 2377 case VERR_PARSE_INVALID_NUMBER: 2378 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2379 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs); 2380 break; 2381 case VERR_PARSE_NUMBER_TOO_BIG: 2382 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2383 "Error: Numeric overflow (argument %d).\n", cArgs); 2384 break; 2385 case VERR_PARSE_INVALID_OPERATION: 2386 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2387 "Error: Invalid operation attempted (argument %d).\n", cArgs); 2388 break; 2389 case VERR_PARSE_FUNCTION_NOT_FOUND: 2390 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2391 "Error: Function not found (argument %d).\n", cArgs); 2392 break; 2393 case VERR_PARSE_NOT_A_FUNCTION: 2394 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2395 "Error: The function specified is not a function (argument %d).\n", cArgs); 2396 break; 2397 case VERR_PARSE_NO_MEMORY: 2398 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2399 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs); 2400 break; 2401 case VERR_PARSE_INCORRECT_ARG_TYPE: 2402 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2403 "Error: Incorrect argument type (argument %d?).\n", cArgs); 2404 break; 2405 case VERR_PARSE_VARIABLE_NOT_FOUND: 2406 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2407 "Error: An undefined variable was referenced (argument %d).\n", cArgs); 2408 break; 2409 case VERR_PARSE_CONVERSION_FAILED: 2410 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2411 "Error: A conversion between two types failed (argument %d).\n", cArgs); 2412 break; 2413 case VERR_PARSE_NOT_IMPLEMENTED: 2414 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2415 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs); 2416 break; 2417 case VERR_PARSE_BAD_RESULT_TYPE: 2418 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2419 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs); 2420 break; 2421 case VERR_PARSE_WRITEONLY_SYMBOL: 2422 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2423 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs); 2424 break; 2425 2426 default: 2427 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2428 "Error: Unknown error %d!\n", rc); 2429 return rc; 2430 } 2431 2432 /* 2433 * Parse errors are non fatal. 2434 */ 2435 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST) 2436 rc = 0; 2437 } 2438 2439 return rc; 2440 } 2441 2442 2443 /** 2444 * Process all commands current in the buffer. 2445 * 2446 * @returns VBox status code. Any error indicates the termination of the console session. 2447 * @param pDbgc Debugger console instance data. 2448 */ 2449 static int dbgcProcessCommands(PDBGC pDbgc) 2450 { 2451 int rc = 0; 2452 while (pDbgc->cInputLines) 2453 { 2454 /* 2455 * Empty the log buffer if we're hooking the log. 2456 */ 2457 if (pDbgc->fLog) 2458 { 2459 rc = dbgcProcessLog(pDbgc); 2460 if (VBOX_FAILURE(rc)) 2461 break; 2462 } 2463 2464 if (pDbgc->iRead == pDbgc->iWrite) 2465 { 2466 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines)); 2467 pDbgc->cInputLines = 0; 2468 return 0; 2469 } 2470 2471 /* 2472 * Copy the command to the parse buffer. 2473 */ 2474 char ch; 2475 char *psz = &pDbgc->achInput[pDbgc->iRead]; 2476 char *pszTrg = &pDbgc->achScratch[0]; 2477 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' ) 2478 { 2479 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)]) 2480 psz = &pDbgc->achInput[0]; 2481 2482 if (psz == &pDbgc->achInput[pDbgc->iWrite]) 2483 { 2484 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines)); 2485 pDbgc->cInputLines = 0; 2486 return 0; 2487 } 2488 2489 pszTrg++; 2490 } 2491 *pszTrg = '\0'; 2492 2493 /* 2494 * Advance the buffer. 2495 */ 2496 pDbgc->iRead = psz - &pDbgc->achInput[0]; 2497 if (ch == '\n') 2498 pDbgc->cInputLines--; 2499 2500 /* 2501 * Parse and execute this command. 2502 */ 2503 pDbgc->pszScratch = psz; 2504 pDbgc->iArg = 0; 2505 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1); 2506 if (rc) 2507 break; 2508 } 2509 2510 return rc; 2511 } 2512 2513 2514 /** 2515 * Reads input, parses it and executes commands on '\n'. 2516 * 2517 * @returns VBox status. 2518 * @param pDbgc Debugger console instance data. 2519 */ 2520 static int dbgcProcessInput(PDBGC pDbgc) 2521 { 2522 /* 2523 * We know there's input ready, so let's read it first. 2524 */ 2525 int rc = dbgcInputRead(pDbgc); 2526 if (VBOX_FAILURE(rc)) 2527 return rc; 2528 2529 /* 2530 * Now execute any ready commands. 2531 */ 2532 if (pDbgc->cInputLines) 2533 { 2534 /** @todo this fReady stuff is broken. */ 2535 pDbgc->fReady = false; 2536 rc = dbgcProcessCommands(pDbgc); 2537 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING) 2538 pDbgc->fReady = true; 2539 if ( VBOX_SUCCESS(rc) 2540 && pDbgc->iRead == pDbgc->iWrite 2541 && pDbgc->fReady) 2542 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> "); 2543 } 2544 2545 return rc; 2546 } 2547 2548 2549 /** 2550 * Gets the event context identifier string. 2551 * @returns Read only string. 2552 * @param enmCtx The context. 2553 */ 2554 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx) 2555 { 2556 switch (enmCtx) 2557 { 2558 case DBGFEVENTCTX_RAW: return "raw"; 2559 case DBGFEVENTCTX_REM: return "rem"; 2560 case DBGFEVENTCTX_HWACCL: return "hwaccl"; 2561 case DBGFEVENTCTX_HYPER: return "hyper"; 2562 case DBGFEVENTCTX_OTHER: return "other"; 2563 2564 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!"; 2565 default: 2566 AssertMsgFailed(("enmCtx=%d\n", enmCtx)); 2567 return "!Unknown Event Ctx!"; 2568 } 2569 } 2570 2571 2572 /** 2573 * Processes debugger events. 2574 * 2575 * @returns VBox status. 2576 * @param pDbgc DBGC Instance data. 2577 * @param pEvent Pointer to event data. 2578 */ 2579 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent) 2580 { 2581 /* 2582 * Flush log first. 2583 */ 2584 if (pDbgc->fLog) 2585 { 2586 int rc = dbgcProcessLog(pDbgc); 2587 if (VBOX_FAILURE(rc)) 2588 return rc; 2589 } 2590 2591 /* 2592 * Process the event. 2593 */ 2594 pDbgc->pszScratch = &pDbgc->achInput[0]; 2595 pDbgc->iArg = 0; 2596 bool fPrintPrompt = true; 2597 int rc = VINF_SUCCESS; 2598 switch (pEvent->enmType) 2599 { 2600 /* 2601 * The first part is events we have initiated with commands. 2602 */ 2603 case DBGFEVENT_HALT_DONE: 2604 { 2605 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n", 2606 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx)); 2607 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */ 2608 if (VBOX_SUCCESS(rc)) 2609 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r"); 2610 break; 2611 } 2612 2613 2614 /* 2615 * The second part is events which can occur at any time. 2616 */ 2617 case DBGFEVENT_FATAL_ERROR: 2618 { 2619 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n", 2620 dbgcGetEventCtx(pEvent->enmCtx)); 2621 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */ 2622 if (VBOX_SUCCESS(rc)) 2623 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r"); 2624 break; 2625 } 2626 2627 case DBGFEVENT_BREAKPOINT: 2628 case DBGFEVENT_BREAKPOINT_HYPER: 2629 { 2630 bool fRegCtxGuest = pDbgc->fRegCtxGuest; 2631 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT; 2632 2633 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp); 2634 switch (rc) 2635 { 2636 case VERR_DBGC_BP_NOT_FOUND: 2637 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n", 2638 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx)); 2639 break; 2640 2641 case VINF_DBGC_BP_NO_COMMAND: 2642 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n", 2643 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx)); 2644 break; 2645 2646 case VINF_BUFFER_OVERFLOW: 2647 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n", 2648 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx)); 2649 break; 2650 2651 default: 2652 break; 2653 } 2654 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM)) 2655 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r"); 2656 else 2657 pDbgc->fRegCtxGuest = fRegCtxGuest; 2658 break; 2659 } 2660 2661 case DBGFEVENT_STEPPED: 2662 case DBGFEVENT_STEPPED_HYPER: 2663 { 2664 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED; 2665 2666 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx)); 2667 if (VBOX_SUCCESS(rc)) 2668 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r"); 2669 break; 2670 } 2671 2672 case DBGFEVENT_ASSERTION_HYPER: 2673 { 2674 pDbgc->fRegCtxGuest = false; 2675 2676 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2677 "\ndbgf event: Hypervisor Assertion! (%s)\n" 2678 "%s" 2679 "%s" 2680 "\n", 2681 dbgcGetEventCtx(pEvent->enmCtx), 2682 pEvent->u.Assert.pszMsg1, 2683 pEvent->u.Assert.pszMsg2); 2684 if (VBOX_SUCCESS(rc)) 2685 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r"); 2686 break; 2687 } 2688 2689 case DBGFEVENT_DEV_STOP: 2690 { 2691 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2692 "\n" 2693 "dbgf event: DBGFSTOP (%s)\n" 2694 "File: %s\n" 2695 "Line: %d\n" 2696 "Function: %s\n", 2697 dbgcGetEventCtx(pEvent->enmCtx), 2698 pEvent->u.Src.pszFile, 2699 pEvent->u.Src.uLine, 2700 pEvent->u.Src.pszFunction); 2701 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage) 2702 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2703 "Message: %s\n", 2704 pEvent->u.Src.pszMessage); 2705 if (VBOX_SUCCESS(rc)) 2706 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r"); 2707 break; 2708 } 2709 2710 2711 case DBGFEVENT_INVALID_COMMAND: 2712 { 2713 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n"); 2714 fPrintPrompt = !pDbgc->fReady; 2715 break; 2716 } 2717 2718 case DBGFEVENT_TERMINATING: 2719 { 2720 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n"); 2721 rc = VERR_GENERAL_FAILURE; 2722 break; 2723 } 2724 2725 2726 default: 2727 { 2728 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType); 2729 fPrintPrompt = !pDbgc->fReady; 2730 break; 2731 } 2732 } 2733 2734 /* 2735 * Prompt, anyone? 2736 */ 2737 if (fPrintPrompt && VBOX_SUCCESS(rc)) 2738 { 2739 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> "); 2740 } 2741 2742 return rc; 2743 } 2744 2745 2746 2747 2748 2749 /** 2750 * Make a console instance. 2751 * 2752 * This will not return until either an 'exit' command is issued or a error code 2753 * indicating connection loss is encountered. 2754 * 2755 * @returns VINF_SUCCESS if console termination caused by the 'exit' command. 2756 * @returns The VBox status code causing the console termination. 2757 * 2758 * @param pVM VM Handle. 2759 * @param pBack Pointer to the backend structure. This must contain 2760 * a full set of function pointers to service the console. 2761 * @param fFlags Reserved, must be zero. 2762 * @remark A forced termination of the console is easiest done by forcing the 2763 * callbacks to return fatal failures. 2764 */ 2765 DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags) 2766 { 2767 /* 2768 * Validate input. 2769 */ 2770 AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER); 2771 AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER); 2772 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER); 2773 2774 /* 2775 * Allocate and initialize instance data 2776 */ 2777 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc)); 2778 if (!pDbgc) 2779 return VERR_NO_MEMORY; 2780 649 /** 650 * Initializes the Command Helpers for a DBGC instance. 651 * 652 * @param pDbgc Pointer to the DBGC instance. 653 */ 654 void dbgcInitCmdHlp(PDBGC pDbgc) 655 { 2781 656 pDbgc->CmdHlp.pfnWrite = dbgcHlpWrite; 2782 657 pDbgc->CmdHlp.pfnPrintfV = dbgcHlpPrintfV; … … 2790 665 pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr; 2791 666 pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool; 2792 pDbgc->pBack = pBack; 2793 pDbgc->pVM = NULL; 2794 pDbgc->pszEmulation = "CodeView/WinDbg"; 2795 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0]; 2796 pDbgc->cEmulationCmds = g_cCmdsCodeView; 2797 //pDbgc->fLog = false; 2798 pDbgc->fRegCtxGuest = true; 2799 pDbgc->fRegTerse = true; 2800 //pDbgc->DisasmPos = {0}; 2801 //pDbgc->SourcePos = {0}; 2802 //pDbgc->DumpPos = {0}; 2803 //pDbgc->cbDumpElement = 0; 2804 //pDbgc->cVars = 0; 2805 //pDbgc->paVars = NULL; 2806 //pDbgc->pFirstBp = NULL; 2807 //pDbgc->uInputZero = 0; 2808 //pDbgc->iRead = 0; 2809 //pDbgc->iWrite = 0; 2810 //pDbgc->cInputLines = 0; 2811 //pDbgc->fInputOverflow = false; 2812 pDbgc->fReady = true; 2813 pDbgc->pszScratch = &pDbgc->achScratch[0]; 2814 //pDbgc->iArg = 0; 2815 //pDbgc->rcOutput = 0; 2816 2817 dbgcInitOpCharBitMap(); 2818 2819 /* 2820 * Print welcome message. 2821 */ 2822 int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2823 "Welcome to the VirtualBox Debugger!\n"); 2824 if (VBOX_FAILURE(rc)) 2825 goto l_failure; 2826 2827 /* 2828 * Attach to the VM. 2829 */ 2830 rc = DBGFR3Attach(pVM); 2831 if (VBOX_FAILURE(rc)) 2832 { 2833 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM); 2834 goto l_failure; 2835 } 2836 pDbgc->pVM = pVM; 2837 2838 /* 2839 * Print commandline and auto select result. 2840 */ 2841 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2842 "Current VM is %08x\n" /** @todo get and print the VM name! */ 2843 "VBoxDbg> ", 2844 pDbgc->pVM); 2845 if (VBOX_FAILURE(rc)) 2846 goto l_failure; 2847 2848 /* 2849 * Main Debugger Loop. 2850 * 2851 * This loop will either block on waiting for input or on waiting on 2852 * debug events. If we're forwarding the log we cannot wait for long 2853 * before we must flush the log. 2854 */ 2855 for (rc = 0;;) 2856 { 2857 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM)) 2858 { 2859 /* 2860 * Wait for a debug event. 2861 */ 2862 PCDBGFEVENT pEvent; 2863 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent); 2864 if (VBOX_SUCCESS(rc)) 2865 { 2866 rc = dbgcProcessEvent(pDbgc, pEvent); 2867 if (VBOX_FAILURE(rc)) 2868 break; 2869 } 2870 else if (rc != VERR_TIMEOUT) 2871 break; 2872 2873 /* 2874 * Check for input. 2875 */ 2876 if (pBack->pfnInput(pDbgc->pBack, 0)) 2877 { 2878 rc = dbgcProcessInput(pDbgc); 2879 if (VBOX_FAILURE(rc)) 2880 break; 2881 } 2882 } 2883 else 2884 { 2885 /* 2886 * Wait for input. If Logging is enabled we'll only wait very briefly. 2887 */ 2888 if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000)) 2889 { 2890 rc = dbgcProcessInput(pDbgc); 2891 if (VBOX_FAILURE(rc)) 2892 break; 2893 } 2894 } 2895 2896 /* 2897 * Forward log output. 2898 */ 2899 if (pDbgc->fLog) 2900 { 2901 rc = dbgcProcessLog(pDbgc); 2902 if (VBOX_FAILURE(rc)) 2903 break; 2904 } 2905 } 2906 2907 2908 l_failure: 2909 /* 2910 * Cleanup console debugger session. 2911 */ 2912 /* Disable log hook. */ 2913 if (pDbgc->fLog) 2914 { 2915 2916 } 2917 2918 /* Detach from the VM. */ 2919 if (pDbgc->pVM) 2920 DBGFR3Detach(pDbgc->pVM); 2921 2922 /* finally, free the instance memory. */ 2923 RTMemFree(pDbgc); 2924 2925 return rc; 2926 } 2927 667 } 668 -
trunk/src/VBox/Debugger/DBGCInternal.h
r5675 r5676 341 341 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress); 342 342 343 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult); 343 int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult); 344 int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd); 345 346 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult); 344 347 PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol); 345 348 PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev); … … 350 353 DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 351 354 DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 355 356 void dbgcInitCmdHlp(PDBGC pDbgc); 352 357 353 358 -
trunk/src/VBox/Debugger/DBGConsole.cpp
r5675 r5676 129 129 130 130 /******************************************************************************* 131 * Internal Functions *132 *******************************************************************************/133 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);134 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);135 136 137 /*******************************************************************************138 131 * Global Variables * 139 132 *******************************************************************************/ … … 142 135 143 136 144 145 146 147 148 149 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//150 //151 //152 // C a l l b a c k H e l p e r s153 //154 //155 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//156 157 158 159 /**160 * Command helper for writing text to the debug console.161 *162 * @returns VBox status.163 * @param pCmdHlp Pointer to the command callback structure.164 * @param pvBuf What to write.165 * @param cbBuf Number of bytes to write.166 * @param pcbWritten Where to store the number of bytes actually written.167 * If NULL the entire buffer must be successfully written.168 */169 static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)170 {171 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);172 return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);173 }174 175 176 /**177 * Command helper for writing formatted text to the debug console.178 *179 * @returns VBox status.180 * @param pCmdHlp Pointer to the command callback structure.181 * @param pcb Where to store the number of bytes written.182 * @param pszFormat The format string.183 * This is using the log formatter, so it's format extensions can be used.184 * @param ... Arguments specified in the format string.185 */186 static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)187 {188 /*189 * Do the formatting and output.190 */191 va_list args;192 va_start(args, pszFormat);193 int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);194 va_end(args);195 196 return rc;197 }198 199 /**200 * Callback to format non-standard format specifiers.201 *202 * @returns The number of bytes formatted.203 * @param pvArg Formatter argument.204 * @param pfnOutput Pointer to output function.205 * @param pvArgOutput Argument for the output function.206 * @param ppszFormat Pointer to the format string pointer. Advance this till the char207 * after the format specifier.208 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.209 * @param cchWidth Format Width. -1 if not specified.210 * @param cchPrecision Format Precision. -1 if not specified.211 * @param fFlags Flags (RTSTR_NTFS_*).212 * @param chArgSize The argument size specifier, 'l' or 'L'.213 */214 static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,215 const char **ppszFormat, va_list *pArgs, int cchWidth,216 int cchPrecision, unsigned fFlags, char chArgSize)217 {218 NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);219 if (**ppszFormat != 'D')220 {221 (*ppszFormat)++;222 return 0;223 }224 225 (*ppszFormat)++;226 switch (**ppszFormat)227 {228 /*229 * Print variable without range.230 * The argument is a const pointer to the variable.231 */232 case 'V':233 {234 (*ppszFormat)++;235 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);236 switch (pVar->enmType)237 {238 case DBGCVAR_TYPE_GC_FLAT:239 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);240 case DBGCVAR_TYPE_GC_FAR:241 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);242 case DBGCVAR_TYPE_GC_PHYS:243 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);244 case DBGCVAR_TYPE_HC_FLAT:245 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);246 case DBGCVAR_TYPE_HC_FAR:247 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);248 case DBGCVAR_TYPE_HC_PHYS:249 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);250 case DBGCVAR_TYPE_STRING:251 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);252 case DBGCVAR_TYPE_NUMBER:253 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);254 255 case DBGCVAR_TYPE_UNKNOWN:256 default:257 return pfnOutput(pvArgOutput, "??", 2);258 }259 }260 261 /*262 * Print variable with range.263 * The argument is a const pointer to the variable.264 */265 case 'v':266 {267 (*ppszFormat)++;268 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);269 270 char szRange[32];271 switch (pVar->enmRangeType)272 {273 case DBGCVAR_RANGE_NONE:274 szRange[0] = '\0';275 break;276 case DBGCVAR_RANGE_ELEMENTS:277 RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);278 break;279 case DBGCVAR_RANGE_BYTES:280 RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);281 break;282 }283 284 switch (pVar->enmType)285 {286 case DBGCVAR_TYPE_GC_FLAT:287 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);288 case DBGCVAR_TYPE_GC_FAR:289 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);290 case DBGCVAR_TYPE_GC_PHYS:291 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);292 case DBGCVAR_TYPE_HC_FLAT:293 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);294 case DBGCVAR_TYPE_HC_FAR:295 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);296 case DBGCVAR_TYPE_HC_PHYS:297 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);298 case DBGCVAR_TYPE_STRING:299 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);300 case DBGCVAR_TYPE_NUMBER:301 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);302 303 case DBGCVAR_TYPE_UNKNOWN:304 default:305 return pfnOutput(pvArgOutput, "??", 2);306 }307 }308 309 default:310 AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));311 return 0;312 }313 }314 315 316 /**317 * Output callback.318 *319 * @returns number of bytes written.320 * @param pvArg User argument.321 * @param pachChars Pointer to an array of utf-8 characters.322 * @param cbChars Number of bytes in the character array pointed to by pachChars.323 */324 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)325 {326 PDBGC pDbgc = (PDBGC)pvArg;327 if (cbChars)328 {329 int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);330 if (VBOX_FAILURE(rc))331 {332 pDbgc->rcOutput = rc;333 cbChars = 0;334 }335 }336 337 return cbChars;338 }339 340 341 342 /**343 * Command helper for writing formatted text to the debug console.344 *345 * @returns VBox status.346 * @param pCmdHlp Pointer to the command callback structure.347 * @param pcb Where to store the number of bytes written.348 * @param pszFormat The format string.349 * This is using the log formatter, so it's format extensions can be used.350 * @param args Arguments specified in the format string.351 */352 static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)353 {354 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);355 356 /*357 * Do the formatting and output.358 */359 pDbgc->rcOutput = 0;360 size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);361 362 if (pcbWritten)363 *pcbWritten = cb;364 365 return pDbgc->rcOutput;366 }367 368 369 /**370 * Reports an error from a DBGF call.371 *372 * @returns VBox status code appropriate to return from a command.373 * @param pCmdHlp Pointer to command helpers.374 * @param rc The VBox status code returned by a DBGF call.375 * @param pszFormat Format string for additional messages. Can be NULL.376 * @param ... Format arguments, optional.377 */378 static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)379 {380 switch (rc)381 {382 case VINF_SUCCESS:383 break;384 385 default:386 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");387 if (VBOX_SUCCESS(rc) && pszFormat)388 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);389 break;390 }391 return rc;392 }393 394 395 /**396 * Reports an error from a DBGF call.397 *398 * @returns VBox status code appropriate to return from a command.399 * @param pCmdHlp Pointer to command helpers.400 * @param rc The VBox status code returned by a DBGF call.401 * @param pszFormat Format string for additional messages. Can be NULL.402 * @param ... Format arguments, optional.403 */404 static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)405 {406 va_list args;407 va_start(args, pszFormat);408 int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);409 va_end(args);410 return rcRet;411 }412 413 414 /**415 * Command helper for reading memory specified by a DBGC variable.416 *417 * @returns VBox status code appropriate to return from a command.418 * @param pCmdHlp Pointer to the command callback structure.419 * @param pVM VM handle if GC or physical HC address.420 * @param pvBuffer Where to store the read data.421 * @param cbRead Number of bytes to read.422 * @param pVarPointer DBGC variable specifying where to start reading.423 * @param pcbRead Where to store the number of bytes actually read.424 * This optional, but it's useful when read GC virtual memory where a425 * page in the requested range might not be present.426 * If not specified not-present failure or end of a HC physical page427 * will cause failure.428 */429 static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)430 {431 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);432 433 /*434 * Dummy check.435 */436 if (cbRead == 0)437 {438 if (*pcbRead)439 *pcbRead = 0;440 return VINF_SUCCESS;441 }442 443 /*444 * Convert Far addresses getting size and the correct base address.445 * Getting and checking the size is what makes this messy and slow.446 */447 DBGCVAR Var = *pVarPointer;448 switch (pVarPointer->enmType)449 {450 case DBGCVAR_TYPE_GC_FAR:451 {452 /* Use DBGFR3AddrFromSelOff for the conversion. */453 Assert(pDbgc->pVM);454 DBGFADDRESS Address;455 int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);456 if (VBOX_FAILURE(rc))457 return rc;458 459 /* don't bother with flat selectors (for now). */460 if (!DBGFADDRESS_IS_FLAT(&Address))461 {462 SELMSELINFO SelInfo;463 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);464 if (VBOX_SUCCESS(rc))465 {466 RTGCUINTPTR cb; /* -1 byte */467 if (SELMSelInfoIsExpandDown(&SelInfo))468 {469 if ( !SelInfo.Raw.Gen.u1Granularity470 && Address.off > UINT16_C(0xffff))471 return VERR_OUT_OF_SELECTOR_BOUNDS;472 if (Address.off <= SelInfo.cbLimit)473 return VERR_OUT_OF_SELECTOR_BOUNDS;474 cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;475 }476 else477 {478 if (Address.off > SelInfo.cbLimit)479 return VERR_OUT_OF_SELECTOR_BOUNDS;480 cb = SelInfo.cbLimit - Address.off;481 }482 if (cbRead - 1 > cb)483 {484 if (!pcbRead)485 return VERR_OUT_OF_SELECTOR_BOUNDS;486 cbRead = cb + 1;487 }488 }489 490 Var.enmType = DBGCVAR_TYPE_GC_FLAT;491 Var.u.GCFlat = Address.FlatPtr;492 }493 break;494 }495 496 case DBGCVAR_TYPE_GC_FLAT:497 case DBGCVAR_TYPE_GC_PHYS:498 case DBGCVAR_TYPE_HC_FLAT:499 case DBGCVAR_TYPE_HC_PHYS:500 break;501 502 case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */503 default:504 return VERR_NOT_IMPLEMENTED;505 }506 507 508 509 /*510 * Copy page by page.511 */512 size_t cbLeft = cbRead;513 for (;;)514 {515 /*516 * Calc read size.517 */518 size_t cb = RT_MIN(PAGE_SIZE, cbLeft);519 switch (pVarPointer->enmType)520 {521 case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;522 case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;523 case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;524 case DBGCVAR_TYPE_HC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - ((size_t)Var.u.HCPhys & PAGE_OFFSET_MASK)); break; /* size_t: MSC has braindead loss of data warnings! */525 default: break;526 }527 528 /*529 * Perform read.530 */531 int rc;532 switch (Var.enmType)533 {534 case DBGCVAR_TYPE_GC_FLAT:535 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);536 break;537 case DBGCVAR_TYPE_GC_PHYS:538 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);539 break;540 541 case DBGCVAR_TYPE_HC_PHYS:542 case DBGCVAR_TYPE_HC_FLAT:543 case DBGCVAR_TYPE_HC_FAR:544 {545 DBGCVAR Var2;546 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);547 if (VBOX_SUCCESS(rc))548 {549 /** @todo protect this!!! */550 memcpy(pvBuffer, Var2.u.pvHCFlat, cb);551 rc = 0;552 }553 else554 rc = VERR_INVALID_POINTER;555 break;556 }557 558 default:559 rc = VERR_PARSE_INCORRECT_ARG_TYPE;560 }561 562 /*563 * Check for failure.564 */565 if (VBOX_FAILURE(rc))566 {567 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)568 return VINF_SUCCESS;569 return rc;570 }571 572 /*573 * Next.574 */575 cbLeft -= cb;576 if (!cbLeft)577 break;578 pvBuffer = (char *)pvBuffer + cb;579 rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);580 if (VBOX_FAILURE(rc))581 {582 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)583 return VINF_SUCCESS;584 return rc;585 }586 }587 588 /*589 * Done590 */591 if (pcbRead)592 *pcbRead = cbRead;593 return 0;594 }595 596 /**597 * Command helper for writing memory specified by a DBGC variable.598 *599 * @returns VBox status code appropriate to return from a command.600 * @param pCmdHlp Pointer to the command callback structure.601 * @param pVM VM handle if GC or physical HC address.602 * @param pvBuffer What to write.603 * @param cbWrite Number of bytes to write.604 * @param pVarPointer DBGC variable specifying where to start reading.605 * @param pcbWritten Where to store the number of bytes written.606 * This is optional. If NULL be aware that some of the buffer607 * might have been written to the specified address.608 */609 static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)610 {611 NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);612 return VERR_NOT_IMPLEMENTED;613 }614 615 616 /**617 * Evaluates an expression.618 * (Hopefully the parser and functions are fully reentrant.)619 *620 * @returns VBox status code appropriate to return from a command.621 * @param pCmdHlp Pointer to the command callback structure.622 * @param pResult Where to store the result.623 * @param pszExpr The expression. Format string with the format DBGC extensions.624 * @param ... Format arguments.625 */626 static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)627 {628 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);629 630 /*631 * Format the expression.632 */633 char szExprFormatted[2048];634 va_list args;635 va_start(args, pszExpr);636 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);637 va_end(args);638 /* ignore overflows. */639 640 return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);641 }642 643 644 /**645 * Executes one command expression.646 * (Hopefully the parser and functions are fully reentrant.)647 *648 * @returns VBox status code appropriate to return from a command.649 * @param pCmdHlp Pointer to the command callback structure.650 * @param pszExpr The expression. Format string with the format DBGC extensions.651 * @param ... Format arguments.652 */653 static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)654 {655 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);656 /* Save the scratch state. */657 char *pszScratch = pDbgc->pszScratch;658 unsigned iArg = pDbgc->iArg;659 660 /*661 * Format the expression.662 */663 va_list args;664 va_start(args, pszExpr);665 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);666 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);667 va_end(args);668 if (cb >= cbScratch)669 return VERR_BUFFER_OVERFLOW;670 671 /*672 * Execute the command.673 * We save and restore the arg index and scratch buffer pointer.674 */675 pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;676 int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);677 678 /* Restore the scratch state. */679 pDbgc->iArg = iArg;680 pDbgc->pszScratch = pszScratch;681 682 return rc;683 }684 685 686 /**687 * Converts a DBGC variable to a DBGF address structure.688 *689 * @returns VBox status code.690 * @param pCmdHlp Pointer to the command callback structure.691 * @param pVar The variable to convert.692 * @param pAddress The target address.693 */694 static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)695 {696 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);697 return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);698 }699 700 701 /**702 * Converts a DBGC variable to a boolean.703 *704 * @returns VBox status code.705 * @param pCmdHlp Pointer to the command callback structure.706 * @param pVar The variable to convert.707 * @param pf Where to store the boolean.708 */709 static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)710 {711 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);712 NOREF(pDbgc);713 714 switch (pVar->enmType)715 {716 case DBGCVAR_TYPE_STRING:717 /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */718 if ( !strcmp(pVar->u.pszString, "true")719 || !strcmp(pVar->u.pszString, "True")720 || !strcmp(pVar->u.pszString, "TRUE")721 || !strcmp(pVar->u.pszString, "on")722 || !strcmp(pVar->u.pszString, "On")723 || !strcmp(pVar->u.pszString, "oN")724 || !strcmp(pVar->u.pszString, "ON")725 || !strcmp(pVar->u.pszString, "enabled")726 || !strcmp(pVar->u.pszString, "Enabled")727 || !strcmp(pVar->u.pszString, "DISABLED"))728 {729 *pf = true;730 return VINF_SUCCESS;731 }732 if ( !strcmp(pVar->u.pszString, "false")733 || !strcmp(pVar->u.pszString, "False")734 || !strcmp(pVar->u.pszString, "FALSE")735 || !strcmp(pVar->u.pszString, "off")736 || !strcmp(pVar->u.pszString, "Off")737 || !strcmp(pVar->u.pszString, "OFF")738 || !strcmp(pVar->u.pszString, "disabled")739 || !strcmp(pVar->u.pszString, "Disabled")740 || !strcmp(pVar->u.pszString, "DISABLED"))741 {742 *pf = false;743 return VINF_SUCCESS;744 }745 return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */746 747 case DBGCVAR_TYPE_GC_FLAT:748 case DBGCVAR_TYPE_GC_PHYS:749 case DBGCVAR_TYPE_HC_FLAT:750 case DBGCVAR_TYPE_HC_PHYS:751 case DBGCVAR_TYPE_NUMBER:752 *pf = pVar->u.u64Number != 0;753 return VINF_SUCCESS;754 755 case DBGCVAR_TYPE_HC_FAR:756 case DBGCVAR_TYPE_GC_FAR:757 case DBGCVAR_TYPE_SYMBOL:758 default:759 return VERR_PARSE_INCORRECT_ARG_TYPE;760 }761 }762 137 763 138 … … 1899 1274 * @param pResult Where to store the result of the expression evaluation. 1900 1275 */ 1901 staticint dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)1276 int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult) 1902 1277 { 1903 1278 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr)); … … 2295 1670 * @param cchCmd Length of the command. 2296 1671 */ 2297 staticint dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)1672 int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd) 2298 1673 { 2299 1674 char *pszCmdInput = pszCmd; … … 2779 2154 return VERR_NO_MEMORY; 2780 2155 2781 pDbgc->CmdHlp.pfnWrite = dbgcHlpWrite; 2782 pDbgc->CmdHlp.pfnPrintfV = dbgcHlpPrintfV; 2783 pDbgc->CmdHlp.pfnPrintf = dbgcHlpPrintf; 2784 pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV; 2785 pDbgc->CmdHlp.pfnVBoxError = dbgcHlpVBoxError; 2786 pDbgc->CmdHlp.pfnMemRead = dbgcHlpMemRead; 2787 pDbgc->CmdHlp.pfnMemWrite = dbgcHlpMemWrite; 2788 pDbgc->CmdHlp.pfnEval = dbgcHlpEval; 2789 pDbgc->CmdHlp.pfnExec = dbgcHlpExec; 2790 pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr; 2791 pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool; 2156 dbgcInitCmdHlp(pDbgc); 2792 2157 pDbgc->pBack = pBack; 2793 2158 pDbgc->pVM = NULL; -
trunk/src/VBox/Debugger/Makefile.kmk
r5675 r5676 37 37 DBGConsole.cpp \ 38 38 DBGCBuiltInSymbols.cpp \ 39 DBGCCmdHlp.cpp \ 39 40 DBGCCommands.cpp \ 40 41 DBGCEmulateCodeView.cpp \ … … 102 103 DBGConsole.cpp \ 103 104 DBGCBuiltInSymbols.cpp \ 105 DBGCCmdHlp.cpp \ 104 106 DBGCCommands.cpp \ 105 107 DBGCEmulateCodeView.cpp \
Note:
See TracChangeset
for help on using the changeset viewer.