java_asm/dex/
raw.rs

1use crate::dex::insn::DexInsn;
2use crate::impls::jvms::r::U32BasedSize;
3use crate::StrRef;
4use java_asm_macro::ReadFrom;
5
6#[derive(Clone, Debug, Eq, PartialEq)]
7pub struct DexFile {
8    pub header: Header,
9    pub string_ids: Vec<StringId>,
10    pub type_ids: Vec<TypeId>,
11    pub proto_ids: Vec<ProtoId>,
12    pub field_ids: Vec<FieldId>,
13    pub method_ids: Vec<MethodId>,
14    pub class_defs: Vec<ClassDef>,
15    // we don't need to save the actual data chunk, every data item is indexed by
16    // using the offset from the start of the file.
17    // 
18    // pub call_site_ids: Vec<CallSiteId>,
19    // pub method_handles: Vec<MethodHandle>,
20    // pub data: Vec<u8>,
21    // pub link_data: Vec<u8>,
22}
23
24#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
25#[align(4)]
26pub struct Header {
27    /// should be "dex\n039\0", and 039 is the dex version number
28    pub magic: [u8; 8],
29    /// adler32 checksum of the rest of the file (everything except magic and this field)
30    pub checksum: DUInt,
31    /// SHA-1 hash of the rest of the file (everything except magic, checksum, and this field)
32    pub signature: [u8; 20], 
33    /// size of the entire file (including the header), in bytes
34    pub file_size: DUInt,
35    /// length of this section
36    pub header_size: DUInt,
37    /// [Header::LITTLE_ENDIAN_TAG] or [Header::BIG_ENDIAN_TAG]
38    pub endian_tag: DUInt,
39    /// size of the link section, or 0 if this file isn't statically linked
40    pub link_size: DUInt,
41    /// offset from the start of the file to the link section, or 0 if link_size == 0
42    pub link_off: DUInt, 
43    /// offset from the start of the file to the data chunk with `map_item` format
44    pub map_off: DUInt,
45    /// count of StringId items
46    pub string_ids_size: U32BasedSize,
47    /// offset from the start of the file to the StringId items
48    pub string_ids_off: DUInt,
49    /// count of TypeId items, at most 65535
50    pub type_ids_size: U32BasedSize,   
51    pub type_ids_off: DUInt,
52    /// count of ProtoId items, at most 65535
53    pub proto_ids_size: U32BasedSize, 
54    pub proto_ids_off: DUInt,
55    /// count of FieldId items
56    pub field_ids_size: U32BasedSize,
57    pub field_ids_off: DUInt,
58    pub method_ids_size: U32BasedSize,
59    pub method_ids_off: DUInt,
60    pub class_defs_size: U32BasedSize,
61    pub class_defs_off: DUInt,
62    /// size of the data section, must be an even multiple of sizeof(uint)
63    pub data_size: U32BasedSize, 
64    pub data_off: DUInt,
65}
66
67impl Header {
68    pub const LITTLE_ENDIAN_TAG: u32 = 0x12345678;
69    pub const BIG_ENDIAN_TAG: u32 = 0x78563412;
70}
71
72#[derive(Clone, Debug, Eq, PartialEq, ReadFrom, Default)]
73#[align(4)]
74pub struct MapList {
75    pub size: U32BasedSize,
76    #[index(size)]
77    pub items: Vec<MapItem>,
78}
79
80#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
81pub struct MapItem {
82    /// defined in [crate::dex::constant::MapListTypeConst]
83    pub type_value: DUShort,
84    pub unused: DUShort, // reserved
85    /// count of items to be found at the specified offset
86    pub size: U32BasedSize,
87    pub offset: DUInt, // offset from the start of the file
88}
89
90#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
91#[align(4)]
92pub struct StringId {
93    /// [StringData], offset from the start of the file
94    pub string_data_off: DUInt,
95}
96
97#[derive(Clone, Debug, Eq, PartialEq)]
98pub struct StringData {
99    /// The size of the string, in UTF-16 code units, this is the decoded length of the string,
100    /// and the encoded length is implied by position of `\0` in the data. (because the MUTF-8
101    /// format will not include a `\0` in the encoded data)
102    pub utf16_size: DULeb128,
103    /// decoded string.
104    pub str_ref: StrRef,
105}
106
107#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
108#[align(4)]
109pub struct TypeId {
110    pub descriptor_idx: U32BasedSize, // index into `string_ids` for the descriptor string
111}
112
113#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
114#[align(4)]
115pub struct ProtoId {
116    pub shorty_idx: U32BasedSize,      // index into `string_ids` for shorty descriptor
117    pub return_type_idx: U32BasedSize, // index into `type_ids` for return type
118    /// [TypeList], offset from the start of the file, 0 if no parameters
119    pub parameters_off: DUInt,
120}
121
122#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
123#[align(4)]
124pub struct FieldId {
125    pub class_idx: DUShort, // index into `type_ids` for the definer
126    pub type_idx: DUShort,  // index into `type_ids` for the type
127    pub name_idx: U32BasedSize,    // index into `string_ids` for the name
128}
129
130#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
131#[align(4)]
132pub struct MethodId {
133    pub class_idx: DUShort, // index into `type_ids` for the definer
134    pub proto_idx: DUShort, // index into `proto_ids` for the prototype
135    pub name_idx: U32BasedSize,    // index into `string_ids` for the name
136}
137
138#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
139#[align(4)]
140pub struct ClassDef {
141    /// index into `type_ids`
142    pub class_idx: U32BasedSize,
143    /// [crate::dex::ClassAccessFlags]
144    pub access_flags: DUInt,
145    /// index into `type_ids`, or NO_INDEX if this class has no superclass
146    pub superclass_idx: U32BasedSize,
147    /// offset from the start of the file to the list of interfaces, or 0 if there are no interfaces
148    /// for this class. Must be an offset of a [TypeList] structure.
149    pub interfaces_off: DUInt,
150    // index into `string_ids` for the source file name, or NO_INDEX
151    pub source_file_idx: U32BasedSize,
152    /// offset from the start of the file to the `annotations_directory_item` or 0 if not present.
153    pub annotations_off: DUInt,
154    /// offset from the start of the file to the [ClassDataItem] or 0 if not present.
155    pub class_data_off: DUInt,
156    /// offset from the start of the file to the list of [EncodedArray], or 0 if not present.
157    /// Same order of the static fields in the `field_list`.
158    pub static_values_off: DUInt,
159}
160
161#[derive(Clone, Debug, Eq, PartialEq, ReadFrom)]
162pub struct ClassDataItem {
163    pub static_fields_size: DULeb128,
164    pub instance_fields_size: DULeb128,
165    pub direct_methods_size: DULeb128,
166    pub virtual_methods_size: DULeb128,
167    #[index(static_fields_size)]
168    pub static_fields: Vec<EncodedField>,
169    #[index(instance_fields_size)]
170    pub instance_fields: Vec<EncodedField>,
171    #[index(direct_methods_size)]
172    pub direct_methods: Vec<EncodedMethod>,
173    #[index(virtual_methods_size)]
174    pub virtual_methods: Vec<EncodedMethod>,
175}
176
177#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
178pub struct EncodedField {
179    /// index into `field_ids`[FieldId], diff with previous encoded field
180    pub field_idx_diff: DULeb128,
181    /// see [crate::dex::FieldAccessFlags]
182    pub access_flags: DULeb128,
183}
184
185#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
186pub struct EncodedMethod {
187    /// index into `method_ids`[MethodId], diff with previous encoded method
188    pub method_idx_diff: DULeb128,
189    /// see [crate::dex::MethodAccessFlags]
190    pub access_flags: DULeb128,
191    /// offset from the start of the file to the [CodeItem],
192    /// or 0 if this method is abstract or native
193    pub code_off: DULeb128,
194}
195
196#[derive(Clone, Debug, Eq, PartialEq)]
197pub struct CodeItem {
198    pub registers_size: DUShort,
199    pub ins_size: DUShort,
200    pub outs_size: DUShort,
201    pub tries_size: DUShort,
202    pub debug_info_off: DUInt,
203    pub insn_container: InsnContainer,
204    pub tries: Vec<TryItem>,
205    pub handlers: EncodedCatchHandlerList,
206}
207
208#[derive(Clone, Debug, Eq, PartialEq)]
209pub struct DebugInfoItem {
210    pub line_start: DULeb128,
211    // -1 -> no name
212    pub parameter_names: Vec<DULeb128P1>,
213    // addr, source line, alternative source file name_idx 
214    pub records: Vec<(DUInt, DUInt, DULeb128P1)>,
215    pub local_vars: Vec<LocalVar>,
216}
217
218#[derive(Copy, Clone, Debug, Eq, PartialEq)]
219pub struct LocalVar {
220    pub register: DULeb128,
221    pub name_idx: DULeb128P1,
222    pub type_idx: DULeb128P1,
223    pub sig_idx: DULeb128P1,
224    pub start_addr: Option<DUInt>,
225    pub end_addr: Option<DUInt>,
226}
227
228#[derive(Clone, Debug, Eq, PartialEq)]
229pub struct InsnContainer {
230    pub insns_size: DUInt,
231    pub insns: Vec<DexInsn>,
232}
233
234#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
235pub struct TryItem {
236    pub start_addr: DUInt,
237    /// The last code unit covered (inclusive) is `start_addr + insn_count - 1`.
238    pub insn_count: DUShort,
239    /// offset in bytes from the start of the associated `encoded_catch_hander_list` 
240    /// to the `encoded_catch_handler`
241    pub handler_off: DUShort,
242}
243
244#[derive(Clone, Debug, Eq, PartialEq, ReadFrom, Default)]
245pub struct EncodedCatchHandlerList {
246    pub size: DULeb128,
247    #[index(size)]
248    pub list: Vec<EncodedCatchHandler>,
249}
250
251#[derive(Clone, Debug, Eq, PartialEq)]
252pub struct EncodedCatchHandler {
253    pub size: DSleb128,
254    pub handlers: Vec<EncodedTypeAddrPair>,
255    pub catch_all_addr: Option<DULeb128>,
256}
257
258#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
259pub struct EncodedTypeAddrPair {
260    pub type_idx: DULeb128,
261    pub addr: DULeb128,
262}
263
264#[derive(Clone, Debug, Eq, PartialEq, ReadFrom)]
265#[align(4)]
266pub struct TypeList {
267    pub size: U32BasedSize,
268    #[index(size)]
269    pub type_id_indices: Vec<DUShort>, // index into `type_ids`
270}
271
272#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
273#[align(4)]
274pub struct CallSiteId {
275    /// offset from the start of the file to the `call_site_item`
276    pub call_site_off: DUInt,
277}
278
279/// The call site item is an encoded array of the following form:
280/// 1. A method handle representing the bootstrap linker method (VALUE_METHOD_HANDLE).
281/// 2. A method name that the bootstrap linker should resolve (VALUE_STRING).
282/// 3. A method type corresponding to the type of the method name to be resolved (VALUE_METHOD_TYPE).
283/// ... Any additional arguments are constant values passed to the bootstrap linker method.
284pub type CallSiteItem = EncodedArray;
285
286#[derive(Clone, Debug, Eq, PartialEq)]
287pub enum EncodedValue {
288    Byte(DByte),
289    Short(DShort),
290    Char(DUShort),
291    Int(DInt),
292    Long(DLong),
293    Float([DUByte; 4]),                 // IEEE754 32-bit
294    Double([DUByte; 8]),                // IEEE754 64-bit
295    MethodType(U32BasedSize),           // index into `proto_ids`
296    MethodHandle(U32BasedSize),         // index into `method_handles`
297    String(U32BasedSize),               // index into `string_ids`
298    Type(U32BasedSize),                 // index into `type_ids`
299    Field(U32BasedSize),                // index into `field_ids`
300    Method(U32BasedSize),               // index into `method_ids`
301    Enum(U32BasedSize),                 // index into `field_ids`
302    Array(EncodedArray),                // `encoded_array`
303    Annotation(EncodedAnnotation),      // `encoded_annotation`
304    Null,
305    Boolean(bool),
306}
307
308#[derive(Clone, Debug, Eq, PartialEq, ReadFrom)]
309pub struct EncodedArray {
310    pub size: DULeb128,
311    #[index(size)]
312    pub values: Vec<EncodedValue>,
313}
314
315#[derive(Clone, Debug, Eq, PartialEq, ReadFrom)]
316pub struct EncodedAnnotation {
317    pub type_idx: DULeb128, // index into `type_ids`
318    pub size: DULeb128,     // size of name-value mappings
319    #[index(size)]
320    pub elements: Vec<EncodedAnnotationAttribute>,
321}
322
323#[derive(Clone, Debug, Eq, PartialEq, ReadFrom)]
324pub struct EncodedAnnotationAttribute {
325    pub name_idx: DULeb128, // index into `string_ids`
326    pub value: EncodedValue,
327}
328
329#[derive(Copy, Clone, Debug, Eq, PartialEq, ReadFrom)]
330#[align(4)]
331pub struct MethodHandle {
332    pub method_handle_type: DUShort,
333    pub unused_stub_0: DUShort, // android reserved, don't know why.
334    pub field_or_method_id: DUShort,
335    pub unused_stub_1: DUShort, // android reserved, don't know why.
336}
337
338// dex types
339pub type DByte = i8;
340pub type DUByte = u8;
341pub type DShort = i16;
342pub type DUShort = u16;
343pub type DInt = i32;
344pub type DUInt = u32;
345pub type DLong = i64;
346pub type DULong = u64;
347
348#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash)]
349pub struct DSleb128(pub(crate) u32);
350#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash)]
351pub struct DULeb128(pub(crate) u32);
352#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash)]
353pub struct DULeb128P1(pub(crate) u32);
354
355pub const NO_INDEX: u32 = 0xFFFFFFFF;
356
357impl DSleb128 {
358    #[inline]
359    pub const fn value(&self) -> i32 {
360        self.0 as i32
361    }
362}
363
364impl DULeb128 {
365    #[inline]
366    pub const fn value(&self) -> u32 {
367        self.0
368    }
369}
370
371impl Into<usize> for DULeb128 {
372    fn into(self) -> usize {
373        self.value() as usize
374    }
375}
376
377impl DULeb128P1 {
378    pub const ZERO: DULeb128P1 = DULeb128P1(0);
379    
380    // -1 usually used for representing null (NO_INDEX in dex format)
381    #[inline]
382    pub const fn value(&self) -> Option<u32> {
383        let internal = self.0;
384        if internal == 0 {
385            None
386        } else {
387            Some(internal - 1)
388        }
389    }
390}