Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  macros.rs

  Sprache: Rust
 

use crate::common::{DebugMacinfoOffset, SectionId};
use crate::endianity::Endianity;
use crate::read::{EndianSlice, Reader, ReaderOffset, Section, UnitRef};
use crate::{
    constants, DebugLineOffset, DebugMacroOffset, DebugStrOffset, DebugStrOffsetsIndex, DwMacinfo,
    DwMacro, Error, Format, Result,
};

/// The raw contents of the `.debug_macinfo` section.
#[derive(Debug, Default, Clone, Copy)]
pub struct DebugMacinfo<R> {
    pub(crate) section: R,
}

impl<'input, Endian> DebugMacinfo<EndianSlice<'input, Endian>>
where
    Endian: Endianity,
{
    /// Construct a new `DebugMacinfo` instance from the data in the `.debug_macinfo`
    /// section.
    ///
    /// It is the caller's responsibility to read the `.debug_macinfo` 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::{DebugMacinfo, LittleEndian};
    ///
    /// # let buf = [1, 0, 95, 95, 83, 84, 68, 67, 95, 95, 32, 49, 0];
    /// # let read_section_somehow = || &buf;
    /// let debug_str = DebugMacinfo::new(read_section_somehow(), LittleEndian);
    /// ```
    pub fn new(macinfo_section: &'input [u8], endian: Endian) -> Self {
        Self::from(EndianSlice::new(macinfo_section, endian))
    }
}

impl<R: Reader> DebugMacinfo<R> {
    /// Look up a macro reference the `.debug_macinfo` section by DebugMacinfoOffset.
    ///
    /// A macinfo offset points to a list of macro information entries in the `.debug_macinfo` section.
    /// To handle this, the function returns an iterator.
    ///
    /// ```
    /// use gimli::{DebugMacinfo, DebugMacinfoOffset, LittleEndian};
    ///
    /// # fn main() -> Result<(), gimli::Error> {
    /// # let buf = [1, 0, 95, 95, 83, 84, 68, 67, 95, 95, 32, 49, 0, 0];
    /// # let offset = DebugMacinfoOffset(0);
    /// # let read_section_somehow = || &buf;
    /// # let debug_macinfo_offset_somehow = || offset;
    /// let debug_macinfo = DebugMacinfo::new(read_section_somehow(), LittleEndian);
    /// let mut iter = debug_macinfo.get_macinfo(debug_macinfo_offset_somehow())?;
    /// while let Some(macinfo) = iter.next()? {
    ///     println!("Found macro info {:?}", macinfo);
    /// }
    /// # Ok(()) }
    /// ```
    pub fn get_macinfo(&self, offset: DebugMacinfoOffset<R::Offset>) -> Result<MacroIter<R>> {
        let mut input = self.section.clone();
        input.skip(offset.0)?;
        Ok(MacroIter {
            input,
            format: Format::Dwarf32,
            is_macro: false,
        })
    }
}

impl<T> DebugMacinfo<T> {
    /// Create a `DebugMacinfo` section that references the data in `self`.
    ///
    /// This is useful when `R` implements `Reader` but `T` does not.
    ///
    /// Used by `DwarfSections::borrow`.
    pub fn borrow<'a, F, R>(&'selfmut borrow: F) -> DebugMacinfo<R>
    where
        F: FnMut(&'a T) -> R,
    {
        borrow(&self.section).into()
    }
}

impl<R> Section<R> for DebugMacinfo<R> {
    fn id() -> SectionId {
        SectionId::DebugMacinfo
    }

    fn reader(&self) -> &R {
        &self.section
    }
}

impl<R> From<R> for DebugMacinfo<R> {
    fn from(macinfo_section: R) -> Self {
        DebugMacinfo {
            section: macinfo_section,
        }
    }
}

/// The raw contents of the `.debug_macro` section.
#[derive(Debug, Default, Clone, Copy)]
pub struct DebugMacro<R> {
    pub(crate) section: R,
}

impl<'input, Endian> DebugMacro<EndianSlice<'input, Endian>>
where
    Endian: Endianity,
{
    /// Construct a new `DebugMacro` instance from the data in the `.debug_macro`
    /// section.
    ///
    /// It is the caller's responsibility to read the `.debug_macro` 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::{DebugMacro, LittleEndian};
    ///
    /// # let buf = [1, 0, 95, 95, 83, 84, 68, 67, 95, 95, 32, 49, 0];
    /// # let read_section_somehow = || &buf;
    /// let debug_str = DebugMacro::new(read_section_somehow(), LittleEndian);
    /// ```
    pub fn new(macro_section: &'input [u8], endian: Endian) -> Self {
        Self::from(EndianSlice::new(macro_section, endian))
    }
}

impl<R: Reader> DebugMacro<R> {
    /// Look up a macro reference the `.debug_macinfo` section by DebugMacroOffset.
    ///
    /// A macinfo offset points to a list of macro information entries in the `.debug_macinfo` section.
    /// To handle this, the function returns an iterator.
    ///
    /// ```
    /// use gimli::{DebugMacro, DebugMacroOffset, LittleEndian};
    ///
    /// # fn main() -> Result<(), gimli::Error> {
    /// # let buf = [0x05, 0x00, 0x00, 0x01, 0x00, 0x5f, 0x5f, 0x53, 0x54, 0x44, 0x43, 0x5f, 0x5f, 0x20, 0x31, 0x00, 0x00];
    /// # let offset = DebugMacroOffset(0);
    /// # let read_section_somehow = || &buf;
    /// # let debug_macro_offset_somehow = || offset;
    /// let debug_macro = DebugMacro::new(read_section_somehow(), LittleEndian);
    /// let mut iter = debug_macro.get_macros(debug_macro_offset_somehow())?;
    /// while let Some(cur_macro) = iter.next()? {
    ///     println!("Found macro info {:?}", cur_macro);
    /// }
    /// # Ok(()) }
    /// ```
    pub fn get_macros(&self, offset: DebugMacroOffset<R::Offset>) -> Result<MacroIter<R>> {
        let mut input = self.section.clone();
        input.skip(offset.0)?;
        let header = MacroUnitHeader::parse(&mut input)?;
        Ok(MacroIter {
            input,
            format: header.format(),
            is_macro: true,
        })
    }
}

impl<T> DebugMacro<T> {
    /// Create a `DebugMacro` section that references the data in `self`.
    ///
    /// This is useful when `R` implements `Reader` but `T` does not.
    ///
    /// Used by `DwarfSections::borrow`.
    pub fn borrow<'a, F, R>(&'selfmut borrow: F) -> DebugMacro<R>
    where
        F: FnMut(&'a T) -> R,
    {
        borrow(&self.section).into()
    }
}

impl<R> Section<R> for DebugMacro<R> {
    fn id() -> SectionId {
        SectionId::DebugMacro
    }

    fn reader(&self) -> &R {
        &self.section
    }
}

impl<R> From<R> for DebugMacro<R> {
    fn from(macro_section: R) -> Self {
        DebugMacro {
            section: macro_section,
        }
    }
}

#[derive(Debug, Clone)]
struct MacroUnitHeader<R: Reader> {
    /// The version of the macro unit header. At the moment only version 5 is defined.
    _version: u16,
    flags: u8,
    _debug_line_offset: DebugLineOffset<R::Offset>,
}

impl<R: Reader> MacroUnitHeader<R> {
    const OFFSET_SIZE_FLAG: u8 = 0b0000_0001;
    const DEBUG_LINE_OFFSET_FLAG: u8 = 0b0000_0010;
    const OPCODE_OPERANDS_TABLE_FLAG: u8 = 0b0000_0100;

    fn parse(input: &mut R) -> Result<Self> {
        let version = input.read_u16()?;
        let flags = input.read_u8()?;
        let format = if flags & Self::OFFSET_SIZE_FLAG == 0 {
            Format::Dwarf32
        } else {
            Format::Dwarf64
        };
        let _debug_line_offset = if flags & Self::DEBUG_LINE_OFFSET_FLAG != 0 {
            DebugLineOffset(input.read_offset(format)?)
        } else {
            DebugLineOffset(R::Offset::from_u64(0)?)
        };
        // if the opcode operands table flag is set, there is a table in the header which currently isn't parsed
        if flags & Self::OPCODE_OPERANDS_TABLE_FLAG != 0 {
            return Err(Error::UnsupportedOpcodeOperandsTable);
        }
        Ok(MacroUnitHeader {
            _version: version,
            flags,
            _debug_line_offset,
        })
    }

    fn format(&self) -> Format {
        if self.flags & Self::OFFSET_SIZE_FLAG == 0 {
            Format::Dwarf32
        } else {
            Format::Dwarf64
        }
    }
}

/// A string in a macro entry.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MacroString<R, Offset = <R as Reader>::Offset>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    /// The string is directly embedded in the macro entry
    Direct(R),
    /// The macro refers to a string in the `.debug_str` section using a `DebugStrOffset`.
    StringPointer(DebugStrOffset<Offset>),
    /// The macro contains an index into an array in the `.debug_str_offsets`
    /// section, which refers to a string in the `.debug_str` section.
    IndirectStringPointer(DebugStrOffsetsIndex<Offset>),
    /// The macro refers to a string in the `.debug_str` section in the supplementary object file
    Supplementary(DebugStrOffset<Offset>),
}

impl<R: Reader> MacroString<R> {
    /// Get the string slice from the macro entry.
    pub fn string(&self, unit: UnitRef<'_, R>) -> Result<R> {
        match self {
            MacroString::Direct(s) => Ok(s.clone()),
            MacroString::StringPointer(offset) => unit.string(*offset),
            MacroString::IndirectStringPointer(index) => {
                let str_offset = unit.string_offset(*index)?;
                unit.string(str_offset)
            }
            MacroString::Supplementary(offset) => unit.sup_string(*offset),
        }
    }
}

/// an Entry in the `.debug_macro` section.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MacroEntry<R, Offset = <R as Reader>::Offset>
where
    R: Reader<Offset = Offset>,
    Offset: ReaderOffset,
{
    /// A macro definition.
    Define {
        /// The line number where the macro is defined.
        line: u64,
        /// The text of the macro: The name of the macro followed immediately by any formal
        /// parameters including the surrounding parentheses, followed by the macro definition.
        text: MacroString<R>,
    },
    /// A macro undefinition.
    Undef {
        /// The line number where the macro is undefined.
        line: u64,
        /// The name of the macro without the definition.
        name: MacroString<R>,
    },
    /// The start of a file.
    StartFile {
        /// Line number of the source file on which the inclusion macro directive occurred.
        line: u64,
        /// An index into the line number table of the compilation unit.
        file: u64,
    },
    /// The end of the current included file.
    EndFile,
    /// import a macro unit
    Import {
        /// offset of the macro unit in the `.debug_macro` section
        offset: DebugMacroOffset<Offset>,
    },
    /// import a macro unit from the supplementary object file
    ImportSup {
        /// offset of the macro unit in the `.debug_macro` section of the supplementary object file
        offset: DebugMacroOffset<Offset>,
    },
    /// A vendor-specific extension.
    VendorExt {
        /// A numeric constant, whose meaning is vendor specific.
        numeric: u64,
        /// A string whose meaning is vendor specific.
        string: R,
    },
}

/// Iterator over the entries in the `.debug_macro` section.
#[derive(Clone, Debug)]
pub struct MacroIter<R: Reader> {
    input: R,
    format: Format,
    is_macro: bool,
}

impl<R: Reader> MacroIter<R> {
    /// Advance the iterator to the next entry in the `.debug_macro` section.
    pub fn next(&mut self) -> Result<Option<MacroEntry<R>>> {
        // DW_MACINFO_* and DW_MACRO_* have the same values, so we can use the same parsing logic.
        let macro_type = DwMacro(self.input.read_u8()?);
        match macro_type {
            DwMacro(0) => {
                self.input.empty();
                Ok(None)
            }
            constants::DW_MACRO_define => {
                let line = self.input.read_uleb128()?;
                let text = self.input.read_null_terminated_slice()?;
                Ok(Some(MacroEntry::Define {
                    line,
                    text: MacroString::Direct(text),
                }))
            }
            constants::DW_MACRO_undef => {
                let line = self.input.read_uleb128()?;
                let name = self.input.read_null_terminated_slice()?;
                Ok(Some(MacroEntry::Undef {
                    line,
                    name: MacroString::Direct(name),
                }))
            }
            constants::DW_MACRO_start_file => {
                let line = self.input.read_uleb128()?;
                let file = self.input.read_uleb128()?;
                Ok(Some(MacroEntry::StartFile { line, file }))
            }
            constants::DW_MACRO_end_file => Ok(Some(MacroEntry::EndFile)),
            constants::DW_MACRO_define_strp if self.is_macro => {
                let line = self.input.read_uleb128()?;
                let text_offset = DebugStrOffset(self.input.read_offset(self.format)?);
                Ok(Some(MacroEntry::Define {
                    line,
                    text: MacroString::StringPointer(text_offset),
                }))
            }
            constants::DW_MACRO_undef_strp if self.is_macro => {
                let line = self.input.read_uleb128()?;
                let name_offset = DebugStrOffset(self.input.read_offset(self.format)?);
                Ok(Some(MacroEntry::Undef {
                    line,
                    name: MacroString::StringPointer(name_offset),
                }))
            }
            constants::DW_MACRO_import if self.is_macro => {
                let offset = DebugMacroOffset(self.input.read_offset(self.format)?);
                Ok(Some(MacroEntry::Import { offset }))
            }
            constants::DW_MACRO_define_sup if self.is_macro => {
                let line = self.input.read_uleb128()?;
                let text_offset = DebugStrOffset(self.input.read_offset(self.format)?);
                Ok(Some(MacroEntry::Define {
                    line,
                    text: MacroString::Supplementary(text_offset),
                }))
            }
            constants::DW_MACRO_undef_sup if self.is_macro => {
                let line = self.input.read_uleb128()?;
                let name_offset = DebugStrOffset(self.input.read_offset(self.format)?);
                Ok(Some(MacroEntry::Undef {
                    line,
                    name: MacroString::Supplementary(name_offset),
                }))
            }
            constants::DW_MACRO_import_sup if self.is_macro => {
                let offset = DebugMacroOffset(self.input.read_offset(self.format)?);
                Ok(Some(MacroEntry::ImportSup { offset }))
            }
            constants::DW_MACRO_define_strx if self.is_macro => {
                let line = self.input.read_uleb128()?;
                let index = self.input.read_uleb128().and_then(R::Offset::from_u64)?;
                let text_index = DebugStrOffsetsIndex(index);
                Ok(Some(MacroEntry::Define {
                    line,
                    text: MacroString::IndirectStringPointer(text_index),
                }))
            }
            constants::DW_MACRO_undef_strx if self.is_macro => {
                let line = self.input.read_uleb128()?;
                let index = self.input.read_uleb128().and_then(R::Offset::from_u64)?;
                let name_index = DebugStrOffsetsIndex(index);
                Ok(Some(MacroEntry::Undef {
                    line,
                    name: MacroString::IndirectStringPointer(name_index),
                }))
            }
            _ => {
                if self.is_macro {
                    self.input.empty();
                    Err(Error::InvalidMacroType(macro_type))
                } else if macro_type.0 == constants::DW_MACINFO_vendor_ext.0 {
                    let numeric = self.input.read_uleb128()?;
                    let string = self.input.read_null_terminated_slice()?;
                    Ok(Some(MacroEntry::VendorExt { numeric, string }))
                } else {
                    self.input.empty();
                    Err(Error::InvalidMacinfoType(DwMacinfo(macro_type.0)))
                }
            }
        }
    }
}

#[cfg(feature = "fallible-iterator")]
impl<R: Reader> fallible_iterator::FallibleIterator for MacroIter<R> {
    type Item = MacroEntry<R>;
    type Error = Error;

    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Error> {
        MacroIter::next(self)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{test_util::GimliSectionMethods, DebugStr, LittleEndian};
    use test_assembler::{Endian, Label, LabelMaker, Section};

    #[test]
    fn test_get_macinfo() {
        let position = Label::new();

        // Create a test section with some macinfo entries
        let section = Section::with_endian(Endian::Little)
            .set_start_const(0)
            .mark(&position)
            .D8(crate::DW_MACINFO_define.0)
            .uleb(0// line number: 0 - defined on the compiler command line
            .append_bytes(b"__STDC__ 1\0")
            .D8(crate::DW_MACINFO_define.0)
            .uleb(1// line number: 1 - defined in the source file
            .append_bytes(b"__GNUC__ 1\0")
            .D8(crate::DW_MACINFO_undef.0)
            .uleb(2// line number: 2 - undefined in the source file
            .append_bytes(b"__GNUC__\0")
            .D8(crate::DW_MACINFO_start_file.0)
            .uleb(3// line number: 3 - start of file
            .uleb(4// file number index: 4 - index into the line number table
            .D8(crate::DW_MACINFO_end_file.0// end of file
            .D8(crate::DW_MACINFO_vendor_ext.0)
            .uleb(5// numeric constant: 5 - vendor specific
            .append_bytes(b"foo\0")
            .D8(0); // end of unit

        // Create a DebugMacinfo instance from the section
        let section = section.get_contents().unwrap();
        let debug_macinfo = DebugMacinfo::from(EndianSlice::new(§ion, LittleEndian));

        let offset = position.value().unwrap() as usize;

        let mut iter = debug_macinfo
            .get_macinfo(DebugMacinfoOffset(offset))
            .unwrap();

        // Test getting macinfo entries
        let entry = iter.next().unwrap().unwrap();
        assert!(
            matches!(entry, MacroEntry::Define { line: 0, text: MacroString::Direct(text) } if text.slice() == b"__STDC__ 1")
        );

        let entry = iter.next().unwrap().unwrap();
        assert!(
            matches!(entry, MacroEntry::Define { line: 1, text: MacroString::Direct(text) } if text.slice() == b"__GNUC__ 1")
        );

        let entry = iter.next().unwrap().unwrap();
        assert!(
            matches!(entry, MacroEntry::Undef { line: 2, name: MacroString::Direct(name) } if name.slice() == b"__GNUC__")
        );

        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 4 }));

        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::EndFile));

        let entry = iter.next().unwrap().unwrap();
        assert!(
            matches!(entry, MacroEntry::VendorExt { numeric: 5, string } if string.slice() == b"foo")
        );

        assert_eq!(iter.next(), Ok(None));
    }

    #[test]
    fn get_macros_1() {
        let position = Label::new();

        // The test data is originally from the DWARF v5 standard, appendix D.16
        // 1) Figure D.71, simple DWARF encoding
        let section = Section::with_endian(Endian::Little)
            .set_start_const(0)
            .mark(&position)
            .D16(5// Dwarf version
            .D8(0b0000_0010) // Flags: offset_size = 0 (32-bit), debug_line_offset = 1, opcode_operands_table = 0
            .D32(0// debug line offset
            .D8(crate::DW_MACRO_start_file.0// start file: "a.c"
            .uleb(0// line number
            .uleb(0// file number
            .D8(crate::DW_MACRO_start_file.0// start file: "a.h"
            .uleb(1// line number
            .uleb(1// file number
            .D8(crate::DW_MACRO_define.0// define
            .uleb(1// line number
            .append_bytes(b"LONGER_MACRO 1\0"// macro name
            .D8(crate::DW_MACRO_define.0// define
            .uleb(2// line number
            .append_bytes(b"B 2\0"// macro name
            .D8(crate::DW_MACRO_start_file.0// start file: "b.h"
            .uleb(3// line number
            .uleb(2// file number
            .D8(crate::DW_MACRO_undef.0// undef
            .uleb(1// line number
            .append_bytes(b"B\0"// macro name
            .D8(crate::DW_MACRO_define.0// define
            .uleb(2// line number
            .append_bytes(b"D 3\0"// macro name
            .D8(crate::DW_MACRO_define.0// define
            .uleb(3// line number
            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0"// macro name
            .D8(crate::DW_MACRO_end_file.0// end file: "b.h" -> "a.h"
            .D8(crate::DW_MACRO_define.0// define
            .uleb(4// line number
            .append_bytes(b"B 3\0"// macro name
            .D8(crate::DW_MACRO_end_file.0// end file: "a.h" -> "a.c"
            .D8(crate::DW_MACRO_define.0// define
            .uleb(2// line number
            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0"// macro name
            .D8(crate::DW_MACRO_start_file.0// start file: "b.h"
            .uleb(3// line number
            .uleb(2// file number
            .D8(crate::DW_MACRO_undef.0// undef
            .uleb(1// line number
            .append_bytes(b"B\0"// macro name
            .D8(crate::DW_MACRO_define.0// define
            .uleb(2// line number
            .append_bytes(b"D 3\0"// macro name
            .D8(crate::DW_MACRO_define.0// define
            .uleb(3// line number
            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0"// macro name
            .D8(crate::DW_MACRO_end_file.0// end file: "b.h" -> "a.c"
            .D8(crate::DW_MACRO_end_file.0// end file: "a.c" -> ""
            .D8(0); // end of unit

        // Create a DebugMacro instance from the section
        let section = section.get_contents().unwrap();
        let debug_macro = DebugMacro::from(EndianSlice::new(§ion, LittleEndian));

        let offset = position.value().unwrap() as usize;

        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::StartFile { line: 0, file: 0 }));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::StartFile { line: 1, file: 1 }));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 1, text: MacroString::Direct(text)
            } if text.slice() == b"LONGER_MACRO 1"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 2, text: MacroString::Direct(text)
            } if text.slice() == b"B 2"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Undef {
                line: 1, name: MacroString::Direct(name)
            } if name.slice() == b"B"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 2, text: MacroString::Direct(text)
            } if text.slice() == b"D 3"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 3, text: MacroString::Direct(text)
            } if text.slice() == b"FUNCTION_LIKE_MACRO(x) 4+x"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::EndFile));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 4, text: MacroString::Direct(text)
            } if text.slice() == b"B 3"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::EndFile));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 2, text: MacroString::Direct(text)
            } if text.slice() == b"FUNCTION_LIKE_MACRO(x) 4+x"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Undef {
                line: 1, name: MacroString::Direct(name)
            } if name.slice() == b"B"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 2, text: MacroString::Direct(text)
            } if text.slice() == b"D 3"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 3, text: MacroString::Direct(text)
            } if text.slice() == b"FUNCTION_LIKE_MACRO(x) 4+x"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::EndFile));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::EndFile));
        assert_eq!(iter.next(), Ok(None));
    }

    #[test]
    fn get_macros_2() {
        let str_0 = Label::new();
        let str_1 = Label::new();
        let macro_unit_0 = Label::new();
        let macro_unit_1 = Label::new();
        let macro_unit_2 = Label::new();

        // The test data is originally from the DWARF v5 standard, appendix D.16
        // 2) Figure D.72, shareable DWARF encoding
        let str_section = Section::with_endian(Endian::Little)
            .set_start_const(0)
            .mark(&str_0)
            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0"// macro name
            .mark(&str_1)
            .append_bytes(b"LONGER_MACRO 1\0"); // macro name

        let macro_section = Section::with_endian(Endian::Little)
            .set_start_const(0)
            //--------------------unit 0----------------------
            .mark(¯o_unit_0) // start of unit 0
            .D16(5// Dwarf version
            .D8(0b0000_0010) // Flags: offset_size = 0 (32-bit), debug_line_offset = 1, opcode_operands_table = 0
            .D32(0// debug line offset
            .D8(crate::DW_MACRO_start_file.0// start file: "a.c"
            .uleb(0// line number
            .uleb(0// file number
            .D8(crate::DW_MACRO_start_file.0// start file: "a.h"
            .uleb(1// line number
            .uleb(1// file number
            .D8(crate::DW_MACRO_import.0// import unit 1
            .L32(macro_unit_1.clone()) // debug line offset to unit 1
            .D8(crate::DW_MACRO_start_file.0// start file: "b.h"
            .uleb(3// line number
            .uleb(2// file number
            .D8(crate::DW_MACRO_import.0// import unit 2
            .L32(macro_unit_2.clone()) // debug line offset to unit 2
            .D8(crate::DW_MACRO_end_file.0// end file: "b.h" -> "a.h"
            .D8(crate::DW_MACRO_define.0// define
            .uleb(4// line number
            .append_bytes(b"B 3\0"// macro name
            .D8(crate::DW_MACRO_end_file.0// end file: "a.h" -> "a.c"
            .D8(crate::DW_MACRO_define_strp.0// define: "FUNCTION_LIKE_MACRO(x) 4+x"
            .uleb(2// line number
            .D32(0// macro name offset in the string table
            .D8(crate::DW_MACRO_start_file.0// start file: "b.h"
            .uleb(3// line number
            .uleb(2// file number
            .D8(crate::DW_MACRO_import.0// import unit 2
            .L32(¯o_unit_2) // debug line offset to unit 2
            .D8(crate::DW_MACRO_end_file.0// end file: "b.h" -> "a.c"
            .D8(crate::DW_MACRO_end_file.0// end file: "a.c" -> ""
            .D8(0)
            //--------------------unit 1----------------------
            .mark(¯o_unit_1) // start of unit 1
            .D16(5// Dwarf version
            .D8(0b0000_0000) // Flags: offset_size = 0 (32-bit), debug_line_offset = 0, opcode_operands_table = 0
            .D8(crate::DW_MACRO_define_strp.0// define strp: "LONGER_MACRO 1"
            .uleb(1// line number
            .L32(str_0.clone()) // macro name offset in the string table
            .D8(crate::DW_MACRO_define.0// define: "B 2"
            .uleb(2// line number
            .append_bytes(b"B 2\0"// macro name
            .D8(0// end of unit
            //---------------------unit 2---------------------
            .mark(¯o_unit_2) // start of unit 2
            .D16(5// Dwarf version
            .D8(0b0000_0000) // Flags: offset_size = 0 (32-bit), debug_line_offset = 0, opcode_operands_table = 0
            .D8(crate::DW_MACRO_undef.0// undef: "B"
            .uleb(1// line number
            .append_bytes(b"B\0"// macro name
            .D8(crate::DW_MACRO_define.0// define: "D 3"
            .uleb(2// line number
            .append_bytes(b"D 3\0"// macro name
            .D8(crate::DW_MACRO_define_strp.0// define strp: "FUNCTION_LIKE_MACRO(x) 4+x"
            .uleb(2// line number
            .L32(str_1.clone()) // macro name offset in the string table
            .D8(0); // end of unit

        // Create a DebugMacro instance from the section
        let str_section = str_section.get_contents().unwrap();
        let debug_str = DebugStr::from(EndianSlice::new(&str_section, LittleEndian));

        // Create a DebugMacro instance from the section
        let macro_section = macro_section.get_contents().unwrap();
        let debug_macro = DebugMacro::from(EndianSlice::new(¯o_section, LittleEndian));

        // check the content of macro unit 0
        let offset = macro_unit_0.value().unwrap() as usize;
        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::StartFile { line: 0, file: 0 }));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::StartFile { line: 1, file: 1 }));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Import { offset } if offset.0 == macro_unit_1.value().unwrap() as usize
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Import { offset } if offset.0 == macro_unit_2.value().unwrap() as usize
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::EndFile));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 4, text: MacroString::Direct(text)
            } if text.slice() == b"B 3"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::EndFile));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 2, text: MacroString::StringPointer(text_offset)
            } if text_offset.0 == str_0.value().unwrap() as usize
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Import { offset } if offset.0 == macro_unit_2.value().unwrap() as usize
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::EndFile));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(entry, MacroEntry::EndFile));
        assert_eq!(iter.next(), Ok(None));

        // check the content of macro unit 1
        let offset = macro_unit_1.value().unwrap() as usize;
        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 1, text: MacroString::StringPointer(text_offset)
            } if text_offset.0 == str_0.value().unwrap() as usize
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 2, text: MacroString::Direct(text)
            } if text.slice() == b"B 2"
        ));
        assert_eq!(iter.next(), Ok(None));

        // check the content of macro unit 2
        let offset = macro_unit_2.value().unwrap() as usize;
        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Undef {
                line: 1, name: MacroString::Direct(name)
            } if name.slice() == b"B"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 2, text: MacroString::Direct(text)
            } if text.slice() == b"D 3"
        ));
        let entry = iter.next().unwrap().unwrap();
        assert!(matches!(
            entry,
            MacroEntry::Define {
                line: 2, text: MacroString::StringPointer(text_offset)
            } if text_offset.0 == str_1.value().unwrap() as usize
        ));
        assert_eq!(iter.next(), Ok(None));

        // check the content of the string table
        let text_offset = DebugStrOffset(str_0.value().unwrap() as usize);
        assert_eq!(
            debug_str.get_str(text_offset).unwrap().slice(),
            b"FUNCTION_LIKE_MACRO(x) 4+x"
        );
        let text_offset = DebugStrOffset(str_1.value().unwrap() as usize);
        assert_eq!(
            debug_str.get_str(text_offset).unwrap().slice(),
            b"LONGER_MACRO 1"
        );
    }
}

Messung V0.5 in Prozent
C=73 H=100 G=87

¤ Dauer der Verarbeitung: 0.38 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=434850
#Domains=661743