androscalpel/androscalpel_serializer/src/debug.rs

133 lines
3.7 KiB
Rust

//! Debug structs
use crate as androscalpel_serializer;
use crate::{ReadSeek, Result, Serializable, SerializableUntil, Sleb128, Uleb128, Uleb128p1};
use std::io::Write;
/// <https://source.android.com/docs/core/runtime/dex-format#debug-info-item>
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DebugInfoItem {
pub line_start: Uleb128,
//pub parameters_size: Uleb128,
pub parameter_names: Vec<Uleb128p1>,
/// List of opcode. Notice that the trailling [`DbgBytecode::EndSequence`]
/// is not stored in this vec.
pub bytecode: Vec<DbgBytecode>,
}
#[derive(Serializable, Debug, PartialEq, Eq, Copy, Clone)]
#[prefix_type(u8)]
pub enum DbgBytecode {
#[prefix(0x00)]
EndSequence,
#[prefix(0x01)]
AdvancePC { addr_diff: Uleb128 },
#[prefix(0x02)]
AdvanceLine { line_diff: Sleb128 },
#[prefix(0x03)]
StartLocal {
register_num: Uleb128,
name_idx: Uleb128p1,
type_idx: Uleb128p1,
},
#[prefix(0x04)]
StartLocalExtended {
register_num: Uleb128,
name_idx: Uleb128p1,
type_idx: Uleb128p1,
sig_idx: Uleb128p1,
},
#[prefix(0x05)]
EndLocal { register_num: Uleb128 },
#[prefix(0x06)]
RestartLocal { register_num: Uleb128 },
#[prefix(0x07)]
SetPrologueEnd,
#[prefix(0x08)]
SetEpilogueBegin,
#[prefix(0x09)]
SetFile { name_idx: Uleb128p1 },
#[default_variant]
SpecialOpcode(u8),
}
impl DebugInfoItem {
pub fn parameters_size_field(&self) -> Uleb128 {
Uleb128(self.parameter_names.len() as u32)
}
}
impl Serializable for DebugInfoItem {
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
self.line_start.serialize(output)?;
self.parameters_size_field().serialize(output)?;
for item in &self.parameter_names {
item.serialize(output)?;
}
self.bytecode.serialize(output, DbgBytecode::EndSequence)?;
Ok(())
}
fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
let line_start = Uleb128::deserialize(input)?;
let Uleb128(parameters_size) = Uleb128::deserialize(input)?;
let mut parameter_names = vec![];
for _ in 0..parameters_size {
parameter_names.push(Uleb128p1::deserialize(input)?);
}
let bytecode = Vec::<DbgBytecode>::deserialize(input, DbgBytecode::EndSequence)?;
Ok(Self {
line_start,
parameter_names,
bytecode,
})
}
fn size(&self) -> usize {
self.line_start.size()
+ self.parameters_size_field().size()
+ self
.parameter_names
.iter()
.map(|param| param.size())
.sum::<usize>()
+ self.bytecode.size(DbgBytecode::EndSequence)
}
}
#[cfg(test)]
mod test {
use super::DbgBytecode::*;
use super::*;
#[test]
fn test_debug_reserialize() {
let debug = DebugInfoItem {
line_start: Uleb128(2902),
parameter_names: vec![],
bytecode: vec![
SpecialOpcode(14),
AdvanceLine {
line_diff: Sleb128(-1551),
},
AdvancePC {
addr_diff: Uleb128(51),
},
SpecialOpcode(14),
],
};
assert_eq!(
debug,
DebugInfoItem::deserialize_from_slice(&debug.serialize_to_vec().unwrap()).unwrap()
);
}
#[test]
fn test_advance_line_reserialize() {
let advance_line = AdvanceLine {
line_diff: Sleb128(-1551),
};
assert_eq!(
advance_line,
DbgBytecode::deserialize_from_slice(&advance_line.serialize_to_vec().unwrap()).unwrap()
);
}
}