Coverage Report

Created: 2024-10-16 07:58

/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(&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
}