1use getset::{CopyGetters, Getters};
3use num_derive::FromPrimitive;
4use num_traits::FromPrimitive;
5use scroll::{ctx, Pread, Uleb128};
6
7use crate::{
8 annotation::{AnnotationSetItem, AnnotationSetRefList},
9 code::CodeItem,
10 encoded_item::{EncodedItem, EncodedItemArray},
11 error::Error,
12 field::FieldId,
13 jtype::{Type, TypeId},
14 string::{DexString, StringId},
15 uint, ulong, ushort, utils,
16};
17
18bitflags! {
19 pub struct AccessFlags: ulong {
21 const PUBLIC = 0x1;
22 const PRIVATE = 0x2;
23 const PROTECTED = 0x4;
24 const STATIC = 0x8;
25 const FINAL = 0x10;
26 const SYNCHRONIZED = 0x20;
27 const BRIDGE = 0x40;
28 const VARARGS = 0x80;
29 const NATIVE = 0x100;
30 const ABSTRACT = 0x400;
31 const STRICT = 0x800;
32 const SYNTHETIC = 0x1000;
33 const CONSTRUCTOR = 0x10000;
34 const DECLARED_SYNCHRONIZED = 0x20000;
35 }
36}
37
38#[derive(Debug, Getters, CopyGetters)]
40pub struct Method {
41 #[get = "pub"]
43 class: Type,
44 #[get = "pub"]
46 name: DexString,
47 #[get_copy = "pub"]
49 access_flags: AccessFlags,
50 #[get = "pub"]
52 params: Vec<Type>,
53 #[get = "pub"]
56 shorty: DexString,
57 #[get = "pub"]
59 return_type: Type,
60 code: Option<CodeItem>,
62 #[get = "pub"]
64 annotations: AnnotationSetItem,
65 #[get = "pub"]
67 param_annotations: AnnotationSetRefList,
68}
69
70impl Method {
71 gen_is_flag_set!(is_public, PUBLIC);
72 gen_is_flag_set!(is_private, PRIVATE);
73 gen_is_flag_set!(is_protected, PROTECTED);
74 gen_is_flag_set!(is_static, STATIC);
75 gen_is_flag_set!(is_final, FINAL);
76 gen_is_flag_set!(is_synchronized, SYNCHRONIZED);
77 gen_is_flag_set!(is_bridge, BRIDGE);
78 gen_is_flag_set!(is_varargs, VARARGS);
79 gen_is_flag_set!(is_native, NATIVE);
80 gen_is_flag_set!(is_abstract, ABSTRACT);
81 gen_is_flag_set!(is_strict, STRICT);
82 gen_is_flag_set!(is_synthetic, SYNTHETIC);
83 gen_is_flag_set!(is_constructor, CONSTRUCTOR);
84 gen_is_flag_set!(is_declared_synchronized, DECLARED_SYNCHRONIZED);
85
86 pub fn signature(&self) -> super::Result<Option<String>> {
88 utils::get_signature(self.annotations())
89 }
90
91 pub fn code(&self) -> Option<&CodeItem> {
93 self.code.as_ref()
94 }
95}
96
97pub type ProtoId = ulong;
99
100#[derive(Pread, Debug, CopyGetters, PartialEq)]
103#[get_copy = "pub"]
104pub struct ProtoIdItem {
105 shorty: StringId,
107 return_type: TypeId,
109 params_off: uint,
112}
113
114impl ProtoIdItem {
115 pub(crate) fn try_from_dex<S: AsRef<[u8]>>(
116 dex: &super::Dex<S>,
117 offset: ulong,
118 ) -> super::Result<Self> {
119 let source = dex.source.as_ref();
120 Ok(source.pread_with(offset as usize, dex.get_endian())?)
121 }
122}
123
124impl Method {
125 pub(crate) fn try_from_dex<S: AsRef<[u8]>>(
126 dex: &super::Dex<S>,
127 encoded_method: &EncodedMethod,
128 annotations: AnnotationSetItem,
129 param_annotations: AnnotationSetRefList,
130 ) -> super::Result<Method> {
131 debug!(target: "method", "encoded method: {:?}", encoded_method);
132 let source = &dex.source;
133 let method_item = dex.get_method_item(encoded_method.method_id)?;
134 let name = dex.get_string(method_item.name_idx)?;
135 debug!(target: "method", "name: {}, method id item: {:?}", name, method_item);
136 let proto_item = dex.get_proto_item(ProtoId::from(method_item.proto_idx))?;
137 debug!(target: "method", "method proto_item: {:?}", proto_item);
138 let shorty = dex.get_string(proto_item.shorty)?;
139 let return_type = dex.get_type(proto_item.return_type)?;
140 let params = if proto_item.params_off != 0 {
141 if !dex.is_offset_in_data_section(proto_item.params_off) {
142 return Err(Error::BadOffset(
143 proto_item.params_off as usize,
144 format!(
145 "Params offset not in data section for proto_item: {:?}",
146 proto_item
147 ),
148 ));
149 }
150 let offset = &mut (proto_item.params_off as usize);
151 let endian = dex.get_endian();
152 let len = source.gread_with::<uint>(offset, endian)?;
153 let type_ids: Vec<ushort> = try_gread_vec_with!(source, offset, len, endian);
154 utils::get_types(dex, &type_ids)?
155 } else {
156 Default::default()
157 };
158 debug!(target: "method", "code item offset: {}", encoded_method.code_offset);
159 let code = dex.get_code_item(encoded_method.code_offset)?;
160 Ok(Self {
161 name,
162 class: dex.get_type(TypeId::from(method_item.class_idx))?,
163 access_flags: AccessFlags::from_bits(encoded_method.access_flags).ok_or_else(|| {
164 Error::InvalidId(format!(
165 "Invalid access flags for method {}",
166 method_item.name_idx
167 ))
168 })?,
169 shorty,
170 return_type,
171 params,
172 code,
173 annotations,
174 param_annotations,
175 })
176 }
177}
178
179#[derive(Pread, Debug, CopyGetters, PartialEq)]
182#[get_copy = "pub"]
183pub struct MethodIdItem {
184 class_idx: ushort,
186 proto_idx: ushort,
188 name_idx: StringId,
190}
191
192impl MethodIdItem {
193 pub(crate) fn try_from_dex<S: AsRef<[u8]>>(
194 dex: &super::Dex<S>,
195 offset: ulong,
196 ) -> super::Result<Self> {
197 let source = &dex.source;
198 Ok(source.pread_with(offset as usize, dex.get_endian())?)
199 }
200}
201
202pub type MethodId = ulong;
204
205pub type MethodHandleId = uint;
207
208#[derive(Debug, Getters, CopyGetters)]
211pub struct EncodedMethod {
212 #[get_copy = "pub(crate)"]
215 pub(crate) method_id: MethodId,
216 #[get = "pub"]
218 access_flags: ulong,
219 #[get = "pub"]
222 code_offset: ulong,
223}
224
225impl EncodedItem for EncodedMethod {
226 fn id(&self) -> ulong {
227 self.method_id
228 }
229}
230
231pub type EncodedMethodArray = EncodedItemArray<EncodedMethod>;
233
234impl<'a> ctx::TryFromCtx<'a, ulong> for EncodedMethod {
235 type Error = Error;
236 type Size = usize;
237
238 fn try_from_ctx(source: &'a [u8], prev_id: ulong) -> super::Result<(Self, Self::Size)> {
239 let offset = &mut 0;
240 let id = Uleb128::read(source, offset)?;
241 let access_flags = Uleb128::read(source, offset)?;
242 let code_offset = Uleb128::read(source, offset)?;
243 Ok((
244 Self {
245 method_id: prev_id + id,
246 code_offset,
247 access_flags,
248 },
249 *offset,
250 ))
251 }
252}
253
254#[derive(FromPrimitive, Debug, Clone, Copy, PartialEq)]
257pub enum MethodHandleType {
258 StaticPut = 0x00,
259 StaticGet = 0x01,
260 InstancePut = 0x02,
261 InstanceGet = 0x03,
262 InvokeStatic = 0x04,
263 InvokeInstance = 0x05,
264 InvokeConstructor = 0x06,
265 InvokeDirect = 0x07,
266 InvokeInterface = 0x08,
267}
268
269#[derive(Debug, Clone, Copy, PartialEq)]
270pub enum FieldOrMethodId {
271 Field(FieldId),
272 Method(MethodId),
273}
274
275#[derive(Debug, CopyGetters, PartialEq)]
278#[get_copy = "pub"]
279pub struct MethodHandleItem {
280 handle_type: MethodHandleType,
282 id: FieldOrMethodId,
285}
286
287impl<'a, S: AsRef<[u8]>> ctx::TryFromCtx<'a, &super::Dex<S>> for MethodHandleItem {
288 type Error = Error;
289 type Size = usize;
290
291 fn try_from_ctx(source: &'a [u8], dex: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
292 let endian = dex.get_endian();
293 let offset = &mut 0;
294 let handle_type: ushort = source.gread_with(offset, endian)?;
295 let handle_type = MethodHandleType::from_u16(handle_type)
296 .ok_or_else(|| Error::InvalidId(format!("Invalid handle type {}", handle_type)))?;
297 let _: ushort = source.gread_with(offset, endian)?;
298 let id: ushort = source.gread_with(offset, endian)?;
299 let _: ushort = source.gread_with(offset, endian)?;
300 let id = match handle_type {
301 MethodHandleType::StaticPut
302 | MethodHandleType::StaticGet
303 | MethodHandleType::InstancePut
304 | MethodHandleType::InstanceGet => FieldOrMethodId::Field(FieldId::from(id)),
305 _ => FieldOrMethodId::Method(MethodId::from(id)),
306 };
307
308 Ok((Self { handle_type, id }, *offset))
309 }
310}