seriable try block and call site
This commit is contained in:
parent
31e4192eb3
commit
04a6d48e51
3 changed files with 167 additions and 92 deletions
|
|
@ -43,7 +43,7 @@ pub struct DexWriter {
|
|||
/// index in the `class_defs` section.
|
||||
class_defs: HashMap<IdType, (Class, usize)>,
|
||||
/// The call sites refered to in the bytecode.
|
||||
call_sites: Vec<CallSite>,
|
||||
call_site_ids: Vec<CallSiteIdItem>,
|
||||
/// A struct that keep track of sections size, nb elements and offsets.
|
||||
section_manager: SectionManager,
|
||||
/// The string_data section. Once populated, the elements must be sorted according to the spec.
|
||||
|
|
@ -125,7 +125,7 @@ impl Default for DexWriter {
|
|||
field_ids: HashMap::new(),
|
||||
method_ids: HashMap::new(),
|
||||
class_defs: HashMap::new(),
|
||||
call_sites: vec![],
|
||||
call_site_ids: vec![],
|
||||
section_manager: SectionManager::default(),
|
||||
string_data_list: vec![],
|
||||
type_ids_list: vec![],
|
||||
|
|
@ -378,6 +378,7 @@ impl DexWriter {
|
|||
.clone()
|
||||
};
|
||||
|
||||
// Estimate instructions addresses
|
||||
let mut min_addr = 0;
|
||||
let mut max_addr = 0;
|
||||
let mut label_min_max_addrs: HashMap<String, (usize, usize)> = HashMap::new();
|
||||
|
|
@ -404,6 +405,7 @@ impl DexWriter {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Compute instruction size and precise addresses
|
||||
let mut addr = 0;
|
||||
let mut label_addrs = HashMap::new();
|
||||
let mut goto_sizes = vec![];
|
||||
|
|
@ -432,6 +434,10 @@ impl DexWriter {
|
|||
_ => addr += ins.ins_size()? / 2,
|
||||
}
|
||||
}
|
||||
// Serialize instructions
|
||||
let mut tries = vec![];
|
||||
let mut handlers = EncodedCatchHandlerList { list: vec![] };
|
||||
let mut handler_off = 0;
|
||||
let mut insns = vec![];
|
||||
let mut payloads = vec![];
|
||||
let mut goto_idx = 0;
|
||||
|
|
@ -1182,8 +1188,8 @@ impl DexWriter {
|
|||
insns.push(ins);
|
||||
}
|
||||
Instruction::InvokeCustom(ins) => {
|
||||
let call_site_idx = self.call_sites.len();
|
||||
self.call_sites.push(ins.call_site.clone());
|
||||
let call_site_idx = self.call_site_ids.len();
|
||||
self.insert_call_site_item(&ins.call_site)?;
|
||||
let ins = ins.get_raw_ins(call_site_idx);
|
||||
addr += ins.size() / 2;
|
||||
insns.push(ins);
|
||||
|
|
@ -1205,8 +1211,57 @@ impl DexWriter {
|
|||
addr += ins.size() / 2;
|
||||
insns.push(ins);
|
||||
}
|
||||
Instruction::Try(_ins) => {
|
||||
// TODO
|
||||
Instruction::Try(try_) => {
|
||||
let end_block_addr = *label_addrs.get(&try_.end_label).ok_or(anyhow!(
|
||||
"Label {} not found in code of {}, but found try with this label",
|
||||
&try_.end_label,
|
||||
method_id.__repr__()
|
||||
))?;
|
||||
if end_block_addr < addr {
|
||||
bail!(
|
||||
"Found end label of a try block before the try instruction in code of {}",
|
||||
method_id.__repr__()
|
||||
)
|
||||
}
|
||||
let try_item = TryItem {
|
||||
start_addr: addr as u32,
|
||||
insn_count: (end_block_addr - addr) as u16,
|
||||
handler_off: handler_off as u16,
|
||||
};
|
||||
tries.push(try_item);
|
||||
let mut catches = EncodedCatchHandler {
|
||||
handlers: vec![],
|
||||
catch_all_addr: None,
|
||||
};
|
||||
for (ty, label) in &try_.handlers {
|
||||
let type_idx = Uleb128(*self.type_ids.get(ty).ok_or(anyhow!(
|
||||
"Could not found type {} captured by a try block in {}\
|
||||
in the dex builder",
|
||||
ty.__repr__(),
|
||||
method_id.__repr__()
|
||||
))? as u32);
|
||||
let addr = Uleb128(*label_addrs.get(label).ok_or(anyhow!(
|
||||
"Label {} not found in code of {}, but found try \
|
||||
with this label as catch for type {}",
|
||||
&try_.end_label,
|
||||
method_id.__repr__(),
|
||||
ty.__repr__(),
|
||||
))? as u32);
|
||||
catches
|
||||
.handlers
|
||||
.push(EncodedTypeAddrPair { type_idx, addr });
|
||||
}
|
||||
if let Some(ref label) = try_.default_handler {
|
||||
let catch_all_addr = *label_addrs.get(label).ok_or(anyhow!(
|
||||
"Label {} not found in code of {}, but found try \
|
||||
with this label as catch all",
|
||||
&try_.end_label,
|
||||
method_id.__repr__()
|
||||
))?;
|
||||
catches.catch_all_addr = Some(Uleb128(catch_all_addr as u32));
|
||||
}
|
||||
handler_off += catches.size();
|
||||
handlers.list.push(catches);
|
||||
}
|
||||
Instruction::Label(_) => (),
|
||||
_ => {
|
||||
|
|
@ -1224,10 +1279,6 @@ impl DexWriter {
|
|||
}
|
||||
insns.extend(payloads);
|
||||
|
||||
// TODO
|
||||
let mut tries = vec![];
|
||||
let mut handlers = None;
|
||||
|
||||
let debug_info_off = if code.debug_info.is_empty() {
|
||||
0
|
||||
} else {
|
||||
|
|
@ -1238,6 +1289,11 @@ impl DexWriter {
|
|||
self.debug_info_items.push(item);
|
||||
debug_info_off + 1
|
||||
};
|
||||
let handlers = if handlers.list.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(handlers)
|
||||
};
|
||||
let item = CodeItem {
|
||||
registers_size: code.registers_size,
|
||||
ins_size: code.ins_size,
|
||||
|
|
@ -1250,51 +1306,6 @@ impl DexWriter {
|
|||
self.section_manager
|
||||
.add_elt(Section::CodeItem, Some(item.size()));
|
||||
self.code_items.push(item);
|
||||
/*
|
||||
let mut tries = vec![];
|
||||
let mut local_off = 0;
|
||||
let mut handler_offsets = HashMap::new();
|
||||
let mut handler_list = EncodedCatchHandlerList { list: vec![] };
|
||||
for (start_addr, insn_count, (list, catch_all_addr)) in code.tries.iter().cloned() {
|
||||
let mut handlers = vec![];
|
||||
for (ty, addr) in list {
|
||||
let type_idx = Uleb128(*self.type_ids.get(&ty).ok_or(anyhow!(
|
||||
"Could not found type {} captured by a try block in {} in the dex builder",
|
||||
ty.__repr__(),
|
||||
method_id.__repr__()
|
||||
))? as u32);
|
||||
let addr = Uleb128(addr);
|
||||
handlers.push(EncodedTypeAddrPair { type_idx, addr });
|
||||
}
|
||||
let handler = EncodedCatchHandler {
|
||||
handlers,
|
||||
catch_all_addr: catch_all_addr.map(Uleb128),
|
||||
};
|
||||
let handler_off = if let Some(handler_off) = handler_offsets.get(&handler).cloned() {
|
||||
handler_off
|
||||
} else {
|
||||
let old_local_off = local_off;
|
||||
local_off += handler.size() as u16;
|
||||
handler_list.list.push(handler.clone());
|
||||
handler_offsets.insert(handler, old_local_off);
|
||||
old_local_off
|
||||
};
|
||||
|
||||
tries.push(TryItem {
|
||||
start_addr,
|
||||
insn_count,
|
||||
handler_off,
|
||||
});
|
||||
}
|
||||
for try_ in tries.iter_mut() {
|
||||
try_.handler_off += handler_list.size_field().size() as u16;
|
||||
}
|
||||
let handlers = if tries.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(handler_list)
|
||||
};
|
||||
*/
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1597,6 +1608,24 @@ impl DexWriter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Insert a [`CallSite`] to the encoded array items
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This method can insert element in the dex file like method_handles.
|
||||
pub fn insert_call_site_item(&mut self, call_site: &CallSite) -> Result<()> {
|
||||
let mut values = vec![];
|
||||
values.push(DexValue::MethodHandle(call_site.method_handle.clone()));
|
||||
values.push(DexValue::String(call_site.name.clone()));
|
||||
values.push(DexValue::MethodType(call_site.type_.clone()));
|
||||
values.extend(call_site.args.iter().cloned());
|
||||
self.call_site_ids.push(CallSiteIdItem {
|
||||
call_site_off: self.section_manager.get_size(Section::EncodedArrayItem),
|
||||
}); // linked in link_call_site_ids()
|
||||
self.section_manager.add_elt(Section::CallSiteIdItem, None);
|
||||
self.insert_encoded_array_item(DexArray(values))
|
||||
}
|
||||
|
||||
/// Insert the encoded_array_item encoding the static_values of a class.
|
||||
fn insert_class_static_values(&mut self, class_id: &IdType) -> Result<()> {
|
||||
let (class, _) = self.class_defs.get(class_id).unwrap();
|
||||
|
|
@ -1672,11 +1701,18 @@ impl DexWriter {
|
|||
}); // linked in link_annotations()
|
||||
|
||||
let item = AnnotationItem {
|
||||
visibility: match (annot.visibility_build, annot.visibility_runtime, annot.visibility_system) {
|
||||
visibility: match (
|
||||
annot.visibility_build,
|
||||
annot.visibility_runtime,
|
||||
annot.visibility_system,
|
||||
) {
|
||||
(true, false, false) => AnnotationVisibility::Build,
|
||||
(false, true, false) => AnnotationVisibility::Runtime,
|
||||
(false, false, true) => AnnotationVisibility::System,
|
||||
_ => bail!("Annotation need visibility set to one and only one of build, runtime or system"), // TODO: check if this is true
|
||||
_ => bail!(
|
||||
"Annotation need visibility set to one and only one of build, \
|
||||
runtime or system"
|
||||
), // TODO: check if this is true
|
||||
},
|
||||
annotation: self.dex_annotation_to_encoded_annotation(annot.annotation)?,
|
||||
};
|
||||
|
|
@ -1712,11 +1748,18 @@ impl DexWriter {
|
|||
}); // linked in link_annotations()
|
||||
|
||||
let item = AnnotationItem {
|
||||
visibility: match (annot.visibility_build, annot.visibility_runtime, annot.visibility_system) {
|
||||
visibility: match (
|
||||
annot.visibility_build,
|
||||
annot.visibility_runtime,
|
||||
annot.visibility_system,
|
||||
) {
|
||||
(true, false, false) => AnnotationVisibility::Build,
|
||||
(false, true, false) => AnnotationVisibility::Runtime,
|
||||
(false, false, true) => AnnotationVisibility::System,
|
||||
_ => bail!("Annotation need visibility set to one and only one of build, runtime or system"), // TODO: check if this is true
|
||||
_ => bail!(
|
||||
"Annotation need visibility set to one and only one of build, \
|
||||
runtime or system"
|
||||
), // TODO: check if this is true
|
||||
},
|
||||
annotation: self.dex_annotation_to_encoded_annotation(annot.annotation)?,
|
||||
};
|
||||
|
|
@ -1752,11 +1795,18 @@ impl DexWriter {
|
|||
}); // linked in link_annotations()
|
||||
|
||||
let item = AnnotationItem {
|
||||
visibility: match (annot.visibility_build, annot.visibility_runtime, annot.visibility_system) {
|
||||
visibility: match (
|
||||
annot.visibility_build,
|
||||
annot.visibility_runtime,
|
||||
annot.visibility_system,
|
||||
) {
|
||||
(true, false, false) => AnnotationVisibility::Build,
|
||||
(false, true, false) => AnnotationVisibility::Runtime,
|
||||
(false, false, true) => AnnotationVisibility::System,
|
||||
_ => bail!("Annotation need visibility set to one and only one of build, runtime or system"), // TODO: check if this is true
|
||||
_ => bail!(
|
||||
"Annotation need visibility set to one and only one of build, \
|
||||
runtime or system"
|
||||
), // TODO: check if this is true
|
||||
},
|
||||
annotation: self.dex_annotation_to_encoded_annotation(annot.annotation)?,
|
||||
};
|
||||
|
|
@ -1793,11 +1843,18 @@ impl DexWriter {
|
|||
}); // linked in link_annotations()
|
||||
|
||||
let item = AnnotationItem {
|
||||
visibility: match (annot.visibility_build, annot.visibility_runtime, annot.visibility_system) {
|
||||
visibility: match (
|
||||
annot.visibility_build,
|
||||
annot.visibility_runtime,
|
||||
annot.visibility_system,
|
||||
) {
|
||||
(true, false, false) => AnnotationVisibility::Build,
|
||||
(false, true, false) => AnnotationVisibility::Runtime,
|
||||
(false, false, true) => AnnotationVisibility::System,
|
||||
_ => bail!("Annotation need visibility set to one and only one of build, runtime or system"), // TODO: check if this is true
|
||||
_ => bail!(
|
||||
"Annotation need visibility set to one and only one of build, \
|
||||
runtime or system"
|
||||
), // TODO: check if this is true
|
||||
},
|
||||
annotation: self.dex_annotation_to_encoded_annotation(annot.annotation)?,
|
||||
};
|
||||
|
|
@ -2173,6 +2230,18 @@ impl DexWriter {
|
|||
self.header.data_off = self.section_manager.get_offset(Section::Data);
|
||||
}
|
||||
|
||||
/// Link the offsets in the call site id items.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// Linking can only occur once all sections are entirelly generated.
|
||||
fn link_call_site_ids(&mut self) {
|
||||
debug!("Link call site id items");
|
||||
for id in &mut self.call_site_ids {
|
||||
id.call_site_off += self.section_manager.get_offset(Section::EncodedArrayItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// Link the offsets of type_lists items in proto_id_items and class_def_items.
|
||||
///
|
||||
/// # Warning
|
||||
|
|
@ -2338,7 +2407,9 @@ impl DexWriter {
|
|||
|
||||
self.get_map_list()?;
|
||||
|
||||
// From now on, all section are generated and the value in section_manager do not change.
|
||||
self.link_header();
|
||||
self.link_call_site_ids();
|
||||
self.link_type_list_occurences()?;
|
||||
self.link_class_data_occurences();
|
||||
self.link_static_values();
|
||||
|
|
@ -2378,7 +2449,11 @@ impl DexWriter {
|
|||
for class_def in &self.class_defs_list {
|
||||
class_def.serialize(writer)?;
|
||||
}
|
||||
// TODO: CallSiteIdItem, data must be inserted as encoded array item later
|
||||
// CallSiteIdItem, data are inserted as encoded array item later
|
||||
for call_site_id in &self.call_site_ids {
|
||||
call_site_id.serialize(writer)?;
|
||||
}
|
||||
|
||||
// MethodHandleItem section
|
||||
for handle in &self.method_handles {
|
||||
handle.serialize(writer)?;
|
||||
|
|
@ -2428,7 +2503,7 @@ impl DexWriter {
|
|||
for annot in &self.annotation_items {
|
||||
annot.serialize(writer)?;
|
||||
}
|
||||
// TODO: EncodedArrayItem: partialy done
|
||||
// EncodedArrayItem section
|
||||
for array in &self.encoded_array_items {
|
||||
array.serialize(writer)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6027,7 +6027,7 @@ impl IfLeZ {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the value at arr[idx] in register dest (all values are in registers)
|
||||
/// Put the value at `arr[idx]` in register dest (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct AGet {
|
||||
|
|
@ -6099,7 +6099,7 @@ impl AGet {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the value at arr[idx] in register pair dest (all values are in registers)
|
||||
/// Put the value at `arr[idx]` in register pair dest (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct AGetWide {
|
||||
|
|
@ -6171,7 +6171,7 @@ impl AGetWide {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the reference at arr[idx] in register (all values are in registers)
|
||||
/// Put the reference at `arr[idx]` in register (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct AGetObject {
|
||||
|
|
@ -6243,7 +6243,7 @@ impl AGetObject {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the boolean at arr[idx] in register dest (all values are in registers)
|
||||
/// Put the boolean at `arr[idx]` in register dest (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct AGetBoolean {
|
||||
|
|
@ -6315,7 +6315,7 @@ impl AGetBoolean {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the byte at arr[idx] in register dest (all values are in registers)
|
||||
/// Put the byte at `arr[idx]` in register dest (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct AGetByte {
|
||||
|
|
@ -6387,7 +6387,7 @@ impl AGetByte {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the char at arr[idx] in register dest (all values are in registers)
|
||||
/// Put the char at `arr[idx]` in register dest (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct AGetChar {
|
||||
|
|
@ -6459,7 +6459,7 @@ impl AGetChar {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the short at arr[idx] in register dest (all values are in registers)
|
||||
/// Put the short at `arr[idx]` in register dest (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct AGetShort {
|
||||
|
|
@ -6531,7 +6531,7 @@ impl AGetShort {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the value of register 'from' in arr[idx] (all values are in registers)
|
||||
/// Put the value of register 'from' in `arr[idx]` (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct APut {
|
||||
|
|
@ -6603,7 +6603,7 @@ impl APut {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the value of the register pair 'from' in arr[idx] (all values are in registers)
|
||||
/// Put the value of the register pair 'from' in `arr[idx]` (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct APutWide {
|
||||
|
|
@ -6675,7 +6675,7 @@ impl APutWide {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the object reference in 'from' in arr[idx] (all values are in registers)
|
||||
/// Put the object reference in 'from' in `arr[idx]` (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct APutObject {
|
||||
|
|
@ -6747,7 +6747,7 @@ impl APutObject {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the boolean in 'from' in arr[idx] (all values are in registers)
|
||||
/// Put the boolean in 'from' in `arr[idx]` (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct APutBoolean {
|
||||
|
|
@ -6819,7 +6819,7 @@ impl APutBoolean {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the byte in 'from' in arr[idx] (all values are in registers)
|
||||
/// Put the byte in 'from' in `arr[idx]` (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct APutByte {
|
||||
|
|
@ -6891,7 +6891,7 @@ impl APutByte {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the char in 'from' in arr[idx] (all values are in registers)
|
||||
/// Put the char in 'from' in `arr[idx]` (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct APutChar {
|
||||
|
|
@ -6963,7 +6963,7 @@ impl APutChar {
|
|||
}
|
||||
}
|
||||
|
||||
/// Put the short in 'from' in arr[idx] (all values are in registers)
|
||||
/// Put the short in 'from' in `arr[idx]` (all values are in registers)
|
||||
#[pyclass]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct APutShort {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ pub struct ClassDefItem {
|
|||
pub interfaces_off: u32,
|
||||
/// Index of a [`crate::StringIdItem`] in `string_ids` or [`crate::NO_INDEX`].
|
||||
pub source_file_idx: u32,
|
||||
/// 0 if no annotation, else offset to a [`crate::AnnotationDirectoryItem`].
|
||||
/// 0 if no annotation, else offset to a [`crate::AnnotationsDirectoryItem`].
|
||||
pub annotations_off: u32,
|
||||
/// 0 if no data for this class, else offset to a [`crate::ClassDataItem`].
|
||||
pub class_data_off: u32,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue