Coverage Report

Created: 2026-02-14 07:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/gimli-0.32.3/src/read/addr.rs
Line
Count
Source
1
use crate::common::{DebugAddrBase, DebugAddrIndex, DebugAddrOffset, Encoding, SectionId};
2
use crate::read::{Error, Reader, ReaderOffset, Result, Section};
3
4
/// The raw contents of the `.debug_addr` section.
5
#[derive(Debug, Default, Clone, Copy)]
6
pub struct DebugAddr<R> {
7
    section: R,
8
}
9
10
impl<R: Reader> DebugAddr<R> {
11
    /// Returns the address at the given `base` and `index`.
12
    ///
13
    /// A set of addresses in the `.debug_addr` section consists of a header
14
    /// followed by a series of addresses.
15
    ///
16
    /// The `base` must be the `DW_AT_addr_base` value from the compilation unit DIE.
17
    /// This is an offset that points to the first address following the header.
18
    ///
19
    /// The `index` is the value of a `DW_FORM_addrx` attribute.
20
    ///
21
    /// The `address_size` must be the size of the address for the compilation unit.
22
    /// This value must also match the header. However, note that we do not parse the
23
    /// header to validate this, since locating the header is unreliable, and the GNU
24
    /// extensions do not emit it.
25
0
    pub fn get_address(
26
0
        &self,
27
0
        address_size: u8,
28
0
        base: DebugAddrBase<R::Offset>,
29
0
        index: DebugAddrIndex<R::Offset>,
30
0
    ) -> Result<u64> {
31
0
        let input = &mut self.section.clone();
32
0
        input.skip(base.0)?;
33
0
        input.skip(R::Offset::from_u64(
34
0
            index.0.into_u64() * u64::from(address_size),
35
0
        )?)?;
36
0
        input.read_address(address_size)
37
0
    }
Unexecuted instantiation: <gimli::read::addr::DebugAddr<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::get_address
Unexecuted instantiation: <gimli::read::addr::DebugAddr<_>>::get_address
38
39
    /// Iterate the sets of entries in the `.debug_addr` section.
40
    ///
41
    /// Each set of entries belongs to a single unit.
42
0
    pub fn headers(&self) -> AddrHeaderIter<R> {
43
0
        AddrHeaderIter {
44
0
            input: self.section.clone(),
45
0
            offset: DebugAddrOffset(R::Offset::from_u8(0)),
46
0
        }
47
0
    }
48
}
49
50
impl<T> DebugAddr<T> {
51
    /// Create a `DebugAddr` section that references the data in `self`.
52
    ///
53
    /// This is useful when `R` implements `Reader` but `T` does not.
54
    ///
55
    /// Used by `DwarfSections::borrow`.
56
0
    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAddr<R>
57
0
    where
58
0
        F: FnMut(&'a T) -> R,
59
    {
60
0
        borrow(&self.section).into()
61
0
    }
62
}
63
64
impl<R> Section<R> for DebugAddr<R> {
65
0
    fn id() -> SectionId {
66
0
        SectionId::DebugAddr
67
0
    }
Unexecuted instantiation: <gimli::read::addr::DebugAddr<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as gimli::read::Section<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::id
Unexecuted instantiation: <gimli::read::addr::DebugAddr<_> as gimli::read::Section<_>>::id
68
69
0
    fn reader(&self) -> &R {
70
0
        &self.section
71
0
    }
72
}
73
74
impl<R> From<R> for DebugAddr<R> {
75
0
    fn from(section: R) -> Self {
76
0
        DebugAddr { section }
77
0
    }
Unexecuted instantiation: <gimli::read::addr::DebugAddr<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as core::convert::From<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::from
Unexecuted instantiation: <gimli::read::addr::DebugAddr<_> as core::convert::From<_>>::from
78
}
79
80
/// An iterator over the headers of a `.debug_addr` section.
81
#[derive(Clone, Debug)]
82
pub struct AddrHeaderIter<R: Reader> {
83
    input: R,
84
    offset: DebugAddrOffset<R::Offset>,
85
}
86
87
impl<R: Reader> AddrHeaderIter<R> {
88
    /// Advance the iterator to the next header.
89
0
    pub fn next(&mut self) -> Result<Option<AddrHeader<R>>> {
90
0
        if self.input.is_empty() {
91
0
            return Ok(None);
92
0
        }
93
94
0
        let len = self.input.len();
95
0
        match AddrHeader::parse(&mut self.input, self.offset) {
96
0
            Ok(header) => {
97
0
                self.offset.0 += len - self.input.len();
98
0
                Ok(Some(header))
99
            }
100
0
            Err(e) => {
101
0
                self.input.empty();
102
0
                Err(e)
103
            }
104
        }
105
0
    }
106
}
107
108
#[cfg(feature = "fallible-iterator")]
109
impl<R: Reader> fallible_iterator::FallibleIterator for AddrHeaderIter<R> {
110
    type Item = AddrHeader<R>;
111
    type Error = Error;
112
113
0
    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
114
0
        AddrHeaderIter::next(self)
115
0
    }
116
}
117
118
/// A header for a set of entries in the `.debug_addr` section.
119
///
120
/// These entries all belong to a single unit.
121
#[derive(Debug, Clone, PartialEq, Eq)]
122
pub struct AddrHeader<R, Offset = <R as Reader>::Offset>
123
where
124
    R: Reader<Offset = Offset>,
125
    Offset: ReaderOffset,
126
{
127
    offset: DebugAddrOffset<Offset>,
128
    encoding: Encoding,
129
    length: Offset,
130
    entries: R,
131
}
132
133
impl<R, Offset> AddrHeader<R, Offset>
134
where
135
    R: Reader<Offset = Offset>,
136
    Offset: ReaderOffset,
137
{
138
0
    fn parse(input: &mut R, offset: DebugAddrOffset<Offset>) -> Result<Self> {
139
0
        let (length, format) = input.read_initial_length()?;
140
0
        let mut rest = input.split(length)?;
141
142
        // Check the version. The DWARF 5 spec says that this is always 5.
143
0
        let version = rest.read_u16()?;
144
0
        if version != 5 {
145
0
            return Err(Error::UnknownVersion(u64::from(version)));
146
0
        }
147
148
0
        let address_size = rest.read_address_size()?;
149
0
        let segment_size = rest.read_u8()?;
150
0
        if segment_size != 0 {
151
0
            return Err(Error::UnsupportedSegmentSize);
152
0
        }
153
154
        // unit_length + version + address_size + segment_size
155
0
        let header_length = format.initial_length_size() + 2 + 1 + 1;
156
157
        // The first tuple following the header in each set begins at an offset that is
158
        // a multiple of the size of a single tuple (that is, the size of a segment,
159
        // which must be zero, and an address).
160
0
        let tuple_length = address_size;
161
0
        if tuple_length == 0 {
162
0
            return Err(Error::UnsupportedAddressSize(address_size));
163
0
        }
164
0
        let padding = if header_length % tuple_length == 0 {
165
0
            0
166
        } else {
167
0
            tuple_length - header_length % tuple_length
168
        };
169
0
        rest.skip(R::Offset::from_u8(padding))?;
170
171
0
        let encoding = Encoding {
172
0
            format,
173
0
            version,
174
0
            address_size,
175
0
        };
176
0
        Ok(AddrHeader {
177
0
            offset,
178
0
            encoding,
179
0
            length,
180
0
            entries: rest,
181
0
        })
182
0
    }
183
184
    /// Return the offset of this header within the `.debug_addr` section.
185
    #[inline]
186
0
    pub fn offset(&self) -> DebugAddrOffset<Offset> {
187
0
        self.offset
188
0
    }
189
190
    /// Return the length of this set of entries, including the header.
191
    #[inline]
192
0
    pub fn length(&self) -> Offset {
193
0
        self.length
194
0
    }
195
196
    /// Return the encoding parameters for this set of entries.
197
    #[inline]
198
0
    pub fn encoding(&self) -> Encoding {
199
0
        self.encoding
200
0
    }
201
202
    /// Return the address entries in this set.
203
    #[inline]
204
0
    pub fn entries(&self) -> AddrEntryIter<R> {
205
0
        AddrEntryIter {
206
0
            input: self.entries.clone(),
207
0
            encoding: self.encoding,
208
0
        }
209
0
    }
210
}
211
212
/// An iterator over the addresses from a `.debug_addr` section.
213
///
214
/// Can be [used with
215
/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
216
#[derive(Debug, Clone)]
217
pub struct AddrEntryIter<R: Reader> {
218
    input: R,
219
    encoding: Encoding,
220
}
221
222
impl<R: Reader> AddrEntryIter<R> {
223
    /// Advance the iterator and return the next address.
224
    ///
225
    /// Returns the newly parsed address as `Ok(Some(addr))`. Returns `Ok(None)`
226
    /// when iteration is complete and all addresses have already been parsed and
227
    /// yielded. If an error occurs while parsing the next address, then this error
228
    /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`.
229
0
    pub fn next(&mut self) -> Result<Option<u64>> {
230
0
        if self.input.is_empty() {
231
0
            return Ok(None);
232
0
        }
233
234
0
        match self.input.read_address(self.encoding.address_size) {
235
0
            Ok(entry) => Ok(Some(entry)),
236
0
            Err(e) => {
237
0
                self.input.empty();
238
0
                Err(e)
239
            }
240
        }
241
0
    }
242
}
243
244
#[cfg(feature = "fallible-iterator")]
245
impl<R: Reader> fallible_iterator::FallibleIterator for AddrEntryIter<R> {
246
    type Item = u64;
247
    type Error = Error;
248
249
0
    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
250
0
        AddrEntryIter::next(self)
251
0
    }
252
}
253
254
#[cfg(test)]
255
mod tests {
256
    use super::*;
257
    use crate::read::EndianSlice;
258
    use crate::test_util::GimliSectionMethods;
259
    use crate::{Format, LittleEndian};
260
    use test_assembler::{Endian, Label, LabelMaker, Section};
261
262
    #[test]
263
    fn test_get_address() {
264
        for format in [Format::Dwarf32, Format::Dwarf64] {
265
            for address_size in [4, 8] {
266
                let zero = Label::new();
267
                let length = Label::new();
268
                let start = Label::new();
269
                let first = Label::new();
270
                let end = Label::new();
271
                let mut section = Section::with_endian(Endian::Little)
272
                    .mark(&zero)
273
                    .initial_length(format, &length, &start)
274
                    .D16(5)
275
                    .D8(address_size)
276
                    .D8(0)
277
                    .mark(&first);
278
                for i in 0..20 {
279
                    section = section.word(address_size, 1000 + i);
280
                }
281
                section = section.mark(&end);
282
                length.set_const((&end - &start) as u64);
283
284
                let section = section.get_contents().unwrap();
285
                let debug_addr = DebugAddr::from(EndianSlice::new(&section, LittleEndian));
286
                let base = DebugAddrBase((&first - &zero) as usize);
287
288
                assert_eq!(
289
                    debug_addr.get_address(address_size, base, DebugAddrIndex(0)),
290
                    Ok(1000)
291
                );
292
                assert_eq!(
293
                    debug_addr.get_address(address_size, base, DebugAddrIndex(19)),
294
                    Ok(1019)
295
                );
296
            }
297
        }
298
    }
299
300
    #[test]
301
    fn test_iterator() {
302
        let length = Label::new();
303
        let start = Label::new();
304
        let end = Label::new();
305
        // First CU.
306
        let mut section = Section::with_endian(Endian::Little)
307
            .initial_length(Format::Dwarf32, &length, &start)
308
            .D16(5) // Version
309
            .D8(4) // Address size
310
            .D8(0) // Segment size
311
            .word(4, 0x12345678)
312
            .word(4, 0xdeadbeef)
313
            .mark(&end);
314
        length.set_const((&end - &start) as u64);
315
        // Second CU.
316
        let length = Label::new();
317
        let start = Label::new();
318
        let end = Label::new();
319
        section = section
320
            .initial_length(Format::Dwarf64, &length, &start)
321
            .D16(5) // Version
322
            .D8(8) // Address size
323
            .D8(0) // Segment size
324
            .word(8, 0x123456789abcdef0)
325
            .word(8, 0xdeadbeefdeadbeef)
326
            .mark(&end);
327
        length.set_const((&end - &start) as u64);
328
        let section = section.get_contents().unwrap();
329
        let debug_addr = DebugAddr::from(EndianSlice::new(&section, LittleEndian));
330
        let mut iter = debug_addr.headers();
331
        let first_header = iter.next().unwrap().unwrap();
332
        let first_encoding = first_header.encoding();
333
        assert_eq!(first_encoding.address_size, 4);
334
        assert_eq!(first_encoding.format, Format::Dwarf32);
335
        assert_eq!(first_encoding.version, 5);
336
        assert_eq!(first_header.length(), 12);
337
        let mut first_entries = first_header.entries();
338
        assert_eq!(first_entries.next(), Ok(Some(0x12345678)));
339
        assert_eq!(first_entries.next(), Ok(Some(0xdeadbeef)));
340
        assert_eq!(first_entries.next(), Ok(None));
341
        let second_header = iter.next().unwrap().unwrap();
342
        let second_encoding = second_header.encoding();
343
        assert_eq!(second_encoding.address_size, 8);
344
        assert_eq!(second_encoding.format, Format::Dwarf64);
345
        assert_eq!(second_encoding.version, 5);
346
        assert_eq!(second_header.length(), 20);
347
        let mut second_entries = second_header.entries();
348
        assert_eq!(second_entries.next(), Ok(Some(0x123456789abcdef0)));
349
        assert_eq!(second_entries.next(), Ok(Some(0xdeadbeefdeadbeef)));
350
        assert_eq!(second_entries.next(), Ok(None));
351
        assert_eq!(iter.next(), Ok(None));
352
    }
353
}