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)?;