WIP: gen class def in frag

This commit is contained in:
Jean-Marie Mineau 2024-03-11 17:12:59 +01:00
parent 71fc0d2398
commit 7e63a523d7
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2

View file

@ -54,8 +54,8 @@ pub struct DexFragment {
type_lists_with_offset: Vec<(TypeList, u32)>,
/// The encoded_array_items section.
encoded_array_items: Vec<EncodedArrayItem>,
/// The annotations_directory_item section.
annotations_directory_items: Vec<AnnotationsDirectoryItem>,
/// The annotations_directory_item.
annotations_directory_items: Option<AnnotationsDirectoryItem>,
/// The annotation_set_item section.
annotation_set_items: Vec<AnnotationSetItem>,
/// The annotation item section.
@ -68,6 +68,8 @@ pub struct DexFragment {
code_items: Vec<CodeItem>,
/// The debug info items section.
debug_info_items: Vec<DebugInfoItem>,
/// The list of interfaces of the class.
interfaces: Vec<IdType>,
}
impl DexFragment {
@ -101,11 +103,12 @@ impl DexFragment {
encoded_array_items: vec![],
method_handles: vec![],
code_items: vec![],
annotations_directory_items: vec![],
annotations_directory_items: None,
annotation_set_items: vec![],
annotation_items: vec![],
annotation_set_lists: vec![],
debug_info_items: vec![],
interfaces: class.interfaces.clone(),
};
frag.strings = class.get_all_strings().into_iter().collect();
frag.strings.sort();
@ -150,6 +153,54 @@ impl DexFragment {
frag.section_manager
.add_elt(FragSection::ClassDefItem, None);
frag.class_def.class_idx = *types_index.get(&class.descriptor).ok_or(anyhow!(
"Type {} (type of class {}) not found in type list",
class.descriptor.__repr__(),
class.__repr__()
))? as u32;
frag.class_def.access_flags = class.get_raw_access_flags();
frag.class_def.superclass_idx = if let Some(sup) = &class.superclass {
*types_index.get(sup).ok_or(anyhow!(
"Type {} (superclass of class {}) not found in dex builder",
sup.__repr__(),
class.__repr__()
))? as u32
} else {
NO_INDEX.0
};
frag.class_def.interfaces_off = 0; // set when linking
frag.class_def.source_file_idx = if let Some(file) = &class.source_file {
*strings_index.get(file).ok_or(anyhow!(
"String {} (source file of class {}) not found in dex builder",
file.__repr__(),
class.__repr__()
))? as u32
} else {
NO_INDEX.0
};
frag.class_def.annotations_off = if class.has_annotations() {
// TODO: frag.insert_annotations(class)?;
1
} else {
0
};
frag.class_def.class_data_off = if class.has_data_item() {
//TODO: frag.insert_class_data_item(class_id)?;
1
} else {
0
};
frag.class_def.static_values_off = if class.has_static_values_array() {
let static_values_off = frag
.section_manager
.get_aligned_size(FragSection::EncodedArrayItem);
// TODO: frag.insert_class_static_values(class)?;
static_values_off + 1
} else {
0
};
Ok(frag)
}
@ -1947,97 +1998,6 @@ impl DexFragment {
Ok(())
}
/// Insert a class_def_item in the class_defs section **and** the other struct that needs to be
/// generated on the fly.
///
/// # Warning
///
/// The class_defs section **MUST** be sorted by inheritance dependencies (parents classes and
/// interfaces must appear **before** child classes). Accordingly, this method must be invoked
/// in the right order.
///
/// # Note
///
/// annotations_directory_item, encoded_array_item and class_data_item objects are 4 bytes
/// aligns, so their offset cannot be odd.
///
/// To distinguish prelinked value (offset inside the code_item section) to actual values (offset
/// in the whole file or 0), their value is set to the actual value prelink value + 1. This allow
/// to distinguish the offset of the first item (equal to zero before linking) and the value
/// 0 used to indicate an abscence of item.
fn insert_class_def_item(&mut self, class_id: &IdType) -> Result<()> {
let idx = self.class_defs_list.len();
self.class_defs
.entry(class_id.clone())
.and_modify(|(_, i)| *i = idx);
let (class, _) = self.class_defs.get(class_id).unwrap();
let class_data_off = if class.has_data_item() {
let class_data_off = self
.section_manager
.get_aligned_size(Section::ClassDataItem);
self.insert_class_data_item(class_id)?;
class_data_off + 1
} else {
0
};
// & vs &mut cluster-f, this make rust drop the ref so self hold by `class` before
// mutating self with `insert_class_data_item`, and get a new ref afterward
let (class, _) = self.class_defs.get(class_id).unwrap();
let static_values_off = if class.has_static_values_array() {
let static_values_off = self
.section_manager
.get_aligned_size(Section::EncodedArrayItem);
self.insert_class_static_values(class_id)?;
static_values_off + 1
} else {
0
};
let (class, _) = self.class_defs.get(class_id).unwrap();
let annotations_off = if class.has_annotations() {
let annotations_off = self
.section_manager
.get_aligned_size(Section::AnnotationsDirectoryItem);
self.insert_annotations(class_id)?;
annotations_off + 1
} else {
0
};
let (class, _) = self.class_defs.get(class_id).unwrap();
self.class_defs_list.push(ClassDefItem {
class_idx: *self.type_ids.get(class_id).ok_or(anyhow!(
"Type {} (type of class {}) not found in dex builder",
class_id.__repr__(),
class.__repr__()
))? as u32,
access_flags: class.get_raw_access_flags(),
superclass_idx: if let Some(sup) = &class.superclass {
*self.type_ids.get(sup).ok_or(anyhow!(
"Type {} (superclass of class {}) not found in dex builder",
sup.__repr__(),
class.__repr__()
))? as u32
} else {
NO_INDEX.0
},
interfaces_off: 0,
source_file_idx: if let Some(file) = &class.source_file {
*self.strings.get(file).ok_or(anyhow!(
"String {} (source file of class {}) not found in dex builder",
file.__repr__(),
class.__repr__()
))? as u32
} else {
NO_INDEX.0
},
annotations_off, // need relinking once offset of class_def_item section is known
class_data_off, // need relinking once offset of class_data section is known
static_values_off, // need relinking once offset of encoded_array section is known
});
self.section_manager.add_elt(Section::ClassDefItem, None);
Ok(())
}
fn gen_type_list_section(&mut self) -> Result<()> {
debug!("Generate the type_list section");
// Collect all type lists
@ -2781,7 +2741,9 @@ impl FragSectionManager {
if !self.editable {
panic!("Try to modify a section when the sections are set to read only");
}
if (section == FragSection::ClassDefItem || section == FragSection::ClassDataItem)
if (section == FragSection::ClassDefItem
|| section == FragSection::ClassDataItem
|| section == FragSection::AnnotationsDirectoryItem)
&& (self.nb_elt[section.get_index()] >= 1)
{
panic!("{section:#?} cannot contain more than one element in a dex fragment");