Skip to content

Commit

Permalink
Merge pull request #208 from khuey/downstream
Browse files Browse the repository at this point in the history
Parse DW_OP_GNU_parameter_ref, add plumbing for evaluating it.
  • Loading branch information
philipc committed Jun 24, 2017
2 parents cf3491a + 48ada86 commit 350cd3d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/constants.rs
Expand Up @@ -1156,6 +1156,7 @@ dw!(DwOp(u8) {
DW_OP_GNU_push_tls_address = 0xe0,
DW_OP_GNU_implicit_pointer = 0xf2,
DW_OP_GNU_entry_value = 0xf3,
DW_OP_GNU_parameter_ref = 0xfa,
});

/// Pointer encoding used by `.eh_frame`. The four lower bits describe the
Expand Down
61 changes: 61 additions & 0 deletions src/op.rs
Expand Up @@ -184,6 +184,14 @@ pub enum Operation<'input, Endian>
/// The expression to be evaluated.
expression: EndianBuf<'input, Endian>,
},
/// Represents `DW_OP_GNU_parameter_ref`. This represents a parameter that was
/// optimized out. The offset points to the definition of the parameter, and is
/// matched to the `DW_TAG_GNU_call_site_parameter` in the caller that also
/// points to the same definition of the parameter.
ParameterRef {
/// The DIE to use.
offset: UnitOffset,
},
}

#[derive(Debug)]
Expand All @@ -206,6 +214,7 @@ enum OperationEvaluationResult<'input, Endian>
AwaitingCfa,
AwaitingAtLocation { location: DieReference },
AwaitingEntryValue { expression: EndianBuf<'input, Endian>, },
AwaitingParameterRef { parameter: UnitOffset },
}

/// A single location of a piece of the result of a DWARF expression.
Expand Down Expand Up @@ -761,6 +770,10 @@ impl<'input, Endian> Operation<'input, Endian>
let expression = parse_length_uleb_value(bytes)?;
Ok(Operation::EntryValue { expression: expression })
}
constants::DW_OP_GNU_parameter_ref => {
let value = parse_u32(bytes)?;
Ok(Operation::ParameterRef { offset: UnitOffset(value as usize) })
}

_ => Err(Error::InvalidExpression(name)),
}
Expand Down Expand Up @@ -827,6 +840,11 @@ pub enum EvaluationResult<'input, Endian>
/// caller determines what value to provide it should resume the
/// `Evaluation` by calling `Evaluation::resume_with_entry_value`.
RequiresEntryValue(EndianBuf<'input, Endian>),
/// The `Evaluation` needs the value of the parameter at the given location
/// in the current function's caller. Once the caller determins what value
/// to provide it should resume the `Evaluation` by calling
/// `Evaluation::resume_with_parameter_ref`.
RequiresParameterRef(UnitOffset),
}

/// A DWARF expression evaluator.
Expand Down Expand Up @@ -1260,6 +1278,10 @@ impl<'input, Endian> Evaluation<'input, Endian>
});
}

Operation::ParameterRef { offset } => {
return Ok(OperationEvaluationResult::AwaitingParameterRef { parameter: offset });
}

Operation::Piece { .. } => {
piece_end = true;
}
Expand Down Expand Up @@ -1494,6 +1516,31 @@ impl<'input, Endian> Evaluation<'input, Endian>
self.evaluate_internal()
}

/// Resume the `Evaluation` with the provided `parameter_value`. This will
/// apply the provided parameter value to the evaluation and continue evaluating
/// opcodes until the evaluation is completed, reaches an error, or needs
/// more information again.
///
/// # Panics
/// Panics if this `Evaluation` did not previously stop with `EvaluationResult::RequiresParameterRef`.
pub fn resume_with_parameter_ref(&mut self,
parameter_value: u64)
-> Result<EvaluationResult<'input, Endian>, Error>
where Endian: Endianity
{
match self.state {
EvaluationState::Error(err) => return Err(err),
EvaluationState::Waiting(OperationEvaluationResult::AwaitingParameterRef { .. }) => {
self.push(parameter_value);
}
_ => {
panic!("Called `Evaluation::resume_with_parameter_ref` without a preceding `EvaluationResult::RequiresParameterRef`")
}
};

self.evaluate_internal()
}

fn evaluate_internal(&mut self) -> Result<EvaluationResult<'input, Endian>, Error>
where Endian: Endianity
{
Expand Down Expand Up @@ -1615,6 +1662,10 @@ impl<'input, Endian> Evaluation<'input, Endian>
self.state = EvaluationState::Waiting(op_result);
return Ok(EvaluationResult::RequiresEntryValue(expression));
}
OperationEvaluationResult::AwaitingParameterRef { parameter } => {
self.state = EvaluationState::Waiting(op_result);
return Ok(EvaluationResult::RequiresParameterRef(parameter));
}
};
}

Expand Down Expand Up @@ -2161,6 +2212,16 @@ mod tests {
}
}

#[test]
fn test_op_parse_gnu_parameter_ref() {
check_op_parse(|s| s.D8(constants::DW_OP_GNU_parameter_ref.0).D32(0x12345678),
&Operation::ParameterRef {
offset: UnitOffset(0x12345678)
},
4,
Format::Dwarf32)
}

enum AssemblerEntry {
Op(constants::DwOp),
Mark(u8),
Expand Down

0 comments on commit 350cd3d

Please sign in to comment.