Coverage Report

Created: 2026-01-13 06:28

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/lookup.rs
Line
Count
Source
1
use core::marker::PhantomData;
2
3
use crate::common::{DebugInfoOffset, Format};
4
use crate::read::{parse_debug_info_offset, Error, Reader, ReaderOffset, Result, UnitOffset};
5
6
// The various "Accelerated Access" sections (DWARF standard v4 Section 6.1) all have
7
// similar structures. They consist of a header with metadata and an offset into the
8
// .debug_info section for the entire compilation unit, and a series
9
// of following entries that list addresses (for .debug_aranges) or names
10
// (for .debug_pubnames and .debug_pubtypes) that are covered.
11
//
12
// Because these three tables all have similar structures, we abstract out some of
13
// the parsing mechanics.
14
15
pub trait LookupParser<R: Reader> {
16
    /// The type of the produced header.
17
    type Header;
18
    /// The type of the produced entry.
19
    type Entry;
20
21
    /// Parse a header from `input`. Returns a tuple of `input` sliced to contain just the entries
22
    /// corresponding to this header (without the header itself), and the parsed representation of
23
    /// the header itself.
24
    fn parse_header(input: &mut R) -> Result<(R, Self::Header)>;
25
26
    /// Parse a single entry from `input`. Returns either a parsed representation of the entry
27
    /// or None if `input` is exhausted.
28
    fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>>;
29
}
30
31
#[derive(Clone, Debug)]
32
pub struct DebugLookup<R, Parser>
33
where
34
    R: Reader,
35
    Parser: LookupParser<R>,
36
{
37
    input_buffer: R,
38
    phantom: PhantomData<Parser>,
39
}
40
41
impl<R, Parser> From<R> for DebugLookup<R, Parser>
42
where
43
    R: Reader,
44
    Parser: LookupParser<R>,
45
{
46
0
    fn from(input_buffer: R) -> Self {
47
0
        DebugLookup {
48
0
            input_buffer,
49
0
            phantom: PhantomData,
50
0
        }
51
0
    }
52
}
53
54
impl<R, Parser> DebugLookup<R, Parser>
55
where
56
    R: Reader,
57
    Parser: LookupParser<R>,
58
{
59
0
    pub fn items(&self) -> LookupEntryIter<R, Parser> {
60
0
        LookupEntryIter {
61
0
            current_set: None,
62
0
            remaining_input: self.input_buffer.clone(),
63
0
        }
64
0
    }
65
66
0
    pub fn reader(&self) -> &R {
67
0
        &self.input_buffer
68
0
    }
69
}
70
71
#[derive(Clone, Debug)]
72
pub struct LookupEntryIter<R, Parser>
73
where
74
    R: Reader,
75
    Parser: LookupParser<R>,
76
{
77
    current_set: Option<(R, Parser::Header)>, // Only none at the very beginning and end.
78
    remaining_input: R,
79
}
80
81
impl<R, Parser> LookupEntryIter<R, Parser>
82
where
83
    R: Reader,
84
    Parser: LookupParser<R>,
85
{
86
    /// Advance the iterator and return the next entry.
87
    ///
88
    /// Returns the newly parsed entry as `Ok(Some(Parser::Entry))`. Returns
89
    /// `Ok(None)` when iteration is complete and all entries have already been
90
    /// parsed and yielded. If an error occurs while parsing the next entry,
91
    /// then this error is returned as `Err(e)`, and all subsequent calls return
92
    /// `Ok(None)`.
93
    ///
94
    /// Can be [used with `FallibleIterator`](./index.html#using-with-fallibleiterator).
95
0
    pub fn next(&mut self) -> Result<Option<Parser::Entry>> {
96
        loop {
97
0
            if let Some((ref mut input, ref header)) = self.current_set {
98
0
                if !input.is_empty() {
99
0
                    match Parser::parse_entry(input, header) {
100
0
                        Ok(Some(entry)) => return Ok(Some(entry)),
101
0
                        Ok(None) => {}
102
0
                        Err(e) => {
103
0
                            input.empty();
104
0
                            self.remaining_input.empty();
105
0
                            return Err(e);
106
                        }
107
                    }
108
0
                }
109
0
            }
110
0
            if self.remaining_input.is_empty() {
111
0
                self.current_set = None;
112
0
                return Ok(None);
113
0
            }
114
0
            match Parser::parse_header(&mut self.remaining_input) {
115
0
                Ok(set) => {
116
0
                    self.current_set = Some(set);
117
0
                }
118
0
                Err(e) => {
119
0
                    self.current_set = None;
120
0
                    self.remaining_input.empty();
121
0
                    return Err(e);
122
                }
123
            }
124
        }
125
0
    }
126
}
127
128
#[derive(Debug, Clone, PartialEq, Eq)]
129
pub struct PubStuffHeader<T = usize> {
130
    format: Format,
131
    length: T,
132
    version: u16,
133
    unit_offset: DebugInfoOffset<T>,
134
    unit_length: T,
135
}
136
137
pub trait PubStuffEntry<R: Reader> {
138
    fn new(
139
        die_offset: UnitOffset<R::Offset>,
140
        name: R,
141
        unit_header_offset: DebugInfoOffset<R::Offset>,
142
    ) -> Self;
143
}
144
145
#[derive(Clone, Debug)]
146
pub struct PubStuffParser<R, Entry>
147
where
148
    R: Reader,
149
    Entry: PubStuffEntry<R>,
150
{
151
    // This struct is never instantiated.
152
    phantom: PhantomData<(R, Entry)>,
153
}
154
155
impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry>
156
where
157
    R: Reader,
158
    Entry: PubStuffEntry<R>,
159
{
160
    type Header = PubStuffHeader<R::Offset>;
161
    type Entry = Entry;
162
163
    /// Parse an pubthings set header. Returns a tuple of the
164
    /// pubthings to be parsed for this set, and the newly created PubThingHeader struct.
165
0
    fn parse_header(input: &mut R) -> Result<(R, Self::Header)> {
166
0
        let (length, format) = input.read_initial_length()?;
167
0
        let mut rest = input.split(length)?;
168
169
0
        let version = rest.read_u16()?;
170
0
        if version != 2 {
171
0
            return Err(Error::UnknownVersion(u64::from(version)));
172
0
        }
173
174
0
        let unit_offset = parse_debug_info_offset(&mut rest, format)?;
175
0
        let unit_length = rest.read_length(format)?;
176
177
0
        let header = PubStuffHeader {
178
0
            format,
179
0
            length,
180
0
            version,
181
0
            unit_offset,
182
0
            unit_length,
183
0
        };
184
0
        Ok((rest, header))
185
0
    }
186
187
    /// Parse a single pubthing. Return `None` for the null pubthing, `Some` for an actual pubthing.
188
0
    fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> {
189
0
        let offset = input.read_offset(header.format)?;
190
0
        if offset.into_u64() == 0 {
191
0
            input.empty();
192
0
            Ok(None)
193
        } else {
194
0
            let name = input.read_null_terminated_slice()?;
195
0
            Ok(Some(Self::Entry::new(
196
0
                UnitOffset(offset),
197
0
                name,
198
0
                header.unit_offset,
199
0
            )))
200
        }
201
0
    }
202
}