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 | pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self { |
35 | Self::from(EndianSlice::new(slice:debug_str_section, endian)) |
36 | } |
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 | pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> { |
53 | let input: &mut {unknown} = &mut self.debug_str_section.clone(); |
54 | input.skip(len:offset.0)?; |
55 | input.read_null_terminated_slice() |
56 | } |
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 | /// ## Example Usage |
65 | /// |
66 | /// ```rust,no_run |
67 | /// # let load_section = || unimplemented!(); |
68 | /// // Read the DWARF section into a `Vec` with whatever object loader you're using. |
69 | /// let owned_section: gimli::DebugStr<Vec<u8>> = load_section(); |
70 | /// // Create a reference to the DWARF section. |
71 | /// let section = owned_section.borrow(|section| { |
72 | /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) |
73 | /// }); |
74 | /// ``` |
75 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R> |
76 | where |
77 | F: FnMut(&'a T) -> R, |
78 | { |
79 | borrow(&self.debug_str_section).into() |
80 | } |
81 | } |
82 | |
83 | impl<R> Section<R> for DebugStr<R> { |
84 | fn id() -> SectionId { |
85 | SectionId::DebugStr |
86 | } |
87 | |
88 | fn reader(&self) -> &R { |
89 | &self.debug_str_section |
90 | } |
91 | } |
92 | |
93 | impl<R> From<R> for DebugStr<R> { |
94 | fn from(debug_str_section: R) -> Self { |
95 | DebugStr { debug_str_section } |
96 | } |
97 | } |
98 | |
99 | /// The raw contents of the `.debug_str_offsets` section. |
100 | #[derive(Debug, Default, Clone, Copy)] |
101 | pub struct DebugStrOffsets<R> { |
102 | section: R, |
103 | } |
104 | |
105 | impl<R: Reader> DebugStrOffsets<R> { |
106 | // TODO: add an iterator over the sets of entries in the section. |
107 | // This is not needed for common usage of the section though. |
108 | |
109 | /// Returns the `.debug_str` offset at the given `base` and `index`. |
110 | /// |
111 | /// A set of entries in the `.debug_str_offsets` section consists of a header |
112 | /// followed by a series of string table offsets. |
113 | /// |
114 | /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE. |
115 | /// This is an offset that points to the first entry following the header. |
116 | /// |
117 | /// The `index` is the value of a `DW_FORM_strx` attribute. |
118 | /// |
119 | /// The `format` must be the DWARF format of the compilation unit. This format must |
120 | /// match the header. However, note that we do not parse the header to validate this, |
121 | /// since locating the header is unreliable, and the GNU extensions do not emit it. |
122 | pub fn get_str_offset( |
123 | &self, |
124 | format: Format, |
125 | base: DebugStrOffsetsBase<R::Offset>, |
126 | index: DebugStrOffsetsIndex<R::Offset>, |
127 | ) -> Result<DebugStrOffset<R::Offset>> { |
128 | let input = &mut self.section.clone(); |
129 | input.skip(base.0)?; |
130 | input.skip(R::Offset::from_u64( |
131 | index.0.into_u64() * u64::from(format.word_size()), |
132 | )?)?; |
133 | input.read_offset(format).map(DebugStrOffset) |
134 | } |
135 | } |
136 | |
137 | impl<T> DebugStrOffsets<T> { |
138 | /// Create a `DebugStrOffsets` section that references the data in `self`. |
139 | /// |
140 | /// This is useful when `R` implements `Reader` but `T` does not. |
141 | /// |
142 | /// ## Example Usage |
143 | /// |
144 | /// ```rust,no_run |
145 | /// # let load_section = || unimplemented!(); |
146 | /// // Read the DWARF section into a `Vec` with whatever object loader you're using. |
147 | /// let owned_section: gimli::DebugStrOffsets<Vec<u8>> = load_section(); |
148 | /// // Create a reference to the DWARF section. |
149 | /// let section = owned_section.borrow(|section| { |
150 | /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) |
151 | /// }); |
152 | /// ``` |
153 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R> |
154 | where |
155 | F: FnMut(&'a T) -> R, |
156 | { |
157 | borrow(&self.section).into() |
158 | } |
159 | } |
160 | |
161 | impl<R> Section<R> for DebugStrOffsets<R> { |
162 | fn id() -> SectionId { |
163 | SectionId::DebugStrOffsets |
164 | } |
165 | |
166 | fn reader(&self) -> &R { |
167 | &self.section |
168 | } |
169 | } |
170 | |
171 | impl<R> From<R> for DebugStrOffsets<R> { |
172 | fn from(section: R) -> Self { |
173 | DebugStrOffsets { section } |
174 | } |
175 | } |
176 | |
177 | impl<Offset> DebugStrOffsetsBase<Offset> |
178 | where |
179 | Offset: ReaderOffset, |
180 | { |
181 | /// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base |
182 | /// for the given `Encoding` and `DwarfFileType`. |
183 | pub fn default_for_encoding_and_file( |
184 | encoding: Encoding, |
185 | file_type: DwarfFileType, |
186 | ) -> DebugStrOffsetsBase<Offset> { |
187 | if encoding.version >= 5 && file_type == DwarfFileType::Dwo { |
188 | // In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is |
189 | // only a single unit in the file) but we must skip past the header, which the attribute |
190 | // would normally do for us. |
191 | // initial_length_size + version + 2 bytes of padding. |
192 | DebugStrOffsetsBase(Offset::from_u8( |
193 | offset:encoding.format.initial_length_size() + 2 + 2, |
194 | )) |
195 | } else { |
196 | DebugStrOffsetsBase(Offset::from_u8(offset:0)) |
197 | } |
198 | } |
199 | } |
200 | |
201 | /// The `DebugLineStr` struct represents the DWARF strings |
202 | /// found in the `.debug_line_str` section. |
203 | #[derive(Debug, Default, Clone, Copy)] |
204 | pub struct DebugLineStr<R> { |
205 | section: R, |
206 | } |
207 | |
208 | impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>> |
209 | where |
210 | Endian: Endianity, |
211 | { |
212 | /// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str` |
213 | /// section. |
214 | /// |
215 | /// It is the caller's responsibility to read the `.debug_line_str` section and |
216 | /// present it as a `&[u8]` slice. That means using some ELF loader on |
217 | /// Linux, a Mach-O loader on macOS, etc. |
218 | /// |
219 | /// ``` |
220 | /// use gimli::{DebugLineStr, LittleEndian}; |
221 | /// |
222 | /// # let buf = [0x00, 0x01, 0x02, 0x03]; |
223 | /// # let read_debug_line_str_section_somehow = || &buf; |
224 | /// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian); |
225 | /// ``` |
226 | pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self { |
227 | Self::from(EndianSlice::new(slice:debug_line_str_section, endian)) |
228 | } |
229 | } |
230 | |
231 | impl<R: Reader> DebugLineStr<R> { |
232 | /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset. |
233 | pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> { |
234 | let input: &mut {unknown} = &mut self.section.clone(); |
235 | input.skip(len:offset.0)?; |
236 | input.read_null_terminated_slice() |
237 | } |
238 | } |
239 | |
240 | impl<T> DebugLineStr<T> { |
241 | /// Create a `DebugLineStr` section that references the data in `self`. |
242 | /// |
243 | /// This is useful when `R` implements `Reader` but `T` does not. |
244 | /// |
245 | /// ## Example Usage |
246 | /// |
247 | /// ```rust,no_run |
248 | /// # let load_section = || unimplemented!(); |
249 | /// // Read the DWARF section into a `Vec` with whatever object loader you're using. |
250 | /// let owned_section: gimli::DebugLineStr<Vec<u8>> = load_section(); |
251 | /// // Create a reference to the DWARF section. |
252 | /// let section = owned_section.borrow(|section| { |
253 | /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) |
254 | /// }); |
255 | /// ``` |
256 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R> |
257 | where |
258 | F: FnMut(&'a T) -> R, |
259 | { |
260 | borrow(&self.section).into() |
261 | } |
262 | } |
263 | |
264 | impl<R> Section<R> for DebugLineStr<R> { |
265 | fn id() -> SectionId { |
266 | SectionId::DebugLineStr |
267 | } |
268 | |
269 | fn reader(&self) -> &R { |
270 | &self.section |
271 | } |
272 | } |
273 | |
274 | impl<R> From<R> for DebugLineStr<R> { |
275 | fn from(section: R) -> Self { |
276 | DebugLineStr { section } |
277 | } |
278 | } |
279 | |
280 | #[cfg (test)] |
281 | mod tests { |
282 | use super::*; |
283 | use crate::test_util::GimliSectionMethods; |
284 | use crate::LittleEndian; |
285 | use test_assembler::{Endian, Label, LabelMaker, Section}; |
286 | |
287 | #[test] |
288 | fn test_get_str_offset() { |
289 | for format in vec![Format::Dwarf32, Format::Dwarf64] { |
290 | let zero = Label::new(); |
291 | let length = Label::new(); |
292 | let start = Label::new(); |
293 | let first = Label::new(); |
294 | let end = Label::new(); |
295 | let mut section = Section::with_endian(Endian::Little) |
296 | .mark(&zero) |
297 | .initial_length(format, &length, &start) |
298 | .D16(5) |
299 | .D16(0) |
300 | .mark(&first); |
301 | for i in 0..20 { |
302 | section = section.word(format.word_size(), 1000 + i); |
303 | } |
304 | section = section.mark(&end); |
305 | length.set_const((&end - &start) as u64); |
306 | |
307 | let section = section.get_contents().unwrap(); |
308 | let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian)); |
309 | let base = DebugStrOffsetsBase((&first - &zero) as usize); |
310 | |
311 | assert_eq!( |
312 | debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)), |
313 | Ok(DebugStrOffset(1000)) |
314 | ); |
315 | assert_eq!( |
316 | debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)), |
317 | Ok(DebugStrOffset(1019)) |
318 | ); |
319 | } |
320 | } |
321 | } |
322 | |