use constants;
use endianity::{EndianBuf, Endianity};
use parser::{Error, Format, Result};
use reader::Reader;
use unit::UnitHeader;
use std::collections::hash_map;
use Section;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DebugAbbrevOffset<T = usize>(pub T);
#[derive(Debug, Clone, Copy)]
pub struct DebugAbbrev<R: Reader> {
debug_abbrev_section: R,
}
impl<'input, Endian> DebugAbbrev<EndianBuf<'input, Endian>>
where
Endian: Endianity,
{
pub fn new(debug_abbrev_section: &'input [u8], endian: Endian) -> Self {
Self::from(EndianBuf::new(debug_abbrev_section, endian))
}
}
impl<R: Reader> DebugAbbrev<R> {
pub fn abbreviations(
&self,
debug_abbrev_offset: DebugAbbrevOffset<R::Offset>,
) -> Result<Abbreviations> {
let input = &mut self.debug_abbrev_section.clone();
input.skip(debug_abbrev_offset.0)?;
Abbreviations::parse(input)
}
}
impl<R: Reader> Section<R> for DebugAbbrev<R> {
fn section_name() -> &'static str {
".debug_abbrev"
}
}
impl<R: Reader> From<R> for DebugAbbrev<R> {
fn from(debug_abbrev_section: R) -> Self {
DebugAbbrev {
debug_abbrev_section,
}
}
}
#[derive(Debug, Default, Clone)]
pub struct Abbreviations {
vec: Vec<Abbreviation>,
map: hash_map::HashMap<u64, Abbreviation>,
}
impl Abbreviations {
fn empty() -> Abbreviations {
Abbreviations {
vec: Vec::new(),
map: hash_map::HashMap::new(),
}
}
fn insert(&mut self, abbrev: Abbreviation) -> ::std::result::Result<(), ()> {
let code_usize = abbrev.code as usize;
if code_usize as u64 == abbrev.code {
if code_usize - 1 < self.vec.len() {
return Err(());
} else if code_usize - 1 == self.vec.len() {
if !self.map.is_empty() && self.map.contains_key(&abbrev.code) {
return Err(());
} else {
self.vec.push(abbrev);
return Ok(());
}
}
}
match self.map.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> {
let code_usize = code as usize;
if code_usize as u64 == code && code_usize - 1 < self.vec.len() {
Some(&self.vec[code_usize - 1])
} else {
self.map.get(&code)
}
}
fn parse<R: Reader>(input: &mut R) -> Result<Abbreviations> {
let mut abbrevs = Abbreviations::empty();
while let Some(abbrev) = Abbreviation::parse(input)? {
if abbrevs.insert(abbrev).is_err() {
return Err(Error::DuplicateAbbreviationCode);
}
}
Ok(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_ne!(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<R: Reader>(input: &mut R) -> Result<constants::DwTag> {
let val = input.read_uleb128()?;
if val == 0 {
Err(Error::AbbreviationTagZero)
} else {
Ok(constants::DwTag(val))
}
}
fn parse_has_children<R: Reader>(input: &mut R) -> Result<constants::DwChildren> {
let val = input.read_u8()?;
let val = constants::DwChildren(val);
if val == constants::DW_CHILDREN_no || val == constants::DW_CHILDREN_yes {
Ok(val)
} else {
Err(Error::BadHasChildren)
}
}
fn parse_attributes<R: Reader>(input: &mut R) -> Result<Vec<AttributeSpecification>> {
let mut attrs = Vec::new();
while let Some(attr) = AttributeSpecification::parse(input)? {
attrs.push(attr);
}
Ok(attrs)
}
fn parse<R: Reader>(input: &mut R) -> Result<Option<Abbreviation>> {
let code = input.read_uleb128()?;
if code == 0 {
return Ok(None);
}
let tag = Self::parse_tag(input)?;
let has_children = Self::parse_has_children(input)?;
let attributes = Self::parse_attributes(input)?;
let abbrev = Abbreviation::new(code, tag, has_children, attributes);
Ok(Some(abbrev))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AttributeSpecification {
name: constants::DwAt,
form: constants::DwForm,
implicit_const_value: i64,
}
impl AttributeSpecification {
#[inline]
pub fn new(name: constants::DwAt, form: constants::DwForm,
implicit_const_value: Option<i64>) -> AttributeSpecification {
debug_assert!((form == constants::DW_FORM_implicit_const && implicit_const_value.is_some()) ||
(form != constants::DW_FORM_implicit_const && implicit_const_value.is_none()));
AttributeSpecification {
name: name,
form: form,
implicit_const_value: implicit_const_value.unwrap_or(0),
}
}
#[inline]
pub fn name(&self) -> constants::DwAt {
self.name
}
#[inline]
pub fn form(&self) -> constants::DwForm {
self.form
}
#[inline]
pub fn implicit_const_value(&self) -> i64 {
assert!(self.form == constants::DW_FORM_implicit_const);
self.implicit_const_value
}
pub fn size<R: Reader>(&self, header: &UnitHeader<R, R::Offset>) -> Option<usize> {
match self.form {
constants::DW_FORM_addr => Some(header.address_size() as usize),
constants::DW_FORM_implicit_const => Some(0),
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,
}
}
fn parse_form<R: Reader>(input: &mut R) -> Result<constants::DwForm> {
let val = input.read_uleb128()?;
if val == 0 {
Err(Error::AttributeFormZero)
} else {
Ok(constants::DwForm(val))
}
}
fn parse<R: Reader>(input: &mut R) -> Result<Option<AttributeSpecification>> {
let name = input.read_uleb128()?;
if name == 0 {
let form = input.read_uleb128()?;
return if form == 0 {
Ok(None)
} else {
Err(Error::ExpectedZero)
};
}
let name = constants::DwAt(name);
let form = Self::parse_form(input)?;
let implicit_const_value = if form == constants::DW_FORM_implicit_const {
Some(input.read_sleb128()?)
} else {
None
};
let spec = AttributeSpecification::new(name, form, implicit_const_value);
Ok(Some(spec))
}
}
#[cfg(test)]
pub mod tests {
extern crate test_assembler;
use super::*;
use constants;
use endianity::{EndianBuf, LittleEndian};
use parser::Error;
use self::test_assembler::Section;
use std::u64;
use test_util::GimliSectionMethods;
pub trait AbbrevSectionMethods {
fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self;
fn abbrev_null(self) -> Self;
fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self;
fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self;
fn abbrev_attr_null(self) -> Self;
}
impl AbbrevSectionMethods for Section {
fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self {
self.uleb(code).uleb(tag.0).D8(children.0)
}
fn abbrev_null(self) -> Self {
self.D8(0)
}
fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self {
self.uleb(name.0).uleb(form.0)
}
fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self {
self.uleb(name.0).uleb(constants::DW_FORM_implicit_const.0).sleb(value)
}
fn abbrev_attr_null(self) -> Self {
self.D8(0).D8(0)
}
}
#[test]
fn test_debug_abbrev_ok() {
let extra_start = [1, 2, 3, 4];
let expected_rest = [5, 6, 7, 8];
let buf = Section::new()
.append_bytes(&extra_start)
.abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
.abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string)
.abbrev_attr_null()
.abbrev(
1,
constants::DW_TAG_compile_unit,
constants::DW_CHILDREN_yes,
)
.abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp)
.abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2)
.abbrev_attr_null()
.abbrev_null()
.append_bytes(&expected_rest)
.get_contents()
.unwrap();
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, None),
AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2, None),
],
);
let abbrev2 = Abbreviation::new(
2,
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_no,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
],
);
let debug_abbrev = DebugAbbrev::new(&buf, LittleEndian);
let debug_abbrev_offset = DebugAbbrevOffset(extra_start.len());
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]
fn test_abbreviations_insert() {
fn abbrev(code: u64) -> Abbreviation {
Abbreviation::new(
code,
constants::DwTag(code),
constants::DW_CHILDREN_no,
vec![],
)
}
fn assert_abbrev(abbrevs: &Abbreviations, code: u64) {
let abbrev = abbrevs.get(code).unwrap();
assert_eq!(abbrev.tag(), constants::DwTag(code));
}
let mut abbrevs = Abbreviations::empty();
abbrevs.insert(abbrev(1)).unwrap();
abbrevs.insert(abbrev(2)).unwrap();
assert_eq!(abbrevs.vec.len(), 2);
assert!(abbrevs.map.is_empty());
assert_abbrev(&abbrevs, 1);
assert_abbrev(&abbrevs, 2);
let mut abbrevs = Abbreviations::empty();
abbrevs.insert(abbrev(2)).unwrap();
abbrevs.insert(abbrev(3)).unwrap();
assert!(abbrevs.vec.is_empty());
assert_abbrev(&abbrevs, 2);
assert_abbrev(&abbrevs, 3);
let mut abbrevs = Abbreviations::empty();
abbrevs.insert(abbrev(1)).unwrap();
abbrevs.insert(abbrev(3)).unwrap();
abbrevs.insert(abbrev(2)).unwrap();
assert_eq!(abbrevs.vec.len(), 2);
assert_abbrev(&abbrevs, 1);
assert_abbrev(&abbrevs, 2);
assert_abbrev(&abbrevs, 3);
let mut abbrevs = Abbreviations::empty();
abbrevs.insert(abbrev(1)).unwrap();
abbrevs.insert(abbrev(2)).unwrap();
assert_eq!(abbrevs.insert(abbrev(1)), Err(()));
assert_eq!(abbrevs.insert(abbrev(2)), Err(()));
let mut abbrevs = Abbreviations::empty();
abbrevs.insert(abbrev(2)).unwrap();
assert_eq!(abbrevs.insert(abbrev(2)), Err(()));
let mut abbrevs = Abbreviations::empty();
abbrevs.insert(abbrev(2)).unwrap();
abbrevs.insert(abbrev(1)).unwrap();
assert_eq!(abbrevs.insert(abbrev(2)), Err(()));
let mut abbrevs = Abbreviations::empty();
abbrevs.insert(abbrev(2)).unwrap();
}
#[test]
#[cfg(target_pointer_width = "32")]
fn test_abbreviations_insert_32() {
fn abbrev(code: u64) -> Abbreviation {
Abbreviation::new(
code,
constants::DwTag(code),
constants::DW_CHILDREN_no,
vec![],
)
}
fn assert_abbrev(abbrevs: &Abbreviations, code: u64) {
let abbrev = abbrevs.get(code).unwrap();
assert_eq!(abbrev.tag(), constants::DwTag(code));
}
let mut abbrevs = Abbreviations::empty();
abbrevs.insert(abbrev(1)).unwrap();
let wrap_code = (u32::MAX as u64 + 1) + 1;
assert_eq!(abbrevs.get(wrap_code), None);
abbrevs.insert(abbrev(wrap_code)).unwrap();
assert_abbrev(&abbrevs, 1);
assert_abbrev(&abbrevs, wrap_code);
}
#[test]
fn test_parse_abbreviations_ok() {
let expected_rest = [1, 2, 3, 4];
let buf = Section::new()
.abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
.abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string)
.abbrev_attr_null()
.abbrev(
1,
constants::DW_TAG_compile_unit,
constants::DW_CHILDREN_yes,
)
.abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp)
.abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2)
.abbrev_attr_null()
.abbrev_null()
.append_bytes(&expected_rest)
.get_contents()
.unwrap();
let rest = &mut EndianBuf::new(&*buf, LittleEndian);
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, None),
AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2, None),
],
);
let abbrev2 = Abbreviation::new(
2,
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_no,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
],
);
let abbrevs = Abbreviations::parse(rest).expect("Should parse abbreviations");
assert_eq!(abbrevs.get(1), Some(&abbrev1));
assert_eq!(abbrevs.get(2), Some(&abbrev2));
assert_eq!(*rest, EndianBuf::new(&expected_rest, LittleEndian));
}
#[test]
fn test_parse_abbreviations_duplicate() {
let expected_rest = [1, 2, 3, 4];
let buf = Section::new()
.abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
.abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string)
.abbrev_attr_null()
.abbrev(
1,
constants::DW_TAG_compile_unit,
constants::DW_CHILDREN_yes,
)
.abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp)
.abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2)
.abbrev_attr_null()
.abbrev_null()
.append_bytes(&expected_rest)
.get_contents()
.unwrap();
let buf = &mut EndianBuf::new(&*buf, LittleEndian);
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 = &mut EndianBuf::new(&buf, LittleEndian);
let tag = Abbreviation::parse_tag(rest).expect("Should parse tag");
assert_eq!(tag, constants::DW_TAG_array_type);
assert_eq!(*rest, EndianBuf::new(&buf[1..], LittleEndian));
}
#[test]
fn test_parse_abbreviation_tag_zero() {
let buf = [0x00];
let buf = &mut EndianBuf::new(&buf, LittleEndian);
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 = &mut EndianBuf::new(&buf, LittleEndian);
let val = Abbreviation::parse_has_children(rest).expect("Should parse children");
assert_eq!(val, constants::DW_CHILDREN_no);
let 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]
fn test_parse_abbreviation_ok() {
let expected_rest = [0x01, 0x02, 0x03, 0x04];
let buf = Section::new()
.abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
.abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string)
.abbrev_attr_null()
.append_bytes(&expected_rest)
.get_contents()
.unwrap();
let rest = &mut EndianBuf::new(&*buf, LittleEndian);
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, None),
],
));
let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation");
assert_eq!(abbrev, expect);
assert_eq!(*rest, EndianBuf::new(&expected_rest, LittleEndian));
}
#[test]
fn test_parse_abbreviation_implicit_const_ok() {
let expected_rest = [0x01, 0x02, 0x03, 0x04];
let buf = Section::new()
.abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
.abbrev_attr_implicit_const(constants::DW_AT_name, -42)
.abbrev_attr_null()
.append_bytes(&expected_rest)
.get_contents()
.unwrap();
let rest = &mut EndianBuf::new(&*buf, LittleEndian);
let expect = Some(Abbreviation::new(
1,
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_no,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_implicit_const, Some(-42)),
],
));
let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation");
assert_eq!(abbrev, expect);
assert_eq!(*rest, EndianBuf::new(&expected_rest, LittleEndian));
}
#[test]
fn test_parse_abbreviation_implicit_const_no_const() {
let buf = Section::new()
.abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no)
.abbrev_attr(constants::DW_AT_name, constants::DW_FORM_implicit_const)
.get_contents()
.unwrap();
let buf = &mut EndianBuf::new(&*buf, LittleEndian);
match Abbreviation::parse(buf) {
Err(Error::UnexpectedEof) => {},
otherwise => panic!("Unexpected result: {:?}", otherwise),
}
}
#[test]
fn test_parse_null_abbreviation_ok() {
let expected_rest = [0x01, 0x02, 0x03, 0x04];
let buf = Section::new()
.abbrev_null()
.append_bytes(&expected_rest)
.get_contents()
.unwrap();
let rest = &mut EndianBuf::new(&*buf, LittleEndian);
let abbrev = Abbreviation::parse(rest).expect("Should parse null abbreviation");
assert!(abbrev.is_none());
assert_eq!(*rest, EndianBuf::new(&expected_rest, LittleEndian));
}
#[test]
fn test_parse_attribute_form_ok() {
let buf = [0x01, 0x02];
let rest = &mut EndianBuf::new(&buf, LittleEndian);
let tag = AttributeSpecification::parse_form(rest).expect("Should parse form");
assert_eq!(tag, constants::DW_FORM_addr);
assert_eq!(*rest, EndianBuf::new(&buf[1..], LittleEndian));
}
#[test]
fn test_parse_attribute_form_zero() {
let buf = [0x00];
let buf = &mut EndianBuf::new(&buf, LittleEndian);
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 = &mut EndianBuf::new(&buf, LittleEndian);
let attr =
AttributeSpecification::parse(rest).expect("Should parse null attribute specification");
assert!(attr.is_none());
assert_eq!(*rest, EndianBuf::new(&buf[2..], LittleEndian));
}
#[test]
fn test_parse_attribute_specifications_name_zero() {
let buf = [0x00, 0x01, 0x00, 0x00];
let buf = &mut EndianBuf::new(&buf, LittleEndian);
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];
let buf = &mut EndianBuf::new(&buf, LittleEndian);
match AttributeSpecification::parse(buf) {
Err(Error::AttributeFormZero) => {}
otherwise => panic!("Unexpected result: {:?}", otherwise),
};
}
}