Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse DW_OP_GNU_parameter_ref, add plumbing for evaluating it. #208

Merged
merged 1 commit into from
Jun 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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