gimli/read/
str.rs

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(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 self.debug_str_section.clone();
54        input.skip(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    /// Used by `DwarfSections::borrow`.
65    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R>
66    where
67        F: FnMut(&'a T) -> R,
68    {
69        borrow(&self.debug_str_section).into()
70    }
71}
72
73impl<R> Section<R> for DebugStr<R> {
74    fn id() -> SectionId {
75        SectionId::DebugStr
76    }
77
78    fn reader(&self) -> &R {
79        &self.debug_str_section
80    }
81}
82
83impl<R> From<R> for DebugStr<R> {
84    fn from(debug_str_section: R) -> Self {
85        DebugStr { debug_str_section }
86    }
87}
88
89/// The raw contents of the `.debug_str_offsets` section.
90#[derive(Debug, Default, Clone, Copy)]
91pub struct DebugStrOffsets<R> {
92    section: R,
93}
94
95impl<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    pub fn get_str_offset(
113        &self,
114        format: Format,
115        base: DebugStrOffsetsBase<R::Offset>,
116        index: DebugStrOffsetsIndex<R::Offset>,
117    ) -> Result<DebugStrOffset<R::Offset>> {
118        let input = &mut self.section.clone();
119        input.skip(base.0)?;
120        input.skip(R::Offset::from_u64(
121            index.0.into_u64() * u64::from(format.word_size()),
122        )?)?;
123        input.read_offset(format).map(DebugStrOffset)
124    }
125}
126
127impl<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    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R>
134    where
135        F: FnMut(&'a T) -> R,
136    {
137        borrow(&self.section).into()
138    }
139}
140
141impl<R> Section<R> for DebugStrOffsets<R> {
142    fn id() -> SectionId {
143        SectionId::DebugStrOffsets
144    }
145
146    fn reader(&self) -> &R {
147        &self.section
148    }
149}
150
151impl<R> From<R> for DebugStrOffsets<R> {
152    fn from(section: R) -> Self {
153        DebugStrOffsets { section }
154    }
155}
156
157impl<Offset> DebugStrOffsetsBase<Offset>
158where
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    pub fn default_for_encoding_and_file(
164        encoding: Encoding,
165        file_type: DwarfFileType,
166    ) -> DebugStrOffsetsBase<Offset> {
167        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            DebugStrOffsetsBase(Offset::from_u8(
173                encoding.format.initial_length_size() + 2 + 2,
174            ))
175        } else {
176            DebugStrOffsetsBase(Offset::from_u8(0))
177        }
178    }
179}
180
181/// The `DebugLineStr` struct represents the DWARF strings
182/// found in the `.debug_line_str` section.
183#[derive(Debug, Default, Clone, Copy)]
184pub struct DebugLineStr<R> {
185    section: R,
186}
187
188impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>>
189where
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    pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self {
207        Self::from(EndianSlice::new(debug_line_str_section, endian))
208    }
209}
210
211impl<R: Reader> DebugLineStr<R> {
212    /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset.
213    pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
214        let input = &mut self.section.clone();
215        input.skip(offset.0)?;
216        input.read_null_terminated_slice()
217    }
218}
219
220impl<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    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R>
227    where
228        F: FnMut(&'a T) -> R,
229    {
230        borrow(&self.section).into()
231    }
232}
233
234impl<R> Section<R> for DebugLineStr<R> {
235    fn id() -> SectionId {
236        SectionId::DebugLineStr
237    }
238
239    fn reader(&self) -> &R {
240        &self.section
241    }
242}
243
244impl<R> From<R> for DebugLineStr<R> {
245    fn from(section: R) -> Self {
246        DebugLineStr { section }
247    }
248}
249
250#[cfg(test)]
251mod 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(&section, 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}