#![deny(missing_docs)]
use constants;
use leb128;
use abbrev::{DebugAbbrev, DebugAbbrevOffset, Abbreviations, Abbreviation, AttributeSpecification};
use endianity::{Endianity, EndianBuf};
#[cfg(test)]
use endianity::LittleEndian;
use std::cell::Cell;
use std::error;
use std::ffi;
use std::fmt::{self, Debug};
use std::io;
use std::marker::PhantomData;
use std::ops::{Range, RangeFrom, RangeTo};
use str::{DebugStrOffset};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
BadUnsignedLeb128,
BadSignedLeb128,
AbbreviationTagZero,
AttributeFormZero,
BadHasChildren,
UnknownForm,
ExpectedZero,
DuplicateAbbreviationCode,
UnknownReservedLength,
UnknownVersion,
UnitHeaderLengthTooShort,
UnknownAbbreviation,
UnexpectedEof,
UnknownStandardOpcode(constants::DwLns),
UnknownExtendedOpcode(constants::DwLne),
UnsupportedAddressSize(u8),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
Debug::fmt(self, f)
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value",
Error::BadSignedLeb128 => "An error parsing a signed LEB128 value",
Error::AbbreviationTagZero => {
"An abbreviation declared that its tag is zero,
but zero is reserved for null records"
}
Error::AttributeFormZero => {
"An attribute specification declared that its form is zero,
but zero is reserved for null records"
}
Error::BadHasChildren => {
"The abbreviation's has-children byte was not one of
`DW_CHILDREN_{yes,no}`"
}
Error::UnknownForm => "Found an unknown `DW_FORM_*` type",
Error::ExpectedZero => "Expected a zero, found something else",
Error::DuplicateAbbreviationCode => {
"Found an abbreviation code that has already been used"
}
Error::UnknownReservedLength => "Found an unknown reserved length value",
Error::UnknownVersion => "Found an unknown DWARF version",
Error::UnitHeaderLengthTooShort => {
"The unit header's claimed length is too short to even hold
the header itself"
}
Error::UnknownAbbreviation => "Found a record with an unknown abbreviation code",
Error::UnexpectedEof => "Hit the end of input before it was expected",
Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode",
Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode",
Error::UnsupportedAddressSize(_) => "The specified address size is not supported",
}
}
}
pub type ParseResult<T> = Result<T, Error>;
#[doc(hidden)]
#[inline]
pub fn parse_u8(input: &[u8]) -> ParseResult<(&[u8], u8)> {
if input.len() == 0 {
Err(Error::UnexpectedEof)
} else {
Ok((&input[1..], input[0]))
}
}
#[doc(hidden)]
#[inline]
pub fn parse_i8(input: &[u8]) -> ParseResult<(&[u8], i8)> {
if input.len() == 0 {
Err(Error::UnexpectedEof)
} else {
Ok((&input[1..], input[0] as i8))
}
}
#[doc(hidden)]
#[inline]
pub fn parse_u16<Endian>(input: EndianBuf<Endian>) -> ParseResult<(EndianBuf<Endian>, u16)>
where Endian: Endianity
{
if input.len() < 2 {
Err(Error::UnexpectedEof)
} else {
Ok((input.range_from(2..), Endian::read_u16(&input)))
}
}
#[doc(hidden)]
#[inline]
pub fn parse_u32<Endian>(input: EndianBuf<Endian>) -> ParseResult<(EndianBuf<Endian>, u32)>
where Endian: Endianity
{
if input.len() < 4 {
Err(Error::UnexpectedEof)
} else {
Ok((input.range_from(4..), Endian::read_u32(&input)))
}
}
#[doc(hidden)]
#[inline]
pub fn parse_u64<Endian>(input: EndianBuf<Endian>) -> ParseResult<(EndianBuf<Endian>, u64)>
where Endian: Endianity
{
if input.len() < 8 {
Err(Error::UnexpectedEof)
} else {
Ok((input.range_from(8..), Endian::read_u64(&input)))
}
}
#[doc(hidden)]
#[inline]
pub fn parse_u32_as_u64<Endian>(input: EndianBuf<Endian>) -> ParseResult<(EndianBuf<Endian>, u64)>
where Endian: Endianity
{
if input.len() < 4 {
Err(Error::UnexpectedEof)
} else {
Ok((input.range_from(4..), Endian::read_u32(&input) as u64))
}
}
#[doc(hidden)]
#[inline]
pub fn parse_null_terminated_string(input: &[u8]) -> ParseResult<(&[u8], &ffi::CStr)> {
let null_idx = input.iter().position(|ch| *ch == 0);
if let Some(idx) = null_idx {
let cstr = unsafe {
ffi::CStr::from_bytes_with_nul_unchecked(&input[0..idx + 1])
};
Ok((&input[idx + 1..], cstr))
} else {
Err(Error::UnexpectedEof)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugTypesOffset(pub u64);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugInfoOffset(pub u64);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugLocOffset(pub u64);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugMacinfoOffset(pub u64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
pub struct UnitOffset(pub u64);
#[derive(Debug, Clone, Copy)]
pub struct DebugInfo<'input, Endian>
where Endian: Endianity
{
debug_info_section: EndianBuf<'input, Endian>,
}
impl<'input, Endian> DebugInfo<'input, Endian>
where Endian: Endianity
{
pub fn new(debug_info_section: &'input [u8]) -> DebugInfo<'input, Endian> {
DebugInfo { debug_info_section: EndianBuf(debug_info_section, PhantomData) }
}
pub fn units(&self) -> UnitHeadersIter<'input, Endian> {
UnitHeadersIter { input: self.debug_info_section }
}
}
pub struct UnitHeadersIter<'input, Endian>
where Endian: Endianity
{
input: EndianBuf<'input, Endian>,
}
impl<'input, Endian> Iterator for UnitHeadersIter<'input, Endian>
where Endian: Endianity
{
type Item = ParseResult<UnitHeader<'input, Endian>>;
fn next(&mut self) -> Option<Self::Item> {
if self.input.is_empty() {
None
} else {
match parse_unit_header(self.input) {
Ok((_, header)) => {
let unit_len = header.length_including_self() as usize;
if self.input.len() < unit_len {
self.input = self.input.range_to(..0);
} else {
self.input = self.input.range_from(unit_len..);
}
Some(Ok(header))
}
Err(e) => {
self.input = self.input.range_to(..0);
Some(Err(e))
}
}
}
}
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_units() {
let buf = [
0xff, 0xff, 0xff, 0xff,
0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00,
0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x27, 0x00, 0x00, 0x00,
0x04, 0x00,
0x05, 0x06, 0x07, 0x08,
0x04,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
];
let debug_info = DebugInfo::<LittleEndian>::new(&buf);
let mut units = debug_info.units();
match units.next() {
Some(Ok(header)) => {
let expected = UnitHeader::<LittleEndian>::new(0x000000000000002b,
4,
DebugAbbrevOffset(0x0102030405060708),
8,
Format::Dwarf64,
&buf[23..23+32]);
assert_eq!(header, expected);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
match units.next() {
Some(Ok(header)) => {
let expected =
UnitHeader::new(0x00000027,
4,
DebugAbbrevOffset(0x08070605),
4,
Format::Dwarf32,
&buf[buf.len()-32..]);
assert_eq!(header, expected);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
assert!(units.next().is_none());
}
#[inline]
pub fn parse_unsigned_leb(mut input: &[u8]) -> ParseResult<(&[u8], u64)> {
match leb128::read::unsigned(&mut input) {
Ok(val) => Ok((input, val)),
Err(leb128::read::Error::IoError(ref e)) if e.kind() == io::ErrorKind::UnexpectedEof => {
Err(Error::UnexpectedEof)
}
Err(_) => Err(Error::BadUnsignedLeb128),
}
}
#[inline]
pub fn parse_signed_leb(mut input: &[u8]) -> ParseResult<(&[u8], i64)> {
match leb128::read::signed(&mut input) {
Ok(val) => Ok((input, val)),
Err(leb128::read::Error::IoError(ref e)) if e.kind() == io::ErrorKind::UnexpectedEof => {
Err(Error::UnexpectedEof)
}
Err(_) => Err(Error::BadSignedLeb128),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Format {
Dwarf64,
Dwarf32,
}
const MAX_DWARF_32_UNIT_LENGTH: u64 = 0xfffffff0;
const DWARF_64_INITIAL_UNIT_LENGTH: u64 = 0xffffffff;
#[doc(hidden)]
pub fn parse_unit_length<Endian>(input: EndianBuf<Endian>)
-> ParseResult<(EndianBuf<Endian>, (u64, Format))>
where Endian: Endianity
{
let (rest, val) = try!(parse_u32_as_u64(input));
if val < MAX_DWARF_32_UNIT_LENGTH {
Ok((rest, (val, Format::Dwarf32)))
} else if val == DWARF_64_INITIAL_UNIT_LENGTH {
let (rest, val) = try!(parse_u64(rest));
Ok((rest, (val, Format::Dwarf64)))
} else {
Err(Error::UnknownReservedLength)
}
}
#[test]
fn test_parse_unit_length_32_ok() {
let buf = [0x12, 0x34, 0x56, 0x78];
match parse_unit_length(EndianBuf::<LittleEndian>::new(&buf)) {
Ok((rest, (length, format))) => {
assert_eq!(rest.len(), 0);
assert_eq!(format, Format::Dwarf32);
assert_eq!(0x78563412, length);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_parse_unit_length_64_ok() {
let buf = [
0xff, 0xff, 0xff, 0xff,
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff
];
match parse_unit_length(EndianBuf::<LittleEndian>::new(&buf)) {
Ok((rest, (length, format))) => {
assert_eq!(rest.len(), 0);
assert_eq!(format, Format::Dwarf64);
assert_eq!(0xffdebc9a78563412, length);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
fn test_parse_unit_length_unknown_reserved_value() {
let buf = [0xfe, 0xff, 0xff, 0xff];
match parse_unit_length(EndianBuf::<LittleEndian>::new(&buf)) {
Err(Error::UnknownReservedLength) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_unit_length_incomplete() {
let buf = [0xff, 0xff, 0xff];
match parse_unit_length(EndianBuf::<LittleEndian>::new(&buf)) {
Err(Error::UnexpectedEof) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_parse_unit_length_64_incomplete() {
let buf = [
0xff, 0xff, 0xff, 0xff,
0x12, 0x34, 0x56, 0x78
];
match parse_unit_length(EndianBuf::<LittleEndian>::new(&buf)) {
Err(Error::UnexpectedEof) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
fn parse_version<Endian>(input: EndianBuf<Endian>) -> ParseResult<(EndianBuf<Endian>, u16)>
where Endian: Endianity
{
let (rest, val) = try!(parse_u16(input));
if 2 <= val && val <= 4 {
Ok((rest, val))
} else {
Err(Error::UnknownVersion)
}
}
#[test]
fn test_unit_version_ok() {
let buf = [0x04, 0x00, 0xff, 0xff];
match parse_version(EndianBuf::<LittleEndian>::new(&buf)) {
Ok((rest, val)) => {
assert_eq!(val, 4);
assert_eq!(rest, EndianBuf::new(&[0xff, 0xff]));
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_unit_version_unknown_version() {
let buf = [0xab, 0xcd];
match parse_version(EndianBuf::<LittleEndian>::new(&buf)) {
Err(Error::UnknownVersion) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
let buf = [0x1, 0x0];
match parse_version(EndianBuf::<LittleEndian>::new(&buf)) {
Err(Error::UnknownVersion) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_unit_version_incomplete() {
let buf = [0x04];
match parse_version(EndianBuf::<LittleEndian>::new(&buf)) {
Err(Error::UnexpectedEof) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
fn parse_debug_abbrev_offset<Endian>(input: EndianBuf<Endian>,
format: Format)
-> ParseResult<(EndianBuf<Endian>, DebugAbbrevOffset)>
where Endian: Endianity
{
let offset = match format {
Format::Dwarf32 => parse_u32_as_u64(input),
Format::Dwarf64 => parse_u64(input),
};
offset.map(|(rest, offset)| (rest, DebugAbbrevOffset(offset)))
}
#[test]
fn test_parse_debug_abbrev_offset_32() {
let buf = [0x01, 0x02, 0x03, 0x04];
match parse_debug_abbrev_offset(EndianBuf::<LittleEndian>::new(&buf), Format::Dwarf32) {
Ok((_, val)) => assert_eq!(val, DebugAbbrevOffset(0x04030201)),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_debug_abbrev_offset_32_incomplete() {
let buf = [0x01, 0x02];
match parse_debug_abbrev_offset(EndianBuf::<LittleEndian>::new(&buf), Format::Dwarf32) {
Err(Error::UnexpectedEof) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_debug_abbrev_offset_64() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
match parse_debug_abbrev_offset(EndianBuf::<LittleEndian>::new(&buf), Format::Dwarf64) {
Ok((_, val)) => assert_eq!(val, DebugAbbrevOffset(0x0807060504030201)),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_debug_abbrev_offset_64_incomplete() {
let buf = [0x01, 0x02];
match parse_debug_abbrev_offset(EndianBuf::<LittleEndian>::new(&buf), Format::Dwarf64) {
Err(Error::UnexpectedEof) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
fn parse_address_size(input: &[u8]) -> ParseResult<(&[u8], u8)> {
parse_u8(input)
}
#[test]
fn test_parse_address_size_ok() {
let buf = [0x04];
match parse_address_size(&buf) {
Ok((_, val)) => assert_eq!(val, 4),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UnitHeader<'input, Endian>
where Endian: Endianity
{
unit_length: u64,
version: u16,
debug_abbrev_offset: DebugAbbrevOffset,
address_size: u8,
format: Format,
entries_buf: EndianBuf<'input, Endian>,
}
impl<'input, Endian> UnitHeader<'input, Endian>
where Endian: Endianity
{
pub fn new(unit_length: u64,
version: u16,
debug_abbrev_offset: DebugAbbrevOffset,
address_size: u8,
format: Format,
entries_buf: &'input [u8])
-> UnitHeader<'input, Endian> {
UnitHeader {
unit_length: unit_length,
version: version,
debug_abbrev_offset: debug_abbrev_offset,
address_size: address_size,
format: format,
entries_buf: EndianBuf(entries_buf, PhantomData),
}
}
pub fn size_of_unit_length(format: Format) -> usize {
match format {
Format::Dwarf32 => 4,
Format::Dwarf64 => 12,
}
}
pub fn size_of_header(format: Format) -> usize {
let unit_length_size = Self::size_of_unit_length(format);
let version_size = 2;
let debug_abbrev_offset_size = match format {
Format::Dwarf32 => 4,
Format::Dwarf64 => 8,
};
let address_size_size = 1;
unit_length_size + version_size + debug_abbrev_offset_size + address_size_size
}
}
impl<'input, Endian> UnitHeader<'input, Endian>
where Endian: Endianity
{
pub fn unit_length(&self) -> u64 {
self.unit_length
}
pub fn length_including_self(&self) -> u64 {
match self.format {
Format::Dwarf32 => 4 + self.unit_length,
Format::Dwarf64 => 4 + 8 + self.unit_length,
}
}
pub fn version(&self) -> u16 {
self.version
}
pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset {
self.debug_abbrev_offset
}
pub fn address_size(&self) -> u8 {
self.address_size
}
pub fn format(&self) -> Format {
self.format
}
fn is_valid_offset(&self, offset: UnitOffset) -> bool {
let size_of_header = Self::size_of_header(self.format);
if (offset.0 as usize) < size_of_header {
return false;
}
let relative_to_entries_buf = offset.0 as usize - size_of_header;
relative_to_entries_buf < self.entries_buf.len()
}
pub fn range(&self, idx: Range<UnitOffset>) -> &'input [u8] {
assert!(self.is_valid_offset(idx.start));
assert!(self.is_valid_offset(idx.end));
assert!(idx.start <= idx.end);
let size_of_header = Self::size_of_header(self.format);
let start = idx.start.0 as usize - size_of_header;
let end = idx.end.0 as usize - size_of_header;
&self.entries_buf.0[start..end]
}
pub fn range_from(&self, idx: RangeFrom<UnitOffset>) -> &'input [u8] {
assert!(self.is_valid_offset(idx.start));
let start = idx.start.0 as usize - Self::size_of_header(self.format);
&self.entries_buf.0[start..]
}
pub fn range_to(&self, idx: RangeTo<UnitOffset>) -> &'input [u8] {
assert!(self.is_valid_offset(idx.end));
let end = idx.end.0 as usize - Self::size_of_header(self.format);
&self.entries_buf.0[..end]
}
pub fn entries<'me, 'abbrev>(&'me self,
abbreviations: &'abbrev Abbreviations)
-> EntriesCursor<'input, 'abbrev, 'me, Endian> {
EntriesCursor {
unit: self,
input: self.entries_buf.into(),
abbreviations: abbreviations,
cached_current: None,
delta_depth: 0,
}
}
pub fn abbreviations(&self, debug_abbrev: DebugAbbrev<Endian>) -> ParseResult<Abbreviations> {
debug_abbrev.abbreviations(self.debug_abbrev_offset())
}
}
fn parse_unit_header<Endian>(input: EndianBuf<Endian>)
-> ParseResult<(EndianBuf<Endian>, UnitHeader<Endian>)>
where Endian: Endianity
{
let (rest, (unit_length, format)) = try!(parse_unit_length(input));
let (rest, version) = try!(parse_version(rest));
let (rest, offset) = try!(parse_debug_abbrev_offset(rest, format));
let (rest, address_size) = try!(parse_address_size(rest.into()));
let size_of_unit_length = UnitHeader::<Endian>::size_of_unit_length(format);
let size_of_header = UnitHeader::<Endian>::size_of_header(format);
if unit_length as usize + size_of_unit_length < size_of_header {
return Err(Error::UnitHeaderLengthTooShort);
}
let end = unit_length as usize + size_of_unit_length - size_of_header;
if end > rest.len() {
return Err(Error::UnexpectedEof);
}
let entries_buf = &rest[..end];
Ok((EndianBuf::new(rest),
UnitHeader::new(unit_length,
version,
offset,
address_size,
format,
entries_buf)))
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_parse_unit_header_32_ok() {
let buf = [
0x07, 0x00, 0x00, 0x00,
0x04, 0x00,
0x05, 0x06, 0x07, 0x08,
0x04
];
match parse_unit_header(EndianBuf::<LittleEndian>::new(&buf)) {
Ok((_, header)) => {
assert_eq!(header,
UnitHeader::new(7,
4,
DebugAbbrevOffset(0x08070605),
4,
Format::Dwarf32,
&[]))
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_parse_unit_header_64_ok() {
let buf = [
0xff, 0xff, 0xff, 0xff,
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00,
0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
0x08
];
match parse_unit_header(EndianBuf::<LittleEndian>::new(&buf)) {
Ok((_, header)) => {
let expected = UnitHeader::new(11,
4,
DebugAbbrevOffset(0x0102030405060708),
8,
Format::Dwarf64,
&[]);
assert_eq!(header, expected)
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[derive(Clone, Debug)]
pub struct DebuggingInformationEntry<'input, 'abbrev, 'unit, Endian>
where 'input: 'unit,
Endian: Endianity + 'unit
{
attrs_slice: &'input [u8],
after_attrs: Cell<Option<&'input [u8]>>,
code: u64,
abbrev: &'abbrev Abbreviation,
unit: &'unit UnitHeader<'input, Endian>,
}
impl<'input, 'abbrev, 'unit, Endian> DebuggingInformationEntry<'input, 'abbrev, 'unit, Endian>
where Endian: Endianity
{
pub fn code(&self) -> u64 {
self.code
}
pub fn tag(&self) -> constants::DwTag {
self.abbrev.tag()
}
pub fn attrs<'me>(&'me self) -> AttrsIter<'input, 'abbrev, 'me, 'unit, Endian> {
AttrsIter {
input: self.attrs_slice,
attributes: self.abbrev.attributes(),
entry: self,
}
}
pub fn attr_value(&self, name: constants::DwAt) -> Option<AttributeValue<'input>> {
let mut attrs = self.attrs();
while let Ok(Some(attr)) = attrs.next() {
if attr.name() == name {
return Some(attr.value());
}
}
None
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AttributeValue<'input> {
Addr(&'input [u8]),
Block(&'input [u8]),
Data(&'input [u8]),
Sdata(i64),
Udata(u64),
Exprloc(&'input [u8]),
Flag(bool),
SecOffset(u64),
UnitRef(UnitOffset),
DebugInfoRef(DebugInfoOffset),
DebugTypesRef(DebugTypesOffset),
DebugStrRef(DebugStrOffset),
String(&'input ffi::CStr),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Attribute<'input> {
name: constants::DwAt,
value: AttributeValue<'input>,
}
impl<'input> Attribute<'input> {
pub fn name(&self) -> constants::DwAt {
self.name
}
pub fn value(&self) -> AttributeValue<'input> {
self.value
}
}
#[inline]
fn take(bytes: usize, input: &[u8]) -> ParseResult<(&[u8], &[u8])> {
if input.len() < bytes {
Err(Error::UnexpectedEof)
} else {
Ok((&input[bytes..], &input[0..bytes]))
}
}
fn length_u8_value(input: &[u8]) -> ParseResult<(&[u8], &[u8])> {
let (rest, len) = try!(parse_u8(input));
take(len as usize, rest)
}
fn length_u16_value<Endian>(input: EndianBuf<Endian>) -> ParseResult<(EndianBuf<Endian>, &[u8])>
where Endian: Endianity
{
let (rest, len) = try!(parse_u16(input));
take(len as usize, rest.into()).map(|(rest, result)| (EndianBuf::new(rest), result))
}
fn length_u32_value<Endian>(input: EndianBuf<Endian>) -> ParseResult<(EndianBuf<Endian>, &[u8])>
where Endian: Endianity
{
let (rest, len) = try!(parse_u32(input));
take(len as usize, rest.into()).map(|(rest, result)| (EndianBuf::new(rest), result))
}
fn length_leb_value(input: &[u8]) -> ParseResult<(&[u8], &[u8])> {
let (rest, len) = try!(parse_unsigned_leb(input));
take(len as usize, rest)
}
fn parse_attribute<'input, 'unit, Endian>
(mut input: EndianBuf<'input, Endian>,
unit: &'unit UnitHeader<'input, Endian>,
spec: AttributeSpecification)
-> ParseResult<(EndianBuf<'input, Endian>, Attribute<'input>)>
where Endian: Endianity
{
let mut form = spec.form();
loop {
match form {
constants::DW_FORM_indirect => {
let (rest, dynamic_form) = try!(parse_unsigned_leb(input.into()));
form = constants::DwForm(dynamic_form);
input = EndianBuf::new(rest);
continue;
}
constants::DW_FORM_addr => {
return take(unit.address_size() as usize, input.into()).map(|(rest, addr)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Addr(addr),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_block1 => {
return length_u8_value(input.into()).map(|(rest, block)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Block(block),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_block2 => {
return length_u16_value(input.into()).map(|(rest, block)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Block(block),
};
(rest, attr)
});
}
constants::DW_FORM_block4 => {
return length_u32_value(input.into()).map(|(rest, block)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Block(block),
};
(rest, attr)
});
}
constants::DW_FORM_block => {
return length_leb_value(input.into()).map(|(rest, block)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Block(block),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_data1 => {
return take(1, input.into()).map(|(rest, data)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Data(data),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_data2 => {
return take(2, input.into()).map(|(rest, data)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Data(data),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_data4 => {
return take(4, input.into()).map(|(rest, data)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Data(data),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_data8 => {
return take(8, input.into()).map(|(rest, data)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Data(data),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_udata => {
return parse_unsigned_leb(input.into()).map(|(rest, data)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Udata(data),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_sdata => {
return parse_signed_leb(input.into()).map(|(rest, data)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Sdata(data),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_exprloc => {
return length_leb_value(input.into()).map(|(rest, block)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Exprloc(block),
};
(EndianBuf::new(rest), attr)
})
}
constants::DW_FORM_flag => {
return parse_u8(input.into()).map(|(rest, present)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::Flag(present != 0),
};
(EndianBuf::new(rest), attr)
})
}
constants::DW_FORM_flag_present => {
return Ok((input,
Attribute {
name: spec.name(),
value: AttributeValue::Flag(true),
}));
}
constants::DW_FORM_sec_offset => {
return match unit.format() {
Format::Dwarf32 => {
parse_u32(input.into()).map(|(rest, offset)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::SecOffset(offset as u64),
};
(rest, attr)
})
}
Format::Dwarf64 => {
parse_u64(input.into()).map(|(rest, offset)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::SecOffset(offset),
};
(rest, attr)
})
}
};
}
constants::DW_FORM_ref1 => {
return parse_u8(input.into()).map(|(rest, reference)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::UnitRef(UnitOffset(reference as u64)),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_ref2 => {
return parse_u16(input.into()).map(|(rest, reference)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::UnitRef(UnitOffset(reference as u64)),
};
(rest, attr)
});
}
constants::DW_FORM_ref4 => {
return parse_u32(input.into()).map(|(rest, reference)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::UnitRef(UnitOffset(reference as u64)),
};
(rest, attr)
});
}
constants::DW_FORM_ref8 => {
return parse_u64(input.into()).map(|(rest, reference)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::UnitRef(UnitOffset(reference)),
};
(rest, attr)
});
}
constants::DW_FORM_ref_udata => {
return parse_unsigned_leb(input.into()).map(|(rest, reference)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::UnitRef(UnitOffset(reference)),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_ref_addr => {
return match unit.format() {
Format::Dwarf32 => {
parse_u32(input.into()).map(|(rest, offset)| {
let offset = DebugInfoOffset(offset as u64);
let attr = Attribute {
name: spec.name(),
value: AttributeValue::DebugInfoRef(offset),
};
(rest, attr)
})
}
Format::Dwarf64 => {
parse_u64(input.into()).map(|(rest, offset)| {
let offset = DebugInfoOffset(offset);
let attr = Attribute {
name: spec.name(),
value: AttributeValue::DebugInfoRef(offset),
};
(rest, attr)
})
}
};
}
constants::DW_FORM_ref_sig8 => {
return parse_u64(input.into()).map(|(rest, offset)| {
let offset = DebugTypesOffset(offset);
let attr = Attribute {
name: spec.name(),
value: AttributeValue::DebugTypesRef(offset),
};
(rest, attr)
});
}
constants::DW_FORM_string => {
return parse_null_terminated_string(input.0).map(|(rest, string)| {
let attr = Attribute {
name: spec.name(),
value: AttributeValue::String(string),
};
(EndianBuf::new(rest), attr)
});
}
constants::DW_FORM_strp => {
return match unit.format() {
Format::Dwarf32 => {
parse_u32(input.into()).map(|(rest, offset)| {
let offset = DebugStrOffset(offset as u64);
let attr = Attribute {
name: spec.name(),
value: AttributeValue::DebugStrRef(offset),
};
(rest, attr)
})
}
Format::Dwarf64 => {
parse_u64(input.into()).map(|(rest, offset)| {
let offset = DebugStrOffset(offset);
let attr = Attribute {
name: spec.name(),
value: AttributeValue::DebugStrRef(offset),
};
(rest, attr)
})
}
};
}
_ => {
return Err(Error::UnknownForm);
}
};
}
}
#[cfg(test)]
fn test_parse_attribute_unit<Endian>(address_size: u8,
format: Format)
-> UnitHeader<'static, Endian>
where Endian: Endianity
{
UnitHeader::<Endian>::new(7,
4,
DebugAbbrevOffset(0x08070605),
address_size,
format,
&[])
}
#[cfg(test)]
fn test_parse_attribute_unit_default() -> UnitHeader<'static, LittleEndian> {
test_parse_attribute_unit(4, Format::Dwarf32)
}
#[cfg(test)]
fn test_parse_attribute<Endian>(buf: &[u8],
len: usize,
unit: &UnitHeader<Endian>,
form: constants::DwForm,
value: AttributeValue)
where Endian: Endianity
{
let spec = AttributeSpecification::new(constants::DW_AT_low_pc, form);
let expect = Attribute {
name: constants::DW_AT_low_pc,
value: value,
};
match parse_attribute(EndianBuf::new(buf), unit, spec) {
Ok((rest, attr)) => {
assert_eq!(attr, expect);
assert_eq!(rest, EndianBuf::new(&buf[len..]));
}
otherwise => {
println!("Unexpected parse result = {:#?}", otherwise);
assert!(false);
}
};
}
#[test]
fn test_parse_attribute_addr() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let unit = test_parse_attribute_unit::<LittleEndian>(4, Format::Dwarf32);
let form = constants::DW_FORM_addr;
let value = AttributeValue::Addr(&buf[..4]);
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::<LittleEndian>(8, Format::Dwarf32);
let form = constants::DW_FORM_addr;
let value = AttributeValue::Addr(&buf[..8]);
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(&buf[1..4]);
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(&buf[2..4]);
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(&buf[4..]);
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(&buf[1..]);
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::Data(&buf[..]);
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::Data(&buf[..2]);
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::Data(&buf[..4]);
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::Data(&buf[..8]);
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(&buf[1..3]);
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::<LittleEndian>(4, Format::Dwarf32);
let form = constants::DW_FORM_sec_offset;
let value = AttributeValue::SecOffset(0x04030201);
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
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::<LittleEndian>(4, Format::Dwarf64);
let form = constants::DW_FORM_sec_offset;
let value = AttributeValue::SecOffset(0x0807060504030201);
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(67305985));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
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(578437695752307201));
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::<LittleEndian>(4, Format::Dwarf32);
let form = constants::DW_FORM_ref_addr;
let value = AttributeValue::DebugInfoRef(DebugInfoOffset(67305985));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
fn test_parse_attribute_refaddr_64() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit::<LittleEndian>(4, Format::Dwarf64);
let form = constants::DW_FORM_ref_addr;
let value = AttributeValue::DebugInfoRef(DebugInfoOffset(578437695752307201));
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(DebugTypesOffset(578437695752307201));
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(ffi::CStr::from_bytes_with_nul(&buf[..6]).unwrap());
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::<LittleEndian>(4, Format::Dwarf32);
let form = constants::DW_FORM_strp;
let value = AttributeValue::DebugStrRef(DebugStrOffset(67305985));
test_parse_attribute(&buf, 4, &unit, form, value);
}
#[test]
fn test_parse_attribute_strp_64() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x99, 0x99];
let unit = test_parse_attribute_unit::<LittleEndian>(4, Format::Dwarf64);
let form = constants::DW_FORM_strp;
let value = AttributeValue::DebugStrRef(DebugStrOffset(578437695752307201));
test_parse_attribute(&buf, 8, &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)
.expect("should write udata") +
leb128::write::unsigned(&mut writable, 9999999).expect("should write value")
};
let unit = test_parse_attribute_unit_default();
let form = constants::DW_FORM_indirect;
let value = AttributeValue::Udata(9999999);
test_parse_attribute(&buf, bytes_written, &unit, form, value);
}
#[derive(Clone, Copy, Debug)]
pub struct AttrsIter<'input, 'abbrev, 'entry, 'unit, Endian>
where 'input: 'entry + 'unit,
'abbrev: 'entry,
'unit: 'entry,
Endian: Endianity + 'entry + 'unit
{
input: &'input [u8],
attributes: &'abbrev [AttributeSpecification],
entry: &'entry DebuggingInformationEntry<'input, 'abbrev, 'unit, Endian>,
}
impl<'input, 'abbrev, 'entry, 'unit, Endian> AttrsIter<'input, 'abbrev, 'entry, 'unit, Endian>
where Endian: Endianity
{
pub fn next(&mut self) -> ParseResult<Option<Attribute<'input>>> {
if self.attributes.len() == 0 {
if let Some(end) = self.entry.after_attrs.get() {
debug_assert!(end == self.input);
} else {
self.entry.after_attrs.set(Some(self.input));
}
return Ok(None);
}
let attr = self.attributes[0];
let (rest, attr) = try!(parse_attribute(EndianBuf::new(self.input), self.entry.unit, attr));
self.attributes = &self.attributes[1..];
self.input = rest.into();
Ok(Some(attr))
}
}
#[test]
fn test_attrs_iter() {
let unit = UnitHeader::<LittleEndian>::new(7,
4,
DebugAbbrevOffset(0x08070605),
4,
Format::Dwarf32,
&[]);
let abbrev = Abbreviation::new(42,
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_yes,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string),
AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr),
AttributeSpecification::new(constants::DW_AT_high_pc, constants::DW_FORM_addr),
]);
let buf = [0x66, 0x6f, 0x6f, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x39, 0x05, 0x00, 0x00, 0xaa, 0xaa,
0xaa, 0xaa];
let entry = DebuggingInformationEntry {
attrs_slice: &buf,
after_attrs: Cell::new(None),
code: 1,
abbrev: &abbrev,
unit: &unit,
};
let mut attrs = AttrsIter {
input: &buf[..],
attributes: abbrev.attributes(),
entry: &entry,
};
match attrs.next() {
Ok(Some(attr)) => {
assert_eq!(attr,
Attribute {
name: constants::DW_AT_name,
value: AttributeValue::String(ffi::CStr::from_bytes_with_nul(b"foo\0")
.unwrap()),
});
}
otherwise => {
println!("Unexpected parse result = {:#?}", otherwise);
assert!(false);
}
}
assert!(entry.after_attrs.get().is_none());
match attrs.next() {
Ok(Some(attr)) => {
assert_eq!(attr,
Attribute {
name: constants::DW_AT_low_pc,
value: AttributeValue::Addr(&[0x2a, 0x00, 0x00, 0x00]),
});
}
otherwise => {
println!("Unexpected parse result = {:#?}", otherwise);
assert!(false);
}
}
assert!(entry.after_attrs.get().is_none());
match attrs.next() {
Ok(Some(attr)) => {
assert_eq!(attr,
Attribute {
name: constants::DW_AT_high_pc,
value: AttributeValue::Addr(&[0x39, 0x05, 0x00, 0x00]),
});
}
otherwise => {
println!("Unexpected parse result = {:#?}", otherwise);
assert!(false);
}
}
assert!(entry.after_attrs.get().is_none());
assert!(attrs.next().expect("should parse next").is_none());
assert!(entry.after_attrs.get().is_some());
assert_eq!(entry.after_attrs.get().expect("should have entry.after_attrs"),
&buf[buf.len() - 4..])
}
#[test]
fn test_attrs_iter_incomplete() {
let unit = UnitHeader::<LittleEndian>::new(7,
4,
DebugAbbrevOffset(0x08070605),
4,
Format::Dwarf32,
&[]);
let abbrev = Abbreviation::new(42,
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_yes,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string),
AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr),
AttributeSpecification::new(constants::DW_AT_high_pc, constants::DW_FORM_addr),
]);
let buf = [0x66, 0x6f, 0x6f, 0x00];
let entry = DebuggingInformationEntry {
attrs_slice: &buf,
after_attrs: Cell::new(None),
code: 1,
abbrev: &abbrev,
unit: &unit,
};
let mut attrs = AttrsIter {
input: &buf[..],
attributes: abbrev.attributes(),
entry: &entry,
};
match attrs.next() {
Ok(Some(attr)) => {
assert_eq!(attr,
Attribute {
name: constants::DW_AT_name,
value: AttributeValue::String(ffi::CStr::from_bytes_with_nul(b"foo\0")
.unwrap()),
});
}
otherwise => {
println!("Unexpected parse result = {:#?}", otherwise);
assert!(false);
}
}
assert!(entry.after_attrs.get().is_none());
assert!(attrs.next().is_err());
assert!(entry.after_attrs.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.after_attrs.get().is_none());
}
#[derive(Clone, Debug)]
pub struct EntriesCursor<'input, 'abbrev, 'unit, Endian>
where 'input: 'unit,
Endian: Endianity + 'unit
{
input: &'input [u8],
unit: &'unit UnitHeader<'input, Endian>,
abbreviations: &'abbrev Abbreviations,
cached_current: Option<DebuggingInformationEntry<'input, 'abbrev, 'unit, Endian>>,
delta_depth: isize,
}
impl<'input, 'abbrev, 'unit, Endian> EntriesCursor<'input, 'abbrev, 'unit, Endian>
where Endian: Endianity
{
pub fn current<'me>
(&'me self)
-> Option<&'me DebuggingInformationEntry<'input, 'abbrev, 'unit, Endian>> {
self.cached_current.as_ref()
}
fn after_entry(&self) -> ParseResult<&'input [u8]> {
if let Some(ref current) = self.cached_current {
if let Some(after_attrs) = current.after_attrs.get() {
Ok(after_attrs)
} else {
let mut attrs = current.attrs();
while let Some(_) = try!(attrs.next()) {
}
Ok(current.after_attrs
.get()
.expect("should have after_attrs after iterating attrs"))
}
} else {
Ok(self.input)
}
}
pub fn next_entry(&mut self) -> ParseResult<Option<()>> {
let input = try!(self.after_entry());
if input.len() == 0 {
self.input = input;
self.cached_current = None;
self.delta_depth = 0;
return Ok(None);
}
match try!(parse_unsigned_leb(input)) {
(rest, 0) => {
self.input = rest;
self.cached_current = None;
self.delta_depth = -1;
Ok(Some(()))
}
(rest, code) => {
if let Some(abbrev) = self.abbreviations.get(code) {
self.cached_current = Some(DebuggingInformationEntry {
attrs_slice: rest,
after_attrs: Cell::new(None),
code: code,
abbrev: abbrev,
unit: self.unit,
});
self.delta_depth = if abbrev.has_children() {
1
} else {
0
};
Ok(Some(()))
} else {
Err(Error::UnknownAbbreviation)
}
}
}
}
pub fn next_dfs<'me>(&'me mut self)
-> ParseResult<Option<(isize,
&'me DebuggingInformationEntry<'input, 'abbrev, 'unit, Endian>)>> {
let mut delta_depth = self.delta_depth;
loop {
let mut input = try!(self.after_entry());
while input.len() > 0 && input[0] == 0 {
delta_depth -= 1;
input = &input[1..];
}
self.input = input;
self.cached_current = None;
if try!(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<'me>
(&'me mut self)
-> ParseResult<Option<(&'me DebuggingInformationEntry<'input, 'abbrev, 'unit, Endian>)>> {
if self.cached_current.is_some() {
let sibling_ptr = self.current().unwrap().attr_value(constants::DW_AT_sibling);
if let Some(AttributeValue::UnitRef(offset)) = sibling_ptr {
if self.unit.is_valid_offset(offset) {
self.input = self.unit.range_from(offset..);
self.cached_current = None;
try!(self.next_entry());
return Ok(self.current());
}
}
let mut depth = self.delta_depth;
while depth > 0 {
if try!(self.next_entry()).is_none() {
return Ok(None);
}
depth += self.delta_depth;
}
try!(self.next_entry());
Ok(self.current())
} else {
Ok(None)
}
}
}
fn parse_type_signature<Endian>(input: EndianBuf<Endian>) -> ParseResult<(EndianBuf<Endian>, u64)>
where Endian: Endianity
{
parse_u64(input)
}
#[test]
fn test_parse_type_signature_ok() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
match parse_type_signature(EndianBuf::<LittleEndian>::new(&buf)) {
Ok((_, val)) => assert_eq!(val, 0x0807060504030201),
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
fn test_parse_type_signature_incomplete() {
let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
match parse_type_signature(EndianBuf::<LittleEndian>::new(&buf)) {
Err(Error::UnexpectedEof) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
fn parse_type_offset<Endian>(input: EndianBuf<Endian>,
format: Format)
-> ParseResult<(EndianBuf<Endian>, DebugTypesOffset)>
where Endian: Endianity
{
let result = match format {
Format::Dwarf32 => parse_u32_as_u64(input),
Format::Dwarf64 => parse_u64(input),
};
result.map(|(rest, offset)| (rest, DebugTypesOffset(offset)))
}
#[test]
fn test_parse_type_offset_32_ok() {
let buf = [0x12, 0x34, 0x56, 0x78, 0x00];
match parse_type_offset(EndianBuf::<LittleEndian>::new(&buf), Format::Dwarf32) {
Ok((rest, offset)) => {
assert_eq!(rest.len(), 1);
assert_eq!(DebugTypesOffset(0x78563412), offset);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
fn test_parse_type_offset_64_ok() {
let buf = [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0x00];
match parse_type_offset(EndianBuf::<LittleEndian>::new(&buf), Format::Dwarf64) {
Ok((rest, offset)) => {
assert_eq!(rest.len(), 1);
assert_eq!(DebugTypesOffset(0xffdebc9a78563412), offset);
}
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
fn test_parse_type_offset_incomplete() {
let buf = [0xff, 0xff, 0xff];
match parse_type_offset(EndianBuf::<LittleEndian>::new(&buf), Format::Dwarf32) {
Err(Error::UnexpectedEof) => assert!(true),
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[derive(Debug, Clone, Copy)]
pub struct DebugTypes<'input, Endian>
where Endian: Endianity
{
debug_types_section: EndianBuf<'input, Endian>,
}
impl<'input, Endian> DebugTypes<'input, Endian>
where Endian: Endianity
{
pub fn new(debug_types_section: &'input [u8]) -> DebugTypes<'input, Endian> {
DebugTypes { debug_types_section: EndianBuf(debug_types_section, PhantomData) }
}
pub fn units(&self) -> TypeUnitHeadersIter<'input, Endian> {
TypeUnitHeadersIter { input: self.debug_types_section }
}
}
pub struct TypeUnitHeadersIter<'input, Endian>
where Endian: Endianity
{
input: EndianBuf<'input, Endian>,
}
impl<'input, Endian> Iterator for TypeUnitHeadersIter<'input, Endian>
where Endian: Endianity
{
type Item = ParseResult<TypeUnitHeader<'input, Endian>>;
fn next(&mut self) -> Option<Self::Item> {
if self.input.is_empty() {
None
} else {
match parse_type_unit_header(self.input) {
Ok((_, header)) => {
let unit_len = header.length_including_self() as usize;
if self.input.len() < unit_len {
self.input = self.input.range_to(..0);
} else {
self.input = self.input.range_from(unit_len..);
}
Some(Ok(header))
}
Err(e) => {
self.input = self.input.range_to(..0);
Some(Err(e))
}
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TypeUnitHeader<'input, Endian>
where Endian: Endianity
{
header: UnitHeader<'input, Endian>,
type_signature: u64,
type_offset: DebugTypesOffset,
}
impl<'input, Endian> TypeUnitHeader<'input, Endian>
where Endian: Endianity
{
fn new(mut header: UnitHeader<'input, Endian>,
type_signature: u64,
type_offset: DebugTypesOffset)
-> TypeUnitHeader<'input, Endian> {
let additional = Self::additional_header_size(header.format);
header.entries_buf = header.entries_buf.range_from(additional..);
TypeUnitHeader {
header: header,
type_signature: type_signature,
type_offset: type_offset,
}
}
pub fn unit_length(&self) -> u64 {
self.header.unit_length
}
fn additional_header_size(format: Format) -> usize {
let type_signature_size = 8;
let type_offset_size = match format {
Format::Dwarf32 => 4,
Format::Dwarf64 => 8,
};
type_signature_size + type_offset_size
}
pub fn length_including_self(&self) -> u64 {
self.header.length_including_self() +
Self::additional_header_size(self.header.format) as u64
}
pub fn version(&self) -> u16 {
self.header.version
}
pub fn debug_abbrev_offset(&self) -> DebugAbbrevOffset {
self.header.debug_abbrev_offset
}
pub fn address_size(&self) -> u8 {
self.header.address_size
}
pub fn type_signature(&self) -> u64 {
self.type_signature
}
pub fn type_offset(&self) -> DebugTypesOffset {
self.type_offset
}
pub fn entries<'me, 'abbrev>(&'me self,
abbreviations: &'abbrev Abbreviations)
-> EntriesCursor<'input, 'abbrev, 'me, Endian> {
EntriesCursor {
unit: &self.header,
input: self.header.entries_buf.into(),
abbreviations: abbreviations,
cached_current: None,
delta_depth: 0,
}
}
pub fn abbreviations(&self, debug_abbrev: DebugAbbrev<Endian>) -> ParseResult<Abbreviations> {
debug_abbrev.abbreviations(self.debug_abbrev_offset())
}
}
fn parse_type_unit_header<Endian>(input: EndianBuf<Endian>)
-> ParseResult<(EndianBuf<Endian>, TypeUnitHeader<Endian>)>
where Endian: Endianity
{
let (rest, header) = try!(parse_unit_header(input));
let (rest, signature) = try!(parse_type_signature(rest));
let (rest, offset) = try!(parse_type_offset(rest, header.format()));
Ok((rest, TypeUnitHeader::new(header, signature, offset)))
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_parse_type_unit_header_64_ok() {
let buf = [
0xff, 0xff, 0xff, 0xff,
0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x08,
0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde,
0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78
];
let result = parse_type_unit_header(EndianBuf::<LittleEndian>::new(&buf));
match result {
Ok((_, header)) => {
assert_eq!(header,
TypeUnitHeader::new(UnitHeader::new(27,
4,
DebugAbbrevOffset(0x0807060504030201),
8,
Format::Dwarf64,
&buf[buf.len() - 16..]),
0xdeadbeefdeadbeef,
DebugTypesOffset(0x7856341278563412)))
},
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}