133 lines
3.7 KiB
Rust
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()
|
|
);
|
|
}
|
|
}
|