/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 | | } |