use core::cell::Cell;
use core::ops::{Range, RangeFrom, RangeTo};
use crate::common::{
DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset,
DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex, DebugMacinfoOffset,
DebugMacroOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase,
DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwoId, Encoding, Format,
LocationListsOffset, RawRangeListsOffset, SectionId, UnitSectionOffset,
};
use crate::constants;
use crate::endianity::Endianity;
use crate::read::abbrev::get_attribute_size;
use crate::read::{
Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, DebugStr, EndianSlice, Error,
Expression, Reader, ReaderOffset, Result, Section, UnitOffset,
};
impl<T: ReaderOffset> DebugTypesOffset<T> {
pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>>
where
R: Reader<Offset = T>,
{
let unit_offset = unit.offset().as_debug_types_offset()?;
let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?);
if !unit.is_valid_offset(offset) {
return None;
}
Some(offset)
}
}
impl<T: ReaderOffset> DebugInfoOffset<T> {
pub fn to_unit_offset<R>(&self, unit: &UnitHeader<R>) -> Option<UnitOffset<T>>
where
R: Reader<Offset = T>,
{
let unit_offset = unit.offset().as_debug_info_offset()?;
let offset = UnitOffset(self.0.checked_sub(unit_offset.0)?);
if !unit.is_valid_offset(offset) {
return None;
}
Some(offset)
}
}
impl<T: ReaderOffset> UnitOffset<T> {
pub fn to_debug_info_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugInfoOffset<T>>
where
R: Reader<Offset = T>,
{
let unit_offset = unit.offset().as_debug_info_offset()?;
Some(DebugInfoOffset(unit_offset.0 + self.0))
}
pub fn to_debug_types_offset<R>(&self, unit: &UnitHeader<R>) -> Option<DebugTypesOffset<T>>
where
R: Reader<Offset = T>,
{
let unit_offset = unit.offset().as_debug_types_offset()?;
Some(DebugTypesOffset(unit_offset.0 + self.0))
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct DebugInfo<R> {
debug_info_section: R,
}
impl<'input, Endian> DebugInfo<EndianSlice<'input, Endian>>
where
Endian: Endianity,
{
pub fn new(debug_info_section: &'input [u8], endian: Endian) -> Self {
Self::from(EndianSlice::new(debug_info_section, endian))
}
}
impl<R: Reader> DebugInfo<R> {
pub fn units(&self) -> DebugInfoUnitHeadersIter<R> {
DebugInfoUnitHeadersIter {
input: self.debug_info_section.clone(),
offset: DebugInfoOffset(R::Offset::from_u8(0)),
}
}
pub fn header_from_offset(&self, offset: DebugInfoOffset<R::Offset>) -> Result<UnitHeader<R>> {
let input = &mut self.debug_info_section.clone();
input.skip(offset.0)?;
parse_unit_header(input, offset.into())
}
}
impl<T> DebugInfo<T> {
pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugInfo<R>
where
F: FnMut(&'a T) -> R,
{
borrow(&self.debug_info_section).into()
}
}
impl<R> Section<R> for DebugInfo<R> {
fn id() -> SectionId {
SectionId::DebugInfo
}
fn reader(&self) -> &R {
&self.debug_info_section
}
}
impl<R> From<R> for DebugInfo<R> {
fn from(debug_info_section: R) -> Self {
DebugInfo { debug_info_section }
}
}
#[derive(Clone, Debug)]
pub struct DebugInfoUnitHeadersIter<R: Reader> {
input: R,
offset: DebugInfoOffset<R::Offset>,
}
impl<R: Reader> DebugInfoUnitHeadersIter<R> {
pub fn next(&mut self) -> Result<Option<UnitHeader<R>>> {
if self.input.is_empty() {
Ok(None)
} else {
let len = self.input.len();
match parse_unit_header(&mut self.input, self.offset.into()) {
Ok(header) => {
self.offset.0 += len - self.input.len();
Ok(Some(header))
}
Err(e) => {
self.input.empty();
Err(e)
}
}
}
}
}
#[cfg(feature = "fallible-iterator")]
impl<R: Reader> fallible_iterator::FallibleIterator for DebugInfoUnitHeadersIter<R> {
type Item = UnitHeader<R>;
type Error = Error;
fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
DebugInfoUnitHeadersIter::next(self)
}
}
fn parse_unit_type<R: Reader>(input: &mut R) -> Result<constants::DwUt> {
let val = input.read_u8()?;
Ok(constants::DwUt(val))
}
fn parse_debug_abbrev_offset<R: Reader>(
input: &mut R,
format: Format,
) -> Result<DebugAbbrevOffset<R::Offset>> {
input.read_offset(format).map(DebugAbbrevOffset)
}
pub(crate) fn parse_debug_info_offset<R: Reader>(
input: &mut R,
format: Format,
) -> Result<DebugInfoOffset<R::Offset>> {
input.read_offset(format).map(DebugInfoOffset)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnitType<Offset>
where
Offset: ReaderOffset,
{
Compilation,
Type {
type_signature: DebugTypeSignature,
type_offset: UnitOffset<Offset>,
},
Partial,
Skeleton(DwoId),
SplitCompilation(DwoId),
SplitType {
type_signature: DebugTypeSignature,
type_offset: UnitOffset<Offset>,
},
}
impl<Offset> UnitType<Offset>
where
Offset: ReaderOffset,
{
#[allow(unused)]
pub(crate) fn dw_ut(&self) -> constants::DwUt {
match self {
UnitType::Compilation => constants::DW_UT_compile,
UnitType::Type { .. } => constants::DW_UT_type,
UnitType::Partial => constants::DW_UT_partial,
UnitType::Skeleton(_) => constants::DW_UT_skeleton,
UnitType::SplitCompilation(_) => constants::DW_UT_split_compile,
UnitType::SplitType { .. } => constants::DW_UT_split_type,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UnitHeader<R, Offset = <R as Reader>::Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
encoding: Encoding,
unit_length: Offset,
unit_type: UnitType<Offset>,
debug_abbrev_offset: DebugAbbrevOffset<Offset>,
unit_offset: UnitSectionOffset<Offset>,
entries_buf: R,
}
impl<R, Offset> UnitHeader<R, Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
pub fn new(
encoding: Encoding,
unit_length: Offset,
unit_type: UnitType<Offset>,
debug_abbrev_offset: DebugAbbrevOffset<Offset>,
unit_offset: UnitSectionOffset<Offset>,
entries_buf: R,
) -> Self {
UnitHeader {
encoding,
unit_length,
unit_type,
debug_abbrev_offset,
unit_offset,
entries_buf,
}
}
}
impl<R, Offset> UnitHeader<R, Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
pub fn offset(&self) -> UnitSectionOffset<Offset> {
self.unit_offset
}
pub fn size_of_header(&self) -> usize {
let unit_length_size = self.encoding.format.initial_length_size() as usize;
let version_size = 2;
let debug_abbrev_offset_size = self.encoding.format.word_size() as usize;
let address_size_size = 1;
let unit_type_size = if self.encoding.version == 5 { 1 } else { 0 };
let type_specific_size = match self.unit_type {
UnitType::Compilation | UnitType::Partial => 0,
UnitType::Type { .. } | UnitType::SplitType { .. } => {
let type_signature_size = 8;
let type_offset_size = self.encoding.format.word_size() as usize;
type_signature_size + type_offset_size
}
UnitType::Skeleton(_) | UnitType::SplitCompilation(_) => 8,
};
unit_length_size
+ version_size
+ debug_abbrev_offset_size
+ address_size_size
+ unit_type_size
+ type_specific_size
}
pub fn unit_length(&self) -> Offset {
self.unit_length
}
pub fn length_including_self(&self) -> Offset {
Offset::from_u8(self.format().initial_length_size()) + self.unit_length
}
pub fn encoding(&self) -> Encoding {
self.encoding
}
pub fn version(&self) -> u16 {
self.encoding.version
}
pub fn type_(&self) -> UnitType<Offset> {
self.unit_type
}
pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset<Offset> {
self.debug_abbrev_offset
}
pub fn address_size(&self) -> u8 {
self.encoding.address_size
}
pub fn format(&self) -> Format {
self.encoding.format
}
pub fn header_size(&self) -> Offset {
self.length_including_self() - self.entries_buf.len()
}
pub(crate) fn is_valid_offset(&self, offset: UnitOffset<Offset>) -> bool {
let size_of_header = self.header_size();
if offset.0 < size_of_header {
return false;
}
let relative_to_entries_buf = offset.0 - size_of_header;
relative_to_entries_buf < self.entries_buf.len()
}
pub fn range(&self, idx: Range<UnitOffset<Offset>>) -> Result<R> {
if !self.is_valid_offset(idx.start) {
return Err(Error::OffsetOutOfBounds);
}
if !self.is_valid_offset(idx.end) {
return Err(Error::OffsetOutOfBounds);
}
assert!(idx.start <= idx.end);
let size_of_header = self.header_size();
let start = idx.start.0 - size_of_header;
let end = idx.end.0 - size_of_header;
let mut input = self.entries_buf.clone();
input.skip(start)?;
input.truncate(end - start)?;
Ok(input)
}
pub fn range_from(&self, idx: RangeFrom<UnitOffset<Offset>>) -> Result<R> {
if !self.is_valid_offset(idx.start) {
return Err(Error::OffsetOutOfBounds);
}
let start = idx.start.0 - self.header_size();
let mut input = self.entries_buf.clone();
input.skip(start)?;
Ok(input)
}
pub fn range_to(&self, idx: RangeTo<UnitOffset<Offset>>) -> Result<R> {
if !self.is_valid_offset(idx.end) {
return Err(Error::OffsetOutOfBounds);
}
let end = idx.end.0 - self.header_size();
let mut input = self.entries_buf.clone();
input.truncate(end)?;
Ok(input)
}
pub fn entry<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
offset: UnitOffset<Offset>,
) -> Result<DebuggingInformationEntry<'abbrev, 'me, R>> {
let mut input = self.range_from(offset..)?;
let entry = DebuggingInformationEntry::parse(&mut input, self, abbreviations)?;
entry.ok_or(Error::NoEntryAtGivenOffset)
}
pub fn entries<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
) -> EntriesCursor<'abbrev, 'me, R> {
EntriesCursor {
unit: self,
input: self.entries_buf.clone(),
abbreviations,
cached_current: None,
delta_depth: 0,
}
}
pub fn entries_at_offset<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
offset: UnitOffset<Offset>,
) -> Result<EntriesCursor<'abbrev, 'me, R>> {
let input = self.range_from(offset..)?;
Ok(EntriesCursor {
unit: self,
input,
abbreviations,
cached_current: None,
delta_depth: 0,
})
}
pub fn entries_tree<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
offset: Option<UnitOffset<Offset>>,
) -> Result<EntriesTree<'abbrev, 'me, R>> {
let input = match offset {
Some(offset) => self.range_from(offset..)?,
None => self.entries_buf.clone(),
};
Ok(EntriesTree::new(input, self, abbreviations))
}
pub fn entries_raw<'me, 'abbrev>(
&'me self,
abbreviations: &'abbrev Abbreviations,
offset: Option<UnitOffset<Offset>>,
) -> Result<EntriesRaw<'abbrev, 'me, R>> {
let input = match offset {
Some(offset) => self.range_from(offset..)?,
None => self.entries_buf.clone(),
};
Ok(EntriesRaw {
input,
unit: self,
abbreviations,
depth: 0,
})
}
pub fn abbreviations(&self, debug_abbrev: &DebugAbbrev<R>) -> Result<Abbreviations> {
debug_abbrev.abbreviations(self.debug_abbrev_offset())
}
}
fn parse_unit_header<R, Offset>(
input: &mut R,
unit_offset: UnitSectionOffset<Offset>,
) -> Result<UnitHeader<R>>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
let (unit_length, format) = input.read_initial_length()?;
let mut rest = input.split(unit_length)?;
let version = rest.read_u16()?;
let abbrev_offset;
let address_size;
let unit_type;
if 2 <= version && version <= 4 {
abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?;
address_size = rest.read_address_size()?;
unit_type = match unit_offset {
UnitSectionOffset::DebugInfoOffset(_) => constants::DW_UT_compile,
UnitSectionOffset::DebugTypesOffset(_) => constants::DW_UT_type,
};
} else if version == 5 {
unit_type = parse_unit_type(&mut rest)?;
address_size = rest.read_address_size()?;
abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?;
} else {
return Err(Error::UnknownVersion(u64::from(version)));
}
let encoding = Encoding {
format,
version,
address_size,
};
let unit_type = match unit_type {
constants::DW_UT_compile => UnitType::Compilation,
constants::DW_UT_type => {
let type_signature = parse_type_signature(&mut rest)?;
let type_offset = parse_type_offset(&mut rest, format)?;
UnitType::Type {
type_signature,
type_offset,
}
}
constants::DW_UT_partial => UnitType::Partial,
constants::DW_UT_skeleton => {
let dwo_id = parse_dwo_id(&mut rest)?;
UnitType::Skeleton(dwo_id)
}
constants::DW_UT_split_compile => {
let dwo_id = parse_dwo_id(&mut rest)?;
UnitType::SplitCompilation(dwo_id)
}
constants::DW_UT_split_type => {
let type_signature = parse_type_signature(&mut rest)?;
let type_offset = parse_type_offset(&mut rest, format)?;
UnitType::SplitType {
type_signature,
type_offset,
}
}
_ => return Err(Error::UnsupportedUnitType),
};
Ok(UnitHeader::new(
encoding,
unit_length,
unit_type,
abbrev_offset,
unit_offset,
rest,
))
}
fn parse_dwo_id<R: Reader>(input: &mut R) -> Result<DwoId> {
Ok(DwoId(input.read_u64()?))
}
#[derive(Clone, Debug)]
pub struct DebuggingInformationEntry<'abbrev, 'unit, R, Offset = <R as Reader>::Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
offset: UnitOffset<Offset>,
attrs_slice: R,
attrs_len: Cell<Option<Offset>>,
abbrev: &'abbrev Abbreviation,
unit: &'unit UnitHeader<R, Offset>,
}
impl<'abbrev, 'unit, R, Offset> DebuggingInformationEntry<'abbrev, 'unit, R, Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
pub fn new(
offset: UnitOffset<Offset>,
attrs_slice: R,
abbrev: &'abbrev Abbreviation,
unit: &'unit UnitHeader<R, Offset>,
) -> Self {
DebuggingInformationEntry {
offset,
attrs_slice,
attrs_len: Cell::new(None),
abbrev,
unit,
}
}
pub fn code(&self) -> u64 {
self.abbrev.code()
}
pub fn offset(&self) -> UnitOffset<Offset> {
self.offset
}
pub fn tag(&self) -> constants::DwTag {
self.abbrev.tag()
}
pub fn has_children(&self) -> bool {
self.abbrev.has_children()
}
pub fn attrs<'me>(&'me self) -> AttrsIter<'abbrev, 'me, 'unit, R> {
AttrsIter {
input: self.attrs_slice.clone(),
attributes: self.abbrev.attributes(),
entry: self,
}
}
pub fn attr(&self, name: constants::DwAt) -> Result<Option<Attribute<R>>> {
let mut attrs = self.attrs();
while let Some(attr) = attrs.next()? {
if attr.name() == name {
return Ok(Some(attr));
}
}
Ok(None)
}
pub fn attr_value_raw(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> {
self.attr(name)
.map(|attr| attr.map(|attr| attr.raw_value()))
}
pub fn attr_value(&self, name: constants::DwAt) -> Result<Option<AttributeValue<R>>> {
self.attr(name).map(|attr| attr.map(|attr| attr.value()))
}
#[inline(always)]
fn after_attrs(&self) -> Result<R> {
if let Some(attrs_len) = self.attrs_len.get() {
let mut input = self.attrs_slice.clone();
input.skip(attrs_len)?;
Ok(input)
} else {
let mut attrs = self.attrs();
while attrs.next()?.is_some() {}
Ok(attrs.input)
}
}
fn sibling(&self) -> Option<R> {
let attr = self.attr_value(constants::DW_AT_sibling);
if let Ok(Some(AttributeValue::UnitRef(offset))) = attr {
if offset.0 > self.offset.0 {
if let Ok(input) = self.unit.range_from(offset..) {
return Some(input);
}
}
}
None
}
#[inline(always)]
fn parse(
input: &mut R,
unit: &'unit UnitHeader<R>,
abbreviations: &'abbrev Abbreviations,
) -> Result<Option<Self>> {
let offset = unit.header_size() + input.offset_from(&unit.entries_buf);
let code = input.read_uleb128()?;
if code == 0 {
return Ok(None);
};
let abbrev = abbreviations
.get(code)
.ok_or(Error::UnknownAbbreviation(code))?;
Ok(Some(DebuggingInformationEntry {
offset: UnitOffset(offset),
attrs_slice: input.clone(),
attrs_len: Cell::new(None),
abbrev,
unit,
}))
}
}
#[repr(u64)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AttributeValue<R, Offset = <R as Reader>::Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
Addr(u64),
Block(R),
Data1(u8),
Data2(u16),
Data4(u32),
Data8(u64),
Sdata(i64),
Udata(u64),
Exprloc(Expression<R>),
Flag(bool),
SecOffset(Offset),
DebugAddrBase(DebugAddrBase<Offset>),
DebugAddrIndex(DebugAddrIndex<Offset>),
UnitRef(UnitOffset<Offset>),
DebugInfoRef(DebugInfoOffset<Offset>),
DebugInfoRefSup(DebugInfoOffset<Offset>),
DebugLineRef(DebugLineOffset<Offset>),
LocationListsRef(LocationListsOffset<Offset>),
DebugLocListsBase(DebugLocListsBase<Offset>),
DebugLocListsIndex(DebugLocListsIndex<Offset>),
DebugMacinfoRef(DebugMacinfoOffset<Offset>),
DebugMacroRef(DebugMacroOffset<Offset>),
RangeListsRef(RawRangeListsOffset<Offset>),
DebugRngListsBase(DebugRngListsBase<Offset>),
DebugRngListsIndex(DebugRngListsIndex<Offset>),
DebugTypesRef(DebugTypeSignature),
DebugStrRef(DebugStrOffset<Offset>),
DebugStrRefSup(DebugStrOffset<Offset>),
DebugStrOffsetsBase(DebugStrOffsetsBase<Offset>),
DebugStrOffsetsIndex(DebugStrOffsetsIndex<Offset>),
DebugLineStrRef(DebugLineStrOffset<Offset>),
String(R),
Encoding(constants::DwAte),
DecimalSign(constants::DwDs),
Endianity(constants::DwEnd),
Accessibility(constants::DwAccess),
Visibility(constants::DwVis),
Virtuality(constants::DwVirtuality),
Language(constants::DwLang),
AddressClass(constants::DwAddr),
IdentifierCase(constants::DwId),
CallingConvention(constants::DwCc),
Inline(constants::DwInl),
Ordering(constants::DwOrd),
FileIndex(u64),
DwoId(DwoId),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Attribute<R: Reader> {
name: constants::DwAt,
value: AttributeValue<R>,
}
impl<R: Reader> Attribute<R> {
pub fn name(&self) -> constants::DwAt {
self.name
}
pub fn raw_value(&self) -> AttributeValue<R> {
self.value.clone()
}
pub fn value(&self) -> AttributeValue<R> {
macro_rules! address {
() => {};
}
macro_rules! addrptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugAddrBase(DebugAddrBase(offset));
}
};
}
macro_rules! block {
() => {};
}
macro_rules! constant {
($value:ident, $variant:ident) => {
if let Some(value) = self.$value() {
return AttributeValue::$variant(value);
}
};
($value:ident, $variant:ident, $constant:ident) => {
if let Some(value) = self.$value() {
return AttributeValue::$variant(constants::$constant(value));
}
};
}
macro_rules! exprloc {
() => {
if let Some(value) = self.exprloc_value() {
return AttributeValue::Exprloc(value);
}
};
}
macro_rules! flag {
() => {};
}
macro_rules! lineptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugLineRef(DebugLineOffset(offset));
}
};
}
macro_rules! loclistptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::LocationListsRef(LocationListsOffset(offset));
}
};
}
macro_rules! loclistsptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugLocListsBase(DebugLocListsBase(offset));
}
};
}
macro_rules! macinfoptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(offset));
}
};
}
macro_rules! macroptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugMacroRef(DebugMacroOffset(offset));
}
};
}
macro_rules! reference {
() => {};
}
macro_rules! rangelistptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::RangeListsRef(RawRangeListsOffset(offset));
}
};
}
macro_rules! rnglistsptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugRngListsBase(DebugRngListsBase(offset));
}
};
}
macro_rules! string {
() => {};
}
macro_rules! stroffsetsptr {
() => {
if let Some(offset) = self.offset_value() {
return AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(offset));
}
};
}
macro_rules! dwoid {
() => {
if let Some(value) = self.udata_value() {
return AttributeValue::DwoId(DwoId(value));
}
};
}
match self.name {
constants::DW_AT_sibling => {
reference!();
}
constants::DW_AT_location => {
exprloc!();
loclistptr!();
}
constants::DW_AT_name => {
string!();
}
constants::DW_AT_ordering => {
constant!(u8_value, Ordering, DwOrd);
}
constants::DW_AT_byte_size
| constants::DW_AT_bit_offset
| constants::DW_AT_bit_size => {
constant!(udata_value, Udata);
exprloc!();
reference!();
}
constants::DW_AT_stmt_list => {
lineptr!();
}
constants::DW_AT_low_pc => {
address!();
}
constants::DW_AT_high_pc => {
address!();
constant!(udata_value, Udata);
}
constants::DW_AT_language => {
constant!(u16_value, Language, DwLang);
}
constants::DW_AT_discr => {
reference!();
}
constants::DW_AT_discr_value => {
}
constants::DW_AT_visibility => {
constant!(u8_value, Visibility, DwVis);
}
constants::DW_AT_import => {
reference!();
}
constants::DW_AT_string_length => {
exprloc!();
loclistptr!();
reference!();
}
constants::DW_AT_common_reference => {
reference!();
}
constants::DW_AT_comp_dir => {
string!();
}
constants::DW_AT_const_value => {
block!();
string!();
}
constants::DW_AT_containing_type => {
reference!();
}
constants::DW_AT_default_value => {
reference!();
flag!();
}
constants::DW_AT_inline => {
constant!(u8_value, Inline, DwInl);
}
constants::DW_AT_is_optional => {
flag!();
}
constants::DW_AT_lower_bound => {
exprloc!();
reference!();
}
constants::DW_AT_producer => {
string!();
}
constants::DW_AT_prototyped => {
flag!();
}
constants::DW_AT_return_addr => {
exprloc!();
loclistptr!();
}
constants::DW_AT_start_scope => {
rangelistptr!();
}
constants::DW_AT_bit_stride => {
constant!(udata_value, Udata);
exprloc!();
reference!();
}
constants::DW_AT_upper_bound => {
exprloc!();
reference!();
}
constants::DW_AT_abstract_origin => {
reference!();
}
constants::DW_AT_accessibility => {
constant!(u8_value, Accessibility, DwAccess);
}
constants::DW_AT_address_class => {
constant!(udata_value, AddressClass, DwAddr);
}
constants::DW_AT_artificial => {
flag!();
}
constants::DW_AT_base_types => {
reference!();
}
constants::DW_AT_calling_convention => {
constant!(u8_value, CallingConvention, DwCc);
}
constants::DW_AT_count => {
exprloc!();
reference!();
}
constants::DW_AT_data_member_location => {
constant!(udata_value, Udata);
exprloc!();
loclistptr!();
}
constants::DW_AT_decl_column => {
constant!(udata_value, Udata);
}
constants::DW_AT_decl_file => {
constant!(udata_value, FileIndex);
}
constants::DW_AT_decl_line => {
constant!(udata_value, Udata);
}
constants::DW_AT_declaration => {
flag!();
}
constants::DW_AT_discr_list => {
block!();
}
constants::DW_AT_encoding => {
constant!(u8_value, Encoding, DwAte);
}
constants::DW_AT_external => {
flag!();
}
constants::DW_AT_frame_base => {
exprloc!();
loclistptr!();
}
constants::DW_AT_friend => {
reference!();
}
constants::DW_AT_identifier_case => {
constant!(u8_value, IdentifierCase, DwId);
}
constants::DW_AT_macro_info => {
macinfoptr!();
}
constants::DW_AT_namelist_item => {
reference!();
}
constants::DW_AT_priority => {
reference!();
}
constants::DW_AT_segment => {
exprloc!();
loclistptr!();
}
constants::DW_AT_specification => {
reference!();
}
constants::DW_AT_static_link => {
exprloc!();
loclistptr!();
}
constants::DW_AT_type => {
reference!();
}
constants::DW_AT_use_location => {
exprloc!();
loclistptr!();
}
constants::DW_AT_variable_parameter => {
flag!();
}
constants::DW_AT_virtuality => {
constant!(u8_value, Virtuality, DwVirtuality);
}
constants::DW_AT_vtable_elem_location => {
exprloc!();
loclistptr!();
}
constants::DW_AT_allocated => {
exprloc!();
reference!();
}
constants::DW_AT_associated => {
exprloc!();
reference!();
}
constants::DW_AT_data_location => {
exprloc!();
}
constants::DW_AT_byte_stride => {
constant!(udata_value, Udata);
exprloc!();
reference!();
}
constants::DW_AT_entry_pc => {
address!();
}
constants::DW_AT_use_UTF8 => {
flag!();
}
constants::DW_AT_extension => {
reference!();
}
constants::DW_AT_ranges => {
rangelistptr!();
}
constants::DW_AT_trampoline => {
address!();
flag!();
reference!();
string!();
}
constants::DW_AT_call_column => {
constant!(udata_value, Udata);
}
constants::DW_AT_call_file => {
constant!(udata_value, FileIndex);
}
constants::DW_AT_call_line => {
constant!(udata_value, Udata);
}
constants::DW_AT_description => {
string!();
}
constants::DW_AT_binary_scale => {
}
constants::DW_AT_decimal_scale => {
}
constants::DW_AT_small => {
reference!();
}
constants::DW_AT_decimal_sign => {
constant!(u8_value, DecimalSign, DwDs);
}
constants::DW_AT_digit_count => {
}
constants::DW_AT_picture_string => {
string!();
}
constants::DW_AT_mutable => {
flag!();
}
constants::DW_AT_threads_scaled => {
flag!();
}
constants::DW_AT_explicit => {
flag!();
}
constants::DW_AT_object_pointer => {
reference!();
}
constants::DW_AT_endianity => {
constant!(u8_value, Endianity, DwEnd);
}
constants::DW_AT_elemental => {
flag!();
}
constants::DW_AT_pure => {
flag!();
}
constants::DW_AT_recursive => {
flag!();
}
constants::DW_AT_signature => {
reference!();
}
constants::DW_AT_main_subprogram => {
flag!();
}
constants::DW_AT_data_bit_offset => {
}
constants::DW_AT_const_expr => {
flag!();
}
constants::DW_AT_enum_class => {
flag!();
}
constants::DW_AT_linkage_name => {
string!();
}
constants::DW_AT_string_length_bit_size => {
}
constants::DW_AT_string_length_byte_size => {
}
constants::DW_AT_rank => {
exprloc!();
}
constants::DW_AT_str_offsets_base => {
stroffsetsptr!();
}
constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => {
addrptr!();
}
constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => {
rnglistsptr!();
}
constants::DW_AT_dwo_name => {
string!();
}
constants::DW_AT_reference => {
flag!();
}
constants::DW_AT_rvalue_reference => {
flag!();
}
constants::DW_AT_macros => {
macroptr!();
}
constants::DW_AT_call_all_calls => {
flag!();
}
constants::DW_AT_call_all_source_calls => {
flag!();
}
constants::DW_AT_call_all_tail_calls => {
flag!();
}
constants::DW_AT_call_return_pc => {
address!();
}
constants::DW_AT_call_value => {
exprloc!();
}
constants::DW_AT_call_origin => {
exprloc!();
}
constants::DW_AT_call_parameter => {
reference!();
}
constants::DW_AT_call_pc => {
address!();
}
constants::DW_AT_call_tail_call => {
flag!();
}
constants::DW_AT_call_target => {
exprloc!();
}
constants::DW_AT_call_target_clobbered => {
exprloc!();
}
constants::DW_AT_call_data_location => {
exprloc!();
}
constants::DW_AT_call_data_value => {
exprloc!();
}
constants::DW_AT_noreturn => {
flag!();
}
constants::DW_AT_alignment => {
}
constants::DW_AT_export_symbols => {
flag!();
}
constants::DW_AT_deleted => {
flag!();
}
constants::DW_AT_defaulted => {
}
constants::DW_AT_loclists_base => {
loclistsptr!();
}
constants::DW_AT_GNU_dwo_id => {
dwoid!();
}
_ => {}
}
self.value.clone()
}
#[inline]
pub fn u8_value(&self) -> Option<u8> {
self.value.u8_value()
}
#[inline]
pub fn u16_value(&self) -> Option<u16> {
self.value.u16_value()
}
#[inline]
pub fn udata_value(&self) -> Option<u64> {
self.value.udata_value()
}
#[inline]
pub fn sdata_value(&self) -> Option<i64> {
self.value.sdata_value()
}
#[inline]
pub fn offset_value(&self) -> Option<R::Offset> {
self.value.offset_value()
}
#[inline]
pub fn exprloc_value(&self) -> Option<Expression<R>> {
self.value.exprloc_value()
}
#[inline]
pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> {
self.value.string_value(debug_str)
}
#[inline]
pub fn string_value_sup(
&self,
debug_str: &DebugStr<R>,
debug_str_sup: Option<&DebugStr<R>>,
) -> Option<R> {
self.value.string_value_sup(debug_str, debug_str_sup)
}
}
impl<R, Offset> AttributeValue<R, Offset>
where
R: Reader<Offset = Offset>,
Offset: ReaderOffset,
{
pub fn u8_value(&self) -> Option<u8> {
if let Some(value) = self.udata_value() {
if value <= u64::from(u8::MAX) {
return Some(value as u8);
}
}
None
}
pub fn u16_value(&self) -> Option<u16> {
if let Some(value) = self.udata_value() {
if value <= u64::from(u16::MAX) {
return Some(value as u16);
}
}
None
}
pub fn udata_value(&self) -> Option<u64> {
Some(match *self {
AttributeValue::Data1(data) => u64::from(data),
AttributeValue::Data2(data) => u64::from(data),
AttributeValue::Data4(data) => u64::from(data),
AttributeValue::Data8(data) => data,
AttributeValue::Udata(data) => data,
AttributeValue::Sdata(data) => {
if data < 0 {
return None;
}
data as u64
}
_ => return None,
})
}
pub fn sdata_value(&self) -> Option<i64> {
Some(match *self {
AttributeValue::Data1(data) => i64::from(data as i8),
AttributeValue::Data2(data) => i64::from(data as i16),
AttributeValue::Data4(data) => i64::from(data as i32),
AttributeValue::Data8(data) => data as i64,
AttributeValue::Sdata(data) => data,
AttributeValue::Udata(data) => {
if data > i64::MAX as u64 {
return None;
}
data as i64
}
_ => return None,
})
}
pub fn offset_value(&self) -> Option<R::Offset> {
if let AttributeValue::SecOffset(offset) = *self {
Some(offset)
} else {
None
}
}
pub fn exprloc_value(&self) -> Option<Expression<R>> {
Some(match *self {
AttributeValue::Block(ref data) => Expression(data.clone()),
AttributeValue::Exprloc(ref data) => data.clone(),
_ => return None,
})
}
pub fn string_value(&self, debug_str: &DebugStr<R>) -> Option<R> {
match *self {
AttributeValue::String(ref string) => Some(string.clone()),
AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(),
_ => None,
}
}
pub fn string_value_sup(
&self,
debug_str: &DebugStr<R>,
debug_str_sup: Option<&DebugStr<R>>,
) -> Option<R> {
match *self {
AttributeValue::String(ref string) => Some(string.clone()),
AttributeValue::DebugStrRef(offset) => debug_str.get_str(offset).ok(),
AttributeValue::DebugStrRefSup(offset) => {
debug_str_sup.and_then(|s| s.get_str(offset).ok())
}
_ => None,
}
}
}
fn length_u8_value<R: Reader>(input: &mut R) -> Result<R> {
let len = input.read_u8().map(R::Offset::from_u8)?;
input.split(len)
}
fn length_u16_value<R: Reader>(input: &mut R) -> Result<R> {
let len = input.read_u16().map(R::Offset::from_u16)?;
input.split(len)
}
fn length_u32_value<R: Reader>(input: &mut R) -> Result<R> {
let len = input.read_u32().map(R::Offset::from_u32)?;
input.split(len)
}
fn length_uleb128_value<R: Reader>(input: &mut R) -> Result<R> {
let len = input.read_uleb128().and_then(R::Offset::from_u64)?;
input.split(len)
}
fn allow_section_offset(name: constants::DwAt, version: u16) -> bool {
match name {
constants::DW_AT_location
| constants::DW_AT_stmt_list
| constants::DW_AT_string_length
| constants::DW_AT_return_addr
| constants::DW_AT_start_scope
| constants::DW_AT_frame_base
| constants::DW_AT_macro_info
| constants::DW_AT_macros
| constants::DW_AT_segment
| constants::DW_AT_static_link
| constants::DW_AT_use_location
| constants::DW_AT_vtable_elem_location
| constants::DW_AT_ranges => true,
constants::DW_AT_data_member_location => version == 2 || version == 3,
_ => false,
}
}
pub(crate) fn parse_attribute<R: Reader>(
input: &mut R,
encoding: Encoding,
spec: AttributeSpecification,
) -> Result<Attribute<R>> {
let mut form = spec.form();
loop {
let value = match form {
constants::DW_FORM_indirect => {
let dynamic_form = input.read_uleb128_u16()?;
form = constants::DwForm(dynamic_form);
continue;
}
constants::DW_FORM_addr => {
let addr = input.read_address(encoding.address_size)?;
AttributeValue::Addr(addr)
}
constants::DW_FORM_block1 => {
let block = length_u8_value(input)?;
AttributeValue::Block(block)
}
constants::DW_FORM_block2 => {
let block = length_u16_value(input)?;
AttributeValue::Block(block)
}
constants::DW_FORM_block4 => {
let block = length_u32_value(input)?;
AttributeValue::Block(block)
}
constants::DW_FORM_block => {
let block = length_uleb128_value(input)?;
AttributeValue::Block(block)
}
constants::DW_FORM_data1 => {
let data = input.read_u8()?;
AttributeValue::Data1(data)
}
constants::DW_FORM_data2 => {
let data = input.read_u16()?;
AttributeValue::Data2(data)
}
constants::DW_FORM_data4 => {
if encoding.format == Format::Dwarf32
&& allow_section_offset(spec.name(), encoding.version)
{
let offset = input.read_offset(Format::Dwarf32)?;
AttributeValue::SecOffset(offset)
} else {
let data = input.read_u32()?;
AttributeValue::Data4(data)
}
}
constants::DW_FORM_data8 => {
if encoding.format == Format::Dwarf64
&& allow_section_offset(spec.name(), encoding.version)
{
let offset = input.read_offset(Format::Dwarf64)?;
AttributeValue::SecOffset(offset)
} else {
let data = input.read_u64()?;
AttributeValue::Data8(data)
}
}
constants::DW_FORM_data16 => {
let block = input.split(R::Offset::from_u8(16))?;
AttributeValue::Block(block)
}
constants::DW_FORM_udata => {
let data = input.read_uleb128()?;
AttributeValue::Udata(data)
}
constants::DW_FORM_sdata => {
let data = input.read_sleb128()?;
AttributeValue::Sdata(data)
}
constants::DW_FORM_exprloc => {
let block = length_uleb128_value(input)?;
AttributeValue::Exprloc(Expression(block))
}
constants::DW_FORM_flag => {
let present = input.read_u8()?;
AttributeValue::Flag(present != 0)
}
constants::DW_FORM_flag_present => {
AttributeValue::Flag(true)
}
constants::DW_FORM_sec_offset => {
let offset = input.read_offset(encoding.format)?;
AttributeValue::SecOffset(offset)
}
constants::DW_FORM_ref1 => {
let reference = input.read_u8().map(R::Offset::from_u8)?;
AttributeValue::UnitRef(UnitOffset(reference))
}
constants::DW_FORM_ref2 => {
let reference = input.read_u16().map(R::Offset::from_u16)?;
AttributeValue::UnitRef(UnitOffset(reference))
}
constants::DW_FORM_ref4 => {
let reference = input.read_u32().map(R::Offset::from_u32)?;
AttributeValue::UnitRef(UnitOffset(reference))
}
constants::DW_FORM_ref8 => {
let reference = input.read_u64().and_then(R::Offset::from_u64)?;
AttributeValue::UnitRef(UnitOffset(reference))
}
constants::DW_FORM_ref_udata => {
let reference = input.read_uleb128().and_then(R::Offset::from_u64)?;
AttributeValue::UnitRef(UnitOffset(reference))
}
constants::DW_FORM_ref_addr => {
let offset = if encoding.version == 2 {
input.read_sized_offset(encoding.address_size)?
} else {
input.read_offset(encoding.format)?
};
AttributeValue::DebugInfoRef(DebugInfoOffset(offset))
}
constants::DW_FORM_ref_sig8 => {
let signature = input.read_u64()?;
AttributeValue::DebugTypesRef(DebugTypeSignature(signature))
}
constants::DW_FORM_ref_sup4 => {
let offset = input.read_u32().map(R::Offset::from_u32)?;
AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset))
}
constants::DW_FORM_ref_sup8 => {
let offset = input.read_u64().and_then(R::Offset::from_u64)?;
AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset))
}
constants::DW_FORM_GNU_ref_alt => {
let offset = input.read_offset(encoding.format)?;
AttributeValue::DebugInfoRefSup(DebugInfoOffset(offset))
}
constants::DW_FORM_string => {
let string = input.read_null_terminated_slice()?;
AttributeValue::String(string)
}
constants::DW_FORM_strp => {
let offset = input.read_offset(encoding.format)?;
AttributeValue::DebugStrRef(DebugStrOffset(offset))
}
constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => {
let offset = input.read_offset(encoding.format)?;
AttributeValue::DebugStrRefSup(DebugStrOffset(offset))
}
constants::DW_FORM_line_strp => {
let offset = input.read_offset(encoding.format)?;
AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset))
}
constants::DW_FORM_implicit_const => {
let data = spec
.implicit_const_value()
.ok_or(Error::InvalidImplicitConst)?;
AttributeValue::Sdata(data)
}
constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => {
let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
}
constants::DW_FORM_strx1 => {
let index = input.read_u8().map(R::Offset::from_u8)?;
AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
}
constants::DW_FORM_strx2 => {
let index = input.read_u16().map(R::Offset::from_u16)?;
AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
}
constants::DW_FORM_strx3 => {
let index = input.read_uint(3).and_then(R::Offset::from_u64)?;
AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
}
constants::DW_FORM_strx4 => {
let index = input.read_u32().map(R::Offset::from_u32)?;
AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
}
constants::DW_FORM_addrx | constants::DW_FORM_GNU_addr_index => {
let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
}
constants::DW_FORM_addrx1 => {
let index = input.read_u8().map(R::Offset::from_u8)?;
AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
}
constants::DW_FORM_addrx2 => {
let index = input.read_u16().map(R::Offset::from_u16)?;
AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
}
constants::DW_FORM_addrx3 => {
let index = input.read_uint(3).and_then(R::Offset::from_u64)?;
AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
}
constants::DW_FORM_addrx4 => {
let index = input.read_u32().map(R::Offset::from_u32)?;
AttributeValue::DebugAddrIndex(DebugAddrIndex(index))
}
constants::DW_FORM_loclistx => {
let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
AttributeValue::DebugLocListsIndex(DebugLocListsIndex(index))
}
constants::DW_FORM_rnglistx => {
let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
AttributeValue::DebugRngListsIndex(DebugRngListsIndex(index))
}
_ => {
return Err(Error::UnknownForm(form));
}
};
let attr = Attribute {
name: spec.name(),
value,
};
return Ok(attr);
}
}
pub(crate) fn skip_attributes<R: Reader>(
input: &mut R,
encoding: Encoding,
specs: &[AttributeSpecification],
) -> Result<()> {
let mut skip_bytes = R::Offset::from_u8(0);
for spec in specs {
let mut form = spec.form();
loop {
if let Some(len) = get_attribute_size(form, encoding) {
skip_bytes += R::Offset::from_u8(len);
break;
}
if skip_bytes != R::Offset::from_u8(0) {
input.skip(skip_bytes)?;
skip_bytes = R::Offset::from_u8(0);
}
match form {
constants::DW_FORM_indirect => {
let dynamic_form = input.read_uleb128_u16()?;
form = constants::DwForm(dynamic_form);
continue;
}
constants::DW_FORM_block1 => {
skip_bytes = input.read_u8().map(R::Offset::from_u8)?;
}
constants::DW_FORM_block2 => {
skip_bytes = input.read_u16().map(R::Offset::from_u16)?;
}
constants::DW_FORM_block4 => {
skip_bytes = input.read_u32().map(R::Offset::from_u32)?;
}
constants::DW_FORM_block | constants::DW_FORM_exprloc => {
skip_bytes = input.read_uleb128().and_then(R::Offset::from_u64)?;
}
constants::DW_FORM_string => {
let _ = input.read_null_terminated_slice()?;
}
constants::DW_FORM_udata
| constants::DW_FORM_sdata
| constants::DW_FORM_ref_udata
| constants::DW_FORM_strx
| constants::DW_FORM_GNU_str_index
| constants::DW_FORM_addrx
| constants::DW_FORM_GNU_addr_index
| constants::DW_FORM_loclistx
| constants::DW_FORM_rnglistx => {
input.skip_leb128()?;
}
_ => {
return Err(Error::UnknownForm(form));
}
};
break;
}
}
if skip_bytes != R::Offset::from_u8(0) {
input.skip(skip_bytes)?;
}
Ok(())
}
#[derive(Clone, Copy, Debug)]
pub struct AttrsIter<'abbrev, 'entry, 'unit, R: Reader> {
input: R,
attributes: &'abbrev [AttributeSpecification],
entry: &'entry DebuggingInformationEntry<'abbrev, 'unit, R>,
}
impl<'abbrev, 'entry, 'unit, R: Reader> AttrsIter<'abbrev, 'entry, 'unit, R> {
#[inline(always)]
pub fn next(&mut self) -> Result<Option<Attribute<R>>> {
if self.attributes.is_empty() {
if let Some(end) = self.entry.attrs_len.get() {
debug_assert_eq!(end, self.input.offset_from(&self.entry.attrs_slice));
} else {
self.entry
.attrs_len
.set(Some(self.input.offset_from(&self.entry.attrs_slice)));
}
return Ok(None);
}
let spec = self.attributes[0];
let rest_spec = &self.attributes[1..];
match parse_attribute(&mut self.input, self.entry.unit.encoding(), spec) {
Ok(attr) => {
self.attributes = rest_spec;
Ok(Some(attr))
}
Err(e) => {
self.input.empty();
Err(e)
}
}
}
}
#[cfg(feature = "fallible-iterator")]
impl<'abbrev, 'entry, 'unit, R: Reader> fallible_iterator::FallibleIterator
for AttrsIter<'abbrev, 'entry, 'unit, R>
{
type Item = Attribute<R>;
type Error = Error;
fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
AttrsIter::next(self)
}
}
#[derive(Clone, Debug)]
pub struct EntriesRaw<'abbrev, 'unit, R>
where
R: Reader,
{
input: R,
unit: &'unit UnitHeader<R>,
abbreviations: &'abbrev Abbreviations,
depth: isize,
}
impl<'abbrev, 'unit, R: Reader> EntriesRaw<'abbrev, 'unit, R> {
#[inline]
pub fn is_empty(&self) -> bool {
self.input.is_empty()
}
pub fn next_offset(&self) -> UnitOffset<R::Offset> {
UnitOffset(self.unit.header_size() + self.input.offset_from(&self.unit.entries_buf))
}
#[inline]
pub fn next_depth(&self) -> isize {
self.depth
}
#[inline]
pub fn read_abbreviation(&mut self) -> Result<Option<&'abbrev Abbreviation>> {
let code = self.input.read_uleb128()?;
if code == 0 {
self.depth -= 1;
return Ok(None);
};
let abbrev = self
.abbreviations
.get(code)
.ok_or(Error::UnknownAbbreviation(code))?;
if abbrev.has_children() {
self.depth += 1;
}
Ok(Some(abbrev))
}
#[inline]
pub fn read_attribute(&mut self, spec: AttributeSpecification) -> Result<Attribute<R>> {
parse_attribute(&mut self.input, self.unit.encoding(), spec)
}
#[inline]
pub fn skip_attributes(&mut self, specs: &[AttributeSpecification]) -> Result<()> {
skip_attributes(&mut self.input, self.unit.encoding(), specs)
}
}
#[derive(Clone, Debug)]
pub struct EntriesCursor<'abbrev, 'unit, R>
where
R: Reader,
{
input: R,
unit: &'unit UnitHeader<R>,
abbreviations: &'abbrev Abbreviations,
cached_current: Option<DebuggingInformationEntry<'abbrev, 'unit, R>>,
delta_depth: isize,
}
impl<'abbrev, 'unit, R: Reader> EntriesCursor<'abbrev, 'unit, R> {
#[inline]
pub fn current(&self) -> Option<&DebuggingInformationEntry<'abbrev, 'unit, R>> {
self.cached_current.as_ref()
}
pub fn next_entry(&mut self) -> Result<Option<()>> {
if let Some(ref current) = self.cached_current {
self.input = current.after_attrs()?;
}
if self.input.is_empty() {
self.cached_current = None;
self.delta_depth = 0;
return Ok(None);
}
match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) {
Ok(Some(entry)) => {
self.delta_depth = entry.has_children() as isize;
self.cached_current = Some(entry);
Ok(Some(()))
}
Ok(None) => {
self.delta_depth = -1;
self.cached_current = None;
Ok(Some(()))
}
Err(e) => {
self.input.empty();
self.delta_depth = 0;
self.cached_current = None;
Err(e)
}
}
}
pub fn next_dfs(
&mut self,
) -> Result<Option<(isize, &DebuggingInformationEntry<'abbrev, 'unit, R>)>> {
let mut delta_depth = self.delta_depth;
loop {
if self.next_entry()?.is_some() {
if let Some(ref entry) = self.cached_current {
return Ok(Some((delta_depth, entry)));
}
delta_depth += self.delta_depth;
} else {
return Ok(None);
}
}
}
pub fn next_sibling(
&mut self,
) -> Result<Option<&DebuggingInformationEntry<'abbrev, 'unit, R>>> {
if self.current().is_none() {
return Ok(None);
}
let mut depth = 0;
loop {
if self.current().is_some() && self.current().unwrap().has_children() {
if let Some(sibling_input) = self.current().unwrap().sibling() {
self.input = sibling_input;
self.cached_current = None;
} else {
depth += 1;
}
}
if self.next_entry()?.is_none() {
return Ok(None);
}
if depth == 0 {
return Ok(self.current());
}
if self.current().is_none() {
depth -= 1;
}
}
}
}
#[derive(Clone, Debug)]
pub struct EntriesTree<'abbrev, 'unit, R>
where
R: Reader,
{
root: R,
unit: &'unit UnitHeader<R>,
abbreviations: &'abbrev Abbreviations,
input: R,
entry: Option<DebuggingInformationEntry<'abbrev, 'unit, R>>,
depth: isize,
}
impl<'abbrev, 'unit, R: Reader> EntriesTree<'abbrev, 'unit, R> {
fn new(root: R, unit: &'unit UnitHeader<R>, abbreviations: &'abbrev Abbreviations) -> Self {
let input = root.clone();
EntriesTree {
root,
unit,
abbreviations,
input,
entry: None,
depth: 0,
}
}
pub fn root<'me>(&'me mut self) -> Result<EntriesTreeNode<'abbrev, 'unit, 'me, R>> {
self.input = self.root.clone();
self.entry =
DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations)?;
if self.entry.is_none() {
return Err(Error::UnexpectedNull);
}
self.depth = 0;
Ok(EntriesTreeNode::new(self, 1))
}
fn next(&mut self, depth: isize) -> Result<bool> {
if self.depth < depth {
debug_assert_eq!(self.depth + 1, depth);
match self.entry {
Some(ref entry) => {
if !entry.has_children() {
return Ok(false);
}
self.depth += 1;
self.input = entry.after_attrs()?;
}
None => return Ok(false),
}
if self.input.is_empty() {
self.entry = None;
return Ok(false);
}
return match DebuggingInformationEntry::parse(
&mut self.input,
self.unit,
self.abbreviations,
) {
Ok(entry) => {
self.entry = entry;
Ok(self.entry.is_some())
}
Err(e) => {
self.input.empty();
self.entry = None;
Err(e)
}
};
}
loop {
match self.entry {
Some(ref entry) => {
if entry.has_children() {
if let Some(sibling_input) = entry.sibling() {
self.input = sibling_input;
} else {
self.depth += 1;
self.input = entry.after_attrs()?;
}
} else {
self.input = entry.after_attrs()?;
}
}
None => {
self.depth -= 1;
}
}
if self.input.is_empty() {
self.entry = None;
return Ok(false);
}
match DebuggingInformationEntry::parse(&mut self.input, self.unit, self.abbreviations) {
Ok(entry) => {
self.entry = entry;
if self.depth == depth {
return Ok(self.entry.is_some());
}
}
Err(e) => {
self.input.empty();
self.entry = None;
return Err(e);
}
}
}
}
}
#[derive(Debug)]
pub struct EntriesTreeNode<'abbrev, 'unit, 'tree, R: Reader> {
tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
depth: isize,
}
impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeNode<'abbrev, 'unit, 'tree, R> {
fn new(
tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
depth: isize,
) -> EntriesTreeNode<'abbrev, 'unit, 'tree, R> {
debug_assert!(tree.entry.is_some());
EntriesTreeNode { tree, depth }
}
pub fn entry(&self) -> &DebuggingInformationEntry<'abbrev, 'unit, R> {
self.tree.entry.as_ref().unwrap()
}
pub fn children(self) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> {
EntriesTreeIter::new(self.tree, self.depth)
}
}
#[derive(Debug)]
pub struct EntriesTreeIter<'abbrev, 'unit, 'tree, R: Reader> {
tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
depth: isize,
empty: bool,
}
impl<'abbrev, 'unit, 'tree, R: Reader> EntriesTreeIter<'abbrev, 'unit, 'tree, R> {
fn new(
tree: &'tree mut EntriesTree<'abbrev, 'unit, R>,
depth: isize,
) -> EntriesTreeIter<'abbrev, 'unit, 'tree, R> {
EntriesTreeIter {
tree,
depth,
empty: false,
}
}
pub fn next<'me>(&'me mut self) -> Result<Option<EntriesTreeNode<'abbrev, 'unit, 'me, R>>> {
if self.empty {
Ok(None)
} else if self.tree.next(self.depth)? {
Ok(Some(EntriesTreeNode::new(self.tree, self.depth + 1)))
} else {
self.empty = true;
Ok(None)
}
}
}
fn parse_type_signature<R: Reader>(input: &mut R) -> Result<DebugTypeSignature> {
input.read_u64().map(DebugTypeSignature)
}
fn parse_type_offset<R: Reader>(input: &mut R, format: Format) -> Result<UnitOffset<R::Offset>> {
input.read_offset(format).map(UnitOffset)
}
#[derive(Debug, Default, Clone, Copy)]
pub struct DebugTypes<R> {
debug_types_section: R,
}
impl<'input, Endian> DebugTypes<EndianSlice<'input, Endian>>
where
Endian: Endianity,
{
pub fn new(debug_types_section: &'input [u8], endian: Endian) -> Self {
Self::from(EndianSlice::new(debug_types_section, endian))
}
}
impl<T> DebugTypes<T> {
pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugTypes<R>
where
F: FnMut(&'a T) -> R,
{
borrow(&self.debug_types_section).into()
}
}
impl<R> Section<R> for DebugTypes<R> {
fn id() -> SectionId {
SectionId::DebugTypes
}
fn reader(&self) -> &R {
&self.debug_types_section
}
}
impl<R> From<R> for DebugTypes<R> {
fn from(debug_types_section: R) -> Self {
DebugTypes {
debug_types_section,
}
}
}
impl<R: Reader> DebugTypes<R> {
pub fn units(&self) -> DebugTypesUnitHeadersIter<R> {
DebugTypesUnitHeadersIter {
input: self.debug_types_section.clone(),
offset: DebugTypesOffset(R::Offset::from_u8(0)),
}
}
}
#[derive(Clone, Debug)]
pub struct DebugTypesUnitHeadersIter<R: Reader> {
input: R,
offset: DebugTypesOffset<R::Offset>,
}
impl<R: Reader> DebugTypesUnitHeadersIter<R> {
pub fn next(&mut self) -> Result<Option<UnitHeader<R>>> {
if self.input.is_empty() {
Ok(None)
} else {
let len = self.input.len();
match parse_unit_header(&mut self.input, self.offset.into()) {
Ok(header) => {
self.offset.0 += len - self.input.len();
Ok(Some(header))
}
Err(e) => {
self.input.empty();
Err(e)
}
}
}
}
}
#[cfg(feature = "fallible-iterator")]
impl<R: Reader> fallible_iterator::FallibleIterator for DebugTypesUnitHeadersIter<R> {
type Item = UnitHeader<R>;
type Error = Error;
fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
DebugTypesUnitHeadersIter::next(self)
}
}
#[cfg(test)]
#[cfg(feature = "write")]
mod tests {
use super::*;
use crate::constants;
use crate::constants::*;
use crate::endianity::{Endianity, LittleEndian};
use crate::leb128;
use crate::read::abbrev::tests::AbbrevSectionMethods;
use crate::read::{
Abbreviation, AttributeSpecification, DebugAbbrev, EndianSlice, Error, Result,
};
use crate::test_util::GimliSectionMethods;
use alloc::vec::Vec;
use core::cell::Cell;
use test_assembler::{Endian, Label, LabelMaker, Section};
trait UnitSectionMethods {
fn unit<E>(self, unit: &mut UnitHeader<EndianSlice<'_, E>>) -> Self
where
E: Endianity;
fn die<F>(self, code: u64, attr: F) -> Self
where
F: Fn(Section) -> Section;
fn die_null(self) -> Self;
fn attr_string(self, s: &str) -> Self;
fn attr_ref1(self, o: u8) -> Self;
fn offset(self, offset: usize, format: Format) -> Self;
}
impl UnitSectionMethods for Section {
fn unit<E>(self, unit: &mut UnitHeader<EndianSlice<'_, E>>) -> Self
where
E: Endianity,
{
let size = self.size();
let length = Label::new();
let start = Label::new();
let end = Label::new();
let section = match unit.format() {
Format::Dwarf32 => self.L32(&length),
Format::Dwarf64 => self.L32(0xffff_ffff).L64(&length),
};
let section = match unit.version() {
2..=4 => section
.mark(&start)
.L16(unit.version())
.offset(unit.debug_abbrev_offset.0, unit.format())
.D8(unit.address_size()),
5 => section
.mark(&start)
.L16(unit.version())
.D8(unit.type_().dw_ut().0)
.D8(unit.address_size())
.offset(unit.debug_abbrev_offset.0, unit.format()),
_ => unreachable!(),
};
let section = match unit.type_() {
UnitType::Compilation | UnitType::Partial => {
unit.unit_offset = DebugInfoOffset(size as usize).into();
section
}
UnitType::Type {
type_signature,
type_offset,
}
| UnitType::SplitType {
type_signature,
type_offset,
} => {
if unit.version() == 5 {
unit.unit_offset = DebugInfoOffset(size as usize).into();
} else {
unit.unit_offset = DebugTypesOffset(size as usize).into();
}
section
.L64(type_signature.0)
.offset(type_offset.0, unit.format())
}
UnitType::Skeleton(dwo_id) | UnitType::SplitCompilation(dwo_id) => {
unit.unit_offset = DebugInfoOffset(size as usize).into();
section.L64(dwo_id.0)
}
};
let section = section.append_bytes(unit.entries_buf.slice()).mark(&end);
unit.unit_length = (&end - &start) as usize;
length.set_const(unit.unit_length as u64);
section
}
fn die<F>(self, code: u64, attr: F) -> Self
where
F: Fn(Section) -> Section,
{
let section = self.uleb(code);
attr(section)
}
fn die_null(self) -> Self {
self.D8(0)
}
fn attr_string(self, attr: &str) -> Self {
self.append_bytes(attr.as_bytes()).D8(0)
}
fn attr_ref1(self, attr: u8) -> Self {
self.D8(attr)
}
fn offset(self, offset: usize, format: Format) -> Self {
match format {
Format::Dwarf32 => self.L32(offset as u32),
Format::Dwarf64 => self.L64(offset as u64),
}
}
}
#[test]
fn test_unit_header_variance() {
fn _f<'a: 'b, 'b, E: Endianity>(
x: UnitHeader<EndianSlice<'a, E>>,
) -> UnitHeader<EndianSlice<'b, E>> {
x
}
}
#[test]
fn test_parse_debug_abbrev_offset_32() {
let section = Section::with_endian(Endian::Little).L32(0x0403_0201);
let buf = section.get_contents().unwrap();
let buf = &mut EndianSlice::new(&buf, LittleEndian);
match parse_debug_abbrev_offset(buf, Format::Dwarf32) {
Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0403_0201)),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_debug_abbrev_offset_32_incomplete() {
let buf = [0x01, 0x02];
let buf = &mut EndianSlice::new(&buf, LittleEndian);
match parse_debug_abbrev_offset(buf, Format::Dwarf32) {
Err(Error::UnexpectedEof(_)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_debug_abbrev_offset_64() {
let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201);
let buf = section.get_contents().unwrap();
let buf = &mut EndianSlice::new(&buf, LittleEndian);
match parse_debug_abbrev_offset(buf, Format::Dwarf64) {
Ok(val) => assert_eq!(val, DebugAbbrevOffset(0x0807_0605_0403_0201)),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_debug_abbrev_offset_64_incomplete() {
let buf = [0x01, 0x02];
let buf = &mut EndianSlice::new(&buf, LittleEndian);
match parse_debug_abbrev_offset(buf, Format::Dwarf64) {
Err(Error::UnexpectedEof(_)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_debug_info_offset_32() {
let section = Section::with_endian(Endian::Little).L32(0x0403_0201);
let buf = section.get_contents().unwrap();
let buf = &mut EndianSlice::new(&buf, LittleEndian);
match parse_debug_info_offset(buf, Format::Dwarf32) {
Ok(val) => assert_eq!(val, DebugInfoOffset(0x0403_0201)),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_debug_info_offset_32_incomplete() {
let buf = [0x01, 0x02];
let buf = &mut EndianSlice::new(&buf, LittleEndian);
match parse_debug_info_offset(buf, Format::Dwarf32) {
Err(Error::UnexpectedEof(_)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_debug_info_offset_64() {
let section = Section::with_endian(Endian::Little).L64(0x0807_0605_0403_0201);
let buf = section.get_contents().unwrap();
let buf = &mut EndianSlice::new(&buf, LittleEndian);
match parse_debug_info_offset(buf, Format::Dwarf64) {
Ok(val) => assert_eq!(val, DebugInfoOffset(0x0807_0605_0403_0201)),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_debug_info_offset_64_incomplete() {
let buf = [0x01, 0x02];
let buf = &mut EndianSlice::new(&buf, LittleEndian);
match parse_debug_info_offset(buf, Format::Dwarf64) {
Err(Error::UnexpectedEof(_)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_units() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut unit64 = UnitHeader {
encoding: Encoding {
format: Format::Dwarf64,
version: 4,
address_size: 8,
},
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let mut unit32 = UnitHeader {
encoding: Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
},
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut unit64)
.unit(&mut unit32);
let buf = section.get_contents().unwrap();
let debug_info = DebugInfo::new(&buf, LittleEndian);
let mut units = debug_info.units();
assert_eq!(units.next(), Ok(Some(unit64)));
assert_eq!(units.next(), Ok(Some(unit32)));
assert_eq!(units.next(), Ok(None));
}
#[test]
fn test_unit_version_unknown_version() {
let buf = [0x02, 0x00, 0x00, 0x00, 0xab, 0xcd];
let rest = &mut EndianSlice::new(&buf, LittleEndian);
match parse_unit_header(rest, DebugInfoOffset(0).into()) {
Err(Error::UnknownVersion(0xcdab)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
let buf = [0x02, 0x00, 0x00, 0x00, 0x1, 0x0];
let rest = &mut EndianSlice::new(&buf, LittleEndian);
match parse_unit_header(rest, DebugInfoOffset(0).into()) {
Err(Error::UnknownVersion(1)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_unit_version_incomplete() {
let buf = [0x01, 0x00, 0x00, 0x00, 0x04];
let rest = &mut EndianSlice::new(&buf, LittleEndian);
match parse_unit_header(rest, DebugInfoOffset(0).into()) {
Err(Error::UnexpectedEof(_)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_unit_header_32_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_unit_header_64_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf64,
version: 4,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
fn test_parse_v5_unit_header_32_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf32,
version: 5,
address_size: 4,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_v5_unit_header_64_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf64,
version: 5,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
fn test_parse_v5_partial_unit_header_32_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf32,
version: 5,
address_size: 4,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Partial,
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_v5_partial_unit_header_64_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf64,
version: 5,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Partial,
debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
fn test_parse_v5_skeleton_unit_header_32_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf32,
version: 5,
address_size: 4,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)),
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_v5_skeleton_unit_header_64_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf64,
version: 5,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Skeleton(DwoId(0x0706_5040_0302_1000)),
debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
fn test_parse_v5_split_compilation_unit_header_32_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf32,
version: 5,
address_size: 4,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)),
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_v5_split_compilation_unit_header_64_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf64,
version: 5,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::SplitCompilation(DwoId(0x0706_5040_0302_1000)),
debug_abbrev_offset: DebugAbbrevOffset(0x0102_0304_0506_0708),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
fn test_parse_type_offset_32_ok() {
let buf = [0x12, 0x34, 0x56, 0x78, 0x00];
let rest = &mut EndianSlice::new(&buf, LittleEndian);
match parse_type_offset(rest, Format::Dwarf32) {
Ok(offset) => {
assert_eq!(rest.len(), 1);
assert_eq!(UnitOffset(0x7856_3412), offset);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_type_offset_64_ok() {
let buf = [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0x00];
let rest = &mut EndianSlice::new(&buf, LittleEndian);
match parse_type_offset(rest, Format::Dwarf64) {
Ok(offset) => {
assert_eq!(rest.len(), 1);
assert_eq!(UnitOffset(0xffde_bc9a_7856_3412), offset);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
fn test_parse_type_offset_incomplete() {
let buf = [0xff, 0xff, 0xff];
let rest = &mut EndianSlice::new(&buf, LittleEndian);
match parse_type_offset(rest, Format::Dwarf32) {
Err(Error::UnexpectedEof(_)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_type_unit_header_32_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Type {
type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
type_offset: UnitOffset(0x7856_3412),
},
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugTypesOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugTypesOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_type_unit_header_64_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf64,
version: 4,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Type {
type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
type_offset: UnitOffset(0x7856_3412_7856_3412),
},
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugTypesOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugTypesOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
fn test_parse_v5_type_unit_header_32_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf32,
version: 5,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Type {
type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
type_offset: UnitOffset(0x7856_3412),
},
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_v5_type_unit_header_64_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf64,
version: 5,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Type {
type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
type_offset: UnitOffset(0x7856_3412_7856_3412),
},
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
fn test_parse_v5_split_type_unit_header_32_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf32,
version: 5,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::SplitType {
type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
type_offset: UnitOffset(0x7856_3412),
},
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_v5_split_type_unit_header_64_ok() {
let expected_rest = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
let encoding = Encoding {
format: Format::Dwarf64,
version: 5,
address_size: 8,
};
let mut expected_unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::SplitType {
type_signature: DebugTypeSignature(0xdead_beef_dead_beef),
type_offset: UnitOffset(0x7856_3412_7856_3412),
},
debug_abbrev_offset: DebugAbbrevOffset(0x0807_0605),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(expected_rest, LittleEndian),
};
let section = Section::with_endian(Endian::Little)
.unit(&mut expected_unit)
.append_bytes(expected_rest);
let buf = section.get_contents().unwrap();
let rest = &mut EndianSlice::new(&buf, LittleEndian);
assert_eq!(
parse_unit_header(rest, DebugInfoOffset(0).into()),
Ok(expected_unit)
);
assert_eq!(*rest, EndianSlice::new(expected_rest, LittleEndian));
}
fn section_contents<F>(f: F) -> Vec<u8>
where
F: Fn(Section) -> Section,
{
f(Section::with_endian(Endian::Little))
.get_contents()
.unwrap()
}
#[test]
fn test_attribute_value() {
let mut unit = test_parse_attribute_unit_default();
let endian = unit.entries_buf.endian();
let block_data = &[1, 2, 3, 4];
let buf = section_contents(|s| s.uleb(block_data.len() as u64).append_bytes(block_data));
let block = EndianSlice::new(&buf, endian);
let buf = section_contents(|s| s.L32(0x0102_0304));
let data4 = EndianSlice::new(&buf, endian);
let buf = section_contents(|s| s.L64(0x0102_0304_0506_0708));
let data8 = EndianSlice::new(&buf, endian);
let tests = [
(
Format::Dwarf32,
2,
constants::DW_AT_data_member_location,
constants::DW_FORM_block,
block,
AttributeValue::Block(EndianSlice::new(block_data, endian)),
AttributeValue::Exprloc(Expression(EndianSlice::new(block_data, endian))),
),
(
Format::Dwarf32,
2,
constants::DW_AT_data_member_location,
constants::DW_FORM_data4,
data4,
AttributeValue::SecOffset(0x0102_0304),
AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)),
),
(
Format::Dwarf64,
2,
constants::DW_AT_data_member_location,
constants::DW_FORM_data4,
data4,
AttributeValue::Data4(0x0102_0304),
AttributeValue::Udata(0x0102_0304),
),
(
Format::Dwarf32,
4,
constants::DW_AT_data_member_location,
constants::DW_FORM_data4,
data4,
AttributeValue::Data4(0x0102_0304),
AttributeValue::Udata(0x0102_0304),
),
(
Format::Dwarf32,
2,
constants::DW_AT_data_member_location,
constants::DW_FORM_data8,
data8,
AttributeValue::Data8(0x0102_0304_0506_0708),
AttributeValue::Udata(0x0102_0304_0506_0708),
),
#[cfg(target_pointer_width = "64")]
(
Format::Dwarf64,
2,
constants::DW_AT_data_member_location,
constants::DW_FORM_data8,
data8,
AttributeValue::SecOffset(0x0102_0304_0506_0708),
AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)),
),
(
Format::Dwarf64,
4,
constants::DW_AT_data_member_location,
constants::DW_FORM_data8,
data8,
AttributeValue::Data8(0x0102_0304_0506_0708),
AttributeValue::Udata(0x0102_0304_0506_0708),
),
(
Format::Dwarf32,
4,
constants::DW_AT_location,
constants::DW_FORM_data4,
data4,
AttributeValue::SecOffset(0x0102_0304),
AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304)),
),
#[cfg(target_pointer_width = "64")]
(
Format::Dwarf64,
4,
constants::DW_AT_location,
constants::DW_FORM_data8,
data8,
AttributeValue::SecOffset(0x0102_0304_0506_0708),
AttributeValue::LocationListsRef(LocationListsOffset(0x0102_0304_0506_0708)),
),
(
Format::Dwarf32,
4,
constants::DW_AT_str_offsets_base,
constants::DW_FORM_sec_offset,
data4,
AttributeValue::SecOffset(0x0102_0304),
AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(0x0102_0304)),
),
(
Format::Dwarf32,
4,
constants::DW_AT_stmt_list,
constants::DW_FORM_sec_offset,
data4,
AttributeValue::SecOffset(0x0102_0304),
AttributeValue::DebugLineRef(DebugLineOffset(0x0102_0304)),
),
(
Format::Dwarf32,
4,
constants::DW_AT_addr_base,
constants::DW_FORM_sec_offset,
data4,
AttributeValue::SecOffset(0x0102_0304),
AttributeValue::DebugAddrBase(DebugAddrBase(0x0102_0304)),
),
(
Format::Dwarf32,
4,
constants::DW_AT_rnglists_base,
constants::DW_FORM_sec_offset,
data4,
AttributeValue::SecOffset(0x0102_0304),
AttributeValue::DebugRngListsBase(DebugRngListsBase(0x0102_0304)),
),
(
Format::Dwarf32,
4,
constants::DW_AT_loclists_base,
constants::DW_FORM_sec_offset,
data4,
AttributeValue::SecOffset(0x0102_0304),
AttributeValue::DebugLocListsBase(DebugLocListsBase(0x0102_0304)),
),
];
for test in tests.iter() {
let (format, version, name, form, mut input, expect_raw, expect_value) = *test;
unit.encoding.format = format;
unit.encoding.version = version;
let spec = AttributeSpecification::new(name, form, None);
let attribute =
parse_attribute(&mut input, unit.encoding(), spec).expect("Should parse attribute");
assert_eq!(attribute.raw_value(), expect_raw);
assert_eq!(attribute.value(), expect_value);
}
}
#[test]
fn test_attribute_udata_sdata_value() {
#[allow(clippy::type_complexity)]
let tests: &[(
AttributeValue<EndianSlice<'_, LittleEndian>>,
Option<u64>,
Option<i64>,
)] = &[
(AttributeValue::Data1(1), Some(1), Some(1)),
(
AttributeValue::Data1(u8::MAX),
Some(u64::from(u8::MAX)),
Some(-1),
),
(AttributeValue::Data2(1), Some(1), Some(1)),
(
AttributeValue::Data2(u16::MAX),
Some(u64::from(u16::MAX)),
Some(-1),
),
(AttributeValue::Data4(1), Some(1), Some(1)),
(
AttributeValue::Data4(u32::MAX),
Some(u64::from(u32::MAX)),
Some(-1),
),
(AttributeValue::Data8(1), Some(1), Some(1)),
(AttributeValue::Data8(u64::MAX), Some(u64::MAX), Some(-1)),
(AttributeValue::Sdata(1), Some(1), Some(1)),
(AttributeValue::Sdata(-1), None, Some(-1)),
(AttributeValue::Udata(1), Some(1), Some(1)),
(AttributeValue::Udata(1u64 << 63), Some(1u64 << 63), None),
];
for test in tests.iter() {
let (value, expect_udata, expect_sdata) = *test;
let attribute = Attribute {
name: DW_AT_data_member_location,
value,
};
assert_eq!(attribute.udata_value(), expect_udata);
assert_eq!(attribute.sdata_value(), expect_sdata);
}
}
fn test_parse_attribute_unit<Endian>(
address_size: u8,
format: Format,
endian: Endian,
) -> UnitHeader<EndianSlice<'static, Endian>>
where
Endian: Endianity,
{
let encoding = Encoding {
format,
version: 4,
address_size,
};
UnitHeader::new(
encoding,
7,
UnitType::Compilation,
DebugAbbrevOffset(0x0807_0605),
DebugInfoOffset(0).into(),
EndianSlice::new(&[], endian),
)
}
fn test_parse_attribute_unit_default() -> UnitHeader<EndianSlice<'static, LittleEndian>> {
test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian)
}
fn test_parse_attribute<'input, Endian>(
buf: &'input [u8],
len: usize,
unit: &UnitHeader<EndianSlice<'input, Endian>>,
form: constants::DwForm,
value: AttributeValue<EndianSlice<'input, Endian>>,
) where
Endian: Endianity,
{
let spec = AttributeSpecification::new(constants::DW_AT_low_pc, form, None);
let expect = Attribute {
name: constants::DW_AT_low_pc,
value,
};
let rest = &mut EndianSlice::new(buf, Endian::default());
match parse_attribute(rest, unit.encoding(), spec) {
Ok(attr) => {
assert_eq!(attr, expect);
assert_eq!(*rest, EndianSlice::new(&buf[len..], Endian::default()));
if let Some(size) = spec.size(unit) {
assert_eq!(rest.len() + size, buf.len());
}
}
otherwise => {
panic!("Unexpected parse result = {:#?}", otherwise);
}
};
}
#[test]
fn test_parse_attribute_addr() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
let form = constants::DW_FORM_addr;
let value = AttributeValue::Addr(0x0403_0201);
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
fn test_parse_attribute_addr8() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian);
let form = constants::DW_FORM_addr;
let value = AttributeValue::Addr(0x0807_0605_0403_0201);
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_block1() {
let buf = [0x03, 0x09, 0x09, 0x09, 0x00, 0x00];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_block1;
let value = AttributeValue::Block(EndianSlice::new(&buf[1..4], LittleEndian));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
fn test_parse_attribute_block2() {
let buf = [0x02, 0x00, 0x09, 0x09, 0x00, 0x00];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_block2;
let value = AttributeValue::Block(EndianSlice::new(&buf[2..4], LittleEndian));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
fn test_parse_attribute_block4() {
let buf = [0x02, 0x00, 0x00, 0x00, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_block4;
let value = AttributeValue::Block(EndianSlice::new(&buf[4..], LittleEndian));
test_parse_attribute(&buf, 6, &unit, form, value);
}
#[test]
fn test_parse_attribute_block() {
let buf = [0x02, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_block;
let value = AttributeValue::Block(EndianSlice::new(&buf[1..], LittleEndian));
test_parse_attribute(&buf, 3, &unit, form, value);
}
#[test]
fn test_parse_attribute_data1() {
let buf = [0x03];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_data1;
let value = AttributeValue::Data1(0x03);
test_parse_attribute(&buf, 1, &unit, form, value);
}
#[test]
fn test_parse_attribute_data2() {
let buf = [0x02, 0x01, 0x0];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_data2;
let value = AttributeValue::Data2(0x0102);
test_parse_attribute(&buf, 2, &unit, form, value);
}
#[test]
fn test_parse_attribute_data4() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_data4;
let value = AttributeValue::Data4(0x0403_0201);
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
fn test_parse_attribute_data8() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_data8;
let value = AttributeValue::Data8(0x0807_0605_0403_0201);
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_udata() {
let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let bytes_written = {
let mut writable = &mut buf[..];
leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
};
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_udata;
let value = AttributeValue::Udata(4097);
test_parse_attribute(&buf, bytes_written, &unit, form, value);
}
#[test]
fn test_parse_attribute_sdata() {
let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let bytes_written = {
let mut writable = &mut buf[..];
leb128::write::signed(&mut writable, -4097).expect("should write ok")
};
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_sdata;
let value = AttributeValue::Sdata(-4097);
test_parse_attribute(&buf, bytes_written, &unit, form, value);
}
#[test]
fn test_parse_attribute_exprloc() {
let buf = [0x02, 0x99, 0x99, 0x11];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_exprloc;
let value = AttributeValue::Exprloc(Expression(EndianSlice::new(&buf[1..3], LittleEndian)));
test_parse_attribute(&buf, 3, &unit, form, value);
}
#[test]
fn test_parse_attribute_flag_true() {
let buf = [0x42];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_flag;
let value = AttributeValue::Flag(true);
test_parse_attribute(&buf, 1, &unit, form, value);
}
#[test]
fn test_parse_attribute_flag_false() {
let buf = [0x00];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_flag;
let value = AttributeValue::Flag(false);
test_parse_attribute(&buf, 1, &unit, form, value);
}
#[test]
fn test_parse_attribute_flag_present() {
let buf = [0x01, 0x02, 0x03, 0x04];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_flag_present;
let value = AttributeValue::Flag(true);
test_parse_attribute(&buf, 0, &unit, form, value);
}
#[test]
fn test_parse_attribute_sec_offset_32() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10];
let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
let form = constants::DW_FORM_sec_offset;
let value = AttributeValue::SecOffset(0x0403_0201);
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_attribute_sec_offset_64() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_sec_offset;
let value = AttributeValue::SecOffset(0x0807_0605_0403_0201);
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_ref1() {
let buf = [0x03];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_ref1;
let value = AttributeValue::UnitRef(UnitOffset(3));
test_parse_attribute(&buf, 1, &unit, form, value);
}
#[test]
fn test_parse_attribute_ref2() {
let buf = [0x02, 0x01, 0x0];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_ref2;
let value = AttributeValue::UnitRef(UnitOffset(258));
test_parse_attribute(&buf, 2, &unit, form, value);
}
#[test]
fn test_parse_attribute_ref4() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_ref4;
let value = AttributeValue::UnitRef(UnitOffset(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_attribute_ref8() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_ref8;
let value = AttributeValue::UnitRef(UnitOffset(0x0807_0605_0403_0201));
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_ref_sup4() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_ref_sup4;
let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_attribute_ref_sup8() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_ref_sup8;
let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201));
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_refudata() {
let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let bytes_written = {
let mut writable = &mut buf[..];
leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
};
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_ref_udata;
let value = AttributeValue::UnitRef(UnitOffset(4097));
test_parse_attribute(&buf, bytes_written, &unit, form, value);
}
#[test]
fn test_parse_attribute_refaddr_32() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
let form = constants::DW_FORM_ref_addr;
let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_attribute_refaddr_64() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_ref_addr;
let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201));
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_refaddr_version2() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let mut unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
unit.encoding.version = 2;
let form = constants::DW_FORM_ref_addr;
let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_attribute_refaddr8_version2() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let mut unit = test_parse_attribute_unit(8, Format::Dwarf32, LittleEndian);
unit.encoding.version = 2;
let form = constants::DW_FORM_ref_addr;
let value = AttributeValue::DebugInfoRef(DebugInfoOffset(0x0807_0605_0403_0201));
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_gnu_ref_alt_32() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
let form = constants::DW_FORM_GNU_ref_alt;
let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_attribute_gnu_ref_alt_64() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_GNU_ref_alt;
let value = AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x0807_0605_0403_0201));
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_refsig8() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_ref_sig8;
let value = AttributeValue::DebugTypesRef(DebugTypeSignature(0x0807_0605_0403_0201));
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_string() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x0, 0x99, 0x99];
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_string;
let value = AttributeValue::String(EndianSlice::new(&buf[..5], LittleEndian));
test_parse_attribute(&buf, 6, &unit, form, value);
}
#[test]
fn test_parse_attribute_strp_32() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
let form = constants::DW_FORM_strp;
let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_attribute_strp_64() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_strp;
let value = AttributeValue::DebugStrRef(DebugStrOffset(0x0807_0605_0403_0201));
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_strp_sup_32() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
let form = constants::DW_FORM_strp_sup;
let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_attribute_strp_sup_64() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_strp_sup;
let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201));
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_gnu_strp_alt_32() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf32, LittleEndian);
let form = constants::DW_FORM_GNU_strp_alt;
let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_attribute_gnu_strp_alt_64() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_GNU_strp_alt;
let value = AttributeValue::DebugStrRefSup(DebugStrOffset(0x0807_0605_0403_0201));
test_parse_attribute(&buf, 8, &unit, form, value);
}
#[test]
fn test_parse_attribute_strx() {
let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let bytes_written = {
let mut writable = &mut buf[..];
leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
};
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_strx;
let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(4097));
test_parse_attribute(&buf, bytes_written, &unit, form, value);
}
#[test]
fn test_parse_attribute_strx1() {
let buf = [0x01, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_strx1;
let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x01));
test_parse_attribute(&buf, 1, &unit, form, value);
}
#[test]
fn test_parse_attribute_strx2() {
let buf = [0x01, 0x02, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_strx2;
let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0201));
test_parse_attribute(&buf, 2, &unit, form, value);
}
#[test]
fn test_parse_attribute_strx3() {
let buf = [0x01, 0x02, 0x03, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_strx3;
let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x03_0201));
test_parse_attribute(&buf, 3, &unit, form, value);
}
#[test]
fn test_parse_attribute_strx4() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_strx4;
let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
fn test_parse_attribute_addrx() {
let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let bytes_written = {
let mut writable = &mut buf[..];
leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
};
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_addrx;
let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(4097));
test_parse_attribute(&buf, bytes_written, &unit, form, value);
}
#[test]
fn test_parse_attribute_addrx1() {
let buf = [0x01, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_addrx1;
let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x01));
test_parse_attribute(&buf, 1, &unit, form, value);
}
#[test]
fn test_parse_attribute_addrx2() {
let buf = [0x01, 0x02, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_addrx2;
let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0201));
test_parse_attribute(&buf, 2, &unit, form, value);
}
#[test]
fn test_parse_attribute_addrx3() {
let buf = [0x01, 0x02, 0x03, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_addrx3;
let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x03_0201));
test_parse_attribute(&buf, 3, &unit, form, value);
}
#[test]
fn test_parse_attribute_addrx4() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99];
let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian);
let form = constants::DW_FORM_addrx4;
let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0403_0201));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
fn test_parse_attribute_loclistx() {
let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let bytes_written = {
let mut writable = &mut buf[..];
leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
};
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_loclistx;
let value = AttributeValue::DebugLocListsIndex(DebugLocListsIndex(4097));
test_parse_attribute(&buf, bytes_written, &unit, form, value);
}
#[test]
fn test_parse_attribute_rnglistx() {
let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let bytes_written = {
let mut writable = &mut buf[..];
leb128::write::unsigned(&mut writable, 4097).expect("should write ok")
};
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_rnglistx;
let value = AttributeValue::DebugRngListsIndex(DebugRngListsIndex(4097));
test_parse_attribute(&buf, bytes_written, &unit, form, value);
}
#[test]
fn test_parse_attribute_indirect() {
let mut buf = [0; 100];
let bytes_written = {
let mut writable = &mut buf[..];
leb128::write::unsigned(&mut writable, constants::DW_FORM_udata.0.into())
.expect("should write udata")
+ leb128::write::unsigned(&mut writable, 9_999_999).expect("should write value")
};
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_indirect;
let value = AttributeValue::Udata(9_999_999);
test_parse_attribute(&buf, bytes_written, &unit, form, value);
}
#[test]
fn test_parse_attribute_indirect_implicit_const() {
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut buf = [0; 100];
let mut writable = &mut buf[..];
leb128::write::unsigned(&mut writable, constants::DW_FORM_implicit_const.0.into())
.expect("should write implicit_const");
let input = &mut EndianSlice::new(&buf, LittleEndian);
let spec =
AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_indirect, None);
assert_eq!(
parse_attribute(input, encoding, spec),
Err(Error::InvalidImplicitConst)
);
}
#[test]
fn test_attrs_iter() {
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let unit = UnitHeader::new(
encoding,
7,
UnitType::Compilation,
DebugAbbrevOffset(0x0807_0605),
DebugInfoOffset(0).into(),
EndianSlice::new(&[], LittleEndian),
);
let abbrev = Abbreviation::new(
42,
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_yes,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None),
AttributeSpecification::new(
constants::DW_AT_high_pc,
constants::DW_FORM_addr,
None,
),
]
.into(),
);
let buf = [
0x66, 0x6f, 0x6f, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x39, 0x05, 0x00, 0x00, 0xaa, 0xaa,
0xaa, 0xaa,
];
let entry = DebuggingInformationEntry {
offset: UnitOffset(0),
attrs_slice: EndianSlice::new(&buf, LittleEndian),
attrs_len: Cell::new(None),
abbrev: &abbrev,
unit: &unit,
};
let mut attrs = AttrsIter {
input: EndianSlice::new(&buf, LittleEndian),
attributes: abbrev.attributes(),
entry: &entry,
};
match attrs.next() {
Ok(Some(attr)) => {
assert_eq!(
attr,
Attribute {
name: constants::DW_AT_name,
value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)),
}
);
}
otherwise => {
panic!("Unexpected parse result = {:#?}", otherwise);
}
}
assert!(entry.attrs_len.get().is_none());
match attrs.next() {
Ok(Some(attr)) => {
assert_eq!(
attr,
Attribute {
name: constants::DW_AT_low_pc,
value: AttributeValue::Addr(0x2a),
}
);
}
otherwise => {
panic!("Unexpected parse result = {:#?}", otherwise);
}
}
assert!(entry.attrs_len.get().is_none());
match attrs.next() {
Ok(Some(attr)) => {
assert_eq!(
attr,
Attribute {
name: constants::DW_AT_high_pc,
value: AttributeValue::Addr(0x539),
}
);
}
otherwise => {
panic!("Unexpected parse result = {:#?}", otherwise);
}
}
assert!(entry.attrs_len.get().is_none());
assert!(attrs.next().expect("should parse next").is_none());
assert!(entry.attrs_len.get().is_some());
assert_eq!(
entry.attrs_len.get().expect("should have entry.attrs_len"),
buf.len() - 4
)
}
#[test]
fn test_attrs_iter_incomplete() {
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let unit = UnitHeader::new(
encoding,
7,
UnitType::Compilation,
DebugAbbrevOffset(0x0807_0605),
DebugInfoOffset(0).into(),
EndianSlice::new(&[], LittleEndian),
);
let abbrev = Abbreviation::new(
42,
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_yes,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None),
AttributeSpecification::new(
constants::DW_AT_high_pc,
constants::DW_FORM_addr,
None,
),
]
.into(),
);
let buf = [0x66, 0x6f, 0x6f, 0x00];
let entry = DebuggingInformationEntry {
offset: UnitOffset(0),
attrs_slice: EndianSlice::new(&buf, LittleEndian),
attrs_len: Cell::new(None),
abbrev: &abbrev,
unit: &unit,
};
let mut attrs = AttrsIter {
input: EndianSlice::new(&buf, LittleEndian),
attributes: abbrev.attributes(),
entry: &entry,
};
match attrs.next() {
Ok(Some(attr)) => {
assert_eq!(
attr,
Attribute {
name: constants::DW_AT_name,
value: AttributeValue::String(EndianSlice::new(b"foo", LittleEndian)),
}
);
}
otherwise => {
panic!("Unexpected parse result = {:#?}", otherwise);
}
}
assert!(entry.attrs_len.get().is_none());
assert!(attrs.next().is_err());
assert!(entry.attrs_len.get().is_none());
assert!(attrs.next().is_err());
assert!(attrs.next().is_err());
assert!(attrs.next().is_err());
assert!(attrs.next().is_err());
assert!(entry.attrs_len.get().is_none());
}
fn assert_entry_name<Endian>(
entry: &DebuggingInformationEntry<'_, '_, EndianSlice<'_, Endian>>,
name: &str,
) where
Endian: Endianity,
{
let value = entry
.attr_value(constants::DW_AT_name)
.expect("Should have parsed the name attribute")
.expect("Should have found the name attribute");
assert_eq!(
value,
AttributeValue::String(EndianSlice::new(name.as_bytes(), Endian::default()))
);
}
fn assert_current_name<Endian>(
cursor: &EntriesCursor<'_, '_, EndianSlice<'_, Endian>>,
name: &str,
) where
Endian: Endianity,
{
let entry = cursor.current().expect("Should have an entry result");
assert_entry_name(entry, name);
}
fn assert_next_entry<Endian>(
cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, Endian>>,
name: &str,
) where
Endian: Endianity,
{
cursor
.next_entry()
.expect("Should parse next entry")
.expect("Should have an entry");
assert_current_name(cursor, name);
}
fn assert_next_entry_null<Endian>(cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, Endian>>)
where
Endian: Endianity,
{
cursor
.next_entry()
.expect("Should parse next entry")
.expect("Should have an entry");
assert!(cursor.current().is_none());
}
fn assert_next_dfs<Endian>(
cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, Endian>>,
name: &str,
depth: isize,
) where
Endian: Endianity,
{
{
let (val, entry) = cursor
.next_dfs()
.expect("Should parse next dfs")
.expect("Should not be done with traversal");
assert_eq!(val, depth);
assert_entry_name(entry, name);
}
assert_current_name(cursor, name);
}
fn assert_next_sibling<Endian>(
cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, Endian>>,
name: &str,
) where
Endian: Endianity,
{
{
let entry = cursor
.next_sibling()
.expect("Should parse next sibling")
.expect("Should not be done with traversal");
assert_entry_name(entry, name);
}
assert_current_name(cursor, name);
}
fn assert_valid_sibling_ptr<Endian>(cursor: &EntriesCursor<'_, '_, EndianSlice<'_, Endian>>)
where
Endian: Endianity,
{
let sibling_ptr = cursor
.current()
.expect("Should have current entry")
.attr_value(constants::DW_AT_sibling);
match sibling_ptr {
Ok(Some(AttributeValue::UnitRef(offset))) => {
cursor
.unit
.range_from(offset..)
.expect("Sibling offset should be valid");
}
_ => panic!("Invalid sibling pointer {:?}", sibling_ptr),
}
}
fn entries_cursor_tests_abbrev_buf() -> Vec<u8> {
#[rustfmt::skip]
let section = Section::with_endian(Endian::Little)
.abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes)
.abbrev_attr(DW_AT_name, DW_FORM_string)
.abbrev_attr_null()
.abbrev_null();
section.get_contents().unwrap()
}
fn entries_cursor_tests_debug_info_buf() -> Vec<u8> {
#[rustfmt::skip]
let section = Section::with_endian(Endian::Little)
.die(1, |s| s.attr_string("001"))
.die(1, |s| s.attr_string("002"))
.die(1, |s| s.attr_string("003"))
.die_null()
.die_null()
.die(1, |s| s.attr_string("004"))
.die(1, |s| s.attr_string("005"))
.die_null()
.die(1, |s| s.attr_string("006"))
.die_null()
.die_null()
.die(1, |s| s.attr_string("007"))
.die(1, |s| s.attr_string("008"))
.die(1, |s| s.attr_string("009"))
.die_null()
.die_null()
.die_null()
.die(1, |s| s.attr_string("010"))
.die_null()
.die_null();
let entries_buf = section.get_contents().unwrap();
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(&entries_buf, LittleEndian),
};
let section = Section::with_endian(Endian::Little).unit(&mut unit);
section.get_contents().unwrap()
}
#[test]
fn test_cursor_next_entry_incomplete() {
#[rustfmt::skip]
let section = Section::with_endian(Endian::Little)
.die(1, |s| s.attr_string("001"))
.die(1, |s| s.attr_string("002"))
.die(1, |s| s);
let entries_buf = section.get_contents().unwrap();
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(&entries_buf, LittleEndian),
};
let section = Section::with_endian(Endian::Little).unit(&mut unit);
let info_buf = §ion.get_contents().unwrap();
let debug_info = DebugInfo::new(info_buf, LittleEndian);
let unit = debug_info
.units()
.next()
.expect("should have a unit result")
.expect("and it should be ok");
let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut cursor = unit.entries(&abbrevs);
assert_next_entry(&mut cursor, "001");
assert_next_entry(&mut cursor, "002");
{
cursor
.next_entry()
.expect("Should parse next entry")
.expect("Should have an entry");
let entry = cursor.current().expect("Should have an entry result");
assert!(entry.attrs().next().is_err());
}
assert!(cursor.next_entry().is_err());
assert!(cursor.next_entry().is_err());
}
#[test]
fn test_cursor_next_entry() {
let info_buf = &entries_cursor_tests_debug_info_buf();
let debug_info = DebugInfo::new(info_buf, LittleEndian);
let unit = debug_info
.units()
.next()
.expect("should have a unit result")
.expect("and it should be ok");
let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut cursor = unit.entries(&abbrevs);
assert_next_entry(&mut cursor, "001");
assert_next_entry(&mut cursor, "002");
assert_next_entry(&mut cursor, "003");
assert_next_entry_null(&mut cursor);
assert_next_entry_null(&mut cursor);
assert_next_entry(&mut cursor, "004");
assert_next_entry(&mut cursor, "005");
assert_next_entry_null(&mut cursor);
assert_next_entry(&mut cursor, "006");
assert_next_entry_null(&mut cursor);
assert_next_entry_null(&mut cursor);
assert_next_entry(&mut cursor, "007");
assert_next_entry(&mut cursor, "008");
assert_next_entry(&mut cursor, "009");
assert_next_entry_null(&mut cursor);
assert_next_entry_null(&mut cursor);
assert_next_entry_null(&mut cursor);
assert_next_entry(&mut cursor, "010");
assert_next_entry_null(&mut cursor);
assert_next_entry_null(&mut cursor);
assert!(cursor
.next_entry()
.expect("Should parse next entry")
.is_none());
assert!(cursor.current().is_none());
}
#[test]
fn test_cursor_next_dfs() {
let info_buf = &entries_cursor_tests_debug_info_buf();
let debug_info = DebugInfo::new(info_buf, LittleEndian);
let unit = debug_info
.units()
.next()
.expect("should have a unit result")
.expect("and it should be ok");
let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut cursor = unit.entries(&abbrevs);
assert_next_dfs(&mut cursor, "001", 0);
assert_next_dfs(&mut cursor, "002", 1);
assert_next_dfs(&mut cursor, "003", 1);
assert_next_dfs(&mut cursor, "004", -1);
assert_next_dfs(&mut cursor, "005", 1);
assert_next_dfs(&mut cursor, "006", 0);
assert_next_dfs(&mut cursor, "007", -1);
assert_next_dfs(&mut cursor, "008", 1);
assert_next_dfs(&mut cursor, "009", 1);
assert_next_dfs(&mut cursor, "010", -2);
assert!(cursor.next_dfs().expect("Should parse next dfs").is_none());
assert!(cursor.current().is_none());
}
#[test]
fn test_cursor_next_sibling_no_sibling_ptr() {
let info_buf = &entries_cursor_tests_debug_info_buf();
let debug_info = DebugInfo::new(info_buf, LittleEndian);
let unit = debug_info
.units()
.next()
.expect("should have a unit result")
.expect("and it should be ok");
let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut cursor = unit.entries(&abbrevs);
assert_next_dfs(&mut cursor, "001", 0);
assert_next_dfs(&mut cursor, "002", 1);
assert_next_sibling(&mut cursor, "004");
assert_next_sibling(&mut cursor, "007");
assert_next_sibling(&mut cursor, "010");
assert!(cursor
.next_sibling()
.expect("Should parse next sibling")
.is_none());
assert!(cursor.current().is_none());
}
#[test]
fn test_cursor_next_sibling_continuation() {
let info_buf = &entries_cursor_tests_debug_info_buf();
let debug_info = DebugInfo::new(info_buf, LittleEndian);
let unit = debug_info
.units()
.next()
.expect("should have a unit result")
.expect("and it should be ok");
let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut cursor = unit.entries(&abbrevs);
assert_next_dfs(&mut cursor, "001", 0);
assert_next_dfs(&mut cursor, "002", 1);
assert_next_sibling(&mut cursor, "004");
assert_next_dfs(&mut cursor, "005", 1);
assert_next_sibling(&mut cursor, "006");
assert!(cursor
.next_sibling()
.expect("Should parse next sibling")
.is_none());
assert!(cursor
.next_sibling()
.expect("Should parse next sibling")
.is_none());
assert!(cursor
.next_sibling()
.expect("Should parse next sibling")
.is_none());
assert!(cursor
.next_sibling()
.expect("Should parse next sibling")
.is_none());
assert_next_dfs(&mut cursor, "007", -1);
assert_next_sibling(&mut cursor, "010");
assert!(cursor
.next_sibling()
.expect("Should parse next sibling")
.is_none());
assert!(cursor.current().is_none());
}
fn entries_cursor_sibling_abbrev_buf() -> Vec<u8> {
#[rustfmt::skip]
let section = Section::with_endian(Endian::Little)
.abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes)
.abbrev_attr(DW_AT_name, DW_FORM_string)
.abbrev_attr(DW_AT_sibling, DW_FORM_ref1)
.abbrev_attr_null()
.abbrev(2, DW_TAG_subprogram, DW_CHILDREN_yes)
.abbrev_attr(DW_AT_name, DW_FORM_string)
.abbrev_attr_null()
.abbrev_null();
section.get_contents().unwrap()
}
fn entries_cursor_sibling_entries_buf(header_size: usize) -> Vec<u8> {
let start = Label::new();
let sibling004_ref = Label::new();
let sibling004 = Label::new();
let sibling009_ref = Label::new();
let sibling009 = Label::new();
#[rustfmt::skip]
let section = Section::with_endian(Endian::Little)
.mark(&start)
.die(2, |s| s.attr_string("001"))
.die(1, |s| s.attr_string("002").D8(&sibling004_ref))
.die(10, |s| s.attr_string("003"))
.die_null()
.die_null()
.mark(&sibling004)
.die(1, |s| s.attr_string("004").attr_ref1(255))
.die(2, |s| s.attr_string("005"))
.die_null()
.die_null()
.die(2, |s| s.attr_string("006"))
.die(1, |s| s.attr_string("007").D8(&sibling009_ref))
.die(10, |s| s.attr_string("008"))
.die_null()
.die_null()
.mark(&sibling009)
.die(2, |s| s.attr_string("009"))
.die_null()
.die_null()
.die(2, |s| s.attr_string("010"))
.die(2, |s| s.attr_string("011"))
.die_null()
.die_null()
.die_null();
let offset = header_size as u64 + (&sibling004 - &start) as u64;
sibling004_ref.set_const(offset);
let offset = header_size as u64 + (&sibling009 - &start) as u64;
sibling009_ref.set_const(offset);
section.get_contents().unwrap()
}
fn test_cursor_next_sibling_with_ptr(
cursor: &mut EntriesCursor<'_, '_, EndianSlice<'_, LittleEndian>>,
) {
assert_next_dfs(cursor, "001", 0);
assert_next_dfs(cursor, "002", 1);
assert_valid_sibling_ptr(cursor);
assert_next_sibling(cursor, "004");
assert_next_sibling(cursor, "006");
assert_next_sibling(cursor, "010");
assert!(cursor
.next_sibling()
.expect("Should parse next sibling")
.is_none());
assert!(cursor.current().is_none());
}
#[test]
fn test_debug_info_next_sibling_with_ptr() {
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(&[], LittleEndian),
};
let header_size = unit.size_of_header();
let entries_buf = entries_cursor_sibling_entries_buf(header_size);
unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian);
let section = Section::with_endian(Endian::Little).unit(&mut unit);
let info_buf = section.get_contents().unwrap();
let debug_info = DebugInfo::new(&info_buf, LittleEndian);
let unit = debug_info
.units()
.next()
.expect("should have a unit result")
.expect("and it should be ok");
let abbrev_buf = entries_cursor_sibling_abbrev_buf();
let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian);
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut cursor = unit.entries(&abbrevs);
test_cursor_next_sibling_with_ptr(&mut cursor);
}
#[test]
fn test_debug_types_next_sibling_with_ptr() {
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Type {
type_signature: DebugTypeSignature(0),
type_offset: UnitOffset(0),
},
debug_abbrev_offset: DebugAbbrevOffset(0),
unit_offset: DebugTypesOffset(0).into(),
entries_buf: EndianSlice::new(&[], LittleEndian),
};
let header_size = unit.size_of_header();
let entries_buf = entries_cursor_sibling_entries_buf(header_size);
unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian);
let section = Section::with_endian(Endian::Little).unit(&mut unit);
let info_buf = section.get_contents().unwrap();
let debug_types = DebugTypes::new(&info_buf, LittleEndian);
let unit = debug_types
.units()
.next()
.expect("should have a unit result")
.expect("and it should be ok");
let abbrev_buf = entries_cursor_sibling_abbrev_buf();
let debug_abbrev = DebugAbbrev::new(&abbrev_buf, LittleEndian);
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut cursor = unit.entries(&abbrevs);
test_cursor_next_sibling_with_ptr(&mut cursor);
}
#[test]
fn test_entries_at_offset() {
let info_buf = &entries_cursor_tests_debug_info_buf();
let debug_info = DebugInfo::new(info_buf, LittleEndian);
let unit = debug_info
.units()
.next()
.expect("should have a unit result")
.expect("and it should be ok");
let abbrevs_buf = &entries_cursor_tests_abbrev_buf();
let debug_abbrev = DebugAbbrev::new(abbrevs_buf, LittleEndian);
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut cursor = unit
.entries_at_offset(&abbrevs, UnitOffset(unit.header_size()))
.unwrap();
assert_next_entry(&mut cursor, "001");
let cursor = unit.entries_at_offset(&abbrevs, UnitOffset(0));
match cursor {
Err(Error::OffsetOutOfBounds) => {}
otherwise => {
panic!("Unexpected parse result = {:#?}", otherwise);
}
}
}
fn entries_tree_tests_debug_abbrevs_buf() -> Vec<u8> {
#[rustfmt::skip]
let section = Section::with_endian(Endian::Little)
.abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes)
.abbrev_attr(DW_AT_name, DW_FORM_string)
.abbrev_attr_null()
.abbrev(2, DW_TAG_subprogram, DW_CHILDREN_no)
.abbrev_attr(DW_AT_name, DW_FORM_string)
.abbrev_attr_null()
.abbrev_null()
.get_contents()
.unwrap();
section
}
fn entries_tree_tests_debug_info_buf(header_size: usize) -> (Vec<u8>, UnitOffset) {
let start = Label::new();
let entry2 = Label::new();
#[rustfmt::skip]
let section = Section::with_endian(Endian::Little)
.mark(&start)
.die(1, |s| s.attr_string("root"))
.die(1, |s| s.attr_string("1"))
.die(1, |s| s.attr_string("1a"))
.die_null()
.die(2, |s| s.attr_string("1b"))
.die_null()
.mark(&entry2)
.die(1, |s| s.attr_string("2"))
.die(1, |s| s.attr_string("2a"))
.die(1, |s| s.attr_string("2a1"))
.die_null()
.die_null()
.die(1, |s| s.attr_string("2b"))
.die(2, |s| s.attr_string("2b1"))
.die_null()
.die_null()
.die(1, |s| s.attr_string("3"))
.die(1, |s| s.attr_string("3a"))
.die(2, |s| s.attr_string("3a1"))
.die(2, |s| s.attr_string("3a2"))
.die_null()
.die(2, |s| s.attr_string("3b"))
.die_null()
.die(2, |s| s.attr_string("final"))
.die_null()
.get_contents()
.unwrap();
let entry2 = UnitOffset(header_size + (&entry2 - &start) as usize);
(section, entry2)
}
#[test]
fn test_entries_tree() {
fn assert_entry<'input, 'abbrev, 'unit, 'tree, Endian>(
node: Result<
Option<EntriesTreeNode<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>>>,
>,
name: &str,
) -> EntriesTreeIter<'abbrev, 'unit, 'tree, EndianSlice<'input, Endian>>
where
Endian: Endianity,
{
let node = node
.expect("Should parse entry")
.expect("Should have entry");
assert_entry_name(node.entry(), name);
node.children()
}
fn assert_null<E: Endianity>(
node: Result<Option<EntriesTreeNode<'_, '_, '_, EndianSlice<'_, E>>>>,
) {
match node {
Ok(None) => {}
otherwise => {
panic!("Unexpected parse result = {:#?}", otherwise);
}
}
}
let abbrevs_buf = entries_tree_tests_debug_abbrevs_buf();
let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian);
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(&[], LittleEndian),
};
let header_size = unit.size_of_header();
let (entries_buf, entry2) = entries_tree_tests_debug_info_buf(header_size);
unit.entries_buf = EndianSlice::new(&entries_buf, LittleEndian);
let info_buf = Section::with_endian(Endian::Little)
.unit(&mut unit)
.get_contents()
.unwrap();
let debug_info = DebugInfo::new(&info_buf, LittleEndian);
let unit = debug_info
.units()
.next()
.expect("Should parse unit")
.expect("and it should be some");
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut tree = unit
.entries_tree(&abbrevs, None)
.expect("Should have entries tree");
{
let mut iter = assert_entry(tree.root().map(Some), "root");
assert_entry(iter.next(), "1");
}
{
let mut iter = assert_entry(tree.root().map(Some), "root");
assert_entry(iter.next(), "1");
}
let mut iter = assert_entry(tree.root().map(Some), "root");
{
let mut iter = assert_entry(iter.next(), "1");
{
let mut iter = assert_entry(iter.next(), "1a");
assert_null(iter.next());
assert_null(iter.next());
}
{
let mut iter = assert_entry(iter.next(), "1b");
assert_null(iter.next());
assert_null(iter.next());
}
assert_null(iter.next());
assert_null(iter.next());
}
{
let mut iter = assert_entry(iter.next(), "2");
assert_entry(iter.next(), "2a");
assert_entry(iter.next(), "2b");
assert_null(iter.next());
}
{
let mut iter = assert_entry(iter.next(), "3");
{
let mut iter = assert_entry(iter.next(), "3a");
assert_entry(iter.next(), "3a1");
}
assert_entry(iter.next(), "3b");
assert_null(iter.next());
}
assert_entry(iter.next(), "final");
assert_null(iter.next());
let mut tree = unit
.entries_tree(&abbrevs, Some(entry2))
.expect("Should have entries tree");
let mut iter = assert_entry(tree.root().map(Some), "2");
assert_entry(iter.next(), "2a");
assert_entry(iter.next(), "2b");
assert_null(iter.next());
}
#[test]
fn test_entries_raw() {
fn assert_abbrev<'abbrev, Endian>(
entries: &mut EntriesRaw<'abbrev, '_, EndianSlice<'_, Endian>>,
tag: DwTag,
) -> &'abbrev Abbreviation
where
Endian: Endianity,
{
let abbrev = entries
.read_abbreviation()
.expect("Should parse abbrev")
.expect("Should have abbrev");
assert_eq!(abbrev.tag(), tag);
abbrev
}
fn assert_null<Endian>(entries: &mut EntriesRaw<'_, '_, EndianSlice<'_, Endian>>)
where
Endian: Endianity,
{
match entries.read_abbreviation() {
Ok(None) => {}
otherwise => {
panic!("Unexpected parse result = {:#?}", otherwise);
}
}
}
fn assert_attr<Endian>(
entries: &mut EntriesRaw<'_, '_, EndianSlice<'_, Endian>>,
spec: Option<AttributeSpecification>,
name: DwAt,
value: &str,
) where
Endian: Endianity,
{
let spec = spec.expect("Should have attribute specification");
let attr = entries
.read_attribute(spec)
.expect("Should parse attribute");
assert_eq!(attr.name(), name);
assert_eq!(
attr.value(),
AttributeValue::String(EndianSlice::new(value.as_bytes(), Endian::default()))
);
}
#[rustfmt::skip]
let section = Section::with_endian(Endian::Little)
.abbrev(1, DW_TAG_subprogram, DW_CHILDREN_yes)
.abbrev_attr(DW_AT_name, DW_FORM_string)
.abbrev_attr(DW_AT_linkage_name, DW_FORM_string)
.abbrev_attr_null()
.abbrev(2, DW_TAG_variable, DW_CHILDREN_no)
.abbrev_attr(DW_AT_name, DW_FORM_string)
.abbrev_attr_null()
.abbrev_null();
let abbrevs_buf = section.get_contents().unwrap();
let debug_abbrev = DebugAbbrev::new(&abbrevs_buf, LittleEndian);
#[rustfmt::skip]
let section = Section::with_endian(Endian::Little)
.die(1, |s| s.attr_string("f1").attr_string("l1"))
.die(2, |s| s.attr_string("v1"))
.die(2, |s| s.attr_string("v2"))
.die(1, |s| s.attr_string("f2").attr_string("l2"))
.die_null()
.die_null();
let entries_buf = section.get_contents().unwrap();
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(&entries_buf, LittleEndian),
};
let section = Section::with_endian(Endian::Little).unit(&mut unit);
let info_buf = section.get_contents().unwrap();
let debug_info = DebugInfo::new(&info_buf, LittleEndian);
let unit = debug_info
.units()
.next()
.expect("should have a unit result")
.expect("and it should be ok");
let abbrevs = unit
.abbreviations(&debug_abbrev)
.expect("Should parse abbreviations");
let mut entries = unit
.entries_raw(&abbrevs, None)
.expect("Should have entries");
assert_eq!(entries.next_depth(), 0);
let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram);
let mut attrs = abbrev.attributes().iter().copied();
assert_attr(&mut entries, attrs.next(), DW_AT_name, "f1");
assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l1");
assert!(attrs.next().is_none());
assert_eq!(entries.next_depth(), 1);
let abbrev = assert_abbrev(&mut entries, DW_TAG_variable);
let mut attrs = abbrev.attributes().iter().copied();
assert_attr(&mut entries, attrs.next(), DW_AT_name, "v1");
assert!(attrs.next().is_none());
assert_eq!(entries.next_depth(), 1);
let abbrev = assert_abbrev(&mut entries, DW_TAG_variable);
let mut attrs = abbrev.attributes().iter().copied();
assert_attr(&mut entries, attrs.next(), DW_AT_name, "v2");
assert!(attrs.next().is_none());
assert_eq!(entries.next_depth(), 1);
let abbrev = assert_abbrev(&mut entries, DW_TAG_subprogram);
let mut attrs = abbrev.attributes().iter().copied();
assert_attr(&mut entries, attrs.next(), DW_AT_name, "f2");
assert_attr(&mut entries, attrs.next(), DW_AT_linkage_name, "l2");
assert!(attrs.next().is_none());
assert_eq!(entries.next_depth(), 2);
assert_null(&mut entries);
assert_eq!(entries.next_depth(), 1);
assert_null(&mut entries);
assert_eq!(entries.next_depth(), 0);
assert!(entries.is_empty());
}
#[test]
fn test_debug_info_offset() {
let padding = &[0; 10];
let entries = &[0; 20];
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(entries, LittleEndian),
};
Section::with_endian(Endian::Little)
.append_bytes(padding)
.unit(&mut unit);
let offset = padding.len();
let header_length = unit.size_of_header();
let length = unit.length_including_self();
assert_eq!(DebugInfoOffset(0).to_unit_offset(&unit), None);
assert_eq!(DebugInfoOffset(offset - 1).to_unit_offset(&unit), None);
assert_eq!(DebugInfoOffset(offset).to_unit_offset(&unit), None);
assert_eq!(
DebugInfoOffset(offset + header_length - 1).to_unit_offset(&unit),
None
);
assert_eq!(
DebugInfoOffset(offset + header_length).to_unit_offset(&unit),
Some(UnitOffset(header_length))
);
assert_eq!(
DebugInfoOffset(offset + length - 1).to_unit_offset(&unit),
Some(UnitOffset(length - 1))
);
assert_eq!(DebugInfoOffset(offset + length).to_unit_offset(&unit), None);
assert_eq!(
UnitOffset(header_length).to_debug_info_offset(&unit),
Some(DebugInfoOffset(offset + header_length))
);
assert_eq!(
UnitOffset(length - 1).to_debug_info_offset(&unit),
Some(DebugInfoOffset(offset + length - 1))
);
}
#[test]
fn test_debug_types_offset() {
let padding = &[0; 10];
let entries = &[0; 20];
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Type {
type_signature: DebugTypeSignature(0),
type_offset: UnitOffset(0),
},
debug_abbrev_offset: DebugAbbrevOffset(0),
unit_offset: DebugTypesOffset(0).into(),
entries_buf: EndianSlice::new(entries, LittleEndian),
};
Section::with_endian(Endian::Little)
.append_bytes(padding)
.unit(&mut unit);
let offset = padding.len();
let header_length = unit.size_of_header();
let length = unit.length_including_self();
assert_eq!(DebugTypesOffset(0).to_unit_offset(&unit), None);
assert_eq!(DebugTypesOffset(offset - 1).to_unit_offset(&unit), None);
assert_eq!(DebugTypesOffset(offset).to_unit_offset(&unit), None);
assert_eq!(
DebugTypesOffset(offset + header_length - 1).to_unit_offset(&unit),
None
);
assert_eq!(
DebugTypesOffset(offset + header_length).to_unit_offset(&unit),
Some(UnitOffset(header_length))
);
assert_eq!(
DebugTypesOffset(offset + length - 1).to_unit_offset(&unit),
Some(UnitOffset(length - 1))
);
assert_eq!(
DebugTypesOffset(offset + length).to_unit_offset(&unit),
None
);
assert_eq!(
UnitOffset(header_length).to_debug_types_offset(&unit),
Some(DebugTypesOffset(offset + header_length))
);
assert_eq!(
UnitOffset(length - 1).to_debug_types_offset(&unit),
Some(DebugTypesOffset(offset + length - 1))
);
}
#[test]
fn test_length_including_self() {
let encoding = Encoding {
format: Format::Dwarf32,
version: 4,
address_size: 4,
};
let mut unit = UnitHeader {
encoding,
unit_length: 0,
unit_type: UnitType::Compilation,
debug_abbrev_offset: DebugAbbrevOffset(0),
unit_offset: DebugInfoOffset(0).into(),
entries_buf: EndianSlice::new(&[], LittleEndian),
};
unit.encoding.format = Format::Dwarf32;
assert_eq!(unit.length_including_self(), 4);
unit.encoding.format = Format::Dwarf64;
assert_eq!(unit.length_including_self(), 12);
unit.unit_length = 10;
assert_eq!(unit.length_including_self(), 22);
}
#[test]
fn test_parse_type_unit_abbrevs() {
let types_buf = [
0x25, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x01, 0x66, 0x6f, 0x6f, 0x00, 0x01, 0x66, 0x6f, 0x6f, 0x00, 0x01, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x00, ];
let debug_types = DebugTypes::new(&types_buf, LittleEndian);
let abbrev_buf = [
0x01, 0x2e, 0x01, 0x03, 0x08, 0x00, 0x00, 0x00, ];
let get_some_type_unit = || debug_types.units().next().unwrap().unwrap();
let unit = get_some_type_unit();
let read_debug_abbrev_section_somehow = || &abbrev_buf;
let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian);
let _abbrevs_for_unit = unit.abbreviations(&debug_abbrev).unwrap();
}
}