1use core::marker::PhantomData;
2
3use crate::common::{DebugInfoOffset, Format};
4use 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
15pub 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)]
32pub struct DebugLookup<R, Parser>
33where
34 R: Reader,
35 Parser: LookupParser<R>,
36{
37 input_buffer: R,
38 phantom: PhantomData<Parser>,
39}
40
41impl<R, Parser> From<R> for DebugLookup<R, Parser>
42where
43 R: Reader,
44 Parser: LookupParser<R>,
45{
46 fn from(input_buffer: R) -> Self {
47 DebugLookup {
48 input_buffer,
49 phantom: PhantomData,
50 }
51 }
52}
53
54impl<R, Parser> DebugLookup<R, Parser>
55where
56 R: Reader,
57 Parser: LookupParser<R>,
58{
59 pub fn items(&self) -> LookupEntryIter<R, Parser> {
60 LookupEntryIter {
61 current_set: None,
62 remaining_input: self.input_buffer.clone(),
63 }
64 }
65
66 pub fn reader(&self) -> &R {
67 &self.input_buffer
68 }
69}
70
71#[derive(Clone, Debug)]
72pub struct LookupEntryIter<R, Parser>
73where
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
81impl<R, Parser> LookupEntryIter<R, Parser>
82where
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 pub fn next(&mut self) -> Result<Option<Parser::Entry>> {
96 loop {
97 if let Some((ref mut input, ref header)) = self.current_set {
98 if !input.is_empty() {
99 match Parser::parse_entry(input, header) {
100 Ok(Some(entry)) => return Ok(Some(entry)),
101 Ok(None) => {}
102 Err(e) => {
103 input.empty();
104 self.remaining_input.empty();
105 return Err(e);
106 }
107 }
108 }
109 }
110 if self.remaining_input.is_empty() {
111 self.current_set = None;
112 return Ok(None);
113 }
114 match Parser::parse_header(&mut self.remaining_input) {
115 Ok(set) => {
116 self.current_set = Some(set);
117 }
118 Err(e) => {
119 self.current_set = None;
120 self.remaining_input.empty();
121 return Err(e);
122 }
123 }
124 }
125 }
126}
127
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub struct PubStuffHeader<T = usize> {
130 format: Format,
131 length: T,
132 version: u16,
133 unit_offset: DebugInfoOffset<T>,
134 unit_length: T,
135}
136
137pub 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)]
146pub struct PubStuffParser<R, Entry>
147where
148 R: Reader,
149 Entry: PubStuffEntry<R>,
150{
151 // This struct is never instantiated.
152 phantom: PhantomData<(R, Entry)>,
153}
154
155impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry>
156where
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 fn parse_header(input: &mut R) -> Result<(R, Self::Header)> {
166 let (length, format) = input.read_initial_length()?;
167 let mut rest = input.split(length)?;
168
169 let version = rest.read_u16()?;
170 if version != 2 {
171 return Err(Error::UnknownVersion(u64::from(version)));
172 }
173
174 let unit_offset = parse_debug_info_offset(&mut rest, format)?;
175 let unit_length = rest.read_length(format)?;
176
177 let header = PubStuffHeader {
178 format,
179 length,
180 version,
181 unit_offset,
182 unit_length,
183 };
184 Ok((rest, header))
185 }
186
187 /// Parse a single pubthing. Return `None` for the null pubthing, `Some` for an actual pubthing.
188 fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> {
189 let offset = input.read_offset(header.format)?;
190 if offset.into_u64() == 0 {
191 input.empty();
192 Ok(None)
193 } else {
194 let name = input.read_null_terminated_slice()?;
195 Ok(Some(Self::Entry::new(
196 UnitOffset(offset),
197 name,
198 header.unit_offset,
199 )))
200 }
201 }
202}
203