Skip to content

Commit

Permalink
write: implement expressions
Browse files Browse the repository at this point in the history
Expressions are now are Vec of operations, instead of raw bytecode.
This is required to support addresses and references within the
expression.
  • Loading branch information
philipc committed Apr 27, 2020
1 parent b94117d commit daa8a39
Show file tree
Hide file tree
Showing 9 changed files with 1,907 additions and 184 deletions.
36 changes: 36 additions & 0 deletions src/read/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,42 @@ impl<R: Reader> Expression<R> {
pub fn evaluation(self, encoding: Encoding) -> Evaluation<R> {
Evaluation::new(self.0, encoding)
}

/// Return an iterator for the operations in the expression.
pub fn operations(self, encoding: Encoding) -> OperationIter<R> {
OperationIter {
input: self.0,
encoding,
}
}
}

/// An iterator for the operations in an expression.
#[derive(Debug, Clone, Copy)]
pub struct OperationIter<R: Reader> {
input: R,
encoding: Encoding,
}

impl<R: Reader> OperationIter<R> {
/// Read the next operation in an expression.
pub fn next(&mut self) -> Result<Option<Operation<R>>> {
if self.input.is_empty() {
return Ok(None);
}
match Operation::parse(&mut self.input, self.encoding) {
Ok(op) => Ok(Some(op)),
Err(e) => {
self.input.empty();
Err(e)
}
}
}

/// Return the current byte offset of the iterator.
pub fn offset_from(&self, expression: &Expression<R>) -> R::Offset {
self.input.offset_from(&expression.0)
}
}

/// A DWARF expression evaluator.
Expand Down
69 changes: 38 additions & 31 deletions src/write/cfi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ impl CommonInformationEntry {
}

for instruction in &self.instructions {
instruction.write(w, self)?;
instruction.write(w, encoding, self)?;
}

write_nop(
Expand Down Expand Up @@ -357,7 +357,7 @@ impl FrameDescriptionEntry {
for (offset, instruction) in &self.instructions {
write_advance_loc(w, cie.code_alignment_factor, prev_offset, *offset)?;
prev_offset = *offset;
instruction.write(w, cie)?;
instruction.write(w, encoding, cie)?;
}

write_nop(
Expand Down Expand Up @@ -413,7 +413,12 @@ pub enum CallFrameInstruction {
}

impl CallFrameInstruction {
fn write<W: Writer>(&self, w: &mut W, cie: &CommonInformationEntry) -> Result<()> {
fn write<W: Writer>(
&self,
w: &mut W,
encoding: Encoding,
cie: &CommonInformationEntry,
) -> Result<()> {
match *self {
CallFrameInstruction::Cfa(register, offset) => {
if offset < 0 {
Expand Down Expand Up @@ -445,8 +450,8 @@ impl CallFrameInstruction {
}
CallFrameInstruction::CfaExpression(ref expression) => {
w.write_u8(constants::DW_CFA_def_cfa_expression.0)?;
w.write_uleb128(expression.0.len() as u64)?;
w.write(&expression.0)?;
w.write_uleb128(expression.size(encoding, None) as u64)?;
expression.write(w, None, encoding, None)?;
}
CallFrameInstruction::Restore(register) => {
if register.0 < 0x40 {
Expand Down Expand Up @@ -499,14 +504,14 @@ impl CallFrameInstruction {
CallFrameInstruction::Expression(register, ref expression) => {
w.write_u8(constants::DW_CFA_expression.0)?;
w.write_uleb128(register.0.into())?;
w.write_uleb128(expression.0.len() as u64)?;
w.write(&expression.0)?;
w.write_uleb128(expression.size(encoding, None) as u64)?;
expression.write(w, None, encoding, None)?;
}
CallFrameInstruction::ValExpression(register, ref expression) => {
w.write_u8(constants::DW_CFA_val_expression.0)?;
w.write_uleb128(register.0.into())?;
w.write_uleb128(expression.0.len() as u64)?;
w.write(&expression.0)?;
w.write_uleb128(expression.size(encoding, None) as u64)?;
expression.write(w, None, encoding, None)?;
}
CallFrameInstruction::RememberState => {
w.write_u8(constants::DW_CFA_remember_state.0)?;
Expand Down Expand Up @@ -675,9 +680,12 @@ pub(crate) mod convert {
let mut offset = 0;
let mut from_instructions = from_cie.instructions(frame, bases);
while let Some(from_instruction) = from_instructions.next()? {
if let Some(instruction) =
CallFrameInstruction::from(from_instruction, from_cie, &mut offset)?
{
if let Some(instruction) = CallFrameInstruction::from(
from_instruction,
from_cie,
convert_address,
&mut offset,
)? {
cie.instructions.push(instruction);
}
}
Expand Down Expand Up @@ -716,9 +724,12 @@ pub(crate) mod convert {
let mut offset = 0;
let mut from_instructions = from_fde.instructions(frame, bases);
while let Some(from_instruction) = from_instructions.next()? {
if let Some(instruction) =
CallFrameInstruction::from(from_instruction, from_cie, &mut offset)?
{
if let Some(instruction) = CallFrameInstruction::from(
from_instruction,
from_cie,
convert_address,
&mut offset,
)? {
fde.instructions.push((offset, instruction));
}
}
Expand All @@ -731,8 +742,11 @@ pub(crate) mod convert {
fn from<R: Reader<Offset = usize>>(
from_instruction: read::CallFrameInstruction<R>,
from_cie: &read::CommonInformationEntry<R>,
convert_address: &dyn Fn(u64) -> Option<Address>,
offset: &mut u32,
) -> ConvertResult<Option<CallFrameInstruction>> {
let convert_expression =
|x| Expression::from(x, from_cie.encoding(), None, None, None, convert_address);
// TODO: validate integer type conversions
Ok(Some(match from_instruction {
read::CallFrameInstruction::SetLoc { .. } => {
Expand Down Expand Up @@ -764,8 +778,7 @@ pub(crate) mod convert {
CallFrameInstruction::CfaOffset(offset as i32)
}
read::CallFrameInstruction::DefCfaExpression { expression } => {
let expression = Expression(expression.0.to_slice()?.into());
CallFrameInstruction::CfaExpression(expression)
CallFrameInstruction::CfaExpression(convert_expression(expression)?)
}
read::CallFrameInstruction::Undefined { register } => {
CallFrameInstruction::Undefined(register)
Expand Down Expand Up @@ -808,17 +821,11 @@ pub(crate) mod convert {
read::CallFrameInstruction::Expression {
register,
expression,
} => {
let expression = Expression(expression.0.to_slice()?.into());
CallFrameInstruction::Expression(register, expression)
}
} => CallFrameInstruction::Expression(register, convert_expression(expression)?),
read::CallFrameInstruction::ValExpression {
register,
expression,
} => {
let expression = Expression(expression.0.to_slice()?.into());
CallFrameInstruction::ValExpression(register, expression)
}
} => CallFrameInstruction::ValExpression(register, convert_expression(expression)?),
read::CallFrameInstruction::Restore { register } => {
CallFrameInstruction::Restore(register)
}
Expand Down Expand Up @@ -922,6 +929,9 @@ mod tests {

#[test]
fn test_frame_instruction() {
let mut expression = Expression::new();
expression.op_constu(0);

let cie_instructions = [
CallFrameInstruction::Cfa(X86_64::RSP, 8),
CallFrameInstruction::Offset(X86_64::RA, -8),
Expand All @@ -934,10 +944,7 @@ mod tests {
(4, CallFrameInstruction::CfaOffset(8)),
(4, CallFrameInstruction::CfaOffset(0)),
(4, CallFrameInstruction::CfaOffset(-8)),
(
6,
CallFrameInstruction::CfaExpression(Expression(vec![1, 2, 3])),
),
(6, CallFrameInstruction::CfaExpression(expression.clone())),
(8, CallFrameInstruction::Restore(Register(1))),
(8, CallFrameInstruction::Restore(Register(101))),
(10, CallFrameInstruction::Undefined(Register(2))),
Expand All @@ -949,11 +956,11 @@ mod tests {
(18, CallFrameInstruction::Register(Register(6), Register(7))),
(
20,
CallFrameInstruction::Expression(Register(8), Expression(vec![2, 3, 4])),
CallFrameInstruction::Expression(Register(8), expression.clone()),
),
(
22,
CallFrameInstruction::ValExpression(Register(9), Expression(vec![3, 4, 5])),
CallFrameInstruction::ValExpression(Register(9), expression.clone()),
),
(24 + 0x80, CallFrameInstruction::RememberState),
(26 + 0x280, CallFrameInstruction::RestoreState),
Expand Down
6 changes: 3 additions & 3 deletions src/write/dwarf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,17 @@ impl DwarfUnit {
let abbrev_offset = sections.debug_abbrev.offset();
let mut abbrevs = AbbreviationTable::default();

let mut debug_info_refs = Vec::new();
self.unit.write(
sections,
abbrev_offset,
&mut abbrevs,
&line_strings,
&strings,
&mut debug_info_refs,
)?;
// None should exist because we didn't give out any UnitId.
assert!(debug_info_refs.is_empty());
assert!(sections.debug_info_refs.is_empty());
assert!(sections.debug_loc_refs.is_empty());
assert!(sections.debug_loclists_refs.is_empty());

abbrevs.write(&mut sections.debug_abbrev)?;
Ok(())
Expand Down
Loading

0 comments on commit daa8a39

Please sign in to comment.