/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_strUnexecuted 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>>>::idUnexecuted 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>>>::fromUnexecuted 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_offsetUnexecuted 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>>>::idUnexecuted 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>>>::readerUnexecuted 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>>>::fromUnexecuted 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_fileUnexecuted 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_strUnexecuted 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>>>::idUnexecuted 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>>>::fromUnexecuted 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(§ion, 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 |  | } |