1use indexmap::map::IndexMap;
34use scroll::{
35 ctx::{self, SizeWith},
36 Endian, Pread, Pwrite,
37};
38use std::convert::TryInto;
39use std::mem::size_of;
40
41use super::{
42 ArchitectureIdentifier, BasicBlock, Error, Header, Immediate, ImmediateDesc, Instruction, Op,
43 Operand, RegisterDesc, RegisterFlags, Result, Routine, RoutineConvention, SubroutineConvention,
44 Vip, LOCAL_ID_MASK,
45};
46
47const VTIL_MAGIC_1: u32 = 0x4c495456;
48const VTIL_MAGIC_2: u16 = 0xdead;
49
50impl ctx::SizeWith<ArchitectureIdentifier> for ArchitectureIdentifier {
51 fn size_with(_arch_id: &ArchitectureIdentifier) -> usize {
52 size_of::<u8>()
53 }
54}
55
56impl ctx::TryFromCtx<'_, Endian> for ArchitectureIdentifier {
57 type Error = Error;
58
59 fn try_from_ctx(source: &[u8], _endian: Endian) -> Result<(Self, usize)> {
60 let arch_id = match source.pread::<u8>(0)? {
61 0 => ArchitectureIdentifier::Amd64,
62 1 => ArchitectureIdentifier::Arm64,
63 2 => ArchitectureIdentifier::Virtual,
64 arch_id => {
65 return Err(Error::Malformed(format!(
66 "Invalid architecture identifier: {:#x}",
67 arch_id
68 )))
69 }
70 };
71 assert_eq!(ArchitectureIdentifier::size_with(&arch_id), 1);
72 Ok((arch_id, 1))
73 }
74}
75
76impl ctx::TryIntoCtx<Endian> for ArchitectureIdentifier {
77 type Error = Error;
78
79 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
80 sink.pwrite::<u8>(self as u8, 0)?;
81 Ok(size_of::<u8>())
82 }
83}
84
85impl ctx::SizeWith<Header> for Header {
86 fn size_with(header: &Header) -> usize {
87 let mut size = size_of::<u32>();
88 size += ArchitectureIdentifier::size_with(&header.arch_id);
89 size += size_of::<u8>();
90 size += size_of::<u16>();
91 size
92 }
93}
94
95impl ctx::TryFromCtx<'_, Endian> for Header {
96 type Error = Error;
97
98 fn try_from_ctx(source: &[u8], endian: Endian) -> Result<(Self, usize)> {
99 let offset = &mut 0;
100
101 let magic = source.gread_with::<u32>(offset, endian)?;
102 if magic != VTIL_MAGIC_1 {
103 return Err(Error::Malformed(format!(
104 "VTIL magic is invalid: {:#x}",
105 magic
106 )));
107 }
108
109 let arch_id = source.gread_with::<ArchitectureIdentifier>(offset, endian)?;
110 let _zero = source.gread::<u8>(offset)?;
111
112 let magic = source.gread_with::<u16>(offset, endian)?;
113 if magic != VTIL_MAGIC_2 {
114 return Err(Error::Malformed(format!(
115 "VTIL magic is invalid: {:#x}",
116 magic
117 )));
118 }
119
120 let header = Header { arch_id };
121 assert_eq!(Header::size_with(&header), *offset);
122 Ok((header, *offset))
123 }
124}
125
126impl ctx::TryIntoCtx<Endian> for Header {
127 type Error = Error;
128
129 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
130 let offset = &mut 0;
131 sink.gwrite::<u32>(VTIL_MAGIC_1, offset)?;
132 sink.gwrite::<ArchitectureIdentifier>(self.arch_id, offset)?;
133 sink.gwrite::<u8>(0, offset)?;
134 sink.gwrite::<u16>(VTIL_MAGIC_2, offset)?;
135 Ok(*offset)
136 }
137}
138
139impl ctx::SizeWith<Vip> for Vip {
140 fn size_with(_vip: &Vip) -> usize {
141 size_of::<u64>()
142 }
143}
144
145impl ctx::TryFromCtx<'_, Endian> for Vip {
146 type Error = Error;
147
148 fn try_from_ctx(source: &[u8], endian: Endian) -> Result<(Self, usize)> {
149 let offset = &mut 0;
150 let vip = Vip(source.gread_with::<u64>(offset, endian)?);
151 assert_eq!(Vip::size_with(&vip), *offset);
152 Ok((vip, *offset))
153 }
154}
155
156impl ctx::TryIntoCtx<Endian> for Vip {
157 type Error = Error;
158
159 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
160 Ok(sink.pwrite::<u64>(self.0, 0)?)
161 }
162}
163
164impl ctx::SizeWith<RegisterDesc> for RegisterDesc {
165 fn size_with(_reg: &RegisterDesc) -> usize {
166 let mut size = 0;
167 size += size_of::<u64>();
168 size += size_of::<u64>();
169 size += size_of::<i32>();
170 size += size_of::<i32>();
171 size
172 }
173}
174
175impl ctx::TryFromCtx<'_, Endian> for RegisterDesc {
176 type Error = Error;
177
178 fn try_from_ctx(source: &[u8], endian: Endian) -> Result<(Self, usize)> {
179 let offset = &mut 0;
180
181 let flags = unsafe {
182 RegisterFlags::from_bits_unchecked(source.gread_with::<u64>(offset, endian)?)
183 };
184
185 let combined_id = source.gread_with::<u64>(offset, endian)?;
186 if ((combined_id & !LOCAL_ID_MASK) >> 56) > 2 {
187 return Err(Error::Malformed(
188 "Register flags are invalid: >2".to_string(),
189 ));
190 }
191
192 let bit_count = source.gread_with::<i32>(offset, endian)?;
193 let bit_offset = source.gread_with::<i32>(offset, endian)?;
194
195 let reg = RegisterDesc {
196 flags,
197 combined_id,
198 bit_count,
199 bit_offset,
200 };
201 assert_eq!(RegisterDesc::size_with(®), *offset);
202 Ok((reg, *offset))
203 }
204}
205
206impl ctx::TryIntoCtx<Endian> for RegisterDesc {
207 type Error = Error;
208
209 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
210 let offset = &mut 0;
211 sink.gwrite::<u64>(self.flags.bits(), offset)?;
212 sink.gwrite::<u64>(self.combined_id, offset)?;
213 sink.gwrite::<i32>(self.bit_count, offset)?;
214 sink.gwrite::<i32>(self.bit_offset, offset)?;
215 Ok(*offset)
216 }
217}
218
219impl ctx::SizeWith<RoutineConvention> for RoutineConvention {
220 fn size_with(routine_convention: &RoutineConvention) -> usize {
221 let mut size = 0;
222
223 size += size_of::<u32>();
224 for reg in &routine_convention.volatile_registers {
225 size += RegisterDesc::size_with(reg);
226 }
227
228 size += size_of::<u32>();
229 for reg in &routine_convention.param_registers {
230 size += RegisterDesc::size_with(reg);
231 }
232
233 size += size_of::<u32>();
234 for reg in &routine_convention.retval_registers {
235 size += RegisterDesc::size_with(reg);
236 }
237
238 size += RegisterDesc::size_with(&routine_convention.frame_register);
239 size += size_of::<u64>();
240 size += size_of::<u8>();
241
242 size
243 }
244}
245
246impl ctx::TryFromCtx<'_, Endian> for RoutineConvention {
247 type Error = Error;
248
249 fn try_from_ctx(source: &[u8], endian: Endian) -> Result<(Self, usize)> {
250 let offset = &mut 0;
251
252 let volatile_registers_count = source.gread_with::<u32>(offset, endian)?;
253 let mut volatile_registers =
254 Vec::<RegisterDesc>::with_capacity(volatile_registers_count as usize);
255 for _ in 0..volatile_registers_count {
256 volatile_registers.push(source.gread_with(offset, endian)?);
257 }
258
259 let param_registers_count = source.gread_with::<u32>(offset, endian)?;
260 let mut param_registers =
261 Vec::<RegisterDesc>::with_capacity(param_registers_count as usize);
262 for _ in 0..param_registers_count {
263 param_registers.push(source.gread_with(offset, endian)?);
264 }
265
266 let retval_registers_count = source.gread_with::<u32>(offset, endian)?;
267 let mut retval_registers =
268 Vec::<RegisterDesc>::with_capacity(retval_registers_count as usize);
269 for _ in 0..retval_registers_count {
270 retval_registers.push(source.gread_with(offset, endian)?);
271 }
272
273 let frame_register = source.gread_with::<RegisterDesc>(offset, endian)?;
274 let shadow_space = source.gread_with::<u64>(offset, endian)?;
275 let purge_stack = source.gread_with::<u8>(offset, endian)? != 0;
276
277 let routine_convention = RoutineConvention {
278 volatile_registers,
279 param_registers,
280 retval_registers,
281 frame_register,
282 shadow_space,
283 purge_stack,
284 };
285 assert_eq!(RoutineConvention::size_with(&routine_convention), *offset);
286 Ok((routine_convention, *offset))
287 }
288}
289
290impl ctx::TryIntoCtx<Endian> for RoutineConvention {
291 type Error = Error;
292
293 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
294 let offset = &mut 0;
295
296 sink.gwrite::<u32>(self.volatile_registers.len().try_into()?, offset)?;
297 for reg in self.volatile_registers {
298 sink.gwrite::<RegisterDesc>(reg, offset)?;
299 }
300
301 sink.gwrite::<u32>(self.param_registers.len().try_into()?, offset)?;
302 for reg in self.param_registers {
303 sink.gwrite::<RegisterDesc>(reg, offset)?;
304 }
305
306 sink.gwrite::<u32>(self.retval_registers.len().try_into()?, offset)?;
307 for reg in self.retval_registers {
308 sink.gwrite::<RegisterDesc>(reg, offset)?;
309 }
310
311 sink.gwrite::<RegisterDesc>(self.frame_register, offset)?;
312 sink.gwrite::<u64>(self.shadow_space, offset)?;
313 sink.gwrite::<u8>(self.purge_stack.into(), offset)?;
314 Ok(*offset)
315 }
316}
317
318impl ctx::SizeWith<ImmediateDesc> for ImmediateDesc {
319 fn size_with(_imm: &ImmediateDesc) -> usize {
320 let mut size = 0;
321 size += size_of::<u64>();
322 size += size_of::<u32>();
323 size
324 }
325}
326
327impl ctx::TryFromCtx<'_, Endian> for ImmediateDesc {
328 type Error = Error;
329
330 fn try_from_ctx(source: &[u8], endian: Endian) -> Result<(Self, usize)> {
331 let offset = &mut 0;
332
333 let value = source.gread_with::<u64>(offset, endian)?;
334 let bit_count = source.gread_with::<u32>(offset, endian)?;
335
336 let imm = ImmediateDesc {
337 value: Immediate { u64: value },
338 bit_count,
339 };
340 assert_eq!(ImmediateDesc::size_with(&imm), *offset);
341 Ok((imm, *offset))
342 }
343}
344
345impl ctx::TryIntoCtx<Endian> for ImmediateDesc {
346 type Error = Error;
347
348 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
349 let offset = &mut 0;
350 sink.gwrite::<u64>(self.value.u64(), offset)?;
351 sink.gwrite::<u32>(self.bit_count, offset)?;
352 Ok(*offset)
353 }
354}
355
356impl ctx::SizeWith<Operand> for Operand {
357 fn size_with(operand: &Operand) -> usize {
358 let mut size = 0;
359 size += size_of::<u32>();
360 size += match operand {
361 Operand::ImmediateDesc(i) => ImmediateDesc::size_with(i),
362 Operand::RegisterDesc(r) => RegisterDesc::size_with(r),
363 };
364 size
365 }
366}
367
368impl ctx::TryFromCtx<'_, Endian> for Operand {
369 type Error = Error;
370
371 fn try_from_ctx(source: &[u8], endian: Endian) -> Result<(Self, usize)> {
372 let offset = &mut 0;
373
374 let sp_index = source.gread_with::<u32>(offset, endian)?;
375 let operand = match sp_index {
376 0 => Operand::ImmediateDesc(source.gread_with::<ImmediateDesc>(offset, endian)?),
377 1 => Operand::RegisterDesc(source.gread_with::<RegisterDesc>(offset, endian)?),
378 i => return Err(Error::Malformed(format!("Invalid operand: {:#x}", i))),
379 };
380 assert_eq!(Operand::size_with(&operand), *offset);
381 Ok((operand, *offset))
382 }
383}
384
385impl ctx::TryIntoCtx<Endian> for Operand {
386 type Error = Error;
387
388 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
389 let offset = &mut 0;
390 match self {
391 Operand::ImmediateDesc(i) => {
392 sink.gwrite::<u32>(0, offset)?;
393 sink.gwrite::<ImmediateDesc>(i, offset)?;
394 }
395 Operand::RegisterDesc(r) => {
396 sink.gwrite::<u32>(1, offset)?;
397 sink.gwrite::<RegisterDesc>(r, offset)?;
398 }
399 }
400 Ok(*offset)
401 }
402}
403
404impl ctx::SizeWith<Op> for Op {
405 fn size_with(op: &Op) -> usize {
406 let mut size = 0;
407 size += size_of::<u32>();
408 size += op.name().as_bytes().len();
409 size += size_of::<u32>();
410 for operand in op.operands() {
411 size += Operand::size_with(operand);
412 }
413 size
414 }
415}
416
417impl<'a> ctx::TryFromCtx<'a, Endian> for Op {
418 type Error = Error;
419
420 fn try_from_ctx(source: &'a [u8], endian: Endian) -> Result<(Self, usize)> {
421 let offset = &mut 0;
422
423 let name_size = source.gread_with::<u32>(offset, endian)?;
424 let name = std::str::from_utf8(source.gread_with::<&'a [u8]>(offset, name_size as usize)?)?;
425
426 let operands_count = source.gread_with::<u32>(offset, endian)?;
427
428 let op = match name {
429 "mov" => {
430 if operands_count == 2 {
431 let op1 = source.gread_with::<Operand>(offset, endian)?;
432 let op2 = source.gread_with::<Operand>(offset, endian)?;
433 Op::Mov(op1, op2)
434 } else {
435 return Err(Error::OperandMismatch);
436 }
437 }
438 "movsx" => {
439 if operands_count == 2 {
440 let op1 = source.gread_with::<Operand>(offset, endian)?;
441 let op2 = source.gread_with::<Operand>(offset, endian)?;
442 Op::Movsx(op1, op2)
443 } else {
444 return Err(Error::OperandMismatch);
445 }
446 }
447 "str" => {
448 if operands_count == 3 {
449 let op1 = source.gread_with::<Operand>(offset, endian)?;
450 let op2 = source.gread_with::<Operand>(offset, endian)?;
451 let op3 = source.gread_with::<Operand>(offset, endian)?;
452 Op::Str(op1, op2, op3)
453 } else {
454 return Err(Error::OperandMismatch);
455 }
456 }
457 "ldd" => {
458 if operands_count == 3 {
459 let op1 = source.gread_with::<Operand>(offset, endian)?;
460 let op2 = source.gread_with::<Operand>(offset, endian)?;
461 let op3 = source.gread_with::<Operand>(offset, endian)?;
462 Op::Ldd(op1, op2, op3)
463 } else {
464 return Err(Error::OperandMismatch);
465 }
466 }
467 "neg" => {
468 if operands_count == 1 {
469 let op1 = source.gread_with::<Operand>(offset, endian)?;
470 Op::Neg(op1)
471 } else {
472 return Err(Error::OperandMismatch);
473 }
474 }
475 "add" => {
476 if operands_count == 2 {
477 let op1 = source.gread_with::<Operand>(offset, endian)?;
478 let op2 = source.gread_with::<Operand>(offset, endian)?;
479 Op::Add(op1, op2)
480 } else {
481 return Err(Error::OperandMismatch);
482 }
483 }
484 "sub" => {
485 if operands_count == 2 {
486 let op1 = source.gread_with::<Operand>(offset, endian)?;
487 let op2 = source.gread_with::<Operand>(offset, endian)?;
488 Op::Sub(op1, op2)
489 } else {
490 return Err(Error::OperandMismatch);
491 }
492 }
493 "mul" => {
494 if operands_count == 2 {
495 let op1 = source.gread_with::<Operand>(offset, endian)?;
496 let op2 = source.gread_with::<Operand>(offset, endian)?;
497 Op::Mul(op1, op2)
498 } else {
499 return Err(Error::OperandMismatch);
500 }
501 }
502 "mulhi" => {
503 if operands_count == 2 {
504 let op1 = source.gread_with::<Operand>(offset, endian)?;
505 let op2 = source.gread_with::<Operand>(offset, endian)?;
506 Op::Mulhi(op1, op2)
507 } else {
508 return Err(Error::OperandMismatch);
509 }
510 }
511 "imul" => {
512 if operands_count == 2 {
513 let op1 = source.gread_with::<Operand>(offset, endian)?;
514 let op2 = source.gread_with::<Operand>(offset, endian)?;
515 Op::Imul(op1, op2)
516 } else {
517 return Err(Error::OperandMismatch);
518 }
519 }
520 "imulhi" => {
521 if operands_count == 2 {
522 let op1 = source.gread_with::<Operand>(offset, endian)?;
523 let op2 = source.gread_with::<Operand>(offset, endian)?;
524 Op::Imulhi(op1, op2)
525 } else {
526 return Err(Error::OperandMismatch);
527 }
528 }
529 "div" => {
530 if operands_count == 3 {
531 let op1 = source.gread_with::<Operand>(offset, endian)?;
532 let op2 = source.gread_with::<Operand>(offset, endian)?;
533 let op3 = source.gread_with::<Operand>(offset, endian)?;
534 Op::Div(op1, op2, op3)
535 } else {
536 return Err(Error::OperandMismatch);
537 }
538 }
539 "rem" => {
540 if operands_count == 3 {
541 let op1 = source.gread_with::<Operand>(offset, endian)?;
542 let op2 = source.gread_with::<Operand>(offset, endian)?;
543 let op3 = source.gread_with::<Operand>(offset, endian)?;
544 Op::Rem(op1, op2, op3)
545 } else {
546 return Err(Error::OperandMismatch);
547 }
548 }
549 "idiv" => {
550 if operands_count == 3 {
551 let op1 = source.gread_with::<Operand>(offset, endian)?;
552 let op2 = source.gread_with::<Operand>(offset, endian)?;
553 let op3 = source.gread_with::<Operand>(offset, endian)?;
554 Op::Idiv(op1, op2, op3)
555 } else {
556 return Err(Error::OperandMismatch);
557 }
558 }
559 "irem" => {
560 if operands_count == 3 {
561 let op1 = source.gread_with::<Operand>(offset, endian)?;
562 let op2 = source.gread_with::<Operand>(offset, endian)?;
563 let op3 = source.gread_with::<Operand>(offset, endian)?;
564 Op::Irem(op1, op2, op3)
565 } else {
566 return Err(Error::OperandMismatch);
567 }
568 }
569 "popcnt" => {
570 if operands_count == 1 {
571 let op1 = source.gread_with::<Operand>(offset, endian)?;
572 Op::Popcnt(op1)
573 } else {
574 return Err(Error::OperandMismatch);
575 }
576 }
577 "bsf" => {
578 if operands_count == 1 {
579 let op1 = source.gread_with::<Operand>(offset, endian)?;
580 Op::Bsf(op1)
581 } else {
582 return Err(Error::OperandMismatch);
583 }
584 }
585 "bsr" => {
586 if operands_count == 1 {
587 let op1 = source.gread_with::<Operand>(offset, endian)?;
588 Op::Bsr(op1)
589 } else {
590 return Err(Error::OperandMismatch);
591 }
592 }
593 "not" => {
594 if operands_count == 1 {
595 let op1 = source.gread_with::<Operand>(offset, endian)?;
596 Op::Not(op1)
597 } else {
598 return Err(Error::OperandMismatch);
599 }
600 }
601 "shr" => {
602 if operands_count == 2 {
603 let op1 = source.gread_with::<Operand>(offset, endian)?;
604 let op2 = source.gread_with::<Operand>(offset, endian)?;
605 Op::Shr(op1, op2)
606 } else {
607 return Err(Error::OperandMismatch);
608 }
609 }
610 "shl" => {
611 if operands_count == 2 {
612 let op1 = source.gread_with::<Operand>(offset, endian)?;
613 let op2 = source.gread_with::<Operand>(offset, endian)?;
614 Op::Shl(op1, op2)
615 } else {
616 return Err(Error::OperandMismatch);
617 }
618 }
619 "xor" => {
620 if operands_count == 2 {
621 let op1 = source.gread_with::<Operand>(offset, endian)?;
622 let op2 = source.gread_with::<Operand>(offset, endian)?;
623 Op::Xor(op1, op2)
624 } else {
625 return Err(Error::OperandMismatch);
626 }
627 }
628 "or" => {
629 if operands_count == 2 {
630 let op1 = source.gread_with::<Operand>(offset, endian)?;
631 let op2 = source.gread_with::<Operand>(offset, endian)?;
632 Op::Or(op1, op2)
633 } else {
634 return Err(Error::OperandMismatch);
635 }
636 }
637 "and" => {
638 if operands_count == 2 {
639 let op1 = source.gread_with::<Operand>(offset, endian)?;
640 let op2 = source.gread_with::<Operand>(offset, endian)?;
641 Op::And(op1, op2)
642 } else {
643 return Err(Error::OperandMismatch);
644 }
645 }
646 "ror" => {
647 if operands_count == 2 {
648 let op1 = source.gread_with::<Operand>(offset, endian)?;
649 let op2 = source.gread_with::<Operand>(offset, endian)?;
650 Op::Ror(op1, op2)
651 } else {
652 return Err(Error::OperandMismatch);
653 }
654 }
655 "rol" => {
656 if operands_count == 2 {
657 let op1 = source.gread_with::<Operand>(offset, endian)?;
658 let op2 = source.gread_with::<Operand>(offset, endian)?;
659 Op::Rol(op1, op2)
660 } else {
661 return Err(Error::OperandMismatch);
662 }
663 }
664 "tg" => {
665 if operands_count == 3 {
666 let op1 = source.gread_with::<Operand>(offset, endian)?;
667 let op2 = source.gread_with::<Operand>(offset, endian)?;
668 let op3 = source.gread_with::<Operand>(offset, endian)?;
669 Op::Tg(op1, op2, op3)
670 } else {
671 return Err(Error::OperandMismatch);
672 }
673 }
674 "tge" => {
675 if operands_count == 3 {
676 let op1 = source.gread_with::<Operand>(offset, endian)?;
677 let op2 = source.gread_with::<Operand>(offset, endian)?;
678 let op3 = source.gread_with::<Operand>(offset, endian)?;
679 Op::Tge(op1, op2, op3)
680 } else {
681 return Err(Error::OperandMismatch);
682 }
683 }
684 "te" => {
685 if operands_count == 3 {
686 let op1 = source.gread_with::<Operand>(offset, endian)?;
687 let op2 = source.gread_with::<Operand>(offset, endian)?;
688 let op3 = source.gread_with::<Operand>(offset, endian)?;
689 Op::Te(op1, op2, op3)
690 } else {
691 return Err(Error::OperandMismatch);
692 }
693 }
694 "tne" => {
695 if operands_count == 3 {
696 let op1 = source.gread_with::<Operand>(offset, endian)?;
697 let op2 = source.gread_with::<Operand>(offset, endian)?;
698 let op3 = source.gread_with::<Operand>(offset, endian)?;
699 Op::Tne(op1, op2, op3)
700 } else {
701 return Err(Error::OperandMismatch);
702 }
703 }
704 "tl" => {
705 if operands_count == 3 {
706 let op1 = source.gread_with::<Operand>(offset, endian)?;
707 let op2 = source.gread_with::<Operand>(offset, endian)?;
708 let op3 = source.gread_with::<Operand>(offset, endian)?;
709 Op::Tl(op1, op2, op3)
710 } else {
711 return Err(Error::OperandMismatch);
712 }
713 }
714 "tle" => {
715 if operands_count == 3 {
716 let op1 = source.gread_with::<Operand>(offset, endian)?;
717 let op2 = source.gread_with::<Operand>(offset, endian)?;
718 let op3 = source.gread_with::<Operand>(offset, endian)?;
719 Op::Tle(op1, op2, op3)
720 } else {
721 return Err(Error::OperandMismatch);
722 }
723 }
724 "tug" => {
725 if operands_count == 3 {
726 let op1 = source.gread_with::<Operand>(offset, endian)?;
727 let op2 = source.gread_with::<Operand>(offset, endian)?;
728 let op3 = source.gread_with::<Operand>(offset, endian)?;
729 Op::Tug(op1, op2, op3)
730 } else {
731 return Err(Error::OperandMismatch);
732 }
733 }
734 "tuge" => {
735 if operands_count == 3 {
736 let op1 = source.gread_with::<Operand>(offset, endian)?;
737 let op2 = source.gread_with::<Operand>(offset, endian)?;
738 let op3 = source.gread_with::<Operand>(offset, endian)?;
739 Op::Tuge(op1, op2, op3)
740 } else {
741 return Err(Error::OperandMismatch);
742 }
743 }
744 "tul" => {
745 if operands_count == 3 {
746 let op1 = source.gread_with::<Operand>(offset, endian)?;
747 let op2 = source.gread_with::<Operand>(offset, endian)?;
748 let op3 = source.gread_with::<Operand>(offset, endian)?;
749 Op::Tul(op1, op2, op3)
750 } else {
751 return Err(Error::OperandMismatch);
752 }
753 }
754 "tule" => {
755 if operands_count == 3 {
756 let op1 = source.gread_with::<Operand>(offset, endian)?;
757 let op2 = source.gread_with::<Operand>(offset, endian)?;
758 let op3 = source.gread_with::<Operand>(offset, endian)?;
759 Op::Tule(op1, op2, op3)
760 } else {
761 return Err(Error::OperandMismatch);
762 }
763 }
764 "ifs" => {
765 if operands_count == 3 {
766 let op1 = source.gread_with::<Operand>(offset, endian)?;
767 let op2 = source.gread_with::<Operand>(offset, endian)?;
768 let op3 = source.gread_with::<Operand>(offset, endian)?;
769 Op::Ifs(op1, op2, op3)
770 } else {
771 return Err(Error::OperandMismatch);
772 }
773 }
774 "js" => {
775 if operands_count == 3 {
776 let op1 = source.gread_with::<Operand>(offset, endian)?;
777 let op2 = source.gread_with::<Operand>(offset, endian)?;
778 let op3 = source.gread_with::<Operand>(offset, endian)?;
779 Op::Js(op1, op2, op3)
780 } else {
781 return Err(Error::OperandMismatch);
782 }
783 }
784 "jmp" => {
785 if operands_count == 1 {
786 let op1 = source.gread_with::<Operand>(offset, endian)?;
787 Op::Jmp(op1)
788 } else {
789 return Err(Error::OperandMismatch);
790 }
791 }
792 "vexit" => {
793 if operands_count == 1 {
794 let op1 = source.gread_with::<Operand>(offset, endian)?;
795 Op::Vexit(op1)
796 } else {
797 return Err(Error::OperandMismatch);
798 }
799 }
800 "vxcall" => {
801 if operands_count == 1 {
802 let op1 = source.gread_with::<Operand>(offset, endian)?;
803 Op::Vxcall(op1)
804 } else {
805 return Err(Error::OperandMismatch);
806 }
807 }
808 "nop" => {
809 if operands_count == 0 {
810 Op::Nop
811 } else {
812 return Err(Error::OperandMismatch);
813 }
814 }
815 "sfence" => {
816 if operands_count == 0 {
817 Op::Sfence
818 } else {
819 return Err(Error::OperandMismatch);
820 }
821 }
822 "lfence" => {
823 if operands_count == 0 {
824 Op::Lfence
825 } else {
826 return Err(Error::OperandMismatch);
827 }
828 }
829 "vemit" => {
830 if operands_count == 1 {
831 let op1 = source.gread_with::<Operand>(offset, endian)?;
832 Op::Vemit(op1)
833 } else {
834 return Err(Error::OperandMismatch);
835 }
836 }
837 "vpinr" => {
838 if operands_count == 1 {
839 let op1 = source.gread_with::<Operand>(offset, endian)?;
840 Op::Vpinr(op1)
841 } else {
842 return Err(Error::OperandMismatch);
843 }
844 }
845 "vpinw" => {
846 if operands_count == 1 {
847 let op1 = source.gread_with::<Operand>(offset, endian)?;
848 Op::Vpinw(op1)
849 } else {
850 return Err(Error::OperandMismatch);
851 }
852 }
853 "vpinrm" => {
854 if operands_count == 3 {
855 let op1 = source.gread_with::<Operand>(offset, endian)?;
856 let op2 = source.gread_with::<Operand>(offset, endian)?;
857 let op3 = source.gread_with::<Operand>(offset, endian)?;
858 Op::Vpinrm(op1, op2, op3)
859 } else {
860 return Err(Error::OperandMismatch);
861 }
862 }
863 "vpinwm" => {
864 if operands_count == 3 {
865 let op1 = source.gread_with::<Operand>(offset, endian)?;
866 let op2 = source.gread_with::<Operand>(offset, endian)?;
867 let op3 = source.gread_with::<Operand>(offset, endian)?;
868 Op::Vpinwm(op1, op2, op3)
869 } else {
870 return Err(Error::OperandMismatch);
871 }
872 }
873 _ => return Err(Error::Malformed(format!("Invalid operation: {}", name))),
874 };
875 assert_eq!(Op::size_with(&op), *offset);
876 Ok((op, *offset))
877 }
878}
879
880impl ctx::TryIntoCtx<Endian> for Op {
881 type Error = Error;
882
883 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
884 let offset = &mut 0;
885
886 let name = self.name();
887
888 sink.gwrite::<u32>(name.len().try_into()?, offset)?;
889 sink.gwrite::<&[u8]>(name.as_bytes(), offset)?;
890
891 sink.gwrite::<u32>(self.operands().len().try_into()?, offset)?;
892 for operand in self.operands() {
893 sink.gwrite::<Operand>(*operand, offset)?;
894 }
895
896 Ok(*offset)
897 }
898}
899
900impl ctx::SizeWith<Instruction> for Instruction {
901 fn size_with(instr: &Instruction) -> usize {
902 let mut size = 0;
903 size += Op::size_with(&instr.op);
904 size += Vip::size_with(&instr.vip);
905 size += size_of::<i64>();
906 size += size_of::<u32>();
907 size += size_of::<u8>();
908 size
909 }
910}
911
912impl ctx::TryFromCtx<'_, Endian> for Instruction {
913 type Error = Error;
914
915 fn try_from_ctx(source: &[u8], endian: Endian) -> Result<(Self, usize)> {
916 let offset = &mut 0;
917
918 let op = source.gread_with::<Op>(offset, endian)?;
919 let vip = source.gread_with::<Vip>(offset, endian)?;
920 let sp_offset = source.gread_with::<i64>(offset, endian)?;
921 let sp_index = source.gread_with::<u32>(offset, endian)?;
922 let sp_reset = source.gread::<u8>(offset)? != 0;
923
924 let instr = Instruction {
925 op,
926 vip,
927 sp_offset,
928 sp_index,
929 sp_reset,
930 };
931 assert_eq!(Instruction::size_with(&instr), *offset);
932 Ok((instr, *offset))
933 }
934}
935
936impl ctx::TryIntoCtx<Endian> for Instruction {
937 type Error = Error;
938
939 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
940 let offset = &mut 0;
941
942 sink.gwrite::<Op>(self.op, offset)?;
943 sink.gwrite::<Vip>(self.vip, offset)?;
944 sink.gwrite::<i64>(self.sp_offset, offset)?;
945 sink.gwrite::<u32>(self.sp_index, offset)?;
946 sink.gwrite::<u8>(self.sp_reset.into(), offset)?;
947
948 Ok(*offset)
949 }
950}
951
952impl ctx::SizeWith<BasicBlock> for BasicBlock {
953 fn size_with(basic_block: &BasicBlock) -> usize {
954 let mut size = 0;
955
956 size += Vip::size_with(&basic_block.vip);
957 size += size_of::<i64>();
958 size += size_of::<u32>();
959 size += size_of::<u32>();
960
961 size += size_of::<u32>();
962 for instr in &basic_block.instructions {
963 size += Instruction::size_with(instr);
964 }
965
966 size += size_of::<u32>();
967 for prev_vip in &basic_block.prev_vip {
968 size += Vip::size_with(prev_vip);
969 }
970
971 size += size_of::<u32>();
972 for next_vip in &basic_block.next_vip {
973 size += Vip::size_with(next_vip);
974 }
975
976 size
977 }
978}
979
980impl ctx::TryFromCtx<'_, Endian> for BasicBlock {
981 type Error = Error;
982
983 fn try_from_ctx(source: &[u8], endian: Endian) -> Result<(Self, usize)> {
984 let offset = &mut 0;
985
986 let vip = Vip(source.gread_with::<u64>(offset, endian)?);
987 let sp_offset = source.gread_with::<i64>(offset, endian)?;
988 let sp_index = source.gread_with::<u32>(offset, endian)?;
989 let last_temporary_index = source.gread_with::<u32>(offset, endian)?;
990
991 let instruction_count = source.gread_with::<u32>(offset, endian)?;
992 let mut instructions = Vec::<Instruction>::with_capacity(instruction_count as usize);
993 for _ in 0..instruction_count {
994 instructions.push(source.gread_with(offset, endian)?);
995 }
996
997 let prev_vip_count = source.gread_with::<u32>(offset, endian)?;
998 let mut prev_vip = Vec::<Vip>::with_capacity(prev_vip_count as usize);
999 for _ in 0..prev_vip_count {
1000 prev_vip.push(Vip(source.gread_with(offset, endian)?));
1001 }
1002
1003 let next_vip_count = source.gread_with::<u32>(offset, endian)?;
1004 let mut next_vip = Vec::<Vip>::with_capacity(next_vip_count as usize);
1005 for _ in 0..next_vip_count {
1006 next_vip.push(Vip(source.gread_with(offset, endian)?));
1007 }
1008
1009 let basic_block = BasicBlock {
1010 vip,
1011 sp_offset,
1012 sp_index,
1013 last_temporary_index,
1014 instructions,
1015 prev_vip,
1016 next_vip,
1017 };
1018 assert_eq!(BasicBlock::size_with(&basic_block), *offset);
1019 Ok((basic_block, *offset))
1020 }
1021}
1022
1023impl ctx::TryIntoCtx<Endian> for BasicBlock {
1024 type Error = Error;
1025
1026 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
1027 let offset = &mut 0;
1028
1029 sink.gwrite::<Vip>(self.vip, offset)?;
1030 sink.gwrite::<i64>(self.sp_offset, offset)?;
1031 sink.gwrite::<u32>(self.sp_index, offset)?;
1032 sink.gwrite::<u32>(self.last_temporary_index, offset)?;
1033
1034 sink.gwrite::<u32>(self.instructions.len().try_into()?, offset)?;
1035 for instr in self.instructions {
1036 sink.gwrite::<Instruction>(instr, offset)?;
1037 }
1038
1039 sink.gwrite::<u32>(self.prev_vip.len().try_into()?, offset)?;
1040 for vip in self.prev_vip {
1041 sink.gwrite::<Vip>(vip, offset)?;
1042 }
1043
1044 sink.gwrite::<u32>(self.next_vip.len().try_into()?, offset)?;
1045 for vip in self.next_vip {
1046 sink.gwrite::<Vip>(vip, offset)?;
1047 }
1048
1049 Ok(*offset)
1050 }
1051}
1052
1053impl ctx::SizeWith<Routine> for Routine {
1054 fn size_with(routine: &Routine) -> usize {
1055 let mut size = 0;
1056 size += Header::size_with(&routine.header);
1057 size += Vip::size_with(&routine.vip);
1058 size += RoutineConvention::size_with(&routine.routine_convention);
1059 size += SubroutineConvention::size_with(&routine.subroutine_convention);
1060
1061 size += size_of::<u32>();
1062 for convention in &routine.spec_subroutine_conventions {
1063 size += SubroutineConvention::size_with(convention);
1064 }
1065
1066 size += size_of::<u32>();
1067 for basic_block in routine.explored_blocks.values() {
1068 size += BasicBlock::size_with(basic_block);
1069 }
1070 size
1071 }
1072}
1073
1074impl ctx::TryFromCtx<'_, Endian> for Routine {
1075 type Error = Error;
1076
1077 fn try_from_ctx(source: &[u8], endian: Endian) -> Result<(Self, usize)> {
1078 let offset = &mut 0;
1079
1080 let header = source.gread_with::<Header>(offset, endian)?;
1081 let vip = source.gread_with::<Vip>(offset, endian)?;
1082 let routine_convention = source.gread_with::<RoutineConvention>(offset, endian)?;
1083 let subroutine_convention = source.gread_with::<SubroutineConvention>(offset, endian)?;
1084
1085 let spec_subroutine_conventions_count = source.gread_with::<u32>(offset, endian)?;
1086 let mut spec_subroutine_conventions =
1087 Vec::<SubroutineConvention>::with_capacity(spec_subroutine_conventions_count as usize);
1088 for _ in 0..spec_subroutine_conventions_count {
1089 spec_subroutine_conventions.push(source.gread_with(offset, endian)?);
1090 }
1091
1092 let explored_blocks_count = source.gread_with::<u32>(offset, endian)?;
1093 let mut explored_blocks = IndexMap::new();
1094 for _ in 0..explored_blocks_count {
1095 let basic_block = source.gread_with::<BasicBlock>(offset, endian)?;
1096 explored_blocks.insert(basic_block.vip, basic_block);
1097 }
1098
1099 let routine = Routine {
1100 header,
1101 vip,
1102 routine_convention,
1103 subroutine_convention,
1104 spec_subroutine_conventions,
1105 explored_blocks,
1106 };
1107 assert_eq!(Routine::size_with(&routine), *offset);
1108 Ok((routine, *offset))
1109 }
1110}
1111
1112impl ctx::TryIntoCtx<Endian> for Routine {
1113 type Error = Error;
1114
1115 fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result<usize> {
1116 let offset = &mut 0;
1117
1118 sink.gwrite::<Header>(self.header, offset)?;
1119 sink.gwrite::<Vip>(self.vip, offset)?;
1120 sink.gwrite::<RoutineConvention>(self.routine_convention, offset)?;
1121 sink.gwrite::<SubroutineConvention>(self.subroutine_convention, offset)?;
1122
1123 sink.gwrite::<u32>(self.spec_subroutine_conventions.len().try_into()?, offset)?;
1124 for convention in self.spec_subroutine_conventions {
1125 sink.gwrite::<SubroutineConvention>(convention, offset)?;
1126 }
1127
1128 sink.gwrite::<u32>(self.explored_blocks.len().try_into()?, offset)?;
1129 for (_, basic_block) in self.explored_blocks.into_iter() {
1130 sink.gwrite::<BasicBlock>(basic_block, offset)?;
1131 }
1132
1133 Ok(*offset)
1134 }
1135}
1136
1137#[cfg(test)]
1138mod test {
1139 use super::Result;
1140
1141 #[test]
1142 fn round_trip() -> Result<()> {
1143 use crate::Routine;
1144 let data = std::fs::read("resources/big.vtil")?;
1145 let routine = Routine::from_vec(&data)?;
1146 let rounded_data = routine.into_bytes()?;
1147 assert_eq!(data, rounded_data);
1148 Ok(())
1149 }
1150}