fix offsets
This commit is contained in:
parent
e1f1d01e2c
commit
92d4ecaa1c
1 changed files with 252 additions and 38 deletions
|
|
@ -89,6 +89,22 @@ pub struct DexWriter {
|
||||||
debug_info_items: Vec<DebugInfoItem>,
|
debug_info_items: Vec<DebugInfoItem>,
|
||||||
/// The map_list
|
/// The map_list
|
||||||
map_list: MapList,
|
map_list: MapList,
|
||||||
|
/// Map the **local** offset of **unlinked** class data offset to the **local**
|
||||||
|
/// offset of the **linked**.
|
||||||
|
///
|
||||||
|
/// local offset means the offset of the first data item in the section is 0 (i.e. not
|
||||||
|
/// the offset from the beginning of the file).
|
||||||
|
///
|
||||||
|
/// This hack is necessary (well, maybe not necessary but that would require some refactoring)
|
||||||
|
/// because someone thought that encoding offsets in Uleb format was a good idea. It was not.
|
||||||
|
/// The size of the encoded offset depend on the value of the offset, so the linking change the
|
||||||
|
/// size of the struct, and doing so change the offset of the next struct, ect.
|
||||||
|
///
|
||||||
|
/// When generating the structs refering to `class_data_item`s, the local offset of the
|
||||||
|
/// unlinked `class_data_item` is known, but not the linked offset. This struct is filled
|
||||||
|
/// when linking the `class_data_item`s, and can then be used to link the structs refering to
|
||||||
|
/// the `class_data_item`s.
|
||||||
|
corrected_class_data_offset: HashMap<u32, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DexWriter {
|
impl Default for DexWriter {
|
||||||
|
|
@ -147,6 +163,7 @@ impl Default for DexWriter {
|
||||||
annotation_items: vec![],
|
annotation_items: vec![],
|
||||||
annotation_set_lists: vec![],
|
annotation_set_lists: vec![],
|
||||||
debug_info_items: vec![],
|
debug_info_items: vec![],
|
||||||
|
corrected_class_data_offset: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1440,6 +1457,7 @@ impl DexWriter {
|
||||||
}
|
}
|
||||||
self.section_manager
|
self.section_manager
|
||||||
.add_elt(Section::ClassDataItem, Some(data.size()));
|
.add_elt(Section::ClassDataItem, Some(data.size()));
|
||||||
|
assert_eq!(data.size(), data.serialize_to_vec().unwrap().len());
|
||||||
self.class_data_list.push(data);
|
self.class_data_list.push(data);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -2171,8 +2189,10 @@ impl DexWriter {
|
||||||
///
|
///
|
||||||
/// # Warning
|
/// # Warning
|
||||||
///
|
///
|
||||||
/// All sections must be generated (but not necessarely linked) before generating the map list.
|
/// All sections must be generated (but not linked) before generating the map list.
|
||||||
fn get_map_list(&mut self) -> Result<()> {
|
///
|
||||||
|
/// This method switch the section manager from edit mode to read only.
|
||||||
|
fn gen_map_list(&mut self) -> Result<()> {
|
||||||
debug!("Generate the map_list");
|
debug!("Generate the map_list");
|
||||||
// Get the size of a map item
|
// Get the size of a map item
|
||||||
let map_item_size = 12; /* = MapItem {
|
let map_item_size = 12; /* = MapItem {
|
||||||
|
|
@ -2192,6 +2212,8 @@ impl DexWriter {
|
||||||
.incr_section_size(Section::MapList, map_item_size);
|
.incr_section_size(Section::MapList, map_item_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// All sections are knowns and should not be eddited anymore
|
||||||
|
self.section_manager.finalize_sections();
|
||||||
for section in Section::VARIANT_LIST {
|
for section in Section::VARIANT_LIST {
|
||||||
if !section.is_data() && self.section_manager.get_nb_elt(*section) != 0 {
|
if !section.is_data() && self.section_manager.get_nb_elt(*section) != 0 {
|
||||||
/*
|
/*
|
||||||
|
|
@ -2292,8 +2314,15 @@ impl DexWriter {
|
||||||
for class_def in self.class_defs_list.iter_mut() {
|
for class_def in self.class_defs_list.iter_mut() {
|
||||||
// prelink value is set to offset in the section + 1 (to distinguish with 0)
|
// prelink value is set to offset in the section + 1 (to distinguish with 0)
|
||||||
if class_def.class_data_off != 0 {
|
if class_def.class_data_off != 0 {
|
||||||
class_def.class_data_off +=
|
let unlinked_local_offset = class_def.class_data_off - 1;
|
||||||
self.section_manager.get_offset(Section::ClassDataItem) - 1;
|
let linked_local_offset = *self
|
||||||
|
.corrected_class_data_offset
|
||||||
|
.get(&unlinked_local_offset)
|
||||||
|
.expect(
|
||||||
|
"Unlinked class_data_item offset not found in corrected_class_data_offset",
|
||||||
|
);
|
||||||
|
class_def.class_data_off =
|
||||||
|
self.section_manager.get_offset(Section::ClassDataItem) + linked_local_offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2320,7 +2349,10 @@ impl DexWriter {
|
||||||
/// Linking can only occur once all sections are entirelly generated.
|
/// Linking can only occur once all sections are entirelly generated.
|
||||||
fn link_code_item(&mut self) {
|
fn link_code_item(&mut self) {
|
||||||
debug!("Link the code_item entries in class_data_items");
|
debug!("Link the code_item entries in class_data_items");
|
||||||
|
let mut unlinked_local_offset = 0;
|
||||||
|
let mut linked_local_offset = 0;
|
||||||
for data in &mut self.class_data_list {
|
for data in &mut self.class_data_list {
|
||||||
|
let unlinked_size = data.size() as u32;
|
||||||
for method in &mut data.direct_methods {
|
for method in &mut data.direct_methods {
|
||||||
if method.code_off.0 != 0 {
|
if method.code_off.0 != 0 {
|
||||||
method.code_off.0 += self.section_manager.get_offset(Section::CodeItem) - 1;
|
method.code_off.0 += self.section_manager.get_offset(Section::CodeItem) - 1;
|
||||||
|
|
@ -2331,6 +2363,13 @@ impl DexWriter {
|
||||||
method.code_off.0 += self.section_manager.get_offset(Section::CodeItem) - 1;
|
method.code_off.0 += self.section_manager.get_offset(Section::CodeItem) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
linked_local_offset += data.size() as u32;
|
||||||
|
self.corrected_class_data_offset
|
||||||
|
.insert(unlinked_local_offset, linked_local_offset);
|
||||||
|
unlinked_local_offset += unlinked_size;
|
||||||
|
// TODO: update section manager even if read only? seams like a bad idea but
|
||||||
|
// this invalidate the size of the section and the offset of the hidden api
|
||||||
|
// section
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2411,114 +2450,152 @@ impl DexWriter {
|
||||||
}
|
}
|
||||||
self.gen_type_list_section()?;
|
self.gen_type_list_section()?;
|
||||||
|
|
||||||
self.get_map_list()?;
|
self.gen_map_list()?;
|
||||||
|
|
||||||
// From now on, all section are generated and the value in section_manager do not change.
|
// From now on, all section are generated and the value in section_manager do not change,
|
||||||
|
// except for class data items, because F (see doc of self.corrected_class_data_offset).
|
||||||
|
|
||||||
|
// start by linking class_data_items to populate self.corrected_class_data_offset
|
||||||
|
// TODO: reorganize this: group by referenced structures instead of grouping by referencer.
|
||||||
|
// this would make it easier handle the class data structure incident.
|
||||||
|
self.link_code_item();
|
||||||
self.link_header();
|
self.link_header();
|
||||||
self.link_call_site_ids();
|
self.link_call_site_ids();
|
||||||
self.link_type_list_occurences()?;
|
self.link_type_list_occurences()?;
|
||||||
self.link_class_data_occurences();
|
self.link_class_data_occurences();
|
||||||
self.link_static_values();
|
self.link_static_values();
|
||||||
self.link_code_item();
|
|
||||||
self.link_debug_info();
|
self.link_debug_info();
|
||||||
self.link_annotations();
|
self.link_annotations();
|
||||||
|
|
||||||
debug!("Serialize the dex file");
|
debug!("Serialize the dex file");
|
||||||
let mut buffer = Cursor::new(Vec::<u8>::new());
|
let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||||
// TODO: compute checksum, hash, ect
|
|
||||||
|
self.check_section_offset(&buffer, Section::HeaderItem);
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::HeaderItem)?;
|
||||||
self.header.serialize(&mut buffer)?;
|
self.header.serialize(&mut buffer)?;
|
||||||
// StringIdItem section
|
// StringIdItem section
|
||||||
let mut string_off = self.section_manager.get_offset(Section::StringDataItem);
|
let mut string_off = self.section_manager.get_offset(Section::StringDataItem);
|
||||||
|
self.check_section_offset(&buffer, Section::StringIdItem);
|
||||||
for string in self.string_data_list.iter() {
|
for string in self.string_data_list.iter() {
|
||||||
let str_id = StringIdItem {
|
let str_id = StringIdItem {
|
||||||
string_data_off: string_off,
|
string_data_off: string_off,
|
||||||
};
|
};
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::StringIdItem)?;
|
||||||
str_id.serialize(&mut buffer)?;
|
str_id.serialize(&mut buffer)?;
|
||||||
string_off += string.size() as u32;
|
string_off += string.size() as u32;
|
||||||
}
|
}
|
||||||
// TypeId section
|
// TypeId section
|
||||||
|
self.check_section_offset(&buffer, Section::TypeIdItem);
|
||||||
for ty in &self.type_ids_list {
|
for ty in &self.type_ids_list {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::TypeIdItem)?;
|
||||||
ty.serialize(&mut buffer)?;
|
ty.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// ProtoId section
|
// ProtoId section
|
||||||
|
self.check_section_offset(&buffer, Section::ProtoIdItem);
|
||||||
for proto in &self.proto_ids_list {
|
for proto in &self.proto_ids_list {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::ProtoIdItem)?;
|
||||||
proto.serialize(&mut buffer)?;
|
proto.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// FieldIdItem section
|
// FieldIdItem section
|
||||||
|
self.check_section_offset(&buffer, Section::FieldIdItem);
|
||||||
for field_id in &self.field_ids_list {
|
for field_id in &self.field_ids_list {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::FieldIdItem)?;
|
||||||
field_id.serialize(&mut buffer)?;
|
field_id.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// MethodIdItem section
|
// MethodIdItem section
|
||||||
|
self.check_section_offset(&buffer, Section::MethodIdItem);
|
||||||
for method_id in &self.method_ids_list {
|
for method_id in &self.method_ids_list {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::MethodIdItem)?;
|
||||||
method_id.serialize(&mut buffer)?;
|
method_id.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// ClassDefItem section
|
// ClassDefItem section
|
||||||
|
self.check_section_offset(&buffer, Section::ClassDefItem);
|
||||||
for class_def in &self.class_defs_list {
|
for class_def in &self.class_defs_list {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::ClassDefItem)?;
|
||||||
class_def.serialize(&mut buffer)?;
|
class_def.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// CallSiteIdItem, data are inserted as encoded array item later
|
// CallSiteIdItem, data are inserted as encoded array item later
|
||||||
|
self.check_section_offset(&buffer, Section::CallSiteIdItem);
|
||||||
for call_site_id in &self.call_site_ids {
|
for call_site_id in &self.call_site_ids {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::CallSiteIdItem)?;
|
||||||
call_site_id.serialize(&mut buffer)?;
|
call_site_id.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MethodHandleItem section
|
// MethodHandleItem section
|
||||||
|
self.check_section_offset(&buffer, Section::MethodHandleItem);
|
||||||
for handle in &self.method_handles {
|
for handle in &self.method_handles {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::MethodHandleItem)?;
|
||||||
handle.serialize(&mut buffer)?;
|
handle.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// MapList
|
// MapList
|
||||||
|
self.check_section_offset(&buffer, Section::MapList);
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::MapList)?;
|
||||||
self.map_list.serialize(&mut buffer)?;
|
self.map_list.serialize(&mut buffer)?;
|
||||||
// TypeList,
|
// TypeList,
|
||||||
let mut offset = 0; // the sections are always aligned until the type_lists
|
self.check_section_offset(&buffer, Section::TypeList);
|
||||||
for (list, _) in &self.type_lists_with_offset {
|
for (list, _) in &self.type_lists_with_offset {
|
||||||
while offset % 4 != 0 {
|
Self::fix_section_alignement(&mut buffer, Section::TypeList)?;
|
||||||
offset += 1;
|
|
||||||
0u8.serialize(&mut buffer)?;
|
|
||||||
}
|
|
||||||
offset += list.size();
|
|
||||||
list.serialize(&mut buffer)?;
|
list.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// The next section requires alignment to 4
|
|
||||||
while offset % 4 != 0 {
|
|
||||||
// Alignment
|
|
||||||
self.section_manager.incr_section_size(Section::TypeList, 1);
|
|
||||||
offset += 1;
|
|
||||||
}
|
|
||||||
// AnnotationSetRefList section
|
// AnnotationSetRefList section
|
||||||
|
self.check_section_offset(&buffer, Section::AnnotationSetRefList);
|
||||||
for list in &self.annotation_set_lists {
|
for list in &self.annotation_set_lists {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::AnnotationSetRefList)?;
|
||||||
list.serialize(&mut buffer)?;
|
list.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// AnnotationSetItem section
|
// AnnotationSetItem section
|
||||||
|
self.check_section_offset(&buffer, Section::AnnotationSetItem);
|
||||||
for set in &self.annotation_set_items {
|
for set in &self.annotation_set_items {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::AnnotationSetItem)?;
|
||||||
set.serialize(&mut buffer)?;
|
set.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// ClassDataItem section
|
|
||||||
for data in &self.class_data_list {
|
|
||||||
data.serialize(&mut buffer)?;
|
|
||||||
}
|
|
||||||
// CodeItem section
|
// CodeItem section
|
||||||
|
self.check_section_offset(&buffer, Section::CodeItem);
|
||||||
for code_item in &self.code_items {
|
for code_item in &self.code_items {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::CodeItem)?;
|
||||||
code_item.serialize(&mut buffer)?
|
code_item.serialize(&mut buffer)?
|
||||||
}
|
}
|
||||||
|
// StringDataItem section
|
||||||
|
self.check_section_offset(&buffer, Section::StringDataItem);
|
||||||
for string in &self.string_data_list {
|
for string in &self.string_data_list {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::StringDataItem)?;
|
||||||
string.serialize(&mut buffer)?;
|
string.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// DebugInfoItem section
|
// DebugInfoItem section
|
||||||
|
self.check_section_offset(&buffer, Section::DebugInfoItem);
|
||||||
for debug_info in &self.debug_info_items {
|
for debug_info in &self.debug_info_items {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::DebugInfoItem)?;
|
||||||
debug_info.serialize(&mut buffer)?;
|
debug_info.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// AnnotationItem section
|
// AnnotationItem section
|
||||||
|
self.check_section_offset(&buffer, Section::AnnotationItem);
|
||||||
for annot in &self.annotation_items {
|
for annot in &self.annotation_items {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::AnnotationItem)?;
|
||||||
annot.serialize(&mut buffer)?;
|
annot.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// EncodedArrayItem section
|
// EncodedArrayItem section
|
||||||
|
self.check_section_offset(&buffer, Section::EncodedArrayItem);
|
||||||
for array in &self.encoded_array_items {
|
for array in &self.encoded_array_items {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::EncodedArrayItem)?;
|
||||||
array.serialize(&mut buffer)?;
|
array.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
// AnnotationsDirectoryItem section
|
// AnnotationsDirectoryItem section
|
||||||
|
self.check_section_offset(&buffer, Section::AnnotationsDirectoryItem);
|
||||||
for dir in &self.annotations_directory_items {
|
for dir in &self.annotations_directory_items {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::AnnotationsDirectoryItem)?;
|
||||||
dir.serialize(&mut buffer)?;
|
dir.serialize(&mut buffer)?;
|
||||||
}
|
}
|
||||||
|
// ClassDataItem section
|
||||||
|
self.check_section_offset(&buffer, Section::ClassDataItem);
|
||||||
|
for data in &self.class_data_list {
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::ClassDataItem)?;
|
||||||
|
data.serialize(&mut buffer)?;
|
||||||
|
}
|
||||||
// TODO: HiddenapiClassDataItem,
|
// TODO: HiddenapiClassDataItem,
|
||||||
|
/*
|
||||||
|
self.check_section_offset(&buffer, Section::HiddenapiClassDataItem);
|
||||||
|
Self::fix_section_alignement(&mut buffer, Section::HiddenapiClassDataItem)?;
|
||||||
|
*/
|
||||||
|
|
||||||
// compute signature
|
// compute signature
|
||||||
buffer.seek(SeekFrom::Start(8 + 4 + 20))?;
|
buffer.seek(SeekFrom::Start(8 + 4 + 20))?;
|
||||||
|
|
@ -2543,6 +2620,29 @@ impl DexWriter {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert 0 to a buffer until the right alignment is reached for an element of the
|
||||||
|
/// given section.
|
||||||
|
fn fix_section_alignement(buffer: &mut Cursor<Vec<u8>>, section: Section) -> Result<()> {
|
||||||
|
while buffer.position() % section.get_item_alignment() as u64 != 0 {
|
||||||
|
0u8.serialize(buffer)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a section
|
||||||
|
fn check_section_offset<T>(&self, buffer: &Cursor<T>, section: Section) {
|
||||||
|
let mut pos = buffer.position();
|
||||||
|
while pos % section.get_item_alignment() as u64 != 0 {
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
let expected = self.section_manager.get_offset(section) as u64;
|
||||||
|
assert_eq!(
|
||||||
|
pos, expected,
|
||||||
|
"Computed section offset and actual section offset do not match for section \
|
||||||
|
{section:?}, expected 0x{expected:x}, found 0x{pos:x}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute the order of the classes in the section `class_defs`.
|
/// Compute the order of the classes in the section `class_defs`.
|
||||||
/// Class definitions must be sorted so that a class's superclass and interfaces
|
/// Class definitions must be sorted so that a class's superclass and interfaces
|
||||||
/// are before the class.
|
/// are before the class.
|
||||||
|
|
@ -2641,7 +2741,6 @@ enum Section {
|
||||||
TypeList,
|
TypeList,
|
||||||
AnnotationSetRefList,
|
AnnotationSetRefList,
|
||||||
AnnotationSetItem,
|
AnnotationSetItem,
|
||||||
ClassDataItem,
|
|
||||||
CodeItem,
|
CodeItem,
|
||||||
StringDataItem,
|
StringDataItem,
|
||||||
DebugInfoItem,
|
DebugInfoItem,
|
||||||
|
|
@ -2649,6 +2748,7 @@ enum Section {
|
||||||
EncodedArrayItem,
|
EncodedArrayItem,
|
||||||
AnnotationsDirectoryItem,
|
AnnotationsDirectoryItem,
|
||||||
HiddenapiClassDataItem,
|
HiddenapiClassDataItem,
|
||||||
|
ClassDataItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Section {
|
impl Section {
|
||||||
|
|
@ -2667,13 +2767,14 @@ impl Section {
|
||||||
Self::TypeList,
|
Self::TypeList,
|
||||||
Self::AnnotationSetRefList,
|
Self::AnnotationSetRefList,
|
||||||
Self::AnnotationSetItem,
|
Self::AnnotationSetItem,
|
||||||
Self::ClassDataItem,
|
|
||||||
Self::CodeItem,
|
Self::CodeItem,
|
||||||
Self::StringDataItem,
|
Self::StringDataItem,
|
||||||
Self::DebugInfoItem,
|
Self::DebugInfoItem,
|
||||||
Self::AnnotationItem,
|
Self::AnnotationItem,
|
||||||
Self::EncodedArrayItem,
|
Self::EncodedArrayItem,
|
||||||
Self::AnnotationsDirectoryItem,
|
Self::AnnotationsDirectoryItem,
|
||||||
|
Self::ClassDataItem, // must be last because contains offsets in Uleb,
|
||||||
|
// so size change when linking !
|
||||||
Self::HiddenapiClassDataItem,
|
Self::HiddenapiClassDataItem,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -2693,13 +2794,13 @@ impl Section {
|
||||||
Self::TypeList => 11,
|
Self::TypeList => 11,
|
||||||
Self::AnnotationSetRefList => 12,
|
Self::AnnotationSetRefList => 12,
|
||||||
Self::AnnotationSetItem => 13,
|
Self::AnnotationSetItem => 13,
|
||||||
Self::ClassDataItem => 14,
|
Self::CodeItem => 14,
|
||||||
Self::CodeItem => 15,
|
Self::StringDataItem => 15,
|
||||||
Self::StringDataItem => 16,
|
Self::DebugInfoItem => 16,
|
||||||
Self::DebugInfoItem => 17,
|
Self::AnnotationItem => 17,
|
||||||
Self::AnnotationItem => 18,
|
Self::EncodedArrayItem => 18,
|
||||||
Self::EncodedArrayItem => 19,
|
Self::AnnotationsDirectoryItem => 19,
|
||||||
Self::AnnotationsDirectoryItem => 20,
|
Self::ClassDataItem => 20,
|
||||||
Self::HiddenapiClassDataItem => 21,
|
Self::HiddenapiClassDataItem => 21,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2748,6 +2849,34 @@ impl Section {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the previous section if it exist.
|
||||||
|
fn prev(&self) -> Option<Self> {
|
||||||
|
match self {
|
||||||
|
Self::HeaderItem => None,
|
||||||
|
Self::StringIdItem => Some(Self::HeaderItem),
|
||||||
|
Self::TypeIdItem => Some(Self::StringIdItem),
|
||||||
|
Self::ProtoIdItem => Some(Self::TypeIdItem),
|
||||||
|
Self::FieldIdItem => Some(Self::ProtoIdItem),
|
||||||
|
Self::MethodIdItem => Some(Self::FieldIdItem),
|
||||||
|
Self::ClassDefItem => Some(Self::MethodIdItem),
|
||||||
|
Self::CallSiteIdItem => Some(Self::ClassDefItem),
|
||||||
|
Self::MethodHandleItem => Some(Self::CallSiteIdItem),
|
||||||
|
Self::Data => Some(Self::MethodHandleItem),
|
||||||
|
Self::MapList => Some(Self::MethodHandleItem), // Data is just an indicator
|
||||||
|
Self::TypeList => Some(Self::MapList),
|
||||||
|
Self::AnnotationSetRefList => Some(Self::TypeList),
|
||||||
|
Self::AnnotationSetItem => Some(Self::AnnotationSetRefList),
|
||||||
|
Self::CodeItem => Some(Self::AnnotationSetItem),
|
||||||
|
Self::StringDataItem => Some(Self::CodeItem),
|
||||||
|
Self::DebugInfoItem => Some(Self::StringDataItem),
|
||||||
|
Self::AnnotationItem => Some(Self::DebugInfoItem),
|
||||||
|
Self::EncodedArrayItem => Some(Self::AnnotationItem),
|
||||||
|
Self::AnnotationsDirectoryItem => Some(Self::EncodedArrayItem),
|
||||||
|
Self::ClassDataItem => Some(Self::AnnotationsDirectoryItem),
|
||||||
|
Self::HiddenapiClassDataItem => Some(Self::ClassDataItem),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_map_item_type(&self) -> MapItemType {
|
fn get_map_item_type(&self) -> MapItemType {
|
||||||
match self {
|
match self {
|
||||||
Self::HeaderItem => MapItemType::HeaderItem,
|
Self::HeaderItem => MapItemType::HeaderItem,
|
||||||
|
|
@ -2764,17 +2893,45 @@ impl Section {
|
||||||
Self::TypeList => MapItemType::TypeList,
|
Self::TypeList => MapItemType::TypeList,
|
||||||
Self::AnnotationSetRefList => MapItemType::AnnotationSetRefList,
|
Self::AnnotationSetRefList => MapItemType::AnnotationSetRefList,
|
||||||
Self::AnnotationSetItem => MapItemType::AnnotationSetItem,
|
Self::AnnotationSetItem => MapItemType::AnnotationSetItem,
|
||||||
Self::ClassDataItem => MapItemType::ClassDataItem,
|
|
||||||
Self::CodeItem => MapItemType::CodeItem,
|
Self::CodeItem => MapItemType::CodeItem,
|
||||||
Self::StringDataItem => MapItemType::StringDataItem,
|
Self::StringDataItem => MapItemType::StringDataItem,
|
||||||
Self::DebugInfoItem => MapItemType::DebugInfoItem,
|
Self::DebugInfoItem => MapItemType::DebugInfoItem,
|
||||||
Self::AnnotationItem => MapItemType::AnnotationItem,
|
Self::AnnotationItem => MapItemType::AnnotationItem,
|
||||||
Self::EncodedArrayItem => MapItemType::EncodedArrayItem,
|
Self::EncodedArrayItem => MapItemType::EncodedArrayItem,
|
||||||
Self::AnnotationsDirectoryItem => MapItemType::AnnotationsDirectoryItem,
|
Self::AnnotationsDirectoryItem => MapItemType::AnnotationsDirectoryItem,
|
||||||
|
Self::ClassDataItem => MapItemType::ClassDataItem,
|
||||||
Self::HiddenapiClassDataItem => MapItemType::HiddenapiClassDataItem,
|
Self::HiddenapiClassDataItem => MapItemType::HiddenapiClassDataItem,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the alignment of the item in byte.
|
||||||
|
fn get_item_alignment(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::HeaderItem => 4,
|
||||||
|
Self::StringIdItem => 4,
|
||||||
|
Self::TypeIdItem => 4,
|
||||||
|
Self::ProtoIdItem => 4,
|
||||||
|
Self::FieldIdItem => 4,
|
||||||
|
Self::MethodIdItem => 4,
|
||||||
|
Self::ClassDefItem => 4,
|
||||||
|
Self::CallSiteIdItem => 1,
|
||||||
|
Self::MethodHandleItem => 4,
|
||||||
|
Self::Data => 1,
|
||||||
|
Self::MapList => 4,
|
||||||
|
Self::TypeList => 4,
|
||||||
|
Self::AnnotationSetRefList => 4,
|
||||||
|
Self::AnnotationSetItem => 4,
|
||||||
|
Self::CodeItem => 4,
|
||||||
|
Self::StringDataItem => 1,
|
||||||
|
Self::DebugInfoItem => 1,
|
||||||
|
Self::AnnotationItem => 1,
|
||||||
|
Self::EncodedArrayItem => 1,
|
||||||
|
Self::AnnotationsDirectoryItem => 4,
|
||||||
|
Self::ClassDataItem => 1,
|
||||||
|
Self::HiddenapiClassDataItem => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_data(&self) -> bool {
|
fn is_data(&self) -> bool {
|
||||||
matches!(self, Self::Data)
|
matches!(self, Self::Data)
|
||||||
}
|
}
|
||||||
|
|
@ -2784,6 +2941,7 @@ impl Section {
|
||||||
struct SectionManager {
|
struct SectionManager {
|
||||||
sizes: [u32; Self::NB_SECTION],
|
sizes: [u32; Self::NB_SECTION],
|
||||||
nb_elt: [usize; Self::NB_SECTION],
|
nb_elt: [usize; Self::NB_SECTION],
|
||||||
|
editable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SectionManager {
|
impl SectionManager {
|
||||||
|
|
@ -2791,28 +2949,47 @@ impl SectionManager {
|
||||||
|
|
||||||
fn reset(&mut self) {
|
fn reset(&mut self) {
|
||||||
self.sizes = [0; Self::NB_SECTION];
|
self.sizes = [0; Self::NB_SECTION];
|
||||||
self.nb_elt = [0; Self::NB_SECTION]
|
self.nb_elt = [0; Self::NB_SECTION];
|
||||||
|
self.editable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_elt(&mut self, section: Section, size: Option<usize>) {
|
fn add_elt(&mut self, section: Section, size: Option<usize>) {
|
||||||
|
if !self.editable {
|
||||||
|
panic!("Try to modify a section when the sections are set to read only");
|
||||||
|
}
|
||||||
if section.is_data() {
|
if section.is_data() {
|
||||||
panic!("Cannot add element directly in section data");
|
panic!("Cannot add element directly in section data");
|
||||||
}
|
}
|
||||||
|
while self.sizes[section.get_index()] % section.get_item_alignment() != 0 {
|
||||||
|
self.sizes[section.get_index()] += 1;
|
||||||
|
}
|
||||||
self.sizes[section.get_index()] += section.get_elt_size(size) as u32;
|
self.sizes[section.get_index()] += section.get_elt_size(size) as u32;
|
||||||
self.nb_elt[section.get_index()] += 1;
|
self.nb_elt[section.get_index()] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn incr_section_size(&mut self, section: Section, size: usize) {
|
fn incr_section_size(&mut self, section: Section, size: usize) {
|
||||||
|
if !self.editable {
|
||||||
|
panic!("Try to modify a section when the sections are set to read only");
|
||||||
|
}
|
||||||
self.sizes[section.get_index()] += size as u32;
|
self.sizes[section.get_index()] += size as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_offset(&self, section: Section) -> u32 {
|
fn get_offset(&self, section: Section) -> u32 {
|
||||||
// TODO: check alignment
|
if self.editable {
|
||||||
self.sizes[..section.get_index()].iter().sum()
|
panic!("Try to get section offset before sections are finilized");
|
||||||
|
}
|
||||||
|
let size = self.sizes[..section.get_index()].iter().sum();
|
||||||
|
let alignment = section.get_item_alignment();
|
||||||
|
if size % alignment != 0 {
|
||||||
|
panic!(
|
||||||
|
"section {section:?} must be aligned on {alignment} bytes, \
|
||||||
|
found section offset 0x{size:x}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
size
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(&self, section: Section) -> u32 {
|
fn get_size(&self, section: Section) -> u32 {
|
||||||
// TODO: check alignment
|
|
||||||
if section.is_data() {
|
if section.is_data() {
|
||||||
self.sizes[section.get_index()..].iter().sum()
|
self.sizes[section.get_index()..].iter().sum()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2823,4 +3000,41 @@ impl SectionManager {
|
||||||
fn get_nb_elt(&self, section: Section) -> usize {
|
fn get_nb_elt(&self, section: Section) -> usize {
|
||||||
self.nb_elt[section.get_index()]
|
self.nb_elt[section.get_index()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finialize the sections: switch to read only and fix the section alignment.
|
||||||
|
fn finalize_sections(&mut self) {
|
||||||
|
for section in Section::VARIANT_LIST {
|
||||||
|
while self.sizes[..section.get_index()].iter().sum::<u32>()
|
||||||
|
% section.get_item_alignment()
|
||||||
|
!= 0
|
||||||
|
{
|
||||||
|
self.incr_section_size(
|
||||||
|
section.prev().expect(
|
||||||
|
"First section (Header) should alway be aligned but \
|
||||||
|
found unaligned section without predecessor",
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.editable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Display the sections informations.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn show(&self) {
|
||||||
|
let mut offset = 0;
|
||||||
|
for section in Section::VARIANT_LIST {
|
||||||
|
let size = self.get_size(*section);
|
||||||
|
let new_offset = offset + size;
|
||||||
|
let nb_elt = self.get_nb_elt(*section);
|
||||||
|
println!(
|
||||||
|
"{section:?}: 0x{offset:x} -> 0x{new_offset:x} (size: 0x{size:x}, \
|
||||||
|
nb elt: {nb_elt})"
|
||||||
|
);
|
||||||
|
if !section.is_data() {
|
||||||
|
offset = new_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue