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;
89/// 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}
1516impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>>
17where
18Endian: 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 /// ```
34pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self {
35Self::from(EndianSlice::new(debug_str_section, endian))
36 }
37}
3839impl<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 /// ```
52pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> {
53let input = &mut self.debug_str_section.clone();
54 input.skip(offset.0)?;
55 input.read_null_terminated_slice()
56 }
57}
5859impl<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`.
65pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R>
66where
67F: FnMut(&'a T) -> R,
68 {
69 borrow(&self.debug_str_section).into()
70 }
71}
7273impl<R> Section<R> for DebugStr<R> {
74fn id() -> SectionId {
75 SectionId::DebugStr
76 }
7778fn reader(&self) -> &R {
79&self.debug_str_section
80 }
81}
8283impl<R> From<R> for DebugStr<R> {
84fn from(debug_str_section: R) -> Self {
85 DebugStr { debug_str_section }
86 }
87}
8889/// The raw contents of the `.debug_str_offsets` section.
90#[derive(Debug, Default, Clone, Copy)]
91pub struct DebugStrOffsets<R> {
92 section: R,
93}
9495impl<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.
9899/// 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.
112pub fn get_str_offset(
113&self,
114 format: Format,
115 base: DebugStrOffsetsBase<R::Offset>,
116 index: DebugStrOffsetsIndex<R::Offset>,
117 ) -> Result<DebugStrOffset<R::Offset>> {
118let 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}
126127impl<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`.
133pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R>
134where
135F: FnMut(&'a T) -> R,
136 {
137 borrow(&self.section).into()
138 }
139}
140141impl<R> Section<R> for DebugStrOffsets<R> {
142fn id() -> SectionId {
143 SectionId::DebugStrOffsets
144 }
145146fn reader(&self) -> &R {
147&self.section
148 }
149}
150151impl<R> From<R> for DebugStrOffsets<R> {
152fn from(section: R) -> Self {
153 DebugStrOffsets { section }
154 }
155}
156157impl<Offset> DebugStrOffsetsBase<Offset>
158where
159Offset: ReaderOffset,
160{
161/// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base
162 /// for the given `Encoding` and `DwarfFileType`.
163pub fn default_for_encoding_and_file(
164 encoding: Encoding,
165 file_type: DwarfFileType,
166 ) -> DebugStrOffsetsBase<Offset> {
167if 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.
172DebugStrOffsetsBase(Offset::from_u8(
173 encoding.format.initial_length_size() + 2 + 2,
174 ))
175 } else {
176 DebugStrOffsetsBase(Offset::from_u8(0))
177 }
178 }
179}
180181/// 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}
187188impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>>
189where
190Endian: 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 /// ```
206pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self {
207Self::from(EndianSlice::new(debug_line_str_section, endian))
208 }
209}
210211impl<R: Reader> DebugLineStr<R> {
212/// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset.
213pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
214let input = &mut self.section.clone();
215 input.skip(offset.0)?;
216 input.read_null_terminated_slice()
217 }
218}
219220impl<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`.
226pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R>
227where
228F: FnMut(&'a T) -> R,
229 {
230 borrow(&self.section).into()
231 }
232}
233234impl<R> Section<R> for DebugLineStr<R> {
235fn id() -> SectionId {
236 SectionId::DebugLineStr
237 }
238239fn reader(&self) -> &R {
240&self.section
241 }
242}
243244impl<R> From<R> for DebugLineStr<R> {
245fn from(section: R) -> Self {
246 DebugLineStr { section }
247 }
248}
249250#[cfg(test)]
251mod tests {
252use super::*;
253use crate::test_util::GimliSectionMethods;
254use crate::LittleEndian;
255use test_assembler::{Endian, Label, LabelMaker, Section};
256257#[test]
258fn test_get_str_offset() {
259for format in [Format::Dwarf32, Format::Dwarf64] {
260let zero = Label::new();
261let length = Label::new();
262let start = Label::new();
263let first = Label::new();
264let end = Label::new();
265let 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);
271for 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);
276277let section = section.get_contents().unwrap();
278let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian));
279let base = DebugStrOffsetsBase((&first - &zero) as usize);
280281assert_eq!(
282 debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)),
283Ok(DebugStrOffset(1000))
284 );
285assert_eq!(
286 debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)),
287Ok(DebugStrOffset(1019))
288 );
289 }
290 }
291}