復元したいVirtualBoxのファイルがあります.sav
。しかし、問題は、このファイルしか持っていないことです(ディスクファイルやRAMサイズなどの他の情報はありません)。仮想マシンの1つを複製し、スナップショットを作成し、スナップショットを置き換えました(正しいファイル名を使用)。そして、状態を復元すると、VirtualBoxがエラーをスローしました。
ユニット 'mm' のロードに失敗しました (VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH)
メモリサイズが分からないので先に進めません。
.sav
Google で検索したところ、スナップショット ファイルに仮想マシンのすべての情報と構成が含まれていることがわかりました。正しい構成を取得できるように、ファイルから情報を抽出できる方法はありますか?
答え1
以下は、執筆時点での VirtualBox の最新バージョン (4.3) に関するものです。古いバージョンについては不明です。
ファイルSAV
は で構成されていますunits
。 ファイルを 16 進エディターで開くと、SAV
次の 16 進文字列を検索して単位間を移動できます。
0A 55 6E 69 74 0A 00 00
これは、Unit
周囲にいくつかの文字がある単語です。ヒット後の 0x24 (36) バイトに、いくつかの ASCII 文字が表示されます。たとえば、最初の文字は次のようになりますSSM
。これはユニットの記述子であり、この場合は「Saved State Manager」です。
(メモリ マネージャー) ユニットを見つけたいとしますmm
。私の場合、これは常に SAV ファイル内の 3 番目のユニットでした。つまり、検索すると 3 番目の結果になります。
16 進数:
0A 55 6E 69 74 0A 00 00 52 01 00 00 00 00 00 00 7C 36 11 91 CE B0 E2
CE 02 00 00 00 01 00 00 00 FF FF FF FF 00 00 00 00 03 00 00 00 6D 6D
00 92 10 1E 00 08 00 00 00 00 00 00 00 00 80 00 00 00 00 91 0E 01 00
38 7E D4 06 22 00 00 00 00 00 00 00
ご覧のとおり、最初の 8 バイトはヘッダーです。unit
その後、0x24 (36) バイト後に が見つかります。3 バイト ( ) をスキップすると、スナップショットが作成された時点のシステム メモリの量である uint16 (リトルエンディアン) が得られます。私の例では、= = = です。6D 6D 00
mm\0
92 10 1E
00 08
0x800
2048
2GB
答え2
実行してみることができますvboxmanage 採用状態ドキュメントによると、これは VM を変更して、現在のスナップショットを提案された保存状態に添付しようとします。
うまくいかない場合は、parsiya が SAV 状態の解析について書いた興味深いブログをこちらからご覧ください。パルシアブログ
彼のブログによると、SAVE状態は次のように説明されている。SSM.cpp
私が見つけた新しい情報は、SSMFILEHDRV12(parsiyaより新しい)に基づいています。RTGCPHYSの単位はGIM_HV_PAGE_SIZE(4096)です。これは単位であり、私が正しく理解していれば、一般的に08 * 4096です。実際には、さらに作成されたデータ用の別の単位があります。
私が正しく理解していれば、冒頭で説明した SSM.cpp コードのロジックは、ライブ保存状態を実行することです。つまり、合計サイズは不明です。したがって、複数のメモリ ユニットが記録されている可能性があります。生のメモリが 1 ユニットしかない場合は、はい、VM のサイズを推測できます。マイレージは異なります。
ファイルの冒頭から抜粋
* 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の「Unit」で始まるが、最後のユニットは「TheEnd」で終わることに気づいた。
彼は、SSMInternal.h に記述されている UNIT の構造に基づいて、SAV ファイルの構造の一部を解析しました。バーチャルボックスオープンソースヘッダー