aboutsummaryrefslogtreecommitdiff
path: root/vendor/gimli/src/read/str.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gimli/src/read/str.rs')
-rw-r--r--vendor/gimli/src/read/str.rs321
1 files changed, 321 insertions, 0 deletions
diff --git a/vendor/gimli/src/read/str.rs b/vendor/gimli/src/read/str.rs
new file mode 100644
index 0000000..c6b87d8
--- /dev/null
+++ b/vendor/gimli/src/read/str.rs
@@ -0,0 +1,321 @@
+use crate::common::{
+ DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType,
+ Encoding, SectionId,
+};
+use crate::endianity::Endianity;
+use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section};
+use crate::Format;
+
+/// The `DebugStr` struct represents the DWARF strings
+/// found in the `.debug_str` section.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct DebugStr<R> {
+ debug_str_section: R,
+}
+
+impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>>
+where
+ Endian: Endianity,
+{
+ /// Construct a new `DebugStr` instance from the data in the `.debug_str`
+ /// section.
+ ///
+ /// It is the caller's responsibility to read the `.debug_str` section and
+ /// present it as a `&[u8]` slice. That means using some ELF loader on
+ /// Linux, a Mach-O loader on macOS, etc.
+ ///
+ /// ```
+ /// use gimli::{DebugStr, LittleEndian};
+ ///
+ /// # let buf = [0x00, 0x01, 0x02, 0x03];
+ /// # let read_debug_str_section_somehow = || &buf;
+ /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
+ /// ```
+ pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self {
+ Self::from(EndianSlice::new(debug_str_section, endian))
+ }
+}
+
+impl<R: Reader> DebugStr<R> {
+ /// Lookup a string from the `.debug_str` section by DebugStrOffset.
+ ///
+ /// ```
+ /// use gimli::{DebugStr, DebugStrOffset, LittleEndian};
+ ///
+ /// # let buf = [0x01, 0x02, 0x00];
+ /// # let offset = DebugStrOffset(0);
+ /// # let read_debug_str_section_somehow = || &buf;
+ /// # let debug_str_offset_somehow = || offset;
+ /// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
+ /// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow()));
+ /// ```
+ pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> {
+ let input = &mut self.debug_str_section.clone();
+ input.skip(offset.0)?;
+ input.read_null_terminated_slice()
+ }
+}
+
+impl<T> DebugStr<T> {
+ /// Create a `DebugStr` section that references the data in `self`.
+ ///
+ /// This is useful when `R` implements `Reader` but `T` does not.
+ ///
+ /// ## Example Usage
+ ///
+ /// ```rust,no_run
+ /// # let load_section = || unimplemented!();
+ /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
+ /// let owned_section: gimli::DebugStr<Vec<u8>> = load_section();
+ /// // Create a reference to the DWARF section.
+ /// let section = owned_section.borrow(|section| {
+ /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
+ /// });
+ /// ```
+ pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R>
+ where
+ F: FnMut(&'a T) -> R,
+ {
+ borrow(&self.debug_str_section).into()
+ }
+}
+
+impl<R> Section<R> for DebugStr<R> {
+ fn id() -> SectionId {
+ SectionId::DebugStr
+ }
+
+ fn reader(&self) -> &R {
+ &self.debug_str_section
+ }
+}
+
+impl<R> From<R> for DebugStr<R> {
+ fn from(debug_str_section: R) -> Self {
+ DebugStr { debug_str_section }
+ }
+}
+
+/// The raw contents of the `.debug_str_offsets` section.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct DebugStrOffsets<R> {
+ section: R,
+}
+
+impl<R: Reader> DebugStrOffsets<R> {
+ // TODO: add an iterator over the sets of entries in the section.
+ // This is not needed for common usage of the section though.
+
+ /// Returns the `.debug_str` offset at the given `base` and `index`.
+ ///
+ /// A set of entries in the `.debug_str_offsets` section consists of a header
+ /// followed by a series of string table offsets.
+ ///
+ /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE.
+ /// This is an offset that points to the first entry following the header.
+ ///
+ /// The `index` is the value of a `DW_FORM_strx` attribute.
+ ///
+ /// The `format` must be the DWARF format of the compilation unit. This format must
+ /// match the header. However, note that we do not parse the header to validate this,
+ /// since locating the header is unreliable, and the GNU extensions do not emit it.
+ pub fn get_str_offset(
+ &self,
+ format: Format,
+ base: DebugStrOffsetsBase<R::Offset>,
+ index: DebugStrOffsetsIndex<R::Offset>,
+ ) -> Result<DebugStrOffset<R::Offset>> {
+ let input = &mut self.section.clone();
+ input.skip(base.0)?;
+ input.skip(R::Offset::from_u64(
+ index.0.into_u64() * u64::from(format.word_size()),
+ )?)?;
+ input.read_offset(format).map(DebugStrOffset)
+ }
+}
+
+impl<T> DebugStrOffsets<T> {
+ /// Create a `DebugStrOffsets` section that references the data in `self`.
+ ///
+ /// This is useful when `R` implements `Reader` but `T` does not.
+ ///
+ /// ## Example Usage
+ ///
+ /// ```rust,no_run
+ /// # let load_section = || unimplemented!();
+ /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
+ /// let owned_section: gimli::DebugStrOffsets<Vec<u8>> = load_section();
+ /// // Create a reference to the DWARF section.
+ /// let section = owned_section.borrow(|section| {
+ /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
+ /// });
+ /// ```
+ pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R>
+ where
+ F: FnMut(&'a T) -> R,
+ {
+ borrow(&self.section).into()
+ }
+}
+
+impl<R> Section<R> for DebugStrOffsets<R> {
+ fn id() -> SectionId {
+ SectionId::DebugStrOffsets
+ }
+
+ fn reader(&self) -> &R {
+ &self.section
+ }
+}
+
+impl<R> From<R> for DebugStrOffsets<R> {
+ fn from(section: R) -> Self {
+ DebugStrOffsets { section }
+ }
+}
+
+impl<Offset> DebugStrOffsetsBase<Offset>
+where
+ Offset: ReaderOffset,
+{
+ /// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base
+ /// for the given `Encoding` and `DwarfFileType`.
+ pub fn default_for_encoding_and_file(
+ encoding: Encoding,
+ file_type: DwarfFileType,
+ ) -> DebugStrOffsetsBase<Offset> {
+ if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
+ // In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is
+ // only a single unit in the file) but we must skip past the header, which the attribute
+ // would normally do for us.
+ // initial_length_size + version + 2 bytes of padding.
+ DebugStrOffsetsBase(Offset::from_u8(
+ encoding.format.initial_length_size() + 2 + 2,
+ ))
+ } else {
+ DebugStrOffsetsBase(Offset::from_u8(0))
+ }
+ }
+}
+
+/// The `DebugLineStr` struct represents the DWARF strings
+/// found in the `.debug_line_str` section.
+#[derive(Debug, Default, Clone, Copy)]
+pub struct DebugLineStr<R> {
+ section: R,
+}
+
+impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>>
+where
+ Endian: Endianity,
+{
+ /// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str`
+ /// section.
+ ///
+ /// It is the caller's responsibility to read the `.debug_line_str` section and
+ /// present it as a `&[u8]` slice. That means using some ELF loader on
+ /// Linux, a Mach-O loader on macOS, etc.
+ ///
+ /// ```
+ /// use gimli::{DebugLineStr, LittleEndian};
+ ///
+ /// # let buf = [0x00, 0x01, 0x02, 0x03];
+ /// # let read_debug_line_str_section_somehow = || &buf;
+ /// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian);
+ /// ```
+ pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self {
+ Self::from(EndianSlice::new(debug_line_str_section, endian))
+ }
+}
+
+impl<R: Reader> DebugLineStr<R> {
+ /// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset.
+ pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
+ let input = &mut self.section.clone();
+ input.skip(offset.0)?;
+ input.read_null_terminated_slice()
+ }
+}
+
+impl<T> DebugLineStr<T> {
+ /// Create a `DebugLineStr` section that references the data in `self`.
+ ///
+ /// This is useful when `R` implements `Reader` but `T` does not.
+ ///
+ /// ## Example Usage
+ ///
+ /// ```rust,no_run
+ /// # let load_section = || unimplemented!();
+ /// // Read the DWARF section into a `Vec` with whatever object loader you're using.
+ /// let owned_section: gimli::DebugLineStr<Vec<u8>> = load_section();
+ /// // Create a reference to the DWARF section.
+ /// let section = owned_section.borrow(|section| {
+ /// gimli::EndianSlice::new(&section, gimli::LittleEndian)
+ /// });
+ /// ```
+ pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R>
+ where
+ F: FnMut(&'a T) -> R,
+ {
+ borrow(&self.section).into()
+ }
+}
+
+impl<R> Section<R> for DebugLineStr<R> {
+ fn id() -> SectionId {
+ SectionId::DebugLineStr
+ }
+
+ fn reader(&self) -> &R {
+ &self.section
+ }
+}
+
+impl<R> From<R> for DebugLineStr<R> {
+ fn from(section: R) -> Self {
+ DebugLineStr { section }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::test_util::GimliSectionMethods;
+ use crate::LittleEndian;
+ use test_assembler::{Endian, Label, LabelMaker, Section};
+
+ #[test]
+ fn test_get_str_offset() {
+ for format in vec![Format::Dwarf32, Format::Dwarf64] {
+ let zero = Label::new();
+ let length = Label::new();
+ let start = Label::new();
+ let first = Label::new();
+ let end = Label::new();
+ let mut section = Section::with_endian(Endian::Little)
+ .mark(&zero)
+ .initial_length(format, &length, &start)
+ .D16(5)
+ .D16(0)
+ .mark(&first);
+ for i in 0..20 {
+ section = section.word(format.word_size(), 1000 + i);
+ }
+ section = section.mark(&end);
+ length.set_const((&end - &start) as u64);
+
+ let section = section.get_contents().unwrap();
+ let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(&section, LittleEndian));
+ let base = DebugStrOffsetsBase((&first - &zero) as usize);
+
+ assert_eq!(
+ debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)),
+ Ok(DebugStrOffset(1000))
+ );
+ assert_eq!(
+ debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)),
+ Ok(DebugStrOffset(1019))
+ );
+ }
+ }
+}