1use core::fmt::{self, Debug};
177use core::result;
178#[cfg(feature = "std")]
179use std::{error, io};
180
181use crate::common::{Register, SectionId};
182use crate::constants;
183
184mod util;
185pub use util::*;
186
187mod addr;
188pub use self::addr::*;
189
190mod cfi;
191pub use self::cfi::*;
192
193#[cfg(feature = "read")]
194mod dwarf;
195#[cfg(feature = "read")]
196pub use self::dwarf::*;
197
198mod endian_slice;
199pub use self::endian_slice::*;
200
201#[cfg(feature = "endian-reader")]
202mod endian_reader;
203#[cfg(feature = "endian-reader")]
204pub use self::endian_reader::*;
205
206mod reader;
207pub use self::reader::*;
208
209mod relocate;
210pub use self::relocate::*;
211
212#[cfg(feature = "read")]
213mod abbrev;
214#[cfg(feature = "read")]
215pub use self::abbrev::*;
216
217mod aranges;
218pub use self::aranges::*;
219
220mod index;
221pub use self::index::*;
222
223#[cfg(feature = "read")]
224mod line;
225#[cfg(feature = "read")]
226pub use self::line::*;
227
228mod lists;
229
230mod loclists;
231pub use self::loclists::*;
232
233#[cfg(feature = "read")]
234mod lookup;
235
236#[cfg(feature = "read")]
237mod macros;
238#[cfg(feature = "read")]
239pub use self::macros::*;
240
241mod op;
242pub use self::op::*;
243
244#[cfg(feature = "read")]
245mod pubnames;
246#[cfg(feature = "read")]
247pub use self::pubnames::*;
248
249#[cfg(feature = "read")]
250mod pubtypes;
251#[cfg(feature = "read")]
252pub use self::pubtypes::*;
253
254mod rnglists;
255pub use self::rnglists::*;
256
257mod str;
258pub use self::str::*;
259
260#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
262pub struct UnitOffset<T = usize>(pub T);
263
264#[cfg(feature = "read")]
265mod unit;
266#[cfg(feature = "read")]
267pub use self::unit::*;
268
269mod value;
270pub use self::value::*;
271
272#[derive(Debug, Clone, Copy, PartialEq, Eq)]
274pub struct StoreOnHeap;
275
276#[deprecated(note = "EndianBuf has been renamed to EndianSlice, use that instead.")]
279pub type EndianBuf<'input, Endian> = EndianSlice<'input, Endian>;
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq)]
283#[non_exhaustive]
284pub enum Error {
285 Io,
287 PcRelativePointerButSectionBaseIsUndefined,
289 TextRelativePointerButTextBaseIsUndefined,
291 DataRelativePointerButDataBaseIsUndefined,
293 FuncRelativePointerInBadContext,
296 CannotParseOmitPointerEncoding,
298 BadUnsignedLeb128,
300 BadSignedLeb128,
302 AbbreviationTagZero,
305 AttributeFormZero,
308 BadHasChildren,
311 BadLength,
313 UnknownForm(constants::DwForm),
315 ExpectedZero,
317 DuplicateAbbreviationCode,
319 DuplicateArange,
321 UnknownReservedLength,
323 UnknownVersion(u64),
325 UnknownAbbreviation(u64),
327 UnexpectedEof(ReaderOffsetId),
329 UnexpectedNull,
331 UnknownStandardOpcode(constants::DwLns),
333 UnknownExtendedOpcode(constants::DwLne),
335 UnknownLocListsEntry(constants::DwLle),
337 UnknownRangeListsEntry(constants::DwRle),
339 UnsupportedAddressSize(u8),
341 UnsupportedOffsetSize(u8),
343 UnsupportedFieldSize(u8),
345 MinimumInstructionLengthZero,
347 MaximumOperationsPerInstructionZero,
349 LineRangeZero,
351 OpcodeBaseZero,
353 BadUtf8,
355 NotCieId,
357 NotCiePointer,
359 NotFdePointer,
361 BadBranchTarget(u64),
363 InvalidPushObjectAddress,
365 NotEnoughStackItems,
367 TooManyIterations,
369 InvalidExpression(constants::DwOp),
372 UnsupportedEvaluation,
374 InvalidPiece,
377 InvalidExpressionTerminator(u64),
380 DivisionByZero,
382 TypeMismatch,
384 IntegralTypeRequired,
387 UnsupportedTypeOperation,
389 InvalidShiftExpression,
391 InvalidDerefSize(u8),
393 UnknownCallFrameInstruction(constants::DwCfa),
395 InvalidAddressRange,
397 AddressOverflow,
402 CfiInstructionInInvalidContext,
405 PopWithEmptyStack,
408 NoUnwindInfoForAddress,
410 UnsupportedOffset,
412 UnknownPointerEncoding(constants::DwEhPe),
414 NoEntryAtGivenOffset,
416 OffsetOutOfBounds,
418 UnknownAugmentation,
420 UnsupportedPointerEncoding,
422 UnsupportedRegister(u64),
424 TooManyRegisterRules,
426 StackFull,
429 VariableLengthSearchTable,
432 UnsupportedUnitType,
434 UnsupportedAddressIndex,
436 UnsupportedSegmentSize,
438 MissingUnitDie,
440 UnsupportedAttributeForm,
442 MissingFileEntryFormatPath,
444 ExpectedStringAttributeValue,
446 InvalidImplicitConst,
448 InvalidIndexSectionCount,
450 InvalidIndexSlotCount,
452 InvalidIndexRow,
454 UnknownIndexSection(constants::DwSect),
456 UnknownIndexSectionV2(constants::DwSectV2),
458 InvalidMacinfoType(constants::DwMacinfo),
460 InvalidMacroType(constants::DwMacro),
462 UnsupportedOpcodeOperandsTable,
464}
465
466impl fmt::Display for Error {
467 #[inline]
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> ::core::result::Result<(), fmt::Error> {
469 write!(f, "{}", self.description())
470 }
471}
472
473impl Error {
474 pub fn description(&self) -> &str {
476 match *self {
477 Error::Io => "An I/O error occurred while reading.",
478 Error::PcRelativePointerButSectionBaseIsUndefined => {
479 "Found a PC relative pointer, but the section base is undefined."
480 }
481 Error::TextRelativePointerButTextBaseIsUndefined => {
482 "Found a `.text` relative pointer, but the `.text` base is undefined."
483 }
484 Error::DataRelativePointerButDataBaseIsUndefined => {
485 "Found a data relative pointer, but the data base is undefined."
486 }
487 Error::FuncRelativePointerInBadContext => {
488 "Found a function relative pointer in a context that does not have a function base."
489 }
490 Error::CannotParseOmitPointerEncoding => {
491 "Cannot parse a pointer with a `DW_EH_PE_omit` encoding."
492 }
493 Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value",
494 Error::BadSignedLeb128 => "An error parsing a signed LEB128 value",
495 Error::AbbreviationTagZero => {
496 "An abbreviation declared that its tag is zero,
497 but zero is reserved for null records"
498 }
499 Error::AttributeFormZero => {
500 "An attribute specification declared that its form is zero,
501 but zero is reserved for null records"
502 }
503 Error::BadHasChildren => {
504 "The abbreviation's has-children byte was not one of
505 `DW_CHILDREN_{yes,no}`"
506 }
507 Error::BadLength => "The specified length is impossible",
508 Error::UnknownForm(_) => "Found an unknown `DW_FORM_*` type",
509 Error::ExpectedZero => "Expected a zero, found something else",
510 Error::DuplicateAbbreviationCode => {
511 "Found an abbreviation code that has already been used"
512 }
513 Error::DuplicateArange => "Found a duplicate arange",
514 Error::UnknownReservedLength => "Found an unknown reserved length value",
515 Error::UnknownVersion(_) => "Found an unknown DWARF version",
516 Error::UnknownAbbreviation(_) => "Found a record with an unknown abbreviation code",
517 Error::UnexpectedEof(_) => "Hit the end of input before it was expected",
518 Error::UnexpectedNull => "Read a null entry before it was expected.",
519 Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode",
520 Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode",
521 Error::UnknownLocListsEntry(_) => "Found an unknown location lists entry",
522 Error::UnknownRangeListsEntry(_) => "Found an unknown range lists entry",
523 Error::UnsupportedAddressSize(_) => "The specified address size is not supported",
524 Error::UnsupportedOffsetSize(_) => "The specified offset size is not supported",
525 Error::UnsupportedFieldSize(_) => "The specified field size is not supported",
526 Error::MinimumInstructionLengthZero => {
527 "The minimum instruction length must not be zero."
528 }
529 Error::MaximumOperationsPerInstructionZero => {
530 "The maximum operations per instruction must not be zero."
531 }
532 Error::LineRangeZero => "The line range must not be zero.",
533 Error::OpcodeBaseZero => "The opcode base must not be zero.",
534 Error::BadUtf8 => "Found an invalid UTF-8 string.",
535 Error::NotCieId => "Expected to find the CIE ID, but found something else.",
536 Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.",
537 Error::NotFdePointer => {
538 "Expected to find an FDE pointer, but found a CIE pointer instead."
539 }
540 Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression",
541 Error::InvalidPushObjectAddress => {
542 "DW_OP_push_object_address used but no object address given"
543 }
544 Error::NotEnoughStackItems => "Not enough items on stack when evaluating expression",
545 Error::TooManyIterations => "Too many iterations to evaluate DWARF expression",
546 Error::InvalidExpression(_) => "Invalid opcode in DWARF expression",
547 Error::UnsupportedEvaluation => "Unsupported operation when evaluating expression",
548 Error::InvalidPiece => {
549 "DWARF expression has piece followed by non-piece expression at end"
550 }
551 Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece",
552 Error::DivisionByZero => "Division or modulus by zero when evaluating expression",
553 Error::TypeMismatch => "Type mismatch when evaluating expression",
554 Error::IntegralTypeRequired => "Integral type expected when evaluating expression",
555 Error::UnsupportedTypeOperation => {
556 "An expression operation used types that are not supported"
557 }
558 Error::InvalidShiftExpression => {
559 "The shift value in an expression must be a non-negative integer."
560 }
561 Error::InvalidDerefSize(_) => {
562 "The size of a deref expression must not be larger than the size of an address."
563 }
564 Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instruction",
565 Error::InvalidAddressRange => {
566 "The end of an address range must not be before the beginning."
567 }
568 Error::AddressOverflow => "An address calculation overflowed.",
569 Error::CfiInstructionInInvalidContext => {
570 "Encountered a call frame instruction in a context in which it is not valid."
571 }
572 Error::PopWithEmptyStack => {
573 "When evaluating call frame instructions, found a `DW_CFA_restore_state` stack pop \
574 instruction, but the stack was empty, and had nothing to pop."
575 }
576 Error::NoUnwindInfoForAddress => "Do not have unwind info for the given address.",
577 Error::UnsupportedOffset => {
578 "An offset value was larger than the maximum supported value."
579 }
580 Error::UnknownPointerEncoding(_) => {
581 "The given pointer encoding is either unknown or invalid."
582 }
583 Error::NoEntryAtGivenOffset => "Did not find an entry at the given offset.",
584 Error::OffsetOutOfBounds => "The given offset is out of bounds.",
585 Error::UnknownAugmentation => "Found an unknown CFI augmentation.",
586 Error::UnsupportedPointerEncoding => {
587 "We do not support the given pointer encoding yet."
588 }
589 Error::UnsupportedRegister(_) => "Registers larger than `u16` are not supported.",
590 Error::TooManyRegisterRules => {
591 "The CFI program defined more register rules than we have storage for."
592 }
593 Error::StackFull => {
594 "Attempted to push onto the CFI stack, but it was already at full capacity."
595 }
596 Error::VariableLengthSearchTable => {
597 "The `.eh_frame_hdr` binary search table claims to be variable-length encoded, \
598 which makes binary search impossible."
599 }
600 Error::UnsupportedUnitType => "The `DW_UT_*` value for this unit is not supported yet",
601 Error::UnsupportedAddressIndex => "Ranges involving AddressIndex are not supported yet",
602 Error::UnsupportedSegmentSize => "Nonzero segment size not supported yet",
603 Error::MissingUnitDie => {
604 "A compilation unit or type unit is missing its top level DIE."
605 }
606 Error::UnsupportedAttributeForm => "A DIE attribute used an unsupported form.",
607 Error::MissingFileEntryFormatPath => "Missing DW_LNCT_path in file entry format.",
608 Error::ExpectedStringAttributeValue => {
609 "Expected an attribute value to be a string form."
610 }
611 Error::InvalidImplicitConst => "DW_FORM_implicit_const used in an invalid context.",
612 Error::InvalidIndexSectionCount => "Invalid section count in `.dwp` index.",
613 Error::InvalidIndexSlotCount => "Invalid slot count in `.dwp` index.",
614 Error::InvalidIndexRow => "Invalid hash row in `.dwp` index.",
615 Error::UnknownIndexSection(_) => "Unknown section type in `.dwp` index.",
616 Error::UnknownIndexSectionV2(_) => "Unknown section type in version 2 `.dwp` index.",
617 Error::InvalidMacinfoType(_) => "Invalid macinfo type in `.debug_macinfo`.",
618 Error::InvalidMacroType(_) => "Invalid macro type in `.debug_macro`.",
619 Error::UnsupportedOpcodeOperandsTable => {
620 "The optional `opcode_operands_table` in `.debug_macro` is currently not supported."
621 }
622 }
623 }
624}
625
626#[cfg(feature = "std")]
627impl error::Error for Error {}
628
629#[cfg(feature = "std")]
630impl From<io::Error> for Error {
631 fn from(_: io::Error) -> Self {
632 Error::Io
633 }
634}
635
636pub type Result<T> = result::Result<T, Error>;
638
639pub trait Section<R>: From<R> {
652 fn id() -> SectionId;
654
655 fn section_name() -> &'static str {
657 Self::id().name()
658 }
659
660 fn dwo_section_name() -> Option<&'static str> {
663 Self::id().dwo_name()
664 }
665
666 fn xcoff_section_name() -> Option<&'static str> {
669 Self::id().xcoff_name()
670 }
671
672 fn load<F, E>(f: F) -> core::result::Result<Self, E>
674 where
675 F: FnOnce(SectionId) -> core::result::Result<R, E>,
676 {
677 f(Self::id()).map(From::from)
678 }
679
680 fn reader(&self) -> &R
682 where
683 R: Reader;
684
685 fn dwp_range(&self, offset: u32, size: u32) -> Result<Self>
688 where
689 R: Reader,
690 {
691 let mut data = self.reader().clone();
692 data.skip(R::Offset::from_u32(offset))?;
693 data.truncate(R::Offset::from_u32(size))?;
694 Ok(data.into())
695 }
696
697 fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)>
699 where
700 R: Reader,
701 {
702 self.reader()
703 .lookup_offset_id(id)
704 .map(|offset| (Self::id(), offset))
705 }
706}
707
708impl Register {
709 pub(crate) fn from_u64(x: u64) -> Result<Register> {
710 let y = x as u16;
711 if u64::from(y) == x {
712 Ok(Register(y))
713 } else {
714 Err(Error::UnsupportedRegister(x))
715 }
716 }
717}
718
719#[cfg(test)]
720mod tests {
721 use super::*;
722 use crate::common::Format;
723 use crate::endianity::LittleEndian;
724 use test_assembler::{Endian, Section};
725
726 #[test]
727 fn test_parse_initial_length_32_ok() {
728 let section = Section::with_endian(Endian::Little).L32(0x7856_3412);
729 let buf = section.get_contents().unwrap();
730
731 let input = &mut EndianSlice::new(&buf, LittleEndian);
732 match input.read_initial_length() {
733 Ok((length, format)) => {
734 assert_eq!(input.len(), 0);
735 assert_eq!(format, Format::Dwarf32);
736 assert_eq!(0x7856_3412, length);
737 }
738 otherwise => panic!("Unexpected result: {:?}", otherwise),
739 }
740 }
741
742 #[test]
743 fn test_parse_initial_length_64_ok() {
744 let section = Section::with_endian(Endian::Little)
745 .L32(0xffff_ffff)
747 .L64(0xffde_bc9a_7856_3412);
749 let buf = section.get_contents().unwrap();
750 let input = &mut EndianSlice::new(&buf, LittleEndian);
751
752 #[cfg(target_pointer_width = "64")]
753 match input.read_initial_length() {
754 Ok((length, format)) => {
755 assert_eq!(input.len(), 0);
756 assert_eq!(format, Format::Dwarf64);
757 assert_eq!(0xffde_bc9a_7856_3412, length);
758 }
759 otherwise => panic!("Unexpected result: {:?}", otherwise),
760 }
761
762 #[cfg(target_pointer_width = "32")]
763 match input.read_initial_length() {
764 Err(Error::UnsupportedOffset) => {}
765 otherwise => panic!("Unexpected result: {:?}", otherwise),
766 };
767 }
768
769 #[test]
770 fn test_parse_initial_length_unknown_reserved_value() {
771 let section = Section::with_endian(Endian::Little).L32(0xffff_fffe);
772 let buf = section.get_contents().unwrap();
773
774 let input = &mut EndianSlice::new(&buf, LittleEndian);
775 match input.read_initial_length() {
776 Err(Error::UnknownReservedLength) => {}
777 otherwise => panic!("Unexpected result: {:?}", otherwise),
778 };
779 }
780
781 #[test]
782 fn test_parse_initial_length_incomplete() {
783 let buf = [0xff, 0xff, 0xff]; let input = &mut EndianSlice::new(&buf, LittleEndian);
786 match input.read_initial_length() {
787 Err(Error::UnexpectedEof(_)) => {}
788 otherwise => panic!("Unexpected result: {:?}", otherwise),
789 };
790 }
791
792 #[test]
793 fn test_parse_initial_length_64_incomplete() {
794 let section = Section::with_endian(Endian::Little)
795 .L32(0xffff_ffff)
797 .L32(0x7856_3412);
799 let buf = section.get_contents().unwrap();
800
801 let input = &mut EndianSlice::new(&buf, LittleEndian);
802 match input.read_initial_length() {
803 Err(Error::UnexpectedEof(_)) => {}
804 otherwise => panic!("Unexpected result: {:?}", otherwise),
805 };
806 }
807
808 #[test]
809 fn test_parse_offset_32() {
810 let section = Section::with_endian(Endian::Little).L32(0x0123_4567);
811 let buf = section.get_contents().unwrap();
812
813 let input = &mut EndianSlice::new(&buf, LittleEndian);
814 match input.read_offset(Format::Dwarf32) {
815 Ok(val) => {
816 assert_eq!(input.len(), 0);
817 assert_eq!(val, 0x0123_4567);
818 }
819 otherwise => panic!("Unexpected result: {:?}", otherwise),
820 };
821 }
822
823 #[test]
824 fn test_parse_offset_64_small() {
825 let section = Section::with_endian(Endian::Little).L64(0x0123_4567);
826 let buf = section.get_contents().unwrap();
827
828 let input = &mut EndianSlice::new(&buf, LittleEndian);
829 match input.read_offset(Format::Dwarf64) {
830 Ok(val) => {
831 assert_eq!(input.len(), 0);
832 assert_eq!(val, 0x0123_4567);
833 }
834 otherwise => panic!("Unexpected result: {:?}", otherwise),
835 };
836 }
837
838 #[test]
839 #[cfg(target_pointer_width = "64")]
840 fn test_parse_offset_64_large() {
841 let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef);
842 let buf = section.get_contents().unwrap();
843
844 let input = &mut EndianSlice::new(&buf, LittleEndian);
845 match input.read_offset(Format::Dwarf64) {
846 Ok(val) => {
847 assert_eq!(input.len(), 0);
848 assert_eq!(val, 0x0123_4567_89ab_cdef);
849 }
850 otherwise => panic!("Unexpected result: {:?}", otherwise),
851 };
852 }
853
854 #[test]
855 #[cfg(target_pointer_width = "32")]
856 fn test_parse_offset_64_large() {
857 let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef);
858 let buf = section.get_contents().unwrap();
859
860 let input = &mut EndianSlice::new(&buf, LittleEndian);
861 match input.read_offset(Format::Dwarf64) {
862 Err(Error::UnsupportedOffset) => {}
863 otherwise => panic!("Unexpected result: {:?}", otherwise),
864 };
865 }
866}