1use scroll::{ctx, Pread, Uleb128};
3use std::{fmt, ops::Deref};
4
5use getset::{CopyGetters, Getters};
6
7use crate::{
8 encoded_item::EncodedCatchHandlers, error::Error, jtype::Type, string::DexString, uint, ulong,
9 ushort,
10};
11
12#[derive(Debug, Getters, CopyGetters)]
15pub struct DebugInfoItem {
16 #[get_copy = "pub"]
18 line_start: usize,
19 #[get = "pub"]
21 parameter_names: Vec<Option<DexString>>,
22}
23
24#[derive(Getters, CopyGetters)]
26pub struct CodeItem {
27 #[get_copy = "pub"]
29 registers_size: ushort,
30 debug_info_item: Option<DebugInfoItem>,
32 #[get_copy = "pub"]
34 ins_size: ushort,
35 #[get_copy = "pub"]
37 outs_size: ushort,
38 #[get = "pub"]
40 insns: Vec<ushort>,
41 #[get = "pub"]
43 tries: Tries,
44}
45
46impl CodeItem {
47 pub fn debug_info_item(&self) -> Option<&DebugInfoItem> {
49 self.debug_info_item.as_ref()
50 }
51}
52
53impl fmt::Debug for CodeItem {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "CodeItem {{ registers_size: {}, debug_info: {}, ins_size: {}, outs_size: {}, tries: {} }}",
56 self.registers_size, self.debug_info_item.is_some(), self.ins_size, self.outs_size, self.tries.len())
57 }
58}
59
60#[derive(Pread, Clone, Copy, Debug, Getters, CopyGetters)]
62pub(crate) struct TryItem {
63 #[get_copy = "pub"]
65 start_addr: uint,
66 #[get_copy = "pub"]
68 insn_count: ushort,
69 #[get_copy = "pub"]
71 handler_off: ushort,
72}
73
74#[derive(Debug, Clone)]
75pub enum ExceptionType {
76 BaseException,
78 Ty(Type),
80}
81
82#[derive(Debug, Clone, Getters, CopyGetters)]
83pub struct CatchHandler {
84 #[get = "pub"]
86 pub(crate) exception: ExceptionType,
87 #[get_copy = "pub"]
89 pub(crate) addr: ulong,
90}
91
92#[derive(Debug, Getters, CopyGetters)]
94pub struct TryCatchHandlers {
95 #[get_copy = "pub"]
97 start_addr: uint,
98 #[get_copy = "pub"]
100 insn_count: ushort,
101 #[get = "pub"]
103 catch_handlers: Vec<CatchHandler>,
104}
105
106#[derive(Debug, Default, Getters, CopyGetters)]
108pub struct Tries {
109 #[get = "pub"]
110 try_catch_blocks: Vec<TryCatchHandlers>,
111}
112
113impl Deref for Tries {
114 type Target = Vec<TryCatchHandlers>;
115
116 fn deref(&self) -> &Self::Target {
117 &self.try_catch_blocks
118 }
119}
120
121impl<'a, S> ctx::TryFromCtx<'a, (usize, &super::Dex<S>)> for Tries
122where
123 S: AsRef<[u8]>,
124{
125 type Error = Error;
126 type Size = usize;
127
128 fn try_from_ctx(
129 source: &'a [u8],
130 (tries_size, dex): (usize, &super::Dex<S>),
131 ) -> Result<(Self, Self::Size), Self::Error> {
132 let offset = &mut 0;
133 let endian = dex.get_endian();
134 let tries: Vec<TryItem> = try_gread_vec_with!(source, offset, tries_size, endian);
135 let encoded_catch_handlers: EncodedCatchHandlers = source.gread_with(offset, dex)?;
136 let tries: super::Result<Vec<_>> = tries
137 .into_iter()
138 .map(|c| {
139 let encoded_handler =
140 encoded_catch_handlers.find(c.handler_off).ok_or_else(|| {
141 Error::InvalidId(format!("Invalid catch handler: {}", c.handler_off))
142 })?;
143 Ok(TryCatchHandlers {
144 start_addr: c.start_addr,
145 insn_count: c.insn_count,
146 catch_handlers: encoded_handler.handlers(),
147 })
148 })
149 .collect();
150 Ok((
151 Self {
152 try_catch_blocks: tries?,
153 },
154 *offset,
155 ))
156 }
157}
158
159impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for DebugInfoItem
160where
161 S: AsRef<[u8]>,
162{
163 type Error = Error;
164 type Size = usize;
165
166 fn try_from_ctx(
167 source: &'a [u8],
168 dex: &super::Dex<S>,
169 ) -> Result<(Self, Self::Size), Self::Error> {
170 let offset = &mut 0;
171 let line_start = Uleb128::read(source, offset)? as usize;
172 let parameters_size = Uleb128::read(source, offset)?;
173 let mut parameter_names = Vec::with_capacity(parameters_size as usize);
174 for _ in 0..parameters_size {
175 let string_id = Uleb128::read(source, offset)? + 1;
176 parameter_names.push(if string_id != u64::from(crate::NO_INDEX) {
177 Some(dex.get_string(string_id as uint)?)
178 } else {
179 None
180 });
181 }
182 Ok((
183 Self {
184 line_start,
185 parameter_names,
186 },
187 *offset,
188 ))
189 }
190}
191
192impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for CodeItem
193where
194 S: AsRef<[u8]>,
195{
196 type Error = Error;
197 type Size = usize;
198
199 fn try_from_ctx(
200 source: &'a [u8],
201 dex: &super::Dex<S>,
202 ) -> Result<(Self, Self::Size), Self::Error> {
203 let offset = &mut 0;
204 let endian = dex.get_endian();
205 let registers_size: ushort = source.gread_with(offset, endian)?;
206 let ins_size = source.gread_with(offset, endian)?;
207 let outs_size = source.gread_with(offset, endian)?;
208 let tries_size: ushort = source.gread_with(offset, endian)?;
209 let debug_info_off = source.gread_with(offset, endian)?;
210 let debug_info_item = if debug_info_off != 0 {
211 Some(dex.get_debug_info_item(debug_info_off)?)
212 } else {
213 None
214 };
215 let insns_size: uint = source.gread_with(offset, endian)?;
216 let insns: Vec<ushort> = try_gread_vec_with!(source, offset, insns_size, endian);
217 if insns_size % 2 != 0 && tries_size != 0 {
218 source.gread_with::<ushort>(offset, endian)?;
219 }
220 let tries: Tries = if tries_size != 0 {
221 source.gread_with(offset, (tries_size as usize, dex))?
222 } else {
223 Default::default()
224 };
225 Ok((
226 Self {
227 registers_size,
228 debug_info_item,
229 ins_size,
230 outs_size,
231 insns,
232 tries,
233 },
234 *offset,
235 ))
236 }
237}