]> git.proxmox.com Git - rustc.git/blob - vendor/gimli/src/read/str.rs
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / vendor / gimli / src / read / str.rs
1 use crate::common::{
2 DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, SectionId,
3 };
4 use crate::endianity::Endianity;
5 use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section};
6 use crate::Format;
7
8 /// The `DebugStr` struct represents the DWARF strings
9 /// found in the `.debug_str` section.
10 #[derive(Debug, Default, Clone, Copy)]
11 pub struct DebugStr<R> {
12 debug_str_section: R,
13 }
14
15 impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>>
16 where
17 Endian: Endianity,
18 {
19 /// Construct a new `DebugStr` instance from the data in the `.debug_str`
20 /// section.
21 ///
22 /// It is the caller's responsibility to read the `.debug_str` section and
23 /// present it as a `&[u8]` slice. That means using some ELF loader on
24 /// Linux, a Mach-O loader on OSX, etc.
25 ///
26 /// ```
27 /// use gimli::{DebugStr, LittleEndian};
28 ///
29 /// # let buf = [0x00, 0x01, 0x02, 0x03];
30 /// # let read_debug_str_section_somehow = || &buf;
31 /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
32 /// ```
33 pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self {
34 Self::from(EndianSlice::new(debug_str_section, endian))
35 }
36 }
37
38 impl<R: Reader> DebugStr<R> {
39 /// Lookup a string from the `.debug_str` section by DebugStrOffset.
40 ///
41 /// ```
42 /// use gimli::{DebugStr, DebugStrOffset, LittleEndian};
43 ///
44 /// # let buf = [0x01, 0x02, 0x00];
45 /// # let offset = DebugStrOffset(0);
46 /// # let read_debug_str_section_somehow = || &buf;
47 /// # let debug_str_offset_somehow = || offset;
48 /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
49 /// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow()));
50 /// ```
51 pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> {
52 let input = &mut self.debug_str_section.clone();
53 input.skip(offset.0)?;
54 input.read_null_terminated_slice()
55 }
56 }
57
58 impl<T> DebugStr<T> {
59 /// Create a `DebugStr` section that references the data in `self`.
60 ///
61 /// This is useful when `R` implements `Reader` but `T` does not.
62 ///
63 /// ## Example Usage
64 ///
65 /// ```rust,no_run
66 /// # let load_section = || unimplemented!();
67 /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
68 /// let owned_section: gimli::DebugStr<Vec<u8>> = load_section();
69 /// // Create a reference to the DWARF section.
70 /// let section = owned_section.borrow(|section| {
71 /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
72 /// });
73 /// ```
74 pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R>
75 where
76 F: FnMut(&'a T) -> R,
77 {
78 borrow(&self.debug_str_section).into()
79 }
80 }
81
82 impl<R> Section<R> for DebugStr<R> {
83 fn id() -> SectionId {
84 SectionId::DebugStr
85 }
86
87 fn reader(&self) -> &R {
88 &self.debug_str_section
89 }
90 }
91
92 impl<R> From<R> for DebugStr<R> {
93 fn from(debug_str_section: R) -> Self {
94 DebugStr { debug_str_section }
95 }
96 }
97
98 /// The raw contents of the `.debug_str_offsets` section.
99 #[derive(Debug, Default, Clone, Copy)]
100 pub struct DebugStrOffsets<R> {
101 section: R,
102 }
103
104 impl<R: Reader> DebugStrOffsets<R> {
105 // TODO: add an iterator over the sets of entries in the section.
106 // This is not needed for common usage of the section though.
107
108 /// Returns the `.debug_str` offset at the given `base` and `index`.
109 ///
110 /// A set of entries in the `.debug_str_offsets` section consists of a header
111 /// followed by a series of string table offsets.
112 ///
113 /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE.
114 /// This is an offset that points to the first entry following the header.
115 ///
116 /// The `index` is the value of a `DW_FORM_strx` attribute.
117 ///
118 /// The `format` must be the DWARF format of the compilation unit. This format must
119 /// match the header. However, note that we do not parse the header to validate this,
120 /// since locating the header is unreliable, and the GNU extensions do not emit it.
121 pub fn get_str_offset(
122 &self,
123 format: Format,
124 base: DebugStrOffsetsBase<R::Offset>,
125 index: DebugStrOffsetsIndex<R::Offset>,
126 ) -> Result<DebugStrOffset<R::Offset>> {
127 let input = &mut self.section.clone();
128 input.skip(base.0)?;
129 input.skip(R::Offset::from_u64(
130 index.0.into_u64() * u64::from(format.word_size()),
131 )?)?;
132 input.read_offset(format).map(DebugStrOffset)
133 }
134 }
135
136 impl<T> DebugStrOffsets<T> {
137 /// Create a `DebugStrOffsets` section that references the data in `self`.
138 ///
139 /// This is useful when `R` implements `Reader` but `T` does not.
140 ///
141 /// ## Example Usage
142 ///
143 /// ```rust,no_run
144 /// # let load_section = || unimplemented!();
145 /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
146 /// let owned_section: gimli::DebugStrOffsets<Vec<u8>> = load_section();
147 /// // Create a reference to the DWARF section.
148 /// let section = owned_section.borrow(|section| {
149 /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
150 /// });
151 /// ```
152 pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R>
153 where
154 F: FnMut(&'a T) -> R,
155 {
156 borrow(&self.section).into()
157 }
158 }
159
160 impl<R> Section<R> for DebugStrOffsets<R> {
161 fn id() -> SectionId {
162 SectionId::DebugStrOffsets
163 }
164
165 fn reader(&self) -> &R {
166 &self.section
167 }
168 }
169
170 impl<R> From<R> for DebugStrOffsets<R> {
171 fn from(section: R) -> Self {
172 DebugStrOffsets { section }
173 }
174 }
175
176 /// The `DebugLineStr` struct represents the DWARF strings
177 /// found in the `.debug_line_str` section.
178 #[derive(Debug, Default, Clone, Copy)]
179 pub struct DebugLineStr<R> {
180 section: R,
181 }
182
183 impl<R: Reader> DebugLineStr<R> {
184 /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset.
185 pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
186 let input = &mut self.section.clone();
187 input.skip(offset.0)?;
188 input.read_null_terminated_slice()
189 }
190 }
191
192 impl<T> DebugLineStr<T> {
193 /// Create a `DebugLineStr` section that references the data in `self`.
194 ///
195 /// This is useful when `R` implements `Reader` but `T` does not.
196 ///
197 /// ## Example Usage
198 ///
199 /// ```rust,no_run
200 /// # let load_section = || unimplemented!();
201 /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
202 /// let owned_section: gimli::DebugLineStr<Vec<u8>> = load_section();
203 /// // Create a reference to the DWARF section.
204 /// let section = owned_section.borrow(|section| {
205 /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
206 /// });
207 /// ```
208 pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R>
209 where
210 F: FnMut(&'a T) -> R,
211 {
212 borrow(&self.section).into()
213 }
214 }
215
216 impl<R> Section<R> for DebugLineStr<R> {
217 fn id() -> SectionId {
218 SectionId::DebugLineStr
219 }
220
221 fn reader(&self) -> &R {
222 &self.section
223 }
224 }
225
226 impl<R> From<R> for DebugLineStr<R> {
227 fn from(section: R) -> Self {
228 DebugLineStr { section }
229 }
230 }
231
232 #[cfg(test)]
233 mod tests {
234 use super::*;
235 use crate::test_util::GimliSectionMethods;
236 use crate::LittleEndian;
237 use test_assembler::{Endian, Label, LabelMaker, Section};
238
239 #[test]
240 fn test_get_str_offset() {
241 for format in vec![Format::Dwarf32, Format::Dwarf64] {
242 let zero = Label::new();
243 let length = Label::new();
244 let start = Label::new();
245 let first = Label::new();
246 let end = Label::new();
247 let mut section = Section::with_endian(Endian::Little)
248 .mark(&zero)
249 .initial_length(format, &length, &start)
250 .D16(5)
251 .D16(0)
252 .mark(&first);
253 for i in 0..20 {
254 section = section.word(format.word_size(), 1000 + i);
255 }
256 section = section.mark(&end);
257 length.set_const((&end - &start) as u64);
258
259 let section = section.get_contents().unwrap();
260 let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(&section, LittleEndian));
261 let base = DebugStrOffsetsBase((&first - &zero) as usize);
262
263 assert_eq!(
264 debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)),
265 Ok(DebugStrOffset(1000))
266 );
267 assert_eq!(
268 debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)),
269 Ok(DebugStrOffset(1019))
270 );
271 }
272 }
273 }