Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/object-0.28.4/src/read/elf/note.rs
Line
Count
Source (jump to first uncovered line)
1
use core::fmt::Debug;
2
use core::mem;
3
4
use crate::elf;
5
use crate::endian;
6
use crate::pod::Pod;
7
use crate::read::util;
8
use crate::read::{self, Bytes, Error, ReadError};
9
10
use super::FileHeader;
11
12
/// An iterator over the notes in an ELF section or segment.
13
#[derive(Debug)]
14
pub struct NoteIterator<'data, Elf>
15
where
16
    Elf: FileHeader,
17
{
18
    endian: Elf::Endian,
19
    align: usize,
20
    data: Bytes<'data>,
21
}
22
23
impl<'data, Elf> NoteIterator<'data, Elf>
24
where
25
    Elf: FileHeader,
26
{
27
    /// Returns `Err` if `align` is invalid.
28
0
    pub(super) fn new(
29
0
        endian: Elf::Endian,
30
0
        align: Elf::Word,
31
0
        data: &'data [u8],
32
0
    ) -> read::Result<Self> {
33
0
        let align = match align.into() {
34
0
            0u64..=4 => 4,
35
0
            8 => 8,
36
0
            _ => return Err(Error("Invalid ELF note alignment")),
37
        };
38
        // TODO: check data alignment?
39
0
        Ok(NoteIterator {
40
0
            endian,
41
0
            align,
42
0
            data: Bytes(data),
43
0
        })
44
0
    }
45
46
    /// Returns the next note.
47
0
    pub fn next(&mut self) -> read::Result<Option<Note<'data, Elf>>> {
48
0
        let mut data = self.data;
49
0
        if data.is_empty() {
50
0
            return Ok(None);
51
0
        }
52
53
0
        let header = data
54
0
            .read_at::<Elf::NoteHeader>(0)
55
0
            .read_error("ELF note is too short")?;
56
57
        // The name has no alignment requirement.
58
0
        let offset = mem::size_of::<Elf::NoteHeader>();
59
0
        let namesz = header.n_namesz(self.endian) as usize;
60
0
        let name = data
61
0
            .read_bytes_at(offset, namesz)
62
0
            .read_error("Invalid ELF note namesz")?
63
            .0;
64
65
        // The descriptor must be aligned.
66
0
        let offset = util::align(offset + namesz, self.align);
67
0
        let descsz = header.n_descsz(self.endian) as usize;
68
0
        let desc = data
69
0
            .read_bytes_at(offset, descsz)
70
0
            .read_error("Invalid ELF note descsz")?
71
            .0;
72
73
        // The next note (if any) must be aligned.
74
0
        let offset = util::align(offset + descsz, self.align);
75
0
        if data.skip(offset).is_err() {
76
0
            data = Bytes(&[]);
77
0
        }
78
0
        self.data = data;
79
0
80
0
        Ok(Some(Note { header, name, desc }))
81
0
    }
82
}
83
84
/// A parsed `NoteHeader`.
85
#[derive(Debug)]
86
pub struct Note<'data, Elf>
87
where
88
    Elf: FileHeader,
89
{
90
    header: &'data Elf::NoteHeader,
91
    name: &'data [u8],
92
    desc: &'data [u8],
93
}
94
95
impl<'data, Elf: FileHeader> Note<'data, Elf> {
96
    /// Return the `n_type` field of the `NoteHeader`.
97
    ///
98
    /// The meaning of this field is determined by `name`.
99
0
    pub fn n_type(&self, endian: Elf::Endian) -> u32 {
100
0
        self.header.n_type(endian)
101
0
    }
102
103
    /// Return the `n_namesz` field of the `NoteHeader`.
104
0
    pub fn n_namesz(&self, endian: Elf::Endian) -> u32 {
105
0
        self.header.n_namesz(endian)
106
0
    }
107
108
    /// Return the `n_descsz` field of the `NoteHeader`.
109
0
    pub fn n_descsz(&self, endian: Elf::Endian) -> u32 {
110
0
        self.header.n_descsz(endian)
111
0
    }
112
113
    /// Return the bytes for the name field following the `NoteHeader`,
114
    /// excluding any null terminator.
115
    ///
116
    /// This field is usually a string including a null terminator
117
    /// (but it is not required to be).
118
    ///
119
    /// The length of this field (including any null terminator) is given by
120
    /// `n_namesz`.
121
0
    pub fn name(&self) -> &'data [u8] {
122
0
        if let Some((last, name)) = self.name.split_last() {
123
0
            if *last == 0 {
124
0
                return name;
125
0
            }
126
0
        }
127
0
        self.name
128
0
    }
129
130
    /// Return the bytes for the desc field following the `NoteHeader`.
131
    ///
132
    /// The length of this field is given by `n_descsz`. The meaning
133
    /// of this field is determined by `name` and `n_type`.
134
0
    pub fn desc(&self) -> &'data [u8] {
135
0
        self.desc
136
0
    }
137
}
138
139
/// A trait for generic access to `NoteHeader32` and `NoteHeader64`.
140
#[allow(missing_docs)]
141
pub trait NoteHeader: Debug + Pod {
142
    type Endian: endian::Endian;
143
144
    fn n_namesz(&self, endian: Self::Endian) -> u32;
145
    fn n_descsz(&self, endian: Self::Endian) -> u32;
146
    fn n_type(&self, endian: Self::Endian) -> u32;
147
}
148
149
impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader32<Endian> {
150
    type Endian = Endian;
151
152
    #[inline]
153
0
    fn n_namesz(&self, endian: Self::Endian) -> u32 {
154
0
        self.n_namesz.get(endian)
155
0
    }
156
157
    #[inline]
158
0
    fn n_descsz(&self, endian: Self::Endian) -> u32 {
159
0
        self.n_descsz.get(endian)
160
0
    }
161
162
    #[inline]
163
0
    fn n_type(&self, endian: Self::Endian) -> u32 {
164
0
        self.n_type.get(endian)
165
0
    }
166
}
167
168
impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader64<Endian> {
169
    type Endian = Endian;
170
171
    #[inline]
172
0
    fn n_namesz(&self, endian: Self::Endian) -> u32 {
173
0
        self.n_namesz.get(endian)
174
0
    }
175
176
    #[inline]
177
0
    fn n_descsz(&self, endian: Self::Endian) -> u32 {
178
0
        self.n_descsz.get(endian)
179
0
    }
180
181
    #[inline]
182
0
    fn n_type(&self, endian: Self::Endian) -> u32 {
183
0
        self.n_type.get(endian)
184
0
    }
185
}