From 5f71609491aa3497a041deb237b3f8c7b95644d9 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Mon, 14 Aug 2023 17:02:09 +1000 Subject: [PATCH] read/op: add ExpressionKind DWARF expressions can be used to either compute a value or a location description, depending on context, and this affects the result of the evaluation, and which operations are valid within them. Use the attribute tag to determine the expression kind for expressions in DIE attributes. --- benches/bench.rs | 18 +- crates/examples/src/bin/dwarfdump.rs | 4 +- src/read/mod.rs | 12 ++ src/read/op.rs | 285 ++++++++++++++++++--------- src/read/unit.rs | 72 +++---- src/write/unit.rs | 7 +- tests/parse_self.rs | 18 +- 7 files changed, 266 insertions(+), 150 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index fb29df77..95928f4a 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -5,8 +5,8 @@ extern crate test; use gimli::{ AttributeValue, DebugAbbrev, DebugAddr, DebugAddrBase, DebugAranges, DebugInfo, DebugLine, DebugLineOffset, DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, - DebugRngLists, Encoding, EndianSlice, EntriesTreeNode, Expression, LittleEndian, LocationLists, - Operation, RangeLists, RangeListsOffset, Reader, ReaderOffset, + DebugRngLists, Encoding, EndianSlice, EntriesTreeNode, Expression, ExpressionKind, + LittleEndian, LocationLists, Operation, RangeLists, RangeListsOffset, Reader, ReaderOffset, }; use std::env; use std::fs::File; @@ -405,7 +405,7 @@ fn bench_parsing_debug_ranges(b: &mut test::Bencher) { fn debug_info_expressions( debug_info: &DebugInfo, debug_abbrev: &DebugAbbrev, -) -> Vec<(Expression, Encoding)> { +) -> Vec<(Expression, ExpressionKind, Encoding)> { let mut expressions = Vec::new(); let mut iter = debug_info.units(); @@ -418,8 +418,8 @@ fn debug_info_expressions( while let Some((_, entry)) = cursor.next_dfs().expect("Should parse next dfs") { let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { - if let AttributeValue::Exprloc(expression) = attr.value() { - expressions.push((expression, unit.encoding())); + if let AttributeValue::Exprloc(expression, kind) = attr.value() { + expressions.push((expression, kind, unit.encoding())); } } } @@ -439,7 +439,7 @@ fn bench_parsing_debug_info_expressions(b: &mut test::Bencher) { let expressions = debug_info_expressions(&debug_info, &debug_abbrev); b.iter(|| { - for &(expression, encoding) in &*expressions { + for &(expression, _kind, encoding) in &*expressions { let mut pc = expression.0; while !pc.is_empty() { Operation::parse(&mut pc, encoding).expect("Should parse operation"); @@ -459,8 +459,8 @@ fn bench_evaluating_debug_info_expressions(b: &mut test::Bencher) { let expressions = debug_info_expressions(&debug_info, &debug_abbrev); b.iter(|| { - for &(expression, encoding) in &*expressions { - let mut eval = expression.evaluation(encoding); + for &(expression, kind, encoding) in &*expressions { + let mut eval = expression.evaluation(kind, encoding); eval.set_initial_value(0); let result = eval.evaluate().expect("Should evaluate expression"); test::black_box(result); @@ -564,7 +564,7 @@ fn bench_evaluating_debug_loc_expressions(b: &mut test::Bencher) { b.iter(|| { for &(expression, encoding) in &*expressions { - let mut eval = expression.evaluation(encoding); + let mut eval = expression.evaluation(ExpressionKind::Location, encoding); eval.set_initial_value(0); let result = eval.evaluate().expect("Should evaluate expression"); test::black_box(result); diff --git a/crates/examples/src/bin/dwarfdump.rs b/crates/examples/src/bin/dwarfdump.rs index 84e10e04..08431db2 100644 --- a/crates/examples/src/bin/dwarfdump.rs +++ b/crates/examples/src/bin/dwarfdump.rs @@ -1434,8 +1434,8 @@ fn dump_attr_value( } }; } - gimli::AttributeValue::Exprloc(ref data) => { - if let gimli::AttributeValue::Exprloc(_) = attr.raw_value() { + gimli::AttributeValue::Exprloc(ref data, _kind) => { + if let gimli::AttributeValue::Exprloc(..) = attr.raw_value() { write!(w, "len 0x{:04x}: ", data.0.len())?; for byte in data.0.to_slice()?.iter() { write!(w, "{:02x}", byte)?; diff --git a/src/read/mod.rs b/src/read/mod.rs index 22a8e9fb..fc06ab4b 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -363,6 +363,11 @@ pub enum Error { /// An expression-terminating operation was followed by something /// other than the end of the expression or a piece operation. InvalidExpressionTerminator(u64), + /// An expression for a value contained an operation that is only valid for location + /// descriptions. + InvalidValueExpression, + /// Cannot evaluate an expression without knowing its kind. + UnknownExpressionKind, /// Division or modulus by zero when evaluating an expression. DivisionByZero, /// An expression operation used mismatching types. @@ -520,6 +525,13 @@ impl Error { "DWARF expression has piece followed by non-piece expression at end" } Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece", + Error::InvalidValueExpression => { + "An expression for a value contained an operation that is only valid for location \ + descriptions" + } + Error::UnknownExpressionKind => { + "Cannot evaluate an expression without knowing its kind" + } Error::DivisionByZero => "Division or modulus by zero when evaluating expression", Error::TypeMismatch => "Type mismatch when evaluating expression", Error::IntegralTypeRequired => "Integral type expected when evaluating expression", diff --git a/src/read/op.rs b/src/read/op.rs index 0b6a71b4..18fbe3db 100644 --- a/src/read/op.rs +++ b/src/read/op.rs @@ -294,7 +294,7 @@ where #[derive(Debug)] enum OperationEvaluationResult { - Piece, + Piece { piece: Piece }, Incomplete, Complete { location: Location }, Waiting(EvaluationWaiting, EvaluationResult), @@ -919,6 +919,19 @@ pub enum EvaluationResult { RequiresBaseType(UnitOffset), } +/// Whether a DWARF expression is for a value or a location description. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ExpressionKind { + /// The kind of expression is unknown. + /// + /// This expression will not be able to be evaluated. + Unknown, + /// The expression is for a value. + Value, + /// The expression is for a location description. + Location, +} + /// The bytecode for a DWARF expression or location description. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Expression(pub R); @@ -938,14 +951,15 @@ impl Expression { /// # let debug_info = gimli::DebugInfo::from(gimli::EndianSlice::new(&[], endian)); /// # let unit = debug_info.units().next().unwrap().unwrap(); /// # let bytecode = gimli::EndianSlice::new(&[], endian); + /// # let kind = gimli::ExpressionKind::Unknown; /// let expression = gimli::Expression(bytecode); - /// let mut eval = expression.evaluation(unit.encoding()); + /// let mut eval = expression.evaluation(kind, unit.encoding()); /// let mut result = eval.evaluate().unwrap(); /// ``` #[cfg(feature = "read")] #[inline] - pub fn evaluation(self, encoding: Encoding) -> Evaluation { - Evaluation::new(self.0, encoding) + pub fn evaluation(self, kind: ExpressionKind, encoding: Encoding) -> Evaluation { + Evaluation::new(self, kind, encoding) } /// Return an iterator for the operations in the expression. @@ -1010,6 +1024,7 @@ on the heap using [`Vec`]. This is the default storage type parameter for [`Eval /// ```rust,no_run /// # use gimli::*; /// # let bytecode = EndianSlice::new(&[], LittleEndian); +/// # let kind = ExpressionKind::Unknown; /// # let encoding = unimplemented!(); /// # let get_register_value = |_, _| Value::Generic(42); /// # let get_frame_base = || 0xdeadbeef; @@ -1022,7 +1037,7 @@ on the heap using [`Vec`]. This is the default storage type parameter for [`Eval /// type Result = [Piece; 1]; /// } /// -/// let mut eval = Evaluation::<_, StoreOnStack>::new_in(bytecode, encoding); +/// let mut eval = Evaluation::<_, StoreOnStack>::new_in(Expression(bytecode), kind, encoding); /// let mut result = eval.evaluate().unwrap(); /// while result != EvaluationResult::Complete { /// match result { @@ -1077,13 +1092,14 @@ impl EvaluationStorage for StoreOnHeap { /// /// # Examples /// ```rust,no_run -/// use gimli::{EndianSlice, Evaluation, EvaluationResult, Format, LittleEndian, Value}; -/// # let bytecode = EndianSlice::new(&[], LittleEndian); +/// use gimli::{Evaluation, EvaluationResult, Expression}; +/// # let bytecode = gimli::EndianSlice::new(&[], gimli::LittleEndian); +/// # let kind = gimli::ExpressionKind::Unknown; /// # let encoding = unimplemented!(); -/// # let get_register_value = |_, _| Value::Generic(42); +/// # let get_register_value = |_, _| gimli::Value::Generic(42); /// # let get_frame_base = || 0xdeadbeef; /// -/// let mut eval = Evaluation::new(bytecode, encoding); +/// let mut eval = Evaluation::new(Expression(bytecode), kind, encoding); /// let mut result = eval.evaluate().unwrap(); /// while result != EvaluationResult::Complete { /// match result { @@ -1105,6 +1121,7 @@ impl EvaluationStorage for StoreOnHeap { #[derive(Debug)] pub struct Evaluation = StoreOnHeap> { bytecode: R, + kind: ExpressionKind, encoding: Encoding, object_address: Option, max_iterations: Option, @@ -1126,7 +1143,8 @@ pub struct Evaluation = StoreOnHeap> { // is stored here while evaluating the subroutine. expression_stack: ArrayVec, - result: ArrayVec, + value_result: Value, + location_result: ArrayVec, } #[cfg(feature = "read")] @@ -1135,17 +1153,18 @@ impl Evaluation { /// /// The new evaluator is created without an initial value, without /// an object address, and without a maximum number of iterations. - pub fn new(bytecode: R, encoding: Encoding) -> Self { - Self::new_in(bytecode, encoding) + pub fn new(expression: Expression, kind: ExpressionKind, encoding: Encoding) -> Self { + Self::new_in(expression, kind, encoding) } /// Get the result of this `Evaluation`. /// /// # Panics /// Panics if this `Evaluation` has not been driven to completion. + #[deprecated(note = "Use value_result or location_result")] pub fn result(self) -> Vec> { match self.state { - EvaluationState::Complete => self.result.into_vec(), + EvaluationState::Complete => self.location_result.into_vec(), _ => { panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed") } @@ -1158,10 +1177,11 @@ impl> Evaluation { /// /// The new evaluator is created without an initial value, without /// an object address, and without a maximum number of iterations. - pub fn new_in(bytecode: R, encoding: Encoding) -> Self { - let pc = bytecode.clone(); + pub fn new_in(expression: Expression, kind: ExpressionKind, encoding: Encoding) -> Self { + let pc = expression.0.clone(); Evaluation { - bytecode, + bytecode: expression.0, + kind, encoding, object_address: None, max_iterations: None, @@ -1175,7 +1195,8 @@ impl> Evaluation { stack: Default::default(), expression_stack: Default::default(), pc, - result: Default::default(), + value_result: Value::Generic(0), + location_result: Default::default(), } } @@ -1562,14 +1583,12 @@ impl> Evaluation { let address = entry.to_u64(self.addr_mask)?; Location::Address { address } }; - self.result - .try_push(Piece { - size_in_bits: Some(size_in_bits), - bit_offset, - location, - }) - .map_err(|_| Error::StackFull)?; - return Ok(OperationEvaluationResult::Piece); + let piece = Piece { + size_in_bits: Some(size_in_bits), + bit_offset, + location, + }; + return Ok(OperationEvaluationResult::Piece { piece }); } Operation::TypedLiteral { base_type, value } => { @@ -1600,19 +1619,46 @@ impl> Evaluation { Ok(OperationEvaluationResult::Incomplete) } - /// Get the result of this `Evaluation`. + /// Get the kind of expression being evaluated. + pub fn kind(&self) -> ExpressionKind { + self.kind + } + + /// Get the result if this is an evaluation for a value. /// /// # Panics /// Panics if this `Evaluation` has not been driven to completion. - pub fn as_result(&self) -> &[Piece] { + pub fn value_result(&self) -> Value { match self.state { - EvaluationState::Complete => &self.result, + EvaluationState::Complete => self.value_result, _ => { - panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed") + panic!("Called `Evaluation::value_result` on an `Evaluation` that has not been completed") } } } + /// Get the result if this is an evaluation for a location. + /// + /// # Panics + /// Panics if this `Evaluation` has not been driven to completion. + pub fn location_result(&self) -> &[Piece] { + match self.state { + EvaluationState::Complete => &self.location_result, + _ => { + panic!("Called `Evaluation::location_result` on an `Evaluation` that has not been completed") + } + } + } + + /// Get the result of this `Evaluation`. + /// + /// # Panics + /// Panics if this `Evaluation` has not been driven to completion. + #[deprecated(note = "Use value_result or location_result")] + pub fn as_result(&self) -> &[Piece] { + self.location_result() + } + /// Evaluate a DWARF expression. This method should only ever be called /// once. If the returned `EvaluationResult` is not /// `EvaluationResult::Complete`, the caller should provide the required @@ -1905,84 +1951,135 @@ impl> Evaluation { false } - fn evaluate_internal(&mut self) -> Result> { - while !self.end_of_expression() { - self.iteration += 1; - if let Some(max_iterations) = self.max_iterations { - if self.iteration > max_iterations { - return Err(Error::TooManyIterations); - } + fn evaluate_value( + &mut self, + op_result: OperationEvaluationResult, + ) -> Result>> { + match op_result { + OperationEvaluationResult::Piece { .. } + | OperationEvaluationResult::Complete { .. } => Err(Error::InvalidValueExpression), + OperationEvaluationResult::Incomplete => Ok(None), + OperationEvaluationResult::Waiting(waiting, result) => { + self.state = EvaluationState::Waiting(waiting); + Ok(Some(result)) } + } + } - let op_result = self.evaluate_one_operation()?; - match op_result { - OperationEvaluationResult::Piece => {} - OperationEvaluationResult::Incomplete => { - if self.end_of_expression() && !self.result.is_empty() { + fn evaluate_location( + &mut self, + op_result: OperationEvaluationResult, + ) -> Result>> { + match op_result { + OperationEvaluationResult::Piece { piece } => { + self.location_result + .try_push(piece) + .map_err(|_| Error::StackFull)?; + } + OperationEvaluationResult::Incomplete => { + if self.end_of_expression() && !self.location_result.is_empty() { + // We saw a piece earlier and then some + // unterminated piece. It's not clear this is + // well-defined. + return Err(Error::InvalidPiece); + } + } + OperationEvaluationResult::Complete { location } => { + if self.end_of_expression() { + if !self.location_result.is_empty() { // We saw a piece earlier and then some // unterminated piece. It's not clear this is // well-defined. return Err(Error::InvalidPiece); } - } - OperationEvaluationResult::Complete { location } => { - if self.end_of_expression() { - if !self.result.is_empty() { - // We saw a piece earlier and then some - // unterminated piece. It's not clear this is - // well-defined. - return Err(Error::InvalidPiece); + self.location_result + .try_push(Piece { + size_in_bits: None, + bit_offset: None, + location, + }) + .map_err(|_| Error::StackFull)?; + } else { + // If there are more operations, then the next operation must + // be a Piece. + match Operation::parse(&mut self.pc, self.encoding)? { + Operation::Piece { + size_in_bits, + bit_offset, + } => { + self.location_result + .try_push(Piece { + size_in_bits: Some(size_in_bits), + bit_offset, + location, + }) + .map_err(|_| Error::StackFull)?; } - self.result - .try_push(Piece { - size_in_bits: None, - bit_offset: None, - location, - }) - .map_err(|_| Error::StackFull)?; - } else { - // If there are more operations, then the next operation must - // be a Piece. - match Operation::parse(&mut self.pc, self.encoding)? { - Operation::Piece { - size_in_bits, - bit_offset, - } => { - self.result - .try_push(Piece { - size_in_bits: Some(size_in_bits), - bit_offset, - location, - }) - .map_err(|_| Error::StackFull)?; - } - _ => { - let value = - self.bytecode.len().into_u64() - self.pc.len().into_u64() - 1; - return Err(Error::InvalidExpressionTerminator(value)); - } + _ => { + let value = + self.bytecode.len().into_u64() - self.pc.len().into_u64() - 1; + return Err(Error::InvalidExpressionTerminator(value)); } } } - OperationEvaluationResult::Waiting(waiting, result) => { - self.state = EvaluationState::Waiting(waiting); - return Ok(result); + } + OperationEvaluationResult::Waiting(waiting, result) => { + self.state = EvaluationState::Waiting(waiting); + return Ok(Some(result)); + } + } + Ok(None) + } + + fn evaluate_internal(&mut self) -> Result> { + while !self.end_of_expression() { + self.iteration += 1; + if let Some(max_iterations) = self.max_iterations { + if self.iteration > max_iterations { + return Err(Error::TooManyIterations); } + } + + let op_result = self.evaluate_one_operation()?; + let result = match self.kind { + ExpressionKind::Value => self.evaluate_value(op_result)?, + ExpressionKind::Location => self.evaluate_location(op_result)?, + ExpressionKind::Unknown => return Err(Error::UnknownExpressionKind), }; + if let Some(result) = result { + return Ok(result); + } } - // If no pieces have been seen, use the stack top as the - // result. - if self.result.is_empty() { - let entry = self.pop()?; - let addr = entry.to_u64(self.addr_mask)?; - self.result - .try_push(Piece { - size_in_bits: None, - bit_offset: None, - location: Location::Address { address: addr }, - }) - .map_err(|_| Error::StackFull)?; + match self.kind { + ExpressionKind::Value => { + // Use the stack top as the result. + self.value_result = self.pop()?; + // Also store it in location_result for backwards compatibility. + let addr = self.value_result.to_u64(self.addr_mask)?; + self.location_result + .try_push(Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Address { address: addr }, + }) + .map_err(|_| Error::StackFull)?; + } + ExpressionKind::Location => { + // If no pieces have been seen, use the stack top as the result. + if self.location_result.is_empty() { + let entry = self.pop()?; + let addr = entry.to_u64(self.addr_mask)?; + self.location_result + .try_push(Piece { + size_in_bits: None, + bit_offset: None, + location: Location::Address { address: addr }, + }) + .map_err(|_| Error::StackFull)?; + } + } + ExpressionKind::Unknown => {} } self.state = EvaluationState::Complete; @@ -2912,7 +3009,7 @@ mod tests { let bytes = assemble(program); let bytes = EndianSlice::new(&bytes, LittleEndian); - let mut eval = Evaluation::new(bytes, encoding); + let mut eval = Evaluation::new(Expression(bytes), ExpressionKind::Location, encoding); if let Some(val) = object_address { eval.set_object_address(val); @@ -2931,7 +3028,7 @@ mod tests { match (result, expect) { (Ok(EvaluationResult::Complete), Ok(pieces)) => { - let vec = eval.result(); + let vec = eval.location_result(); assert_eq!(vec.len(), pieces.len()); for i in 0..pieces.len() { assert_eq!(vec[i], pieces[i]); diff --git a/src/read/unit.rs b/src/read/unit.rs index d799f0f0..0580cd0b 100644 --- a/src/read/unit.rs +++ b/src/read/unit.rs @@ -16,7 +16,7 @@ use crate::endianity::Endianity; use crate::read::abbrev::get_attribute_size; use crate::read::{ Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, DebugStr, EndianSlice, Error, - Expression, Reader, ReaderOffset, Result, Section, UnitOffset, + Expression, ExpressionKind, Reader, ReaderOffset, Result, Section, UnitOffset, }; impl DebugTypesOffset { @@ -995,7 +995,7 @@ where /// "The information bytes contain a DWARF expression (see Section 2.5) or /// location description (see Section 2.6)." - Exprloc(Expression), + Exprloc(Expression, ExpressionKind), /// A boolean that indicates presence or absence of the attribute. Flag(bool), @@ -1204,9 +1204,9 @@ impl Attribute { } // DW_FORM_exprloc macro_rules! exprloc { - () => { + ($kind:expr) => { if let Some(value) = self.exprloc_value() { - return AttributeValue::Exprloc(value); + return AttributeValue::Exprloc(value, $kind); } }; } @@ -1326,7 +1326,7 @@ impl Attribute { reference!(); } constants::DW_AT_location => { - exprloc!(); + exprloc!(ExpressionKind::Location); loclistptr!(); } constants::DW_AT_name => { @@ -1339,7 +1339,7 @@ impl Attribute { | constants::DW_AT_bit_offset | constants::DW_AT_bit_size => { constant!(udata_value, Udata); - exprloc!(); + exprloc!(ExpressionKind::Value); reference!(); } constants::DW_AT_stmt_list => { @@ -1369,7 +1369,7 @@ impl Attribute { reference!(); } constants::DW_AT_string_length => { - exprloc!(); + exprloc!(ExpressionKind::Location); loclistptr!(); reference!(); } @@ -1400,7 +1400,7 @@ impl Attribute { } constants::DW_AT_lower_bound => { // TODO: constant: sign depends on DW_AT_type. - exprloc!(); + exprloc!(ExpressionKind::Value); reference!(); } constants::DW_AT_producer => { @@ -1410,7 +1410,7 @@ impl Attribute { flag!(); } constants::DW_AT_return_addr => { - exprloc!(); + exprloc!(ExpressionKind::Location); loclistptr!(); } constants::DW_AT_start_scope => { @@ -1419,12 +1419,12 @@ impl Attribute { } constants::DW_AT_bit_stride => { constant!(udata_value, Udata); - exprloc!(); + exprloc!(ExpressionKind::Value); reference!(); } constants::DW_AT_upper_bound => { // TODO: constant: sign depends on DW_AT_type. - exprloc!(); + exprloc!(ExpressionKind::Value); reference!(); } constants::DW_AT_abstract_origin => { @@ -1447,14 +1447,14 @@ impl Attribute { } constants::DW_AT_count => { // TODO: constant - exprloc!(); + exprloc!(ExpressionKind::Value); reference!(); } constants::DW_AT_data_member_location => { // Constants must be handled before loclistptr so that DW_FORM_data4/8 // are correctly interpreted for DWARF version 4+. constant!(udata_value, Udata); - exprloc!(); + exprloc!(ExpressionKind::Location); loclistptr!(); } constants::DW_AT_decl_column => { @@ -1479,7 +1479,7 @@ impl Attribute { flag!(); } constants::DW_AT_frame_base => { - exprloc!(); + exprloc!(ExpressionKind::Location); loclistptr!(); } constants::DW_AT_friend => { @@ -1498,21 +1498,21 @@ impl Attribute { reference!(); } constants::DW_AT_segment => { - exprloc!(); + exprloc!(ExpressionKind::Location); loclistptr!(); } constants::DW_AT_specification => { reference!(); } constants::DW_AT_static_link => { - exprloc!(); + exprloc!(ExpressionKind::Location); loclistptr!(); } constants::DW_AT_type => { reference!(); } constants::DW_AT_use_location => { - exprloc!(); + exprloc!(ExpressionKind::Location); loclistptr!(); } constants::DW_AT_variable_parameter => { @@ -1522,25 +1522,25 @@ impl Attribute { constant!(u8_value, Virtuality, DwVirtuality); } constants::DW_AT_vtable_elem_location => { - exprloc!(); + exprloc!(ExpressionKind::Location); loclistptr!(); } constants::DW_AT_allocated => { // TODO: constant - exprloc!(); + exprloc!(ExpressionKind::Value); reference!(); } constants::DW_AT_associated => { // TODO: constant - exprloc!(); + exprloc!(ExpressionKind::Value); reference!(); } constants::DW_AT_data_location => { - exprloc!(); + exprloc!(ExpressionKind::Location); } constants::DW_AT_byte_stride => { constant!(udata_value, Udata); - exprloc!(); + exprloc!(ExpressionKind::Value); reference!(); } constants::DW_AT_entry_pc => { @@ -1642,7 +1642,7 @@ impl Attribute { } constants::DW_AT_rank => { // TODO: constant - exprloc!(); + exprloc!(ExpressionKind::Value); } constants::DW_AT_str_offsets_base => { stroffsetsptr!(); @@ -1678,10 +1678,10 @@ impl Attribute { address!(); } constants::DW_AT_call_value => { - exprloc!(); + exprloc!(ExpressionKind::Value); } constants::DW_AT_call_origin => { - exprloc!(); + reference!(); } constants::DW_AT_call_parameter => { reference!(); @@ -1693,16 +1693,16 @@ impl Attribute { flag!(); } constants::DW_AT_call_target => { - exprloc!(); + exprloc!(ExpressionKind::Value); } constants::DW_AT_call_target_clobbered => { - exprloc!(); + exprloc!(ExpressionKind::Value); } constants::DW_AT_call_data_location => { - exprloc!(); + exprloc!(ExpressionKind::Location); } constants::DW_AT_call_data_value => { - exprloc!(); + exprloc!(ExpressionKind::Value); } constants::DW_AT_noreturn => { flag!(); @@ -1886,7 +1886,7 @@ where pub fn exprloc_value(&self) -> Option> { Some(match *self { AttributeValue::Block(ref data) => Expression(data.clone()), - AttributeValue::Exprloc(ref data) => data.clone(), + AttributeValue::Exprloc(ref data, ..) => data.clone(), _ => return None, }) } @@ -2057,7 +2057,7 @@ pub(crate) fn parse_attribute( } constants::DW_FORM_exprloc => { let block = length_uleb128_value(input)?; - AttributeValue::Exprloc(Expression(block)) + AttributeValue::Exprloc(Expression(block), ExpressionKind::Unknown) } constants::DW_FORM_flag => { let present = input.read_u8()?; @@ -4070,7 +4070,10 @@ mod tests { constants::DW_FORM_block, block, AttributeValue::Block(EndianSlice::new(block_data, endian)), - AttributeValue::Exprloc(Expression(EndianSlice::new(block_data, endian))), + AttributeValue::Exprloc( + Expression(EndianSlice::new(block_data, endian)), + ExpressionKind::Location, + ), ), ( Format::Dwarf32, @@ -4440,7 +4443,10 @@ mod tests { let buf = [0x02, 0x99, 0x99, 0x11]; let unit = test_parse_attribute_unit_default(); let form = constants::DW_FORM_exprloc; - let value = AttributeValue::Exprloc(Expression(EndianSlice::new(&buf[1..3], LittleEndian))); + let value = AttributeValue::Exprloc( + Expression(EndianSlice::new(&buf[1..3], LittleEndian)), + ExpressionKind::Unknown, + ); test_parse_attribute(&buf, 3, &unit, form, value); } diff --git a/src/write/unit.rs b/src/write/unit.rs index dd8ba674..0f2b4d13 100644 --- a/src/write/unit.rs +++ b/src/write/unit.rs @@ -1749,7 +1749,7 @@ pub(crate) mod convert { read::AttributeValue::Data8(val) => AttributeValue::Data8(val), read::AttributeValue::Sdata(val) => AttributeValue::Sdata(val), read::AttributeValue::Udata(val) => AttributeValue::Udata(val), - read::AttributeValue::Exprloc(expression) => { + read::AttributeValue::Exprloc(expression, _kind) => { let expression = Expression::from( expression, context.unit.encoding(), @@ -2357,7 +2357,10 @@ mod tests { ( constants::DW_AT_name, AttributeValue::Exprloc(expression.clone()), - read::AttributeValue::Exprloc(read_expression), + read::AttributeValue::Exprloc( + read_expression, + read::ExpressionKind::Unknown, + ), ), ( constants::DW_AT_name, diff --git a/tests/parse_self.rs b/tests/parse_self.rs index fb316314..7b1df9f3 100755 --- a/tests/parse_self.rs +++ b/tests/parse_self.rs @@ -3,7 +3,7 @@ use gimli::{ AttributeValue, DebugAbbrev, DebugAddr, DebugAddrBase, DebugAranges, DebugInfo, DebugLine, DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, DebugStr, - Encoding, EndianSlice, Expression, LittleEndian, LocationLists, Operation, RangeLists, + Encoding, EndianSlice, Expression, ExpressionKind, LittleEndian, LocationLists, RangeLists, RangeListsOffset, Reader, }; use std::collections::hash_map::HashMap; @@ -30,14 +30,12 @@ fn read_section(section: &str) -> Vec { buf } -fn parse_expression(expr: Expression, encoding: Encoding) { - let mut pc = expr.0.clone(); - while !pc.is_empty() { - Operation::parse(&mut pc, encoding).expect("Should parse operation"); - } +fn parse_expression(expr: Expression, kind: ExpressionKind, encoding: Encoding) { + let mut operations = expr.clone().operations(encoding); + while operations.next().expect("Should parse operation").is_some() {} // Also attempt to evaluate some of it. - let mut eval = expr.evaluation(encoding); + let mut eval = expr.evaluation(kind, encoding); eval.set_initial_value(0); eval.evaluate().expect("Should evaluate expression"); } @@ -59,8 +57,8 @@ fn impl_parse_self_debug_info( let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { - if let AttributeValue::Exprloc(expression) = attr.value() { - parse_expression(expression, unit.encoding()); + if let AttributeValue::Exprloc(expression, kind) = attr.value() { + parse_expression(expression, kind, unit.encoding()); } } } @@ -223,7 +221,7 @@ fn test_parse_self_debug_loc() { .expect("Should parse locations OK"); while let Some(loc) = locs.next().expect("Should parse next location") { assert!(loc.range.begin <= loc.range.end); - parse_expression(loc.data, unit.encoding()); + parse_expression(loc.data, ExpressionKind::Location, unit.encoding()); } } }