| 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 | pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self { | 
|---|
| 35 | Self::from(EndianSlice::new(slice:debug_str_section, endian)) | 
|---|
| 36 | } | 
|---|
| 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 | pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> { | 
|---|
| 53 | let input: &mut R = &mut self.debug_str_section.clone(); | 
|---|
| 54 | input.skip(len:offset.0)?; | 
|---|
| 55 | input.read_null_terminated_slice() | 
|---|
| 56 | } | 
|---|
| 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 | /// ## Example Usage | 
|---|
| 65 | /// | 
|---|
| 66 | /// ```rust,no_run | 
|---|
| 67 | /// # let load_section = || unimplemented!(); | 
|---|
| 68 | /// // Read the DWARF section into a `Vec` with whatever object loader you're using. | 
|---|
| 69 | /// let owned_section: gimli::DebugStr<Vec<u8>> = load_section(); | 
|---|
| 70 | /// // Create a reference to the DWARF section. | 
|---|
| 71 | /// let section = owned_section.borrow(|section| { | 
|---|
| 72 | ///     gimli::EndianSlice::new(§ion, gimli::LittleEndian) | 
|---|
| 73 | /// }); | 
|---|
| 74 | /// ``` | 
|---|
| 75 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R> | 
|---|
| 76 | where | 
|---|
| 77 | F: FnMut(&'a T) -> R, | 
|---|
| 78 | { | 
|---|
| 79 | borrow(&self.debug_str_section).into() | 
|---|
| 80 | } | 
|---|
| 81 | } | 
|---|
| 82 |  | 
|---|
| 83 | impl<R> Section<R> for DebugStr<R> { | 
|---|
| 84 | fn id() -> SectionId { | 
|---|
| 85 | SectionId::DebugStr | 
|---|
| 86 | } | 
|---|
| 87 |  | 
|---|
| 88 | fn reader(&self) -> &R { | 
|---|
| 89 | &self.debug_str_section | 
|---|
| 90 | } | 
|---|
| 91 | } | 
|---|
| 92 |  | 
|---|
| 93 | impl<R> From<R> for DebugStr<R> { | 
|---|
| 94 | fn from(debug_str_section: R) -> Self { | 
|---|
| 95 | DebugStr { debug_str_section } | 
|---|
| 96 | } | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 | /// The raw contents of the `.debug_str_offsets` section. | 
|---|
| 100 | #[ derive(Debug, Default, Clone, Copy)] | 
|---|
| 101 | pub struct DebugStrOffsets<R> { | 
|---|
| 102 | section: R, | 
|---|
| 103 | } | 
|---|
| 104 |  | 
|---|
| 105 | impl<R: Reader> DebugStrOffsets<R> { | 
|---|
| 106 | // TODO: add an iterator over the sets of entries in the section. | 
|---|
| 107 | // This is not needed for common usage of the section though. | 
|---|
| 108 |  | 
|---|
| 109 | /// Returns the `.debug_str` offset at the given `base` and `index`. | 
|---|
| 110 | /// | 
|---|
| 111 | /// A set of entries in the `.debug_str_offsets` section consists of a header | 
|---|
| 112 | /// followed by a series of string table offsets. | 
|---|
| 113 | /// | 
|---|
| 114 | /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE. | 
|---|
| 115 | /// This is an offset that points to the first entry following the header. | 
|---|
| 116 | /// | 
|---|
| 117 | /// The `index` is the value of a `DW_FORM_strx` attribute. | 
|---|
| 118 | /// | 
|---|
| 119 | /// The `format` must be the DWARF format of the compilation unit. This format must | 
|---|
| 120 | /// match the header. However, note that we do not parse the header to validate this, | 
|---|
| 121 | /// since locating the header is unreliable, and the GNU extensions do not emit it. | 
|---|
| 122 | pub fn get_str_offset( | 
|---|
| 123 | &self, | 
|---|
| 124 | format: Format, | 
|---|
| 125 | base: DebugStrOffsetsBase<R::Offset>, | 
|---|
| 126 | index: DebugStrOffsetsIndex<R::Offset>, | 
|---|
| 127 | ) -> Result<DebugStrOffset<R::Offset>> { | 
|---|
| 128 | let input = &mut self.section.clone(); | 
|---|
| 129 | input.skip(base.0)?; | 
|---|
| 130 | input.skip(R::Offset::from_u64( | 
|---|
| 131 | index.0.into_u64() * u64::from(format.word_size()), | 
|---|
| 132 | )?)?; | 
|---|
| 133 | input.read_offset(format).map(DebugStrOffset) | 
|---|
| 134 | } | 
|---|
| 135 | } | 
|---|
| 136 |  | 
|---|
| 137 | impl<T> DebugStrOffsets<T> { | 
|---|
| 138 | /// Create a `DebugStrOffsets` section that references the data in `self`. | 
|---|
| 139 | /// | 
|---|
| 140 | /// This is useful when `R` implements `Reader` but `T` does not. | 
|---|
| 141 | /// | 
|---|
| 142 | /// ## Example Usage | 
|---|
| 143 | /// | 
|---|
| 144 | /// ```rust,no_run | 
|---|
| 145 | /// # let load_section = || unimplemented!(); | 
|---|
| 146 | /// // Read the DWARF section into a `Vec` with whatever object loader you're using. | 
|---|
| 147 | /// let owned_section: gimli::DebugStrOffsets<Vec<u8>> = load_section(); | 
|---|
| 148 | /// // Create a reference to the DWARF section. | 
|---|
| 149 | /// let section = owned_section.borrow(|section| { | 
|---|
| 150 | ///     gimli::EndianSlice::new(§ion, gimli::LittleEndian) | 
|---|
| 151 | /// }); | 
|---|
| 152 | /// ``` | 
|---|
| 153 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R> | 
|---|
| 154 | where | 
|---|
| 155 | F: FnMut(&'a T) -> R, | 
|---|
| 156 | { | 
|---|
| 157 | borrow(&self.section).into() | 
|---|
| 158 | } | 
|---|
| 159 | } | 
|---|
| 160 |  | 
|---|
| 161 | impl<R> Section<R> for DebugStrOffsets<R> { | 
|---|
| 162 | fn id() -> SectionId { | 
|---|
| 163 | SectionId::DebugStrOffsets | 
|---|
| 164 | } | 
|---|
| 165 |  | 
|---|
| 166 | fn reader(&self) -> &R { | 
|---|
| 167 | &self.section | 
|---|
| 168 | } | 
|---|
| 169 | } | 
|---|
| 170 |  | 
|---|
| 171 | impl<R> From<R> for DebugStrOffsets<R> { | 
|---|
| 172 | fn from(section: R) -> Self { | 
|---|
| 173 | DebugStrOffsets { section } | 
|---|
| 174 | } | 
|---|
| 175 | } | 
|---|
| 176 |  | 
|---|
| 177 | impl<Offset> DebugStrOffsetsBase<Offset> | 
|---|
| 178 | where | 
|---|
| 179 | Offset: ReaderOffset, | 
|---|
| 180 | { | 
|---|
| 181 | /// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base | 
|---|
| 182 | /// for the given `Encoding` and `DwarfFileType`. | 
|---|
| 183 | pub fn default_for_encoding_and_file( | 
|---|
| 184 | encoding: Encoding, | 
|---|
| 185 | file_type: DwarfFileType, | 
|---|
| 186 | ) -> DebugStrOffsetsBase<Offset> { | 
|---|
| 187 | if encoding.version >= 5 && file_type == DwarfFileType::Dwo { | 
|---|
| 188 | // In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is | 
|---|
| 189 | // only a single unit in the file) but we must skip past the header, which the attribute | 
|---|
| 190 | // would normally do for us. | 
|---|
| 191 | // initial_length_size + version + 2 bytes of padding. | 
|---|
| 192 | DebugStrOffsetsBase(Offset::from_u8( | 
|---|
| 193 | offset:encoding.format.initial_length_size() + 2 + 2, | 
|---|
| 194 | )) | 
|---|
| 195 | } else { | 
|---|
| 196 | DebugStrOffsetsBase(Offset::from_u8(offset:0)) | 
|---|
| 197 | } | 
|---|
| 198 | } | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 | /// The `DebugLineStr` struct represents the DWARF strings | 
|---|
| 202 | /// found in the `.debug_line_str` section. | 
|---|
| 203 | #[ derive(Debug, Default, Clone, Copy)] | 
|---|
| 204 | pub struct DebugLineStr<R> { | 
|---|
| 205 | section: R, | 
|---|
| 206 | } | 
|---|
| 207 |  | 
|---|
| 208 | impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>> | 
|---|
| 209 | where | 
|---|
| 210 | Endian: Endianity, | 
|---|
| 211 | { | 
|---|
| 212 | /// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str` | 
|---|
| 213 | /// section. | 
|---|
| 214 | /// | 
|---|
| 215 | /// It is the caller's responsibility to read the `.debug_line_str` section and | 
|---|
| 216 | /// present it as a `&[u8]` slice. That means using some ELF loader on | 
|---|
| 217 | /// Linux, a Mach-O loader on macOS, etc. | 
|---|
| 218 | /// | 
|---|
| 219 | /// ``` | 
|---|
| 220 | /// use gimli::{DebugLineStr, LittleEndian}; | 
|---|
| 221 | /// | 
|---|
| 222 | /// # let buf = [0x00, 0x01, 0x02, 0x03]; | 
|---|
| 223 | /// # let read_debug_line_str_section_somehow = || &buf; | 
|---|
| 224 | /// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian); | 
|---|
| 225 | /// ``` | 
|---|
| 226 | pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self { | 
|---|
| 227 | Self::from(EndianSlice::new(slice:debug_line_str_section, endian)) | 
|---|
| 228 | } | 
|---|
| 229 | } | 
|---|
| 230 |  | 
|---|
| 231 | impl<R: Reader> DebugLineStr<R> { | 
|---|
| 232 | /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset. | 
|---|
| 233 | pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> { | 
|---|
| 234 | let input: &mut R = &mut self.section.clone(); | 
|---|
| 235 | input.skip(len:offset.0)?; | 
|---|
| 236 | input.read_null_terminated_slice() | 
|---|
| 237 | } | 
|---|
| 238 | } | 
|---|
| 239 |  | 
|---|
| 240 | impl<T> DebugLineStr<T> { | 
|---|
| 241 | /// Create a `DebugLineStr` section that references the data in `self`. | 
|---|
| 242 | /// | 
|---|
| 243 | /// This is useful when `R` implements `Reader` but `T` does not. | 
|---|
| 244 | /// | 
|---|
| 245 | /// ## Example Usage | 
|---|
| 246 | /// | 
|---|
| 247 | /// ```rust,no_run | 
|---|
| 248 | /// # let load_section = || unimplemented!(); | 
|---|
| 249 | /// // Read the DWARF section into a `Vec` with whatever object loader you're using. | 
|---|
| 250 | /// let owned_section: gimli::DebugLineStr<Vec<u8>> = load_section(); | 
|---|
| 251 | /// // Create a reference to the DWARF section. | 
|---|
| 252 | /// let section = owned_section.borrow(|section| { | 
|---|
| 253 | ///     gimli::EndianSlice::new(§ion, gimli::LittleEndian) | 
|---|
| 254 | /// }); | 
|---|
| 255 | /// ``` | 
|---|
| 256 | pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R> | 
|---|
| 257 | where | 
|---|
| 258 | F: FnMut(&'a T) -> R, | 
|---|
| 259 | { | 
|---|
| 260 | borrow(&self.section).into() | 
|---|
| 261 | } | 
|---|
| 262 | } | 
|---|
| 263 |  | 
|---|
| 264 | impl<R> Section<R> for DebugLineStr<R> { | 
|---|
| 265 | fn id() -> SectionId { | 
|---|
| 266 | SectionId::DebugLineStr | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | fn reader(&self) -> &R { | 
|---|
| 270 | &self.section | 
|---|
| 271 | } | 
|---|
| 272 | } | 
|---|
| 273 |  | 
|---|
| 274 | impl<R> From<R> for DebugLineStr<R> { | 
|---|
| 275 | fn from(section: R) -> Self { | 
|---|
| 276 | DebugLineStr { section } | 
|---|
| 277 | } | 
|---|
| 278 | } | 
|---|
| 279 |  | 
|---|
| 280 | #[ cfg(test)] | 
|---|
| 281 | mod tests { | 
|---|
| 282 | use super::*; | 
|---|
| 283 | use crate::test_util::GimliSectionMethods; | 
|---|
| 284 | use crate::LittleEndian; | 
|---|
| 285 | use test_assembler::{Endian, Label, LabelMaker, Section}; | 
|---|
| 286 |  | 
|---|
| 287 | #[ test] | 
|---|
| 288 | fn test_get_str_offset() { | 
|---|
| 289 | for format in vec![Format::Dwarf32, Format::Dwarf64] { | 
|---|
| 290 | let zero = Label::new(); | 
|---|
| 291 | let length = Label::new(); | 
|---|
| 292 | let start = Label::new(); | 
|---|
| 293 | let first = Label::new(); | 
|---|
| 294 | let end = Label::new(); | 
|---|
| 295 | let mut section = Section::with_endian(Endian::Little) | 
|---|
| 296 | .mark(&zero) | 
|---|
| 297 | .initial_length(format, &length, &start) | 
|---|
| 298 | .D16(5) | 
|---|
| 299 | .D16(0) | 
|---|
| 300 | .mark(&first); | 
|---|
| 301 | for i in 0..20 { | 
|---|
| 302 | section = section.word(format.word_size(), 1000 + i); | 
|---|
| 303 | } | 
|---|
| 304 | section = section.mark(&end); | 
|---|
| 305 | length.set_const((&end - &start) as u64); | 
|---|
| 306 |  | 
|---|
| 307 | let section = section.get_contents().unwrap(); | 
|---|
| 308 | let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian)); | 
|---|
| 309 | let base = DebugStrOffsetsBase((&first - &zero) as usize); | 
|---|
| 310 |  | 
|---|
| 311 | assert_eq!( | 
|---|
| 312 | debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)), | 
|---|
| 313 | Ok(DebugStrOffset(1000)) | 
|---|
| 314 | ); | 
|---|
| 315 | assert_eq!( | 
|---|
| 316 | debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)), | 
|---|
| 317 | Ok(DebugStrOffset(1019)) | 
|---|
| 318 | ); | 
|---|
| 319 | } | 
|---|
| 320 | } | 
|---|
| 321 | } | 
|---|
| 322 |  | 
|---|