Skip to content

Commit da5428b

Browse files
authored
Merge pull request #246 from rust-osdev/dev
multiboot2: bug fixes
2 parents 6b15cfb + 4c6f7f9 commit da5428b

File tree

9 files changed

+92
-46
lines changed

9 files changed

+92
-46
lines changed

integration-test/bins/multiboot2_payload/src/verify/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ pub(self) fn print_memory_map(mbi: &BootInformation) -> anyhow::Result<()> {
4848

4949
pub(self) fn print_elf_info(mbi: &BootInformation) -> anyhow::Result<()> {
5050
let sections_iter = mbi
51-
.elf_sections()
51+
.elf_sections_tag()
5252
.ok_or("Should have elf sections")
53+
.map(|tag| tag.sections())
5354
.map_err(anyhow::Error::msg)?;
5455
println!("ELF sections:");
5556
for s in sections_iter {

multiboot2/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
## Unreleased
44

5+
## v0.23.1 (2024-10-21)
6+
7+
- Fix wrong tag ID when using `BootdevTag::new`
8+
- `BootInformation::elf_sections` is now deprecated and replaced by the newly
9+
- added `BootInformation::elf_sections_tag`. On the returned type, you can call
10+
`.sections()` to iterate the sections
11+
- Fixed the debug output of `BootInformation`
12+
513
## v0.23.0 (2024-09-17)
614

715
- dependency updates

multiboot2/src/apm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl ApmTag {
3636
dseg_len: u16,
3737
) -> Self {
3838
Self {
39-
header: TagHeader::new(TagType::Apm, mem::size_of::<Self>() as u32),
39+
header: TagHeader::new(Self::ID, mem::size_of::<Self>() as u32),
4040
version,
4141
cseg,
4242
offset,

multiboot2/src/boot_information.rs

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ impl<'a> BootInformation<'a> {
254254
/// # use multiboot2::{BootInformation, BootInformationHeader};
255255
/// # let ptr = 0xdeadbeef as *const BootInformationHeader;
256256
/// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() };
257-
/// if let Some(sections) = boot_info.elf_sections() {
257+
/// if let Some(sections) = boot_info.elf_sections_tag().map(|tag| tag.sections()) {
258258
/// let mut total = 0;
259259
/// for section in sections {
260260
/// println!("Section: {:?}", section);
@@ -263,14 +263,21 @@ impl<'a> BootInformation<'a> {
263263
/// }
264264
/// ```
265265
#[must_use]
266+
#[deprecated = "Use elf_sections_tag() instead and corresponding getters"]
266267
pub fn elf_sections(&self) -> Option<ElfSectionIter> {
267268
let tag = self.get_tag::<ElfSectionsTag>();
268269
tag.map(|t| {
269270
assert!((t.entry_size() * t.shndx()) <= t.header().size);
270-
t.sections_iter()
271+
t.sections()
271272
})
272273
}
273274

275+
/// Search for the [`ElfSectionsTag`].
276+
#[must_use]
277+
pub fn elf_sections_tag(&self) -> Option<&ElfSectionsTag> {
278+
self.get_tag()
279+
}
280+
274281
/// Search for the [`FramebufferTag`]. The result is `Some(Err(e))`, if the
275282
/// framebuffer type is unknown, while the framebuffer tag is present.
276283
#[must_use]
@@ -421,50 +428,42 @@ impl<'a> BootInformation<'a> {
421428

422429
impl fmt::Debug for BootInformation<'_> {
423430
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
424-
/// Limit how many Elf-Sections should be debug-formatted.
425-
/// Can be thousands of sections for a Rust binary => this is useless output.
426-
/// If the user really wants this, they should debug-format the field directly.
427-
const ELF_SECTIONS_LIMIT: usize = 7;
428-
429431
let mut debug = f.debug_struct("Multiboot2BootInformation");
430432
debug
431433
.field("start_address", &self.start_address())
432434
.field("end_address", &self.end_address())
433435
.field("total_size", &self.total_size())
434436
// now tags in alphabetical order
437+
.field("apm", &self.apm_tag())
435438
.field("basic_memory_info", &(self.basic_memory_info_tag()))
436439
.field("boot_loader_name", &self.boot_loader_name_tag())
437-
// .field("bootdev", &self.bootdev_tag())
440+
.field("bootdev", &self.bootdev_tag())
438441
.field("command_line", &self.command_line_tag())
439442
.field("efi_bs_not_exited", &self.efi_bs_not_exited_tag())
443+
.field("efi_ih32", &self.efi_ih32_tag())
444+
.field("efi_ih64", &self.efi_ih64_tag())
440445
.field("efi_memory_map", &self.efi_memory_map_tag())
441446
.field("efi_sdt32", &self.efi_sdt32_tag())
442447
.field("efi_sdt64", &self.efi_sdt64_tag())
443-
.field("efi_ih32", &self.efi_ih32_tag())
444-
.field("efi_ih64", &self.efi_ih64_tag());
445-
446-
// usually this is REALLY big (thousands of tags) => skip it here
447-
{
448-
let elf_sections_tag_entries_count =
449-
self.elf_sections().map(|x| x.count()).unwrap_or(0);
450-
451-
if elf_sections_tag_entries_count > ELF_SECTIONS_LIMIT {
452-
debug.field("elf_sections (count)", &elf_sections_tag_entries_count);
453-
} else {
454-
debug.field("elf_sections", &self.elf_sections());
455-
}
456-
}
457-
458-
debug
448+
.field("elf_sections", &self.elf_sections_tag())
459449
.field("framebuffer", &self.framebuffer_tag())
460450
.field("load_base_addr", &self.load_base_addr_tag())
461451
.field("memory_map", &self.memory_map_tag())
462452
.field("modules", &self.module_tags())
463-
// .field("network", &self.network_tag())
453+
.field("network", &self.network_tag())
464454
.field("rsdp_v1", &self.rsdp_v1_tag())
465455
.field("rsdp_v2", &self.rsdp_v2_tag())
466-
.field("smbios_tag", &self.smbios_tag())
467-
.field("vbe_info_tag", &self.vbe_info_tag())
456+
.field("smbios", &self.smbios_tag())
457+
.field("vbe_info", &self.vbe_info_tag())
458+
// computed fields
459+
.field("custom_tags_count", &{
460+
self.tags()
461+
.filter(|tag| {
462+
let id: TagType = tag.header().typ.into();
463+
matches!(id, TagType::Custom(_))
464+
})
465+
.count()
466+
})
468467
.finish()
469468
}
470469
}

multiboot2/src/bootdev.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl BootdevTag {
1919
#[must_use]
2020
pub fn new(biosdev: u32, slice: u32, part: u32) -> Self {
2121
Self {
22-
header: TagHeader::new(TagType::Apm, mem::size_of::<Self>() as u32),
22+
header: TagHeader::new(Self::ID, mem::size_of::<Self>() as u32),
2323
biosdev,
2424
slice,
2525
part,

multiboot2/src/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,5 +378,6 @@ mod tests {
378378
// Mainly a test for Miri.
379379
dbg!(tag.header(), tag.payload().len());
380380
}
381+
eprintln!("{info:#x?}")
381382
}
382383
}

multiboot2/src/elf_sections.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ impl ElfSectionsTag {
3737
)
3838
}
3939

40-
/// Get an iterator of loaded ELF sections.
40+
/// Get an iterator over the ELF sections.
4141
#[must_use]
42-
pub(crate) const fn sections_iter(&self) -> ElfSectionIter {
42+
pub const fn sections(&self) -> ElfSectionIter {
4343
let string_section_offset = (self.shndx * self.entry_size) as isize;
4444
let string_section_ptr =
4545
unsafe { self.sections.as_ptr().offset(string_section_offset) as *const _ };
@@ -96,12 +96,12 @@ impl Debug for ElfSectionsTag {
9696
.field("number_of_sections", &self.number_of_sections)
9797
.field("entry_size", &self.entry_size)
9898
.field("shndx", &self.shndx)
99-
.field("sections", &self.sections_iter())
99+
.field("sections", &self.sections())
100100
.finish()
101101
}
102102
}
103103

104-
/// An iterator over some ELF sections.
104+
/// An iterator over [`ElfSection`]s.
105105
#[derive(Clone)]
106106
pub struct ElfSectionIter<'a> {
107107
current_section: *const u8,
@@ -132,27 +132,62 @@ impl<'a> Iterator for ElfSectionIter<'a> {
132132
}
133133
None
134134
}
135+
136+
fn size_hint(&self) -> (usize, Option<usize>) {
137+
(
138+
self.remaining_sections as usize,
139+
Some(self.remaining_sections as usize),
140+
)
141+
}
142+
}
143+
144+
impl ExactSizeIterator for ElfSectionIter<'_> {
145+
fn len(&self) -> usize {
146+
self.remaining_sections as usize
147+
}
135148
}
136149

137150
impl Debug for ElfSectionIter<'_> {
138151
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
152+
/// Limit how many Elf-Sections should be debug-formatted.
153+
/// Can be thousands of sections for a Rust binary => this is useless output.
154+
/// If the user really wants this, they should debug-format the field directly.
155+
const ELF_SECTIONS_LIMIT: usize = 7;
156+
139157
let mut debug = f.debug_list();
140-
self.clone().for_each(|ref e| {
158+
159+
self.clone().take(ELF_SECTIONS_LIMIT).for_each(|ref e| {
141160
debug.entry(e);
142161
});
162+
163+
if self.clone().len() > ELF_SECTIONS_LIMIT {
164+
debug.entry(&"...");
165+
}
166+
143167
debug.finish()
144168
}
145169
}
146170

147171
/// A single generic ELF Section.
148-
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
172+
// TODO Shouldn't this be called ElfSectionPtrs, ElfSectionWrapper or so?
173+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
149174
pub struct ElfSection<'a> {
150175
inner: *const u8,
151176
string_section: *const u8,
152177
entry_size: u32,
153178
_phantom: PhantomData<&'a ()>,
154179
}
155180

181+
impl Debug for ElfSection<'_> {
182+
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
183+
let inner = self.get();
184+
f.debug_struct("ElfSection")
185+
.field("inner", &inner)
186+
.field("string_section_ptr", &self.string_section)
187+
.finish()
188+
}
189+
}
190+
156191
#[derive(Clone, Copy, Debug)]
157192
#[repr(C, packed)]
158193
struct ElfSectionInner32 {
@@ -297,7 +332,7 @@ impl ElfSection<'_> {
297332
}
298333
}
299334

300-
trait ElfSectionInner {
335+
trait ElfSectionInner: Debug {
301336
fn name_index(&self) -> u32;
302337

303338
fn typ(&self) -> u32;

multiboot2/src/end.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub struct EndTag {
1414
impl Default for EndTag {
1515
fn default() -> Self {
1616
Self {
17-
header: TagHeader::new(TagType::End, mem::size_of::<Self>() as u32),
17+
header: TagHeader::new(Self::ID, mem::size_of::<Self>() as u32),
1818
}
1919
}
2020
}

multiboot2/src/lib.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ mod tests {
168168
assert_eq!(addr, bi.start_address());
169169
assert_eq!(addr + bytes.0.len(), bi.end_address());
170170
assert_eq!(bytes.0.len(), bi.total_size());
171-
assert!(bi.elf_sections().is_none());
171+
assert!(bi.elf_sections_tag().is_none());
172172
assert!(bi.memory_map_tag().is_none());
173173
assert!(bi.module_tags().next().is_none());
174174
assert!(bi.boot_loader_name_tag().is_none());
@@ -191,7 +191,7 @@ mod tests {
191191
assert_eq!(addr, bi.start_address());
192192
assert_eq!(addr + bytes.0.len(), bi.end_address());
193193
assert_eq!(bytes.0.len(), bi.total_size());
194-
assert!(bi.elf_sections().is_none());
194+
assert!(bi.elf_sections_tag().is_none());
195195
assert!(bi.memory_map_tag().is_none());
196196
assert!(bi.module_tags().next().is_none());
197197
assert!(bi.boot_loader_name_tag().is_none());
@@ -214,7 +214,7 @@ mod tests {
214214
assert_eq!(addr, bi.start_address());
215215
assert_eq!(addr + bytes.0.len(), bi.end_address());
216216
assert_eq!(bytes.0.len(), bi.total_size());
217-
assert!(bi.elf_sections().is_none());
217+
assert!(bi.elf_sections_tag().is_none());
218218
assert!(bi.memory_map_tag().is_none());
219219
assert!(bi.module_tags().next().is_none());
220220
assert!(bi.boot_loader_name_tag().is_none());
@@ -240,7 +240,7 @@ mod tests {
240240
assert_eq!(addr, bi.start_address());
241241
assert_eq!(addr + bytes.0.len(), bi.end_address());
242242
assert_eq!(bytes.0.len(), bi.total_size());
243-
assert!(bi.elf_sections().is_none());
243+
assert!(bi.elf_sections_tag().is_none());
244244
assert!(bi.memory_map_tag().is_none());
245245
assert!(bi.module_tags().next().is_none());
246246
assert_eq!(
@@ -834,7 +834,7 @@ mod tests {
834834
assert_eq!(addr, bi.start_address());
835835
assert_eq!(addr + bytes.len(), bi.end_address());
836836
assert_eq!(bytes.len(), bi.total_size());
837-
let mut es = bi.elf_sections().unwrap();
837+
let mut es = bi.elf_sections_tag().unwrap().sections();
838838
let s1 = es.next().expect("Should have one more section");
839839
assert_eq!(".rodata", s1.name().expect("Should be valid utf-8"));
840840
assert_eq!(0xFFFF_8000_0010_0000, s1.start_address());
@@ -1007,8 +1007,7 @@ mod tests {
10071007
]);
10081008
#[repr(C, align(8))]
10091009
struct StringBytes([u8; 11]);
1010-
let string_bytes: StringBytes =
1011-
StringBytes([0, 46, 115, 104, 115, 116, 114, 116, 97, 98, 0]);
1010+
let string_bytes: StringBytes = StringBytes(*b"\0.shstrtab\0");
10121011
let string_addr = string_bytes.0.as_ptr() as u64;
10131012
for i in 0..8 {
10141013
let offset = 108;
@@ -1019,10 +1018,13 @@ mod tests {
10191018
let addr = ptr as usize;
10201019
let bi = unsafe { BootInformation::load(ptr.cast()) };
10211020
let bi = bi.unwrap();
1021+
1022+
eprintln!("boot information with elf sections: {bi:#x?}");
1023+
10221024
assert_eq!(addr, bi.start_address());
10231025
assert_eq!(addr + bytes.0.len(), bi.end_address());
10241026
assert_eq!(bytes.0.len(), bi.total_size());
1025-
let mut es = bi.elf_sections().unwrap();
1027+
let mut es = bi.elf_sections_tag().unwrap().sections();
10261028
let s1 = es.next().expect("Should have one more section");
10271029
assert_eq!(".shstrtab", s1.name().expect("Should be valid utf-8"));
10281030
assert_eq!(string_addr, s1.start_address());

0 commit comments

Comments
 (0)