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 list_off = c.pos;
84 let n_handlers = c.read_uleb128()? as usize;
85 let uleb_len = c.pos - list_off;
86 let mut handlers: Vec<CatchHandler> = Vec::with_capacity(n_handlers);
87 let mut idx_by_off: HashMap<usize, usize> = HashMap::new();
89 for _ in 0..n_handlers {
90 let hoff = c.pos - list_off;
91 let h = Self::parse_handler(c)?;
92 idx_by_off.insert(hoff, handlers.len());
93 handlers.push(h);
94 }
95
96 for t in tries.iter_mut() {
100 let raw = t.handler_idx;
101 t.handler_idx = idx_by_off
102 .get(&raw)
103 .or_else(|| idx_by_off.get(&(raw + uleb_len)))
104 .or_else(|| idx_by_off.get(&raw.saturating_sub(uleb_len)))
105 .copied()
106 .unwrap_or(0);
107 }
108
109 Some(CodeItem {
110 registers_size,
111 ins_size,
112 outs_size,
113 debug_info_off,
114 insns,
115 payloads,
116 tries,
117 handlers,
118 })
119 }
120
121 fn parse_handler(mut c: Cursor<'_>) -> Option<CatchHandler> {
122 let sz = c.read_sleb128()?;
123 let mut h = CatchHandler {
124 catches: Vec::new(),
125 catch_all: None,
126 };
127 if sz != 0 {
128 for _ in 0..sz.unsigned_abs() {
129 let ty = c.read_uleb128()? as u32;
130 let addr = c.read_uleb128()? as u32;
131 h.catches.push((ty, addr));
132 }
133 }
134 if sz <= 0 {
135 let addr = c.read_uleb128()? as u32;
136 h.catch_all = Some(addr);
137 }
138 Some(h)
139 }
140
141 pub fn handler_of(&self, t: &TryItem) -> Option<&CatchHandler> {
143 self.handlers.get(t.handler_idx)
144 }
145}