use core::error;
use core::fmt::{self, Debug};
use core::result;
#[cfg(feature = "std")]
use std::io;
use crate::common::{Register, SectionId};
use crate::constants;
mod util;
pub use util::*;
mod addr;
pub use self::addr::*;
mod cfi;
pub use self::cfi::*;
#[cfg(feature = "read")]
mod dwarf;
#[cfg(feature = "read")]
pub use self::dwarf::*;
mod endian_slice;
pub use self::endian_slice::*;
#[cfg(feature = "endian-reader")]
mod endian_reader;
#[cfg(feature = "endian-reader")]
pub use self::endian_reader::*;
mod reader;
pub use self::reader::*;
mod relocate;
pub use self::relocate::*;
#[cfg(feature = "read")]
mod abbrev;
#[cfg(feature = "read")]
pub use self::abbrev::*;
mod aranges;
pub use self::aranges::*;
mod index;
pub use self::index::*;
#[cfg(feature = "read")]
mod line;
#[cfg(feature = "read")]
pub use self::line::*;
mod lists;
#[cfg(feature = "read")]
pub use self::lists::ListsHeader;
mod loclists;
pub use self::loclists::*;
#[cfg(feature = "read")]
mod lookup;
#[cfg(feature = "read")]
mod macros;
#[cfg(feature = "read")]
pub use self::macros::*;
#[cfg(feature = "read")]
mod names;
#[cfg(feature = "read")]
pub use self::names::*;
mod op;
pub use self::op::*;
#[cfg(feature = "read")]
mod pubnames;
#[cfg(feature = "read")]
pub use self::pubnames::*;
#[cfg(feature = "read")]
mod pubtypes;
#[cfg(feature = "read")]
pub use self::pubtypes::*;
mod rnglists;
pub use self::rnglists::*;
mod str;
pub use self::str::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct UnitOffset<T = usize>(pub T);
#[cfg(feature = "read")]
mod unit;
#[cfg(feature = "read")]
pub use self::unit::*;
mod value;
pub use self::value::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StoreOnHeap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Error {
Io,
PcRelativePointerButSectionBaseIsUndefined,
TextRelativePointerButTextBaseIsUndefined,
DataRelativePointerButDataBaseIsUndefined,
FuncRelativePointerInBadContext,
CannotParseOmitPointerEncoding,
BadUnsignedLeb128,
BadSignedLeb128,
AbbreviationTagZero,
AttributeNameZero,
AttributeFormZero,
InvalidAbbreviationChildren(constants::DwChildren),
UnknownForm(constants::DwForm),
DuplicateAbbreviationCode(u64),
UnknownReservedLength(u32),
UnknownVersion(u64),
InvalidAbbreviationCode(u64),
UnexpectedEof(ReaderOffsetId),
UnknownLocListsEntry(constants::DwLle),
UnknownRangeListsEntry(constants::DwRle),
UnsupportedAddressSize(u8),
UnsupportedOffsetSize(u8),
MinimumInstructionLengthZero,
MaximumOperationsPerInstructionZero,
LineRangeZero,
OpcodeBaseZero,
BadUtf8,
NotCieId(u64),
NotCiePointer(u64),
BadBranchTarget(u64),
InvalidPushObjectAddress,
NotEnoughStackItems,
TooManyIterations,
InvalidExpression(constants::DwOp),
UnsupportedEvaluation,
InvalidPiece,
InvalidExpressionTerminator(u64),
DivisionByZero,
TypeMismatch,
IntegralTypeRequired,
UnsupportedTypeOperation,
InvalidShiftExpression,
InvalidDerefSize(u8),
InvalidPieceSize(u64),
UnknownCallFrameInstruction(constants::DwCfa),
InvalidCfiSetLoc(u64),
AddressOverflow,
CfiInstructionInInvalidContext,
PopWithEmptyStack,
NoUnwindInfoForAddress,
UnsupportedOffset,
UnknownPointerEncoding(constants::DwEhPe),
NoEntryAtGivenOffset(u64),
OffsetOutOfBounds(u64),
UnknownAugmentation,
UnsupportedPointerEncoding(constants::DwEhPe),
UnsupportedIndirectPointer,
UnsupportedRegister(u64),
TooManyRegisterRules,
StackFull,
UnknownUnitType(constants::DwUt),
UnsupportedSegmentSize(u8),
MissingUnitDie,
MissingSplitUnit,
UnsupportedAttributeForm(constants::DwForm),
MissingFileEntryFormatPath,
ExpectedStringAttributeValue,
InvalidImplicitConst,
UnsupportedIndexSectionCount(u32),
InvalidIndexSlotCount(u32),
InvalidIndexRow(u32),
UnknownIndexSection(constants::DwSect),
UnknownIndexSectionV2(constants::DwSectV2),
InvalidMacinfoType(constants::DwMacinfo),
InvalidMacroType(constants::DwMacro),
UnsupportedOpcodeOperandsTable,
InvalidNameAttributeIndex(u64),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> ::core::result::Result<(), fmt::Error> {
match *self {
Error::Io => write!(f, "I/O error"),
Error::PcRelativePointerButSectionBaseIsUndefined => {
write!(f, "undefined section base for DW_EH_PE_pcrel pointer")
}
Error::TextRelativePointerButTextBaseIsUndefined => {
write!(f, "undefined text base for DW_EH_PE_textrel pointer")
}
Error::DataRelativePointerButDataBaseIsUndefined => {
write!(f, "undefined data base for DW_EH_PE_datarel pointer")
}
Error::FuncRelativePointerInBadContext => {
write!(f, "invalid context for DW_EH_PE_funcrel pointer")
}
Error::CannotParseOmitPointerEncoding => {
write!(f, "invalid encoding for required pointer: DW_EH_PE_omit")
}
Error::BadUnsignedLeb128 => write!(f, "unsigned LEB128 overflow"),
Error::BadSignedLeb128 => write!(f, "signed LEB128 overflow"),
Error::AbbreviationTagZero => {
write!(f, "invalid abbreviation tag: zero")
}
Error::AttributeNameZero => {
write!(f, "invalid attribute name: zero")
}
Error::AttributeFormZero => {
write!(f, "invalid attribute form: zero")
}
Error::InvalidAbbreviationChildren(val) => {
write!(f, "invalid abbreviation children: 0x{:x}", val.0)
}
Error::UnknownForm(val) => write!(f, "unknown attribute form: 0x{:x}", val.0),
Error::DuplicateAbbreviationCode(val) => {
write!(f, "duplicate abbreviation code: {val}")
}
Error::UnknownReservedLength(val) => write!(f, "unknown reserved length: 0x{val:x}"),
Error::UnknownVersion(version) => write!(f, "unknown DWARF version: {version}"),
Error::InvalidAbbreviationCode(val) => {
write!(f, "invalid abbreviation code: {val}")
}
Error::UnexpectedEof(_) => write!(f, "unexpected end of input"),
Error::UnknownLocListsEntry(val) => {
write!(f, "unknown location lists entry: 0x{:x}", val.0)
}
Error::UnknownRangeListsEntry(val) => {
write!(f, "unknown range lists entry: 0x{:x}", val.0)
}
Error::UnsupportedAddressSize(val) => {
write!(f, "unsupported address size: {val}")
}
Error::UnsupportedOffsetSize(val) => {
write!(f, "unsupported offset size: {val}")
}
Error::MinimumInstructionLengthZero => {
write!(f, "invalid minimum line instruction length: zero")
}
Error::MaximumOperationsPerInstructionZero => {
write!(f, "invalid maximum operations per line instruction: zero")
}
Error::LineRangeZero => write!(f, "invalid line range: zero"),
Error::OpcodeBaseZero => write!(f, "invalid line opcode base: zero"),
Error::BadUtf8 => write!(f, "invalid UTF-8"),
Error::NotCieId(val) => write!(f, "invalid CIE at offset 0x{val:x}: missing CIE ID"),
Error::NotCiePointer(val) => {
write!(f, "invalid FDE at offset 0x{val:x}: missing CIE pointer")
}
Error::BadBranchTarget(_) => write!(f, "invalid expression branch target"),
Error::InvalidPushObjectAddress => {
write!(f, "undefined object address for DW_OP_push_object_address")
}
Error::NotEnoughStackItems => {
write!(f, "expression stack underflow")
}
Error::TooManyIterations => {
write!(f, "exceeded maximum expression iterations")
}
Error::InvalidExpression(val) => write!(f, "unknown expression opcode: 0x{:x}", val.0),
Error::UnsupportedEvaluation => {
write!(f, "unsupported evaluation operation")
}
Error::InvalidPiece => {
write!(f, "invalid expression: piece followed by non-piece")
}
Error::InvalidExpressionTerminator(_) => {
write!(f, "invalid expression terminator")
}
Error::DivisionByZero => {
write!(f, "division by zero")
}
Error::TypeMismatch => write!(f, "invalid operand type: mismatch"),
Error::IntegralTypeRequired => {
write!(f, "invalid operand type: integral required")
}
Error::UnsupportedTypeOperation => {
write!(f, "unsupported operand type")
}
Error::InvalidShiftExpression => {
write!(f, "invalid shift amount")
}
Error::InvalidDerefSize(val) => {
write!(f, "invalid deref size: {val}")
}
Error::InvalidPieceSize(val) => {
write!(f, "invalid piece size: {val}")
}
Error::UnknownCallFrameInstruction(val) => {
write!(f, "unknown call frame instruction: 0x{:x}", val.0)
}
Error::InvalidCfiSetLoc(val) => {
write!(f, "invalid DW_CFA_set_loc: address 0x{val:x} goes backward")
}
Error::AddressOverflow => write!(f, "address overflow"),
Error::CfiInstructionInInvalidContext => {
write!(f, "invalid context for call frame instruction")
}
Error::PopWithEmptyStack => {
write!(f, "invalid DW_CFA_restore_state: empty stack")
}
Error::NoUnwindInfoForAddress => {
write!(f, "no unwind info for address")
}
Error::UnsupportedOffset => {
write!(f, "offset overflow")
}
Error::UnknownPointerEncoding(val) => {
write!(f, "unknown pointer encoding: 0x{:x}", val.0)
}
Error::NoEntryAtGivenOffset(val) => write!(f, "no entry at offset: 0x{val:x}"),
Error::OffsetOutOfBounds(val) => write!(f, "invalid offset: 0x{val:x}"),
Error::UnknownAugmentation => write!(f, "unknown CFI augmentation"),
Error::UnsupportedPointerEncoding(val) => {
write!(f, "unsupported pointer encoding: 0x{:x}", val.0)
}
Error::UnsupportedIndirectPointer => {
write!(f, "unsupported indirect pointer")
}
Error::UnsupportedRegister(val) => {
write!(f, "unsupported register: 0x{val:x}")
}
Error::TooManyRegisterRules => {
write!(f, "too many CFI register rules")
}
Error::StackFull => {
write!(f, "CFI stack overflow")
}
Error::UnknownUnitType(val) => {
write!(f, "unknown unit type: 0x{:x}", val.0)
}
Error::UnsupportedSegmentSize(val) => write!(f, "unsupported segment size: {val}"),
Error::MissingUnitDie => {
write!(f, "missing unit DIE")
}
Error::MissingSplitUnit => {
write!(f, "missing split compilation unit")
}
Error::UnsupportedAttributeForm(val) => {
write!(f, "unsupported attribute form: 0x{:x}", val.0)
}
Error::MissingFileEntryFormatPath => {
write!(f, "missing file entry format path")
}
Error::ExpectedStringAttributeValue => {
write!(f, "invalid attribute form for string")
}
Error::InvalidImplicitConst => {
write!(f, "invalid indirect attribute form: DW_FORM_implicit_const")
}
Error::UnsupportedIndexSectionCount(val) => {
write!(f, "unsupported DWP section count: {val}")
}
Error::InvalidIndexSlotCount(val) => write!(f, "invalid DWP slot count: 0x{:x}", val),
Error::InvalidIndexRow(val) => write!(f, "invalid DWP row index: 0x{:x}", val),
Error::UnknownIndexSection(val) => write!(f, "unknown DWP section type: 0x{:x}", val.0),
Error::UnknownIndexSectionV2(val) => {
write!(f, "unknown DWP v2 section type: 0x{:x}", val.0)
}
Error::InvalidMacinfoType(val) => write!(f, "unknown macinfo type: 0x{:x}", val.0),
Error::InvalidMacroType(val) => write!(f, "unknown macro type: 0x{:x}", val.0),
Error::UnsupportedOpcodeOperandsTable => {
write!(f, "unsupported macro opcode operands table")
}
Error::InvalidNameAttributeIndex(val) => {
write!(f, "invalid index in name attribute: 0x{val:x}")
}
}
}
}
impl error::Error for Error {}
#[cfg(feature = "std")]
impl From<io::Error> for Error {
fn from(_: io::Error) -> Self {
Error::Io
}
}
pub type Result<T> = result::Result<T, Error>;
pub trait Section<R>: From<R> {
fn id() -> SectionId;
fn section_name() -> &'static str {
Self::id().name()
}
fn dwo_section_name() -> Option<&'static str> {
Self::id().dwo_name()
}
fn xcoff_section_name() -> Option<&'static str> {
Self::id().xcoff_name()
}
fn load<F, E>(f: F) -> core::result::Result<Self, E>
where
F: FnOnce(SectionId) -> core::result::Result<R, E>,
{
f(Self::id()).map(From::from)
}
fn reader(&self) -> &R
where
R: Reader;
fn dwp_range(&self, offset: u32, size: u32) -> Result<Self>
where
R: Reader,
{
let mut data = self.reader().clone();
data.skip(R::Offset::from_u32(offset))?;
data.truncate(R::Offset::from_u32(size))?;
Ok(data.into())
}
fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)>
where
R: Reader,
{
self.reader()
.lookup_offset_id(id)
.map(|offset| (Self::id(), offset))
}
}
impl Register {
pub(crate) fn from_u64(x: u64) -> Result<Register> {
let y = x as u16;
if u64::from(y) == x {
Ok(Register(y))
} else {
Err(Error::UnsupportedRegister(x))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::Format;
use crate::endianity::LittleEndian;
use test_assembler::{Endian, Section};
#[test]
fn test_parse_initial_length_32_ok() {
let section = Section::with_endian(Endian::Little).L32(0x7856_3412);
let buf = section.get_contents().unwrap();
let input = &mut EndianSlice::new(&buf, LittleEndian);
match input.read_initial_length() {
Ok((length, format)) => {
assert_eq!(input.len(), 0);
assert_eq!(format, Format::Dwarf32);
assert_eq!(0x7856_3412, length);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
fn test_parse_initial_length_64_ok() {
let section = Section::with_endian(Endian::Little)
.L32(0xffff_ffff)
.L64(0xffde_bc9a_7856_3412);
let buf = section.get_contents().unwrap();
let input = &mut EndianSlice::new(&buf, LittleEndian);
#[cfg(target_pointer_width = "64")]
match input.read_initial_length() {
Ok((length, format)) => {
assert_eq!(input.len(), 0);
assert_eq!(format, Format::Dwarf64);
assert_eq!(0xffde_bc9a_7856_3412, length);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
#[cfg(target_pointer_width = "32")]
match input.read_initial_length() {
Err(Error::UnsupportedOffset) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_initial_length_unknown_reserved_value() {
let section = Section::with_endian(Endian::Little).L32(0xffff_fffe);
let buf = section.get_contents().unwrap();
let input = &mut EndianSlice::new(&buf, LittleEndian);
match input.read_initial_length() {
Err(Error::UnknownReservedLength(0xffff_fffe)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_initial_length_incomplete() {
let buf = [0xff, 0xff, 0xff];
let input = &mut EndianSlice::new(&buf, LittleEndian);
match input.read_initial_length() {
Err(Error::UnexpectedEof(_)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_initial_length_64_incomplete() {
let section = Section::with_endian(Endian::Little)
.L32(0xffff_ffff)
.L32(0x7856_3412);
let buf = section.get_contents().unwrap();
let input = &mut EndianSlice::new(&buf, LittleEndian);
match input.read_initial_length() {
Err(Error::UnexpectedEof(_)) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_offset_32() {
let section = Section::with_endian(Endian::Little).L32(0x0123_4567);
let buf = section.get_contents().unwrap();
let input = &mut EndianSlice::new(&buf, LittleEndian);
match input.read_offset(Format::Dwarf32) {
Ok(val) => {
assert_eq!(input.len(), 0);
assert_eq!(val, 0x0123_4567);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_offset_64_small() {
let section = Section::with_endian(Endian::Little).L64(0x0123_4567);
let buf = section.get_contents().unwrap();
let input = &mut EndianSlice::new(&buf, LittleEndian);
match input.read_offset(Format::Dwarf64) {
Ok(val) => {
assert_eq!(input.len(), 0);
assert_eq!(val, 0x0123_4567);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_parse_offset_64_large() {
let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef);
let buf = section.get_contents().unwrap();
let input = &mut EndianSlice::new(&buf, LittleEndian);
match input.read_offset(Format::Dwarf64) {
Ok(val) => {
assert_eq!(input.len(), 0);
assert_eq!(val, 0x0123_4567_89ab_cdef);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
#[cfg(target_pointer_width = "32")]
fn test_parse_offset_64_large() {
let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef);
let buf = section.get_contents().unwrap();
let input = &mut EndianSlice::new(&buf, LittleEndian);
match input.read_offset(Format::Dwarf64) {
Err(Error::UnsupportedOffset) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
}