Вы можете попытаться выполнить состояние принятия vboxmanage, которое, согласно документации, попытается изменить виртуальную машину, чтобы прикрепить текущий снимок к предлагаемому состоянию сохранения.
Если это не сработало, parsiya сделал интересный блог о разборе состояния SAV, который можно найти здесь: parsiya blog
Согласно его блогу, состояние SAVE описано в SSM.cpp
Новая информация, которую я нашел, основана на SSMFILEHDRV12 (более поздняя, чем парсия). Блок RTGCPHYS находится в GIM_HV_PAGE_SIZE (4096). Это больше единица и в целом 08 * 4096, если я правильно понял.
На самом деле есть еще один блок для данных, созданный в дальнейшем сделано
Если я правильно понял, логика кода SSM.cpp, как объяснено в начале, состоит в том, чтобы выполнить состояние сохранения в реальном времени. Т.е. общий размер неизвестен. Таким образом, может быть записано несколько единиц памяти.
Если есть только одна единица необработанной памяти, то да, вы можете определить размер виртуальной машины. Пробег меняется
Извлечение из начала файла
* The live snapshots feature (LS) is similar to teleportation (TP) and was a
* natural first step when implementing TP. The main differences between LS and
* TP are that after a live snapshot we will have a saved state file, disk image
* snapshots, and the VM will still be running.
* * Compared to normal saved stated and snapshots, the difference is in that the
* VM is running while we do most of the saving. Prior to LS, there was only
* one round of callbacks during saving and the VM was paused during it. With
* LS there are 1 or more passes while the VM is still running and a final one
* after it has been paused. The runtime passes are executed on a dedicated
* thread running at at the same priority as the EMTs so that the saving doesn't
* starve or lose in scheduling questions (note: not implemented yet). The final
* pass is done on EMT(0).
* The saved state units each starts with a variable sized header
* (SSMFILEUNITHDRV2) that contains the name, instance and pass. The data
* follows the header and is encoded as records with a 2-8 byte record header
* indicating the type, flags and size. The first byte in the record header
* indicates the type and flags:
* * - bits 0..3: Record type:
* - type 0: Invalid.
* - type 1: Terminator with CRC-32 and unit size.
* - type 2: Raw data record.
* - type 3: Raw data compressed by LZF. The data is prefixed by a 8-bit
* field containing the length of the uncompressed data given in
* 1KB units.
* - type 4: Zero data. The record header is followed by a 8-bit field
* counting the length of the zero data given in 1KB units.
* - type 5: Named data - length prefixed name followed by the data. This
* type is not implemented yet as we're missing the API part, so
* the type assignment is tentative.
* - types 6 thru 15 are current undefined.
* - bit 4: Important (set), can be skipped (clear).
* - bit 5: Undefined flag, must be zero.
* - bit 6: Undefined flag, must be zero.
* - bit 7: "magic" bit, always set.
/**
* Writes a record header for the specified amount of data.
*
* @returns VBox status code. Sets pSSM->rc on failure.
* @param pSSM The saved state handle
* @param cb The amount of data.
* @param u8TypeAndFlags The record type and flags.
*/
static int ssmR3DataWriteRecHdr(PSSMHANDLE pSSM, size_t cb, uint8_t u8TypeAndFlags)
{
size_t cbHdr;
uint8_t abHdr[8];
abHdr[0] = u8TypeAndFlags;
if (cb < 0x80)
{
cbHdr = 2;
abHdr[1] = (uint8_t)cb;
}
else if (cb < 0x00000800)
{
cbHdr = 3;
abHdr[1] = (uint8_t)(0xc0 | (cb >> 6));
abHdr[2] = (uint8_t)(0x80 | (cb & 0x3f));
}
else if (cb < 0x00010000)
{
cbHdr = 4;
abHdr[1] = (uint8_t)(0xe0 | (cb >> 12));
abHdr[2] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
abHdr[3] = (uint8_t)(0x80 | (cb & 0x3f));
}
else if (cb < 0x00200000)
{
cbHdr = 5;
abHdr[1] = (uint8_t)(0xf0 | (cb >> 18));
abHdr[2] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
abHdr[3] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
abHdr[4] = (uint8_t)(0x80 | (cb & 0x3f));
}
else if (cb < 0x04000000)
{
cbHdr = 6;
abHdr[1] = (uint8_t)(0xf8 | (cb >> 24));
abHdr[2] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
abHdr[3] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
abHdr[4] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
abHdr[5] = (uint8_t)(0x80 | (cb & 0x3f));
}
else if (cb <= 0x7fffffff)
{
cbHdr = 7;
abHdr[1] = (uint8_t)(0xfc | (cb >> 30));
abHdr[2] = (uint8_t)(0x80 | ((cb >> 24) & 0x3f));
abHdr[3] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
abHdr[4] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
abHdr[5] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
abHdr[6] = (uint8_t)(0x80 | (cb & 0x3f));
}
else
AssertLogRelMsgFailedReturn(("cb=%#x\n", cb), pSSM->rc = VERR_SSM_MEM_TOO_BIG);
Log3(("ssmR3DataWriteRecHdr: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
ssmR3StrmTell(&pSSM->Strm) + cbHdr, pSSM->offUnit + cbHdr, cb, u8TypeAndFlags & SSM_REC_TYPE_MASK, !!(u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT), cbHdr));
return ssmR3DataWriteRaw(pSSM, &abHdr[0], cbHdr);
}
Он также заметил, как и Бриджи, что Юниты начинаются с ascii "Юнит", но также и то, что последний юнит заканчивается "TheEnd"
Он проанализировал некоторые структуры SAV-файла на основе структуры UNIT, описанной в SSMInternal.h здесь: virtualbox opensource header