/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(§ion, 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(§ion, 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 | | } |