1use std::collections::HashMap;
4
5use crate::insn::{decode_all, Insn, Payload};
6use crate::reader::Cursor;
7
8#[derive(Debug, Clone)]
10pub struct TryItem {
11 pub start_addr: u32,
13 pub insn_count: u32,
15 pub handler_idx: usize,
17}
18
19#[derive(Debug, Clone)]
21pub struct CatchHandler {
22 pub catches: Vec<(u32, u32)>,
24 pub catch_all: Option<u32>,
26}
27
28#[derive(Debug, Clone)]
30pub struct CodeItem {
31 pub registers_size: u16,
32 pub ins_size: u16,
34 pub outs_size: u16,
35 pub debug_info_off: u32,
36 pub insns: Vec<Insn>,
39 pub payloads: HashMap<u32, Payload>,
41 pub tries: Vec<TryItem>,
42 pub handlers: Vec<CatchHandler>,
43}
44
45impl CodeItem {
46 pub fn parse(data: &[u8], off: usize) -> Option<CodeItem> {
47 let mut c = Cursor::at(data, off);
48 let registers_size = c.u2()?;
49 let ins_size = c.u2()?;
50 let outs_size = c.u2()?;
51 let tries_size = c.u2()?;
52 let debug_info_off = c.u4()?;
53 let insns_size = c.u4()? as usize; let insns_off = c.pos;
55 if insns_off + 2 * insns_size > data.len() {
56 return None;
57 }
58 let insns_end = insns_off + 2 * insns_size;
59 let (insns, payloads) = decode_all(&data[insns_off..insns_end]);
60
61 let mut p = insns_end;
63 if tries_size != 0 && insns_size % 2 == 1 {
64 p += 2;
65 }
66
67 let mut tries = Vec::with_capacity(tries_size as usize);
68 let mut c = Cursor::at(data, p);
69 for _ in 0..tries_size {
70 let start_addr = c.u4()?;
71 let insn_count = c.u2()? as u32;
72 let handler_off = c.u2()? as usize;
75 tries.push(TryItem {
76 start_addr,
77 insn_count,
78 handler_idx: handler_off,
79 });
80 }
81
82 let mut handlers: Vec<CatchHandler> = Vec::new();
90 if tries_size != 0 {
91 let list_off = c.pos;
92 let n_handlers = c.read_uleb128()? as usize;
93 let uleb_len = c.pos - list_off;
94 handlers.reserve(n_handlers);
95 let mut idx_by_off: HashMap<usize, usize> = HashMap::new();
97 for _ in 0..n_handlers {
98 let hoff = c.pos - list_off;
99 let h = Self::parse_handler(c)?;
100 idx_by_off.insert(hoff, handlers.len());
101 handlers.push(h);
102 }
103
104 for t in tries.iter_mut() {
109 let raw = t.handler_idx;
110 t.handler_idx = idx_by_off
111 .get(&raw)
112 .or_else(|| idx_by_off.get(&(raw + uleb_len)))
113 .or_else(|| idx_by_off.get(&raw.saturating_sub(uleb_len)))
114 .copied()
115 .unwrap_or(0);
116 }
117 }
118
119 Some(CodeItem {
120 registers_size,
121 ins_size,
122 outs_size,
123 debug_info_off,
124 insns,
125 payloads,
126 tries,
127 handlers,
128 })
129 }
130
131 fn parse_handler(mut c: Cursor<'_>) -> Option<CatchHandler> {
132 let sz = c.read_sleb128()?;
133 let mut h = CatchHandler {
134 catches: Vec::new(),
135 catch_all: None,
136 };
137 if sz != 0 {
138 for _ in 0..sz.unsigned_abs() {
139 let ty = c.read_uleb128()? as u32;
140 let addr = c.read_uleb128()? as u32;
141 h.catches.push((ty, addr));
142 }
143 }
144 if sz <= 0 {
145 let addr = c.read_uleb128()? as u32;
146 h.catch_all = Some(addr);
147 }
148 Some(h)
149 }
150
151 pub fn handler_of(&self, t: &TryItem) -> Option<&CatchHandler> {
153 self.handlers.get(t.handler_idx)
154 }
155}