add instruction enum to code item

This commit is contained in:
Jean-Marie Mineau 2023-12-14 11:27:43 +01:00
parent ee7cf4d325
commit 81c8d0a8ec
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
2 changed files with 122 additions and 39 deletions

View file

@ -1,7 +1,7 @@
//! Code items
use crate as androscalpel_serializer;
use crate::{Error, ReadSeek, Result, Serializable, Sleb128, Uleb128};
use crate::{Error, Instruction, ReadSeek, Result, Serializable, Sleb128, Uleb128};
use log::debug;
use std::io::Write;
@ -16,7 +16,7 @@ pub struct CodeItem {
/// 0 if no debug info, else offset to a [`crate::DebugInfoItem`].
pub debug_info_off: u32,
// pub insns_size: u32,
pub insns: Vec<u16>,
pub insns: Vec<Instruction>,
// pub padding: Vec<u8>,
/// try items must refere to non overlapping range an order from low to hight addresses.
pub tries: Vec<TryItem>,
@ -29,7 +29,7 @@ impl CodeItem {
}
pub fn insns_size_field(&self) -> u32 {
self.insns.len() as u32
self.insns.iter().map(|ins| ins.size() as u32).sum::<u32>() / 2
}
pub fn sanity_check(&self) -> Result<()> {
@ -56,7 +56,7 @@ impl CodeItem {
/*
// Necessary? no in spec and apk in the wild seams to have try blocks spaming outside the
// insns array.
if max_addr > self.insns.len() as u32 {
if max_addr > self.insns_size_field() {
return Err(Error::InconsistantStruct(
"found try_item whose block span outside of the insns array".into(),
));
@ -72,7 +72,7 @@ impl CodeItem {
handler.sanity_check()?;
for handler in &handler.handlers {
// Necessary? no in spec
if handler.addr.0 > self.insns.len() as u32 {
if handler.addr.0 > self.insns_size_field() {
return Err(Error::InconsistantStruct(
"Found an handler whose address is outside of the insns array".into(),
));
@ -80,7 +80,7 @@ impl CodeItem {
}
if let Some(Uleb128(addr)) = handler.catch_all_addr {
// Necessary? no in spec
if addr > self.insns.len() as u32 {
if addr > self.insns_size_field() {
return Err(Error::InconsistantStruct(
"Found a catch all handler whose address is outside of the insns array"
.into(),
@ -88,6 +88,46 @@ impl CodeItem {
}
}
}
let mut addresses = vec![];
for try_ in &self.tries {
addresses.push(try_.start_addr);
addresses.push(try_.start_addr + try_.insn_count as u32);
}
for handler in &self.handlers {
for catch in &handler.list {
for EncodedTypeAddrPair {
addr: Uleb128(addr),
..
} in &catch.handlers
{
addresses.push(*addr);
}
if let Some(Uleb128(addr)) = catch.catch_all_addr {
addresses.push(addr);
}
}
}
addresses.sort();
let mut addr = 0;
let mut i = 0;
while i < addresses.len() && addresses[i] == addr {
i += 1;
}
for insn in &self.insns {
addr += insn.size() as u32;
while i < addresses.len() && addresses[i] == addr {
i += 1;
}
}
if i < addresses.len() && addresses[i] < addr {
return Err(Error::InconsistantStruct(format!(
"Found an address in try block (0x{addr:x}) that does not align with an instruction"
)));
}
// TODO check goto addresses? pb: op code are not parsed so goto instruction are not known
Ok(())
}
}
@ -127,9 +167,13 @@ impl Serializable for CodeItem {
let tries_size = u16::deserialize(input)?;
let debug_info_off = u32::deserialize(input)?;
let insns_size = u32::deserialize(input)?;
let mut insns = vec![];
for _ in 0..insns_size {
insns.push(u16::deserialize(input)?);
let mut serialized_insns_size = 0;
while serialized_insns_size != insns_size {
let ins = Instruction::deserialize(input)?;
serialized_insns_size += ins.size() as u32;
insns.push(ins);
}
if tries_size != 0 && insns_size % 2 == 1 {
let _ = u16::deserialize(input)?;

View file

@ -269,7 +269,6 @@ impl Instruction {
requires the first byte to be 0 found {v}"
)));
}
// TODO: check bytes order
let a = i16::deserialize(input)?;
Ok(Self::Format20T { op, a })
}
@ -277,7 +276,6 @@ impl Instruction {
pub fn deserialize_20bc(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let a = i8::deserialize(input)?;
// TODO: check bytes order
let b = u16::deserialize(input)?;
Ok(Self::Format20BC { a, op, b })
}
@ -285,7 +283,6 @@ impl Instruction {
pub fn deserialize_22x(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let va = u8::deserialize(input)?;
// TODO: check bytes order
let vb = u16::deserialize(input)?;
Ok(Self::Format22X { va, op, vb })
}
@ -293,7 +290,6 @@ impl Instruction {
pub fn deserialize_21t(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let va = u8::deserialize(input)?;
// TODO: check bytes order
let b = i16::deserialize(input)?;
Ok(Self::Format21T { va, op, b })
}
@ -301,7 +297,6 @@ impl Instruction {
pub fn deserialize_21s(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let va = u8::deserialize(input)?;
// TODO: check bytes order
let b = i16::deserialize(input)?;
Ok(Self::Format21S { va, op, b })
}
@ -309,7 +304,6 @@ impl Instruction {
pub fn deserialize_21h(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let va = u8::deserialize(input)?;
// TODO: check bytes order
let b = i16::deserialize(input)?;
Ok(Self::Format21H { va, op, b })
}
@ -317,7 +311,6 @@ impl Instruction {
pub fn deserialize_21c(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let va = u8::deserialize(input)?;
// TODO: check bytes order
let b = u16::deserialize(input)?;
Ok(Self::Format21C { va, op, b })
}
@ -343,7 +336,6 @@ impl Instruction {
let val = u8::deserialize(input)?;
let va = val & 0b0000_1111;
let vb = (val & 0b1111_0000) >> 4;
// TODO: check bytes order
let c = i16::deserialize(input)?;
Ok(Self::Format22T { vb, va, op, c })
}
@ -353,7 +345,6 @@ impl Instruction {
let val = u8::deserialize(input)?;
let va = val & 0b0000_1111;
let vb = (val & 0b1111_0000) >> 4;
// TODO: check bytes order
let c = i16::deserialize(input)?;
Ok(Self::Format22S { vb, va, op, c })
}
@ -363,7 +354,6 @@ impl Instruction {
let val = u8::deserialize(input)?;
let va = val & 0b0000_1111;
let vb = (val & 0b1111_0000) >> 4;
// TODO: check bytes order
let c = u16::deserialize(input)?;
Ok(Self::Format22C { vb, va, op, c })
}
@ -373,7 +363,6 @@ impl Instruction {
let val = u8::deserialize(input)?;
let va = val & 0b0000_1111;
let vb = (val & 0b1111_0000) >> 4;
// TODO: check bytes order
let c = u16::deserialize(input)?;
Ok(Self::Format22CS { vb, va, op, c })
}
@ -388,7 +377,6 @@ impl Instruction {
requires the first byte to be 0 found {v}"
)));
}
// TODO: check the bytes order
let [a_l0, a_l1, a_h0, a_h1] = i32::deserialize(input)?.to_be_bytes();
let a = i32::from_be_bytes([a_h0, a_h1, a_l0, a_l1]);
Ok(Self::Format30T { op, a })
@ -404,9 +392,7 @@ impl Instruction {
requires the first byte to be 0 found {v}"
)));
}
// TODO: check the bytes order
let va = u16::deserialize(input)?;
// TODO: check the bytes order
let vb = u16::deserialize(input)?;
Ok(Self::Format32X { op, va, vb })
}
@ -415,7 +401,6 @@ impl Instruction {
let op = u8::deserialize(input)?;
let va = u8::deserialize(input)?;
let [b_l0, b_l1, b_h0, b_h1] = i32::deserialize(input)?.to_be_bytes();
// TODO: check the bytes order
let b = i32::from_be_bytes([b_h0, b_h1, b_l0, b_l1]);
Ok(Self::Format31I { va, op, b })
}
@ -424,7 +409,6 @@ impl Instruction {
let op = u8::deserialize(input)?;
let va = u8::deserialize(input)?;
let [b_l0, b_l1, b_h0, b_h1] = i32::deserialize(input)?.to_be_bytes();
// TODO: check the bytes order
let b = i32::from_be_bytes([b_h0, b_h1, b_l0, b_l1]);
Ok(Self::Format31T { va, op, b })
}
@ -433,7 +417,6 @@ impl Instruction {
let op = u8::deserialize(input)?;
let va = u8::deserialize(input)?;
let [b_l0, b_l1, b_h0, b_h1] = u32::deserialize(input)?.to_be_bytes();
// TODO: check the bytes order
let b = u32::from_be_bytes([b_h0, b_h1, b_l0, b_l1]);
Ok(Self::Format31C { va, op, b })
}
@ -449,7 +432,6 @@ impl Instruction {
requires A to be between 0 and 5, found {a}"
)));
}
// TODO: check the bytes order
let b = u16::deserialize(input)?;
let val = u8::deserialize(input)?;
@ -483,7 +465,6 @@ impl Instruction {
requires A to be between 0 and 5, found {a}"
)));
}
// TODO: check the bytes order
let b = u16::deserialize(input)?;
let val = u8::deserialize(input)?;
@ -517,7 +498,6 @@ impl Instruction {
requires A to be between 0 and 5, found {a}"
)));
}
// TODO: check the bytes order
let b = u16::deserialize(input)?;
let val = u8::deserialize(input)?;
@ -543,9 +523,7 @@ impl Instruction {
pub fn deserialize_3rc(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let a = u8::deserialize(input)?;
// TODO: check the bytes order
let b = u16::deserialize(input)?;
// TODO: check the bytes order
let vc = u16::deserialize(input)?;
Ok(Self::Format3RC { a, op, b, vc })
}
@ -553,9 +531,7 @@ impl Instruction {
pub fn deserialize_3rms(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let a = u8::deserialize(input)?;
// TODO: check the bytes order
let b = u16::deserialize(input)?;
// TODO: check the bytes order
let vc = u16::deserialize(input)?;
Ok(Self::Format3RMS { a, op, b, vc })
}
@ -563,9 +539,7 @@ impl Instruction {
pub fn deserialize_3rmi(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let a = u8::deserialize(input)?;
// TODO: check the bytes order
let b = u16::deserialize(input)?;
// TODO: check the bytes order
let vc = u16::deserialize(input)?;
Ok(Self::Format3RMI { a, op, b, vc })
}
@ -581,7 +555,6 @@ impl Instruction {
requires A to be between 0 and 5, found {a}"
)));
}
// TODO: check the bytes order
let b = u16::deserialize(input)?;
let val = u8::deserialize(input)?;
@ -592,7 +565,6 @@ impl Instruction {
let vf = (val & 0b1111_0000) >> 4;
let ve = val & 0b0000_1111;
// TODO: check the bytes order
let h = u16::deserialize(input)?;
Ok(Self::Format45CC {
@ -611,11 +583,8 @@ impl Instruction {
pub fn deserialize_4rcc(input: &mut dyn ReadSeek) -> Result<Self> {
let op = u8::deserialize(input)?;
let a = u8::deserialize(input)?;
// TODO: check the bytes order
let b = u16::deserialize(input)?;
// TODO: check the bytes order
let vc = u16::deserialize(input)?;
// TODO: check the bytes order
let h = u16::deserialize(input)?;
Ok(Self::Format4RCC { a, op, b, vc, h })
}
@ -2113,6 +2082,76 @@ mod test {
}
}
#[test]
fn test_parsing_20t() {
for (raw, expected) in [
(
vec![0x29, 0x00, 0xd4, 0xfe],
Instruction::Format20T { a: -300, op: 0x29 },
),
(
vec![0x29, 0x00, 0x16, 0x01],
Instruction::Format20T { a: 278, op: 0x29 },
),
] {
assert_eq!(expected.size(), raw.len());
assert_eq!(expected, Instruction::deserialize_from_slice(&raw).unwrap());
assert_eq!(raw, expected.serialize_to_vec().unwrap());
}
}
#[test]
fn test_parsing_22x() {
for (raw, expected) in [
(
vec![0x08, 0x0b, 0x11, 0x00],
Instruction::Format22X {
va: 11,
vb: 17,
op: 0x8,
},
),
(
vec![0x08, 0x03, 0x11, 0x00],
Instruction::Format22X {
va: 3,
vb: 17,
op: 0x8,
},
),
] {
assert_eq!(expected.size(), raw.len());
assert_eq!(expected, Instruction::deserialize_from_slice(&raw).unwrap());
assert_eq!(raw, expected.serialize_to_vec().unwrap());
}
}
#[test]
fn test_parsing_21h() {
for (raw, expected) in [
(
vec![0x15, 0x0b, 0x10, 0x00],
Instruction::Format21H {
va: 11,
b: (1048576 / 65536) as i16,
op: 0x15,
},
),
(
vec![0x15, 0x06, 0x00, 0x80],
Instruction::Format21H {
va: 6,
b: (-2147483648 / 65536) as i16,
op: 0x15,
},
),
] {
assert_eq!(expected.size(), raw.len());
assert_eq!(expected, Instruction::deserialize_from_slice(&raw).unwrap());
assert_eq!(raw, expected.serialize_to_vec().unwrap());
}
}
#[test]
fn test_parsing_21c() {
let raw = vec![0x22, 0x00, 0x2d, 0x24];