Skip to main content

mrubyedge/rite/
rite.rs

1extern crate simple_endian;
2
3use super::Error;
4use super::binfmt::*;
5
6use core::ffi::CStr;
7use core::mem;
8use std::ffi::CString;
9
10use super::marker::*;
11
12use simple_endian::{u16be, u32be};
13
14#[derive(Debug, Clone)]
15pub enum PoolValue {
16    Str(CString),    // IREP_TT_STR = 0 (need free)
17    Int32(i32),      // IREP_TT_INT32 = 1
18    SStr(CString),   // IREP_TT_SSTR = 2 (static)
19    Int64(i64),      // IREP_TT_INT64 = 3
20    Float(f64),      // IREP_TT_FLOAT = 5
21    BigInt(Vec<u8>), // IREP_TT_BIGINT = 7 (not yet fully supported)
22}
23
24#[derive(Debug, Default)]
25pub struct Rite<'a> {
26    pub binary_header: RiteBinaryHeader,
27    pub irep_header: SectionIrepHeader,
28    pub irep: Vec<Irep<'a>>,
29    pub lvar: Option<LVar>,
30}
31
32#[derive(Debug)]
33pub struct Irep<'a> {
34    pub header: IrepRecord,
35    pub insn: &'a [u8],
36    pub plen: usize,
37    pub pool: Vec<PoolValue>,
38    pub slen: usize,
39    pub syms: Vec<CString>,
40    pub catch_handlers: Vec<CatchHandler>,
41    pub lv: Vec<Option<CString>>, // Local variable names (indices into LVar::syms)
42}
43
44impl Irep<'_> {
45    pub fn nlocals(&self) -> usize {
46        be16_to_u16(self.header.nlocals) as usize
47    }
48
49    pub fn nregs(&self) -> usize {
50        be16_to_u16(self.header.nregs) as usize
51    }
52
53    pub fn rlen(&self) -> usize {
54        be16_to_u16(self.header.rlen) as usize
55    }
56
57    pub fn clen(&self) -> usize {
58        be16_to_u16(self.header.clen) as usize
59    }
60}
61
62#[derive(Debug)]
63pub struct CatchHandler {
64    pub type_: u8,
65    pub start: usize,
66    pub end: usize,
67    pub target: usize,
68}
69
70#[derive(Debug)]
71pub struct LVar {
72    pub header: SectionMiscHeader,
73    pub syms: Vec<CString>,
74}
75
76const RITE_LV_NULL_MARK: u16 = 0xFFFF;
77
78pub fn load<'a>(src: &'a [u8]) -> Result<Rite<'a>, Error> {
79    let mut rite = Rite::default();
80
81    let mut size = src.len();
82    let mut head = src;
83    let binheader_size = mem::size_of::<RiteBinaryHeader>();
84    if size < binheader_size {
85        dbg!(size < binheader_size);
86        return Err(Error::TooShort);
87    }
88    let binary_header = RiteBinaryHeader::from_bytes(&head[0..binheader_size])?;
89    rite.binary_header = binary_header;
90    size -= binheader_size;
91    head = &head[binheader_size..];
92
93    // let binsize: u32 = be32_to_u32(rite.binary_header.size);
94
95    let irep_header_size = mem::size_of::<SectionIrepHeader>();
96    if size < irep_header_size {
97        dbg!(size, irep_header_size, size < irep_header_size);
98        return Err(Error::TooShort);
99    }
100
101    while let Some(chrs) = peek4(head) {
102        match chrs {
103            IREP => {
104                let (cur, irep_header, irep) = section_irep_1(head)?;
105                rite.irep_header = irep_header;
106                rite.irep = irep;
107                head = &head[cur..];
108            }
109            LVAR => {
110                let (cur, lvar) = section_lvar(head, &mut rite.irep)?;
111                rite.lvar = Some(lvar);
112                head = &head[cur..];
113            }
114            DBG => {
115                let cur = section_skip(head)?;
116                head = &head[cur..];
117            }
118            END => {
119                let cur = section_end(head)?;
120                head = &head[cur..];
121            }
122            _ => {
123                eprintln!("{:?}", chrs);
124                eprint!("{:?}", head);
125                return Err(Error::InvalidFormat);
126            }
127        }
128    }
129
130    Ok(rite)
131}
132
133pub fn section_irep_1(head: &[u8]) -> Result<(usize, SectionIrepHeader, Vec<Irep<'_>>), Error> {
134    let mut cur = 0;
135
136    let irep_header_size = mem::size_of::<SectionIrepHeader>();
137    let irep_header = SectionIrepHeader::from_bytes(&head[cur..irep_header_size])?;
138    let irep_size = be32_to_u32(irep_header.size) as usize;
139    if head.len() < irep_size {
140        dbg!((head.len(), irep_size, head.len() < irep_size));
141        return Err(Error::TooShort);
142    }
143    cur += irep_header_size;
144
145    let mut ireps: Vec<Irep> = Vec::new();
146
147    while cur < irep_size {
148        let mut pool = Vec::<PoolValue>::new();
149        let mut syms = Vec::<CString>::new();
150
151        let start_cur = cur;
152        // insn
153        let record_size = mem::size_of::<IrepRecord>();
154        let irep_record = IrepRecord::from_bytes(&head[cur..cur + record_size])?;
155        let irep_rec_size = be32_to_u32(irep_record.size) as usize;
156        let ilen = be32_to_u32(irep_record.ilen) as usize;
157        cur += record_size;
158
159        let insns = &head[cur..cur + ilen];
160
161        cur += ilen;
162
163        let mut catch_handlers = Vec::<CatchHandler>::new();
164        let clen = be16_to_u16(irep_record.clen) as usize;
165        if clen > 0 {
166            for _ in 0..clen {
167                let value = CatchHandler {
168                    type_: head[cur],
169                    start: be32_to_u32([head[cur + 1], head[cur + 2], head[cur + 3], head[cur + 4]])
170                        as usize,
171                    end: be32_to_u32([head[cur + 5], head[cur + 6], head[cur + 7], head[cur + 8]])
172                        as usize,
173                    target: be32_to_u32([
174                        head[cur + 9],
175                        head[cur + 10],
176                        head[cur + 11],
177                        head[cur + 12],
178                    ]) as usize,
179                };
180                catch_handlers.push(value);
181                cur += mem::size_of::<IrepCatchHandler>();
182            }
183        }
184
185        // pool
186        let data = &head[cur..cur + 2];
187        let plen = be16_to_u16([data[0], data[1]]) as usize;
188        cur += 2;
189
190        for _ in 0..plen {
191            let typ = head[cur];
192            cur += 1;
193            match typ {
194                0 => {
195                    // IREP_TT_STR: String (need free)
196                    let data = &head[cur..cur + 2];
197                    let strlen = be16_to_u16([data[0], data[1]]) as usize + 1;
198                    cur += 2;
199                    let strval = CStr::from_bytes_with_nul(&head[cur..cur + strlen])
200                        .or(Err(Error::InvalidFormat))?;
201                    pool.push(PoolValue::Str(strval.to_owned()));
202                    cur += strlen;
203                }
204                1 => {
205                    // IREP_TT_INT32: 32-bit integer
206                    let data = &head[cur..cur + 4];
207                    let mut bytes = [0u8; 4];
208                    bytes.copy_from_slice(data);
209                    let intval = i32::from_be_bytes(bytes);
210                    pool.push(PoolValue::Int32(intval));
211                    cur += 4;
212                }
213                2 => {
214                    // IREP_TT_SSTR: Static string
215                    let data = &head[cur..cur + 2];
216                    let strlen = be16_to_u16([data[0], data[1]]) as usize + 1;
217                    cur += 2;
218                    let strval = CStr::from_bytes_with_nul(&head[cur..cur + strlen])
219                        .or(Err(Error::InvalidFormat))?;
220                    pool.push(PoolValue::SStr(strval.to_owned()));
221                    cur += strlen;
222                }
223                3 => {
224                    // IREP_TT_INT64: 64-bit integer
225                    let data = &head[cur..cur + 8];
226                    let mut bytes = [0u8; 8];
227                    bytes.copy_from_slice(data);
228                    let intval = i64::from_le_bytes(bytes);
229                    pool.push(PoolValue::Int64(intval));
230                    cur += 8;
231                }
232                5 => {
233                    // IREP_TT_FLOAT: Float (double/float)
234                    let data = &head[cur..cur + 8];
235                    let mut bytes = [0u8; 8];
236                    bytes.copy_from_slice(data);
237                    let floatval = f64::from_le_bytes(bytes);
238                    pool.push(PoolValue::Float(floatval));
239                    cur += 8;
240                }
241                7 => {
242                    // IREP_TT_BIGINT: Big integer (not yet fully supported)
243                    let data = &head[cur..cur + 2];
244                    let bigint_len = be16_to_u16([data[0], data[1]]) as usize;
245                    cur += 2;
246                    let bigint_data = head[cur..cur + bigint_len].to_vec();
247                    pool.push(PoolValue::BigInt(bigint_data));
248                    cur += bigint_len;
249                }
250                v => {
251                    return Err(Error::UnknownPoolType(v));
252                }
253            }
254        }
255
256        // syms
257        let data = &head[cur..cur + 2];
258        let slen = be16_to_u16([data[0], data[1]]) as usize;
259        cur += 2;
260        for _ in 0..slen {
261            let data = &head[cur..cur + 2];
262            let symlen = be16_to_u16([data[0], data[1]]) as usize + 1;
263            cur += 2;
264            let symval = CStr::from_bytes_with_nul(&head[cur..cur + symlen])
265                .or(Err(Error::InvalidFormat))?;
266            syms.push(symval.to_owned());
267            cur += symlen;
268        }
269
270        cur = start_cur + irep_rec_size;
271
272        let irep = Irep {
273            header: irep_record,
274            insn: insns,
275            plen,
276            pool,
277            slen,
278            syms,
279            catch_handlers,
280            lv: Vec::new(), // Will be filled by section_lvar if present
281        };
282        ireps.push(irep);
283    }
284
285    Ok((irep_size, irep_header, ireps))
286}
287
288pub fn section_end(head: &[u8]) -> Result<usize, Error> {
289    let header = SectionMiscHeader::from_bytes(head)?;
290    // eprintln!("end section detected");
291    Ok(be32_to_u32(header.size) as usize)
292}
293
294pub fn section_lvar(head: &[u8], ireps: &mut [Irep]) -> Result<(usize, LVar), Error> {
295    let mut cur = 0;
296    let header_size = mem::size_of::<SectionMiscHeader>();
297    let header = SectionMiscHeader::from_bytes(&head[cur..cur + header_size])?;
298    cur += header_size;
299
300    // Read syms_len (4 bytes)
301    let syms_len = be32_to_u32([head[cur], head[cur + 1], head[cur + 2], head[cur + 3]]) as usize;
302    cur += 4;
303
304    // Read symbols
305    let mut syms = Vec::new();
306    for _ in 0..syms_len {
307        let str_len = be16_to_u16([head[cur], head[cur + 1]]) as usize;
308        cur += 2;
309
310        // Read string bytes (NOT null-terminated in the binary)
311        let str_bytes = &head[cur..cur + str_len];
312        let c_str = CString::new(str_bytes).map_err(|_| Error::InvalidFormat)?;
313        syms.push(c_str);
314        cur += str_len;
315    }
316
317    // Read lv records recursively
318    let _ = read_lv_records(&head[cur..], ireps, 0, &syms, syms_len)?;
319
320    let lvar = LVar { header, syms };
321    Ok((be32_to_u32(lvar.header.size) as usize, lvar))
322}
323
324fn read_lv_records(
325    head: &[u8],
326    ireps: &mut [Irep],
327    irep_idx: usize,
328    syms: &[CString],
329    syms_len: usize,
330) -> Result<(usize, usize), Error> {
331    if irep_idx >= ireps.len() {
332        return Ok((0, irep_idx));
333    }
334
335    let mut cur = 0;
336    let nlocals = ireps[irep_idx].nlocals();
337    let rlen = ireps[irep_idx].rlen();
338
339    if nlocals == 0 {
340        return Err(Error::InvalidFormat);
341    }
342
343    // Read local variable names for this irep (nlocals - 1 entries)
344    let mut lv = Vec::new();
345    for _ in 0..(nlocals - 1) {
346        let sym_idx = be16_to_u16([head[cur], head[cur + 1]]);
347        cur += 2;
348
349        if sym_idx == RITE_LV_NULL_MARK {
350            lv.push(None);
351        } else {
352            let sym_idx = sym_idx as usize;
353            if sym_idx >= syms_len {
354                return Err(Error::InvalidFormat);
355            }
356            lv.push(Some(syms[sym_idx].clone()));
357        }
358    }
359
360    ireps[irep_idx].lv = lv;
361
362    // Recursively read child ireps
363    let mut child_irep_idx = irep_idx + 1;
364    for _ in 0..rlen {
365        let (bytes_read, next_irep_idx) =
366            read_lv_records(&head[cur..], ireps, child_irep_idx, syms, syms_len)?;
367        cur += bytes_read;
368        child_irep_idx = next_irep_idx;
369    }
370
371    Ok((cur, child_irep_idx))
372}
373
374pub fn section_skip(head: &[u8]) -> Result<usize, Error> {
375    let header = SectionMiscHeader::from_bytes(head)?;
376    // eprintln!("skipped section {:?}", header.ident.as_ascii());
377    Ok(be32_to_u32(header.size) as usize)
378}
379
380pub fn peek4(src: &[u8]) -> Option<[char; 4]> {
381    if src.len() < 4 {
382        // EoD
383        return None;
384    }
385    if let [a, b, c, d] = src[0..4] {
386        let a = char::from_u32(a as u32).unwrap();
387        let b = char::from_u32(b as u32).unwrap();
388        let c = char::from_u32(c as u32).unwrap();
389        let d = char::from_u32(d as u32).unwrap();
390        Some([a, b, c, d])
391    } else {
392        None
393    }
394}
395
396pub fn be32_to_u32(be32: [u8; 4]) -> u32 {
397    let binsize_be = unsafe { mem::transmute::<[u8; 4], u32be>(be32) };
398    let binsize: u32 = binsize_be.into();
399    binsize
400}
401
402pub fn be16_to_u16(be16: [u8; 2]) -> u16 {
403    let binsize_be = unsafe { mem::transmute::<[u8; 2], u16be>(be16) };
404    let binsize: u16 = binsize_be.into();
405    binsize
406}