From e0bc758cfc20b4ba639e6a28c39d6eefa5a83520 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 21 Oct 2024 15:34:25 +0200 Subject: [PATCH] multiboot2: improve debug output of BootInformation and ElfSections --- multiboot2/CHANGELOG.md | 1 + multiboot2/src/boot_information.rs | 42 ++++++++++++------------------ multiboot2/src/builder.rs | 1 + multiboot2/src/elf_sections.rs | 28 +++++++++++++++++--- multiboot2/src/lib.rs | 6 +++-- 5 files changed, 48 insertions(+), 30 deletions(-) diff --git a/multiboot2/CHANGELOG.md b/multiboot2/CHANGELOG.md index c3628d66..c061208e 100644 --- a/multiboot2/CHANGELOG.md +++ b/multiboot2/CHANGELOG.md @@ -8,6 +8,7 @@ - `BootInformation::elf_sections` is now deprecated and replaced by the newly - added `BootInformation::elf_sections_tag`. On the returned type, you can call `.sections()` to iterate the sections +- Fixed the debug output of `BootInformation` ## v0.23.0 (2024-09-17) diff --git a/multiboot2/src/boot_information.rs b/multiboot2/src/boot_information.rs index 256a3ae0..1204e1f6 100644 --- a/multiboot2/src/boot_information.rs +++ b/multiboot2/src/boot_information.rs @@ -428,50 +428,42 @@ impl<'a> BootInformation<'a> { impl fmt::Debug for BootInformation<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - /// Limit how many Elf-Sections should be debug-formatted. - /// Can be thousands of sections for a Rust binary => this is useless output. - /// If the user really wants this, they should debug-format the field directly. - const ELF_SECTIONS_LIMIT: usize = 7; - let mut debug = f.debug_struct("Multiboot2BootInformation"); debug .field("start_address", &self.start_address()) .field("end_address", &self.end_address()) .field("total_size", &self.total_size()) // now tags in alphabetical order + .field("apm", &self.apm_tag()) .field("basic_memory_info", &(self.basic_memory_info_tag())) .field("boot_loader_name", &self.boot_loader_name_tag()) - // .field("bootdev", &self.bootdev_tag()) + .field("bootdev", &self.bootdev_tag()) .field("command_line", &self.command_line_tag()) .field("efi_bs_not_exited", &self.efi_bs_not_exited_tag()) + .field("efi_ih32", &self.efi_ih32_tag()) + .field("efi_ih64", &self.efi_ih64_tag()) .field("efi_memory_map", &self.efi_memory_map_tag()) .field("efi_sdt32", &self.efi_sdt32_tag()) .field("efi_sdt64", &self.efi_sdt64_tag()) - .field("efi_ih32", &self.efi_ih32_tag()) - .field("efi_ih64", &self.efi_ih64_tag()); - - // usually this is REALLY big (thousands of tags) => skip it here - { - let elf_sections_tag_entries_count = - self.elf_sections().map(|x| x.count()).unwrap_or(0); - - if elf_sections_tag_entries_count > ELF_SECTIONS_LIMIT { - debug.field("elf_sections (count)", &elf_sections_tag_entries_count); - } else { - debug.field("elf_sections", &self.elf_sections()); - } - } - - debug + .field("elf_sections", &self.elf_sections_tag()) .field("framebuffer", &self.framebuffer_tag()) .field("load_base_addr", &self.load_base_addr_tag()) .field("memory_map", &self.memory_map_tag()) .field("modules", &self.module_tags()) - // .field("network", &self.network_tag()) + .field("network", &self.network_tag()) .field("rsdp_v1", &self.rsdp_v1_tag()) .field("rsdp_v2", &self.rsdp_v2_tag()) - .field("smbios_tag", &self.smbios_tag()) - .field("vbe_info_tag", &self.vbe_info_tag()) + .field("smbios", &self.smbios_tag()) + .field("vbe_info", &self.vbe_info_tag()) + // computed fields + .field("custom_tags_count", &{ + self.tags() + .filter(|tag| { + let id: TagType = tag.header().typ.into(); + matches!(id, TagType::Custom(_)) + }) + .count() + }) .finish() } } diff --git a/multiboot2/src/builder.rs b/multiboot2/src/builder.rs index 0ddab5de..872fe08c 100644 --- a/multiboot2/src/builder.rs +++ b/multiboot2/src/builder.rs @@ -378,5 +378,6 @@ mod tests { // Mainly a test for Miri. dbg!(tag.header(), tag.payload().len()); } + eprintln!("{info:#x?}") } } diff --git a/multiboot2/src/elf_sections.rs b/multiboot2/src/elf_sections.rs index bc7597dc..e4daed7b 100644 --- a/multiboot2/src/elf_sections.rs +++ b/multiboot2/src/elf_sections.rs @@ -136,16 +136,28 @@ impl<'a> Iterator for ElfSectionIter<'a> { impl Debug for ElfSectionIter<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + /// Limit how many Elf-Sections should be debug-formatted. + /// Can be thousands of sections for a Rust binary => this is useless output. + /// If the user really wants this, they should debug-format the field directly. + const ELF_SECTIONS_LIMIT: usize = 7; + let mut debug = f.debug_list(); - self.clone().for_each(|ref e| { + + self.clone().take(ELF_SECTIONS_LIMIT).for_each(|ref e| { debug.entry(e); }); + + if self.clone().len() > ELF_SECTIONS_LIMIT { + debug.entry(&"..."); + } + debug.finish() } } /// A single generic ELF Section. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +// TODO Shouldn't this be called ElfSectionPtrs, ElfSectionWrapper or so? +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ElfSection<'a> { inner: *const u8, string_section: *const u8, @@ -153,6 +165,16 @@ pub struct ElfSection<'a> { _phantom: PhantomData<&'a ()>, } +impl Debug for ElfSection<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let inner = self.get(); + f.debug_struct("ElfSection") + .field("inner", &inner) + .field("string_section_ptr", &self.string_section) + .finish() + } +} + #[derive(Clone, Copy, Debug)] #[repr(C, packed)] struct ElfSectionInner32 { @@ -297,7 +319,7 @@ impl ElfSection<'_> { } } -trait ElfSectionInner { +trait ElfSectionInner: Debug { fn name_index(&self) -> u32; fn typ(&self) -> u32; diff --git a/multiboot2/src/lib.rs b/multiboot2/src/lib.rs index 42a6ff33..3ca45741 100644 --- a/multiboot2/src/lib.rs +++ b/multiboot2/src/lib.rs @@ -1007,8 +1007,7 @@ mod tests { ]); #[repr(C, align(8))] struct StringBytes([u8; 11]); - let string_bytes: StringBytes = - StringBytes([0, 46, 115, 104, 115, 116, 114, 116, 97, 98, 0]); + let string_bytes: StringBytes = StringBytes(*b"\0.shstrtab\0"); let string_addr = string_bytes.0.as_ptr() as u64; for i in 0..8 { let offset = 108; @@ -1019,6 +1018,9 @@ mod tests { let addr = ptr as usize; let bi = unsafe { BootInformation::load(ptr.cast()) }; let bi = bi.unwrap(); + + eprintln!("boot information with elf sections: {bi:#x?}"); + assert_eq!(addr, bi.start_address()); assert_eq!(addr + bytes.0.len(), bi.end_address()); assert_eq!(bytes.0.len(), bi.total_size());