/// Convert a u64 to an i64, with sign extension if required. /// /// This is primarily used when needing to treat `Value::Generic` /// as a signed value. #[inline] fn sign_extend(value: u64, mask: u64) -> i64 { let value = (value & mask) as i64; let sign = ((mask >> 1) + 1) as i64;
(value ^ sign).wrapping_sub(sign)
}
/// The type of an entry on the DWARF stack. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pubenum ValueType { /// The generic type, which is address-sized and of unspecified sign, /// as specified in the DWARF 5 standard, section 2.5.1. /// This type is also used to represent address base types.
Generic, /// Signed 8-bit integer type.
I8, /// Unsigned 8-bit integer type.
U8, /// Signed 16-bit integer type.
I16, /// Unsigned 16-bit integer type.
U16, /// Signed 32-bit integer type.
I32, /// Unsigned 32-bit integer type.
U32, /// Signed 64-bit integer type.
I64, /// Unsigned 64-bit integer type.
U64, /// 32-bit floating point type.
F32, /// 64-bit floating point type.
F64,
}
/// The value of an entry on the DWARF stack. #[derive(Debug, Clone, Copy, PartialEq)] pubenum Value { /// A generic value, which is address-sized and of unspecified sign.
Generic(u64), /// A signed 8-bit integer value.
I8(i8), /// An unsigned 8-bit integer value.
U8(u8), /// A signed 16-bit integer value.
I16(i16), /// An unsigned 16-bit integer value.
U16(u16), /// A signed 32-bit integer value.
I32(i32), /// An unsigned 32-bit integer value.
U32(u32), /// A signed 64-bit integer value.
I64(i64), /// An unsigned 64-bit integer value.
U64(u64), /// A 32-bit floating point value.
F32(f32), /// A 64-bit floating point value.
F64(f64),
}
impl ValueType { /// The size in bits of a value for this type. pubfn bit_size(self, addr_mask: u64) -> u32 { matchself {
ValueType::Generic => mask_bit_size(addr_mask),
ValueType::I8 | ValueType::U8 => 8,
ValueType::I16 | ValueType::U16 => 16,
ValueType::I32 | ValueType::U32 | ValueType::F32 => 32,
ValueType::I64 | ValueType::U64 | ValueType::F64 => 64,
}
}
/// Construct a `ValueType` from the attributes of a base type DIE. pubfn from_encoding(encoding: constants::DwAte, byte_size: u64) -> Option<ValueType> {
Some(match (encoding, byte_size) {
(constants::DW_ATE_signed, 1) => ValueType::I8,
(constants::DW_ATE_signed, 2) => ValueType::I16,
(constants::DW_ATE_signed, 4) => ValueType::I32,
(constants::DW_ATE_signed, 8) => ValueType::I64,
(constants::DW_ATE_unsigned, 1) => ValueType::U8,
(constants::DW_ATE_unsigned, 2) => ValueType::U16,
(constants::DW_ATE_unsigned, 4) => ValueType::U32,
(constants::DW_ATE_unsigned, 8) => ValueType::U64,
(constants::DW_ATE_float, 4) => ValueType::F32,
(constants::DW_ATE_float, 8) => ValueType::F64,
_ => return None,
})
}
if endianity != constants::DW_END_default { // TODO: we could check if it matches the reader endianity, // but normally it would use DW_END_default in that case. return Ok(None);
}
/// Read a `Value` with the given `value_type` from a `Reader`. pubfn parse<R: Reader>(value_type: ValueType, mut bytes: R) -> Result<Value> { let value = match value_type {
ValueType::I8 => Value::I8(bytes.read_i8()?),
ValueType::U8 => Value::U8(bytes.read_u8()?),
ValueType::I16 => Value::I16(bytes.read_i16()?),
ValueType::U16 => Value::U16(bytes.read_u16()?),
ValueType::I32 => Value::I32(bytes.read_i32()?),
ValueType::U32 => Value::U32(bytes.read_u32()?),
ValueType::I64 => Value::I64(bytes.read_i64()?),
ValueType::U64 => Value::U64(bytes.read_u64()?),
ValueType::F32 => Value::F32(bytes.read_f32()?),
ValueType::F64 => Value::F64(bytes.read_f64()?),
_ => return Err(Error::UnsupportedTypeOperation),
};
Ok(value)
}
/// Convert a `Value` to a `u64`. /// /// The `ValueType` of `self` must be integral. /// Values are sign extended if the source value is signed. pubfn to_u64(self, addr_mask: u64) -> Result<u64> { let value = matchself {
Value::Generic(value) => value & addr_mask,
Value::I8(value) => value as u64,
Value::U8(value) => u64::from(value),
Value::I16(value) => value as u64,
Value::U16(value) => u64::from(value),
Value::I32(value) => value as u64,
Value::U32(value) => u64::from(value),
Value::I64(value) => value as u64,
Value::U64(value) => value,
_ => return Err(Error::IntegralTypeRequired),
};
Ok(value)
}
/// Create a `Value` with the given `value_type` from a `u64` value. /// /// The `value_type` may be integral or floating point. /// The result is truncated if the `u64` value does /// not fit the bounds of the `value_type`. pubfn from_u64(value_type: ValueType, value: u64) -> Result<Value> { let value = match value_type {
ValueType::Generic => Value::Generic(value),
ValueType::I8 => Value::I8(value as i8),
ValueType::U8 => Value::U8(value as u8),
ValueType::I16 => Value::I16(value as i16),
ValueType::U16 => Value::U16(value as u16),
ValueType::I32 => Value::I32(value as i32),
ValueType::U32 => Value::U32(value as u32),
ValueType::I64 => Value::I64(value as i64),
ValueType::U64 => Value::U64(value),
ValueType::F32 => Value::F32(value as f32),
ValueType::F64 => Value::F64(value as f64),
};
Ok(value)
}
/// Create a `Value` with the given `value_type` from a `f32` value. /// /// The `value_type` may be integral or floating point. /// The result is not defined if the `f32` value does /// not fit the bounds of the `value_type`. fn from_f32(value_type: ValueType, value: f32) -> Result<Value> { let value = match value_type {
ValueType::Generic => Value::Generic(value as u64),
ValueType::I8 => Value::I8(value as i8),
ValueType::U8 => Value::U8(value as u8),
ValueType::I16 => Value::I16(value as i16),
ValueType::U16 => Value::U16(value as u16),
ValueType::I32 => Value::I32(value as i32),
ValueType::U32 => Value::U32(value as u32),
ValueType::I64 => Value::I64(value as i64),
ValueType::U64 => Value::U64(value as u64),
ValueType::F32 => Value::F32(value),
ValueType::F64 => Value::F64(f64::from(value)),
};
Ok(value)
}
/// Create a `Value` with the given `value_type` from a `f64` value. /// /// The `value_type` may be integral or floating point. /// The result is not defined if the `f64` value does /// not fit the bounds of the `value_type`. fn from_f64(value_type: ValueType, value: f64) -> Result<Value> { let value = match value_type {
ValueType::Generic => Value::Generic(value as u64),
ValueType::I8 => Value::I8(value as i8),
ValueType::U8 => Value::U8(value as u8),
ValueType::I16 => Value::I16(value as i16),
ValueType::U16 => Value::U16(value as u16),
ValueType::I32 => Value::I32(value as i32),
ValueType::U32 => Value::U32(value as u32),
ValueType::I64 => Value::I64(value as i64),
ValueType::U64 => Value::U64(value as u64),
ValueType::F32 => Value::F32(value as f32),
ValueType::F64 => Value::F64(value),
};
Ok(value)
}
/// Convert a `Value` to the given `value_type`. /// /// When converting between integral types, the result is truncated /// if the source value does not fit the bounds of the `value_type`. /// When converting from floating point types, the result is not defined /// if the source value does not fit the bounds of the `value_type`. /// /// This corresponds to the DWARF `DW_OP_convert` operation. pubfn convert(self, value_type: ValueType, addr_mask: u64) -> Result<Value> { matchself {
Value::F32(value) => Value::from_f32(value_type, value),
Value::F64(value) => Value::from_f64(value_type, value),
_ => Value::from_u64(value_type, self.to_u64(addr_mask)?),
}
}
/// Reinterpret the bits in a `Value` as the given `value_type`. /// /// The source and result value types must have equal sizes. /// /// This corresponds to the DWARF `DW_OP_reinterpret` operation. pubfn reinterpret(self, value_type: ValueType, addr_mask: u64) -> Result<Value> { ifself.value_type().bit_size(addr_mask) != value_type.bit_size(addr_mask) { return Err(Error::TypeMismatch);
} let bits = matchself {
Value::Generic(value) => value,
Value::I8(value) => value as u64,
Value::U8(value) => u64::from(value),
Value::I16(value) => value as u64,
Value::U16(value) => u64::from(value),
Value::I32(value) => value as u64,
Value::U32(value) => u64::from(value),
Value::I64(value) => value as u64,
Value::U64(value) => value,
Value::F32(value) => u64::from(f32::to_bits(value)),
Value::F64(value) => f64::to_bits(value),
}; let value = match value_type {
ValueType::Generic => Value::Generic(bits),
ValueType::I8 => Value::I8(bits as i8),
ValueType::U8 => Value::U8(bits as u8),
ValueType::I16 => Value::I16(bits as i16),
ValueType::U16 => Value::U16(bits as u16),
ValueType::I32 => Value::I32(bits as i32),
ValueType::U32 => Value::U32(bits as u32),
ValueType::I64 => Value::I64(bits as i64),
ValueType::U64 => Value::U64(bits),
ValueType::F32 => Value::F32(f32::from_bits(bits as u32)),
ValueType::F64 => Value::F64(f64::from_bits(bits)),
};
Ok(value)
}
/// Perform an absolute value operation. /// /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_abs` operation. pubfn abs(self, addr_mask: u64) -> Result<Value> { // wrapping_abs() can be used because DWARF specifies that the result is undefined // for negative minimal values. let value = matchself {
Value::Generic(value) => {
Value::Generic(sign_extend(value, addr_mask).wrapping_abs() as u64)
}
Value::I8(value) => Value::I8(value.wrapping_abs()),
Value::I16(value) => Value::I16(value.wrapping_abs()),
Value::I32(value) => Value::I32(value.wrapping_abs()),
Value::I64(value) => Value::I64(value.wrapping_abs()), // f32/f64::abs() is not available in libcore
Value::F32(value) => Value::F32(if value < 0. { -value } else { value }),
Value::F64(value) => Value::F64(if value < 0. { -value } else { value }),
Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => self,
};
Ok(value)
}
/// Perform a negation operation. /// /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_neg` operation. pubfn neg(self, addr_mask: u64) -> Result<Value> { // wrapping_neg() can be used because DWARF specifies that the result is undefined // for negative minimal values. let value = matchself {
Value::Generic(value) => {
Value::Generic(sign_extend(value, addr_mask).wrapping_neg() as u64)
}
Value::I8(value) => Value::I8(value.wrapping_neg()),
Value::I16(value) => Value::I16(value.wrapping_neg()),
Value::I32(value) => Value::I32(value.wrapping_neg()),
Value::I64(value) => Value::I64(value.wrapping_neg()),
Value::F32(value) => Value::F32(-value),
Value::F64(value) => Value::F64(-value), // It's unclear if these should implicitly convert to a signed value. // For now, we don't support them.
Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => { return Err(Error::UnsupportedTypeOperation);
}
};
Ok(value)
}
/// Perform a division operation. /// /// This operation requires matching types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_div` operation. pubfn div(self, rhs: Value, addr_mask: u64) -> Result<Value> { match rhs {
Value::Generic(v2) if sign_extend(v2, addr_mask) == 0 => { return Err(Error::DivisionByZero);
}
Value::I8(0)
| Value::U8(0)
| Value::I16(0)
| Value::U16(0)
| Value::I32(0)
| Value::U32(0)
| Value::I64(0)
| Value::U64(0) => { return Err(Error::DivisionByZero);
}
_ => {}
} let value = match (self, rhs) {
(Value::Generic(v1), Value::Generic(v2)) => { // Signed division
Value::Generic(
sign_extend(v1, addr_mask).wrapping_div(sign_extend(v2, addr_mask)) as u64,
)
}
(Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_div(v2)),
(Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_div(v2)),
(Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_div(v2)),
(Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_div(v2)),
(Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_div(v2)),
(Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_div(v2)),
(Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_div(v2)),
(Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_div(v2)),
(Value::F32(v1), Value::F32(v2)) => Value::F32(v1 / v2),
(Value::F64(v1), Value::F64(v2)) => Value::F64(v1 / v2),
_ => return Err(Error::TypeMismatch),
};
Ok(value)
}
/// Perform a remainder operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as an unsigned value. /// /// This corresponds to the DWARF `DW_OP_mod` operation. pubfn rem(self, rhs: Value, addr_mask: u64) -> Result<Value> { match rhs {
Value::Generic(rhs) if (rhs & addr_mask) == 0 => { return Err(Error::DivisionByZero);
}
Value::I8(0)
| Value::U8(0)
| Value::I16(0)
| Value::U16(0)
| Value::I32(0)
| Value::U32(0)
| Value::I64(0)
| Value::U64(0) => { return Err(Error::DivisionByZero);
}
_ => {}
} let value = match (self, rhs) {
(Value::Generic(v1), Value::Generic(v2)) => { // Unsigned modulus
Value::Generic((v1 & addr_mask).wrapping_rem(v2 & addr_mask))
}
(Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_rem(v2)),
(Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_rem(v2)),
(Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_rem(v2)),
(Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_rem(v2)),
(Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_rem(v2)),
(Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_rem(v2)),
(Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_rem(v2)),
(Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_rem(v2)),
(Value::F32(_), Value::F32(_)) => return Err(Error::IntegralTypeRequired),
(Value::F64(_), Value::F64(_)) => return Err(Error::IntegralTypeRequired),
_ => return Err(Error::TypeMismatch),
};
Ok(value)
}
/// Perform a bitwise not operation. /// /// This operation requires matching integral types. /// /// This corresponds to the DWARF `DW_OP_not` operation. pubfn not(self, addr_mask: u64) -> Result<Value> { let value_type = self.value_type(); let v = self.to_u64(addr_mask)?;
Value::from_u64(value_type, !v)
}
/// Perform a bitwise and operation. /// /// This operation requires matching integral types. /// /// This corresponds to the DWARF `DW_OP_and` operation. pubfn and(self, rhs: Value, addr_mask: u64) -> Result<Value> { let value_type = self.value_type(); if value_type != rhs.value_type() { return Err(Error::TypeMismatch);
} let v1 = self.to_u64(addr_mask)?; let v2 = rhs.to_u64(addr_mask)?;
Value::from_u64(value_type, v1 & v2)
}
/// Perform a bitwise or operation. /// /// This operation requires matching integral types. /// /// This corresponds to the DWARF `DW_OP_or` operation. pubfn or(self, rhs: Value, addr_mask: u64) -> Result<Value> { let value_type = self.value_type(); if value_type != rhs.value_type() { return Err(Error::TypeMismatch);
} let v1 = self.to_u64(addr_mask)?; let v2 = rhs.to_u64(addr_mask)?;
Value::from_u64(value_type, v1 | v2)
}
/// Perform a bitwise exclusive-or operation. /// /// This operation requires matching integral types. /// /// This corresponds to the DWARF `DW_OP_xor` operation. pubfn xor(self, rhs: Value, addr_mask: u64) -> Result<Value> { let value_type = self.value_type(); if value_type != rhs.value_type() { return Err(Error::TypeMismatch);
} let v1 = self.to_u64(addr_mask)?; let v2 = rhs.to_u64(addr_mask)?;
Value::from_u64(value_type, v1 ^ v2)
}
/// Convert value to bit length suitable for a shift operation. /// /// If the value is negative then an error is returned. fn shift_length(self) -> Result<u64> { let value = matchself {
Value::Generic(value) => value,
Value::I8(value) if value >= 0 => value as u64,
Value::U8(value) => u64::from(value),
Value::I16(value) if value >= 0 => value as u64,
Value::U16(value) => u64::from(value),
Value::I32(value) if value >= 0 => value as u64,
Value::U32(value) => u64::from(value),
Value::I64(value) if value >= 0 => value as u64,
Value::U64(value) => value,
_ => return Err(Error::InvalidShiftExpression),
};
Ok(value)
}
/// Perform a shift left operation. /// /// This operation requires integral types. /// If the shift length exceeds the type size, then 0 is returned. /// If the shift length is negative then an error is returned. /// /// This corresponds to the DWARF `DW_OP_shl` operation. pubfn shl(self, rhs: Value, addr_mask: u64) -> Result<Value> { let v2 = rhs.shift_length()?; let value = matchself {
Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) { 0
} else {
(v1 & addr_mask) << v2
}),
Value::I8(v1) => Value::I8(if v2 >= 8 { 0 } else { v1 << v2 }),
Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 << v2 }),
Value::I16(v1) => Value::I16(if v2 >= 16 { 0 } else { v1 << v2 }),
Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 << v2 }),
Value::I32(v1) => Value::I32(if v2 >= 32 { 0 } else { v1 << v2 }),
Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 << v2 }),
Value::I64(v1) => Value::I64(if v2 >= 64 { 0 } else { v1 << v2 }),
Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 << v2 }),
_ => return Err(Error::IntegralTypeRequired),
};
Ok(value)
}
/// Perform a logical shift right operation. /// /// This operation requires an unsigned integral type for the value. /// If the value type is `Generic`, then it is interpreted as an unsigned value. /// /// This operation requires an integral type for the shift length. /// If the shift length exceeds the type size, then 0 is returned. /// If the shift length is negative then an error is returned. /// /// This corresponds to the DWARF `DW_OP_shr` operation. pubfn shr(self, rhs: Value, addr_mask: u64) -> Result<Value> { let v2 = rhs.shift_length()?; let value = matchself {
Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) { 0
} else {
(v1 & addr_mask) >> v2
}),
Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 >> v2 }),
Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 >> v2 }),
Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 >> v2 }),
Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 >> v2 }), // It's unclear if signed values should implicitly convert to an unsigned value. // For now, we don't support them.
Value::I8(_) | Value::I16(_) | Value::I32(_) | Value::I64(_) => { return Err(Error::UnsupportedTypeOperation);
}
_ => return Err(Error::IntegralTypeRequired),
};
Ok(value)
}
/// Perform an arithmetic shift right operation. /// /// This operation requires a signed integral type for the value. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This operation requires an integral type for the shift length. /// If the shift length exceeds the type size, then 0 is returned for positive values, /// and -1 is returned for negative values. /// If the shift length is negative then an error is returned. /// /// This corresponds to the DWARF `DW_OP_shra` operation. pubfn shra(self, rhs: Value, addr_mask: u64) -> Result<Value> { let v2 = rhs.shift_length()?; let value = matchself {
Value::Generic(v1) => { let v1 = sign_extend(v1, addr_mask); let value = if v2 >= u64::from(mask_bit_size(addr_mask)) { if v1 < 0 {
!0
} else { 0
}
} else {
(v1 >> v2) as u64
};
Value::Generic(value)
}
Value::I8(v1) => Value::I8(if v2 >= 8 { if v1 < 0 {
!0
} else { 0
}
} else {
v1 >> v2
}),
Value::I16(v1) => Value::I16(if v2 >= 16 { if v1 < 0 {
!0
} else { 0
}
} else {
v1 >> v2
}),
Value::I32(v1) => Value::I32(if v2 >= 32 { if v1 < 0 {
!0
} else { 0
}
} else {
v1 >> v2
}),
Value::I64(v1) => Value::I64(if v2 >= 64 { if v1 < 0 {
!0
} else { 0
}
} else {
v1 >> v2
}), // It's unclear if unsigned values should implicitly convert to a signed value. // For now, we don't support them.
Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => { return Err(Error::UnsupportedTypeOperation);
}
_ => return Err(Error::IntegralTypeRequired),
};
Ok(value)
}
/// Perform the `==` relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_eq` operation. pubfn eq(self, rhs: Value, addr_mask: u64) -> Result<Value> { let value = match (self, rhs) {
(Value::Generic(v1), Value::Generic(v2)) => {
sign_extend(v1, addr_mask) == sign_extend(v2, addr_mask)
}
(Value::I8(v1), Value::I8(v2)) => v1 == v2,
(Value::U8(v1), Value::U8(v2)) => v1 == v2,
(Value::I16(v1), Value::I16(v2)) => v1 == v2,
(Value::U16(v1), Value::U16(v2)) => v1 == v2,
(Value::I32(v1), Value::I32(v2)) => v1 == v2,
(Value::U32(v1), Value::U32(v2)) => v1 == v2,
(Value::I64(v1), Value::I64(v2)) => v1 == v2,
(Value::U64(v1), Value::U64(v2)) => v1 == v2,
(Value::F32(v1), Value::F32(v2)) => v1 == v2,
(Value::F64(v1), Value::F64(v2)) => v1 == v2,
_ => return Err(Error::TypeMismatch),
};
Ok(Value::Generic(value as u64))
}
/// Perform the `>=` relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_ge` operation. pubfn ge(self, rhs: Value, addr_mask: u64) -> Result<Value> { let value = match (self, rhs) {
(Value::Generic(v1), Value::Generic(v2)) => {
sign_extend(v1, addr_mask) >= sign_extend(v2, addr_mask)
}
(Value::I8(v1), Value::I8(v2)) => v1 >= v2,
(Value::U8(v1), Value::U8(v2)) => v1 >= v2,
(Value::I16(v1), Value::I16(v2)) => v1 >= v2,
(Value::U16(v1), Value::U16(v2)) => v1 >= v2,
(Value::I32(v1), Value::I32(v2)) => v1 >= v2,
(Value::U32(v1), Value::U32(v2)) => v1 >= v2,
(Value::I64(v1), Value::I64(v2)) => v1 >= v2,
(Value::U64(v1), Value::U64(v2)) => v1 >= v2,
(Value::F32(v1), Value::F32(v2)) => v1 >= v2,
(Value::F64(v1), Value::F64(v2)) => v1 >= v2,
_ => return Err(Error::TypeMismatch),
};
Ok(Value::Generic(value as u64))
}
/// Perform the `>` relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_gt` operation. pubfn gt(self, rhs: Value, addr_mask: u64) -> Result<Value> { let value = match (self, rhs) {
(Value::Generic(v1), Value::Generic(v2)) => {
sign_extend(v1, addr_mask) > sign_extend(v2, addr_mask)
}
(Value::I8(v1), Value::I8(v2)) => v1 > v2,
(Value::U8(v1), Value::U8(v2)) => v1 > v2,
(Value::I16(v1), Value::I16(v2)) => v1 > v2,
(Value::U16(v1), Value::U16(v2)) => v1 > v2,
(Value::I32(v1), Value::I32(v2)) => v1 > v2,
(Value::U32(v1), Value::U32(v2)) => v1 > v2,
(Value::I64(v1), Value::I64(v2)) => v1 > v2,
(Value::U64(v1), Value::U64(v2)) => v1 > v2,
(Value::F32(v1), Value::F32(v2)) => v1 > v2,
(Value::F64(v1), Value::F64(v2)) => v1 > v2,
_ => return Err(Error::TypeMismatch),
};
Ok(Value::Generic(value as u64))
}
/// Perform the `<= relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_le` operation. pubfn le(self, rhs: Value, addr_mask: u64) -> Result<Value> { let value = match (self, rhs) {
(Value::Generic(v1), Value::Generic(v2)) => {
sign_extend(v1, addr_mask) <= sign_extend(v2, addr_mask)
}
(Value::I8(v1), Value::I8(v2)) => v1 <= v2,
(Value::U8(v1), Value::U8(v2)) => v1 <= v2,
(Value::I16(v1), Value::I16(v2)) => v1 <= v2,
(Value::U16(v1), Value::U16(v2)) => v1 <= v2,
(Value::I32(v1), Value::I32(v2)) => v1 <= v2,
(Value::U32(v1), Value::U32(v2)) => v1 <= v2,
(Value::I64(v1), Value::I64(v2)) => v1 <= v2,
(Value::U64(v1), Value::U64(v2)) => v1 <= v2,
(Value::F32(v1), Value::F32(v2)) => v1 <= v2,
(Value::F64(v1), Value::F64(v2)) => v1 <= v2,
_ => return Err(Error::TypeMismatch),
};
Ok(Value::Generic(value as u64))
}
/// Perform the `< relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_lt` operation. pubfn lt(self, rhs: Value, addr_mask: u64) -> Result<Value> { let value = match (self, rhs) {
(Value::Generic(v1), Value::Generic(v2)) => {
sign_extend(v1, addr_mask) < sign_extend(v2, addr_mask)
}
(Value::I8(v1), Value::I8(v2)) => v1 < v2,
(Value::U8(v1), Value::U8(v2)) => v1 < v2,
(Value::I16(v1), Value::I16(v2)) => v1 < v2,
(Value::U16(v1), Value::U16(v2)) => v1 < v2,
(Value::I32(v1), Value::I32(v2)) => v1 < v2,
(Value::U32(v1), Value::U32(v2)) => v1 < v2,
(Value::I64(v1), Value::I64(v2)) => v1 < v2,
(Value::U64(v1), Value::U64(v2)) => v1 < v2,
(Value::F32(v1), Value::F32(v2)) => v1 < v2,
(Value::F64(v1), Value::F64(v2)) => v1 < v2,
_ => return Err(Error::TypeMismatch),
};
Ok(Value::Generic(value as u64))
}
/// Perform the `!= relational operation. /// /// This operation requires matching integral types. /// If the value type is `Generic`, then it is interpreted as a signed value. /// /// This corresponds to the DWARF `DW_OP_ne` operation. pubfn ne(self, rhs: Value, addr_mask: u64) -> Result<Value> { let value = match (self, rhs) {
(Value::Generic(v1), Value::Generic(v2)) => {
sign_extend(v1, addr_mask) != sign_extend(v2, addr_mask)
}
(Value::I8(v1), Value::I8(v2)) => v1 != v2,
(Value::U8(v1), Value::U8(v2)) => v1 != v2,
(Value::I16(v1), Value::I16(v2)) => v1 != v2,
(Value::U16(v1), Value::U16(v2)) => v1 != v2,
(Value::I32(v1), Value::I32(v2)) => v1 != v2,
(Value::U32(v1), Value::U32(v2)) => v1 != v2,
(Value::I64(v1), Value::I64(v2)) => v1 != v2,
(Value::U64(v1), Value::U64(v2)) => v1 != v2,
(Value::F32(v1), Value::F32(v2)) => v1 != v2,
(Value::F64(v1), Value::F64(v2)) => v1 != v2,
_ => return Err(Error::TypeMismatch),
};
Ok(Value::Generic(value as u64))
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.