1use crate::common::{
2 DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType,
3 Encoding, SectionId,
4};
5use crate::endianity::Endianity;
6use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section};
7use crate::Format;
8
9/// The `DebugStr` struct represents the DWARF strings
10/// found in the `.debug_str` section.
11#[derive(Debug, Default, Clone, Copy)]
12pub struct DebugStr<R> {
13 debug_str_section: R,
14}
15
16impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>>
17where
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
39impl<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
59impl<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(&section, 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
83impl<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
93impl<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)]
101pub struct DebugStrOffsets<R> {
102 section: R,
103}
104
105impl<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
137impl<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(&section, 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
161impl<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
171impl<R> From<R> for DebugStrOffsets<R> {
172 fn from(section: R) -> Self {
173 DebugStrOffsets { section }
174 }
175}
176
177impl<Offset> DebugStrOffsetsBase<Offset>
178where
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)]
204pub struct DebugLineStr<R> {
205 section: R,
206}
207
208impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>>
209where
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
231impl<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
240impl<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(&section, 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
264impl<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
274impl<R> From<R> for DebugLineStr<R> {
275 fn from(section: R) -> Self {
276 DebugLineStr { section }
277 }
278}
279
280#[cfg(test)]
281mod 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(&section, 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