Skip to main content

elf2flash_core/
address_range.rs

1use elf::{ElfBytes, abi::PT_LOAD, endian::EndianParse};
2use thiserror::Error;
3
4#[derive(Copy, Clone, Debug, Eq, PartialEq)]
5pub enum AddressRangeType {
6    /// May have contents
7    Contents,
8    /// Must be uninitialized
9    NoContents,
10    /// will be ignored
11    Ignore,
12}
13
14#[derive(Copy, Clone, Debug)]
15pub struct AddressRange {
16    pub typ: AddressRangeType,
17    pub to: u64,
18    pub from: u64,
19}
20
21impl AddressRange {
22    pub const fn new(from: u64, to: u64, typ: AddressRangeType) -> Self {
23        Self { typ, to, from }
24    }
25}
26
27impl Default for AddressRange {
28    fn default() -> Self {
29        Self {
30            typ: AddressRangeType::Ignore,
31            to: 0,
32            from: 0,
33        }
34    }
35}
36
37#[derive(Error, Debug)]
38pub enum AddressRangesFromElfError {
39    #[error("No segments in ELF")]
40    NoSegments,
41    #[error("ELF contains memory contents for uninitialized memory at {0:08x}")]
42    MemoryContentsForUninitializedMemory(u64),
43    #[error("Memory segment {0:#08x}->{1:#08x} is outside of valid address range for device")]
44    MemorySegmentInvalidForDevice(u64, u64),
45}
46
47pub fn address_ranges_from_elf<E: EndianParse>(
48    file: &ElfBytes<'_, E>,
49) -> Result<Vec<AddressRange>, AddressRangesFromElfError> {
50    let segments = file
51        .segments()
52        .ok_or(AddressRangesFromElfError::NoSegments)?;
53
54    let mut ranges = Vec::new();
55
56    for seg in segments {
57        if seg.p_type != PT_LOAD || seg.p_memsz == 0 {
58            continue;
59        }
60
61        let start = seg.p_paddr;
62        let end = start + seg.p_memsz;
63
64        if seg.p_filesz > 0 {
65            // initialized contents
66            ranges.push(AddressRange::new(
67                start,
68                start + seg.p_filesz,
69                AddressRangeType::Contents,
70            ));
71        }
72
73        if seg.p_memsz > seg.p_filesz {
74            // uninitialized (BSS)
75            ranges.push(AddressRange::new(
76                start + seg.p_filesz,
77                end,
78                AddressRangeType::NoContents,
79            ));
80        }
81    }
82
83    Ok(ranges)
84}