Skip to content

Commit

Permalink
Support DW_FORM_implicit_const.
Browse files Browse the repository at this point in the history
  • Loading branch information
khuey committed Nov 5, 2017
1 parent 9d88355 commit 3d6cf77
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 29 deletions.
85 changes: 75 additions & 10 deletions src/abbrev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,15 +259,21 @@ impl Abbreviation {
pub struct AttributeSpecification {
name: constants::DwAt,
form: constants::DwForm,
implicit_const_value: i64,
}

impl AttributeSpecification {
/// Construct a new `AttributeSpecification` from the given name and form.
/// Construct a new `AttributeSpecification` from the given name and form
/// and implicit const value.
#[inline]
pub fn new(name: constants::DwAt, form: constants::DwForm) -> AttributeSpecification {
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),
}
}

Expand All @@ -283,6 +289,13 @@ impl AttributeSpecification {
self.form
}

/// Get the attribute's implicit const value.
#[inline]
pub fn implicit_const_value(&self) -> i64 {
assert!(self.form == constants::DW_FORM_implicit_const);
self.implicit_const_value
}

/// Return the size of the attribute, in bytes.
///
/// Note that because some attributes are variably sized, the size cannot
Expand All @@ -291,6 +304,8 @@ impl AttributeSpecification {
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 |
Expand Down Expand Up @@ -358,7 +373,12 @@ impl AttributeSpecification {

let name = constants::DwAt(name);
let form = Self::parse_form(input)?;
let spec = AttributeSpecification::new(name, form);
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))
}
}
Expand All @@ -379,6 +399,7 @@ pub mod tests {
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;
}

Expand All @@ -395,6 +416,10 @@ pub mod tests {
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)
}
Expand Down Expand Up @@ -427,8 +452,8 @@ pub mod tests {
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),
AttributeSpecification::new(constants::DW_AT_producer, constants::DW_FORM_strp, None),
AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2, None),
],
);

Expand All @@ -437,7 +462,7 @@ pub mod tests {
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_no,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string),
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
],
);

Expand Down Expand Up @@ -571,8 +596,8 @@ pub mod tests {
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),
AttributeSpecification::new(constants::DW_AT_producer, constants::DW_FORM_strp, None),
AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2, None),
],
);

Expand All @@ -581,7 +606,7 @@ pub mod tests {
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_no,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string),
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
],
);

Expand Down Expand Up @@ -668,7 +693,7 @@ pub mod tests {
constants::DW_TAG_subprogram,
constants::DW_CHILDREN_no,
vec![
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string),
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
],
));

Expand All @@ -677,6 +702,46 @@ pub mod tests {
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];
Expand Down
43 changes: 24 additions & 19 deletions src/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1600,11 +1600,13 @@ fn length_uleb128_value<R: Reader>(input: &mut R) -> Result<R> {
input.split(len)
}

fn parse_attribute<'unit, R: Reader>(
fn parse_attribute<'unit, 'abbrev, R: Reader>(
input: &mut R,
unit: &'unit UnitHeader<R, R::Offset>,
spec: AttributeSpecification,
) -> Result<Attribute<R>> {
mut specs: &'abbrev [AttributeSpecification],
) -> Result<(Attribute<R>, &'abbrev [AttributeSpecification])> {
let spec = specs[0];
specs = &specs[1..];
let mut form = spec.form();
loop {
let value = match form {
Expand Down Expand Up @@ -1741,6 +1743,9 @@ fn parse_attribute<'unit, R: Reader>(
let offset = input.read_offset(unit.format())?;
AttributeValue::DebugStrRef(DebugStrOffset(offset))
}
constants::DW_FORM_implicit_const => {
AttributeValue::Sdata(spec.implicit_const_value())
}
_ => {
return Err(Error::UnknownForm);
}
Expand All @@ -1749,7 +1754,7 @@ fn parse_attribute<'unit, R: Reader>(
name: spec.name(),
value: value,
};
return Ok(attr);
return Ok((attr, specs));
}
}

Expand Down Expand Up @@ -1798,10 +1803,8 @@ impl<'abbrev, 'entry, 'unit, R: Reader> AttrsIter<'abbrev, 'entry, 'unit, R> {
return Ok(None);
}

let attr = self.attributes[0];
let rest_attr = &self.attributes[1..];
match parse_attribute(&mut self.input, self.entry.unit, attr) {
Ok(attr) => {
match parse_attribute(&mut self.input, self.entry.unit, &self.attributes[..]) {
Ok((attr, rest_attr)) => {
self.attributes = rest_attr;
Ok(Some(attr))
}
Expand Down Expand Up @@ -3330,9 +3333,11 @@ mod tests {
for test in tests.iter() {
let (version, name, form, mut input, expect_raw, expect_value) = *test;
unit.version = version;
let spec = AttributeSpecification::new(name, form);
let spec = vec![AttributeSpecification::new(name, form, None)];
let attribute =
parse_attribute(&mut input, &unit, spec).expect("Should parse attribute");
parse_attribute(&mut input, &unit, &spec[..])
.expect("Should parse attribute")
.0;
assert_eq!(attribute.raw_value(), expect_raw);
assert_eq!(attribute.value(), expect_value);
}
Expand Down Expand Up @@ -3419,16 +3424,16 @@ mod tests {
) where
Endian: Endianity,
{
let spec = AttributeSpecification::new(constants::DW_AT_low_pc, form);
let spec = vec![AttributeSpecification::new(constants::DW_AT_low_pc, form, None)];

let expect = Attribute {
name: constants::DW_AT_low_pc,
value: value,
};

let rest = &mut EndianBuf::new(buf, Endian::default());
match parse_attribute(rest, unit, spec) {
Ok(attr) => {
match parse_attribute(rest, unit, &spec[..]) {
Ok((attr, _)) => {
assert_eq!(attr, expect);
assert_eq!(*rest, EndianBuf::new(&buf[len..], Endian::default()));
}
Expand Down Expand Up @@ -3785,9 +3790,9 @@ mod tests {
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),
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None),
AttributeSpecification::new(constants::DW_AT_high_pc, constants::DW_FORM_addr, None),
],
);

Expand Down Expand Up @@ -3903,9 +3908,9 @@ mod tests {
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),
AttributeSpecification::new(constants::DW_AT_name, constants::DW_FORM_string, None),
AttributeSpecification::new(constants::DW_AT_low_pc, constants::DW_FORM_addr, None),
AttributeSpecification::new(constants::DW_AT_high_pc, constants::DW_FORM_addr, None),
],
);

Expand Down

0 comments on commit 3d6cf77

Please sign in to comment.