Skip to content

Commit

Permalink
multiboot2: improve debug output of BootInformation and ElfSections
Browse files Browse the repository at this point in the history
  • Loading branch information
phip1611 committed Oct 21, 2024
1 parent a537d24 commit e0bc758
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 30 deletions.
1 change: 1 addition & 0 deletions multiboot2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
42 changes: 17 additions & 25 deletions multiboot2/src/boot_information.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
1 change: 1 addition & 0 deletions multiboot2/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,5 +378,6 @@ mod tests {
// Mainly a test for Miri.
dbg!(tag.header(), tag.payload().len());
}
eprintln!("{info:#x?}")
}
}
28 changes: 25 additions & 3 deletions multiboot2/src/elf_sections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,23 +136,45 @@ 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,
entry_size: u32,
_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 {
Expand Down Expand Up @@ -297,7 +319,7 @@ impl ElfSection<'_> {
}
}

trait ElfSectionInner {
trait ElfSectionInner: Debug {
fn name_index(&self) -> u32;

fn typ(&self) -> u32;
Expand Down
6 changes: 4 additions & 2 deletions multiboot2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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());
Expand Down

0 comments on commit e0bc758

Please sign in to comment.