#![allow(dead_code)]
use super::encode_sleb128;
use super::encode_uleb128;
use super::dwarf_types::dwarf_ops;
pub type DwarfExpr = DwarfExpression;
#[derive(Debug, Clone)]
pub struct DwarfExpression {
pub output: Vec<u8>,
stack: Vec<i64>,
pub address_size: u8,
pub is_location: bool,
}
impl DwarfExpression {
pub fn new(address_size: u8) -> Self {
Self {
output: Vec::new(),
stack: Vec::new(),
address_size,
is_location: true,
}
}
pub fn finish(self) -> Vec<u8> {
self.output
}
pub fn as_bytes(&self) -> &[u8] {
&self.output
}
pub fn len(&self) -> usize {
self.output.len()
}
pub fn is_empty(&self) -> bool {
self.output.is_empty()
}
pub fn clear(&mut self) {
self.output.clear();
self.stack.clear();
}
pub fn add_op(&mut self, op: u8) {
self.output.push(op);
}
pub fn add_op_u8(&mut self, op: u8, val: u8) {
self.output.push(op);
self.output.push(val);
}
pub fn add_op_u16(&mut self, op: u8, val: u16) {
self.output.push(op);
self.output.extend_from_slice(&val.to_le_bytes());
}
pub fn add_op_u32(&mut self, op: u8, val: u32) {
self.output.push(op);
self.output.extend_from_slice(&val.to_le_bytes());
}
pub fn add_op_u64(&mut self, op: u8, val: u64) {
self.output.push(op);
self.output.extend_from_slice(&val.to_le_bytes());
}
pub fn add_op_sleb(&mut self, op: u8, val: i64) {
self.output.push(op);
encode_sleb128(&mut self.output, val);
}
pub fn add_op_uleb(&mut self, op: u8, val: u64) {
self.output.push(op);
encode_uleb128(&mut self.output, val);
}
pub fn addr(&mut self, val: u64) {
self.output.push(dwarf_ops::DW_OP_addr as u8);
match self.address_size {
4 => self.output.extend_from_slice(&(val as u32).to_le_bytes()),
_ => self.output.extend_from_slice(&val.to_le_bytes()),
}
}
pub fn deref(&mut self) {
self.output.push(dwarf_ops::DW_OP_deref as u8);
}
pub fn deref_size(&mut self, size: u8) {
self.output.push(dwarf_ops::DW_OP_deref_size as u8);
self.output.push(size);
}
pub fn push_object_address(&mut self) {
self.output.push(dwarf_ops::DW_OP_push_object_address as u8);
}
pub fn form_tls_address(&mut self) {
self.output.push(dwarf_ops::DW_OP_form_tls_address as u8);
}
pub fn call_frame_cfa(&mut self) {
self.output.push(dwarf_ops::DW_OP_call_frame_cfa as u8);
}
pub fn const_u8(&mut self, val: u8) {
self.add_op_u8(dwarf_ops::DW_OP_const1u as u8, val);
}
pub fn const_u16(&mut self, val: u16) {
self.add_op_u16(dwarf_ops::DW_OP_const2u as u8, val);
}
pub fn const_u32(&mut self, val: u32) {
self.add_op_u32(dwarf_ops::DW_OP_const4u as u8, val);
}
pub fn const_u64(&mut self, val: u64) {
self.add_op_u64(dwarf_ops::DW_OP_const8u as u8, val);
}
pub fn const_i8(&mut self, val: i8) {
self.output.push(dwarf_ops::DW_OP_const1s as u8);
self.output.push(val as u8);
}
pub fn const_i16(&mut self, val: i16) {
self.output.push(dwarf_ops::DW_OP_const2s as u8);
self.output.extend_from_slice(&val.to_le_bytes());
}
pub fn const_i32(&mut self, val: i32) {
self.output.push(dwarf_ops::DW_OP_const4s as u8);
self.output.extend_from_slice(&val.to_le_bytes());
}
pub fn const_i64(&mut self, val: i64) {
self.output.push(dwarf_ops::DW_OP_const8s as u8);
self.output.extend_from_slice(&val.to_le_bytes());
}
pub fn const_uleb(&mut self, val: u64) {
self.add_op_uleb(dwarf_ops::DW_OP_constu as u8, val);
}
pub fn const_sleb(&mut self, val: i64) {
self.add_op_sleb(dwarf_ops::DW_OP_consts as u8, val);
}
pub fn lit(&mut self, n: u8) {
assert!(n <= 31, "DW_OP_lit only supports values 0–31");
self.output.push(dwarf_ops::DW_OP_lit0 as u8 + n);
}
pub fn reg(&mut self, reg: u16) {
if reg <= 31 {
self.output.push(dwarf_ops::DW_OP_reg0 as u8 + reg as u8);
} else {
self.add_op_uleb(dwarf_ops::DW_OP_regx as u8, reg as u64);
}
}
pub fn breg(&mut self, reg: u16, offset: i64) {
if reg <= 31 {
self.output.push(dwarf_ops::DW_OP_breg0 as u8 + reg as u8);
} else {
self.output.push(dwarf_ops::DW_OP_bregx as u8);
encode_uleb128(&mut self.output, reg as u64);
}
encode_sleb128(&mut self.output, offset);
}
pub fn fbreg(&mut self, offset: i64) {
self.add_op_sleb(dwarf_ops::DW_OP_fbreg as u8, offset);
}
pub fn plus(&mut self) {
self.output.push(dwarf_ops::DW_OP_plus as u8);
}
pub fn minus(&mut self) {
self.output.push(dwarf_ops::DW_OP_minus as u8);
}
pub fn mul(&mut self) {
self.output.push(dwarf_ops::DW_OP_mul as u8);
}
pub fn div(&mut self) {
self.output.push(dwarf_ops::DW_OP_div as u8);
}
pub fn mod_(&mut self) {
self.output.push(dwarf_ops::DW_OP_mod as u8);
}
pub fn abs(&mut self) {
self.output.push(dwarf_ops::DW_OP_abs as u8);
}
pub fn neg(&mut self) {
self.output.push(dwarf_ops::DW_OP_neg as u8);
}
pub fn not(&mut self) {
self.output.push(dwarf_ops::DW_OP_not as u8);
}
pub fn and(&mut self) {
self.output.push(dwarf_ops::DW_OP_and as u8);
}
pub fn or(&mut self) {
self.output.push(dwarf_ops::DW_OP_or as u8);
}
pub fn xor(&mut self) {
self.output.push(dwarf_ops::DW_OP_xor as u8);
}
pub fn shl(&mut self) {
self.output.push(dwarf_ops::DW_OP_shl as u8);
}
pub fn shr(&mut self) {
self.output.push(dwarf_ops::DW_OP_shr as u8);
}
pub fn shra(&mut self) {
self.output.push(dwarf_ops::DW_OP_shra as u8);
}
pub fn eq(&mut self) {
self.output.push(dwarf_ops::DW_OP_eq as u8);
}
pub fn ne(&mut self) {
self.output.push(dwarf_ops::DW_OP_ne as u8);
}
pub fn lt(&mut self) {
self.output.push(dwarf_ops::DW_OP_lt as u8);
}
pub fn le(&mut self) {
self.output.push(dwarf_ops::DW_OP_le as u8);
}
pub fn gt(&mut self) {
self.output.push(dwarf_ops::DW_OP_gt as u8);
}
pub fn ge(&mut self) {
self.output.push(dwarf_ops::DW_OP_ge as u8);
}
pub fn dup(&mut self) {
self.output.push(dwarf_ops::DW_OP_dup as u8);
}
pub fn drop(&mut self) {
self.output.push(dwarf_ops::DW_OP_drop as u8);
}
pub fn swap(&mut self) {
self.output.push(dwarf_ops::DW_OP_swap as u8);
}
pub fn over(&mut self) {
self.output.push(dwarf_ops::DW_OP_over as u8);
}
pub fn pick(&mut self, n: u8) {
self.add_op_u8(dwarf_ops::DW_OP_pick as u8, n);
}
pub fn rot(&mut self) {
self.output.push(dwarf_ops::DW_OP_rot as u8);
}
pub fn skip(&mut self, offset: i16) {
self.add_op_u16(dwarf_ops::DW_OP_skip as u8, offset as u16);
}
pub fn bra(&mut self, offset: i16) {
self.add_op_u16(dwarf_ops::DW_OP_bra as u8, offset as u16);
}
pub fn nop(&mut self) {
self.output.push(dwarf_ops::DW_OP_nop as u8);
}
pub fn piece(&mut self, size: u64) {
self.add_op_uleb(dwarf_ops::DW_OP_piece as u8, size);
}
pub fn bit_piece(&mut self, size: u64, offset: u64) {
self.output.push(dwarf_ops::DW_OP_bit_piece as u8);
encode_uleb128(&mut self.output, size);
encode_uleb128(&mut self.output, offset);
}
pub fn stack_value(&mut self) {
self.output.push(dwarf_ops::DW_OP_stack_value as u8);
self.is_location = false;
}
pub fn entry_value(&mut self, expr: &[u8]) {
self.output.push(dwarf_ops::DW_OP_entry_value as u8);
encode_uleb128(&mut self.output, expr.len() as u64);
self.output.extend_from_slice(expr);
}
pub fn implicit_value(&mut self, value: &[u8]) {
self.output.push(dwarf_ops::DW_OP_implicit_value as u8);
encode_uleb128(&mut self.output, value.len() as u64);
self.output.extend_from_slice(value);
}
pub fn convert(&mut self, dwarf_type: u64) {
self.output.push(dwarf_ops::DW_OP_convert as u8);
encode_uleb128(&mut self.output, dwarf_type);
}
pub fn reinterpret(&mut self, dwarf_type: u64) {
self.output.push(dwarf_ops::DW_OP_reinterpret as u8);
encode_uleb128(&mut self.output, dwarf_type);
}
pub fn plus_uconst(&mut self, val: u64) {
self.add_op_uleb(dwarf_ops::DW_OP_plus_uconst as u8, val);
}
pub fn addrx(&mut self, index: u64) {
self.add_op_uleb(dwarf_ops::DW_OP_addrx as u8, index);
}
pub fn constx(&mut self, index: u64) {
self.add_op_uleb(dwarf_ops::DW_OP_constx as u8, index);
}
pub fn evaluate_const(&self) -> Option<i64> {
if self.output.is_empty() {
return None;
}
let mut stack: Vec<i64> = Vec::new();
let mut pos = 0;
let data = &self.output;
while pos < data.len() {
let op = data[pos];
pos += 1;
match op {
o if o >= dwarf_ops::DW_OP_lit0 && o <= dwarf_ops::DW_OP_lit0 + 31 => {
stack.push((o - dwarf_ops::DW_OP_lit0) as i64);
}
dwarf_ops::DW_OP_const1u => {
if pos >= data.len() {
return None;
}
stack.push(data[pos] as i64);
pos += 1;
}
dwarf_ops::DW_OP_const2u => {
if pos + 2 > data.len() {
return None;
}
let v = u16::from_le_bytes(data[pos..pos + 2].try_into().ok()?);
stack.push(v as i64);
pos += 2;
}
dwarf_ops::DW_OP_const4u => {
if pos + 4 > data.len() {
return None;
}
let v = u32::from_le_bytes(data[pos..pos + 4].try_into().ok()?);
stack.push(v as i64);
pos += 4;
}
dwarf_ops::DW_OP_const8u => {
if pos + 8 > data.len() {
return None;
}
let v = u64::from_le_bytes(data[pos..pos + 8].try_into().ok()?);
stack.push(v as i64);
pos += 8;
}
dwarf_ops::DW_OP_const1s => {
if pos >= data.len() {
return None;
}
stack.push(data[pos] as i8 as i64);
pos += 1;
}
dwarf_ops::DW_OP_const2s => {
if pos + 2 > data.len() {
return None;
}
let v = i16::from_le_bytes(data[pos..pos + 2].try_into().ok()?);
stack.push(v as i64);
pos += 2;
}
dwarf_ops::DW_OP_const4s => {
if pos + 4 > data.len() {
return None;
}
let v = i32::from_le_bytes(data[pos..pos + 4].try_into().ok()?);
stack.push(v as i64);
pos += 4;
}
dwarf_ops::DW_OP_const8s => {
if pos + 8 > data.len() {
return None;
}
let v = i64::from_le_bytes(data[pos..pos + 8].try_into().ok()?);
stack.push(v);
pos += 8;
}
dwarf_ops::DW_OP_constu => {
let (v, advance) = try_decode_uleb128(&data[pos..])?;
stack.push(v as i64);
pos += advance;
}
dwarf_ops::DW_OP_consts => {
let (v, advance) = try_decode_sleb128(&data[pos..])?;
stack.push(v);
pos += advance;
}
dwarf_ops::DW_OP_plus => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(a.wrapping_add(b));
}
dwarf_ops::DW_OP_minus => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(a.wrapping_sub(b));
}
dwarf_ops::DW_OP_mul => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(a.wrapping_mul(b));
}
dwarf_ops::DW_OP_div => {
let b = stack.pop()?;
let a = stack.pop()?;
if b == 0 {
return None;
}
stack.push(a.wrapping_div(b));
}
dwarf_ops::DW_OP_mod => {
let b = stack.pop()?;
let a = stack.pop()?;
if b == 0 {
return None;
}
stack.push(a.wrapping_rem(b));
}
dwarf_ops::DW_OP_neg => {
let a = stack.pop()?;
stack.push(-a);
}
dwarf_ops::DW_OP_abs => {
let a = stack.pop()?;
stack.push(a.abs());
}
dwarf_ops::DW_OP_not => {
let a = stack.pop()?;
stack.push(!a);
}
dwarf_ops::DW_OP_and => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(a & b);
}
dwarf_ops::DW_OP_or => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(a | b);
}
dwarf_ops::DW_OP_xor => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(a ^ b);
}
dwarf_ops::DW_OP_shl => {
let a = stack.pop()?;
stack.push(a << 1);
}
dwarf_ops::DW_OP_shr => {
let a = stack.pop()?;
stack.push((a as u64 >> 1) as i64);
}
dwarf_ops::DW_OP_shra => {
let a = stack.pop()?;
stack.push(a >> 1);
}
dwarf_ops::DW_OP_eq => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(if a == b { 1 } else { 0 });
}
dwarf_ops::DW_OP_ne => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(if a != b { 1 } else { 0 });
}
dwarf_ops::DW_OP_lt => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(if a < b { 1 } else { 0 });
}
dwarf_ops::DW_OP_le => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(if a <= b { 1 } else { 0 });
}
dwarf_ops::DW_OP_gt => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(if a > b { 1 } else { 0 });
}
dwarf_ops::DW_OP_ge => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(if a >= b { 1 } else { 0 });
}
dwarf_ops::DW_OP_dup => {
let a = *stack.last()?;
stack.push(a);
}
dwarf_ops::DW_OP_drop => {
stack.pop()?;
}
dwarf_ops::DW_OP_swap => {
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(b);
stack.push(a);
}
dwarf_ops::DW_OP_over => {
if stack.len() < 2 {
return None;
}
let a = stack[stack.len() - 2];
stack.push(a);
}
dwarf_ops::DW_OP_pick => {
if pos >= data.len() {
return None;
}
let n = data[pos] as usize;
pos += 1;
if stack.len() <= n {
return None;
}
let v = stack[stack.len() - 1 - n];
stack.push(v);
}
dwarf_ops::DW_OP_rot => {
let c = stack.pop()?;
let b = stack.pop()?;
let a = stack.pop()?;
stack.push(b);
stack.push(c);
stack.push(a);
}
dwarf_ops::DW_OP_nop => {
}
_ => return None,
}
}
if stack.len() == 1 {
Some(stack[0])
} else {
None
}
}
pub fn is_register_location(&self) -> Option<u16> {
if self.output.is_empty() {
return None;
}
let op = self.output[0];
if op >= dwarf_ops::DW_OP_reg0 && op <= dwarf_ops::DW_OP_reg0 + 31 {
return Some((op - dwarf_ops::DW_OP_reg0) as u16);
}
if op == dwarf_ops::DW_OP_regx {
if self.output.len() < 2 {
return None;
}
let (reg, _) = try_decode_uleb128(&self.output[1..])?;
return Some(reg as u16);
}
None
}
pub fn is_frame_relative(&self) -> Option<(i64, u64)> {
if self.output.is_empty() {
return None;
}
if self.output[0] != dwarf_ops::DW_OP_fbreg {
return None;
}
let (offset, advance) = try_decode_sleb128(&self.output[1..])?;
let after_fbreg = 1 + advance;
if after_fbreg < self.output.len() {
let next_op = self.output[after_fbreg];
if next_op == dwarf_ops::DW_OP_deref {
return Some((offset, 0)); }
if next_op == dwarf_ops::DW_OP_deref_size && after_fbreg + 1 < self.output.len() {
let size = self.output[after_fbreg + 1] as u64;
return Some((offset, size));
}
}
Some((offset, 0))
}
}
fn try_decode_uleb128(data: &[u8]) -> Option<(u64, usize)> {
let mut result: u64 = 0;
let mut shift = 0;
for (i, &byte) in data.iter().enumerate() {
if i >= 10 {
return None;
}
result |= ((byte & 0x7F) as u64) << shift;
if byte & 0x80 == 0 {
return Some((result, i + 1));
}
shift += 7;
}
None
}
fn try_decode_sleb128(data: &[u8]) -> Option<(i64, usize)> {
let mut result: i64 = 0;
let mut shift = 0;
for (i, &byte) in data.iter().enumerate() {
if i >= 10 {
return None;
}
result |= ((byte & 0x7F) as i64) << shift;
shift += 7;
if byte & 0x80 == 0 {
if shift < 64 && (byte & 0x40) != 0 {
result |= (-1i64) << shift;
}
return Some((result, i + 1));
}
}
None
}
pub fn make_reg_expr(reg: u16) -> Vec<u8> {
let mut expr = DwarfExpression::new(8);
expr.reg(reg);
expr.finish()
}
pub fn make_fbreg_expr(offset: i64) -> Vec<u8> {
let mut expr = DwarfExpression::new(8);
expr.fbreg(offset);
expr.finish()
}
pub fn make_fbreg_deref_expr(offset: i64) -> Vec<u8> {
let mut expr = DwarfExpression::new(8);
expr.fbreg(offset);
expr.deref();
expr.finish()
}
pub fn make_const_expr(value: i64) -> Vec<u8> {
let mut expr = DwarfExpression::new(8);
if value >= 0 && value <= 31 {
expr.lit(value as u8);
} else if value >= 0 && value <= 255 {
expr.const_u8(value as u8);
} else if value >= -128 && value <= 127 {
expr.const_i8(value as i8);
} else if value >= 0 && value <= 65535 {
expr.const_u16(value as u16);
} else {
expr.const_sleb(value);
}
expr.stack_value();
expr.finish()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_expression() {
let expr = DwarfExpression::new(8);
assert!(expr.output.is_empty());
assert_eq!(expr.address_size, 8);
assert!(expr.is_location);
assert!(expr.is_empty());
assert_eq!(expr.len(), 0);
}
#[test]
fn test_new_expression_32bit() {
let expr = DwarfExpression::new(4);
assert_eq!(expr.address_size, 4);
}
#[test]
fn test_finish_and_clear() {
let mut expr = DwarfExpression::new(8);
expr.nop();
assert_eq!(expr.len(), 1);
let bytes = expr.clone().finish();
assert_eq!(bytes.len(), 1);
expr.clear();
assert!(expr.is_empty());
}
#[test]
fn test_add_op() {
let mut expr = DwarfExpression::new(8);
expr.add_op(0x50);
assert_eq!(expr.output, vec![0x50]);
}
#[test]
fn test_add_op_u8() {
let mut expr = DwarfExpression::new(8);
expr.add_op_u8(0x08, 42);
assert_eq!(expr.output, vec![0x08, 42]);
}
#[test]
fn test_add_op_u16() {
let mut expr = DwarfExpression::new(8);
expr.add_op_u16(0x02, 0x1234);
assert_eq!(expr.output.len(), 3);
assert_eq!(expr.output[0], 0x02);
}
#[test]
fn test_add_op_u32() {
let mut expr = DwarfExpression::new(8);
expr.add_op_u32(0x03, 0xDEADBEEF);
assert_eq!(expr.output.len(), 5);
assert_eq!(expr.output[0], 0x03);
}
#[test]
fn test_add_op_u64() {
let mut expr = DwarfExpression::new(8);
expr.add_op_u64(0x04, 0x1234567890ABCDEF);
assert_eq!(expr.output.len(), 9);
assert_eq!(expr.output[0], 0x04);
}
#[test]
fn test_addr_64bit() {
let mut expr = DwarfExpression::new(8);
expr.addr(0x400000);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_addr as u8);
assert_eq!(expr.output.len(), 9); let addr = u64::from_le_bytes(expr.output[1..9].try_into().unwrap());
assert_eq!(addr, 0x400000);
}
#[test]
fn test_addr_32bit() {
let mut expr = DwarfExpression::new(4);
expr.addr(0x4000);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_addr as u8);
assert_eq!(expr.output.len(), 5); }
#[test]
fn test_deref() {
let mut expr = DwarfExpression::new(8);
expr.deref();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_deref as u8);
}
#[test]
fn test_deref_size() {
let mut expr = DwarfExpression::new(8);
expr.deref_size(8);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_deref_size as u8);
assert_eq!(expr.output[1], 8);
}
#[test]
fn test_push_object_address() {
let mut expr = DwarfExpression::new(8);
expr.push_object_address();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_push_object_address as u8);
}
#[test]
fn test_form_tls_address() {
let mut expr = DwarfExpression::new(8);
expr.form_tls_address();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_form_tls_address as u8);
}
#[test]
fn test_call_frame_cfa() {
let mut expr = DwarfExpression::new(8);
expr.call_frame_cfa();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_call_frame_cfa as u8);
}
#[test]
fn test_const_u8() {
let mut expr = DwarfExpression::new(8);
expr.const_u8(42);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_const1u as u8);
assert_eq!(expr.output[1], 42);
}
#[test]
fn test_const_u16() {
let mut expr = DwarfExpression::new(8);
expr.const_u16(0x1234);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_const2u as u8);
}
#[test]
fn test_const_u32() {
let mut expr = DwarfExpression::new(8);
expr.const_u32(0xDEADBEEF);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_const4u as u8);
}
#[test]
fn test_const_u64() {
let mut expr = DwarfExpression::new(8);
expr.const_u64(0xFFFFFFFF);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_const8u as u8);
}
#[test]
fn test_const_i8() {
let mut expr = DwarfExpression::new(8);
expr.const_i8(-42);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_const1s as u8);
assert_eq!(expr.output[1] as i8, -42);
}
#[test]
fn test_const_uleb() {
let mut expr = DwarfExpression::new(8);
expr.const_uleb(127);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_constu as u8);
assert_eq!(expr.output[1], 127);
}
#[test]
fn test_const_sleb() {
let mut expr = DwarfExpression::new(8);
expr.const_sleb(-1);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_consts as u8);
assert_eq!(expr.output[1], 0x7F);
}
#[test]
fn test_lit() {
for n in 0..=31 {
let mut expr = DwarfExpression::new(8);
expr.lit(n);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_lit0 as u8 + n);
}
}
#[test]
#[should_panic]
fn test_lit_too_large() {
let mut expr = DwarfExpression::new(8);
expr.lit(32);
}
#[test]
fn test_reg_compact() {
let mut expr = DwarfExpression::new(8);
expr.reg(5);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_reg0 as u8 + 5);
}
#[test]
fn test_reg_extended() {
let mut expr = DwarfExpression::new(8);
expr.reg(32);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_regx as u8);
}
#[test]
fn test_breg_compact() {
let mut expr = DwarfExpression::new(8);
expr.breg(7, -8);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_breg0 as u8 + 7);
}
#[test]
fn test_breg_extended() {
let mut expr = DwarfExpression::new(8);
expr.breg(64, 0);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_bregx as u8);
}
#[test]
fn test_fbreg() {
let mut expr = DwarfExpression::new(8);
expr.fbreg(-16);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_fbreg as u8);
}
#[test]
fn test_plus() {
let mut expr = DwarfExpression::new(8);
expr.plus();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_plus as u8);
}
#[test]
fn test_minus() {
let mut expr = DwarfExpression::new(8);
expr.minus();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_minus as u8);
}
#[test]
fn test_mul() {
let mut expr = DwarfExpression::new(8);
expr.mul();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_mul as u8);
}
#[test]
fn test_div() {
let mut expr = DwarfExpression::new(8);
expr.div();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_div as u8);
}
#[test]
fn test_mod() {
let mut expr = DwarfExpression::new(8);
expr.mod_();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_mod as u8);
}
#[test]
fn test_neg_abs_not() {
let mut expr = DwarfExpression::new(8);
expr.neg();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_neg as u8);
let mut expr = DwarfExpression::new(8);
expr.abs();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_abs as u8);
let mut expr = DwarfExpression::new(8);
expr.not();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_not as u8);
}
#[test]
fn test_bitwise() {
let mut expr = DwarfExpression::new(8);
expr.and();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_and as u8);
let mut expr = DwarfExpression::new(8);
expr.or();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_or as u8);
let mut expr = DwarfExpression::new(8);
expr.xor();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_xor as u8);
}
#[test]
fn test_shifts() {
let mut expr = DwarfExpression::new(8);
expr.shl();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_shl as u8);
let mut expr = DwarfExpression::new(8);
expr.shr();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_shr as u8);
let mut expr = DwarfExpression::new(8);
expr.shra();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_shra as u8);
}
#[test]
fn test_comparisons() {
let mut expr = DwarfExpression::new(8);
expr.eq();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_eq as u8);
let mut expr = DwarfExpression::new(8);
expr.ne();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_ne as u8);
let mut expr = DwarfExpression::new(8);
expr.lt();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_lt as u8);
let mut expr = DwarfExpression::new(8);
expr.le();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_le as u8);
let mut expr = DwarfExpression::new(8);
expr.gt();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_gt as u8);
let mut expr = DwarfExpression::new(8);
expr.ge();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_ge as u8);
}
#[test]
fn test_stack_ops() {
let mut expr = DwarfExpression::new(8);
expr.dup();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_dup as u8);
let mut expr = DwarfExpression::new(8);
expr.drop();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_drop as u8);
let mut expr = DwarfExpression::new(8);
expr.swap();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_swap as u8);
let mut expr = DwarfExpression::new(8);
expr.over();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_over as u8);
let mut expr = DwarfExpression::new(8);
expr.pick(3);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_pick as u8);
assert_eq!(expr.output[1], 3);
let mut expr = DwarfExpression::new(8);
expr.rot();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_rot as u8);
}
#[test]
fn test_skip() {
let mut expr = DwarfExpression::new(8);
expr.skip(10);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_skip as u8);
}
#[test]
fn test_bra() {
let mut expr = DwarfExpression::new(8);
expr.bra(-5);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_bra as u8);
}
#[test]
fn test_nop() {
let mut expr = DwarfExpression::new(8);
expr.nop();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_nop as u8);
}
#[test]
fn test_piece() {
let mut expr = DwarfExpression::new(8);
expr.piece(8);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_piece as u8);
}
#[test]
fn test_bit_piece() {
let mut expr = DwarfExpression::new(8);
expr.bit_piece(32, 0);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_bit_piece as u8);
}
#[test]
fn test_stack_value() {
let mut expr = DwarfExpression::new(8);
expr.stack_value();
assert_eq!(expr.output[0], dwarf_ops::DW_OP_stack_value as u8);
assert!(!expr.is_location);
}
#[test]
fn test_entry_value() {
let mut expr = DwarfExpression::new(8);
expr.entry_value(&[0x50, 0x30]); assert_eq!(expr.output[0], dwarf_ops::DW_OP_entry_value as u8);
}
#[test]
fn test_implicit_value() {
let mut expr = DwarfExpression::new(8);
expr.implicit_value(&[0x42, 0x00, 0x00, 0x00]);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_implicit_value as u8);
}
#[test]
fn test_convert() {
let mut expr = DwarfExpression::new(8);
expr.convert(0x100);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_convert as u8);
}
#[test]
fn test_reinterpret() {
let mut expr = DwarfExpression::new(8);
expr.reinterpret(0x200);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_reinterpret as u8);
}
#[test]
fn test_plus_uconst() {
let mut expr = DwarfExpression::new(8);
expr.plus_uconst(16);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_plus_uconst as u8);
}
#[test]
fn test_addrx() {
let mut expr = DwarfExpression::new(8);
expr.addrx(3);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_addrx as u8);
}
#[test]
fn test_constx() {
let mut expr = DwarfExpression::new(8);
expr.constx(1);
assert_eq!(expr.output[0], dwarf_ops::DW_OP_constx as u8);
}
#[test]
fn test_evaluate_const_lit() {
let mut expr = DwarfExpression::new(8);
expr.lit(5);
let result = expr.evaluate_const();
assert_eq!(result, Some(5));
}
#[test]
fn test_evaluate_const_constu() {
let mut expr = DwarfExpression::new(8);
expr.const_uleb(100);
let result = expr.evaluate_const();
assert_eq!(result, Some(100));
}
#[test]
fn test_evaluate_const_plus() {
let mut expr = DwarfExpression::new(8);
expr.lit(3);
expr.lit(4);
expr.plus();
let result = expr.evaluate_const();
assert_eq!(result, Some(7));
}
#[test]
fn test_evaluate_const_complex() {
let mut expr = DwarfExpression::new(8);
expr.lit(10); expr.lit(3); expr.mul(); expr.lit(5); expr.plus(); let result = expr.evaluate_const();
assert_eq!(result, Some(35));
}
#[test]
fn test_evaluate_const_stack_ops() {
let mut expr = DwarfExpression::new(8);
expr.lit(10);
expr.dup(); expr.plus(); let result = expr.evaluate_const();
assert_eq!(result, Some(20));
}
#[test]
fn test_evaluate_const_drop() {
let mut expr = DwarfExpression::new(8);
expr.lit(1);
expr.lit(2);
expr.drop(); let result = expr.evaluate_const();
assert_eq!(result, Some(1));
}
#[test]
fn test_evaluate_const_comparison_eq() {
let mut expr = DwarfExpression::new(8);
expr.lit(5);
expr.lit(5);
expr.eq();
let result = expr.evaluate_const();
assert_eq!(result, Some(1));
}
#[test]
fn test_evaluate_const_comparison_lt() {
let mut expr = DwarfExpression::new(8);
expr.lit(3);
expr.lit(7);
expr.lt();
let result = expr.evaluate_const();
assert_eq!(result, Some(1));
}
#[test]
fn test_evaluate_const_neg() {
let mut expr = DwarfExpression::new(8);
expr.const_u8(42);
expr.neg();
let result = expr.evaluate_const();
assert_eq!(result, Some(-42));
}
#[test]
fn test_evaluate_const_abs() {
let mut expr = DwarfExpression::new(8);
expr.const_sleb(-15);
expr.abs();
let result = expr.evaluate_const();
assert_eq!(result, Some(15));
}
#[test]
fn test_evaluate_const_empty() {
let expr = DwarfExpression::new(8);
assert_eq!(expr.evaluate_const(), None);
}
#[test]
fn test_evaluate_const_unsupported_op() {
let mut expr = DwarfExpression::new(8);
expr.reg(0); let result = expr.evaluate_const();
assert_eq!(result, None);
}
#[test]
fn test_evaluate_const_div_by_zero() {
let mut expr = DwarfExpression::new(8);
expr.lit(10);
expr.lit(0);
expr.div();
let result = expr.evaluate_const();
assert_eq!(result, None);
}
#[test]
fn test_is_register_location_compact() {
let expr_bytes = make_reg_expr(5);
let expr = DwarfExpression {
output: expr_bytes,
stack: Vec::new(),
address_size: 8,
is_location: true,
};
assert_eq!(expr.is_register_location(), Some(5));
}
#[test]
fn test_is_register_location_extended() {
let expr_bytes = make_reg_expr(32);
let expr = DwarfExpression {
output: expr_bytes,
stack: Vec::new(),
address_size: 8,
is_location: true,
};
assert_eq!(expr.is_register_location(), Some(32));
}
#[test]
fn test_is_register_location_none() {
let mut expr = DwarfExpression::new(8);
expr.fbreg(-8);
assert_eq!(expr.is_register_location(), None);
}
#[test]
fn test_is_register_location_empty() {
let expr = DwarfExpression::new(8);
assert_eq!(expr.is_register_location(), None);
}
#[test]
fn test_is_frame_relative_fbreg_only() {
let expr_bytes = make_fbreg_expr(-8);
let expr = DwarfExpression {
output: expr_bytes,
stack: Vec::new(),
address_size: 8,
is_location: true,
};
let result = expr.is_frame_relative();
assert!(result.is_some());
assert_eq!(result.unwrap().0, -8);
}
#[test]
fn test_is_frame_relative_fbreg_deref() {
let expr_bytes = make_fbreg_deref_expr(-16);
let expr = DwarfExpression {
output: expr_bytes,
stack: Vec::new(),
address_size: 8,
is_location: true,
};
let result = expr.is_frame_relative();
assert!(result.is_some());
assert_eq!(result.unwrap().0, -16);
}
#[test]
fn test_is_frame_relative_none() {
let mut expr = DwarfExpression::new(8);
expr.reg(3);
assert_eq!(expr.is_frame_relative(), None);
}
#[test]
fn test_make_reg_expr_compact() {
let bytes = make_reg_expr(10);
assert_eq!(bytes.len(), 1);
assert_eq!(bytes[0], dwarf_ops::DW_OP_reg0 as u8 + 10);
}
#[test]
fn test_make_reg_expr_extended() {
let bytes = make_reg_expr(32);
assert!(bytes.len() > 1);
assert_eq!(bytes[0], dwarf_ops::DW_OP_regx as u8);
}
#[test]
fn test_make_fbreg_expr() {
let bytes = make_fbreg_expr(-8);
assert_eq!(bytes[0], dwarf_ops::DW_OP_fbreg as u8);
}
#[test]
fn test_make_fbreg_deref_expr() {
let bytes = make_fbreg_deref_expr(-16);
assert_eq!(bytes[0], dwarf_ops::DW_OP_fbreg as u8);
assert_eq!(bytes.last(), Some(&(dwarf_ops::DW_OP_deref as u8)));
}
#[test]
fn test_make_const_expr_lit() {
let bytes = make_const_expr(5);
assert_eq!(bytes[0], dwarf_ops::DW_OP_lit0 as u8 + 5);
assert_eq!(bytes.last(), Some(&(dwarf_ops::DW_OP_stack_value as u8)));
}
#[test]
fn test_make_const_expr_large() {
let bytes = make_const_expr(1000);
assert_eq!(bytes[0], dwarf_ops::DW_OP_const2u as u8);
assert_eq!(bytes.last(), Some(&(dwarf_ops::DW_OP_stack_value as u8)));
}
#[test]
fn test_try_decode_uleb128_small() {
let data = vec![42u8];
let (val, len) = try_decode_uleb128(&data).unwrap();
assert_eq!(val, 42);
assert_eq!(len, 1);
}
#[test]
fn test_try_decode_uleb128_multi() {
let data = vec![0xE5, 0x8E, 0x26];
let (val, len) = try_decode_uleb128(&data).unwrap();
assert_eq!(val, 624485);
assert_eq!(len, 3);
}
#[test]
fn test_try_decode_uleb128_zero() {
let data = vec![0u8];
let (val, _) = try_decode_uleb128(&data).unwrap();
assert_eq!(val, 0);
}
#[test]
fn test_try_decode_sleb128_positive() {
let data = vec![42u8];
let (val, _) = try_decode_sleb128(&data).unwrap();
assert_eq!(val, 42);
}
#[test]
fn test_try_decode_sleb128_negative() {
let data = vec![0x7Fu8];
let (val, _) = try_decode_sleb128(&data).unwrap();
assert_eq!(val, -1);
}
}