linux.rs: replace Error enum with anyhow

Use the anyhow crate to provide ad-hoc errors with context. This removes
the large, manually-updated enum, which we never use programmatically
anyway (error messages are printed in human-readable form and otherwise
not matched against).

BUG=b:190433480
TEST=cargo build
TEST=./test_all

Change-Id: Ia7b90b33774d4031054b346d650861d3105044ee
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3105436
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
diff --git a/Cargo.toml b/Cargo.toml
index 1a4b9d2..fcdae29 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -115,6 +115,7 @@
 x = ["devices/x"]
 
 [dependencies]
+anyhow = "1.0.32"
 arch = { path = "arch" }
 assertions = { path = "common/assertions" }
 audio_streams = "*"
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs
index 7d4eee0..2a0200e 100644
--- a/aarch64/src/lib.rs
+++ b/aarch64/src/lib.rs
@@ -152,8 +152,6 @@
     CloneIrqChip(base::Error),
     #[error("the given kernel command line was invalid: {0}")]
     Cmdline(kernel_cmdline::Error),
-    #[error("error creating devices: {0}")]
-    CreateDevices(Box<dyn StdError>),
     #[error("unable to make an Event: {0}")]
     CreateEvent(base::Error),
     #[error("FDT could not be created: {0}")]
@@ -170,12 +168,10 @@
     CreateSocket(io::Error),
     #[error("failed to create VCPU: {0}")]
     CreateVcpu(base::Error),
-    #[error("failed to create vm: {0}")]
-    CreateVm(Box<dyn StdError>),
     #[error("vm created wrong kind of vcpu")]
     DowncastVcpu,
     #[error("failed to finalize IRQ chip: {0}")]
-    FinalizeIrqChip(Box<dyn StdError>),
+    FinalizeIrqChip(base::Error),
     #[error("failed to get PSCI version: {0}")]
     GetPsciVersion(base::Error),
     #[error("failed to get serial cmdline: {0}")]
@@ -300,9 +296,7 @@
             kvm_vcpu_ids.push(vcpu_id);
         }
 
-        irq_chip
-            .finalize()
-            .map_err(|e| Error::FinalizeIrqChip(Box::new(e)))?;
+        irq_chip.finalize().map_err(Error::FinalizeIrqChip)?;
 
         if has_pvtime {
             let pvtime_mem = MemoryMappingBuilder::new(AARCH64_PVTIME_IPA_MAX_SIZE as usize)
diff --git a/src/crosvm.rs b/src/crosvm.rs
index 6522713..d7bb767 100644
--- a/src/crosvm.rs
+++ b/src/crosvm.rs
@@ -6,7 +6,6 @@
 //! configs.
 
 pub mod argument;
-pub mod error;
 #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
 pub mod gdb;
 #[path = "linux.rs"]
diff --git a/src/error.rs b/src/error.rs
deleted file mode 100644
index ca9b61b..0000000
--- a/src/error.rs
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright 2021 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use arch::{self, LinuxArch};
-use base::TubeError;
-use devices::virtio;
-use devices::virtio::vhost::user::vmm::Error as VhostUserVmmError;
-use std::error::Error as StdError;
-use std::fmt::{self, Display};
-use std::io;
-use std::num::ParseIntError;
-use std::path::PathBuf;
-#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
-use std::sync::mpsc;
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-use x86_64::X8664arch as Arch;
-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
-use {
-    aarch64::AArch64 as Arch,
-    devices::IrqChipAArch64 as IrqChipArch,
-    hypervisor::{VcpuAArch64 as VcpuArch, VmAArch64 as VmArch},
-};
-
-use net_util::Error as NetError;
-use remain::sorted;
-#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
-use vm_control::VcpuDebugStatusMessage;
-
-#[sorted]
-#[derive(Debug)]
-pub enum Error {
-    AddGpuDeviceMemory(base::Error),
-    AddIrqChipVcpu(base::Error),
-    AddPmemDeviceMemory(base::Error),
-    AllocateGpuDeviceAddress,
-    AllocatePmemDeviceAddress(resources::Error),
-    BalloonDeviceNew(virtio::BalloonError),
-    BlockDeviceNew(base::Error),
-    BlockSignal(base::signal::Error),
-    BuildVm(<Arch as LinuxArch>::Error),
-    ChownTpmStorage(base::Error),
-    CloneEvent(base::Error),
-    CloneTube(base::TubeError),
-    CloneVcpu(base::Error),
-    ConfigureHotPlugDevice(<Arch as LinuxArch>::Error),
-    ConfigureVcpu(<Arch as LinuxArch>::Error),
-    ConnectTube(io::Error),
-    #[cfg(feature = "audio_cras")]
-    CrasSoundDeviceNew(virtio::snd::cras_backend::Error),
-    #[cfg(feature = "audio")]
-    CreateAc97(devices::PciDeviceError),
-    CreateAsyncDiskError(disk::Error),
-    CreateConsole(devices::SerialError),
-    CreateControlServer(io::Error),
-    CreateDiskCheckAsyncOkError(disk::Error),
-    CreateDiskError(disk::Error),
-    CreateEvent(base::Error),
-    CreateGrallocError(rutabaga_gfx::RutabagaError),
-    CreateGuestMemory(vm_memory::GuestMemoryError),
-    CreateIrqChip(base::Error),
-    CreateKvm(base::Error),
-    CreateSignalFd(base::SignalFdError),
-    CreateSocket(io::Error),
-    CreateTapDevice(NetError),
-    CreateTimer(base::Error),
-    CreateTpmStorage(PathBuf, io::Error),
-    CreateTube(TubeError),
-    #[cfg(feature = "usb")]
-    CreateUsbProvider(devices::usb::host_backend::error::Error),
-    CreateVcpu(base::Error),
-    CreateVfioDevice(devices::vfio::VfioError),
-    CreateVirtioIommu(base::Error),
-    CreateVm(base::Error),
-    CreateWaitContext(base::Error),
-    DeviceJail(minijail::Error),
-    DevicePivotRoot(minijail::Error),
-    #[cfg(feature = "direct")]
-    DirectIo(io::Error),
-    #[cfg(feature = "direct")]
-    DirectIrq(devices::DirectIrqError),
-    Disk(PathBuf, io::Error),
-    DiskImageLock(base::Error),
-    DropCapabilities(base::Error),
-    FsDeviceNew(virtio::fs::Error),
-    GenerateAcpi,
-    GetMaxOpenFiles(base::Error),
-    GetSignalMask(base::signal::Error),
-    GuestMemoryLayout(<Arch as LinuxArch>::Error),
-    #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
-    HandleDebugCommand(<Arch as LinuxArch>::Error),
-    InputDeviceNew(virtio::InputError),
-    InputEventsOpen(io::Error),
-    InvalidHotPlugKey,
-    InvalidVfioPath,
-    InvalidWaylandPath,
-    IoJail(minijail::Error),
-    LoadKernel(Box<dyn StdError>),
-    MemoryTooLarge,
-    NetDeviceNew(virtio::NetError),
-    NoHotPlugBus,
-    OpenAcpiTable(PathBuf, io::Error),
-    OpenAndroidFstab(PathBuf, io::Error),
-    OpenBios(PathBuf, io::Error),
-    OpenInitrd(PathBuf, io::Error),
-    OpenKernel(PathBuf, io::Error),
-    OpenVinput(PathBuf, io::Error),
-    P9DeviceNew(virtio::P9Error),
-    ParseMaxOpenFiles(ParseIntError),
-    PivotRootDoesntExist(&'static str),
-    PmemDeviceImageTooBig,
-    PmemDeviceNew(base::Error),
-    Pstore(arch::pstore::Error),
-    ReadMemAvailable(io::Error),
-    ReadStatm(io::Error),
-    RegisterBalloon(arch::DeviceRegistrationError),
-    RegisterBlock(arch::DeviceRegistrationError),
-    RegisterGpu(arch::DeviceRegistrationError),
-    RegisterNet(arch::DeviceRegistrationError),
-    RegisterP9(arch::DeviceRegistrationError),
-    RegisterRng(arch::DeviceRegistrationError),
-    RegisterSignalHandler(base::Error),
-    RegisterWayland(arch::DeviceRegistrationError),
-    ReserveGpuMemory(base::MmapError),
-    ReserveMemory(base::Error),
-    ReservePmemMemory(base::MmapError),
-    ResetTimer(base::Error),
-    RngDeviceNew(virtio::RngError),
-    RunnableVcpu(base::Error),
-    #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
-    SendDebugStatus(Box<mpsc::SendError<VcpuDebugStatusMessage>>),
-    SettingGidMap(minijail::Error),
-    SettingMaxOpenFiles(minijail::Error),
-    SettingSignalMask(base::Error),
-    SettingUidMap(minijail::Error),
-    SignalFd(base::SignalFdError),
-    #[cfg(feature = "audio")]
-    SoundDeviceNew(virtio::SoundError),
-    #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
-    SpawnGdbServer(io::Error),
-    SpawnVcpu(io::Error),
-    SwiotlbTooLarge,
-    Timer(base::Error),
-    ValidateRawDescriptor(base::Error),
-    VhostNetDeviceNew(virtio::vhost::Error),
-    VhostUserBlockDeviceNew(VhostUserVmmError),
-    VhostUserConsoleDeviceNew(VhostUserVmmError),
-    VhostUserFsDeviceNew(VhostUserVmmError),
-    VhostUserGpuDeviceNew(VhostUserVmmError),
-    VhostUserMac80211HwsimNew(VhostUserVmmError),
-    VhostUserNetDeviceNew(VhostUserVmmError),
-    VhostUserNetWithNetArgs,
-    VhostUserSndDeviceNew(VhostUserVmmError),
-    VhostUserVsockDeviceNew(VhostUserVmmError),
-    VhostUserWlDeviceNew(VhostUserVmmError),
-    VhostVsockDeviceNew(virtio::vhost::Error),
-    VirtioPciDev(base::Error),
-    VirtioVhostUserDeviceNew(VhostUserVmmError),
-    WaitContextAdd(base::Error),
-    WaitContextDelete(base::Error),
-    WaylandDeviceNew(base::Error),
-}
-
-impl Display for Error {
-    #[remain::check]
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::Error::*;
-
-        #[sorted]
-        match self {
-            AddGpuDeviceMemory(e) => write!(f, "failed to add gpu device memory: {}", e),
-            AddIrqChipVcpu(e) => write!(f, "failed to add vcpu to irq chip: {}", e),
-            AddPmemDeviceMemory(e) => write!(f, "failed to add pmem device memory: {}", e),
-            AllocateGpuDeviceAddress => write!(f, "failed to allocate gpu device guest address"),
-            AllocatePmemDeviceAddress(e) => {
-                write!(f, "failed to allocate memory for pmem device: {}", e)
-            }
-            BalloonDeviceNew(e) => write!(f, "failed to create balloon: {}", e),
-            BlockDeviceNew(e) => write!(f, "failed to create block device: {}", e),
-            BlockSignal(e) => write!(f, "failed to block signal: {}", e),
-            BuildVm(e) => write!(f, "The architecture failed to build the vm: {}", e),
-            ChownTpmStorage(e) => write!(f, "failed to chown tpm storage: {}", e),
-            CloneEvent(e) => write!(f, "failed to clone event: {}", e),
-            CloneTube(e) => write!(f, "failed to clone tube: {}", e),
-            CloneVcpu(e) => write!(f, "failed to clone vcpu: {}", e),
-            ConfigureHotPlugDevice(e) => write!(f, "Failed to configure pci hotplug device:{}", e),
-            ConfigureVcpu(e) => write!(f, "failed to configure vcpu: {}", e),
-            ConnectTube(e) => write!(f, "failed to connect to tube: {}", e),
-            #[cfg(feature = "audio_cras")]
-            CrasSoundDeviceNew(e) => write!(f, "failed to create cras sound device: {}", e),
-            #[cfg(feature = "audio")]
-            CreateAc97(e) => write!(f, "failed to create ac97 device: {}", e),
-            CreateAsyncDiskError(e) => write!(f, "failed to create virtual disk (async): {}", e),
-            CreateConsole(e) => write!(f, "failed to create console device: {}", e),
-            CreateControlServer(e) => write!(f, "failed to create control server: {}", e),
-            CreateDiskCheckAsyncOkError(e) => {
-                write!(f, "failed to create virtual disk checking async: {}", e)
-            }
-            CreateDiskError(e) => write!(f, "failed to create virtual disk: {}", e),
-            CreateEvent(e) => write!(f, "failed to create event: {}", e),
-            CreateGrallocError(e) => write!(f, "failed to create gralloc: {}", e),
-            CreateGuestMemory(e) => write!(f, "failed to create guest memory: {}", e),
-            CreateIrqChip(e) => write!(f, "failed to create IRQ chip: {}", e),
-            CreateKvm(e) => write!(f, "failed to create kvm: {}", e),
-            CreateSignalFd(e) => write!(f, "failed to create signalfd: {}", e),
-            CreateSocket(e) => write!(f, "failed to create socket: {}", e),
-            CreateTapDevice(e) => write!(f, "failed to create tap device: {}", e),
-            CreateTimer(e) => write!(f, "failed to create Timer: {}", e),
-            CreateTpmStorage(p, e) => {
-                write!(f, "failed to create tpm storage dir {}: {}", p.display(), e)
-            }
-            CreateTube(e) => write!(f, "failed to create tube: {}", e),
-            #[cfg(feature = "usb")]
-            CreateUsbProvider(e) => write!(f, "failed to create usb provider: {}", e),
-            CreateVcpu(e) => write!(f, "failed to create vcpu: {}", e),
-            CreateVfioDevice(e) => write!(f, "Failed to create vfio device {}", e),
-            CreateVirtioIommu(e) => write!(f, "Failed to create IOMMU device {}", e),
-            CreateVm(e) => write!(f, "failed to create vm: {}", e),
-            CreateWaitContext(e) => write!(f, "failed to create wait context: {}", e),
-            DeviceJail(e) => write!(f, "failed to jail device: {}", e),
-            DevicePivotRoot(e) => write!(f, "failed to pivot root device: {}", e),
-            #[cfg(feature = "direct")]
-            DirectIo(e) => write!(f, "failed to open direct io device: {}", e),
-            #[cfg(feature = "direct")]
-            DirectIrq(e) => write!(f, "failed to enable interrupt forwarding: {}", e),
-            Disk(p, e) => write!(f, "failed to load disk image {}: {}", p.display(), e),
-            DiskImageLock(e) => write!(f, "failed to lock disk image: {}", e),
-            DropCapabilities(e) => write!(f, "failed to drop process capabilities: {}", e),
-            FsDeviceNew(e) => write!(f, "failed to create fs device: {}", e),
-            GenerateAcpi => write!(f, "failed to generate ACPI table"),
-            GetMaxOpenFiles(e) => write!(f, "failed to get max number of open files: {}", e),
-            GetSignalMask(e) => write!(f, "failed to retrieve signal mask for vcpu: {}", e),
-            GuestMemoryLayout(e) => write!(f, "failed to create guest memory layout: {}", e),
-            #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
-            HandleDebugCommand(e) => write!(f, "failed to handle a gdb command: {}", e),
-            InputDeviceNew(e) => write!(f, "failed to set up input device: {}", e),
-            InputEventsOpen(e) => write!(f, "failed to open event device: {}", e),
-            InvalidHotPlugKey => write!(f, "failed to find hotplug key in hotplug bus"),
-            InvalidVfioPath => write!(f, "failed to parse or find vfio path"),
-            InvalidWaylandPath => write!(f, "wayland socket path has no parent or file name"),
-            IoJail(e) => write!(f, "{}", e),
-            LoadKernel(e) => write!(f, "failed to load kernel: {}", e),
-            MemoryTooLarge => write!(f, "requested memory size too large"),
-            NetDeviceNew(e) => write!(f, "failed to set up virtio networking: {}", e),
-            NoHotPlugBus => write!(f, "HotPlugBus hasn't been implemented"),
-            OpenAcpiTable(p, e) => write!(f, "failed to open ACPI file {}: {}", p.display(), e),
-            OpenAndroidFstab(p, e) => write!(
-                f,
-                "failed to open android fstab file {}: {}",
-                p.display(),
-                e
-            ),
-            OpenBios(p, e) => write!(f, "failed to open bios {}: {}", p.display(), e),
-            OpenInitrd(p, e) => write!(f, "failed to open initrd {}: {}", p.display(), e),
-            OpenKernel(p, e) => write!(f, "failed to open kernel image {}: {}", p.display(), e),
-            OpenVinput(p, e) => write!(f, "failed to open vinput device {}: {}", p.display(), e),
-            P9DeviceNew(e) => write!(f, "failed to create 9p device: {}", e),
-            ParseMaxOpenFiles(e) => write!(f, "failed to parse max number of open files: {}", e),
-            PivotRootDoesntExist(p) => write!(f, "{} doesn't exist, can't jail devices.", p),
-            PmemDeviceImageTooBig => {
-                write!(f, "failed to create pmem device: pmem device image too big")
-            }
-            PmemDeviceNew(e) => write!(f, "failed to create pmem device: {}", e),
-            Pstore(e) => write!(f, "failed to allocate pstore region: {}", e),
-            ReadMemAvailable(e) => write!(
-                f,
-                "failed to read /sys/kernel/mm/chromeos-low_mem/available: {}",
-                e
-            ),
-            ReadStatm(e) => write!(f, "failed to read /proc/self/statm: {}", e),
-            RegisterBalloon(e) => write!(f, "error registering balloon device: {}", e),
-            RegisterBlock(e) => write!(f, "error registering block device: {}", e),
-            RegisterGpu(e) => write!(f, "error registering gpu device: {}", e),
-            RegisterNet(e) => write!(f, "error registering net device: {}", e),
-            RegisterP9(e) => write!(f, "error registering 9p device: {}", e),
-            RegisterRng(e) => write!(f, "error registering rng device: {}", e),
-            RegisterSignalHandler(e) => write!(f, "error registering signal handler: {}", e),
-            RegisterWayland(e) => write!(f, "error registering wayland device: {}", e),
-            ReserveGpuMemory(e) => write!(f, "failed to reserve gpu memory: {}", e),
-            ReserveMemory(e) => write!(f, "failed to reserve memory: {}", e),
-            ReservePmemMemory(e) => write!(f, "failed to reserve pmem memory: {}", e),
-            ResetTimer(e) => write!(f, "failed to reset Timer: {}", e),
-            RngDeviceNew(e) => write!(f, "failed to set up rng: {}", e),
-            RunnableVcpu(e) => write!(f, "failed to set thread id for vcpu: {}", e),
-            #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
-            SendDebugStatus(e) => write!(f, "failed to send a debug status to GDB thread: {}", e),
-            SettingGidMap(e) => write!(f, "error setting GID map: {}", e),
-            SettingMaxOpenFiles(e) => write!(f, "error setting max open files: {}", e),
-            SettingSignalMask(e) => write!(f, "failed to set the signal mask for vcpu: {}", e),
-            SettingUidMap(e) => write!(f, "error setting UID map: {}", e),
-            SignalFd(e) => write!(f, "failed to read signal fd: {}", e),
-            #[cfg(feature = "audio")]
-            SoundDeviceNew(e) => write!(f, "failed to create sound device: {}", e),
-            #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
-            SpawnGdbServer(e) => write!(f, "failed to spawn GDB thread: {}", e),
-            SpawnVcpu(e) => write!(f, "failed to spawn VCPU thread: {}", e),
-            SwiotlbTooLarge => write!(f, "requested swiotlb size too large"),
-            Timer(e) => write!(f, "failed to read timer fd: {}", e),
-            ValidateRawDescriptor(e) => write!(f, "failed to validate raw descriptor: {}", e),
-            VhostNetDeviceNew(e) => write!(f, "failed to set up vhost networking: {}", e),
-            VhostUserBlockDeviceNew(e) => {
-                write!(f, "failed to set up vhost-user block device: {}", e)
-            }
-            VhostUserConsoleDeviceNew(e) => {
-                write!(f, "failed to set up vhost-user console device: {}", e)
-            }
-            VhostUserFsDeviceNew(e) => write!(f, "failed to set up vhost-user fs device: {}", e),
-            VhostUserGpuDeviceNew(e) => write!(f, "failed to set up vhost-user gpu device: {}", e),
-            VhostUserMac80211HwsimNew(e) => {
-                write!(f, "failed to set up vhost-user mac80211_hwsim device {}", e)
-            }
-            VhostUserNetDeviceNew(e) => write!(f, "failed to set up vhost-user net device: {}", e),
-            VhostUserNetWithNetArgs => write!(
-                f,
-                "vhost-user-net cannot be used with any of --host_ip, --netmask or --mac"
-            ),
-            VhostUserSndDeviceNew(e) => write!(f, "failed to set up vhost-user snd device: {}", e),
-            VhostUserVsockDeviceNew(e) => {
-                write!(f, "failed to set up vhost-user vsock device: {}", e)
-            }
-            VhostUserWlDeviceNew(e) => {
-                write!(f, "failed to set up vhost-user wl device: {}", e)
-            }
-            VhostVsockDeviceNew(e) => write!(f, "failed to set up virtual socket device: {}", e),
-            VirtioPciDev(e) => write!(f, "failed to create virtio pci dev: {}", e),
-            VirtioVhostUserDeviceNew(e) => {
-                write!(f, "failed to set up virtio-vhost-user net device: {}", e)
-            }
-            WaitContextAdd(e) => write!(f, "failed to add descriptor to wait context: {}", e),
-            WaitContextDelete(e) => {
-                write!(f, "failed to remove descriptor from wait context: {}", e)
-            }
-            WaylandDeviceNew(e) => write!(f, "failed to create wayland device: {}", e),
-        }
-    }
-}
-
-impl From<minijail::Error> for Error {
-    fn from(err: minijail::Error) -> Self {
-        Error::IoJail(err)
-    }
-}
-
-impl std::error::Error for Error {}
-
-pub type Result<T> = std::result::Result<T, Error>;
diff --git a/src/linux.rs b/src/linux.rs
index 868101d..cc4a778 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -21,11 +21,11 @@
 use std::thread;
 use std::thread::JoinHandle;
 
-use libc::{self, c_int, gid_t, uid_t, EINVAL};
+use libc::{self, c_int, gid_t, uid_t};
 
 use acpi_tables::sdt::SDT;
 
-use crate::error::{Error, Result};
+use anyhow::{anyhow, bail, Context, Result};
 use base::net::{UnixSeqpacket, UnixSeqpacketListener, UnlinkUnixSeqpacketListener};
 use base::*;
 use devices::serial_device::{SerialHardware, SerialParameters};
@@ -127,7 +127,7 @@
 ) -> Result<Minijail> {
     // All child jails run in a new user namespace without any users mapped,
     // they run as nobody unless otherwise configured.
-    let mut j = Minijail::new().map_err(Error::DeviceJail)?;
+    let mut j = Minijail::new().context("failed to jail device")?;
 
     if let Some(config) = config {
         j.namespace_pids();
@@ -138,10 +138,10 @@
             j.use_caps(0);
         }
         if let Some(uid_map) = config.uid_map {
-            j.uidmap(uid_map).map_err(Error::SettingUidMap)?;
+            j.uidmap(uid_map).context("error setting UID map")?;
         }
         if let Some(gid_map) = config.gid_map {
-            j.gidmap(gid_map).map_err(Error::SettingGidMap)?;
+            j.gidmap(gid_map).context("error setting GID map")?;
         }
         // Run in a new mount namespace.
         j.namespace_vfs();
@@ -162,7 +162,7 @@
         let bpf_policy_file = config.seccomp_policy.with_extension("bpf");
         if bpf_policy_file.exists() && !config.log_failures {
             j.parse_seccomp_program(&bpf_policy_file)
-                .map_err(Error::DeviceJail)?;
+                .context("failed to parse precompiled seccomp policy")?;
         } else {
             // Use TSYNC only for the side effect of it using SECCOMP_RET_TRAP,
             // which will correctly kill the entire device process if a worker
@@ -172,7 +172,7 @@
                 j.log_seccomp_filter_failures();
             }
             j.parse_seccomp_filters(&config.seccomp_policy.with_extension("policy"))
-                .map_err(Error::DeviceJail)?;
+                .context("failed to parse seccomp policy")?;
         }
         j.use_seccomp_filter();
         // Don't do init setup.
@@ -183,13 +183,14 @@
     if root != Path::new("/") {
         // It's safe to call `namespace_vfs` multiple times.
         j.namespace_vfs();
-        j.enter_pivot_root(root).map_err(Error::DevicePivotRoot)?;
+        j.enter_pivot_root(root)
+            .context("failed to pivot root device")?;
     }
 
     // Most devices don't need to open many fds.
     let limit = if let Some(r) = r_limit { r } else { 1024u64 };
     j.set_rlimit(libc::RLIMIT_NOFILE as i32, limit, limit)
-        .map_err(Error::SettingMaxOpenFiles)?;
+        .context("error setting max open files")?;
 
     Ok(j)
 }
@@ -200,7 +201,7 @@
         // A directory for a jailed device's pivot root.
         let root_path = Path::new(pivot_root);
         if !root_path.exists() {
-            return Err(Error::PivotRootDoesntExist(pivot_root));
+            bail!("{} doesn't exist, can't jail devices", pivot_root);
         }
         let policy_path: PathBuf = cfg.seccomp_policy_dir.join(policy);
         let config = SandboxConfig {
@@ -216,23 +217,23 @@
     }
 }
 
-type DeviceResult<T = VirtioDeviceStub> = std::result::Result<T, Error>;
+type DeviceResult<T = VirtioDeviceStub> = Result<T>;
 
 fn create_block_device(cfg: &Config, disk: &DiskOption, disk_device_tube: Tube) -> DeviceResult {
     let raw_image: File = open_file(&disk.path, disk.read_only, disk.o_direct)
-        .map_err(|e| Error::Disk(disk.path.clone(), e.into()))?;
+        .with_context(|| format!("failed to load disk image {}", disk.path.display()))?;
     // Lock the disk image to prevent other crosvm instances from using it.
     let lock_op = if disk.read_only {
         FlockOperation::LockShared
     } else {
         FlockOperation::LockExclusive
     };
-    flock(&raw_image, lock_op, true).map_err(Error::DiskImageLock)?;
+    flock(&raw_image, lock_op, true).context("failed to lock disk image")?;
 
     info!("Trying to attach block device: {}", disk.path.display());
-    let dev = if disk::async_ok(&raw_image).map_err(Error::CreateDiskCheckAsyncOkError)? {
-        let async_file =
-            disk::create_async_disk_file(raw_image).map_err(Error::CreateAsyncDiskError)?;
+    let dev = if disk::async_ok(&raw_image).context("failed to check disk async_ok")? {
+        let async_file = disk::create_async_disk_file(raw_image)
+            .context("failed to create async virtual disk")?;
         Box::new(
             virtio::BlockAsync::new(
                 virtio::base_features(cfg.protected_vm),
@@ -243,11 +244,11 @@
                 disk.id,
                 Some(disk_device_tube),
             )
-            .map_err(Error::BlockDeviceNew)?,
+            .context("failed to create block device")?,
         ) as Box<dyn VirtioDevice>
     } else {
         let disk_file = disk::create_disk_file(raw_image, disk::MAX_NESTING_DEPTH)
-            .map_err(Error::CreateDiskError)?;
+            .context("failed to create virtual disk")?;
         Box::new(
             virtio::Block::new(
                 virtio::base_features(cfg.protected_vm),
@@ -258,7 +259,7 @@
                 disk.id,
                 Some(disk_device_tube),
             )
-            .map_err(Error::BlockDeviceNew)?,
+            .context("failed to create block device")?,
         ) as Box<dyn VirtioDevice>
     };
 
@@ -270,7 +271,7 @@
 
 fn create_vhost_user_block_device(cfg: &Config, opt: &VhostUserOption) -> DeviceResult {
     let dev = VhostUserBlock::new(virtio::base_features(cfg.protected_vm), &opt.socket)
-        .map_err(Error::VhostUserBlockDeviceNew)?;
+        .context("failed to set up vhost-user block device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -281,7 +282,7 @@
 
 fn create_vhost_user_console_device(cfg: &Config, opt: &VhostUserOption) -> DeviceResult {
     let dev = VhostUserConsole::new(virtio::base_features(cfg.protected_vm), &opt.socket)
-        .map_err(Error::VhostUserConsoleDeviceNew)?;
+        .context("failed to set up vhost-user console device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -296,7 +297,7 @@
         &option.socket,
         &option.tag,
     )
-    .map_err(Error::VhostUserFsDeviceNew)?;
+    .context("failed to set up vhost-user fs device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -307,7 +308,7 @@
 
 fn create_vhost_user_mac80211_hwsim_device(cfg: &Config, opt: &VhostUserOption) -> DeviceResult {
     let dev = VhostUserMac80211Hwsim::new(virtio::base_features(cfg.protected_vm), &opt.socket)
-        .map_err(Error::VhostUserMac80211HwsimNew)?;
+        .context("failed to set up vhost-user mac80211_hwsim device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -319,7 +320,7 @@
 #[cfg(feature = "audio")]
 fn create_vhost_user_snd_device(cfg: &Config, option: &VhostUserOption) -> DeviceResult {
     let dev = VhostUserSnd::new(virtio::base_features(cfg.protected_vm), &option.socket)
-        .map_err(Error::VhostUserSndDeviceNew)?;
+        .context("failed to set up vhost-user snd device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -329,8 +330,8 @@
 }
 
 fn create_rng_device(cfg: &Config) -> DeviceResult {
-    let dev =
-        virtio::Rng::new(virtio::base_features(cfg.protected_vm)).map_err(Error::RngDeviceNew)?;
+    let dev = virtio::Rng::new(virtio::base_features(cfg.protected_vm))
+        .context("failed to set up rng")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -344,7 +345,7 @@
         virtio::base_features(cfg.protected_vm),
         cras_snd,
     )
-    .map_err(Error::CrasSoundDeviceNew)?;
+    .context("failed to create cras sound device")?;
 
     let jail = match simple_jail(&cfg, "cras_snd_device")? {
         Some(mut jail) => {
@@ -400,11 +401,12 @@
             let pid = process::id();
             let tpm_pid_dir = format!("/run/vm/tpm.{}", pid);
             tpm_storage = Path::new(&tpm_pid_dir).to_owned();
-            fs::create_dir_all(&tpm_storage)
-                .map_err(|e| Error::CreateTpmStorage(tpm_storage.to_owned(), e))?;
+            fs::create_dir_all(&tpm_storage).with_context(|| {
+                format!("failed to create tpm storage dir {}", tpm_storage.display())
+            })?;
             let tpm_pid_dir_c = CString::new(tpm_pid_dir).expect("no nul bytes");
             chown(&tpm_pid_dir_c, crosvm_ids.uid, crosvm_ids.gid)
-                .map_err(Error::ChownTpmStorage)?;
+                .context("failed to chown tpm storage")?;
 
             jail.mount_bind(&tpm_storage, &tpm_storage, true)?;
         }
@@ -443,7 +445,7 @@
         height,
         virtio::base_features(cfg.protected_vm),
     )
-    .map_err(Error::InputDeviceNew)?;
+    .context("failed to set up input device")?;
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
         jail: simple_jail(cfg, "input_device")?,
@@ -471,7 +473,7 @@
         height,
         virtio::base_features(cfg.protected_vm),
     )
-    .map_err(Error::InputDeviceNew)?;
+    .context("failed to set up input device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -497,7 +499,7 @@
         height,
         virtio::base_features(cfg.protected_vm),
     )
-    .map_err(Error::InputDeviceNew)?;
+    .context("failed to set up input device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -512,7 +514,7 @@
     })?;
 
     let dev = virtio::new_mouse(idx, socket, virtio::base_features(cfg.protected_vm))
-        .map_err(Error::InputDeviceNew)?;
+        .context("failed to set up input device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -531,7 +533,7 @@
     })?;
 
     let dev = virtio::new_keyboard(idx, socket, virtio::base_features(cfg.protected_vm))
-        .map_err(Error::InputDeviceNew)?;
+        .context("failed to set up input device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -550,7 +552,7 @@
     })?;
 
     let dev = virtio::new_switches(idx, socket, virtio::base_features(cfg.protected_vm))
-        .map_err(Error::InputDeviceNew)?;
+        .context("failed to set up input device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -563,10 +565,10 @@
         .read(true)
         .write(true)
         .open(dev_path)
-        .map_err(|e| Error::OpenVinput(dev_path.to_owned(), e))?;
+        .with_context(|| format!("failed to open vinput device {}", dev_path.display()))?;
 
     let dev = virtio::new_evdev(dev_file, virtio::base_features(cfg.protected_vm))
-        .map_err(Error::InputDeviceNew)?;
+        .context("failed to set up input device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -576,7 +578,7 @@
 
 fn create_balloon_device(cfg: &Config, tube: Tube) -> DeviceResult {
     let dev = virtio::Balloon::new(virtio::base_features(cfg.protected_vm), tube)
-        .map_err(Error::BalloonDeviceNew)?;
+        .context("failed to create balloon")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -588,9 +590,9 @@
     // Safe because we ensure that we get a unique handle to the fd.
     let tap = unsafe {
         Tap::from_raw_descriptor(
-            validate_raw_descriptor(tap_fd).map_err(Error::ValidateRawDescriptor)?,
+            validate_raw_descriptor(tap_fd).context("failed to validate tap descriptor")?,
         )
-        .map_err(Error::CreateTapDevice)?
+        .context("failed to create tap device")?
     };
 
     let mut vq_pairs = cfg.net_vq_pairs.unwrap_or(1);
@@ -600,7 +602,8 @@
         vq_pairs = 1;
     }
     let features = virtio::base_features(cfg.protected_vm);
-    let dev = virtio::Net::from(features, tap, vq_pairs).map_err(Error::NetDeviceNew)?;
+    let dev =
+        virtio::Net::from(features, tap, vq_pairs).context("failed to set up virtio networking")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -630,11 +633,11 @@
             netmask,
             mac_address,
         )
-        .map_err(Error::VhostNetDeviceNew)?;
+        .context("failed to set up vhost networking")?;
         Box::new(dev) as Box<dyn VirtioDevice>
     } else {
         let dev = virtio::Net::<Tap>::new(features, host_ip, netmask, mac_address, vq_pairs)
-            .map_err(Error::NetDeviceNew)?;
+            .context("failed to set up virtio networking")?;
         Box::new(dev) as Box<dyn VirtioDevice>
     };
 
@@ -652,7 +655,7 @@
 
 fn create_vhost_user_net_device(cfg: &Config, opt: &VhostUserOption) -> DeviceResult {
     let dev = VhostUserNet::new(virtio::base_features(cfg.protected_vm), &opt.socket)
-        .map_err(Error::VhostUserNetDeviceNew)?;
+        .context("failed to set up vhost-user net device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -663,7 +666,7 @@
 
 fn create_vhost_user_vsock_device(cfg: &Config, opt: &VhostUserOption) -> DeviceResult {
     let dev = VhostUserVsock::new(virtio::base_features(cfg.protected_vm), &opt.socket)
-        .map_err(Error::VhostUserVsockDeviceNew)?;
+        .context("failed to set up vhost-user vsock device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -676,7 +679,7 @@
     // The crosvm wl device expects us to connect the tube before it will accept a vhost-user
     // connection.
     let dev = VhostUserWl::new(virtio::base_features(cfg.protected_vm), &opt.socket)
-        .map_err(Error::VhostUserWlDeviceNew)?;
+        .context("failed to set up vhost-user wl device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -700,7 +703,7 @@
         host_tube,
         device_tube,
     )
-    .map_err(Error::VhostUserGpuDeviceNew)?;
+    .context("failed to set up vhost-user gpu device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -730,7 +733,7 @@
         .iter()
         .map(|(_name, path)| path.parent())
         .collect::<Option<Vec<_>>>()
-        .ok_or(Error::InvalidWaylandPath)?;
+        .ok_or_else(|| anyhow!("wayland socket path has no parent or file name"))?;
 
     if let Some(socket_path) = wayland_socket_path {
         display_backends.insert(
@@ -740,7 +743,7 @@
     }
 
     let dev = virtio::Gpu::new(
-        exit_evt.try_clone().map_err(Error::CloneEvent)?,
+        exit_evt.try_clone().context("failed to clone event")?,
         Some(gpu_device_tube),
         resource_bridges,
         display_backends,
@@ -879,7 +882,7 @@
         .iter()
         .map(|(_name, path)| path.parent())
         .collect::<Option<Vec<_>>>()
-        .ok_or(Error::InvalidWaylandPath)?;
+        .ok_or_else(|| anyhow!("wayland socket path has no parent or file name"))?;
 
     let features = virtio::base_features(cfg.protected_vm);
     let dev = virtio::Wl::new(
@@ -888,7 +891,7 @@
         control_tube,
         resource_bridge,
     )
-    .map_err(Error::WaylandDeviceNew)?;
+    .context("failed to create wayland device")?;
 
     let jail = match simple_jail(cfg, "wl_device")? {
         Some(mut jail) => {
@@ -990,7 +993,7 @@
     video_tube: Tube,
     cfg: &Config,
     typ: devices::virtio::VideoDeviceType,
-) -> std::result::Result<(), Error> {
+) -> Result<()> {
     devs.push(create_video_device(cfg, typ, video_tube)?);
     Ok(())
 }
@@ -998,7 +1001,7 @@
 fn create_vhost_vsock_device(cfg: &Config, cid: u64) -> DeviceResult {
     let features = virtio::base_features(cfg.protected_vm);
     let dev = virtio::vhost::Vsock::new(&cfg.vhost_vsock_device_path, features, cid)
-        .map_err(Error::VhostVsockDeviceNew)?;
+        .context("failed to set up virtual socket device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -1015,7 +1018,8 @@
     fs_cfg: virtio::fs::passthrough::Config,
     device_tube: Tube,
 ) -> DeviceResult {
-    let max_open_files = base::get_max_open_files().map_err(Error::GetMaxOpenFiles)?;
+    let max_open_files =
+        base::get_max_open_files().context("failed to get max number of open files")?;
     let j = if cfg.sandbox {
         let seccomp_policy = cfg.seccomp_policy_dir.join("fs_device");
         let config = SandboxConfig {
@@ -1038,8 +1042,8 @@
     let features = virtio::base_features(cfg.protected_vm);
     // TODO(chirantan): Use more than one worker once the kernel driver has been fixed to not panic
     // when num_queues > 1.
-    let dev =
-        virtio::fs::Fs::new(features, tag, 1, fs_cfg, device_tube).map_err(Error::FsDeviceNew)?;
+    let dev = virtio::fs::Fs::new(features, tag, 1, fs_cfg, device_tube)
+        .context("failed to create fs device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -1055,7 +1059,8 @@
     tag: &str,
     mut p9_cfg: p9::Config,
 ) -> DeviceResult {
-    let max_open_files = base::get_max_open_files().map_err(Error::GetMaxOpenFiles)?;
+    let max_open_files =
+        base::get_max_open_files().context("failed to get max number of open files")?;
     let (jail, root) = if cfg.sandbox {
         let seccomp_policy = cfg.seccomp_policy_dir.join("9p_device");
         let config = SandboxConfig {
@@ -1082,7 +1087,7 @@
 
     let features = virtio::base_features(cfg.protected_vm);
     p9_cfg.root = root.into();
-    let dev = virtio::P9::new(features, tag, p9_cfg).map_err(Error::P9DeviceNew)?;
+    let dev = virtio::P9::new(features, tag, p9_cfg).context("failed to create 9p device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -1099,11 +1104,12 @@
     pmem_device_tube: Tube,
 ) -> DeviceResult {
     let fd = open_file(&disk.path, disk.read_only, false /*O_DIRECT*/)
-        .map_err(|e| Error::Disk(disk.path.clone(), e.into()))?;
+        .with_context(|| format!("failed to load disk image {}", disk.path.display()))?;
 
     let (disk_size, arena_size) = {
-        let metadata =
-            std::fs::metadata(&disk.path).map_err(|e| Error::Disk(disk.path.to_path_buf(), e))?;
+        let metadata = std::fs::metadata(&disk.path).with_context(|| {
+            format!("failed to get disk image {} metadata", disk.path.display())
+        })?;
         let disk_len = metadata.len();
         // Linux requires pmem region sizes to be 2 MiB aligned. Linux will fill any partial page
         // at the end of an mmap'd file and won't write back beyond the actual file length, but if
@@ -1120,7 +1126,7 @@
             disk_len,
             disk_len
                 .checked_add(align_adjust)
-                .ok_or(Error::PmemDeviceImageTooBig)?,
+                .ok_or_else(|| anyhow!("pmem device image too big"))?,
         )
     };
 
@@ -1134,13 +1140,14 @@
 
     let arena = {
         // Conversion from u64 to usize may fail on 32bit system.
-        let arena_size = usize::try_from(arena_size).map_err(|_| Error::PmemDeviceImageTooBig)?;
-        let disk_size = usize::try_from(disk_size).map_err(|_| Error::PmemDeviceImageTooBig)?;
+        let arena_size = usize::try_from(arena_size).context("pmem device image too big")?;
+        let disk_size = usize::try_from(disk_size).context("pmem device image too big")?;
 
-        let mut arena = MemoryMappingArena::new(arena_size).map_err(Error::ReservePmemMemory)?;
+        let mut arena =
+            MemoryMappingArena::new(arena_size).context("failed to reserve pmem memory")?;
         arena
             .add_fd_offset_protection(0, disk_size, &fd, 0, protection)
-            .map_err(Error::ReservePmemMemory)?;
+            .context("failed to reserve pmem memory")?;
 
         // If the disk is not a multiple of the page size, the OS will fill the remaining part
         // of the page with zeroes. However, the anonymous mapping added below must start on a
@@ -1152,7 +1159,7 @@
             // size was aligned.
             arena
                 .add_anon_protection(disk_size, arena_size - disk_size, protection)
-                .map_err(Error::ReservePmemMemory)?;
+                .context("failed to reserve pmem padding")?;
         }
         arena
     };
@@ -1166,7 +1173,7 @@
             // Linux kernel requires pmem namespaces to be 128 MiB aligned.
             128 * 1024 * 1024, /* 128 MiB */
         )
-        .map_err(Error::AllocatePmemDeviceAddress)?;
+        .context("failed to allocate memory for pmem device")?;
 
     let slot = vm
         .add_memory_region(
@@ -1175,7 +1182,7 @@
             /* read_only = */ disk.read_only,
             /* log_dirty_pages = */ false,
         )
-        .map_err(Error::AddPmemDeviceMemory)?;
+        .context("failed to add pmem device memory")?;
 
     let dev = virtio::Pmem::new(
         virtio::base_features(cfg.protected_vm),
@@ -1185,7 +1192,7 @@
         arena_size,
         Some(pmem_device_tube),
     )
-    .map_err(Error::PmemDeviceNew)?;
+    .context("failed to create pmem device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev) as Box<dyn VirtioDevice>,
@@ -1203,7 +1210,7 @@
         endpoints,
         phys_max_addr,
     )
-    .map_err(Error::CreateVirtioIommu)?;
+    .context("failed to create IOMMU device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -1213,10 +1220,10 @@
 
 fn create_console_device(cfg: &Config, param: &SerialParameters) -> DeviceResult {
     let mut keep_rds = Vec::new();
-    let evt = Event::new().map_err(Error::CreateEvent)?;
+    let evt = Event::new().context("failed to create event")?;
     let dev = param
         .create_serial_device::<Console>(cfg.protected_vm, &evt, &mut keep_rds)
-        .map_err(Error::CreateConsole)?;
+        .context("failed to create console device")?;
 
     let jail = match simple_jail(cfg, "serial")? {
         Some(mut jail) => {
@@ -1249,7 +1256,7 @@
 #[cfg(feature = "audio")]
 fn create_sound_device(path: &Path, cfg: &Config) -> DeviceResult {
     let dev = virtio::new_sound(path, virtio::base_features(cfg.protected_vm))
-        .map_err(Error::SoundDeviceNew)?;
+        .context("failed to create sound device")?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -1372,7 +1379,7 @@
         (cfg.host_ip, cfg.netmask, cfg.mac_address)
     {
         if !cfg.vhost_user_net.is_empty() {
-            return Err(Error::VhostUserNetWithNetArgs);
+            bail!("vhost-user-net cannot be used with any of --host_ip, --netmask or --mac");
         }
         devs.push(create_net_device(cfg, host_ip, netmask, mac_address)?);
     }
@@ -1409,7 +1416,7 @@
         #[cfg(feature = "gpu")]
         {
             if cfg.gpu_parameters.is_some() {
-                let (wl_socket, gpu_socket) = Tube::pair().map_err(Error::CreateTube)?;
+                let (wl_socket, gpu_socket) = Tube::pair().context("failed to create tube")?;
                 resource_bridges.push(gpu_socket);
                 wl_resource_bridge = Some(wl_socket);
             }
@@ -1424,7 +1431,7 @@
 
     #[cfg(feature = "video-decoder")]
     let video_dec_tube = if cfg.video_dec {
-        let (video_tube, gpu_tube) = Tube::pair().map_err(Error::CreateTube)?;
+        let (video_tube, gpu_tube) = Tube::pair().context("failed to create tube")?;
         resource_bridges.push(gpu_tube);
         Some(video_tube)
     } else {
@@ -1433,7 +1440,7 @@
 
     #[cfg(feature = "video-encoder")]
     let video_enc_tube = if cfg.video_enc {
-        let (video_tube, gpu_tube) = Tube::pair().map_err(Error::CreateTube)?;
+        let (video_tube, gpu_tube) = Tube::pair().context("failed to create tube")?;
         resource_bridges.push(gpu_tube);
         Some(video_tube)
     } else {
@@ -1453,7 +1460,7 @@
             let mut event_devices = Vec::new();
             if cfg.display_window_mouse {
                 let (event_device_socket, virtio_dev_socket) =
-                    UnixStream::pair().map_err(Error::CreateSocket)?;
+                    UnixStream::pair().context("failed to create socket")?;
                 let (multi_touch_width, multi_touch_height) = cfg
                     .virtio_multi_touch
                     .first()
@@ -1469,7 +1476,7 @@
                     multi_touch_height,
                     virtio::base_features(cfg.protected_vm),
                 )
-                .map_err(Error::InputDeviceNew)?;
+                .context("failed to set up mouse device")?;
                 devs.push(VirtioDeviceStub {
                     dev: Box::new(dev),
                     jail: simple_jail(cfg, "input_device")?,
@@ -1478,7 +1485,7 @@
             }
             if cfg.display_window_keyboard {
                 let (event_device_socket, virtio_dev_socket) =
-                    UnixStream::pair().map_err(Error::CreateSocket)?;
+                    UnixStream::pair().context("failed to create socket")?;
                 let dev = virtio::new_keyboard(
                     // u32::MAX is the least likely to collide with the indices generated above for
                     // the multi_touch options, which begin at 0.
@@ -1486,7 +1493,7 @@
                     virtio_dev_socket,
                     virtio::base_features(cfg.protected_vm),
                 )
-                .map_err(Error::InputDeviceNew)?;
+                .context("failed to set up keyboard device")?;
                 devs.push(VirtioDeviceStub {
                     dev: Box::new(dev),
                     jail: simple_jail(cfg, "input_device")?,
@@ -1591,22 +1598,25 @@
     iommu_enabled: bool,
 ) -> DeviceResult<(Box<VfioPciDevice>, Option<Minijail>)> {
     let vfio_container = VfioCommonSetup::vfio_get_container(vfio_path, iommu_enabled)
-        .map_err(Error::CreateVfioDevice)?;
+        .context("failed to get vfio container")?;
 
     // create MSI, MSI-X, and Mem request sockets for each vfio device
-    let (vfio_host_tube_msi, vfio_device_tube_msi) = Tube::pair().map_err(Error::CreateTube)?;
+    let (vfio_host_tube_msi, vfio_device_tube_msi) =
+        Tube::pair().context("failed to create tube")?;
     control_tubes.push(TaggedControlTube::VmIrq(vfio_host_tube_msi));
 
-    let (vfio_host_tube_msix, vfio_device_tube_msix) = Tube::pair().map_err(Error::CreateTube)?;
+    let (vfio_host_tube_msix, vfio_device_tube_msix) =
+        Tube::pair().context("failed to create tube")?;
     control_tubes.push(TaggedControlTube::VmIrq(vfio_host_tube_msix));
 
-    let (vfio_host_tube_mem, vfio_device_tube_mem) = Tube::pair().map_err(Error::CreateTube)?;
+    let (vfio_host_tube_mem, vfio_device_tube_mem) =
+        Tube::pair().context("failed to create tube")?;
     control_tubes.push(TaggedControlTube::VmMemory(vfio_host_tube_mem));
 
     // put hotplug vfio device on Bus#1 temporary
     let bus_num = if hotplug { Some(1) } else { None };
     let vfio_device = VfioDevice::new(vfio_path, vm, vfio_container.clone(), iommu_enabled)
-        .map_err(Error::CreateVfioDevice)?;
+        .context("failed to create vfio device")?;
     let mut vfio_pci_device = Box::new(VfioPciDevice::new(
         vfio_device,
         bus_num,
@@ -1640,13 +1650,14 @@
     iommu_enabled: bool,
 ) -> DeviceResult<(VfioPlatformDevice, Option<Minijail>)> {
     let vfio_container = VfioCommonSetup::vfio_get_container(vfio_path, iommu_enabled)
-        .map_err(Error::CreateVfioDevice)?;
+        .context("Failed to create vfio device")?;
 
-    let (vfio_host_tube_mem, vfio_device_tube_mem) = Tube::pair().map_err(Error::CreateTube)?;
+    let (vfio_host_tube_mem, vfio_device_tube_mem) =
+        Tube::pair().context("failed to create tube")?;
     control_tubes.push(TaggedControlTube::VmMemory(vfio_host_tube_mem));
 
     let vfio_device = VfioDevice::new(vfio_path, vm, vfio_container, iommu_enabled)
-        .map_err(Error::CreateVfioDevice)?;
+        .context("Failed to create vfio device")?;
     let vfio_plat_dev = VfioPlatformDevice::new(vfio_device, vfio_device_tube_mem);
 
     Ok((vfio_plat_dev, simple_jail(cfg, "vfio_platform_device")?))
@@ -1687,10 +1698,10 @@
     let mut devices = Vec::new();
 
     for stub in stubs {
-        let (msi_host_tube, msi_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+        let (msi_host_tube, msi_device_tube) = Tube::pair().context("failed to create tube")?;
         control_tubes.push(TaggedControlTube::VmIrq(msi_host_tube));
         let dev = VirtioPciDevice::new(vm.get_memory().clone(), stub.dev, msi_device_tube)
-            .map_err(Error::VirtioPciDev)?;
+            .context("failed to create virtio pci dev")?;
         let dev = Box::new(dev) as Box<dyn BusDeviceObj>;
         devices.push((dev, stub.jail));
     }
@@ -1698,7 +1709,7 @@
     #[cfg(feature = "audio")]
     for ac97_param in &cfg.ac97_parameters {
         let dev = Ac97Dev::try_new(vm.get_memory().clone(), ac97_param.clone())
-            .map_err(Error::CreateAc97)?;
+            .context("failed to create ac97 device")?;
         let jail = simple_jail(cfg, dev.minijail_policy())?;
         devices.push((Box::new(dev), jail));
     }
@@ -1756,14 +1767,14 @@
         if !iommu_attached_endpoints.is_empty() {
             let iommu_dev = create_iommu_device(cfg, phys_max_addr, iommu_attached_endpoints)?;
 
-            let (msi_host_tube, msi_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+            let (msi_host_tube, msi_device_tube) = Tube::pair().context("failed to create tube")?;
             control_tubes.push(TaggedControlTube::VmIrq(msi_host_tube));
             let mut dev =
                 VirtioPciDevice::new(vm.get_memory().clone(), iommu_dev.dev, msi_device_tube)
-                    .map_err(Error::VirtioPciDev)?;
+                    .context("failed to create virtio pci dev")?;
             // early reservation for viommu.
             dev.allocate_address(resources)
-                .map_err(|_| Error::VirtioPciDev(base::Error::new(EINVAL)))?;
+                .context("failed to allocate resources early for virtio pci dev")?;
             let dev = Box::new(dev);
             devices.push((dev, iommu_dev.jail));
         }
@@ -1791,9 +1802,9 @@
     let crosvm_gid = getegid();
 
     jail.uidmap(&format!("{0} {0} 1", crosvm_uid))
-        .map_err(Error::SettingUidMap)?;
+        .context("error setting UID map")?;
     jail.gidmap(&format!("{0} {0} 1", crosvm_gid))
-        .map_err(Error::SettingGidMap)?;
+        .context("error setting GID map")?;
 
     if crosvm_uid != 0 {
         jail.change_uid(crosvm_uid);
@@ -1814,12 +1825,10 @@
 
 impl<'a> IntoUnixStream for &'a Path {
     fn into_unix_stream(self) -> Result<UnixStream> {
-        if let Some(fd) =
-            safe_descriptor_from_path(self).map_err(|e| Error::InputEventsOpen(e.into()))?
-        {
+        if let Some(fd) = safe_descriptor_from_path(self).context("failed to open event device")? {
             Ok(fd.into())
         } else {
-            UnixStream::connect(self).map_err(Error::InputEventsOpen)
+            UnixStream::connect(self).context("failed to open event device")
         }
     }
 }
@@ -1841,16 +1850,16 @@
             extern "C" fn handle_signal(_: c_int) {}
             // Our signal handler does nothing and is trivially async signal safe.
             register_rt_signal_handler(SIGRTMIN() + 0, handle_signal)
-                .map_err(Error::RegisterSignalHandler)?;
+                .context("error registering signal handler")?;
         }
-        block_signal(SIGRTMIN() + 0).map_err(Error::BlockSignal)?;
+        block_signal(SIGRTMIN() + 0).context("failed to block signal")?;
     } else {
         unsafe {
             extern "C" fn handle_signal<T: Vcpu>(_: c_int) {
                 T::set_local_immediate_exit(true);
             }
             register_rt_signal_handler(SIGRTMIN() + 0, handle_signal::<T>)
-                .map_err(Error::RegisterSignalHandler)?;
+                .context("error registering signal handler")?;
         }
     }
     Ok(())
@@ -1882,7 +1891,7 @@
             // the vcpu thread.
             match vm
                 .create_vcpu(kvm_vcpu_id)
-                .map_err(Error::CreateVcpu)?
+                .context("failed to create vcpu")?
                 .downcast::<V>()
             {
                 Ok(v) => *v,
@@ -1893,7 +1902,7 @@
 
     irq_chip
         .add_vcpu(cpu_id, &vcpu)
-        .map_err(Error::AddIrqChipVcpu)?;
+        .context("failed to add vcpu to irq chip")?;
 
     if !vcpu_affinity.is_empty() {
         if let Err(e) = set_cpu_affinity(vcpu_affinity) {
@@ -1912,7 +1921,7 @@
         no_smt,
         host_cpu_topology,
     )
-    .map_err(Error::ConfigureVcpu)?;
+    .context("failed to configure vcpu")?;
 
     if !enable_per_vm_core_scheduling {
         // Do per-vCPU core scheduling by setting a unique cookie to each vCPU.
@@ -1931,14 +1940,15 @@
     }
 
     if use_hypervisor_signals {
-        let mut v = get_blocked_signals().map_err(Error::GetSignalMask)?;
+        let mut v = get_blocked_signals().context("failed to retrieve signal mask for vcpu")?;
         v.retain(|&x| x != SIGRTMIN() + 0);
-        vcpu.set_signal_mask(&v).map_err(Error::SettingSignalMask)?;
+        vcpu.set_signal_mask(&v)
+            .context("failed to set the signal mask for vcpu")?;
     }
 
     let vcpu_run_handle = vcpu
         .take_run_handle(Some(SIGRTMIN() + 0))
-        .map_err(Error::RunnableVcpu)?;
+        .context("failed to set thread id for vcpu")?;
 
     Ok((vcpu, vcpu_run_handle))
 }
@@ -1959,21 +1969,23 @@
             let msg = VcpuDebugStatusMessage {
                 cpu: cpu_id as usize,
                 msg: VcpuDebugStatus::RegValues(
-                    Arch::debug_read_registers(vcpu as &V).map_err(Error::HandleDebugCommand)?,
+                    Arch::debug_read_registers(vcpu as &V)
+                        .context("failed to handle a gdb ReadRegs command")?,
                 ),
             };
             reply_tube
                 .send(msg)
-                .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+                .context("failed to send a debug status to GDB thread")
         }
         VcpuDebug::WriteRegs(regs) => {
-            Arch::debug_write_registers(vcpu as &V, &regs).map_err(Error::HandleDebugCommand)?;
+            Arch::debug_write_registers(vcpu as &V, &regs)
+                .context("failed to handle a gdb WriteRegs command")?;
             reply_tube
                 .send(VcpuDebugStatusMessage {
                     cpu: cpu_id as usize,
                     msg: VcpuDebugStatus::CommandComplete,
                 })
-                .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+                .context("failed to send a debug status to GDB thread")
         }
         VcpuDebug::ReadMem(vaddr, len) => {
             let msg = VcpuDebugStatusMessage {
@@ -1985,36 +1997,37 @@
             };
             reply_tube
                 .send(msg)
-                .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+                .context("failed to send a debug status to GDB thread")
         }
         VcpuDebug::WriteMem(vaddr, buf) => {
             Arch::debug_write_memory(vcpu as &V, guest_mem, vaddr, &buf)
-                .map_err(Error::HandleDebugCommand)?;
+                .context("failed to handle a gdb WriteMem command")?;
             reply_tube
                 .send(VcpuDebugStatusMessage {
                     cpu: cpu_id as usize,
                     msg: VcpuDebugStatus::CommandComplete,
                 })
-                .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+                .context("failed to send a debug status to GDB thread")
         }
         VcpuDebug::EnableSinglestep => {
-            Arch::debug_enable_singlestep(vcpu as &V).map_err(Error::HandleDebugCommand)?;
+            Arch::debug_enable_singlestep(vcpu as &V)
+                .context("failed to handle a gdb EnableSingleStep command")?;
             reply_tube
                 .send(VcpuDebugStatusMessage {
                     cpu: cpu_id as usize,
                     msg: VcpuDebugStatus::CommandComplete,
                 })
-                .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+                .context("failed to send a debug status to GDB thread")
         }
         VcpuDebug::SetHwBreakPoint(addrs) => {
             Arch::debug_set_hw_breakpoints(vcpu as &V, &addrs)
-                .map_err(Error::HandleDebugCommand)?;
+                .context("failed to handle a gdb SetHwBreakPoint command")?;
             reply_tube
                 .send(VcpuDebugStatusMessage {
                     cpu: cpu_id as usize,
                     msg: VcpuDebugStatus::CommandComplete,
                 })
-                .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+                .context("failed to send a debug status to GDB thread")
         }
     }
 }
@@ -2307,7 +2320,7 @@
                 }
             }
         })
-        .map_err(Error::SpawnVcpu)
+        .context("failed to spawn VCPU thread")
 }
 
 fn setup_vm_components(cfg: &Config) -> Result<VmComponents> {
@@ -2318,7 +2331,7 @@
                 true,  /*read_only*/
                 false, /*O_DIRECT*/
             )
-            .map_err(|e| Error::OpenInitrd(initrd_path.to_owned(), e.into()))?,
+            .with_context(|| format!("failed to open initrd {}", initrd_path.display()))?,
         )
     } else {
         None
@@ -2331,11 +2344,11 @@
                 true,  /*read_only*/
                 false, /*O_DIRECT*/
             )
-            .map_err(|e| Error::OpenKernel(kernel_path.to_owned(), e.into()))?,
+            .with_context(|| format!("failed to open kernel image {}", kernel_path.display()))?,
         ),
         Some(Executable::Bios(ref bios_path)) => VmImage::Bios(
             open_file(bios_path, true /*read_only*/, false /*O_DIRECT*/)
-                .map_err(|e| Error::OpenBios(bios_path.to_owned(), e.into()))?,
+                .with_context(|| format!("failed to open bios {}", bios_path.display()))?,
         ),
         _ => panic!("Did not receive a bios or kernel, should be impossible."),
     };
@@ -2343,7 +2356,7 @@
     let swiotlb = if let Some(size) = cfg.swiotlb {
         Some(
             size.checked_mul(1024 * 1024)
-                .ok_or(Error::SwiotlbTooLarge)?,
+                .ok_or_else(|| anyhow!("requested swiotlb size too large"))?,
         )
     } else {
         match cfg.protected_vm {
@@ -2357,7 +2370,7 @@
             .memory
             .unwrap_or(256)
             .checked_mul(1024 * 1024)
-            .ok_or(Error::MemoryTooLarge)?,
+            .ok_or_else(|| anyhow!("requested memory size too large"))?,
         swiotlb,
         vcpu_count: cfg.vcpu_count.unwrap_or(1),
         vcpu_affinity: cfg.vcpu_affinity.clone(),
@@ -2369,7 +2382,10 @@
         android_fstab: cfg
             .android_fstab
             .as_ref()
-            .map(|x| File::open(x).map_err(|e| Error::OpenAndroidFstab(x.to_path_buf(), e)))
+            .map(|x| {
+                File::open(x)
+                    .with_context(|| format!("failed to open android fstab file {}", x.display()))
+            })
             .map_or(Ok(None), |v| v.map(Some))?,
         pstore: cfg.pstore.clone(),
         initrd_image,
@@ -2377,7 +2393,10 @@
         acpi_sdts: cfg
             .acpi_tables
             .iter()
-            .map(|path| SDT::from_file(path).map_err(|e| Error::OpenAcpiTable(path.clone(), e)))
+            .map(|path| {
+                SDT::from_file(path)
+                    .with_context(|| format!("failed to open ACPI file {}", path.display()))
+            })
             .collect::<Result<Vec<SDT>>>()?,
         rt_cpus: cfg.rt_cpus.clone(),
         delay_rt: cfg.delay_rt,
@@ -2394,16 +2413,16 @@
     let components = setup_vm_components(&cfg)?;
 
     let guest_mem_layout =
-        Arch::guest_memory_layout(&components).map_err(Error::GuestMemoryLayout)?;
-    let guest_mem = GuestMemory::new(&guest_mem_layout).map_err(Error::CreateGuestMemory)?;
+        Arch::guest_memory_layout(&components).context("failed to create guest memory layout")?;
+    let guest_mem = GuestMemory::new(&guest_mem_layout).context("failed to create guest memory")?;
     let mut mem_policy = MemoryPolicy::empty();
     if components.hugepages {
         mem_policy |= MemoryPolicy::USE_HUGEPAGES;
     }
     guest_mem.set_memory_policy(mem_policy);
-    let kvm = Kvm::new_with_path(&cfg.kvm_device_path).map_err(Error::CreateKvm)?;
-    let vm = KvmVm::new(&kvm, guest_mem).map_err(Error::CreateVm)?;
-    let vm_clone = vm.try_clone().map_err(Error::CreateVm)?;
+    let kvm = Kvm::new_with_path(&cfg.kvm_device_path).context("failed to create kvm")?;
+    let vm = KvmVm::new(&kvm, guest_mem).context("failed to create vm")?;
+    let vm_clone = vm.try_clone().context("failed to clone vm")?;
 
     enum KvmIrqChip {
         #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
@@ -2427,7 +2446,7 @@
         unimplemented!("KVM split irqchip mode only supported on x86 processors");
         #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
         {
-            let (host_tube, ioapic_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+            let (host_tube, ioapic_device_tube) = Tube::pair().context("failed to create tube")?;
             ioapic_host_tube = Some(host_tube);
             KvmIrqChip::Split(
                 KvmSplitIrqChip::new(
@@ -2436,13 +2455,14 @@
                     ioapic_device_tube,
                     Some(120),
                 )
-                .map_err(Error::CreateIrqChip)?,
+                .context("failed to create IRQ chip")?,
             )
         }
     } else {
         ioapic_host_tube = None;
         KvmIrqChip::Kernel(
-            KvmKernelIrqChip::new(vm_clone, components.vcpu_count).map_err(Error::CreateIrqChip)?,
+            KvmKernelIrqChip::new(vm_clone, components.vcpu_count)
+                .context("failed to create IRQ chip")?,
         )
     };
 
@@ -2469,16 +2489,16 @@
 
     #[cfg(feature = "usb")]
     let (usb_control_tube, usb_provider) =
-        HostBackendDeviceProvider::new().map_err(Error::CreateUsbProvider)?;
+        HostBackendDeviceProvider::new().context("failed to create usb provider")?;
 
     // Masking signals is inherently dangerous, since this can persist across clones/execs. Do this
     // before any jailed devices have been spawned, so that we can catch any of them that fail very
     // quickly.
-    let sigchld_fd = SignalFd::new(libc::SIGCHLD).map_err(Error::CreateSignalFd)?;
+    let sigchld_fd = SignalFd::new(libc::SIGCHLD).context("failed to create signalfd")?;
 
     let control_server_socket = match &cfg.socket_path {
         Some(path) => Some(UnlinkUnixSeqpacketListener(
-            UnixSeqpacketListener::bind(path).map_err(Error::CreateControlServer)?,
+            UnixSeqpacketListener::bind(path).context("failed to create control server")?,
         )),
         None => None,
     };
@@ -2488,7 +2508,7 @@
     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
     if let Some(port) = cfg.gdb {
         // GDB needs a control socket to interrupt vcpus.
-        let (gdb_host_tube, gdb_control_tube) = Tube::pair().map_err(Error::CreateTube)?;
+        let (gdb_host_tube, gdb_control_tube) = Tube::pair().context("failed to create tube")?;
         control_tubes.push(TaggedControlTube::Vm(gdb_host_tube));
         components.gdb = Some((port, gdb_control_tube));
     }
@@ -2496,35 +2516,35 @@
     for wl_cfg in &cfg.vhost_user_wl {
         let wayland_host_tube = UnixSeqpacket::connect(&wl_cfg.vm_tube)
             .map(Tube::new)
-            .map_err(Error::ConnectTube)?;
+            .context("failed to connect to wayland tube")?;
         control_tubes.push(TaggedControlTube::VmMemory(wayland_host_tube));
     }
 
     let mut vhost_user_gpu_tubes = Vec::with_capacity(cfg.vhost_user_gpu.len());
     for _ in 0..cfg.vhost_user_gpu.len() {
-        let (host_tube, device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+        let (host_tube, device_tube) = Tube::pair().context("failed to create tube")?;
         vhost_user_gpu_tubes.push((
-            host_tube.try_clone().map_err(Error::CloneTube)?,
+            host_tube.try_clone().context("failed to clone tube")?,
             device_tube,
         ));
         control_tubes.push(TaggedControlTube::VmMemory(host_tube));
     }
 
-    let (wayland_host_tube, wayland_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+    let (wayland_host_tube, wayland_device_tube) = Tube::pair().context("failed to create tube")?;
     control_tubes.push(TaggedControlTube::VmMemory(wayland_host_tube));
     // Balloon gets a special socket so balloon requests can be forwarded from the main process.
-    let (balloon_host_tube, balloon_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+    let (balloon_host_tube, balloon_device_tube) = Tube::pair().context("failed to create tube")?;
     // Set recv timeout to avoid deadlock on sending BalloonControlCommand before guest is ready.
     balloon_host_tube
         .set_recv_timeout(Some(Duration::from_millis(100)))
-        .map_err(Error::CreateTube)?;
+        .context("failed to create tube")?;
 
     // Create one control socket per disk.
     let mut disk_device_tubes = Vec::new();
     let mut disk_host_tubes = Vec::new();
     let disk_count = cfg.disks.len();
     for _ in 0..disk_count {
-        let (disk_host_tub, disk_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+        let (disk_host_tub, disk_device_tube) = Tube::pair().context("failed to create tube")?;
         disk_host_tubes.push(disk_host_tub);
         disk_device_tubes.push(disk_device_tube);
     }
@@ -2532,12 +2552,12 @@
     let mut pmem_device_tubes = Vec::new();
     let pmem_count = cfg.pmem_devices.len();
     for _ in 0..pmem_count {
-        let (pmem_host_tube, pmem_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+        let (pmem_host_tube, pmem_device_tube) = Tube::pair().context("failed to create tube")?;
         pmem_device_tubes.push(pmem_device_tube);
         control_tubes.push(TaggedControlTube::VmMsync(pmem_host_tube));
     }
 
-    let (gpu_host_tube, gpu_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+    let (gpu_host_tube, gpu_device_tube) = Tube::pair().context("failed to create tube")?;
     control_tubes.push(TaggedControlTube::VmMemory(gpu_host_tube));
 
     if let Some(ioapic_host_tube) = ioapic_host_tube {
@@ -2584,19 +2604,19 @@
         .count();
     let mut fs_device_tubes = Vec::with_capacity(fs_count);
     for _ in 0..fs_count {
-        let (fs_host_tube, fs_device_tube) = Tube::pair().map_err(Error::CreateTube)?;
+        let (fs_host_tube, fs_device_tube) = Tube::pair().context("failed to create tube")?;
         control_tubes.push(TaggedControlTube::Fs(fs_host_tube));
         fs_device_tubes.push(fs_device_tube);
     }
 
-    let exit_evt = Event::new().map_err(Error::CreateEvent)?;
+    let exit_evt = Event::new().context("failed to create event")?;
     let mut sys_allocator = Arch::create_system_allocator(vm.get_memory());
 
     // Allocate the ramoops region first. AArch64::build_vm() assumes this.
     let ramoops_region = match &components.pstore {
         Some(pstore) => Some(
             arch::pstore::create_memory_region(&mut vm, &mut sys_allocator, pstore)
-                .map_err(Error::Pstore)?,
+                .context("failed to allocate pstore region")?,
         ),
         None => None,
     };
@@ -2632,7 +2652,7 @@
                 error!("ACPI table generation error");
                 None
             })
-            .ok_or(Error::GenerateAcpi)?;
+            .ok_or_else(|| anyhow!("failed to generate ACPI table"))?;
         components.acpi_sdts = sdts;
     }
 
@@ -2653,12 +2673,13 @@
         irq_chip,
         &mut kvm_vcpu_ids,
     )
-    .map_err(Error::BuildVm)?;
+    .context("the architecture failed to build the vm")?;
 
     #[cfg(feature = "direct")]
     if let Some(pmio) = &cfg.direct_pmio {
-        let direct_io =
-            Arc::new(devices::DirectIo::new(&pmio.path, false).map_err(Error::DirectIo)?);
+        let direct_io = Arc::new(
+            devices::DirectIo::new(&pmio.path, false).context("failed to open direct io device")?,
+        );
         for range in pmio.ranges.iter() {
             linux
                 .io_bus
@@ -2669,8 +2690,9 @@
 
     #[cfg(feature = "direct")]
     if let Some(mmio) = &cfg.direct_mmio {
-        let direct_io =
-            Arc::new(devices::DirectIo::new(&mmio.path, false).map_err(Error::DirectIo)?);
+        let direct_io = Arc::new(
+            devices::DirectIo::new(&mmio.path, false).context("failed to open direct io device")?,
+        );
         for range in mmio.ranges.iter() {
             linux
                 .mmio_bus
@@ -2687,15 +2709,17 @@
         if !sys_allocator.reserve_irq(*irq) {
             warn!("irq {} already reserved.", irq);
         }
-        let trigger = Event::new().map_err(Error::CreateEvent)?;
-        let resample = Event::new().map_err(Error::CreateEvent)?;
+        let trigger = Event::new().context("failed to create event")?;
+        let resample = Event::new().context("failed to create event")?;
         linux
             .irq_chip
             .register_irq_event(*irq, &trigger, Some(&resample))
             .unwrap();
-        let direct_irq =
-            devices::DirectIrq::new(trigger, Some(resample)).map_err(Error::DirectIrq)?;
-        direct_irq.irq_enable(*irq).map_err(Error::DirectIrq)?;
+        let direct_irq = devices::DirectIrq::new(trigger, Some(resample))
+            .context("failed to enable interrupt forwarding")?;
+        direct_irq
+            .irq_enable(*irq)
+            .context("failed to enable interrupt forwarding")?;
         irqs.push(direct_irq);
     }
 
@@ -2704,17 +2728,20 @@
         if !sys_allocator.reserve_irq(*irq) {
             warn!("irq {} already reserved.", irq);
         }
-        let trigger = Event::new().map_err(Error::CreateEvent)?;
+        let trigger = Event::new().context("failed to create event")?;
         linux
             .irq_chip
             .register_irq_event(*irq, &trigger, None)
             .unwrap();
-        let direct_irq = devices::DirectIrq::new(trigger, None).map_err(Error::DirectIrq)?;
-        direct_irq.irq_enable(*irq).map_err(Error::DirectIrq)?;
+        let direct_irq = devices::DirectIrq::new(trigger, None)
+            .context("failed to enable interrupt forwarding")?;
+        direct_irq
+            .irq_enable(*irq)
+            .context("failed to enable interrupt forwarding")?;
         irqs.push(direct_irq);
     }
 
-    let gralloc = RutabagaGralloc::new().map_err(Error::CreateGrallocError)?;
+    let gralloc = RutabagaGralloc::new().context("failed to create gralloc")?;
     run_control(
         linux,
         sys_allocator,
@@ -2756,10 +2783,14 @@
     )?;
 
     let pci_address = Arch::register_pci_device(linux, vfio_pci_device, jail, sys_allocator)
-        .map_err(Error::ConfigureHotPlugDevice)?;
+        .context("Failed to configure pci hotplug device")?;
 
-    let host_os_str = vfio_path.file_name().ok_or(Error::InvalidVfioPath)?;
-    let host_str = host_os_str.to_str().ok_or(Error::InvalidVfioPath)?;
+    let host_os_str = vfio_path
+        .file_name()
+        .ok_or_else(|| anyhow!("failed to parse or find vfio path"))?;
+    let host_str = host_os_str
+        .to_str()
+        .ok_or_else(|| anyhow!("failed to parse or find vfio path"))?;
     let host_addr = PciAddress::from_string(host_str);
     let host_key = HostHotPlugKey::Vfio { host_addr };
     if let Some(hp_bus) = &linux.hotplug_bus {
@@ -2769,7 +2800,7 @@
         return Ok(());
     }
 
-    Err(Error::NoHotPlugBus)
+    Err(anyhow!("HotPlugBus hasn't been implemented"))
 }
 
 #[allow(dead_code)]
@@ -2777,20 +2808,24 @@
     linux: &RunnableLinuxVm<V, Vcpu>,
     vfio_path: &Path,
 ) -> Result<()> {
-    let host_os_str = vfio_path.file_name().ok_or(Error::InvalidVfioPath)?;
-    let host_str = host_os_str.to_str().ok_or(Error::InvalidVfioPath)?;
+    let host_os_str = vfio_path
+        .file_name()
+        .ok_or_else(|| anyhow!("failed to parse or find vfio path"))?;
+    let host_str = host_os_str
+        .to_str()
+        .ok_or_else(|| anyhow!("failed to parse or find vfio path"))?;
     let host_addr = PciAddress::from_string(host_str);
     let host_key = HostHotPlugKey::Vfio { host_addr };
     if let Some(hp_bus) = &linux.hotplug_bus {
         let mut hp_bus = hp_bus.lock();
         let pci_addr = hp_bus
             .get_hotplug_device(host_key)
-            .ok_or(Error::InvalidHotPlugKey)?;
+            .ok_or_else(|| anyhow!("failed to find hotplug key in hotplug bus"))?;
         hp_bus.hot_unplug(pci_addr);
         return Ok(());
     }
 
-    Err(Error::NoHotPlugBus)
+    Err(anyhow!("HotPlugBus hasn't been implemented"))
 }
 
 /// Signals all running VCPUs to vmexit, sends VcpuControl message to each VCPU tube, and tells
@@ -2847,33 +2882,33 @@
         (&linux.suspend_evt, Token::Suspend),
         (&sigchld_fd, Token::ChildSignal),
     ])
-    .map_err(Error::WaitContextAdd)?;
+    .context("failed to add descriptor to wait context")?;
 
     if let Some(socket_server) = &control_server_socket {
         wait_ctx
             .add(socket_server, Token::VmControlServer)
-            .map_err(Error::WaitContextAdd)?;
+            .context("failed to add descriptor to wait context")?;
     }
     for (index, socket) in control_tubes.iter().enumerate() {
         wait_ctx
             .add(socket.as_ref(), Token::VmControl { index })
-            .map_err(Error::WaitContextAdd)?;
+            .context("failed to add descriptor to wait context")?;
     }
 
     let events = linux
         .irq_chip
         .irq_event_tokens()
-        .map_err(Error::WaitContextAdd)?;
+        .context("failed to add descriptor to wait context")?;
 
     for (index, _gsi, evt) in events {
         wait_ctx
             .add(&evt, Token::IrqFd { index })
-            .map_err(Error::WaitContextAdd)?;
+            .context("failed to add descriptor to wait context")?;
     }
 
     if sandbox {
         // Before starting VCPUs, in case we started with some capabilities, drop them all.
-        drop_capabilities().map_err(Error::DropCapabilities)?;
+        drop_capabilities().context("failed to drop process capabilities")?;
     }
 
     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
@@ -2917,8 +2952,11 @@
             cpu_id,
             kvm_vcpu_ids[cpu_id],
             vcpu,
-            linux.vm.try_clone().map_err(Error::CloneEvent)?,
-            linux.irq_chip.try_box_clone().map_err(Error::CloneEvent)?,
+            linux.vm.try_clone().context("failed to clone vm")?,
+            linux
+                .irq_chip
+                .try_box_clone()
+                .context("failed to clone irqchip")?,
             linux.vcpu_count,
             linux.rt_cpus.contains(&cpu_id),
             vcpu_affinity,
@@ -2928,7 +2966,7 @@
             linux.has_bios,
             (*linux.io_bus).clone(),
             (*linux.mmio_bus).clone(),
-            exit_evt.try_clone().map_err(Error::CloneEvent)?,
+            exit_evt.try_clone().context("failed to clone event")?,
             linux.vm.check_capability(VmCap::PvClockSuspend),
             from_main_channel,
             use_hypervisor_signals,
@@ -2955,7 +2993,7 @@
         thread::Builder::new()
             .name("gdb".to_owned())
             .spawn(move || gdb_thread(target, gdb_port_num))
-            .map_err(Error::SpawnGdbServer)?;
+            .context("failed to spawn GDB thread")?;
     };
 
     vcpu_thread_barrier.wait();
@@ -2995,7 +3033,9 @@
                 }
                 Token::ChildSignal => {
                     // Print all available siginfo structs, then exit the loop.
-                    while let Some(siginfo) = sigchld_fd.read().map_err(Error::SignalFd)? {
+                    while let Some(siginfo) =
+                        sigchld_fd.read().context("failed to create signalfd")?
+                    {
                         let pid = siginfo.ssi_pid;
                         let pid_label = match linux.pid_debug_label_map.get(&pid) {
                             Some(label) => format!("{} (pid {})", label, pid),
@@ -3024,7 +3064,7 @@
                                             index: control_tubes.len(),
                                         },
                                     )
-                                    .map_err(Error::WaitContextAdd)?;
+                                    .context("failed to add descriptor to wait context")?;
                                 control_tubes.push(TaggedControlTube::Vm(Tube::new(socket)));
                             }
                             Err(e) => error!("failed to accept socket: {}", e),
@@ -3215,7 +3255,9 @@
             // sockets that might not be ready to use. This can cause incorrect hangup detection or
             // blocking on a socket that will never be ready. See also: crbug.com/1019986
             if let Some(socket) = control_tubes.get(index) {
-                wait_ctx.delete(socket).map_err(Error::WaitContextDelete)?;
+                wait_ctx
+                    .delete(socket)
+                    .context("failed to remove descriptor from wait context")?;
             }
 
             // This line implicitly drops the socket at `index` when it gets returned by
@@ -3226,7 +3268,7 @@
             if let Some(tube) = control_tubes.get(index) {
                 wait_ctx
                     .modify(tube, EventType::Read, Token::VmControl { index })
-                    .map_err(Error::WaitContextAdd)?;
+                    .context("failed to add descriptor to wait context")?;
             }
         }
     }
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index 9747737..5a19cd2 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -45,7 +45,6 @@
 mod smbios;
 
 use std::collections::BTreeMap;
-use std::error::Error as StdError;
 use std::ffi::{CStr, CString};
 use std::fs::File;
 use std::io::{self, Seek};
@@ -99,8 +98,6 @@
     CreateAcpi,
     #[error("unable to create battery devices: {0}")]
     CreateBatDevices(arch::DeviceRegistrationError),
-    #[error("error creating devices: {0}")]
-    CreateDevices(Box<dyn StdError>),
     #[error("unable to make an Event: {0}")]
     CreateEvent(base::Error),
     #[error("failed to create fdt: {0}")]
@@ -119,8 +116,6 @@
     CreateSocket(io::Error),
     #[error("failed to create VCPU: {0}")]
     CreateVcpu(base::Error),
-    #[error("failed to create VM: {0}")]
-    CreateVm(Box<dyn StdError>),
     #[error("invalid e820 setup params")]
     E820Configuration,
     #[error("failed to enable singlestep execution: {0}")]