190034fd6SYi Wang // Copyright © 2022 ZTE Corporation 290034fd6SYi Wang // 390034fd6SYi Wang // SPDX-License-Identifier: Apache-2.0 490034fd6SYi Wang // 590034fd6SYi Wang 688a9f799SRob Bradford use std::fs::File; 788a9f799SRob Bradford use std::io::Write; 888a9f799SRob Bradford 9ccb604e1SYi Wang #[cfg(target_arch = "x86_64")] 10f1ab86feSWei Liu use hypervisor::arch::x86::{DescriptorTable, SegmentRegister}; 117e280b6fSYi Wang use linux_loader::elf; 12fff62d93SPhilipp Schuster use thiserror::Error; 137e280b6fSYi Wang use vm_memory::ByteValued; 1490034fd6SYi Wang 1590034fd6SYi Wang #[derive(Clone)] 1690034fd6SYi Wang pub struct CoredumpMemoryRegion { 1790034fd6SYi Wang pub mem_offset_in_elf: u64, 1890034fd6SYi Wang pub mem_size: u64, 1990034fd6SYi Wang } 2090034fd6SYi Wang 2190034fd6SYi Wang #[derive(Clone)] 2290034fd6SYi Wang pub struct CoredumpMemoryRegions { 2390034fd6SYi Wang pub ram_maps: std::collections::BTreeMap<u64, CoredumpMemoryRegion>, 2490034fd6SYi Wang } 2590034fd6SYi Wang 2690034fd6SYi Wang /// Platform information 2790034fd6SYi Wang #[derive(Default)] 2890034fd6SYi Wang pub struct DumpState { 2990034fd6SYi Wang pub elf_note_size: isize, 3090034fd6SYi Wang pub elf_phdr_num: u16, 3190034fd6SYi Wang pub elf_sh_info: u32, 3290034fd6SYi Wang pub mem_offset: u64, 3390034fd6SYi Wang pub mem_info: Option<CoredumpMemoryRegions>, 3490034fd6SYi Wang pub file: Option<File>, 3590034fd6SYi Wang } 3690034fd6SYi Wang 37fff62d93SPhilipp Schuster #[derive(Error, Debug)] 3890034fd6SYi Wang pub enum GuestDebuggableError { 39*d7edd9d5SPhilipp Schuster #[error("coredump")] 40fff62d93SPhilipp Schuster Coredump(#[source] anyhow::Error), 41*d7edd9d5SPhilipp Schuster #[error("coredump file")] 42fff62d93SPhilipp Schuster CoredumpFile(#[source] std::io::Error), 43*d7edd9d5SPhilipp Schuster #[error("Failed to pause")] 44fff62d93SPhilipp Schuster Pause(#[source] vm_migration::MigratableError), 45*d7edd9d5SPhilipp Schuster #[error("Failed to resume")] 46fff62d93SPhilipp Schuster Resume(#[source] vm_migration::MigratableError), 4790034fd6SYi Wang } 4890034fd6SYi Wang 4990034fd6SYi Wang pub trait GuestDebuggable: vm_migration::Pausable { coredump( &mut self, _destination_url: &str, ) -> std::result::Result<(), GuestDebuggableError>5090034fd6SYi Wang fn coredump( 5190034fd6SYi Wang &mut self, 5290034fd6SYi Wang _destination_url: &str, 5390034fd6SYi Wang ) -> std::result::Result<(), GuestDebuggableError> { 5490034fd6SYi Wang Ok(()) 5590034fd6SYi Wang } 5690034fd6SYi Wang } 577e280b6fSYi Wang 587e280b6fSYi Wang #[repr(C)] 597e280b6fSYi Wang #[derive(Default, Copy, Clone)] 607e280b6fSYi Wang pub struct X86_64UserRegs { 617e280b6fSYi Wang /// r15, r14, r13, r12, rbp, rbx, r11, r10; 627e280b6fSYi Wang pub regs1: [u64; 8], 637e280b6fSYi Wang /// r9, r8, rax, rcx, rdx, rsi, rdi, orig_rax; 647e280b6fSYi Wang pub regs2: [u64; 8], 657e280b6fSYi Wang pub rip: u64, 667e280b6fSYi Wang pub cs: u64, 677e280b6fSYi Wang pub eflags: u64, 687e280b6fSYi Wang pub rsp: u64, 697e280b6fSYi Wang pub ss: u64, 707e280b6fSYi Wang pub fs_base: u64, 717e280b6fSYi Wang pub gs_base: u64, 727e280b6fSYi Wang pub ds: u64, 737e280b6fSYi Wang pub es: u64, 747e280b6fSYi Wang pub fs: u64, 757e280b6fSYi Wang pub gs: u64, 767e280b6fSYi Wang } 777e280b6fSYi Wang 78d05586f5SWei Liu // SAFETY: This is just a series of bytes 79ccb604e1SYi Wang unsafe impl ByteValued for X86_64UserRegs {} 80ccb604e1SYi Wang 817e280b6fSYi Wang #[repr(C)] 827e280b6fSYi Wang pub struct X86_64ElfPrStatus { 837e280b6fSYi Wang pub pad1: [u8; 32], 847e280b6fSYi Wang pub pid: u32, 857e280b6fSYi Wang pub pads2: [u8; 76], 867e280b6fSYi Wang pub regs: X86_64UserRegs, 877e280b6fSYi Wang pub pad3: [u8; 8], 887e280b6fSYi Wang } 897e280b6fSYi Wang 90ccb604e1SYi Wang #[repr(C)] 91ccb604e1SYi Wang #[derive(Default, Copy, Clone)] 92ccb604e1SYi Wang pub struct CpuSegment { 93ccb604e1SYi Wang pub selector: u32, 94ccb604e1SYi Wang pub limit: u32, 95ccb604e1SYi Wang pub flags: u32, 96ccb604e1SYi Wang pub pad: u32, 97ccb604e1SYi Wang pub base: u64, 98ccb604e1SYi Wang } 99ccb604e1SYi Wang 100ccb604e1SYi Wang const DESC_TYPE_SHIFT: u32 = 8; 101ccb604e1SYi Wang const DESC_S_SHIFT: u32 = 12; 102ccb604e1SYi Wang const DESC_DPL_SHIFT: u32 = 13; 103ccb604e1SYi Wang const DESC_P_SHIFT: u32 = 15; 104ccb604e1SYi Wang const DESC_P_MASK: u32 = 1 << DESC_P_SHIFT; 105ccb604e1SYi Wang const DESC_AVL_SHIFT: u32 = 20; 106ccb604e1SYi Wang const DESC_AVL_MASK: u32 = 1 << DESC_AVL_SHIFT; 107ccb604e1SYi Wang const DESC_L_SHIFT: u32 = 21; 108ccb604e1SYi Wang const DESC_B_SHIFT: u32 = 22; 109ccb604e1SYi Wang const DESC_S_MASK: u32 = 1 << DESC_S_SHIFT; 110ccb604e1SYi Wang const DESC_G_SHIFT: u32 = 23; 111ccb604e1SYi Wang const DESC_G_MASK: u32 = 1 << DESC_G_SHIFT; 112ccb604e1SYi Wang 113ccb604e1SYi Wang impl CpuSegment { new(reg: SegmentRegister) -> Self114ccb604e1SYi Wang pub fn new(reg: SegmentRegister) -> Self { 115ccb604e1SYi Wang let p_mask = if (reg.present > 0) && (reg.unusable == 0) { 116ccb604e1SYi Wang DESC_P_MASK 117ccb604e1SYi Wang } else { 118ccb604e1SYi Wang 0 119ccb604e1SYi Wang }; 120ccb604e1SYi Wang let flags = ((reg.type_ as u32) << DESC_TYPE_SHIFT) 121ccb604e1SYi Wang | p_mask 122ccb604e1SYi Wang | ((reg.dpl as u32) << DESC_DPL_SHIFT) 123ccb604e1SYi Wang | ((reg.db as u32) << DESC_B_SHIFT) 124ccb604e1SYi Wang | ((reg.s as u32) * DESC_S_MASK) 125ccb604e1SYi Wang | ((reg.l as u32) << DESC_L_SHIFT) 126ccb604e1SYi Wang | ((reg.g as u32) * DESC_G_MASK) 127ccb604e1SYi Wang | ((reg.avl as u32) * DESC_AVL_MASK); 128ccb604e1SYi Wang 129ccb604e1SYi Wang CpuSegment { 130ccb604e1SYi Wang selector: reg.selector as u32, 131a9ec0f33SBo Chen limit: reg.limit, 132ccb604e1SYi Wang flags, 133ccb604e1SYi Wang pad: 0, 134ccb604e1SYi Wang base: reg.base, 135ccb604e1SYi Wang } 136ccb604e1SYi Wang } 137ccb604e1SYi Wang new_from_table(reg: DescriptorTable) -> Self138f1ab86feSWei Liu pub fn new_from_table(reg: DescriptorTable) -> Self { 139ccb604e1SYi Wang CpuSegment { 140ccb604e1SYi Wang selector: 0, 141ccb604e1SYi Wang limit: reg.limit as u32, 142ccb604e1SYi Wang flags: 0, 143ccb604e1SYi Wang pad: 0, 144ccb604e1SYi Wang base: reg.base, 145ccb604e1SYi Wang } 146ccb604e1SYi Wang } 147ccb604e1SYi Wang } 148ccb604e1SYi Wang 149ccb604e1SYi Wang #[repr(C)] 150ccb604e1SYi Wang #[derive(Default, Copy, Clone)] 151ccb604e1SYi Wang pub struct CpuState { 152ccb604e1SYi Wang pub version: u32, 153ccb604e1SYi Wang pub size: u32, 154ccb604e1SYi Wang /// rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp 155ccb604e1SYi Wang pub regs1: [u64; 8], 156ccb604e1SYi Wang /// r8, r9, r10, r11, r12, r13, r14, r15 157ccb604e1SYi Wang pub regs2: [u64; 8], 158ccb604e1SYi Wang pub rip: u64, 159ccb604e1SYi Wang pub rflags: u64, 160ccb604e1SYi Wang pub cs: CpuSegment, 161ccb604e1SYi Wang pub ds: CpuSegment, 162ccb604e1SYi Wang pub es: CpuSegment, 163ccb604e1SYi Wang pub fs: CpuSegment, 164ccb604e1SYi Wang pub gs: CpuSegment, 165ccb604e1SYi Wang pub ss: CpuSegment, 166ccb604e1SYi Wang pub ldt: CpuSegment, 167ccb604e1SYi Wang pub tr: CpuSegment, 168ccb604e1SYi Wang pub gdt: CpuSegment, 169ccb604e1SYi Wang pub idt: CpuSegment, 170ccb604e1SYi Wang pub cr: [u64; 5], 171ccb604e1SYi Wang pub kernel_gs_base: u64, 172ccb604e1SYi Wang } 173ccb604e1SYi Wang 174d05586f5SWei Liu // SAFETY: This is just a series of bytes 175ccb604e1SYi Wang unsafe impl ByteValued for CpuState {} 176ccb604e1SYi Wang 1777e280b6fSYi Wang pub enum NoteDescType { 17894fb9f81SRob Bradford Elf = 0, 17994fb9f81SRob Bradford Vmm = 1, 18094fb9f81SRob Bradford ElfAndVmm = 2, 1817e280b6fSYi Wang } 1827e280b6fSYi Wang 1837e280b6fSYi Wang // "CORE" or "QEMU" 1847e280b6fSYi Wang pub const COREDUMP_NAME_SIZE: u32 = 5; 185ccb604e1SYi Wang pub const NT_PRSTATUS: u32 = 1; 1867e280b6fSYi Wang 1877e280b6fSYi Wang /// Core file. 1887e280b6fSYi Wang const ET_CORE: u16 = 4; 1897e280b6fSYi Wang /// 64-bit object. 1907e280b6fSYi Wang const ELFCLASS64: u8 = 2; 1917e280b6fSYi Wang /// Current ELF version. 1927e280b6fSYi Wang const EV_CURRENT: u8 = 1; 1937e280b6fSYi Wang /// AMD x86-64 architecture 1947e280b6fSYi Wang const EM_X86_64: u16 = 62; 1957e280b6fSYi Wang 1967e280b6fSYi Wang pub trait Elf64Writable { write_header( &mut self, dump_state: &DumpState, ) -> std::result::Result<(), GuestDebuggableError>1977e280b6fSYi Wang fn write_header( 1987e280b6fSYi Wang &mut self, 1997e280b6fSYi Wang dump_state: &DumpState, 2007e280b6fSYi Wang ) -> std::result::Result<(), GuestDebuggableError> { 2017e280b6fSYi Wang let e_ident = [ 2027e280b6fSYi Wang elf::ELFMAG0 as u8, // magic 2037e280b6fSYi Wang elf::ELFMAG1, 2047e280b6fSYi Wang elf::ELFMAG2, 2057e280b6fSYi Wang elf::ELFMAG3, 2067e280b6fSYi Wang ELFCLASS64, // class 2077e280b6fSYi Wang elf::ELFDATA2LSB as u8, //data 2087e280b6fSYi Wang EV_CURRENT, // version 2097e280b6fSYi Wang 0, // os_abi 2107e280b6fSYi Wang 0, // abi_version 2117e280b6fSYi Wang 0, // padding 2127e280b6fSYi Wang 0, 2137e280b6fSYi Wang 0, 2147e280b6fSYi Wang 0, 2157e280b6fSYi Wang 0, 2167e280b6fSYi Wang 0, 2177e280b6fSYi Wang 0, 2187e280b6fSYi Wang ]; 2197e280b6fSYi Wang let elf64_ehdr_size = std::mem::size_of::<elf::Elf64_Ehdr>(); 2207e280b6fSYi Wang let elf64_phdr_size = std::mem::size_of::<elf::Elf64_Phdr>(); 2217e280b6fSYi Wang let mut elf64_ehdr = elf::Elf64_Ehdr { 2227e280b6fSYi Wang e_ident, 2237e280b6fSYi Wang e_type: ET_CORE, 2247e280b6fSYi Wang e_machine: EM_X86_64, 2257e280b6fSYi Wang e_version: EV_CURRENT as u32, 2267e280b6fSYi Wang e_entry: 0, 2277e280b6fSYi Wang e_phoff: elf64_ehdr_size as u64, 2287e280b6fSYi Wang e_shoff: 0, 2297e280b6fSYi Wang e_flags: 0, 2307e280b6fSYi Wang e_ehsize: 0, 2317e280b6fSYi Wang e_phentsize: elf64_phdr_size as u16, 2327e280b6fSYi Wang e_phnum: dump_state.elf_phdr_num, 2337e280b6fSYi Wang e_shentsize: 0, 2347e280b6fSYi Wang e_shnum: 0, 2357e280b6fSYi Wang e_shstrndx: 0, 2367e280b6fSYi Wang }; 2377e280b6fSYi Wang elf64_ehdr.e_ehsize = std::mem::size_of_val(&elf64_ehdr) as u16; 2387e280b6fSYi Wang 2397e280b6fSYi Wang let mut coredump_file = dump_state.file.as_ref().unwrap(); 2407e280b6fSYi Wang let bytes: &[u8] = elf64_ehdr.as_slice(); 2417e280b6fSYi Wang coredump_file 2427e280b6fSYi Wang .write(bytes) 24394fb9f81SRob Bradford .map_err(GuestDebuggableError::CoredumpFile)?; 2447e280b6fSYi Wang 2457e280b6fSYi Wang Ok(()) 2467e280b6fSYi Wang } 2477e280b6fSYi Wang write_note( &mut self, dump_state: &DumpState, ) -> std::result::Result<(), GuestDebuggableError>2487e280b6fSYi Wang fn write_note( 2497e280b6fSYi Wang &mut self, 2507e280b6fSYi Wang dump_state: &DumpState, 2517e280b6fSYi Wang ) -> std::result::Result<(), GuestDebuggableError> { 2527e280b6fSYi Wang let begin = dump_state.mem_offset - dump_state.elf_note_size as u64; 2537e280b6fSYi Wang let elf64_phdr = elf::Elf64_Phdr { 2547e280b6fSYi Wang p_type: elf::PT_NOTE, 2557e280b6fSYi Wang p_flags: 0, 2567e280b6fSYi Wang p_offset: begin, 2577e280b6fSYi Wang p_vaddr: 0, 2587e280b6fSYi Wang p_paddr: 0, 2597e280b6fSYi Wang p_filesz: dump_state.elf_note_size as u64, 2607e280b6fSYi Wang p_memsz: dump_state.elf_note_size as u64, 2617e280b6fSYi Wang p_align: 0, 2627e280b6fSYi Wang }; 2637e280b6fSYi Wang 2647e280b6fSYi Wang let mut coredump_file = dump_state.file.as_ref().unwrap(); 2657e280b6fSYi Wang let bytes: &[u8] = elf64_phdr.as_slice(); 2667e280b6fSYi Wang coredump_file 2677e280b6fSYi Wang .write(bytes) 26894fb9f81SRob Bradford .map_err(GuestDebuggableError::CoredumpFile)?; 2697e280b6fSYi Wang 2707e280b6fSYi Wang Ok(()) 2717e280b6fSYi Wang } 2727e280b6fSYi Wang write_load( &mut self, offset: u64, phys_addr: u64, length: u64, virt_addr: u64, dump_state: &DumpState, ) -> std::result::Result<(), GuestDebuggableError>2737e280b6fSYi Wang fn write_load( 2747e280b6fSYi Wang &mut self, 2757e280b6fSYi Wang offset: u64, 2767e280b6fSYi Wang phys_addr: u64, 2777e280b6fSYi Wang length: u64, 2787e280b6fSYi Wang virt_addr: u64, 2797e280b6fSYi Wang dump_state: &DumpState, 2807e280b6fSYi Wang ) -> std::result::Result<(), GuestDebuggableError> { 2817e280b6fSYi Wang let elf64_load = elf::Elf64_Phdr { 2827e280b6fSYi Wang p_type: elf::PT_LOAD, 2837e280b6fSYi Wang p_flags: 0, 2847e280b6fSYi Wang p_offset: offset, 2857e280b6fSYi Wang p_vaddr: virt_addr, 2867e280b6fSYi Wang p_paddr: phys_addr, 2877e280b6fSYi Wang p_filesz: length, 2887e280b6fSYi Wang p_memsz: length, 2897e280b6fSYi Wang p_align: 0, 2907e280b6fSYi Wang }; 2917e280b6fSYi Wang 2927e280b6fSYi Wang let mut coredump_file = dump_state.file.as_ref().unwrap(); 2937e280b6fSYi Wang let bytes: &[u8] = elf64_load.as_slice(); 2947e280b6fSYi Wang coredump_file 2957e280b6fSYi Wang .write(bytes) 29694fb9f81SRob Bradford .map_err(GuestDebuggableError::CoredumpFile)?; 2977e280b6fSYi Wang 2987e280b6fSYi Wang Ok(()) 2997e280b6fSYi Wang } 3007e280b6fSYi Wang write_loads( &mut self, dump_state: &DumpState, ) -> std::result::Result<(), GuestDebuggableError>3017e280b6fSYi Wang fn write_loads( 3027e280b6fSYi Wang &mut self, 3037e280b6fSYi Wang dump_state: &DumpState, 3047e280b6fSYi Wang ) -> std::result::Result<(), GuestDebuggableError> { 3057e280b6fSYi Wang let mem_info = dump_state.mem_info.as_ref().unwrap(); 3067e280b6fSYi Wang 3077e280b6fSYi Wang for (gpa, load) in &mem_info.ram_maps { 3087e280b6fSYi Wang self.write_load(load.mem_offset_in_elf, *gpa, load.mem_size, 0, dump_state)?; 3097e280b6fSYi Wang } 3107e280b6fSYi Wang 3117e280b6fSYi Wang Ok(()) 3127e280b6fSYi Wang } 3137e280b6fSYi Wang elf_note_size(&self, hdr_size: u32, name_size: u32, desc_size: u32) -> u323147e280b6fSYi Wang fn elf_note_size(&self, hdr_size: u32, name_size: u32, desc_size: u32) -> u32 { 3156164aa08SRuoqing He (hdr_size.div_ceil(4) + name_size.div_ceil(4) + desc_size.div_ceil(4)) * 4 3167e280b6fSYi Wang } 3177e280b6fSYi Wang get_note_size(&self, desc_type: NoteDescType, nr_cpus: u32) -> u323187e280b6fSYi Wang fn get_note_size(&self, desc_type: NoteDescType, nr_cpus: u32) -> u32 { 3197e280b6fSYi Wang let note_head_size = std::mem::size_of::<elf::Elf64_Nhdr>() as u32; 3207e280b6fSYi Wang let elf_desc_size = std::mem::size_of::<X86_64ElfPrStatus>() as u32; 321ccb604e1SYi Wang let cpu_state_desc_size = std::mem::size_of::<CpuState>() as u32; 3227e280b6fSYi Wang 3237e280b6fSYi Wang let elf_note_size = self.elf_note_size(note_head_size, COREDUMP_NAME_SIZE, elf_desc_size); 324ccb604e1SYi Wang let vmm_note_size = 325ccb604e1SYi Wang self.elf_note_size(note_head_size, COREDUMP_NAME_SIZE, cpu_state_desc_size); 3267e280b6fSYi Wang 3277e280b6fSYi Wang match desc_type { 32894fb9f81SRob Bradford NoteDescType::Elf => elf_note_size * nr_cpus, 32994fb9f81SRob Bradford NoteDescType::Vmm => vmm_note_size * nr_cpus, 33094fb9f81SRob Bradford NoteDescType::ElfAndVmm => (elf_note_size + vmm_note_size) * nr_cpus, 3317e280b6fSYi Wang } 3327e280b6fSYi Wang } 3337e280b6fSYi Wang } 334ccb604e1SYi Wang 335ccb604e1SYi Wang pub trait CpuElf64Writable { cpu_write_elf64_note( &mut self, _dump_state: &DumpState, ) -> std::result::Result<(), GuestDebuggableError>336ccb604e1SYi Wang fn cpu_write_elf64_note( 337ccb604e1SYi Wang &mut self, 338ccb604e1SYi Wang _dump_state: &DumpState, 339ccb604e1SYi Wang ) -> std::result::Result<(), GuestDebuggableError> { 340ccb604e1SYi Wang Ok(()) 341ccb604e1SYi Wang } 342ccb604e1SYi Wang cpu_write_vmm_note( &mut self, _dump_state: &DumpState, ) -> std::result::Result<(), GuestDebuggableError>343ccb604e1SYi Wang fn cpu_write_vmm_note( 344ccb604e1SYi Wang &mut self, 345ccb604e1SYi Wang _dump_state: &DumpState, 346ccb604e1SYi Wang ) -> std::result::Result<(), GuestDebuggableError> { 347ccb604e1SYi Wang Ok(()) 348ccb604e1SYi Wang } 349ccb604e1SYi Wang } 350