#![deny(missing_docs)]
use constants;
use endianity::{Endianity, EndianBuf};
use parser::{Error, ParseResult, Format, UnitHeader};
use parser::{parse_unsigned_leb, parse_u8};
use std::collections::hash_map;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugAbbrevOffset(pub u64);
#[derive(Debug, Clone, Copy)]
pub struct DebugAbbrev<'input, Endian>
where Endian: Endianity
{
debug_abbrev_section: EndianBuf<'input, Endian>,
}
impl<'input, Endian> DebugAbbrev<'input, Endian>
where Endian: Endianity
{
pub fn new(debug_abbrev_section: &'input [u8]) -> DebugAbbrev<'input, Endian> {
DebugAbbrev { debug_abbrev_section: EndianBuf::new(debug_abbrev_section) }
}
pub fn abbreviations(&self,
debug_abbrev_offset: DebugAbbrevOffset)
-> ParseResult<Abbreviations> {
let input: &[u8] = self.debug_abbrev_section.into();
Abbreviations::parse(&input[debug_abbrev_offset.0 as usize..]).map(|(_, abbrevs)| abbrevs)
}
}
#[derive(Debug, Default, Clone)]
pub struct Abbreviations {
abbrevs: hash_map::HashMap<u64, Abbreviation>,
}
impl Abbreviations {
fn empty() -> Abbreviations {
Abbreviations { abbrevs: hash_map::HashMap::new() }
}
fn insert(&mut self, abbrev: Abbreviation) -> Result<(), ()> {
match self.abbrevs.entry(abbrev.code) {
hash_map::Entry::Occupied(_) => Err(()),
hash_map::Entry::Vacant(entry) => {
entry.insert(abbrev);
Ok(())
}
}
}
#[inline]
pub fn get(&self, code: u64) -> Option<&Abbreviation> {
self.abbrevs.get(&code)
}
fn parse(mut input: &[u8]) -> ParseResult<(&[u8], Abbreviations)> {
let mut abbrevs = Abbreviations::empty();
loop {
let (rest, abbrev) = try!(Abbreviation::parse(input));
input = rest;
match abbrev {
None => break,
Some(abbrev) => {
if let Err(_) = abbrevs.insert(abbrev) {
return Err(Error::DuplicateAbbreviationCode);
}
}
}
}
Ok((input, abbrevs))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Abbreviation {
code: u64,
tag: constants::DwTag,
has_children: constants::DwChildren,
attributes: Vec<AttributeSpecification>,
}
impl Abbreviation {
pub fn new(code: u64,
tag: constants::DwTag,
has_children: constants::DwChildren,
attributes: Vec<AttributeSpecification>)
-> Abbreviation {
assert!(code != 0);
Abbreviation {
code: code,
tag: tag,
has_children: has_children,
attributes: attributes,
}
}
#[inline]
pub fn code(&self) -> u64 {
self.code
}
#[inline]
pub fn tag(&self) -> constants::DwTag {
self.tag
}
#[inline]
pub fn has_children(&self) -> bool {
self.has_children == constants::DW_CHILDREN_yes
}
#[inline]
pub fn attributes(&self) -> &[AttributeSpecification] {
&self.attributes[..]
}
fn parse_tag(input: &[u8]) -> ParseResult<(&[u8], constants::DwTag)> {
let (rest, val) = try!(parse_unsigned_leb(input));
if val == 0 {
Err(Error::AbbreviationTagZero)
} else {
Ok((rest, constants::DwTag(val)))
}
}
fn parse_has_children(input: &[u8]) -> ParseResult<(&[u8], constants::DwChildren)> {
let (rest, val) = try!(parse_u8(input));
let val = constants::DwChildren(val);
if val == constants::DW_CHILDREN_no || val == constants::DW_CHILDREN_yes {
Ok((rest, val))
} else {
Err(Error::BadHasChildren)
}
}
fn parse_attributes(mut input: &[u8]) -> ParseResult<(&[u8], Vec<AttributeSpecification>)> {
let mut attrs = Vec::new();
loop {
let (rest, attr) = try!(AttributeSpecification::parse(input));
input = rest;
match attr {
None => break,
Some(attr) => attrs.push(attr),
};
}
Ok((input, attrs))
}
fn parse(input: &[u8]) -> ParseResult<(&[u8], Option<Abbreviation>)> {
let (rest, code) = try!(parse_unsigned_leb(input));
if code == 0 {
return Ok((rest, None));
}
let (rest, tag) = try!(Self::parse_tag(rest));
let (rest, has_children) = try!(Self::parse_has_children(rest));
let (rest, attributes) = try!(Self::parse_attributes(rest));
let abbrev = Abbreviation::new(code, tag, has_children, attributes);
Ok((rest, Some(abbrev)))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AttributeSpecification {
name: constants::DwAt,
form: constants::DwForm,
}
impl AttributeSpecification {
pub fn new(name: constants::DwAt, form: constants::DwForm) -> AttributeSpecification {
AttributeSpecification {
name: name,
form: form,
}
}
#[inline]
pub fn name(&self) -> constants::DwAt {
self.name
}
#[inline]
pub fn form(&self) -> constants::DwForm {
self.form
}
pub fn size<Endian>(&self, header: &UnitHeader<Endian>) -> Option<usize>
where Endian: Endianity
{
match self.form {
constants::DW_FORM_addr => Some(header.address_size() as usize),
constants::DW_FORM_flag |
constants::DW_FORM_flag_present |
constants::DW_FORM_data1 |
constants::DW_FORM_ref1 => Some(1),
constants::DW_FORM_data2 |
constants::DW_FORM_ref2 => Some(2),
constants::DW_FORM_data4 |
constants::DW_FORM_ref4 => Some(4),
constants::DW_FORM_data8 |
constants::DW_FORM_ref8 => Some(8),
constants::DW_FORM_sec_offset |
constants::DW_FORM_ref_addr |
constants::DW_FORM_ref_sig8 |
constants::DW_FORM_strp => {
match header.format() {
Format::Dwarf32 => Some(4),
Format::Dwarf64 => Some(8),
}
}
constants::DW_FORM_block |
constants::DW_FORM_block1 |
constants::DW_FORM_block2 |
constants::DW_FORM_block4 |
constants::DW_FORM_exprloc |
constants::DW_FORM_ref_udata |
constants::DW_FORM_string |
constants::DW_FORM_sdata |
constants::DW_FORM_udata |
constants::DW_FORM_indirect => None,
_ => None,
}
}
fn parse_form(input: &[u8]) -> ParseResult<(&[u8], constants::DwForm)> {
let (rest, val) = try!(parse_unsigned_leb(input));
if val == 0 {
Err(Error::AttributeFormZero)
} else {
Ok((rest, constants::DwForm(val)))
}
}
fn parse(input: &[u8]) -> ParseResult<(&[u8], Option<AttributeSpecification>)> {
let (rest, name) = try!(parse_unsigned_leb(input));
if name == 0 {
let (rest, form) = try!(parse_unsigned_leb(rest));
return if form == 0 {
Ok((rest, None))
} else {
Err(Error::ExpectedZero)
};
}
let name = constants::DwAt(name);
let (rest, form) = try!(Self::parse_form(rest));
let spec = AttributeSpecification::new(name, form);
Ok((rest, Some(spec)))
}
}
#[cfg(test)]
mod tests {
use super::*;
use constants;
use parser::Error;
use endianity::LittleEndian;
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_debug_abbrev_ok() {
let buf = [
0x01,
0x02,
0x03,
0x04,
0x02,
0x2e,
0x00,
0x03,
0x08,
0x00,
0x00,
0x01,
0x11,
0x01,
0x25,
0x0e,
0x13,
0x05,
0x00,
0x00,
0x00,
0x05,
0x06,
0x07,
0x08
];
let abbrev1 = Abbreviation::new(
1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes,
vec![
AttributeSpecification::new(constants::DW_AT_producer, constants::DW_FORM_strp),
AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2),
]);
let abbrev2 = Abbreviation::new(
2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string),
]);
let debug_abbrev = DebugAbbrev::<LittleEndian>::new(&buf);
let debug_abbrev_offset = DebugAbbrevOffset(4);
let abbrevs = debug_abbrev.abbreviations(debug_abbrev_offset)
.expect("Should parse abbreviations");
assert_eq!(abbrevs.get(1), Some(&abbrev1));
assert_eq!(abbrevs.get(2), Some(&abbrev2));
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_parse_abbreviations_ok() {
let buf = [
0x02,
0x2e,
0x00,
0x03,
0x08,
0x00,
0x00,
0x01,
0x11,
0x01,
0x25,
0x0e,
0x13,
0x05,
0x00,
0x00,
0x00,
0x01,
0x02,
0x03,
0x04
];
let abbrev1 = Abbreviation::new(
1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes,
vec![
AttributeSpecification::new(constants::DW_AT_producer, constants::DW_FORM_strp),
AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2),
]);
let abbrev2 = Abbreviation::new(
2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string),
]);
let (rest, abbrevs) = Abbreviations::parse(&buf).expect("Should parse abbreviations");
assert_eq!(abbrevs.get(1), Some(&abbrev1));
assert_eq!(abbrevs.get(2), Some(&abbrev2));
assert_eq!(rest, [0x01, 0x02, 0x03, 0x04]);
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_parse_abbreviations_duplicate() {
let buf = [
0x01,
0x2e,
0x00,
0x03,
0x08,
0x00,
0x00,
0x01,
0x11,
0x01,
0x25,
0x0e,
0x13,
0x05,
0x00,
0x00,
0x00,
0x01,
0x02,
0x03,
0x04
];
match Abbreviations::parse(&buf) {
Err(Error::DuplicateAbbreviationCode) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_abbreviation_tag_ok() {
let buf = [0x01, 0x02];
let (rest, tag) = Abbreviation::parse_tag(&buf).expect("Should parse tag");
assert_eq!(tag, constants::DW_TAG_array_type);
assert_eq!(rest, &buf[1..]);
}
#[test]
fn test_parse_abbreviation_tag_zero() {
let buf = [0x00];
match Abbreviation::parse_tag(&buf) {
Err(Error::AbbreviationTagZero) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_abbreviation_has_children() {
let buf = [0x00, 0x01, 0x02];
let (rest, val) = Abbreviation::parse_has_children(&buf).expect("Should parse children");
assert_eq!(val, constants::DW_CHILDREN_no);
let (rest, val) = Abbreviation::parse_has_children(rest).expect("Should parse children");
assert_eq!(val, constants::DW_CHILDREN_yes);
match Abbreviation::parse_has_children(rest) {
Err(Error::BadHasChildren) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_parse_abbreviation_ok() {
let buf = [
0x01,
0x2e,
0x00,
0x03,
0x08,
0x00,
0x00,
0x01,
0x02,
0x03,
0x04
];
let expect = Some(
Abbreviation::new(
1,
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_no,
vec![
AttributeSpecification::new(constants::DW_AT_name,
constants::DW_FORM_string),
]
)
);
let (rest, abbrev) = Abbreviation::parse(&buf).expect("Should parse abbreviation");
assert_eq!(abbrev, expect);
assert_eq!(rest, [0x01, 0x02, 0x03, 0x04]);
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_parse_null_abbreviation_ok() {
let buf = [
0x00,
0x01,
0x02,
0x03,
0x04
];
let (rest, abbrev) = Abbreviation::parse(&buf).expect("Should parse null abbreviation");
assert!(abbrev.is_none());
assert_eq!(rest, [0x01, 0x02, 0x03, 0x04]);
}
#[test]
fn test_parse_attribute_form_ok() {
let buf = [0x01, 0x02];
let (rest, tag) = AttributeSpecification::parse_form(&buf).expect("Should parse form");
assert_eq!(tag, constants::DW_FORM_addr);
assert_eq!(rest, &buf[1..]);
}
#[test]
fn test_parse_attribute_form_zero() {
let buf = [0x00];
match AttributeSpecification::parse_form(&buf) {
Err(Error::AttributeFormZero) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_null_attribute_specification_ok() {
let buf = [0x00, 0x00, 0x01];
let (rest, attr) = AttributeSpecification::parse(&buf)
.expect("Should parse null attribute specification");
assert!(attr.is_none());
assert_eq!(rest, [0x01]);
}
#[test]
fn test_parse_attribute_specifications_name_zero() {
let buf = [0x00, 0x01, 0x00, 0x00];
match AttributeSpecification::parse(&buf) {
Err(Error::ExpectedZero) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
#[test]
fn test_parse_attribute_specifications_form_zero() {
let buf = [0x01, 0x00, 0x00, 0x00];
match AttributeSpecification::parse(&buf) {
Err(Error::AttributeFormZero) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
}