/rust/registry/src/index.crates.io-6f17d22bba15001f/gimli-0.29.0/src/read/str.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::common::{ |
2 | | DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType, |
3 | | Encoding, SectionId, |
4 | | }; |
5 | | use crate::endianity::Endianity; |
6 | | use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section}; |
7 | | use crate::Format; |
8 | | |
9 | | /// The `DebugStr` struct represents the DWARF strings |
10 | | /// found in the `.debug_str` section. |
11 | | #[derive(Debug, Default, Clone, Copy)] |
12 | | pub struct DebugStr<R> { |
13 | | debug_str_section: R, |
14 | | } |
15 | | |
16 | | impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>> |
17 | | where |
18 | | Endian: Endianity, |
19 | | { |
20 | | /// Construct a new `DebugStr` instance from the data in the `.debug_str` |
21 | | /// section. |
22 | | /// |
23 | | /// It is the caller's responsibility to read the `.debug_str` section and |
24 | | /// present it as a `&[u8]` slice. That means using some ELF loader on |
25 | | /// Linux, a Mach-O loader on macOS, etc. |
26 | | /// |
27 | | /// ``` |
28 | | /// use gimli::{DebugStr, LittleEndian}; |
29 | | /// |
30 | | /// # let buf = [0x00, 0x01, 0x02, 0x03]; |
31 | | /// # let read_debug_str_section_somehow = || &buf; |
32 | | /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian); |
33 | | /// ``` |
34 | 0 | pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self { |
35 | 0 | Self::from(EndianSlice::new(debug_str_section, endian)) |
36 | 0 | } |
37 | | } |
38 | | |
39 | | impl<R: Reader> DebugStr<R> { |
40 | | /// Lookup a string from the `.debug_str` section by DebugStrOffset. |
41 | | /// |
42 | | /// ``` |
43 | | /// use gimli::{DebugStr, DebugStrOffset, LittleEndian}; |
44 | | /// |
45 | | /// # let buf = [0x01, 0x02, 0x00]; |
46 | | /// # let offset = DebugStrOffset(0); |
47 | | /// # let read_debug_str_section_somehow = || &buf; |
48 | | /// # let debug_str_offset_somehow = || offset; |
49 | | /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian); |
50 | | /// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow())); |
51 | | /// ``` |
52 | 0 | pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> { |
53 | 0 | let input = &mut self.debug_str_section.clone(); |
54 | 0 | input.skip(offset.0)?; |
55 | 0 | input.read_null_terminated_slice() |
56 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugStr<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::get_str Unexecuted instantiation: <gimli::read::str::DebugStr<_>>::get_str |
57 | | } |
58 | | |
59 | | impl<T> DebugStr<T> { |
60 | | /// Create a `DebugStr` section that references the data in `self`. |
61 | | /// |
62 | | /// This is useful when `R` implements `Reader` but `T` does not. |
63 | | /// |
64 | | /// Used by `DwarfSections::borrow`. |
65 | 0 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R> |
66 | 0 | where |
67 | 0 | F: FnMut(&'a T) -> R, |
68 | 0 | { |
69 | 0 | borrow(&self.debug_str_section).into() |
70 | 0 | } |
71 | | } |
72 | | |
73 | | impl<R> Section<R> for DebugStr<R> { |
74 | 0 | fn id() -> SectionId { |
75 | 0 | SectionId::DebugStr |
76 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugStr<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::str::DebugStr<_> as gimli::read::Section<_>>::id |
77 | | |
78 | 0 | fn reader(&self) -> &R { |
79 | 0 | &self.debug_str_section |
80 | 0 | } |
81 | | } |
82 | | |
83 | | impl<R> From<R> for DebugStr<R> { |
84 | 0 | fn from(debug_str_section: R) -> Self { |
85 | 0 | DebugStr { debug_str_section } |
86 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugStr<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::str::DebugStr<_> as core::convert::From<_>>::from |
87 | | } |
88 | | |
89 | | /// The raw contents of the `.debug_str_offsets` section. |
90 | | #[derive(Debug, Default, Clone, Copy)] |
91 | | pub struct DebugStrOffsets<R> { |
92 | | section: R, |
93 | | } |
94 | | |
95 | | impl<R: Reader> DebugStrOffsets<R> { |
96 | | // TODO: add an iterator over the sets of entries in the section. |
97 | | // This is not needed for common usage of the section though. |
98 | | |
99 | | /// Returns the `.debug_str` offset at the given `base` and `index`. |
100 | | /// |
101 | | /// A set of entries in the `.debug_str_offsets` section consists of a header |
102 | | /// followed by a series of string table offsets. |
103 | | /// |
104 | | /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE. |
105 | | /// This is an offset that points to the first entry following the header. |
106 | | /// |
107 | | /// The `index` is the value of a `DW_FORM_strx` attribute. |
108 | | /// |
109 | | /// The `format` must be the DWARF format of the compilation unit. This format must |
110 | | /// match the header. However, note that we do not parse the header to validate this, |
111 | | /// since locating the header is unreliable, and the GNU extensions do not emit it. |
112 | 0 | pub fn get_str_offset( |
113 | 0 | &self, |
114 | 0 | format: Format, |
115 | 0 | base: DebugStrOffsetsBase<R::Offset>, |
116 | 0 | index: DebugStrOffsetsIndex<R::Offset>, |
117 | 0 | ) -> Result<DebugStrOffset<R::Offset>> { |
118 | 0 | let input = &mut self.section.clone(); |
119 | 0 | input.skip(base.0)?; |
120 | 0 | input.skip(R::Offset::from_u64( |
121 | 0 | index.0.into_u64() * u64::from(format.word_size()), |
122 | 0 | )?)?; |
123 | 0 | input.read_offset(format).map(DebugStrOffset) |
124 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugStrOffsets<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::get_str_offset Unexecuted instantiation: <gimli::read::str::DebugStrOffsets<_>>::get_str_offset |
125 | | } |
126 | | |
127 | | impl<T> DebugStrOffsets<T> { |
128 | | /// Create a `DebugStrOffsets` section that references the data in `self`. |
129 | | /// |
130 | | /// This is useful when `R` implements `Reader` but `T` does not. |
131 | | /// |
132 | | /// Used by `DwarfSections::borrow`. |
133 | 0 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R> |
134 | 0 | where |
135 | 0 | F: FnMut(&'a T) -> R, |
136 | 0 | { |
137 | 0 | borrow(&self.section).into() |
138 | 0 | } |
139 | | } |
140 | | |
141 | | impl<R> Section<R> for DebugStrOffsets<R> { |
142 | 0 | fn id() -> SectionId { |
143 | 0 | SectionId::DebugStrOffsets |
144 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugStrOffsets<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::str::DebugStrOffsets<_> as gimli::read::Section<_>>::id |
145 | | |
146 | 0 | fn reader(&self) -> &R { |
147 | 0 | &self.section |
148 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugStrOffsets<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as gimli::read::Section<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::reader Unexecuted instantiation: <gimli::read::str::DebugStrOffsets<_> as gimli::read::Section<_>>::reader |
149 | | } |
150 | | |
151 | | impl<R> From<R> for DebugStrOffsets<R> { |
152 | 0 | fn from(section: R) -> Self { |
153 | 0 | DebugStrOffsets { section } |
154 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugStrOffsets<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::str::DebugStrOffsets<_> as core::convert::From<_>>::from |
155 | | } |
156 | | |
157 | | impl<Offset> DebugStrOffsetsBase<Offset> |
158 | | where |
159 | | Offset: ReaderOffset, |
160 | | { |
161 | | /// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base |
162 | | /// for the given `Encoding` and `DwarfFileType`. |
163 | 0 | pub fn default_for_encoding_and_file( |
164 | 0 | encoding: Encoding, |
165 | 0 | file_type: DwarfFileType, |
166 | 0 | ) -> DebugStrOffsetsBase<Offset> { |
167 | 0 | if encoding.version >= 5 && file_type == DwarfFileType::Dwo { |
168 | | // In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is |
169 | | // only a single unit in the file) but we must skip past the header, which the attribute |
170 | | // would normally do for us. |
171 | | // initial_length_size + version + 2 bytes of padding. |
172 | 0 | DebugStrOffsetsBase(Offset::from_u8( |
173 | 0 | encoding.format.initial_length_size() + 2 + 2, |
174 | 0 | )) |
175 | | } else { |
176 | 0 | DebugStrOffsetsBase(Offset::from_u8(0)) |
177 | | } |
178 | 0 | } Unexecuted instantiation: <gimli::common::DebugStrOffsetsBase>::default_for_encoding_and_file Unexecuted instantiation: <gimli::common::DebugStrOffsetsBase<_>>::default_for_encoding_and_file |
179 | | } |
180 | | |
181 | | /// The `DebugLineStr` struct represents the DWARF strings |
182 | | /// found in the `.debug_line_str` section. |
183 | | #[derive(Debug, Default, Clone, Copy)] |
184 | | pub struct DebugLineStr<R> { |
185 | | section: R, |
186 | | } |
187 | | |
188 | | impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>> |
189 | | where |
190 | | Endian: Endianity, |
191 | | { |
192 | | /// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str` |
193 | | /// section. |
194 | | /// |
195 | | /// It is the caller's responsibility to read the `.debug_line_str` section and |
196 | | /// present it as a `&[u8]` slice. That means using some ELF loader on |
197 | | /// Linux, a Mach-O loader on macOS, etc. |
198 | | /// |
199 | | /// ``` |
200 | | /// use gimli::{DebugLineStr, LittleEndian}; |
201 | | /// |
202 | | /// # let buf = [0x00, 0x01, 0x02, 0x03]; |
203 | | /// # let read_debug_line_str_section_somehow = || &buf; |
204 | | /// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian); |
205 | | /// ``` |
206 | 0 | pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self { |
207 | 0 | Self::from(EndianSlice::new(debug_line_str_section, endian)) |
208 | 0 | } |
209 | | } |
210 | | |
211 | | impl<R: Reader> DebugLineStr<R> { |
212 | | /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset. |
213 | 0 | pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> { |
214 | 0 | let input = &mut self.section.clone(); |
215 | 0 | input.skip(offset.0)?; |
216 | 0 | input.read_null_terminated_slice() |
217 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugLineStr<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::get_str Unexecuted instantiation: <gimli::read::str::DebugLineStr<_>>::get_str |
218 | | } |
219 | | |
220 | | impl<T> DebugLineStr<T> { |
221 | | /// Create a `DebugLineStr` section that references the data in `self`. |
222 | | /// |
223 | | /// This is useful when `R` implements `Reader` but `T` does not. |
224 | | /// |
225 | | /// Used by `DwarfSections::borrow`. |
226 | 0 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R> |
227 | 0 | where |
228 | 0 | F: FnMut(&'a T) -> R, |
229 | 0 | { |
230 | 0 | borrow(&self.section).into() |
231 | 0 | } |
232 | | } |
233 | | |
234 | | impl<R> Section<R> for DebugLineStr<R> { |
235 | 0 | fn id() -> SectionId { |
236 | 0 | SectionId::DebugLineStr |
237 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugLineStr<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::str::DebugLineStr<_> as gimli::read::Section<_>>::id |
238 | | |
239 | 0 | fn reader(&self) -> &R { |
240 | 0 | &self.section |
241 | 0 | } |
242 | | } |
243 | | |
244 | | impl<R> From<R> for DebugLineStr<R> { |
245 | 0 | fn from(section: R) -> Self { |
246 | 0 | DebugLineStr { section } |
247 | 0 | } Unexecuted instantiation: <gimli::read::str::DebugLineStr<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::str::DebugLineStr<_> as core::convert::From<_>>::from |
248 | | } |
249 | | |
250 | | #[cfg(test)] |
251 | | mod tests { |
252 | | use super::*; |
253 | | use crate::test_util::GimliSectionMethods; |
254 | | use crate::LittleEndian; |
255 | | use test_assembler::{Endian, Label, LabelMaker, Section}; |
256 | | |
257 | | #[test] |
258 | | fn test_get_str_offset() { |
259 | | for format in [Format::Dwarf32, Format::Dwarf64] { |
260 | | let zero = Label::new(); |
261 | | let length = Label::new(); |
262 | | let start = Label::new(); |
263 | | let first = Label::new(); |
264 | | let end = Label::new(); |
265 | | let mut section = Section::with_endian(Endian::Little) |
266 | | .mark(&zero) |
267 | | .initial_length(format, &length, &start) |
268 | | .D16(5) |
269 | | .D16(0) |
270 | | .mark(&first); |
271 | | for i in 0..20 { |
272 | | section = section.word(format.word_size(), 1000 + i); |
273 | | } |
274 | | section = section.mark(&end); |
275 | | length.set_const((&end - &start) as u64); |
276 | | |
277 | | let section = section.get_contents().unwrap(); |
278 | | let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian)); |
279 | | let base = DebugStrOffsetsBase((&first - &zero) as usize); |
280 | | |
281 | | assert_eq!( |
282 | | debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)), |
283 | | Ok(DebugStrOffset(1000)) |
284 | | ); |
285 | | assert_eq!( |
286 | | debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)), |
287 | | Ok(DebugStrOffset(1019)) |
288 | | ); |
289 | | } |
290 | | } |
291 | | } |