diff --git a/CHANGELOG.md b/CHANGELOG.md index e154e19372e..14e90aedf08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ each individual block device will emit metrics under the label `"block_{drive_id}"`. E.g. the associated metrics for the endpoint `"/drives/{drive_id}"` will be available under `"block_drive_id"` in the metrics json object. +- [#4205](https://github.com/firecracker-microvm/firecracker/pull/4205): + Added a new `vm-state` subcommand to `info-vmstate` command in the + `snapshot-editor` tool to print MicrovmState of vmstate snapshot file in + a readable format. Also made the `vcpu-states` subcommand available on + x86_64. ### Changed diff --git a/docs/snapshotting/snapshot-editor.md b/docs/snapshotting/snapshot-editor.md index 4ecbb82c6e2..6101830a1eb 100644 --- a/docs/snapshotting/snapshot-editor.md +++ b/docs/snapshotting/snapshot-editor.md @@ -16,104 +16,125 @@ Firecracker snapshot consists of 2 files: #### `rebase` subcommand -This command is used to merge a `diff` snapshot memory file on -top of a base memory file. - -**Note** -You can also use `rebase-snap` (deprecated) tool for this. - -Arguments: - -- `MEMORY_PATH` - path to the `memory` file -- `DIFF_PATH` - path to the `diff` file - -Usage: - -```bash -snapshot-editor edit-memory rebase \ - --memory-path \ - --diff-path -``` - -Example: - -```bash -snapshot-editor edit-memory rebase \ - --memory-path ./memory_file \ - --diff-path ./diff_file -``` +> This command is used to merge a `diff` snapshot memory file on +> top of a base memory file. +> +> **Note** +> You can also use `rebase-snap` (deprecated) tool for this. +> +> Arguments: +> +> - `MEMORY_PATH` - path to the `memory` file +> - `DIFF_PATH` - path to the `diff` file +> +> Usage: +> +> ```bash +> snapshot-editor edit-memory rebase \ +> --memory-path \ +> --diff-path +> ``` +> +> Example: +> +> ```bash +> snapshot-editor edit-memory rebase \ +> --memory-path ./memory_file \ +> --diff-path ./diff_file +> ``` ### `edit-vmstate` command #### `remove-regs` subcommand (aarch64 only) -This command is used to remove specified registers from vcpu states inside -vmstate snapshot file. - -Arguments: - -- `VMSTATE_PATH` - path to the `vmstate` file -- `OUTPUT_PATH` - path to the file where the output will be placed -- `[REGS]` - set of u32 values representing registers ids as they are defined - in KVM. Can be both in decimal and in hex formats. - -Usage: - -```bash -snapshot-editor edit-vmstate remove-regs \ - --vmstate-path \ - --output-path \ - [REGS]... -``` - -Example: - -```bash -./snapshot-editor edit-vmstate remove-regs \ - --vmstate-path ./vmstate_file \ - --output-path ./new_vmstate_file \ - 0x1 0x2 -``` +> This command is used to remove specified registers from vcpu states inside +> vmstate snapshot file. +> +> Arguments: +> +> - `VMSTATE_PATH` - path to the `vmstate` file +> - `OUTPUT_PATH` - path to the file where the output will be placed +> - `[REGS]` - set of u32 values representing registers ids as they are defined +> in KVM. Can be both in decimal and in hex formats. +> +> Usage: +> +> ```bash +> snapshot-editor edit-vmstate remove-regs \ +> --vmstate-path \ +> --output-path \ +> [REGS]... +> ``` +> +> Example: +> +> ```bash +> ./snapshot-editor edit-vmstate remove-regs \ +> --vmstate-path ./vmstate_file \ +> --output-path ./new_vmstate_file \ +> 0x1 0x2 +> ``` ### `info-vmstate` command #### `version` subcommand -This command is used to print version of the provided -vmstate file. - -Arguments: - -- `VMSTATE_PATH` - path to the `vmstate` file - -Usage: - -```bash -snapshot-editor info-vmstate version --vmstate-path -``` - -Example: - -```bash -./snapshot-editor info-vmstate version --vmstate-path ./vmstate_file -``` - -#### `vcpu-states` subcommand (aarch64 only) - -This command is used to print the vCPU states inside vmstate snapshot file. - -Arguments: - -- `VMSTATE_PATH` - path to the `vmstate` file - -Usage: - -```bash -snapshot-editor info-vmstate vcpu-states --vmstate-path -``` - -Example: - -```bash -./snapshot-editor info-vmstate vcpu-states --vmstate-path ./vmstate_file -``` +> This command is used to print version of the provided +> vmstate file. +> +> Arguments: +> +> - `VMSTATE_PATH` - path to the `vmstate` file +> +> Usage: +> +> ```bash +> snapshot-editor info-vmstate version --vmstate-path +> ``` +> +> Example: +> +> ```bash +> ./snapshot-editor info-vmstate version --vmstate-path ./vmstate_file +> ``` + +#### `vcpu-states` subcommand + +> This command is used to print the vCPU states inside vmstate snapshot file. +> +> Arguments: +> +> - `VMSTATE_PATH` - path to the `vmstate` file +> +> Usage: +> +> ```bash +> snapshot-editor info-vmstate vcpu-states --vmstate-path +> ``` +> +> Example: +> +> ```bash +> ./snapshot-editor info-vmstate vcpu-states --vmstate-path ./vmstate_file +> ``` + +#### `vm-state` subcommand + +> This command is used to print the vmstate of snapshot file in +> readable format thus, making it easier to compare vmstate of 2 snapshots. +> +> Arguments: +> +> - `VMSTATE_PATH` - path to the `vmstate` file +> +> Usage: +> +> ```bash +> snapshot-editor info-vmstate vm-state --vmstate-path +> ``` +> +> Example: +> +> ```bash +> ./snapshot-editor info-vmstate vm-state --vmstate-path ./vmstate_file +> ``` diff --git a/src/snapshot-editor/src/info.rs b/src/snapshot-editor/src/info.rs index a39adbc335e..532f622e512 100644 --- a/src/snapshot-editor/src/info.rs +++ b/src/snapshot-editor/src/info.rs @@ -26,21 +26,26 @@ pub enum InfoVmStateSubCommand { vmstate_path: PathBuf, }, /// Print info about vcpu states. - #[cfg(target_arch = "aarch64")] VcpuStates { /// Path to the vmstate file. #[arg(short, long)] vmstate_path: PathBuf, }, + /// Print readable MicroVM state. + VmState { + /// Path to the vmstate file. + #[arg(short, long)] + vmstate_path: PathBuf, + }, } pub fn info_vmstate_command(command: InfoVmStateSubCommand) -> Result<(), InfoVmStateError> { match command { InfoVmStateSubCommand::Version { vmstate_path } => info(&vmstate_path, info_version)?, - #[cfg(target_arch = "aarch64")] InfoVmStateSubCommand::VcpuStates { vmstate_path } => { info(&vmstate_path, info_vcpu_states)? } + InfoVmStateSubCommand::VmState { vmstate_path } => info(&vmstate_path, info_vmstate)?, } Ok(()) } @@ -67,23 +72,15 @@ fn info_version(_: &MicrovmState, version: u16) -> Result<(), InfoVmStateError> } } -#[cfg(target_arch = "aarch64")] fn info_vcpu_states(state: &MicrovmState, _: u16) -> Result<(), InfoVmStateError> { for (i, state) in state.vcpu_states.iter().enumerate() { println!("vcpu {i}:"); - println!("kvm_mp_state: {:#x}", state.mp_state.mp_state); - println!("mpidr: {:#x}", state.mpidr); - for reg in state.regs.iter() { - println!( - "{:#x} 0x{}", - reg.id, - reg.as_slice() - .iter() - .rev() - .map(|b| format!("{b:x}")) - .collect::() - ); - } + println!("{state:#?}"); } Ok(()) } + +fn info_vmstate(vmstate: &MicrovmState, _version: u16) -> Result<(), InfoVmStateError> { + println!("{vmstate:#?}"); + Ok(()) +} diff --git a/src/vmm/src/vstate/vcpu/aarch64.rs b/src/vmm/src/vstate/vcpu/aarch64.rs index fa9f3d5c0a3..a4ba61c1aa4 100644 --- a/src/vmm/src/vstate/vcpu/aarch64.rs +++ b/src/vmm/src/vstate/vcpu/aarch64.rs @@ -5,6 +5,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the THIRD-PARTY file. +use std::fmt::Debug; + use kvm_bindings::*; use kvm_ioctls::*; use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult}; @@ -250,7 +252,7 @@ impl KvmVcpu { } /// Structure holding VCPU kvm state. -#[derive(Debug, Default, Clone, Versionize)] +#[derive(Default, Clone, Versionize)] pub struct VcpuState { /// Multiprocessing state. pub mp_state: kvm_bindings::kvm_mp_state, @@ -271,6 +273,26 @@ pub struct VcpuState { pub kvi: Option, } +impl Debug for VcpuState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "kvm_mp_state: {:#x}", self.mp_state.mp_state)?; + writeln!(f, "mpidr: {:#x}", self.mpidr)?; + for reg in self.regs.iter() { + writeln!( + f, + "{:#x} 0x{}", + reg.id, + reg.as_slice() + .iter() + .rev() + .map(|b| format!("{b:x}")) + .collect::() + )?; + } + Ok(()) + } +} + impl VcpuState { fn default_old_regs(_: u16) -> Vec { Vec::default() diff --git a/src/vmm/src/vstate/vcpu/x86_64.rs b/src/vmm/src/vstate/vcpu/x86_64.rs index 60fff47daa9..c4d78041543 100644 --- a/src/vmm/src/vstate/vcpu/x86_64.rs +++ b/src/vmm/src/vstate/vcpu/x86_64.rs @@ -6,6 +6,7 @@ // found in the THIRD-PARTY file. use std::collections::{HashMap, HashSet}; +use std::fmt::Debug; use kvm_bindings::{ kvm_debugregs, kvm_lapic_state, kvm_mp_state, kvm_regs, kvm_sregs, kvm_vcpu_events, kvm_xcrs, @@ -540,7 +541,7 @@ impl KvmVcpu { } } -#[derive(Debug, Clone, Versionize)] +#[derive(Clone, Versionize)] /// Structure holding VCPU kvm state. // NOTICE: Any changes to this structure require a snapshot version bump. pub struct VcpuState { @@ -573,6 +574,30 @@ pub struct VcpuState { pub tsc_khz: Option, } +impl Debug for VcpuState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug_kvm_regs: Vec = Vec::new(); + for kvm_msrs in self.saved_msrs.iter() { + debug_kvm_regs = kvm_msrs.clone().into_raw(); + debug_kvm_regs.sort_by_key(|msr| (msr.nmsrs, msr.pad)); + } + f.debug_struct("VcpuState") + .field("cpuid", &self.cpuid) + .field("msrs", &self.msrs) + .field("saved_msrs", &debug_kvm_regs) + .field("debug_regs", &self.debug_regs) + .field("lapic", &self.lapic) + .field("mp_state", &self.mp_state) + .field("regs", &self.regs) + .field("sregs", &self.sregs) + .field("vcpu_events", &self.vcpu_events) + .field("xcrs", &self.xcrs) + .field("xsave", &self.xsave) + .field("tsc_khz", &self.tsc_khz) + .finish() + } +} + impl VcpuState { fn default_tsc_khz(_: u16) -> Option { warn!("CPU TSC freq not found in snapshot");