diff options
author | Zach Reizner <zachr@google.com> | 2019-01-23 19:04:43 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-01-26 00:59:57 -0800 |
commit | 3ba0098d6764df4a7b2c885f0cf5263b4062c357 (patch) | |
tree | 87e285eb55498f152457ffacdf66345feb5ed037 | |
parent | 1be25dc3d2ce8afe41d0fe7fe7b157c3f1787b50 (diff) | |
download | crosvm-3ba0098d6764df4a7b2c885f0cf5263b4062c357.tar crosvm-3ba0098d6764df4a7b2c885f0cf5263b4062c357.tar.gz crosvm-3ba0098d6764df4a7b2c885f0cf5263b4062c357.tar.bz2 crosvm-3ba0098d6764df4a7b2c885f0cf5263b4062c357.tar.lz crosvm-3ba0098d6764df4a7b2c885f0cf5263b4062c357.tar.xz crosvm-3ba0098d6764df4a7b2c885f0cf5263b4062c357.tar.zst crosvm-3ba0098d6764df4a7b2c885f0cf5263b4062c357.zip |
crosvm: add debug labels to devices for improved SIGCHLD logs
Each device (Bus, Pci, Proxy, etc), gets a debug label associated with it. When a child is spawned, the debug label for it is stored in a map with the child's pid as the key. If a SIGCHLD is handled, this map is used to print a more helpful message about exactly which child died. BUG=None TEST=run with sandboxing and a faulty child device check logs for message about child died the child should have a debug label Change-Id: I61fbbee0a8e701249533a7a3a6a1ad48840f12e5 Reviewed-on: https://chromium-review.googlesource.com/1432835 Commit-Ready: Chih-Yang Hsia <paulhsia@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
-rw-r--r-- | aarch64/src/lib.rs | 3 | ||||
-rw-r--r-- | arch/src/lib.rs | 11 | ||||
-rw-r--r-- | devices/src/bus.rs | 12 | ||||
-rw-r--r-- | devices/src/cmos.rs | 4 | ||||
-rw-r--r-- | devices/src/i8042.rs | 4 | ||||
-rw-r--r-- | devices/src/pci/pci_device.rs | 10 | ||||
-rw-r--r-- | devices/src/pci/pci_root.rs | 11 | ||||
-rw-r--r-- | devices/src/pl030.rs | 4 | ||||
-rw-r--r-- | devices/src/proxy.rs | 17 | ||||
-rw-r--r-- | devices/src/serial.rs | 4 | ||||
-rw-r--r-- | devices/src/virtio/mod.rs | 15 | ||||
-rw-r--r-- | devices/src/virtio/virtio_device.rs | 8 | ||||
-rw-r--r-- | devices/src/virtio/virtio_pci_device.rs | 4 | ||||
-rw-r--r-- | src/linux.rs | 10 | ||||
-rw-r--r-- | x86_64/src/lib.rs | 9 |
15 files changed, 114 insertions, 12 deletions
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs index dda7bfc..d579a17 100644 --- a/aarch64/src/lib.rs +++ b/aarch64/src/lib.rs @@ -227,7 +227,7 @@ impl arch::LinuxArch for AArch64 { let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?; let pci_devices = virtio_devs(&mem, &exit_evt)?; - let (pci, pci_irqs) = + let (pci, pci_irqs, pid_debug_label_map) = arch::generate_pci_root(pci_devices, &mut mmio_bus, &mut resources, &mut vm) .map_err(Error::CreatePciRoot)?; let pci_bus = Arc::new(Mutex::new(PciConfigMmio::new(pci))); @@ -277,6 +277,7 @@ impl arch::LinuxArch for AArch64 { irq_chip, io_bus, mmio_bus, + pid_debug_label_map, }) } } diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 057c005..bc326eb 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -11,6 +11,7 @@ extern crate resources; extern crate sync; extern crate sys_util; +use std::collections::BTreeMap; use std::fmt; use std::fs::File; use std::io::{Read, Seek, SeekFrom}; @@ -52,6 +53,7 @@ pub struct RunnableLinuxVm { pub irq_chip: Option<File>, pub io_bus: Bus, pub mmio_bus: Bus, + pub pid_debug_label_map: BTreeMap<u32, String>, } /// The device and optional jail. @@ -144,9 +146,13 @@ pub fn generate_pci_root( mmio_bus: &mut Bus, resources: &mut SystemAllocator, vm: &mut Vm, -) -> std::result::Result<(PciRoot, Vec<(u32, PciInterruptPin)>), DeviceRegistrationError> { +) -> std::result::Result< + (PciRoot, Vec<(u32, PciInterruptPin)>, BTreeMap<u32, String>), + DeviceRegistrationError, +> { let mut root = PciRoot::new(); let mut pci_irqs = Vec::new(); + let mut pid_labels = BTreeMap::new(); for (dev_idx, (mut device, jail)) in devices.into_iter().enumerate() { let mut keep_fds = device.keep_fds(); syslog::push_fds(&mut keep_fds); @@ -182,6 +188,7 @@ pub fn generate_pci_root( let arced_dev: Arc<Mutex<BusDevice>> = if let Some(jail) = jail { let proxy = ProxyDevice::new(device, &jail, keep_fds) .map_err(DeviceRegistrationError::ProxyDeviceCreation)?; + pid_labels.insert(proxy.pid() as u32, proxy.debug_label()); Arc::new(Mutex::new(proxy)) } else { Arc::new(Mutex::new(device)) @@ -193,7 +200,7 @@ pub fn generate_pci_root( .map_err(DeviceRegistrationError::MmioInsert)?; } } - Ok((root, pci_irqs)) + Ok((root, pci_irqs, pid_labels)) } /// Errors for image loading. diff --git a/devices/src/bus.rs b/devices/src/bus.rs index 5eb09a2..1c21661 100644 --- a/devices/src/bus.rs +++ b/devices/src/bus.rs @@ -17,6 +17,8 @@ use sync::Mutex; /// into its allocated portion of address space. #[allow(unused_variables)] pub trait BusDevice: Send { + /// Returns a label suitable for debug output. + fn debug_label(&self) -> String; /// Reads at `offset` from this device fn read(&mut self, offset: u64, data: &mut [u8]) {} /// Writes at `offset` into this device @@ -202,10 +204,18 @@ mod tests { use super::*; struct DummyDevice; - impl BusDevice for DummyDevice {} + impl BusDevice for DummyDevice { + fn debug_label(&self) -> String { + "dummy device".to_owned() + } + } struct ConstantDevice; impl BusDevice for ConstantDevice { + fn debug_label(&self) -> String { + "constant device".to_owned() + } + fn read(&mut self, offset: u64, data: &mut [u8]) { for (i, v) in data.iter_mut().enumerate() { *v = (offset as u8) + (i as u8); diff --git a/devices/src/cmos.rs b/devices/src/cmos.rs index cf5dd7e..5c04678 100644 --- a/devices/src/cmos.rs +++ b/devices/src/cmos.rs @@ -29,6 +29,10 @@ impl Cmos { } impl BusDevice for Cmos { + fn debug_label(&self) -> String { + "cmos".to_owned() + } + fn write(&mut self, offset: u64, data: &[u8]) { if data.len() != 1 { return; diff --git a/devices/src/i8042.rs b/devices/src/i8042.rs index 8981e02..0d0c31d 100644 --- a/devices/src/i8042.rs +++ b/devices/src/i8042.rs @@ -22,6 +22,10 @@ impl I8042Device { // registers: port 0x61 (I8042_PORT_B_REG, offset 0 from base of 0x61), and // port 0x64 (I8042_COMMAND_REG, offset 3 from base of 0x61). impl BusDevice for I8042Device { + fn debug_label(&self) -> String { + "i8042".to_owned() + } + fn read(&mut self, offset: u64, data: &mut [u8]) { if data.len() == 1 && offset == 3 { data[0] = 0x0; diff --git a/devices/src/pci/pci_device.rs b/devices/src/pci/pci_device.rs index 4d3a46e..5ccdfef 100644 --- a/devices/src/pci/pci_device.rs +++ b/devices/src/pci/pci_device.rs @@ -25,6 +25,8 @@ pub enum Error { pub type Result<T> = std::result::Result<T, Error>; pub trait PciDevice: Send { + /// Returns a label suitable for debug output. + fn debug_label(&self) -> String; /// A vector of device-specific file descriptors that must be kept open /// after jailing. Must be called before the process is jailed. fn keep_fds(&self) -> Vec<RawFd>; @@ -66,6 +68,10 @@ pub trait PciDevice: Send { } impl<T: PciDevice> BusDevice for T { + fn debug_label(&self) -> String { + PciDevice::debug_label(self) + } + fn read(&mut self, offset: u64, data: &mut [u8]) { self.read_bar(offset, data) } @@ -102,6 +108,10 @@ impl<T: PciDevice> BusDevice for T { } impl<T: PciDevice + ?Sized> PciDevice for Box<T> { + /// Returns a label suitable for debug output. + fn debug_label(&self) -> String { + (**self).debug_label() + } fn keep_fds(&self) -> Vec<RawFd> { (**self).keep_fds() } diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs index 4864ff7..b432be2 100644 --- a/devices/src/pci/pci_root.rs +++ b/devices/src/pci/pci_root.rs @@ -20,6 +20,9 @@ struct PciRootConfiguration { } impl PciDevice for PciRootConfiguration { + fn debug_label(&self) -> String { + "pci root device".to_owned() + } fn keep_fds(&self) -> Vec<RawFd> { Vec::new() } @@ -188,6 +191,10 @@ impl PciConfigIo { } impl BusDevice for PciConfigIo { + fn debug_label(&self) -> String { + format!("pci config io-port 0x{:03x}", self.config_address) + } + fn read(&mut self, offset: u64, data: &mut [u8]) { // `offset` is relative to 0xcf8 let value = match offset { @@ -245,6 +252,10 @@ impl PciConfigMmio { } impl BusDevice for PciConfigMmio { + fn debug_label(&self) -> String { + format!("pci config mmio") + } + fn read(&mut self, offset: u64, data: &mut [u8]) { // Only allow reads to the register boundary. let start = offset as usize % 4; diff --git a/devices/src/pl030.rs b/devices/src/pl030.rs index 6710b5e..63fedc8 100644 --- a/devices/src/pl030.rs +++ b/devices/src/pl030.rs @@ -70,6 +70,10 @@ impl Pl030 { } impl BusDevice for Pl030 { + fn debug_label(&self) -> String { + "Pl030".to_owned() + } + fn write(&mut self, offset: u64, data: &[u8]) { if data.len() != 4 { warn!("bad write size: {} for pl030", data.len()); diff --git a/devices/src/proxy.rs b/devices/src/proxy.rs index 0b60736..907f33c 100644 --- a/devices/src/proxy.rs +++ b/devices/src/proxy.rs @@ -120,6 +120,7 @@ fn child_proc(sock: UnixDatagram, device: &mut BusDevice) { pub struct ProxyDevice { sock: MsgSocket<Command, CommandResult>, pid: pid_t, + debug_label: String, } impl ProxyDevice { @@ -136,6 +137,7 @@ impl ProxyDevice { jail: &Minijail, mut keep_fds: Vec<RawFd>, ) -> Result<ProxyDevice> { + let debug_label = device.debug_label(); let (child_sock, parent_sock) = UnixDatagram::pair().map_err(Error::Io)?; keep_fds.push(child_sock.as_raw_fd()); @@ -161,6 +163,7 @@ impl ProxyDevice { Ok(ProxyDevice { sock: MsgSocket::<Command, CommandResult>::new(parent_sock), pid, + debug_label, }) } @@ -171,11 +174,17 @@ impl ProxyDevice { fn sync_send(&self, cmd: Command) -> Option<CommandResult> { let res = self.sock.send(&cmd); if let Err(e) = res { - error!("failed write to child device process: {:?}", e); + error!( + "failed write to child device process {}: {:?}", + self.debug_label, e + ); }; match self.sock.recv() { Err(e) => { - error!("failed read from child device process: {:?}", e); + error!( + "failed read from child device process {}: {:?}", + self.debug_label, e + ); None } Ok(r) => Some(r), @@ -184,6 +193,10 @@ impl ProxyDevice { } impl BusDevice for ProxyDevice { + fn debug_label(&self) -> String { + self.debug_label.clone() + } + fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { let len = data.len() as u32; let mut buffer = [0u8; 4]; diff --git a/devices/src/serial.rs b/devices/src/serial.rs index 25911f9..b2a5651 100644 --- a/devices/src/serial.rs +++ b/devices/src/serial.rs @@ -185,6 +185,10 @@ impl Serial { } impl BusDevice for Serial { + fn debug_label(&self) -> String { + "serial".to_owned() + } + fn write(&mut self, offset: u64, data: &[u8]) { if data.len() != 1 { return; diff --git a/devices/src/virtio/mod.rs b/devices/src/virtio/mod.rs index 5a46bea..78cfeb2 100644 --- a/devices/src/virtio/mod.rs +++ b/devices/src/virtio/mod.rs @@ -64,3 +64,18 @@ const INTERRUPT_STATUS_CONFIG_CHANGED: u32 = 0x2; /// Offset from the base MMIO address of a virtio device used by the guest to notify the device of /// queue events. pub const NOTIFY_REG_OFFSET: u32 = 0x50; + +/// Returns a string representation of the given virtio device type number. +pub fn type_to_str(type_: u32) -> Option<&'static str> { + Some(match type_ { + TYPE_NET => "net", + TYPE_BLOCK => "block", + TYPE_RNG => "rng", + TYPE_BALLOON => "balloon", + TYPE_GPU => "gpu", + TYPE_9P => "9p", + TYPE_VSOCK => "vsock", + TYPE_WL => "wl", + _ => return None, + }) +} diff --git a/devices/src/virtio/virtio_device.rs b/devices/src/virtio/virtio_device.rs index 1bf0281..82ca012 100644 --- a/devices/src/virtio/virtio_device.rs +++ b/devices/src/virtio/virtio_device.rs @@ -17,6 +17,14 @@ use sys_util::{EventFd, GuestMemory}; /// Optionally, a virtio device can implement device reset in which it returns said resources and /// resets its internal. pub trait VirtioDevice: Send { + /// Returns a label suitable for debug output. + fn debug_label(&self) -> String { + match type_to_str(self.device_type()) { + Some(s) => format!("virtio-{}", s), + None => format!("virtio (type {})", self.device_type()), + } + } + /// A vector of device-specific file descriptors that must be kept open /// after jailing. Must be called before the process is jailed. fn keep_fds(&self) -> Vec<RawFd>; diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs index 6a9ca5e..f9cb948 100644 --- a/devices/src/virtio/virtio_pci_device.rs +++ b/devices/src/virtio/virtio_pci_device.rs @@ -276,6 +276,10 @@ impl VirtioPciDevice { } impl PciDevice for VirtioPciDevice { + fn debug_label(&self) -> String { + format!("virtio-pci ({})", self.device.debug_label()) + } + fn keep_fds(&self) -> Vec<RawFd> { let mut fds = self.device.keep_fds(); if let Some(ref interrupt_evt) = self.interrupt_evt { diff --git a/src/linux.rs b/src/linux.rs index 1dcedbe..4b684ca 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1023,12 +1023,14 @@ fn run_control( Token::ChildSignal => { // Print all available siginfo structs, then exit the loop. while let Some(siginfo) = sigchld_fd.read().map_err(Error::SignalFd)? { + let pid = siginfo.ssi_pid; + let pid_label = match linux.pid_debug_label_map.get(&pid) { + Some(label) => format!("{} (pid {})", label, pid), + None => format!("pid {}", pid), + }; error!( "child {} died: signo {}, status {}, code {}", - siginfo.ssi_pid, - siginfo.ssi_signo, - siginfo.ssi_status, - siginfo.ssi_code + pid_label, siginfo.ssi_signo, siginfo.ssi_status, siginfo.ssi_code ); } break 'poll; diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index 524013c..2857bb7 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -300,7 +300,7 @@ impl arch::LinuxArch for X8664arch { let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?; let pci_devices = virtio_devs(&mem, &exit_evt)?; - let (pci, pci_irqs) = + let (pci, pci_irqs, pid_debug_label_map) = arch::generate_pci_root(pci_devices, &mut mmio_bus, &mut resources, &mut vm) .map_err(Error::CreatePciRoot)?; let pci_bus = Arc::new(Mutex::new(PciConfigIo::new(pci))); @@ -336,6 +336,7 @@ impl arch::LinuxArch for X8664arch { irq_chip, io_bus, mmio_bus, + pid_debug_label_map, }) } } @@ -463,7 +464,11 @@ impl X8664arch { pci: Option<Arc<Mutex<devices::PciConfigIo>>>, ) -> Result<(devices::Bus, Arc<Mutex<devices::Serial>>)> { struct NoDevice; - impl devices::BusDevice for NoDevice {} + impl devices::BusDevice for NoDevice { + fn debug_label(&self) -> String { + "no device".to_owned() + } + } let mut io_bus = devices::Bus::new(); |