Changeset 23722 in vbox
- Timestamp:
- Oct 13, 2009 1:05:29 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/CPUM.cpp
r23107 r23722 67 67 * Defined Constants And Macros * 68 68 *******************************************************************************/ 69 /** The saved state version. */ 69 /** The current saved state version. */ 70 #ifdef VBOX_WITH_LIVE_MIGRATION 71 #define CPUM_SAVED_STATE_VERSION 11 72 #else 70 73 #define CPUM_SAVED_STATE_VERSION 10 74 #endif 75 /** The saved state version of 3.0 and 3.1 trunk before the live migration 76 * changes. */ 77 #define CPUM_SAVED_STATE_VERSION_VER3_0 10 71 78 /** The saved state version for the 2.1 trunk before the MSR changes. */ 72 79 #define CPUM_SAVED_STATE_VERSION_VER2_1_NOMSR 9 … … 89 96 CPUMDUMPTYPE_DEFAULT, 90 97 CPUMDUMPTYPE_VERBOSE 91 92 98 } CPUMDUMPTYPE; 93 99 /** Pointer to a cpu info dump type. */ … … 99 105 *******************************************************************************/ 100 106 static int cpumR3CpuIdInit(PVM pVM); 101 static DECLCALLBACK(int) cpumR3Save(PVM pVM, PSSMHANDLE pSSM); 102 static DECLCALLBACK(int) cpumR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); 107 #ifdef VBOX_WITH_LIVE_MIGRATION 108 static DECLCALLBACK(int) cpumR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass); 109 #endif 110 static DECLCALLBACK(int) cpumR3SaveExec(PVM pVM, PSSMHANDLE pSSM); 111 static DECLCALLBACK(int) cpumR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); 103 112 static DECLCALLBACK(void) cpumR3InfoAll(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs); 104 113 static DECLCALLBACK(void) cpumR3InfoGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs); … … 198 207 * Register saved state data item. 199 208 */ 209 #ifdef VBOX_WITH_LIVE_MIGRATION 210 int rc = SSMR3RegisterInternal(pVM, "cpum", 1, CPUM_SAVED_STATE_VERSION, sizeof(CPUM), 211 NULL, cpumR3LiveExec, NULL, 212 NULL, cpumR3SaveExec, NULL, 213 NULL, cpumR3LoadExec, NULL); 214 #else 200 215 int rc = SSMR3RegisterInternal(pVM, "cpum", 1, CPUM_SAVED_STATE_VERSION, sizeof(CPUM), 201 216 NULL, NULL, NULL, 202 NULL, cpumR3Save, NULL, 203 NULL, cpumR3Load, NULL); 217 NULL, cpumR3SaveExec, NULL, 218 NULL, cpumR3LoadExec, NULL); 219 #endif 204 220 if (RT_FAILURE(rc)) 205 221 return rc; … … 840 856 } 841 857 858 #ifdef VBOX_WITH_LIVE_MIGRATION 859 860 /** 861 * Called both in pass 0 and the final pass. 862 * 863 * @param pVM The VM handle. 864 * @param pSSM The saved state handle. 865 */ 866 static void cpumR3SaveCpuId(PVM pVM, PSSMHANDLE pSSM) 867 { 868 /* 869 * Save all the CPU ID leafs here so we can check them for compatability 870 * upon loading. 871 */ 872 SSMR3PutU32(pSSM, RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd)); 873 SSMR3PutMem(pSSM, &pVM->cpum.s.aGuestCpuIdStd[0], sizeof(pVM->cpum.s.aGuestCpuIdStd)); 874 875 SSMR3PutU32(pSSM, RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt)); 876 SSMR3PutMem(pSSM, &pVM->cpum.s.aGuestCpuIdExt[0], sizeof(pVM->cpum.s.aGuestCpuIdExt)); 877 878 SSMR3PutU32(pSSM, RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur)); 879 SSMR3PutMem(pSSM, &pVM->cpum.s.aGuestCpuIdCentaur[0], sizeof(pVM->cpum.s.aGuestCpuIdCentaur)); 880 881 SSMR3PutMem(pSSM, &pVM->cpum.s.GuestCpuIdDef, sizeof(pVM->cpum.s.GuestCpuIdDef)); 882 883 /* 884 * Save a good portion of the raw CPU IDs as well as they may come in 885 * handy when validating features for raw mode. 886 */ 887 CPUMCPUID aRawStd[8]; 888 for (unsigned i = 0; i < RT_ELEMENTS(aRawStd); i++) 889 ASMCpuId(i, &aRawStd[i].eax, &aRawStd[i].ebx, &aRawStd[i].ecx, &aRawStd[i].edx); 890 SSMR3PutU32(pSSM, RT_ELEMENTS(aRawStd)); 891 SSMR3PutMem(pSSM, &aRawStd[0], sizeof(aRawStd)); 892 893 CPUMCPUID aRawExt[16]; 894 for (unsigned i = 0; i < RT_ELEMENTS(aRawExt); i++) 895 ASMCpuId(i | UINT32_C(0x80000000), &aRawExt[i].eax, &aRawExt[i].ebx, &aRawExt[i].ecx, &aRawExt[i].edx); 896 SSMR3PutU32(pSSM, RT_ELEMENTS(aRawExt)); 897 SSMR3PutMem(pSSM, &aRawExt[0], sizeof(aRawExt)); 898 } 899 900 901 /** 902 * Loads the CPU ID leafs saved by pass 0. 903 * 904 * @returns VBox status code. 905 * @param pVM The VM handle. 906 * @param pSSM The saved state handle. 907 * @param uVersion The format version. 908 */ 909 static int cpumR3LoadCpuId(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion) 910 { 911 AssertMsgReturn(uVersion >= CPUM_SAVED_STATE_VERSION, ("%u\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION); 912 913 /* 914 * Load them into stack buffers first. 915 */ 916 CPUMCPUID aGuestCpuIdStd[RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd)]; 917 uint32_t cGuestCpuIdStd; 918 int rc = SSMR3GetU32(pSSM, &cGuestCpuIdStd); AssertRCReturn(rc, rc); 919 if (cGuestCpuIdStd > RT_ELEMENTS(aGuestCpuIdStd)) 920 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED; 921 SSMR3GetMem(pSSM, &aGuestCpuIdStd[0], cGuestCpuIdStd * sizeof(aGuestCpuIdStd[0])); 922 923 CPUMCPUID aGuestCpuIdExt[RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdExt)]; 924 uint32_t cGuestCpuIdExt; 925 rc = SSMR3GetU32(pSSM, &cGuestCpuIdExt); AssertRCReturn(rc, rc); 926 if (cGuestCpuIdExt > RT_ELEMENTS(aGuestCpuIdExt)) 927 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED; 928 SSMR3GetMem(pSSM, &aGuestCpuIdExt[0], cGuestCpuIdExt * sizeof(aGuestCpuIdExt[0])); 929 930 CPUMCPUID aGuestCpuIdCentaur[RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdCentaur)]; 931 uint32_t cGuestCpuIdCentaur; 932 rc = SSMR3GetU32(pSSM, &cGuestCpuIdCentaur); AssertRCReturn(rc, rc); 933 if (cGuestCpuIdCentaur > RT_ELEMENTS(aGuestCpuIdCentaur)) 934 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED; 935 SSMR3GetMem(pSSM, &aGuestCpuIdCentaur[0], cGuestCpuIdCentaur * sizeof(aGuestCpuIdCentaur[0])); 936 937 CPUMCPUID GuestCpuIdDef; 938 rc = SSMR3GetMem(pSSM, &pVM->cpum.s.GuestCpuIdDef, sizeof(pVM->cpum.s.GuestCpuIdDef)); 939 AssertRCReturn(rc, rc); 940 941 CPUMCPUID aRawStd[8]; 942 uint32_t cRawStd; 943 rc = SSMR3GetU32(pSSM, &cRawStd); AssertRCReturn(rc, rc); 944 if (cRawStd > RT_ELEMENTS(aRawStd)) 945 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED; 946 SSMR3GetMem(pSSM, &aRawStd[0], cRawStd * sizeof(aRawStd[0])); 947 948 CPUMCPUID aRawExt[16]; 949 uint32_t cRawExt; 950 rc = SSMR3GetU32(pSSM, &cRawExt); AssertRCReturn(rc, rc); 951 if (cRawExt > RT_ELEMENTS(aRawExt)) 952 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED; 953 rc = SSMR3GetMem(pSSM, &aRawExt[0], cRawExt * sizeof(aRawExt[0])); 954 AssertRCReturn(rc, rc); 955 956 /* 957 * Note that we support restoring less than the current amount of standard 958 * leaves because we've been allowed more is newer version of VBox. 959 * 960 * So, pad new entries with the default. 961 */ 962 for (uint32_t i = cGuestCpuIdStd; i < RT_ELEMENTS(aGuestCpuIdStd); i++) 963 aGuestCpuIdStd[i] = GuestCpuIdDef; 964 965 for (uint32_t i = cGuestCpuIdExt; i < RT_ELEMENTS(aGuestCpuIdExt); i++) 966 aGuestCpuIdExt[i] = GuestCpuIdDef; 967 968 for (uint32_t i = cGuestCpuIdCentaur; i < RT_ELEMENTS(aGuestCpuIdCentaur); i++) 969 aGuestCpuIdCentaur[i] = GuestCpuIdDef; 970 971 for (uint32_t i = cRawStd; i < RT_ELEMENTS(aRawStd); i++) 972 ASMCpuId(i, &aRawStd[i].eax, &aRawStd[i].ebx, &aRawStd[i].ecx, &aRawStd[i].edx); 973 974 for (uint32_t i = cRawExt; i < RT_ELEMENTS(aRawExt); i++) 975 ASMCpuId(i | UINT32_C(0x80000000), &aRawExt[i].eax, &aRawExt[i].ebx, &aRawExt[i].ecx, &aRawExt[i].edx); 976 977 /* 978 * Get the raw CPU IDs for the current host. 979 */ 980 CPUMCPUID aHostRawStd[8]; 981 for (unsigned i = 0; i < RT_ELEMENTS(aHostRawStd); i++) 982 ASMCpuId(i, &aHostRawStd[i].eax, &aHostRawStd[i].ebx, &aHostRawStd[i].ecx, &aHostRawStd[i].edx); 983 984 CPUMCPUID aHostRawExt[16]; 985 for (unsigned i = 0; i < RT_ELEMENTS(aHostRawExt); i++) 986 ASMCpuId(i | UINT32_C(0x80000000), &aHostRawExt[i].eax, &aHostRawExt[i].ebx, &aHostRawExt[i].ecx, &aHostRawExt[i].edx); 987 988 /* 989 * Now for the fun part... 990 */ 991 992 993 /* 994 * We're good, commit the CPU ID leafs. 995 */ 996 memcmp(&pVM->cpum.s.aGuestCpuIdStd[0], &aGuestCpuIdStd[0], sizeof(aGuestCpuIdStd)); 997 memcmp(&pVM->cpum.s.aGuestCpuIdExt[0], &aGuestCpuIdExt[0], sizeof(aGuestCpuIdExt)); 998 memcmp(&pVM->cpum.s.aGuestCpuIdCentaur[0], &aGuestCpuIdCentaur[0], sizeof(aGuestCpuIdCentaur)); 999 pVM->cpum.s.GuestCpuIdDef = GuestCpuIdDef; 1000 1001 return VINF_SUCCESS; 1002 } 1003 1004 1005 /** 1006 * Pass 0 live exec callback. 1007 * 1008 * @returns VINF_SSM_DONT_CALL_AGAIN. 1009 * @param pVM The VM handle. 1010 * @param pSSM The saved state handle. 1011 * @param uPass The pass (0). 1012 */ 1013 static DECLCALLBACK(int) cpumR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass) 1014 { 1015 AssertReturn(uPass == 0, VERR_INTERNAL_ERROR_4); 1016 cpumR3SaveCpuId(pVM, pSSM); 1017 return VINF_SSM_DONT_CALL_AGAIN; 1018 } 1019 1020 #endif /* VBOX_WITH_LIVE_MIGRATION */ 842 1021 843 1022 /** … … 848 1027 * @param pSSM SSM operation handle. 849 1028 */ 850 static DECLCALLBACK(int) cpumR3Save (PVM pVM, PSSMHANDLE pSSM)1029 static DECLCALLBACK(int) cpumR3SaveExec(PVM pVM, PSSMHANDLE pSSM) 851 1030 { 852 1031 /* … … 870 1049 SSMR3PutMem(pSSM, &pVCpu->cpum.s.GuestMsr, sizeof(pVCpu->cpum.s.GuestMsr)); 871 1050 } 1051 1052 #ifdef VBOX_WITH_LIVE_MIGRATION 1053 cpumR3SaveCpuId(pVM, pSSM); 1054 return VINF_SUCCESS; 1055 #else 872 1056 873 1057 SSMR3PutU32(pSSM, RT_ELEMENTS(pVM->cpum.s.aGuestCpuIdStd)); … … 887 1071 ASMCpuId(1, &au32CpuId[4], &au32CpuId[5], &au32CpuId[6], &au32CpuId[7]); 888 1072 return SSMR3PutMem(pSSM, &au32CpuId[0], sizeof(au32CpuId)); 1073 #endif 889 1074 } 890 1075 … … 994 1179 * @param uPass The data pass. 995 1180 */ 996 static DECLCALLBACK(int) cpumR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) 997 { 998 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass); 999 1181 static DECLCALLBACK(int) cpumR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) 1182 { 1000 1183 /* 1001 1184 * Validate version. 1002 1185 */ 1003 1186 if ( uVersion != CPUM_SAVED_STATE_VERSION 1187 && uVersion != CPUM_SAVED_STATE_VERSION_VER3_0 1004 1188 && uVersion != CPUM_SAVED_STATE_VERSION_VER2_1_NOMSR 1005 1189 && uVersion != CPUM_SAVED_STATE_VERSION_VER2_0 1006 1190 && uVersion != CPUM_SAVED_STATE_VERSION_VER1_6) 1007 1191 { 1008 AssertMsgFailed(("cpu R3Load: Invalid version uVersion=%d!\n", uVersion));1192 AssertMsgFailed(("cpumR3LoadExec: Invalid version uVersion=%d!\n", uVersion)); 1009 1193 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; 1010 1194 } 1011 1195 1012 /* Set the size of RTGCPTR for SSMR3GetGCPtr. */ 1013 if (uVersion == CPUM_SAVED_STATE_VERSION_VER1_6) 1014 SSMR3SetGCPtrSize(pSSM, sizeof(RTGCPTR32)); 1015 else if (uVersion <= CPUM_SAVED_STATE_VERSION) 1016 SSMR3SetGCPtrSize(pSSM, HC_ARCH_BITS == 32 ? sizeof(RTGCPTR32) : sizeof(RTGCPTR)); 1017 1018 /* 1019 * Restore. 1020 */ 1021 for (VMCPUID i = 0; i < pVM->cCpus; i++) 1022 { 1023 PVMCPU pVCpu = &pVM->aCpus[i]; 1024 uint32_t uCR3 = pVCpu->cpum.s.Hyper.cr3; 1025 uint32_t uESP = pVCpu->cpum.s.Hyper.esp; /* see VMMR3Relocate(). */ 1026 1027 SSMR3GetMem(pSSM, &pVCpu->cpum.s.Hyper, sizeof(pVCpu->cpum.s.Hyper)); 1028 pVCpu->cpum.s.Hyper.cr3 = uCR3; 1029 pVCpu->cpum.s.Hyper.esp = uESP; 1030 } 1031 1032 if (uVersion == CPUM_SAVED_STATE_VERSION_VER1_6) 1033 { 1034 CPUMCTX_VER1_6 cpumctx16; 1035 memset(&pVM->aCpus[0].cpum.s.Guest, 0, sizeof(pVM->aCpus[0].cpum.s.Guest)); 1036 SSMR3GetMem(pSSM, &cpumctx16, sizeof(cpumctx16)); 1037 1038 /* Save the old cpumctx state into the new one. */ 1039 cpumR3LoadCPUM1_6(pVM, &cpumctx16); 1040 1041 SSMR3GetU32(pSSM, &pVM->aCpus[0].cpum.s.fUseFlags); 1042 SSMR3GetU32(pSSM, &pVM->aCpus[0].cpum.s.fChanged); 1043 } 1044 else 1045 { 1046 if (uVersion >= CPUM_SAVED_STATE_VERSION_VER2_1_NOMSR) 1047 { 1048 uint32_t cCpus; 1049 int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc); 1050 AssertLogRelMsgReturn(cCpus == pVM->cCpus, ("Mismatching CPU counts: saved: %u; configured: %u \n", cCpus, pVM->cCpus), 1051 VERR_SSM_UNEXPECTED_DATA); 1052 } 1053 AssertLogRelMsgReturn( uVersion != CPUM_SAVED_STATE_VERSION_VER2_0 1054 || pVM->cCpus == 1, 1055 ("cCpus=%u\n", pVM->cCpus), 1056 VERR_SSM_UNEXPECTED_DATA); 1057 1196 if (uPass == SSM_PASS_FINAL) 1197 { 1198 /* 1199 * Set the size of RTGCPTR for SSMR3GetGCPtr. (Only necessary for 1200 * really old SSM file versions.) 1201 */ 1202 if (uVersion == CPUM_SAVED_STATE_VERSION_VER1_6) 1203 SSMR3SetGCPtrSize(pSSM, sizeof(RTGCPTR32)); 1204 else if (uVersion <= CPUM_SAVED_STATE_VERSION_VER3_0) 1205 SSMR3SetGCPtrSize(pSSM, HC_ARCH_BITS == 32 ? sizeof(RTGCPTR32) : sizeof(RTGCPTR)); 1206 1207 /* 1208 * Restore. 1209 */ 1058 1210 for (VMCPUID i = 0; i < pVM->cCpus; i++) 1059 1211 { 1060 SSMR3GetMem(pSSM, &pVM->aCpus[i].cpum.s.Guest, sizeof(pVM->aCpus[i].cpum.s.Guest)); 1061 SSMR3GetU32(pSSM, &pVM->aCpus[i].cpum.s.fUseFlags); 1062 SSMR3GetU32(pSSM, &pVM->aCpus[i].cpum.s.fChanged); 1063 if (uVersion == CPUM_SAVED_STATE_VERSION) 1064 SSMR3GetMem(pSSM, &pVM->aCpus[i].cpum.s.GuestMsr, sizeof(pVM->aCpus[i].cpum.s.GuestMsr)); 1212 PVMCPU pVCpu = &pVM->aCpus[i]; 1213 uint32_t uCR3 = pVCpu->cpum.s.Hyper.cr3; 1214 uint32_t uESP = pVCpu->cpum.s.Hyper.esp; /* see VMMR3Relocate(). */ 1215 1216 SSMR3GetMem(pSSM, &pVCpu->cpum.s.Hyper, sizeof(pVCpu->cpum.s.Hyper)); 1217 pVCpu->cpum.s.Hyper.cr3 = uCR3; 1218 pVCpu->cpum.s.Hyper.esp = uESP; 1065 1219 } 1066 } 1220 1221 if (uVersion == CPUM_SAVED_STATE_VERSION_VER1_6) 1222 { 1223 CPUMCTX_VER1_6 cpumctx16; 1224 memset(&pVM->aCpus[0].cpum.s.Guest, 0, sizeof(pVM->aCpus[0].cpum.s.Guest)); 1225 SSMR3GetMem(pSSM, &cpumctx16, sizeof(cpumctx16)); 1226 1227 /* Save the old cpumctx state into the new one. */ 1228 cpumR3LoadCPUM1_6(pVM, &cpumctx16); 1229 1230 SSMR3GetU32(pSSM, &pVM->aCpus[0].cpum.s.fUseFlags); 1231 SSMR3GetU32(pSSM, &pVM->aCpus[0].cpum.s.fChanged); 1232 } 1233 else 1234 { 1235 if (uVersion >= CPUM_SAVED_STATE_VERSION_VER2_1_NOMSR) 1236 { 1237 uint32_t cCpus; 1238 int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc); 1239 AssertLogRelMsgReturn(cCpus == pVM->cCpus, ("Mismatching CPU counts: saved: %u; configured: %u \n", cCpus, pVM->cCpus), 1240 VERR_SSM_UNEXPECTED_DATA); 1241 } 1242 AssertLogRelMsgReturn( uVersion != CPUM_SAVED_STATE_VERSION_VER2_0 1243 || pVM->cCpus == 1, 1244 ("cCpus=%u\n", pVM->cCpus), 1245 VERR_SSM_UNEXPECTED_DATA); 1246 1247 for (VMCPUID i = 0; i < pVM->cCpus; i++) 1248 { 1249 SSMR3GetMem(pSSM, &pVM->aCpus[i].cpum.s.Guest, sizeof(pVM->aCpus[i].cpum.s.Guest)); 1250 SSMR3GetU32(pSSM, &pVM->aCpus[i].cpum.s.fUseFlags); 1251 SSMR3GetU32(pSSM, &pVM->aCpus[i].cpum.s.fChanged); 1252 if (uVersion >= CPUM_SAVED_STATE_VERSION_VER3_0) 1253 SSMR3GetMem(pSSM, &pVM->aCpus[i].cpum.s.GuestMsr, sizeof(pVM->aCpus[i].cpum.s.GuestMsr)); 1254 } 1255 } 1256 } 1257 1258 #ifdef VBOX_WITH_LIVE_MIGRATION 1259 if (uVersion > CPUM_SAVED_STATE_VERSION_VER3_0) 1260 return cpumR3LoadCpuId(pVM, pSSM, uVersion); 1261 1262 /** @todo Merge the code below into cpumR3LoadCpuId when we've found out what is 1263 * actually required. */ 1264 #endif 1067 1265 1068 1266 /* … … 1092 1290 /* 1093 1291 * Check that the basic cpuid id information is unchanged. 1094 * @todo we should check the 64 bits capabilities too!1095 */1292 */ 1293 /** @todo we should check the 64 bits capabilities too! */ 1096 1294 uint32_t au32CpuId[8] = {0}; 1097 1295 ASMCpuId(0, &au32CpuId[0], &au32CpuId[1], &au32CpuId[2], &au32CpuId[3]); … … 1156 1354 { 1157 1355 if (SSMR3HandleGetAfter(pSSM) == SSMAFTER_DEBUG_IT) 1158 LogRel(("cpumR3Load : CpuId mismatch! (ignored due to SSMAFTER_DEBUG_IT)\n"1356 LogRel(("cpumR3LoadExec: CpuId mismatch! (ignored due to SSMAFTER_DEBUG_IT)\n" 1159 1357 "Saved=%.*Rhxs\n" 1160 1358 "Real =%.*Rhxs\n", … … 1163 1361 else 1164 1362 { 1165 LogRel(("cpumR3Load : CpuId mismatch!\n"1363 LogRel(("cpumR3LoadExec: CpuId mismatch!\n" 1166 1364 "Saved=%.*Rhxs\n" 1167 1365 "Real =%.*Rhxs\n",
Note:
See TracChangeset
for help on using the changeset viewer.