mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-03-20 07:58:55 +00:00
vmm: save elf header for coredump
The vmcore file of guest is an elf format, so the first step of coredump is to save the elf header. Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
This commit is contained in:
parent
90034fd6ba
commit
7e280b6f70
@ -3,7 +3,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use linux_loader::elf;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use vm_memory::ByteValued;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CoredumpMemoryRegion {
|
||||
@ -41,3 +44,190 @@ pub trait GuestDebuggable: vm_migration::Pausable {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! div_round_up {
|
||||
($n:expr,$d:expr) => {
|
||||
($n + $d - 1) / $d
|
||||
};
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Copy, Clone)]
|
||||
pub struct X86_64UserRegs {
|
||||
/// r15, r14, r13, r12, rbp, rbx, r11, r10;
|
||||
pub regs1: [u64; 8],
|
||||
/// r9, r8, rax, rcx, rdx, rsi, rdi, orig_rax;
|
||||
pub regs2: [u64; 8],
|
||||
pub rip: u64,
|
||||
pub cs: u64,
|
||||
pub eflags: u64,
|
||||
pub rsp: u64,
|
||||
pub ss: u64,
|
||||
pub fs_base: u64,
|
||||
pub gs_base: u64,
|
||||
pub ds: u64,
|
||||
pub es: u64,
|
||||
pub fs: u64,
|
||||
pub gs: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[allow(dead_code)]
|
||||
pub struct X86_64ElfPrStatus {
|
||||
pub pad1: [u8; 32],
|
||||
pub pid: u32,
|
||||
pub pads2: [u8; 76],
|
||||
pub regs: X86_64UserRegs,
|
||||
pub pad3: [u8; 8],
|
||||
}
|
||||
|
||||
pub enum NoteDescType {
|
||||
ElfDesc = 0,
|
||||
}
|
||||
|
||||
// "CORE" or "QEMU"
|
||||
pub const COREDUMP_NAME_SIZE: u32 = 5;
|
||||
|
||||
/// Core file.
|
||||
const ET_CORE: u16 = 4;
|
||||
/// 64-bit object.
|
||||
const ELFCLASS64: u8 = 2;
|
||||
/// Current ELF version.
|
||||
const EV_CURRENT: u8 = 1;
|
||||
/// AMD x86-64 architecture
|
||||
const EM_X86_64: u16 = 62;
|
||||
|
||||
pub trait Elf64Writable {
|
||||
fn write_header(
|
||||
&mut self,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
let e_ident = [
|
||||
elf::ELFMAG0 as u8, // magic
|
||||
elf::ELFMAG1,
|
||||
elf::ELFMAG2,
|
||||
elf::ELFMAG3,
|
||||
ELFCLASS64, // class
|
||||
elf::ELFDATA2LSB as u8, //data
|
||||
EV_CURRENT, // version
|
||||
0, // os_abi
|
||||
0, // abi_version
|
||||
0, // padding
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
let elf64_ehdr_size = std::mem::size_of::<elf::Elf64_Ehdr>();
|
||||
let elf64_phdr_size = std::mem::size_of::<elf::Elf64_Phdr>();
|
||||
let mut elf64_ehdr = elf::Elf64_Ehdr {
|
||||
e_ident,
|
||||
e_type: ET_CORE,
|
||||
e_machine: EM_X86_64,
|
||||
e_version: EV_CURRENT as u32,
|
||||
e_entry: 0,
|
||||
e_phoff: elf64_ehdr_size as u64,
|
||||
e_shoff: 0,
|
||||
e_flags: 0,
|
||||
e_ehsize: 0,
|
||||
e_phentsize: elf64_phdr_size as u16,
|
||||
e_phnum: dump_state.elf_phdr_num,
|
||||
e_shentsize: 0,
|
||||
e_shnum: 0,
|
||||
e_shstrndx: 0,
|
||||
};
|
||||
elf64_ehdr.e_ehsize = std::mem::size_of_val(&elf64_ehdr) as u16;
|
||||
|
||||
let mut coredump_file = dump_state.file.as_ref().unwrap();
|
||||
let bytes: &[u8] = elf64_ehdr.as_slice();
|
||||
coredump_file
|
||||
.write(bytes)
|
||||
.map_err(|e| GuestDebuggableError::CoredumpFile(e.into()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_note(
|
||||
&mut self,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
let begin = dump_state.mem_offset - dump_state.elf_note_size as u64;
|
||||
let elf64_phdr = elf::Elf64_Phdr {
|
||||
p_type: elf::PT_NOTE,
|
||||
p_flags: 0,
|
||||
p_offset: begin,
|
||||
p_vaddr: 0,
|
||||
p_paddr: 0,
|
||||
p_filesz: dump_state.elf_note_size as u64,
|
||||
p_memsz: dump_state.elf_note_size as u64,
|
||||
p_align: 0,
|
||||
};
|
||||
|
||||
let mut coredump_file = dump_state.file.as_ref().unwrap();
|
||||
let bytes: &[u8] = elf64_phdr.as_slice();
|
||||
coredump_file
|
||||
.write(bytes)
|
||||
.map_err(|e| GuestDebuggableError::CoredumpFile(e.into()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_load(
|
||||
&mut self,
|
||||
offset: u64,
|
||||
phys_addr: u64,
|
||||
length: u64,
|
||||
virt_addr: u64,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
let elf64_load = elf::Elf64_Phdr {
|
||||
p_type: elf::PT_LOAD,
|
||||
p_flags: 0,
|
||||
p_offset: offset,
|
||||
p_vaddr: virt_addr,
|
||||
p_paddr: phys_addr,
|
||||
p_filesz: length,
|
||||
p_memsz: length,
|
||||
p_align: 0,
|
||||
};
|
||||
|
||||
let mut coredump_file = dump_state.file.as_ref().unwrap();
|
||||
let bytes: &[u8] = elf64_load.as_slice();
|
||||
coredump_file
|
||||
.write(bytes)
|
||||
.map_err(|e| GuestDebuggableError::CoredumpFile(e.into()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_loads(
|
||||
&mut self,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
let mem_info = dump_state.mem_info.as_ref().unwrap();
|
||||
|
||||
for (gpa, load) in &mem_info.ram_maps {
|
||||
self.write_load(load.mem_offset_in_elf, *gpa, load.mem_size, 0, dump_state)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn elf_note_size(&self, hdr_size: u32, name_size: u32, desc_size: u32) -> u32 {
|
||||
(div_round_up!(hdr_size, 4) + div_round_up!(name_size, 4) + div_round_up!(desc_size, 4)) * 4
|
||||
}
|
||||
|
||||
fn get_note_size(&self, desc_type: NoteDescType, nr_cpus: u32) -> u32 {
|
||||
let note_head_size = std::mem::size_of::<elf::Elf64_Nhdr>() as u32;
|
||||
let elf_desc_size = std::mem::size_of::<X86_64ElfPrStatus>() as u32;
|
||||
|
||||
let elf_note_size = self.elf_note_size(note_head_size, COREDUMP_NAME_SIZE, elf_desc_size);
|
||||
|
||||
match desc_type {
|
||||
NoteDescType::ElfDesc => elf_note_size * nr_cpus,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ use crate::config::{
|
||||
#[cfg(feature = "guest_debug")]
|
||||
use crate::coredump::DumpState;
|
||||
#[cfg(feature = "guest_debug")]
|
||||
use crate::coredump::{Elf64Writable, NoteDescType};
|
||||
#[cfg(feature = "guest_debug")]
|
||||
use crate::coredump::{GuestDebuggable, GuestDebuggableError};
|
||||
use crate::cpu;
|
||||
use crate::device_manager::{Console, DeviceManager, DeviceManagerError, PtyPair};
|
||||
@ -3020,6 +3022,9 @@ impl Debuggable for Vm {
|
||||
#[cfg(feature = "guest_debug")]
|
||||
pub const UINT16_MAX: u32 = 65535;
|
||||
|
||||
#[cfg(feature = "guest_debug")]
|
||||
impl Elf64Writable for Vm {}
|
||||
|
||||
#[cfg(feature = "guest_debug")]
|
||||
impl GuestDebuggable for Vm {
|
||||
fn coredump(&mut self, destination_url: &str) -> std::result::Result<(), GuestDebuggableError> {
|
||||
@ -3043,6 +3048,10 @@ impl GuestDebuggable for Vm {
|
||||
|
||||
let coredump_state = self.get_dump_state(destination_url)?;
|
||||
|
||||
self.write_header(&coredump_state)?;
|
||||
self.write_note(&coredump_state)?;
|
||||
self.write_loads(&coredump_state)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user