├── .gitignore ├── resources └── big.vtil ├── README.md ├── .travis.yml ├── Cargo.toml ├── examples ├── dump.rs ├── simple.rs ├── builder.rs └── dot.rs ├── LICENSE └── src ├── dump.rs ├── error.rs ├── lib.rs ├── arch_info.rs ├── instr_builder.rs ├── pod.rs └── serialize.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | *.vtil -------------------------------------------------------------------------------- /resources/big.vtil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtil-project/VTIL-RustParser/HEAD/resources/big.vtil -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VTIL-RustParser [![Travis](https://travis-ci.com/vtil-project/VTIL-RustParser.svg?branch=main)](https://travis-ci.com/github/vtil-project/VTIL-RustParser) [![docs.rs](https://docs.rs/vtil-parser/badge.svg)](https://docs.rs/vtil-parser) 2 | 3 | An in-place parser for VTIL files written in Rust. 4 | 5 | ## References 6 | 7 | - https://github.com/letmutx/dex-parser 8 | - https://github.com/vtil-project/VTIL-Kaitai 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | cache: cargo 3 | 4 | rust: 5 | - stable 6 | 7 | matrix: 8 | fast_finish: true 9 | include: 10 | - rust: stable 11 | before_script: 12 | - rustup component add rustfmt 13 | - rustup component add clippy 14 | script: 15 | - cargo fmt -- --check 16 | - cargo clippy --all-features -- -D warnings 17 | 18 | script: | 19 | cargo build --verbose && 20 | cargo test --verbose && 21 | cargo doc --verbose -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vtil-parser" 3 | version = "0.7.0" 4 | authors = ["Keegan Saunders "] 5 | edition = "2018" 6 | description = "Read/write VTIL files in Rust." 7 | documentation = "https://docs.rs/vtil-parser" 8 | repository = "https://github.com/vtil-project/VTIL-RustParser" 9 | license = "BSD-3-Clause" 10 | keywords = ["parser", "vtil"] 11 | exclude = ["/resources"] 12 | 13 | [features] 14 | serde-1 = ["serde", "indexmap/serde-1"] 15 | 16 | [dependencies] 17 | scroll = "0.10.2" 18 | memmap = "0.7.0" 19 | bitflags = "1" 20 | thiserror = "1" 21 | indexmap = "1" 22 | serde = { version = "1", optional = true, features = ["derive"] } 23 | 24 | [badges] 25 | travis-ci = { repository = "vtil-project/VTIL-RustParser", branch = "main" } 26 | -------------------------------------------------------------------------------- /examples/dump.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2020-2021 Keegan Saunders 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for 4 | // any purpose with or without fee is hereby granted. 5 | // 6 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 7 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 8 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 9 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 10 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 11 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 12 | // OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 13 | // 14 | 15 | use std::env; 16 | use vtil_parser::{dump::dump_routine, Result, Routine}; 17 | 18 | fn main() -> Result<()> { 19 | let mut argv = env::args(); 20 | let routine = Routine::from_path(argv.nth(1).unwrap())?; 21 | dump_routine(&mut std::io::stdout(), &routine).unwrap(); 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /examples/simple.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2020-2021 Keegan Saunders 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for 4 | // any purpose with or without fee is hereby granted. 5 | // 6 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 7 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 8 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 9 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 10 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 11 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 12 | // OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 13 | // 14 | 15 | use std::env; 16 | use vtil_parser::{Result, Routine}; 17 | 18 | fn main() -> Result<()> { 19 | let mut argv = env::args(); 20 | let routine = Routine::from_path(argv.nth(1).unwrap())?; 21 | println!( 22 | "The architecture of this VTIL routine is: {:?}", 23 | routine.header.arch_id 24 | ); 25 | Ok(()) 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright © 2020-2021 Keegan Saunders 4 | Copyright © 2020 VTIL Project 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /examples/builder.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Keegan Saunders 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for 4 | // any purpose with or without fee is hereby granted. 5 | // 6 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 7 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 8 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 9 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 10 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 11 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 12 | // OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 13 | // 14 | 15 | use vtil_parser::{ArchitectureIdentifier, InstructionBuilder, RegisterDesc, Result, Routine, Vip}; 16 | 17 | fn main() -> Result<()> { 18 | let mut routine = Routine::new(ArchitectureIdentifier::Virtual); 19 | routine.header.arch_id = ArchitectureIdentifier::Amd64; 20 | let basic_block = routine.create_block(Vip(0)).unwrap(); 21 | let mut builder = InstructionBuilder::from(basic_block); 22 | let tmp1 = RegisterDesc::X86_REG_RAX; 23 | 24 | for i in 0..100 { 25 | builder 26 | .add(tmp1, 13u32.into()) 27 | .nop() 28 | .sub(tmp1, 12u32.into()) 29 | .nop() 30 | .add(tmp1, 14u32.into()) 31 | .mov(tmp1, tmp1.into()) 32 | .sub(tmp1, tmp1.into()) 33 | .xor(tmp1, (i as u32).into()) 34 | .push(tmp1.into()); 35 | } 36 | 37 | builder.vpinr(tmp1).vexit(0u64.into()); 38 | 39 | std::fs::write("built.vtil", routine.into_bytes()?)?; 40 | Ok(()) 41 | } 42 | -------------------------------------------------------------------------------- /src/dump.rs: -------------------------------------------------------------------------------- 1 | use crate::{Instruction, Operand, Result, Routine, Vip}; 2 | use std::io; 3 | 4 | /// Dump a VTIL [`Instruction`] to a [`String`]. This format is **not** stable 5 | pub fn dump_instr(buffer: &mut dyn io::Write, instr: &Instruction) -> Result<()> { 6 | if instr.vip != Vip::invalid() { 7 | write!(buffer, "[{:08x}] ", instr.vip.0)?; 8 | } else { 9 | write!(buffer, "[ PSEUDO ] ")?; 10 | } 11 | 12 | if instr.sp_reset { 13 | write!( 14 | buffer, 15 | ">{}{:>#4x} ", 16 | if instr.sp_offset >= 0 { '+' } else { '-' }, 17 | instr.sp_offset.abs() 18 | )?; 19 | } else { 20 | write!( 21 | buffer, 22 | " {}{:>#4x} ", 23 | if instr.sp_offset >= 0 { '+' } else { '-' }, 24 | instr.sp_offset.abs() 25 | )?; 26 | } 27 | 28 | write!(buffer, "{:<8} ", instr.op.name())?; 29 | 30 | for op in instr.op.operands() { 31 | match op { 32 | Operand::RegisterDesc(r) => { 33 | write!(buffer, "{:<12}", format!("{}", r))?; 34 | } 35 | Operand::ImmediateDesc(i) => { 36 | if i.i64() < 0 { 37 | write!(buffer, "-{:<#12x}", -i.i64())?; 38 | } else { 39 | write!(buffer, "{:<#12x}", i.i64())?; 40 | } 41 | } 42 | } 43 | } 44 | 45 | Ok(()) 46 | } 47 | 48 | /// Dump a VTIL [`Routine`] to a [`String`]. This format is **not** stable 49 | pub fn dump_routine(buffer: &mut dyn io::Write, routine: &Routine) -> Result<()> { 50 | for (_, basic_block) in &routine.explored_blocks { 51 | writeln!(buffer, "Entry point VIP: {:#x}", basic_block.vip.0)?; 52 | write!(buffer, "Stack pointer: ")?; 53 | if basic_block.sp_offset < 0 { 54 | writeln!(buffer, "-{:#x}", -basic_block.sp_offset)?; 55 | } else { 56 | writeln!(buffer, "{:#x}", basic_block.sp_offset)?; 57 | } 58 | 59 | for instr in &basic_block.instructions { 60 | dump_instr(buffer, instr)?; 61 | writeln!(buffer)?; 62 | } 63 | } 64 | 65 | Ok(()) 66 | } 67 | -------------------------------------------------------------------------------- /examples/dot.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2020-2021 Keegan Saunders 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for 4 | // any purpose with or without fee is hereby granted. 5 | // 6 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 7 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 8 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 9 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 10 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 11 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 12 | // OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 13 | // 14 | 15 | use indexmap::map::Values; 16 | use std::{env, str}; 17 | use vtil_parser::{dump::dump_instr, BasicBlock, Result, Routine, Vip}; 18 | 19 | fn escape(data: String) -> String { 20 | data.replace("&", "&") 21 | .replace("\"", """) 22 | .replace("'", "'") 23 | .replace("<", "<") 24 | .replace(">", ">") 25 | .replace("|", "\\|") 26 | } 27 | 28 | fn dump_routine(basic_blocks: Values) { 29 | println!("digraph G {{"); 30 | 31 | for basic_block in basic_blocks { 32 | let pc = basic_block.vip.0; 33 | 34 | println!( 35 | r#"vip_{0:x} [ 36 | shape="Mrecord" 37 | fontname="Courier New" 38 | label=< 39 | 40 | "#, 41 | pc 42 | ); 43 | 44 | for instr in &basic_block.instructions { 45 | let mut buffer = Vec::::new(); 46 | dump_instr(&mut buffer, instr).unwrap(); 47 | println!( 48 | r#" "#, 49 | escape(str::from_utf8(&buffer).unwrap().to_string()) 50 | ); 51 | } 52 | 53 | println!( 54 | r#"
{0:x}
{}
55 | > 56 | ];"# 57 | ); 58 | 59 | let successors = &basic_block.next_vip; 60 | if successors.len() == 2 { 61 | println!( 62 | r#"vip_{:x} -> vip_{:x} [color="green"];"#, 63 | pc, successors[0].0 64 | ); 65 | println!( 66 | r#"vip_{:x} -> vip_{:x} [color="red"];"#, 67 | pc, successors[1].0 68 | ); 69 | } else { 70 | for successor in successors { 71 | println!(r#"vip_{:x} -> vip_{:x} [color="blue"];"#, pc, successor.0); 72 | } 73 | } 74 | } 75 | 76 | println!("}}"); 77 | } 78 | 79 | fn main() -> Result<()> { 80 | let mut argv = env::args(); 81 | let routine = Routine::from_path(argv.nth(1).unwrap())?; 82 | dump_routine(routine.explored_blocks.values()); 83 | Ok(()) 84 | } 85 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | // BSD 3-Clause License 2 | // 3 | // Copyright © 2020-2021 Keegan Saunders 4 | // Copyright © 2020-2021 VTIL Project 5 | // All rights reserved. 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are met: 9 | // 10 | // 1. Redistributions of source code must retain the above copyright notice, this 11 | // list of conditions and the following disclaimer. 12 | // 13 | // 2. Redistributions in binary form must reproduce the above copyright notice, 14 | // this list of conditions and the following disclaimer in the documentation 15 | // and/or other materials provided with the distribution. 16 | // 17 | // 3. Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | // 32 | 33 | use std::{fmt, io, num, str}; 34 | use thiserror::Error; 35 | 36 | /// Custom `Error` for VTIL reading/writing 37 | #[derive(Error, Debug)] 38 | pub enum Error { 39 | /// An error occured during parsing due to a malformed VTIL file 40 | #[error("Malformed VTIL file")] 41 | Malformed(String), 42 | 43 | /// An I/O error occured 44 | #[error("I/O error")] 45 | Io(#[from] io::Error), 46 | 47 | /// Error inside of [Scroll](https://docs.rs/scroll) occured 48 | #[error("Scroll error")] 49 | Scroll(#[from] scroll::Error), 50 | 51 | /// Error during UTF-8 decoding, VTIL file is possibly malformed 52 | #[error("UTF-8 decoding error")] 53 | Utf8(#[from] str::Utf8Error), 54 | 55 | /// Error during internal formatting 56 | #[error("Formatting error")] 57 | Formatting(#[from] fmt::Error), 58 | 59 | /// Overflowing during writing 60 | #[error("Encoding error, value overflowed")] 61 | TryFromInt(#[from] num::TryFromIntError), 62 | 63 | /// Operand does not have expected type (immediate or register) 64 | #[error("Operand type mismatch")] 65 | OperandTypeMismatch, 66 | 67 | /// Operator has unexpected operand count 68 | #[error("Operand count mismatch")] 69 | OperandMismatch, 70 | } 71 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // BSD 3-Clause License 2 | // 3 | // Copyright © 2020-2021 Keegan Saunders 4 | // Copyright © 2020-2021 VTIL Project 5 | // All rights reserved. 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are met: 9 | // 10 | // 1. Redistributions of source code must retain the above copyright notice, this 11 | // list of conditions and the following disclaimer. 12 | // 13 | // 2. Redistributions in binary form must reproduce the above copyright notice, 14 | // this list of conditions and the following disclaimer in the documentation 15 | // and/or other materials provided with the distribution. 16 | // 17 | // 3. Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | // 32 | //! # VTIL-RustParser 33 | //! 34 | //! Read/write VTIL files in Rust. 35 | //! 36 | //! You can learn more about VTIL [here](https://github.com/vtil-project/VTIL-Core#introduction) 37 | //! on the main GitHub page. 38 | //! 39 | //! # Examples 40 | //! For a simple example of loading a VTIL routine and reading out some basic data: 41 | //! ``` 42 | //! # use vtil_parser::Result; 43 | //! use vtil_parser::{Routine, ArchitectureIdentifier}; 44 | //! 45 | //! # fn main() -> Result<()> { 46 | //! let routine = Routine::from_path("resources/big.vtil")?; 47 | //! assert_eq!(routine.header.arch_id, ArchitectureIdentifier::Amd64); 48 | //! # Ok(()) 49 | //! # } 50 | //! ``` 51 | //! 52 | //! For a more complex example, iterating over IL instructions: 53 | //! ``` 54 | //! # use vtil_parser::Result; 55 | //! use vtil_parser::{Routine, Op, Operand, RegisterDesc, ImmediateDesc, RegisterFlags}; 56 | //! 57 | //! # fn main() -> Result<()> { 58 | //! let routine = Routine::from_path("resources/big.vtil")?; 59 | //! 60 | //! for (_, basic_block) in routine.explored_blocks.iter().take(1) { 61 | //! for instr in basic_block.instructions.iter().take(1) { 62 | //! match &instr.op { 63 | //! Op::Ldd(_, Operand::RegisterDesc(op2), Operand::ImmediateDesc(op3)) => { 64 | //! assert!(op2.flags.contains(RegisterFlags::PHYSICAL)); 65 | //! assert!(op3.i64() == 0); 66 | //! } 67 | //! _ => assert!(false) 68 | //! } 69 | //! 70 | //! assert_eq!(instr.vip.0, 0x9b833); 71 | //! } 72 | //! } 73 | //! # Ok(()) 74 | //! # } 75 | //! ``` 76 | 77 | #![allow(clippy::upper_case_acronyms)] 78 | #![allow(clippy::useless_conversion)] 79 | #![deny(missing_docs)] 80 | 81 | use memmap::MmapOptions; 82 | use scroll::{ctx::SizeWith, Pread, Pwrite}; 83 | 84 | use indexmap::map::IndexMap; 85 | use std::fs::File; 86 | use std::path::Path; 87 | 88 | #[macro_use] 89 | extern crate bitflags; 90 | 91 | mod error; 92 | pub use error::Error; 93 | 94 | mod arch_info; 95 | 96 | mod pod; 97 | pub use pod::*; 98 | 99 | mod serialize; 100 | pub use serialize::*; 101 | 102 | mod instr_builder; 103 | pub use instr_builder::*; 104 | 105 | /// Helpers for dumping VTIL structures 106 | pub mod dump; 107 | 108 | #[doc(hidden)] 109 | pub type Result = std::result::Result; 110 | 111 | /// VTIL routine container 112 | impl Routine { 113 | /// Build a new VTIL routine container 114 | pub fn new(arch_id: ArchitectureIdentifier) -> Routine { 115 | let (routine_convention, subroutine_convention) = match arch_id { 116 | ArchitectureIdentifier::Virtual => { 117 | let routine_convention = RoutineConvention { 118 | volatile_registers: vec![], 119 | param_registers: vec![], 120 | retval_registers: vec![], 121 | // Not used, so it doesn't matter 122 | frame_register: RegisterDesc { 123 | flags: RegisterFlags::VIRTUAL, 124 | combined_id: 0, 125 | bit_count: 0, 126 | bit_offset: 0, 127 | }, 128 | shadow_space: 0, 129 | purge_stack: true, 130 | }; 131 | (routine_convention.clone(), routine_convention) 132 | } 133 | _ => unimplemented!(), 134 | }; 135 | Routine { 136 | header: Header { arch_id }, 137 | vip: Vip(0), 138 | routine_convention, 139 | subroutine_convention, 140 | spec_subroutine_conventions: vec![], 141 | explored_blocks: IndexMap::new(), 142 | } 143 | } 144 | 145 | /// Tries to create a [`BasicBlock`], returns `None` if a block already 146 | /// exists at the given address 147 | pub fn create_block(&mut self, vip: Vip) -> Option<&mut BasicBlock> { 148 | if !self.explored_blocks.contains_key(&vip) { 149 | let basic_block = BasicBlock { 150 | vip, 151 | sp_offset: 0, 152 | sp_index: 0, 153 | last_temporary_index: 0, 154 | instructions: vec![], 155 | prev_vip: vec![], 156 | next_vip: vec![], 157 | }; 158 | 159 | self.explored_blocks.insert(vip, basic_block); 160 | Some(self.explored_blocks.get_mut(&vip).unwrap()) 161 | } else { 162 | None 163 | } 164 | } 165 | 166 | /// Tries to remove a [`BasicBlock`] from the [`Routine`] 167 | pub fn remove_block(&mut self, vip: Vip) -> Option { 168 | self.explored_blocks.remove(&vip) 169 | } 170 | 171 | /// Tries to load VTIL routine from the given path 172 | pub fn from_path>(path: P) -> Result { 173 | let source = Box::new(unsafe { MmapOptions::new().map(&File::open(path.as_ref())?)? }); 174 | source.pread_with::(0, scroll::LE) 175 | } 176 | 177 | /// Loads VTIL routine from a `Vec` 178 | pub fn from_vec(source: &[u8]) -> Result { 179 | source.as_ref().pread_with::(0, scroll::LE) 180 | } 181 | 182 | /// Serialize the VTIL routine container, consuming it 183 | pub fn into_bytes(self) -> Result> { 184 | let size = Routine::size_with(&self); 185 | let mut buffer = vec![0; size]; 186 | buffer.pwrite_with::(self, 0, scroll::LE)?; 187 | Ok(buffer) 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/arch_info.rs: -------------------------------------------------------------------------------- 1 | // BSD 3-Clause License 2 | // 3 | // Copyright © 2020-2021 Keegan Saunders 4 | // Copyright © 2020-2021 VTIL Project 5 | // All rights reserved. 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are met: 9 | // 10 | // 1. Redistributions of source code must retain the above copyright notice, this 11 | // list of conditions and the following disclaimer. 12 | // 13 | // 2. Redistributions in binary form must reproduce the above copyright notice, 14 | // this list of conditions and the following disclaimer in the documentation 15 | // and/or other materials provided with the distribution. 16 | // 17 | // 3. Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | // 32 | 33 | pub(crate) mod arm64 { 34 | // Extracted from the capstone source @ d71c95b0 35 | pub const ARM64_REG_X0: u64 = 199; 36 | pub const ARM64_REG_X1: u64 = 200; 37 | pub const ARM64_REG_X2: u64 = 201; 38 | pub const ARM64_REG_X3: u64 = 202; 39 | pub const ARM64_REG_X4: u64 = 203; 40 | pub const ARM64_REG_X5: u64 = 204; 41 | pub const ARM64_REG_X6: u64 = 205; 42 | pub const ARM64_REG_X7: u64 = 206; 43 | pub const ARM64_REG_X8: u64 = 207; 44 | pub const ARM64_REG_X9: u64 = 208; 45 | pub const ARM64_REG_X10: u64 = 209; 46 | pub const ARM64_REG_X11: u64 = 210; 47 | pub const ARM64_REG_X12: u64 = 211; 48 | pub const ARM64_REG_X13: u64 = 212; 49 | pub const ARM64_REG_X14: u64 = 213; 50 | pub const ARM64_REG_X15: u64 = 214; 51 | pub const ARM64_REG_X16: u64 = 215; 52 | pub const ARM64_REG_X17: u64 = 216; 53 | pub const ARM64_REG_X18: u64 = 217; 54 | pub const ARM64_REG_X19: u64 = 218; 55 | pub const ARM64_REG_X20: u64 = 219; 56 | pub const ARM64_REG_X21: u64 = 220; 57 | pub const ARM64_REG_X22: u64 = 221; 58 | pub const ARM64_REG_X23: u64 = 222; 59 | pub const ARM64_REG_X24: u64 = 223; 60 | pub const ARM64_REG_X25: u64 = 224; 61 | pub const ARM64_REG_X26: u64 = 225; 62 | pub const ARM64_REG_X27: u64 = 226; 63 | pub const ARM64_REG_X28: u64 = 227; 64 | pub const ARM64_REG_X29: u64 = 1; 65 | pub const ARM64_REG_X30: u64 = 2; 66 | pub const ARM64_REG_XZR: u64 = 7; 67 | pub const ARM64_REG_SP: u64 = 4; 68 | pub const ARM64_REG_NZCV: u64 = 3; 69 | 70 | pub const REGISTER_NAME_MAPPING: &[&str] = &[ 71 | "NULL", "x29", "x30", "nzcv", "sp", "wsp", "wzr", "xzr", "b0", "b1", "b2", "b3", "b4", 72 | "b5", "b6", "b7", "b8", "b9", "b10", "b11", "b12", "b13", "b14", "b15", "b16", "b17", 73 | "b18", "b19", "b20", "b21", "b22", "b23", "b24", "b25", "b26", "b27", "b28", "b29", "b30", 74 | "b31", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", 75 | "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", 76 | "d26", "d27", "d28", "d29", "d30", "d31", "h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7", 77 | "h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15", "h16", "h17", "h18", "h19", "h20", 78 | "h21", "h22", "h23", "h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31", "q0", "q1", 79 | "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", 80 | "q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23", "q24", "q25", "q26", "q27", "q28", 81 | "q29", "q30", "q31", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", 82 | "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", 83 | "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", "w0", "w1", "w2", "w3", "w4", "w5", 84 | "w6", "w7", "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", 85 | "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "x0", 86 | "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", 87 | "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", 88 | "x28", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", 89 | "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", 90 | "v26", "v27", "v28", "v29", "v30", "v31", 91 | ]; 92 | } 93 | 94 | pub(crate) mod amd64 { 95 | // Extracted from the capstone source @ d71c95b0 96 | pub const X86_REG_RAX: u64 = 35; 97 | pub const X86_REG_RBX: u64 = 37; 98 | pub const X86_REG_RCX: u64 = 38; 99 | pub const X86_REG_RDX: u64 = 40; 100 | pub const X86_REG_RDI: u64 = 39; 101 | pub const X86_REG_RSI: u64 = 43; 102 | pub const X86_REG_RBP: u64 = 36; 103 | pub const X86_REG_RSP: u64 = 44; 104 | pub const X86_REG_R8: u64 = 106; 105 | pub const X86_REG_R9: u64 = 107; 106 | pub const X86_REG_R10: u64 = 108; 107 | pub const X86_REG_R11: u64 = 109; 108 | pub const X86_REG_R12: u64 = 110; 109 | pub const X86_REG_R13: u64 = 111; 110 | pub const X86_REG_R14: u64 = 112; 111 | pub const X86_REG_R15: u64 = 113; 112 | pub const X86_REG_EFLAGS: u64 = 25; 113 | 114 | pub const REGISTER_NAME_MAPPING: &[&str] = &[ 115 | "NULL", "ah", "al", "ax", "bh", "bl", "bp", "bpl", "bx", "ch", "cl", "cs", "cx", "dh", 116 | "di", "dil", "dl", "ds", "dx", "eax", "ebp", "ebx", "ecx", "edi", "edx", "flags", "eip", 117 | "eiz", "es", "esi", "esp", "fpsw", "fs", "gs", "ip", "rax", "rbp", "rbx", "rcx", "rdi", 118 | "rdx", "rip", "riz", "rsi", "rsp", "si", "sil", "sp", "spl", "ss", "cr0", "cr1", "cr2", 119 | "cr3", "cr4", "cr5", "cr6", "cr7", "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", 120 | "cr15", "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7", "dr8", "dr9", "dr10", 121 | "dr11", "dr12", "dr13", "dr14", "dr15", "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", 122 | "fp7", "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "mm0", "mm1", "mm2", "mm3", "mm4", 123 | "mm5", "mm6", "mm7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "st(0)", 124 | "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "xmm0", "xmm1", "xmm2", 125 | "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", 126 | "xmm14", "xmm15", "xmm16", "xmm17", "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23", 127 | "xmm24", "xmm25", "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31", "ymm0", "ymm1", 128 | "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", 129 | "ymm13", "ymm14", "ymm15", "ymm16", "ymm17", "ymm18", "ymm19", "ymm20", "ymm21", "ymm22", 130 | "ymm23", "ymm24", "ymm25", "ymm26", "ymm27", "ymm28", "ymm29", "ymm30", "ymm31", "zmm0", 131 | "zmm1", "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7", "zmm8", "zmm9", "zmm10", "zmm11", 132 | "zmm12", "zmm13", "zmm14", "zmm15", "zmm16", "zmm17", "zmm18", "zmm19", "zmm20", "zmm21", 133 | "zmm22", "zmm23", "zmm24", "zmm25", "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31", 134 | "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b", "r8d", "r9d", "r10d", "r11d", 135 | "r12d", "r13d", "r14d", "r15d", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", 136 | "r15w", 137 | ]; 138 | } 139 | -------------------------------------------------------------------------------- /src/instr_builder.rs: -------------------------------------------------------------------------------- 1 | // BSD 3-Clause License 2 | // 3 | // Copyright © 2021 Keegan Saunders 4 | // Copyright © 2021 VTIL Project 5 | // All rights reserved. 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are met: 9 | // 10 | // 1. Redistributions of source code must retain the above copyright notice, this 11 | // list of conditions and the following disclaimer. 12 | // 13 | // 2. Redistributions in binary form must reproduce the above copyright notice, 14 | // this list of conditions and the following disclaimer in the documentation 15 | // and/or other materials provided with the distribution. 16 | // 17 | // 3. Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | // 32 | 33 | use crate::{ 34 | BasicBlock, ImmediateDesc, Instruction, Op, Operand, RegisterDesc, RegisterFlags, Vip, 35 | }; 36 | use std::convert::TryInto; 37 | 38 | const VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN: usize = 2; 39 | 40 | /// Builder for VTIL instructions in an associated [`BasicBlock`] 41 | pub struct InstructionBuilder<'a> { 42 | /// Insertion point, *must* be cleared after use 43 | pub vip: Vip, 44 | /// The current [`BasicBlock`] 45 | pub basic_block: &'a mut BasicBlock, 46 | } 47 | 48 | // Helper for inserting instructions with no associated metadata 49 | fn insert_instr(builder: &mut InstructionBuilder, op: Op) { 50 | let vip = if builder.vip != Vip::invalid() { 51 | let vip = builder.vip; 52 | builder.vip = Vip::invalid(); 53 | vip 54 | } else { 55 | builder.vip 56 | }; 57 | 58 | let sp_offset = builder.basic_block.sp_offset; 59 | let sp_index = builder.basic_block.sp_index; 60 | 61 | builder.basic_block.instructions.push(Instruction { 62 | op, 63 | vip, 64 | sp_offset, 65 | sp_index, 66 | sp_reset: false, 67 | }); 68 | } 69 | 70 | impl<'a> InstructionBuilder<'a> { 71 | /// Build an [`InstructionBuilder`] from an existing [`BasicBlock`] 72 | pub fn from(basic_block: &'a mut BasicBlock) -> InstructionBuilder<'a> { 73 | InstructionBuilder { 74 | vip: Vip::invalid(), 75 | basic_block, 76 | } 77 | } 78 | 79 | /// Queues a stack shift 80 | pub fn shift_sp(&mut self, offset: i64) { 81 | self.basic_block.sp_offset += offset; 82 | } 83 | 84 | /// Pushes an operand up the stack queueing the shift in the stack pointer 85 | pub fn push(&mut self, op1: Operand) -> &mut Self { 86 | if let Operand::RegisterDesc(sp) = op1 { 87 | if sp.flags.contains(RegisterFlags::STACK_POINTER) { 88 | let tmp0 = self.basic_block.tmp(64); 89 | self.mov(tmp0, op1).push(tmp0.into()); 90 | return self; 91 | } 92 | } 93 | 94 | let misalignment = (op1.size() % VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN) as i64; 95 | if misalignment != 0 { 96 | let padding_size = VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN as i64 - misalignment; 97 | self.shift_sp(-padding_size); 98 | self.str( 99 | RegisterDesc::SP, 100 | self.basic_block.sp_offset.into(), 101 | ImmediateDesc::new(0u64, TryInto::::try_into(padding_size).unwrap() * 8) 102 | .into(), 103 | ); 104 | } 105 | 106 | self.shift_sp(-(op1.size() as i64)); 107 | self.str(RegisterDesc::SP, self.basic_block.sp_offset.into(), op1); 108 | 109 | self 110 | } 111 | 112 | /// Pops an operand from the stack queueing the shift in the stack pointer 113 | pub fn pop(&mut self, op1: RegisterDesc) -> &mut Self { 114 | let offset = self.basic_block.sp_offset; 115 | 116 | let misalignment = (op1.size() % VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN) as i64; 117 | if misalignment != 0 { 118 | self.shift_sp(VTIL_ARCH_POPPUSH_ENFORCED_STACK_ALIGN as i64 - misalignment); 119 | } 120 | 121 | self.shift_sp(op1.size() as i64); 122 | self.ldd(op1, RegisterDesc::SP, offset.into()); 123 | 124 | self 125 | } 126 | 127 | /// Push flags register 128 | pub fn pushf(&mut self) -> &mut Self { 129 | self.push(RegisterDesc::FLAGS.into()) 130 | } 131 | 132 | /// Pop flags register 133 | pub fn popf(&mut self) -> &mut Self { 134 | self.push(RegisterDesc::FLAGS.into()) 135 | } 136 | 137 | /// Insert an [`Op::Mov`] 138 | pub fn mov(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 139 | insert_instr(self, Op::Mov(op1.into(), op2.into())); 140 | self 141 | } 142 | 143 | /// Insert an [`Op::Movsx`] 144 | pub fn movsx(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 145 | insert_instr(self, Op::Movsx(op1.into(), op2.into())); 146 | self 147 | } 148 | 149 | /// Insert an [`Op::Str`] 150 | pub fn str(&mut self, op1: RegisterDesc, op2: ImmediateDesc, op3: Operand) -> &mut Self { 151 | insert_instr(self, Op::Str(op1.into(), op2.into(), op3.into())); 152 | self 153 | } 154 | 155 | /// Insert an [`Op::Ldd`] 156 | pub fn ldd(&mut self, op1: RegisterDesc, op2: RegisterDesc, op3: ImmediateDesc) -> &mut Self { 157 | insert_instr(self, Op::Ldd(op1.into(), op2.into(), op3.into())); 158 | self 159 | } 160 | 161 | /// Insert an [`Op::Neg`] 162 | pub fn neg(&mut self, op1: RegisterDesc) -> &mut Self { 163 | insert_instr(self, Op::Neg(op1.into())); 164 | self 165 | } 166 | 167 | /// Insert an [`Op::Add`] 168 | pub fn add(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 169 | insert_instr(self, Op::Add(op1.into(), op2.into())); 170 | self 171 | } 172 | 173 | /// Insert an [`Op::Sub`] 174 | pub fn sub(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 175 | insert_instr(self, Op::Sub(op1.into(), op2.into())); 176 | self 177 | } 178 | 179 | /// Insert an [`Op::Mul`] 180 | pub fn mul(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 181 | insert_instr(self, Op::Mul(op1.into(), op2.into())); 182 | self 183 | } 184 | 185 | /// Insert an [`Op::Mulhi`] 186 | pub fn mulhi(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 187 | insert_instr(self, Op::Mulhi(op1.into(), op2.into())); 188 | self 189 | } 190 | 191 | /// Insert an [`Op::Imul`] 192 | pub fn imul(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 193 | insert_instr(self, Op::Imul(op1.into(), op2.into())); 194 | self 195 | } 196 | 197 | /// Insert an [`Op::Imulhi`] 198 | pub fn imulhi(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 199 | insert_instr(self, Op::Imulhi(op1.into(), op2.into())); 200 | self 201 | } 202 | 203 | /// Insert an [`Op::Div`] 204 | pub fn div(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 205 | insert_instr(self, Op::Div(op1.into(), op2.into(), op3.into())); 206 | self 207 | } 208 | 209 | /// Insert an [`Op::Rem`] 210 | pub fn rem(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 211 | insert_instr(self, Op::Rem(op1.into(), op2.into(), op3.into())); 212 | self 213 | } 214 | 215 | /// Insert an [`Op::Idiv`] 216 | pub fn idiv(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 217 | insert_instr(self, Op::Idiv(op1.into(), op2.into(), op3.into())); 218 | self 219 | } 220 | 221 | /// Insert an [`Op::Irem`] 222 | pub fn irem(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 223 | insert_instr(self, Op::Irem(op1.into(), op2.into(), op3.into())); 224 | self 225 | } 226 | 227 | /// Insert an [`Op::Popcnt`] 228 | pub fn popcnt(&mut self, op1: RegisterDesc) -> &mut Self { 229 | insert_instr(self, Op::Popcnt(op1.into())); 230 | self 231 | } 232 | 233 | /// Insert an [`Op::Bsf`] 234 | pub fn bsf(&mut self, op1: RegisterDesc) -> &mut Self { 235 | insert_instr(self, Op::Bsf(op1.into())); 236 | self 237 | } 238 | 239 | /// Insert an [`Op::Bsr`] 240 | pub fn bsr(&mut self, op1: RegisterDesc) -> &mut Self { 241 | insert_instr(self, Op::Bsr(op1.into())); 242 | self 243 | } 244 | 245 | /// Insert an [`Op::Not`] 246 | pub fn not(&mut self, op1: RegisterDesc) -> &mut Self { 247 | insert_instr(self, Op::Not(op1.into())); 248 | self 249 | } 250 | 251 | /// Insert an [`Op::Shr`] 252 | pub fn shr(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 253 | insert_instr(self, Op::Shr(op1.into(), op2.into())); 254 | self 255 | } 256 | 257 | /// Insert an [`Op::Shl`] 258 | pub fn shl(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 259 | insert_instr(self, Op::Shl(op1.into(), op2.into())); 260 | self 261 | } 262 | 263 | /// Insert an [`Op::Xor`] 264 | pub fn xor(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 265 | insert_instr(self, Op::Xor(op1.into(), op2.into())); 266 | self 267 | } 268 | 269 | /// Insert an [`Op::Or`] 270 | pub fn or(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 271 | insert_instr(self, Op::Or(op1.into(), op2.into())); 272 | self 273 | } 274 | 275 | /// Insert an [`Op::And`] 276 | pub fn and(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 277 | insert_instr(self, Op::And(op1.into(), op2.into())); 278 | self 279 | } 280 | 281 | /// Insert an [`Op::Ror`] 282 | pub fn ror(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 283 | insert_instr(self, Op::Ror(op1.into(), op2.into())); 284 | self 285 | } 286 | 287 | /// Insert an [`Op::Rol`] 288 | pub fn rol(&mut self, op1: RegisterDesc, op2: Operand) -> &mut Self { 289 | insert_instr(self, Op::Rol(op1.into(), op2.into())); 290 | self 291 | } 292 | 293 | /// Insert an [`Op::Tg`] 294 | pub fn tg(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 295 | insert_instr(self, Op::Tg(op1.into(), op2.into(), op3.into())); 296 | self 297 | } 298 | 299 | /// Insert an [`Op::Tge`] 300 | pub fn tge(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 301 | insert_instr(self, Op::Tge(op1.into(), op2.into(), op3.into())); 302 | self 303 | } 304 | 305 | /// Insert an [`Op::Te`] 306 | pub fn te(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 307 | insert_instr(self, Op::Te(op1.into(), op2.into(), op3.into())); 308 | self 309 | } 310 | 311 | /// Insert an [`Op::Tne`] 312 | pub fn tne(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 313 | insert_instr(self, Op::Tne(op1.into(), op2.into(), op3.into())); 314 | self 315 | } 316 | 317 | /// Insert an [`Op::Tl`] 318 | pub fn tl(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 319 | insert_instr(self, Op::Tl(op1.into(), op2.into(), op3.into())); 320 | self 321 | } 322 | 323 | /// Insert an [`Op::Tle`] 324 | pub fn tle(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 325 | insert_instr(self, Op::Tle(op1.into(), op2.into(), op3.into())); 326 | self 327 | } 328 | 329 | /// Insert an [`Op::Tug`] 330 | pub fn tug(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 331 | insert_instr(self, Op::Tug(op1.into(), op2.into(), op3.into())); 332 | self 333 | } 334 | 335 | /// Insert an [`Op::Tuge`] 336 | pub fn tuge(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 337 | insert_instr(self, Op::Tuge(op1.into(), op2.into(), op3.into())); 338 | self 339 | } 340 | 341 | /// Insert an [`Op::Tul`] 342 | pub fn tul(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 343 | insert_instr(self, Op::Tul(op1.into(), op2.into(), op3.into())); 344 | self 345 | } 346 | 347 | /// Insert an [`Op::Tule`] 348 | pub fn tule(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 349 | insert_instr(self, Op::Tule(op1.into(), op2.into(), op3.into())); 350 | self 351 | } 352 | 353 | /// Insert an [`Op::Ifs`] 354 | pub fn ifs(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 355 | insert_instr(self, Op::Ifs(op1.into(), op2.into(), op3.into())); 356 | self 357 | } 358 | 359 | /// Insert an [`Op::Js`] 360 | pub fn js(&mut self, op1: RegisterDesc, op2: Operand, op3: Operand) -> &mut Self { 361 | insert_instr(self, Op::Js(op1.into(), op2.into(), op3.into())); 362 | self 363 | } 364 | 365 | /// Insert an [`Op::Jmp`] 366 | pub fn jmp(&mut self, op1: Operand) -> &mut Self { 367 | insert_instr(self, Op::Jmp(op1.into())); 368 | self 369 | } 370 | 371 | /// Insert an [`Op::Vexit`] 372 | pub fn vexit(&mut self, op1: Operand) -> &mut Self { 373 | insert_instr(self, Op::Vexit(op1.into())); 374 | self 375 | } 376 | 377 | /// Insert an [`Op::Vxcall`] 378 | pub fn vxcall(&mut self, op1: Operand) -> &mut Self { 379 | insert_instr(self, Op::Vxcall(op1.into())); 380 | self 381 | } 382 | 383 | /// Insert an [`Op::Nop`] 384 | pub fn nop(&mut self) -> &mut Self { 385 | insert_instr(self, Op::Nop); 386 | self 387 | } 388 | 389 | /// Insert an [`Op::Sfence`] 390 | pub fn sfence(&mut self) -> &mut Self { 391 | insert_instr(self, Op::Sfence); 392 | self 393 | } 394 | 395 | /// Insert an [`Op::Lfence`] 396 | pub fn lfence(&mut self) -> &mut Self { 397 | insert_instr(self, Op::Lfence); 398 | self 399 | } 400 | 401 | /// Insert an [`Op::Vemit`] 402 | pub fn vemit(&mut self, op1: ImmediateDesc) -> &mut Self { 403 | insert_instr(self, Op::Vemit(op1.into())); 404 | self 405 | } 406 | 407 | /// Insert an [`Op::Vpinr`] 408 | pub fn vpinr(&mut self, op1: RegisterDesc) -> &mut Self { 409 | insert_instr(self, Op::Vpinr(op1.into())); 410 | self 411 | } 412 | 413 | /// Insert an [`Op::Vpinw`] 414 | pub fn vpinw(&mut self, op1: RegisterDesc) -> &mut Self { 415 | insert_instr(self, Op::Vpinw(op1.into())); 416 | self 417 | } 418 | 419 | /// Insert an [`Op::Vpinrm`] 420 | pub fn vpinrm( 421 | &mut self, 422 | op1: RegisterDesc, 423 | op2: ImmediateDesc, 424 | op3: ImmediateDesc, 425 | ) -> &mut Self { 426 | insert_instr(self, Op::Vpinrm(op1.into(), op2.into(), op3.into())); 427 | self 428 | } 429 | 430 | /// Insert an [`Op::Vpinwm`] 431 | pub fn vpinwm( 432 | &mut self, 433 | op1: RegisterDesc, 434 | op2: ImmediateDesc, 435 | op3: ImmediateDesc, 436 | ) -> &mut Self { 437 | insert_instr(self, Op::Vpinwm(op1.into(), op2.into(), op3.into())); 438 | self 439 | } 440 | } 441 | 442 | #[cfg(test)] 443 | mod test { 444 | #[test] 445 | fn basic() { 446 | use crate::*; 447 | 448 | let mut routine = Routine::new(ArchitectureIdentifier::Virtual); 449 | let basic_block = routine.create_block(Vip(0)).unwrap(); 450 | let tmp0 = basic_block.tmp(64); 451 | let mut builder = InstructionBuilder::from(basic_block); 452 | builder.mov(tmp0, 0xA57E6F0335298D0u64.into()); 453 | 454 | assert_eq!(basic_block.instructions.len(), 1); 455 | let instr = &basic_block.instructions[0]; 456 | assert!(matches!(instr.op, Op::Mov(_, _))); 457 | } 458 | } 459 | -------------------------------------------------------------------------------- /src/pod.rs: -------------------------------------------------------------------------------- 1 | // BSD 3-Clause License 2 | // 3 | // Copyright © 2021 Keegan Saunders 4 | // Copyright © 2021 VTIL Project 5 | // All rights reserved. 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are met: 9 | // 10 | // 1. Redistributions of source code must retain the above copyright notice, this 11 | // list of conditions and the following disclaimer. 12 | // 13 | // 2. Redistributions in binary form must reproduce the above copyright notice, 14 | // this list of conditions and the following disclaimer in the documentation 15 | // and/or other materials provided with the distribution. 16 | // 17 | // 3. Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | // 32 | 33 | use crate::{ 34 | arch_info::{self, amd64, arm64}, 35 | Error, Result, 36 | }; 37 | use indexmap::map::IndexMap; 38 | #[cfg(feature = "serde")] 39 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 40 | use std::{convert::TryInto, fmt}; 41 | 42 | /// Architecture for IL inside of VTIL routines 43 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 44 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] 45 | pub enum ArchitectureIdentifier { 46 | /// AMD64 (otherwise known as x86_64) architecture 47 | Amd64, 48 | /// AArch64 architecture 49 | Arm64, 50 | /// Virtual architecture (contains no physical register access) 51 | Virtual, 52 | } 53 | 54 | /// Header containing metadata regarding the VTIL container 55 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 56 | #[derive(Debug)] 57 | pub struct Header { 58 | /// The architecture used by the VTIL routine 59 | pub arch_id: ArchitectureIdentifier, 60 | } 61 | 62 | /// VTIL instruction pointer 63 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 64 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 65 | #[repr(transparent)] 66 | pub struct Vip(pub u64); 67 | 68 | impl Vip { 69 | /// Invalid instruction pointer, unassociated with [`BasicBlock`] 70 | pub fn invalid() -> Vip { 71 | Vip(!0) 72 | } 73 | } 74 | 75 | bitflags! { 76 | /// Flags describing register properties 77 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 78 | pub struct RegisterFlags: u64 { 79 | /// Default value if no flags set. Read/write pure virtual register that 80 | /// is not a stack pointer or flags 81 | const VIRTUAL = 0; 82 | /// Indicates that the register is a physical register 83 | const PHYSICAL = 1 << 0; 84 | /// Indicates that the register is a local temporary register of the current basic block 85 | const LOCAL = 1 << 1; 86 | /// Indicates that the register is used to hold CPU flags 87 | const FLAGS = 1 << 2; 88 | /// Indicates that the register is used as the stack pointer 89 | const STACK_POINTER = 1 << 3; 90 | /// Indicates that the register is an alias to the image base 91 | const IMAGE_BASE = 1 << 4; 92 | /// Indicates that the register can change spontanously (e.g.: IA32_TIME_STAMP_COUNTER) 93 | const VOLATILE = 1 << 5; 94 | /// Indicates that the register can change spontanously (e.g.: IA32_TIME_STAMP_COUNTER) 95 | const READONLY = 1 << 6; 96 | /// Indicates that it is the special "undefined" register 97 | const UNDEFINED = 1 << 7; 98 | /// Indicates that it is a internal-use register that should be treated 99 | /// like any other virtual register 100 | const INTERNAL = 1 << 8; 101 | /// Combined mask of all special registers 102 | const SPECIAL = Self::FLAGS.bits | Self::STACK_POINTER.bits | Self::IMAGE_BASE.bits | Self::UNDEFINED.bits; 103 | } 104 | } 105 | 106 | /// Describes a VTIL register in an operand 107 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 108 | #[derive(Debug, Clone, Copy)] 109 | pub struct RegisterDesc { 110 | /// Flags describing the register 111 | pub flags: RegisterFlags, 112 | /// Identifier for this register, use [`RegisterDesc::local_id`] 113 | pub combined_id: u64, 114 | /// The bit count of this register (e.g.: 32) 115 | pub bit_count: i32, 116 | /// The bit offset of register access 117 | pub bit_offset: i32, 118 | } 119 | 120 | // Mask for local ID in `combined_id`, invert for architecture ID 121 | pub(crate) const LOCAL_ID_MASK: u64 = 0x00ffffffffffffff; 122 | 123 | // Define a physical register, including bit count and bit offset 124 | macro_rules! dr { 125 | ($arch_id:expr, $name:ident, $id:expr, $offset:expr, $count:expr, $doc:expr) => { 126 | #[doc = $doc] 127 | #[doc = " register"] 128 | pub const $name: RegisterDesc = RegisterDesc { 129 | flags: RegisterFlags::PHYSICAL, 130 | combined_id: (($arch_id as u64) << 56) | $id, 131 | bit_count: $count * 8, 132 | bit_offset: $offset * 8, 133 | }; 134 | }; 135 | 136 | ($name:ident, $id:expr, $offset:expr, $count:expr) => { 137 | dr!($name, $id, $offset, $count, stringify!($name)); 138 | }; 139 | } 140 | 141 | macro_rules! dr_amd64 { 142 | ($name:ident, $id:expr, $offset:expr, $count:expr) => { 143 | dr!( 144 | ArchitectureIdentifier::Amd64, 145 | $name, 146 | $id, 147 | $offset, 148 | $count, 149 | stringify!($name) 150 | ); 151 | }; 152 | } 153 | 154 | macro_rules! dr_arm64 { 155 | ($name:ident, $id:expr, $offset:expr, $count:expr) => { 156 | dr!( 157 | ArchitectureIdentifier::Arm64, 158 | $name, 159 | $id, 160 | $offset, 161 | $count, 162 | stringify!($name) 163 | ); 164 | }; 165 | } 166 | 167 | impl RegisterDesc { 168 | /// Undefined register 169 | pub const UNDEFINED: RegisterDesc = RegisterDesc { 170 | flags: RegisterFlags::from_bits_truncate( 171 | RegisterFlags::VOLATILE.bits() | RegisterFlags::UNDEFINED.bits(), 172 | ), 173 | combined_id: 0, 174 | bit_count: 64, 175 | bit_offset: 0, 176 | }; 177 | 178 | /// Image base register 179 | pub const IMGBASE: RegisterDesc = RegisterDesc { 180 | flags: RegisterFlags::from_bits_truncate( 181 | RegisterFlags::READONLY.bits() | RegisterFlags::IMAGE_BASE.bits(), 182 | ), 183 | combined_id: 0, 184 | bit_count: 64, 185 | bit_offset: 0, 186 | }; 187 | 188 | /// Flags register 189 | pub const FLAGS: RegisterDesc = RegisterDesc { 190 | flags: RegisterFlags::from_bits_truncate( 191 | RegisterFlags::PHYSICAL.bits() | RegisterFlags::FLAGS.bits(), 192 | ), 193 | combined_id: 0, 194 | bit_count: 64, 195 | bit_offset: 0, 196 | }; 197 | 198 | /// Stack pointer register 199 | pub const SP: RegisterDesc = RegisterDesc { 200 | flags: RegisterFlags::from_bits_truncate( 201 | RegisterFlags::PHYSICAL.bits() | RegisterFlags::STACK_POINTER.bits(), 202 | ), 203 | combined_id: 0, 204 | bit_count: 64, 205 | bit_offset: 0, 206 | }; 207 | 208 | dr_amd64!(X86_REG_RAX, amd64::X86_REG_RAX, 0, 8); 209 | dr_amd64!(X86_REG_EAX, amd64::X86_REG_RAX, 0, 4); 210 | dr_amd64!(X86_REG_AX, amd64::X86_REG_RAX, 0, 2); 211 | dr_amd64!(X86_REG_AH, amd64::X86_REG_RAX, 1, 1); 212 | dr_amd64!(X86_REG_AL, amd64::X86_REG_RAX, 0, 1); 213 | 214 | dr_amd64!(X86_REG_RBX, amd64::X86_REG_RBX, 0, 8); 215 | dr_amd64!(X86_REG_EBX, amd64::X86_REG_RBX, 0, 4); 216 | dr_amd64!(X86_REG_BX, amd64::X86_REG_RBX, 0, 2); 217 | dr_amd64!(X86_REG_BH, amd64::X86_REG_RBX, 1, 1); 218 | dr_amd64!(X86_REG_BL, amd64::X86_REG_RBX, 0, 1); 219 | 220 | dr_amd64!(X86_REG_RCX, amd64::X86_REG_RCX, 0, 8); 221 | dr_amd64!(X86_REG_ECX, amd64::X86_REG_RCX, 0, 4); 222 | dr_amd64!(X86_REG_CX, amd64::X86_REG_RCX, 0, 2); 223 | dr_amd64!(X86_REG_CH, amd64::X86_REG_RCX, 1, 1); 224 | dr_amd64!(X86_REG_CL, amd64::X86_REG_RCX, 0, 1); 225 | 226 | dr_amd64!(X86_REG_RDX, amd64::X86_REG_RDX, 0, 8); 227 | dr_amd64!(X86_REG_EDX, amd64::X86_REG_RDX, 0, 4); 228 | dr_amd64!(X86_REG_DX, amd64::X86_REG_RDX, 0, 2); 229 | dr_amd64!(X86_REG_DH, amd64::X86_REG_RDX, 1, 1); 230 | dr_amd64!(X86_REG_DL, amd64::X86_REG_RDX, 0, 1); 231 | 232 | dr_amd64!(X86_REG_RDI, amd64::X86_REG_RDI, 0, 8); 233 | dr_amd64!(X86_REG_EDI, amd64::X86_REG_RDI, 0, 4); 234 | dr_amd64!(X86_REG_DI, amd64::X86_REG_RDI, 0, 2); 235 | dr_amd64!(X86_REG_DIL, amd64::X86_REG_RDI, 0, 1); 236 | 237 | dr_amd64!(X86_REG_RSI, amd64::X86_REG_RSI, 0, 8); 238 | dr_amd64!(X86_REG_ESI, amd64::X86_REG_RSI, 0, 4); 239 | dr_amd64!(X86_REG_SI, amd64::X86_REG_RSI, 0, 2); 240 | dr_amd64!(X86_REG_SIL, amd64::X86_REG_RSI, 0, 1); 241 | 242 | dr_amd64!(X86_REG_RBP, amd64::X86_REG_RBP, 0, 8); 243 | dr_amd64!(X86_REG_EBP, amd64::X86_REG_RBP, 0, 4); 244 | dr_amd64!(X86_REG_BP, amd64::X86_REG_RBP, 0, 2); 245 | dr_amd64!(X86_REG_BPL, amd64::X86_REG_RBP, 0, 1); 246 | 247 | dr_amd64!(X86_REG_RSP, amd64::X86_REG_RSP, 0, 8); 248 | dr_amd64!(X86_REG_ESP, amd64::X86_REG_RSP, 0, 4); 249 | dr_amd64!(X86_REG_SP, amd64::X86_REG_RSP, 0, 2); 250 | dr_amd64!(X86_REG_SPL, amd64::X86_REG_RSP, 0, 1); 251 | 252 | dr_amd64!(X86_REG_R8, amd64::X86_REG_R8, 0, 8); 253 | dr_amd64!(X86_REG_R8D, amd64::X86_REG_R8, 0, 4); 254 | dr_amd64!(X86_REG_R8W, amd64::X86_REG_R8, 0, 2); 255 | dr_amd64!(X86_REG_R8B, amd64::X86_REG_R8, 0, 1); 256 | 257 | dr_amd64!(X86_REG_R9, amd64::X86_REG_R9, 0, 8); 258 | dr_amd64!(X86_REG_R9D, amd64::X86_REG_R9, 0, 4); 259 | dr_amd64!(X86_REG_R9W, amd64::X86_REG_R9, 0, 2); 260 | dr_amd64!(X86_REG_R9B, amd64::X86_REG_R9, 0, 1); 261 | 262 | dr_amd64!(X86_REG_R10, amd64::X86_REG_R10, 0, 8); 263 | dr_amd64!(X86_REG_R10D, amd64::X86_REG_R10, 0, 4); 264 | dr_amd64!(X86_REG_R10W, amd64::X86_REG_R10, 0, 2); 265 | dr_amd64!(X86_REG_R10B, amd64::X86_REG_R10, 0, 1); 266 | 267 | dr_amd64!(X86_REG_R11, amd64::X86_REG_R11, 0, 8); 268 | dr_amd64!(X86_REG_R11D, amd64::X86_REG_R11, 0, 4); 269 | dr_amd64!(X86_REG_R11W, amd64::X86_REG_R11, 0, 2); 270 | dr_amd64!(X86_REG_R11B, amd64::X86_REG_R11, 0, 1); 271 | 272 | dr_amd64!(X86_REG_R12, amd64::X86_REG_R12, 0, 8); 273 | dr_amd64!(X86_REG_R12D, amd64::X86_REG_R12, 0, 4); 274 | dr_amd64!(X86_REG_R12W, amd64::X86_REG_R12, 0, 2); 275 | dr_amd64!(X86_REG_R12B, amd64::X86_REG_R12, 0, 1); 276 | 277 | dr_amd64!(X86_REG_R13, amd64::X86_REG_R13, 0, 8); 278 | dr_amd64!(X86_REG_R13D, amd64::X86_REG_R13, 0, 4); 279 | dr_amd64!(X86_REG_R13W, amd64::X86_REG_R13, 0, 2); 280 | dr_amd64!(X86_REG_R13B, amd64::X86_REG_R13, 0, 1); 281 | 282 | dr_amd64!(X86_REG_R14, amd64::X86_REG_R14, 0, 8); 283 | dr_amd64!(X86_REG_R14D, amd64::X86_REG_R14, 0, 4); 284 | dr_amd64!(X86_REG_R14W, amd64::X86_REG_R14, 0, 2); 285 | dr_amd64!(X86_REG_R14B, amd64::X86_REG_R14, 0, 1); 286 | 287 | dr_amd64!(X86_REG_R15, amd64::X86_REG_R15, 0, 8); 288 | dr_amd64!(X86_REG_R15D, amd64::X86_REG_R15, 0, 4); 289 | dr_amd64!(X86_REG_R15W, amd64::X86_REG_R15, 0, 2); 290 | dr_amd64!(X86_REG_R15B, amd64::X86_REG_R15, 0, 1); 291 | 292 | dr_amd64!(X86_REG_EFLAGS, amd64::X86_REG_EFLAGS, 0, 8); 293 | 294 | dr_arm64!(ARM64_REG_X0, arm64::ARM64_REG_X0, 0, 8); 295 | dr_arm64!(ARM64_REG_W0, arm64::ARM64_REG_X0, 0, 4); 296 | 297 | dr_arm64!(ARM64_REG_X1, arm64::ARM64_REG_X1, 0, 8); 298 | dr_arm64!(ARM64_REG_W1, arm64::ARM64_REG_X1, 0, 4); 299 | 300 | dr_arm64!(ARM64_REG_X2, arm64::ARM64_REG_X2, 0, 8); 301 | dr_arm64!(ARM64_REG_W2, arm64::ARM64_REG_X2, 0, 4); 302 | 303 | dr_arm64!(ARM64_REG_X3, arm64::ARM64_REG_X3, 0, 8); 304 | dr_arm64!(ARM64_REG_W3, arm64::ARM64_REG_X3, 0, 4); 305 | 306 | dr_arm64!(ARM64_REG_X4, arm64::ARM64_REG_X4, 0, 8); 307 | dr_arm64!(ARM64_REG_W4, arm64::ARM64_REG_X4, 0, 4); 308 | 309 | dr_arm64!(ARM64_REG_X5, arm64::ARM64_REG_X5, 0, 8); 310 | dr_arm64!(ARM64_REG_W5, arm64::ARM64_REG_X5, 0, 4); 311 | 312 | dr_arm64!(ARM64_REG_X6, arm64::ARM64_REG_X6, 0, 8); 313 | dr_arm64!(ARM64_REG_W6, arm64::ARM64_REG_X6, 0, 4); 314 | 315 | dr_arm64!(ARM64_REG_X7, arm64::ARM64_REG_X7, 0, 8); 316 | dr_arm64!(ARM64_REG_W7, arm64::ARM64_REG_X7, 0, 4); 317 | 318 | dr_arm64!(ARM64_REG_X8, arm64::ARM64_REG_X8, 0, 8); 319 | dr_arm64!(ARM64_REG_W8, arm64::ARM64_REG_X8, 0, 4); 320 | 321 | dr_arm64!(ARM64_REG_X9, arm64::ARM64_REG_X9, 0, 8); 322 | dr_arm64!(ARM64_REG_W9, arm64::ARM64_REG_X9, 0, 4); 323 | 324 | dr_arm64!(ARM64_REG_X10, arm64::ARM64_REG_X10, 0, 8); 325 | dr_arm64!(ARM64_REG_W10, arm64::ARM64_REG_X10, 0, 4); 326 | 327 | dr_arm64!(ARM64_REG_X11, arm64::ARM64_REG_X11, 0, 8); 328 | dr_arm64!(ARM64_REG_W11, arm64::ARM64_REG_X11, 0, 4); 329 | 330 | dr_arm64!(ARM64_REG_X12, arm64::ARM64_REG_X12, 0, 8); 331 | dr_arm64!(ARM64_REG_W12, arm64::ARM64_REG_X12, 0, 4); 332 | 333 | dr_arm64!(ARM64_REG_X13, arm64::ARM64_REG_X13, 0, 8); 334 | dr_arm64!(ARM64_REG_W13, arm64::ARM64_REG_X13, 0, 4); 335 | 336 | dr_arm64!(ARM64_REG_X14, arm64::ARM64_REG_X14, 0, 8); 337 | dr_arm64!(ARM64_REG_W14, arm64::ARM64_REG_X14, 0, 4); 338 | 339 | dr_arm64!(ARM64_REG_X15, arm64::ARM64_REG_X15, 0, 8); 340 | dr_arm64!(ARM64_REG_W15, arm64::ARM64_REG_X15, 0, 4); 341 | 342 | dr_arm64!(ARM64_REG_X16, arm64::ARM64_REG_X16, 0, 8); 343 | dr_arm64!(ARM64_REG_W16, arm64::ARM64_REG_X16, 0, 4); 344 | 345 | dr_arm64!(ARM64_REG_X17, arm64::ARM64_REG_X17, 0, 8); 346 | dr_arm64!(ARM64_REG_W17, arm64::ARM64_REG_X17, 0, 4); 347 | 348 | dr_arm64!(ARM64_REG_X18, arm64::ARM64_REG_X18, 0, 8); 349 | dr_arm64!(ARM64_REG_W18, arm64::ARM64_REG_X18, 0, 4); 350 | 351 | dr_arm64!(ARM64_REG_X19, arm64::ARM64_REG_X19, 0, 8); 352 | dr_arm64!(ARM64_REG_W19, arm64::ARM64_REG_X19, 0, 4); 353 | 354 | dr_arm64!(ARM64_REG_X20, arm64::ARM64_REG_X20, 0, 8); 355 | dr_arm64!(ARM64_REG_W20, arm64::ARM64_REG_X20, 0, 4); 356 | 357 | dr_arm64!(ARM64_REG_X21, arm64::ARM64_REG_X21, 0, 8); 358 | dr_arm64!(ARM64_REG_W21, arm64::ARM64_REG_X21, 0, 4); 359 | 360 | dr_arm64!(ARM64_REG_X22, arm64::ARM64_REG_X22, 0, 8); 361 | dr_arm64!(ARM64_REG_W22, arm64::ARM64_REG_X22, 0, 4); 362 | 363 | dr_arm64!(ARM64_REG_X23, arm64::ARM64_REG_X23, 0, 8); 364 | dr_arm64!(ARM64_REG_W23, arm64::ARM64_REG_X23, 0, 4); 365 | 366 | dr_arm64!(ARM64_REG_X24, arm64::ARM64_REG_X24, 0, 8); 367 | dr_arm64!(ARM64_REG_W24, arm64::ARM64_REG_X24, 0, 4); 368 | 369 | dr_arm64!(ARM64_REG_X25, arm64::ARM64_REG_X25, 0, 8); 370 | dr_arm64!(ARM64_REG_W25, arm64::ARM64_REG_X25, 0, 4); 371 | 372 | dr_arm64!(ARM64_REG_X26, arm64::ARM64_REG_X26, 0, 8); 373 | dr_arm64!(ARM64_REG_W26, arm64::ARM64_REG_X26, 0, 4); 374 | 375 | dr_arm64!(ARM64_REG_X27, arm64::ARM64_REG_X27, 0, 8); 376 | dr_arm64!(ARM64_REG_W27, arm64::ARM64_REG_X27, 0, 4); 377 | 378 | dr_arm64!(ARM64_REG_X28, arm64::ARM64_REG_X28, 0, 8); 379 | dr_arm64!(ARM64_REG_W28, arm64::ARM64_REG_X28, 0, 4); 380 | 381 | dr_arm64!(ARM64_REG_X29, arm64::ARM64_REG_X29, 0, 8); 382 | dr_arm64!(ARM64_REG_FP, arm64::ARM64_REG_X29, 0, 8); 383 | dr_arm64!(ARM64_REG_W29, arm64::ARM64_REG_X29, 0, 4); 384 | 385 | dr_arm64!(ARM64_REG_X30, arm64::ARM64_REG_X30, 0, 8); 386 | dr_arm64!(ARM64_REG_LR, arm64::ARM64_REG_X30, 0, 8); 387 | dr_arm64!(ARM64_REG_W30, arm64::ARM64_REG_X30, 0, 4); 388 | 389 | dr_arm64!(ARM64_REG_XZR, arm64::ARM64_REG_XZR, 0, 8); 390 | dr_arm64!(ARM64_REG_WZR, arm64::ARM64_REG_XZR, 0, 4); 391 | 392 | dr_arm64!(ARM64_REG_SP, arm64::ARM64_REG_SP, 0, 8); 393 | dr_arm64!(ARM64_REG_WSP, arm64::ARM64_REG_SP, 0, 4); 394 | 395 | dr_arm64!(ARM64_REG_NZCV, arm64::ARM64_REG_NZCV, 0, 8); 396 | 397 | /// Local identifier that is intentionally unique to this register 398 | pub fn local_id(&self) -> u64 { 399 | self.combined_id & LOCAL_ID_MASK 400 | } 401 | 402 | /// The underlying architecture of this register 403 | pub fn arch_id(&self) -> ArchitectureIdentifier { 404 | match (self.combined_id & !LOCAL_ID_MASK) >> 56 { 405 | 0 => ArchitectureIdentifier::Amd64, 406 | 1 => ArchitectureIdentifier::Arm64, 407 | _ => ArchitectureIdentifier::Virtual, 408 | } 409 | } 410 | 411 | /// Operand size in bits, rounding up 412 | pub fn size(&self) -> usize { 413 | (self.bit_count as usize + 7) / 8 414 | } 415 | } 416 | 417 | impl fmt::Display for RegisterDesc { 418 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 419 | let mut prefix = String::new(); 420 | 421 | if self.flags.contains(RegisterFlags::VOLATILE) { 422 | prefix = "?".to_string(); 423 | } 424 | 425 | if self.flags.contains(RegisterFlags::READONLY) { 426 | prefix += "&&"; 427 | } 428 | 429 | let mut suffix = String::new(); 430 | 431 | if self.bit_offset != 0 { 432 | suffix = format!("@{}", self.bit_offset); 433 | } 434 | 435 | if self.bit_count != 64 { 436 | suffix.push_str(&format!(":{}", self.bit_count)); 437 | } 438 | 439 | if self.flags.contains(RegisterFlags::INTERNAL) { 440 | write!(f, "{}sr{}{}", prefix, self.local_id(), suffix)?; 441 | return Ok(()); 442 | } else if self.flags.contains(RegisterFlags::UNDEFINED) { 443 | write!(f, "{}UD{}", prefix, suffix)?; 444 | return Ok(()); 445 | } else if self.flags.contains(RegisterFlags::FLAGS) { 446 | write!(f, "{}$flags{}", prefix, suffix)?; 447 | return Ok(()); 448 | } else if self.flags.contains(RegisterFlags::STACK_POINTER) { 449 | write!(f, "{}$sp{}", prefix, suffix)?; 450 | return Ok(()); 451 | } else if self.flags.contains(RegisterFlags::IMAGE_BASE) { 452 | write!(f, "{}base{}", prefix, suffix)?; 453 | return Ok(()); 454 | } else if self.flags.contains(RegisterFlags::LOCAL) { 455 | write!(f, "{}t{}{}", prefix, self.local_id(), suffix)?; 456 | return Ok(()); 457 | } 458 | 459 | if self.flags.contains(RegisterFlags::PHYSICAL) { 460 | match self.arch_id() { 461 | ArchitectureIdentifier::Amd64 => { 462 | write!( 463 | f, 464 | "{}{}{}", 465 | prefix, 466 | arch_info::amd64::REGISTER_NAME_MAPPING[self.local_id() as usize], 467 | suffix 468 | )?; 469 | return Ok(()); 470 | } 471 | ArchitectureIdentifier::Arm64 => { 472 | write!( 473 | f, 474 | "{}{}{}", 475 | prefix, 476 | arch_info::arm64::REGISTER_NAME_MAPPING[self.local_id() as usize], 477 | suffix 478 | )?; 479 | return Ok(()); 480 | } 481 | _ => {} 482 | } 483 | } 484 | 485 | write!(f, "{}vr{}{}", prefix, self.local_id(), suffix)?; 486 | Ok(()) 487 | } 488 | } 489 | 490 | /// Routine calling convention information and associated metadata 491 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 492 | #[derive(Debug, Clone)] 493 | pub struct RoutineConvention { 494 | /// List of registers that may change as a result of the routine execution but 495 | /// will be considered trashed 496 | pub volatile_registers: Vec, 497 | /// List of regsiters that this routine wlil read from as a way of taking arguments 498 | /// * Additional arguments will be passed at `[$sp + shadow_space + n * 8]` 499 | pub param_registers: Vec, 500 | /// List of registers that are used to store the return value of the routine and 501 | /// thus will change during routine execution but must be considered "used" by return 502 | pub retval_registers: Vec, 503 | /// Register that is generally used to store the stack frame if relevant 504 | pub frame_register: RegisterDesc, 505 | /// Size of the shadow space 506 | pub shadow_space: u64, 507 | /// Purges any writes to stack that will be end up below the final stack pointer 508 | pub purge_stack: bool, 509 | } 510 | 511 | #[derive(Clone, Copy)] 512 | pub(crate) union Immediate { 513 | pub(crate) u64: u64, 514 | pub(crate) i64: i64, 515 | } 516 | 517 | impl Immediate { 518 | pub(crate) fn u64(&self) -> u64 { 519 | unsafe { self.u64 } 520 | } 521 | 522 | pub(crate) fn set_u64(&mut self, imm: u64) { 523 | self.u64 = imm; 524 | } 525 | 526 | pub(crate) fn i64(&self) -> i64 { 527 | unsafe { self.i64 } 528 | } 529 | 530 | pub(crate) fn set_i64(&mut self, imm: i64) { 531 | self.i64 = imm; 532 | } 533 | } 534 | 535 | #[cfg(feature = "serde")] 536 | impl Serialize for Immediate { 537 | fn serialize(&self, serializer: S) -> std::result::Result 538 | where 539 | S: Serializer, 540 | { 541 | serializer.serialize_i64(self.i64()) 542 | } 543 | } 544 | 545 | #[cfg(feature = "serde")] 546 | impl<'de> Deserialize<'de> for Immediate { 547 | fn deserialize(deserializer: D) -> std::result::Result 548 | where 549 | D: Deserializer<'de>, 550 | { 551 | Ok(Immediate { 552 | i64: i64::deserialize(deserializer)?, 553 | }) 554 | } 555 | } 556 | 557 | impl fmt::Debug for Immediate { 558 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 559 | f.debug_struct("Immediate") 560 | .field("u64", &self.u64()) 561 | .field("i64", &self.i64()) 562 | .finish() 563 | } 564 | } 565 | 566 | /// Describes a VTIL immediate value in an operand 567 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 568 | #[derive(Debug, Clone, Copy)] 569 | pub struct ImmediateDesc { 570 | pub(crate) value: Immediate, 571 | /// The bit count of this register (e.g.: 32) 572 | pub bit_count: u32, 573 | } 574 | 575 | impl From for ImmediateDesc { 576 | fn from(imm: i64) -> ImmediateDesc { 577 | ImmediateDesc::new_signed(imm, 64) 578 | } 579 | } 580 | 581 | impl From for ImmediateDesc { 582 | fn from(imm: u64) -> ImmediateDesc { 583 | ImmediateDesc::new(imm, 64) 584 | } 585 | } 586 | 587 | impl From for ImmediateDesc { 588 | fn from(imm: i32) -> ImmediateDesc { 589 | ImmediateDesc::new_signed(imm, 32) 590 | } 591 | } 592 | 593 | impl From for ImmediateDesc { 594 | fn from(imm: u32) -> ImmediateDesc { 595 | ImmediateDesc::new(imm, 32) 596 | } 597 | } 598 | 599 | impl From for ImmediateDesc { 600 | fn from(imm: i16) -> ImmediateDesc { 601 | ImmediateDesc::new_signed(imm, 16) 602 | } 603 | } 604 | 605 | impl From for ImmediateDesc { 606 | fn from(imm: u16) -> ImmediateDesc { 607 | ImmediateDesc::new(imm, 16) 608 | } 609 | } 610 | 611 | impl From for ImmediateDesc { 612 | fn from(imm: i8) -> ImmediateDesc { 613 | ImmediateDesc::new_signed(imm, 8) 614 | } 615 | } 616 | 617 | impl From for ImmediateDesc { 618 | fn from(imm: u8) -> ImmediateDesc { 619 | ImmediateDesc::new(imm, 8) 620 | } 621 | } 622 | 623 | impl ImmediateDesc { 624 | /// Immediate from a `u64` 625 | pub fn new>(value: T, bit_count: u32) -> ImmediateDesc { 626 | ImmediateDesc { 627 | value: Immediate { u64: value.into() }, 628 | bit_count, 629 | } 630 | } 631 | 632 | /// Immediate from an `i64` 633 | pub fn new_signed>(value: T, bit_count: u32) -> ImmediateDesc { 634 | ImmediateDesc { 635 | value: Immediate { i64: value.into() }, 636 | bit_count, 637 | } 638 | } 639 | 640 | /// Access the underlying immediate as a `u64` 641 | pub fn u64(&self) -> u64 { 642 | self.value.u64() 643 | } 644 | 645 | /// Set the value of the underlying immediate as a `u64` 646 | pub fn set_u64(&mut self, imm: u64) { 647 | self.value.set_u64(imm); 648 | } 649 | 650 | /// Access the underlying immediate as an `i64` 651 | pub fn i64(&self) -> i64 { 652 | self.value.i64() 653 | } 654 | 655 | /// Set the value of the underlying immediate as an `i64` 656 | pub fn set_i64(&mut self, imm: i64) { 657 | self.value.set_i64(imm); 658 | } 659 | 660 | /// Operand size in bits, rounding up 661 | pub fn size(&self) -> usize { 662 | (self.bit_count as usize + 7) / 8 663 | } 664 | } 665 | 666 | /// VTIL instruction operand 667 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 668 | #[derive(Debug, Clone, Copy)] 669 | pub enum Operand { 670 | /// Immediate operand containing a sized immediate value 671 | ImmediateDesc(ImmediateDesc), 672 | /// Register operand containing a register description 673 | RegisterDesc(RegisterDesc), 674 | } 675 | 676 | impl From for Operand { 677 | fn from(imm: i64) -> Operand { 678 | Operand::ImmediateDesc(imm.into()) 679 | } 680 | } 681 | 682 | impl From for Operand { 683 | fn from(imm: u64) -> Operand { 684 | Operand::ImmediateDesc(imm.into()) 685 | } 686 | } 687 | 688 | impl From for Operand { 689 | fn from(imm: i32) -> Operand { 690 | Operand::ImmediateDesc(imm.into()) 691 | } 692 | } 693 | 694 | impl From for Operand { 695 | fn from(imm: u32) -> Operand { 696 | Operand::ImmediateDesc(imm.into()) 697 | } 698 | } 699 | 700 | impl From for Operand { 701 | fn from(imm: i16) -> Operand { 702 | Operand::ImmediateDesc(imm.into()) 703 | } 704 | } 705 | 706 | impl From for Operand { 707 | fn from(imm: u16) -> Operand { 708 | Operand::ImmediateDesc(imm.into()) 709 | } 710 | } 711 | 712 | impl From for Operand { 713 | fn from(imm: i8) -> Operand { 714 | Operand::ImmediateDesc(imm.into()) 715 | } 716 | } 717 | 718 | impl From for Operand { 719 | fn from(imm: u8) -> Operand { 720 | Operand::ImmediateDesc(imm.into()) 721 | } 722 | } 723 | 724 | impl Operand { 725 | /// Operand size in bits, rounding up 726 | pub fn size(&self) -> usize { 727 | match self { 728 | Operand::ImmediateDesc(i) => i.size(), 729 | Operand::RegisterDesc(r) => r.size(), 730 | } 731 | } 732 | } 733 | 734 | impl From for Operand { 735 | fn from(register_desc: RegisterDesc) -> Self { 736 | Operand::RegisterDesc(register_desc) 737 | } 738 | } 739 | 740 | impl From for Operand { 741 | fn from(immediate_desc: ImmediateDesc) -> Self { 742 | Operand::ImmediateDesc(immediate_desc) 743 | } 744 | } 745 | 746 | impl<'a, 'b> TryInto<&'b ImmediateDesc> for &'a Operand 747 | where 748 | 'a: 'b, 749 | { 750 | type Error = Error; 751 | 752 | fn try_into(self) -> Result<&'a ImmediateDesc> { 753 | match self { 754 | Operand::ImmediateDesc(ref i) => Ok(i), 755 | _ => Err(Error::OperandTypeMismatch), 756 | } 757 | } 758 | } 759 | 760 | impl<'a, 'b> TryInto<&'b RegisterDesc> for &'a Operand 761 | where 762 | 'a: 'b, 763 | { 764 | type Error = Error; 765 | 766 | fn try_into(self) -> Result<&'a RegisterDesc> { 767 | match self { 768 | Operand::RegisterDesc(r) => Ok(r), 769 | _ => Err(Error::OperandTypeMismatch), 770 | } 771 | } 772 | } 773 | 774 | /// VTIL instruction and associated metadata 775 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 776 | #[derive(Debug)] 777 | pub struct Instruction { 778 | /// Instruction operation and operators 779 | pub op: Op, 780 | /// The virtual instruction pointer of this instruction 781 | pub vip: Vip, 782 | /// Stack pointer offset at this instruction 783 | pub sp_offset: i64, 784 | /// Stack instance index 785 | pub sp_index: u32, 786 | /// If the stack pointer is reset at this instruction 787 | pub sp_reset: bool, 788 | } 789 | 790 | /// VTIL operator and operands 791 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 792 | #[derive(Debug)] 793 | pub enum Op { 794 | // Data/Memory instructions 795 | /// OP1 = ZX(OP2) 796 | Mov(Operand, Operand), 797 | /// OP1 = SX(OP2) 798 | Movsx(Operand, Operand), 799 | /// \[OP1+OP2\] <= OP3 800 | Str(Operand, Operand, Operand), 801 | /// OP1 <= \[OP2+OP3\] 802 | Ldd(Operand, Operand, Operand), 803 | 804 | // Arithmetic instructions 805 | /// OP1 = -OP1 806 | Neg(Operand), 807 | /// OP1 = OP1 + OP2 808 | Add(Operand, Operand), 809 | /// OP1 = OP1 - OP2 810 | Sub(Operand, Operand), 811 | /// OP1 = OP1 * OP2 812 | Mul(Operand, Operand), 813 | /// OP1 = \[OP1 * OP2\]>>N 814 | Mulhi(Operand, Operand), 815 | /// OP1 = OP1 * OP2 (Signed) 816 | Imul(Operand, Operand), 817 | /// OP1 = \[OP1 * OP2\]>>N (Signed) 818 | Imulhi(Operand, Operand), 819 | /// OP1 = \[OP2:OP1\] / OP3 820 | Div(Operand, Operand, Operand), 821 | /// OP1 = \[OP2:OP1\] % OP3 822 | Rem(Operand, Operand, Operand), 823 | /// OP1 = \[OP2:OP1\] / OP3 (Signed) 824 | Idiv(Operand, Operand, Operand), 825 | /// OP1 = \[OP2:OP1\] % OP3 (Signed) 826 | Irem(Operand, Operand, Operand), 827 | 828 | // Bitwise instructions 829 | /// OP1 = popcnt OP1 830 | Popcnt(Operand), 831 | /// OP1 = OP1 ? BitScanForward OP1 + 1 : 0 832 | Bsf(Operand), 833 | /// OP1 = OP1 ? BitScanReverse OP1 + 1 : 0 834 | Bsr(Operand), 835 | /// OP1 = ~OP1 836 | Not(Operand), 837 | /// OP1 >>= OP2 838 | Shr(Operand, Operand), 839 | /// OP1 <<= OP2 840 | Shl(Operand, Operand), 841 | /// OP1 ^= OP2 842 | Xor(Operand, Operand), 843 | /// OP1 |= OP2 844 | Or(Operand, Operand), 845 | /// OP1 &= OP2 846 | And(Operand, Operand), 847 | /// OP1 = (OP1>>OP2) | (OP1<<(N-OP2)) 848 | Ror(Operand, Operand), 849 | /// OP1 = (OP1<>(N-OP2)) 850 | Rol(Operand, Operand), 851 | 852 | // Conditional instructions 853 | /// OP1 = OP2 > OP3 854 | Tg(Operand, Operand, Operand), 855 | /// OP1 = OP2 >= OP3 856 | Tge(Operand, Operand, Operand), 857 | /// OP1 = OP2 == OP3 858 | Te(Operand, Operand, Operand), 859 | /// OP1 = OP2 != OP3 860 | Tne(Operand, Operand, Operand), 861 | /// OP1 = OP2 < OP3 862 | Tl(Operand, Operand, Operand), 863 | /// OP1 = OP2 <= OP3 864 | Tle(Operand, Operand, Operand), 865 | /// OP1 = OP2 <= OP3 866 | Tug(Operand, Operand, Operand), 867 | /// OP1 = OP2 u>= OP3 868 | Tuge(Operand, Operand, Operand), 869 | /// OP1 = OP2 u< OP3 870 | Tul(Operand, Operand, Operand), 871 | /// OP1 = OP2 u<= OP3 872 | Tule(Operand, Operand, Operand), 873 | /// OP1 = OP2 ? OP3 : 0 874 | Ifs(Operand, Operand, Operand), 875 | 876 | // Control flow instructions 877 | /// Jumps to OP1 ? OP2 : OP3, continues virtual execution 878 | Js(Operand, Operand, Operand), 879 | /// Jumps to OP1, continues virtual execution 880 | Jmp(Operand), 881 | /// Jumps to OP1, continues real execution 882 | Vexit(Operand), 883 | /// Calls into OP1, pauses virtual execution until the call returns 884 | Vxcall(Operand), 885 | 886 | // Special instructions 887 | /// Placeholder 888 | Nop, 889 | /// Assumes all memory is read from 890 | Sfence, 891 | /// Assumes all memory is written to 892 | Lfence, 893 | /// Emits the opcode as is to the final instruction stream 894 | Vemit(Operand), 895 | /// Pins the register for read 896 | Vpinr(Operand), 897 | /// Pins the register for write 898 | Vpinw(Operand), 899 | /// Pins the memory location for read, with size = OP3 900 | Vpinrm(Operand, Operand, Operand), 901 | /// Pins the memory location for write, with size = OP3 902 | Vpinwm(Operand, Operand, Operand), 903 | } 904 | 905 | impl Op { 906 | /// Name of the operand 907 | pub fn name(&self) -> &'static str { 908 | match self { 909 | Op::Mov(_, _) => "mov", 910 | Op::Movsx(_, _) => "movsx", 911 | Op::Str(_, _, _) => "str", 912 | Op::Ldd(_, _, _) => "ldd", 913 | Op::Neg(_) => "neg", 914 | Op::Add(_, _) => "add", 915 | Op::Sub(_, _) => "sub", 916 | Op::Mul(_, _) => "mul", 917 | Op::Mulhi(_, _) => "mulhi", 918 | Op::Imul(_, _) => "imul", 919 | Op::Imulhi(_, _) => "imulhi", 920 | Op::Div(_, _, _) => "div", 921 | Op::Rem(_, _, _) => "rem", 922 | Op::Idiv(_, _, _) => "idiv", 923 | Op::Irem(_, _, _) => "irem", 924 | Op::Popcnt(_) => "popcnt", 925 | Op::Bsf(_) => "bsf", 926 | Op::Bsr(_) => "bsr", 927 | Op::Not(_) => "not", 928 | Op::Shr(_, _) => "shr", 929 | Op::Shl(_, _) => "shl", 930 | Op::Xor(_, _) => "xor", 931 | Op::Or(_, _) => "or", 932 | Op::And(_, _) => "and", 933 | Op::Ror(_, _) => "ror", 934 | Op::Rol(_, _) => "rol", 935 | Op::Tg(_, _, _) => "tg", 936 | Op::Tge(_, _, _) => "tge", 937 | Op::Te(_, _, _) => "te", 938 | Op::Tne(_, _, _) => "tne", 939 | Op::Tl(_, _, _) => "tl", 940 | Op::Tle(_, _, _) => "tle", 941 | Op::Tug(_, _, _) => "tug", 942 | Op::Tuge(_, _, _) => "tuge", 943 | Op::Tul(_, _, _) => "tul", 944 | Op::Tule(_, _, _) => "tule", 945 | Op::Ifs(_, _, _) => "ifs", 946 | Op::Js(_, _, _) => "js", 947 | Op::Jmp(_) => "jmp", 948 | Op::Vexit(_) => "vexit", 949 | Op::Vxcall(_) => "vxcall", 950 | Op::Nop => "nop", 951 | Op::Sfence => "sfence", 952 | Op::Lfence => "lfence", 953 | Op::Vemit(_) => "vemit", 954 | Op::Vpinr(_) => "vpinr", 955 | Op::Vpinw(_) => "vpinw", 956 | Op::Vpinrm(_, _, _) => "vpinrm", 957 | Op::Vpinwm(_, _, _) => "vpinwm", 958 | } 959 | } 960 | 961 | /// Operands for operator 962 | pub fn operands(&self) -> Vec<&Operand> { 963 | match *self { 964 | Op::Nop | Op::Sfence | Op::Lfence => vec![], 965 | Op::Neg(ref op1) 966 | | Op::Popcnt(ref op1) 967 | | Op::Bsf(ref op1) 968 | | Op::Bsr(ref op1) 969 | | Op::Not(ref op1) 970 | | Op::Jmp(ref op1) 971 | | Op::Vexit(ref op1) 972 | | Op::Vxcall(ref op1) 973 | | Op::Vemit(ref op1) 974 | | Op::Vpinr(ref op1) 975 | | Op::Vpinw(ref op1) => vec![op1], 976 | Op::Mov(ref op1, ref op2) 977 | | Op::Movsx(ref op1, ref op2) 978 | | Op::Add(ref op1, ref op2) 979 | | Op::Sub(ref op1, ref op2) 980 | | Op::Mul(ref op1, ref op2) 981 | | Op::Mulhi(ref op1, ref op2) 982 | | Op::Imul(ref op1, ref op2) 983 | | Op::Imulhi(ref op1, ref op2) 984 | | Op::Shr(ref op1, ref op2) 985 | | Op::Shl(ref op1, ref op2) 986 | | Op::Xor(ref op1, ref op2) 987 | | Op::Or(ref op1, ref op2) 988 | | Op::And(ref op1, ref op2) 989 | | Op::Ror(ref op1, ref op2) 990 | | Op::Rol(ref op1, ref op2) => vec![op1, op2], 991 | Op::Str(ref op1, ref op2, ref op3) 992 | | Op::Ldd(ref op1, ref op2, ref op3) 993 | | Op::Div(ref op1, ref op2, ref op3) 994 | | Op::Rem(ref op1, ref op2, ref op3) 995 | | Op::Idiv(ref op1, ref op2, ref op3) 996 | | Op::Irem(ref op1, ref op2, ref op3) 997 | | Op::Tg(ref op1, ref op2, ref op3) 998 | | Op::Tge(ref op1, ref op2, ref op3) 999 | | Op::Te(ref op1, ref op2, ref op3) 1000 | | Op::Tne(ref op1, ref op2, ref op3) 1001 | | Op::Tl(ref op1, ref op2, ref op3) 1002 | | Op::Tle(ref op1, ref op2, ref op3) 1003 | | Op::Tug(ref op1, ref op2, ref op3) 1004 | | Op::Tuge(ref op1, ref op2, ref op3) 1005 | | Op::Tul(ref op1, ref op2, ref op3) 1006 | | Op::Tule(ref op1, ref op2, ref op3) 1007 | | Op::Ifs(ref op1, ref op2, ref op3) 1008 | | Op::Js(ref op1, ref op2, ref op3) 1009 | | Op::Vpinrm(ref op1, ref op2, ref op3) 1010 | | Op::Vpinwm(ref op1, ref op2, ref op3) => vec![op1, op2, op3], 1011 | } 1012 | } 1013 | 1014 | /// Mutable operands for operator 1015 | pub fn operands_mut(&mut self) -> Vec<&mut Operand> { 1016 | match *self { 1017 | Op::Nop | Op::Sfence | Op::Lfence => vec![], 1018 | Op::Neg(ref mut op1) 1019 | | Op::Popcnt(ref mut op1) 1020 | | Op::Bsf(ref mut op1) 1021 | | Op::Bsr(ref mut op1) 1022 | | Op::Not(ref mut op1) 1023 | | Op::Jmp(ref mut op1) 1024 | | Op::Vexit(ref mut op1) 1025 | | Op::Vxcall(ref mut op1) 1026 | | Op::Vemit(ref mut op1) 1027 | | Op::Vpinr(ref mut op1) 1028 | | Op::Vpinw(ref mut op1) => vec![op1], 1029 | Op::Mov(ref mut op1, ref mut op2) 1030 | | Op::Movsx(ref mut op1, ref mut op2) 1031 | | Op::Add(ref mut op1, ref mut op2) 1032 | | Op::Sub(ref mut op1, ref mut op2) 1033 | | Op::Mul(ref mut op1, ref mut op2) 1034 | | Op::Mulhi(ref mut op1, ref mut op2) 1035 | | Op::Imul(ref mut op1, ref mut op2) 1036 | | Op::Imulhi(ref mut op1, ref mut op2) 1037 | | Op::Shr(ref mut op1, ref mut op2) 1038 | | Op::Shl(ref mut op1, ref mut op2) 1039 | | Op::Xor(ref mut op1, ref mut op2) 1040 | | Op::Or(ref mut op1, ref mut op2) 1041 | | Op::And(ref mut op1, ref mut op2) 1042 | | Op::Ror(ref mut op1, ref mut op2) 1043 | | Op::Rol(ref mut op1, ref mut op2) => vec![op1, op2], 1044 | Op::Str(ref mut op1, ref mut op2, ref mut op3) 1045 | | Op::Ldd(ref mut op1, ref mut op2, ref mut op3) 1046 | | Op::Div(ref mut op1, ref mut op2, ref mut op3) 1047 | | Op::Rem(ref mut op1, ref mut op2, ref mut op3) 1048 | | Op::Idiv(ref mut op1, ref mut op2, ref mut op3) 1049 | | Op::Irem(ref mut op1, ref mut op2, ref mut op3) 1050 | | Op::Tg(ref mut op1, ref mut op2, ref mut op3) 1051 | | Op::Tge(ref mut op1, ref mut op2, ref mut op3) 1052 | | Op::Te(ref mut op1, ref mut op2, ref mut op3) 1053 | | Op::Tne(ref mut op1, ref mut op2, ref mut op3) 1054 | | Op::Tl(ref mut op1, ref mut op2, ref mut op3) 1055 | | Op::Tle(ref mut op1, ref mut op2, ref mut op3) 1056 | | Op::Tug(ref mut op1, ref mut op2, ref mut op3) 1057 | | Op::Tuge(ref mut op1, ref mut op2, ref mut op3) 1058 | | Op::Tul(ref mut op1, ref mut op2, ref mut op3) 1059 | | Op::Tule(ref mut op1, ref mut op2, ref mut op3) 1060 | | Op::Ifs(ref mut op1, ref mut op2, ref mut op3) 1061 | | Op::Js(ref mut op1, ref mut op2, ref mut op3) 1062 | | Op::Vpinrm(ref mut op1, ref mut op2, ref mut op3) 1063 | | Op::Vpinwm(ref mut op1, ref mut op2, ref mut op3) => vec![op1, op2, op3], 1064 | } 1065 | } 1066 | 1067 | /// Returns if the instruction is volatile 1068 | pub fn is_volatile(&self) -> bool { 1069 | matches!( 1070 | self, 1071 | Op::Sfence 1072 | | Op::Lfence 1073 | | Op::Vemit(_) 1074 | | Op::Vpinr(_) 1075 | | Op::Vpinw(_) 1076 | | Op::Vpinrm(_, _, _) 1077 | | Op::Vpinwm(_, _, _) 1078 | ) 1079 | } 1080 | 1081 | /// Returns if the instruction is a branching operation 1082 | pub fn is_branching(&self) -> bool { 1083 | matches!( 1084 | self, 1085 | Op::Js(_, _, _) | Op::Jmp(_) | Op::Vexit(_) | Op::Vxcall(_) 1086 | ) 1087 | } 1088 | } 1089 | 1090 | /// Basic block containing a linear sequence of VTIL instructions 1091 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 1092 | #[derive(Debug)] 1093 | pub struct BasicBlock { 1094 | /// The virtual instruction pointer at entry 1095 | pub vip: Vip, 1096 | /// The stack pointer offset at entry 1097 | pub sp_offset: i64, 1098 | /// The stack instance index at entry 1099 | pub sp_index: u32, 1100 | /// Last temporary index used 1101 | pub last_temporary_index: u32, 1102 | /// List of instructions contained in this basic block (in order) 1103 | pub instructions: Vec, 1104 | /// Predecessor basic block entrypoint(s) 1105 | pub prev_vip: Vec, 1106 | /// Successor basic block entrypoint(s) 1107 | pub next_vip: Vec, 1108 | } 1109 | 1110 | impl BasicBlock { 1111 | /// Allocate a temporary register for this basic block 1112 | pub fn tmp(&mut self, bit_count: i32) -> RegisterDesc { 1113 | let reg = RegisterDesc { 1114 | flags: RegisterFlags::LOCAL, 1115 | combined_id: self.last_temporary_index as u64, 1116 | bit_count, 1117 | bit_offset: 0, 1118 | }; 1119 | self.last_temporary_index += 1; 1120 | reg 1121 | } 1122 | 1123 | /// Returns if the block is complete: terminated by a branching instruction 1124 | pub fn is_complete(&self) -> bool { 1125 | let instructions = &self.instructions; 1126 | !instructions.is_empty() && instructions[instructions.len() - 1].op.is_branching() 1127 | } 1128 | 1129 | /// Makes a new [`BasicBlock`] connected to the current block, at the specified 1130 | /// instruction pointer 1131 | /// 1132 | /// # Panics 1133 | /// 1134 | /// Panics if the block is incomplete, or `entry` is an invalid instruction 1135 | /// pointer 1136 | pub fn fork(&mut self, entry: Vip) -> BasicBlock { 1137 | assert!(self.is_complete()); 1138 | assert!(entry != Vip::invalid()); 1139 | 1140 | let basic_block = BasicBlock { 1141 | vip: entry, 1142 | sp_offset: 0, 1143 | sp_index: 0, 1144 | last_temporary_index: 0, 1145 | instructions: vec![], 1146 | prev_vip: vec![self.vip], 1147 | next_vip: vec![], 1148 | }; 1149 | 1150 | self.next_vip.push(entry); 1151 | 1152 | basic_block 1153 | } 1154 | } 1155 | 1156 | /// Alias for [`RoutineConvention`] for consistent naming 1157 | pub type SubroutineConvention = RoutineConvention; 1158 | 1159 | /// VTIL routine container 1160 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 1161 | #[derive(Debug)] 1162 | pub struct Routine { 1163 | /// Header containing metadata about the VTIL container 1164 | pub header: Header, 1165 | /// The entry virtual instruction pointer for this VTIL routine 1166 | pub vip: Vip, 1167 | /// Metadata regarding the calling conventions of the VTIL routine 1168 | pub routine_convention: RoutineConvention, 1169 | /// Metadata regarding the calling conventions of the VTIL subroutine 1170 | pub subroutine_convention: SubroutineConvention, 1171 | /// All special subroutine calling conventions in the top-level VTIL routine 1172 | pub spec_subroutine_conventions: Vec, 1173 | /// Reachable [`BasicBlock`]s generated during a code-discovery analysis pass 1174 | pub explored_blocks: IndexMap, 1175 | } 1176 | -------------------------------------------------------------------------------- /src/serialize.rs: -------------------------------------------------------------------------------- 1 | // BSD 3-Clause License 2 | // 3 | // Copyright © 2020-2021 Keegan Saunders 4 | // Copyright © 2020-2021 VTIL Project 5 | // All rights reserved. 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are met: 9 | // 10 | // 1. Redistributions of source code must retain the above copyright notice, this 11 | // list of conditions and the following disclaimer. 12 | // 13 | // 2. Redistributions in binary form must reproduce the above copyright notice, 14 | // this list of conditions and the following disclaimer in the documentation 15 | // and/or other materials provided with the distribution. 16 | // 17 | // 3. Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | // 32 | 33 | use indexmap::map::IndexMap; 34 | use scroll::{ 35 | ctx::{self, SizeWith}, 36 | Endian, Pread, Pwrite, 37 | }; 38 | use std::convert::TryInto; 39 | use std::mem::size_of; 40 | 41 | use 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 | 47 | const VTIL_MAGIC_1: u32 = 0x4c495456; 48 | const VTIL_MAGIC_2: u16 = 0xdead; 49 | 50 | impl ctx::SizeWith for ArchitectureIdentifier { 51 | fn size_with(_arch_id: &ArchitectureIdentifier) -> usize { 52 | size_of::() 53 | } 54 | } 55 | 56 | impl 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::(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 | 76 | impl ctx::TryIntoCtx for ArchitectureIdentifier { 77 | type Error = Error; 78 | 79 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 80 | sink.pwrite::(self as u8, 0)?; 81 | Ok(size_of::()) 82 | } 83 | } 84 | 85 | impl ctx::SizeWith
for Header { 86 | fn size_with(header: &Header) -> usize { 87 | let mut size = size_of::(); 88 | size += ArchitectureIdentifier::size_with(&header.arch_id); 89 | size += size_of::(); 90 | size += size_of::(); 91 | size 92 | } 93 | } 94 | 95 | impl 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::(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::(offset, endian)?; 110 | let _zero = source.gread::(offset)?; 111 | 112 | let magic = source.gread_with::(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 | 126 | impl ctx::TryIntoCtx for Header { 127 | type Error = Error; 128 | 129 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 130 | let offset = &mut 0; 131 | sink.gwrite::(VTIL_MAGIC_1, offset)?; 132 | sink.gwrite::(self.arch_id, offset)?; 133 | sink.gwrite::(0, offset)?; 134 | sink.gwrite::(VTIL_MAGIC_2, offset)?; 135 | Ok(*offset) 136 | } 137 | } 138 | 139 | impl ctx::SizeWith for Vip { 140 | fn size_with(_vip: &Vip) -> usize { 141 | size_of::() 142 | } 143 | } 144 | 145 | impl 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::(offset, endian)?); 151 | assert_eq!(Vip::size_with(&vip), *offset); 152 | Ok((vip, *offset)) 153 | } 154 | } 155 | 156 | impl ctx::TryIntoCtx for Vip { 157 | type Error = Error; 158 | 159 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 160 | Ok(sink.pwrite::(self.0, 0)?) 161 | } 162 | } 163 | 164 | impl ctx::SizeWith for RegisterDesc { 165 | fn size_with(_reg: &RegisterDesc) -> usize { 166 | let mut size = 0; 167 | size += size_of::(); 168 | size += size_of::(); 169 | size += size_of::(); 170 | size += size_of::(); 171 | size 172 | } 173 | } 174 | 175 | impl 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::(offset, endian)?) 183 | }; 184 | 185 | let combined_id = source.gread_with::(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::(offset, endian)?; 193 | let bit_offset = source.gread_with::(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 | 206 | impl ctx::TryIntoCtx for RegisterDesc { 207 | type Error = Error; 208 | 209 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 210 | let offset = &mut 0; 211 | sink.gwrite::(self.flags.bits(), offset)?; 212 | sink.gwrite::(self.combined_id, offset)?; 213 | sink.gwrite::(self.bit_count, offset)?; 214 | sink.gwrite::(self.bit_offset, offset)?; 215 | Ok(*offset) 216 | } 217 | } 218 | 219 | impl ctx::SizeWith for RoutineConvention { 220 | fn size_with(routine_convention: &RoutineConvention) -> usize { 221 | let mut size = 0; 222 | 223 | size += size_of::(); 224 | for reg in &routine_convention.volatile_registers { 225 | size += RegisterDesc::size_with(reg); 226 | } 227 | 228 | size += size_of::(); 229 | for reg in &routine_convention.param_registers { 230 | size += RegisterDesc::size_with(reg); 231 | } 232 | 233 | size += size_of::(); 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::(); 240 | size += size_of::(); 241 | 242 | size 243 | } 244 | } 245 | 246 | impl 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::(offset, endian)?; 253 | let mut volatile_registers = 254 | Vec::::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::(offset, endian)?; 260 | let mut param_registers = 261 | Vec::::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::(offset, endian)?; 267 | let mut retval_registers = 268 | Vec::::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::(offset, endian)?; 274 | let shadow_space = source.gread_with::(offset, endian)?; 275 | let purge_stack = source.gread_with::(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 | 290 | impl ctx::TryIntoCtx for RoutineConvention { 291 | type Error = Error; 292 | 293 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 294 | let offset = &mut 0; 295 | 296 | sink.gwrite::(self.volatile_registers.len().try_into()?, offset)?; 297 | for reg in self.volatile_registers { 298 | sink.gwrite::(reg, offset)?; 299 | } 300 | 301 | sink.gwrite::(self.param_registers.len().try_into()?, offset)?; 302 | for reg in self.param_registers { 303 | sink.gwrite::(reg, offset)?; 304 | } 305 | 306 | sink.gwrite::(self.retval_registers.len().try_into()?, offset)?; 307 | for reg in self.retval_registers { 308 | sink.gwrite::(reg, offset)?; 309 | } 310 | 311 | sink.gwrite::(self.frame_register, offset)?; 312 | sink.gwrite::(self.shadow_space, offset)?; 313 | sink.gwrite::(self.purge_stack.into(), offset)?; 314 | Ok(*offset) 315 | } 316 | } 317 | 318 | impl ctx::SizeWith for ImmediateDesc { 319 | fn size_with(_imm: &ImmediateDesc) -> usize { 320 | let mut size = 0; 321 | size += size_of::(); 322 | size += size_of::(); 323 | size 324 | } 325 | } 326 | 327 | impl 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::(offset, endian)?; 334 | let bit_count = source.gread_with::(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 | 345 | impl ctx::TryIntoCtx for ImmediateDesc { 346 | type Error = Error; 347 | 348 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 349 | let offset = &mut 0; 350 | sink.gwrite::(self.value.u64(), offset)?; 351 | sink.gwrite::(self.bit_count, offset)?; 352 | Ok(*offset) 353 | } 354 | } 355 | 356 | impl ctx::SizeWith for Operand { 357 | fn size_with(operand: &Operand) -> usize { 358 | let mut size = 0; 359 | size += size_of::(); 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 | 368 | impl 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::(offset, endian)?; 375 | let operand = match sp_index { 376 | 0 => Operand::ImmediateDesc(source.gread_with::(offset, endian)?), 377 | 1 => Operand::RegisterDesc(source.gread_with::(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 | 385 | impl ctx::TryIntoCtx for Operand { 386 | type Error = Error; 387 | 388 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 389 | let offset = &mut 0; 390 | match self { 391 | Operand::ImmediateDesc(i) => { 392 | sink.gwrite::(0, offset)?; 393 | sink.gwrite::(i, offset)?; 394 | } 395 | Operand::RegisterDesc(r) => { 396 | sink.gwrite::(1, offset)?; 397 | sink.gwrite::(r, offset)?; 398 | } 399 | } 400 | Ok(*offset) 401 | } 402 | } 403 | 404 | impl ctx::SizeWith for Op { 405 | fn size_with(op: &Op) -> usize { 406 | let mut size = 0; 407 | size += size_of::(); 408 | size += op.name().as_bytes().len(); 409 | size += size_of::(); 410 | for operand in op.operands() { 411 | size += Operand::size_with(operand); 412 | } 413 | size 414 | } 415 | } 416 | 417 | impl<'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::(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::(offset, endian)?; 427 | 428 | let op = match name { 429 | "mov" => { 430 | if operands_count == 2 { 431 | let op1 = source.gread_with::(offset, endian)?; 432 | let op2 = source.gread_with::(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::(offset, endian)?; 441 | let op2 = source.gread_with::(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::(offset, endian)?; 450 | let op2 = source.gread_with::(offset, endian)?; 451 | let op3 = source.gread_with::(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::(offset, endian)?; 460 | let op2 = source.gread_with::(offset, endian)?; 461 | let op3 = source.gread_with::(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::(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::(offset, endian)?; 478 | let op2 = source.gread_with::(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::(offset, endian)?; 487 | let op2 = source.gread_with::(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::(offset, endian)?; 496 | let op2 = source.gread_with::(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::(offset, endian)?; 505 | let op2 = source.gread_with::(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::(offset, endian)?; 514 | let op2 = source.gread_with::(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::(offset, endian)?; 523 | let op2 = source.gread_with::(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::(offset, endian)?; 532 | let op2 = source.gread_with::(offset, endian)?; 533 | let op3 = source.gread_with::(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::(offset, endian)?; 542 | let op2 = source.gread_with::(offset, endian)?; 543 | let op3 = source.gread_with::(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::(offset, endian)?; 552 | let op2 = source.gread_with::(offset, endian)?; 553 | let op3 = source.gread_with::(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::(offset, endian)?; 562 | let op2 = source.gread_with::(offset, endian)?; 563 | let op3 = source.gread_with::(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::(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::(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::(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::(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::(offset, endian)?; 604 | let op2 = source.gread_with::(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::(offset, endian)?; 613 | let op2 = source.gread_with::(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::(offset, endian)?; 622 | let op2 = source.gread_with::(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::(offset, endian)?; 631 | let op2 = source.gread_with::(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::(offset, endian)?; 640 | let op2 = source.gread_with::(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::(offset, endian)?; 649 | let op2 = source.gread_with::(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::(offset, endian)?; 658 | let op2 = source.gread_with::(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::(offset, endian)?; 667 | let op2 = source.gread_with::(offset, endian)?; 668 | let op3 = source.gread_with::(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::(offset, endian)?; 677 | let op2 = source.gread_with::(offset, endian)?; 678 | let op3 = source.gread_with::(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::(offset, endian)?; 687 | let op2 = source.gread_with::(offset, endian)?; 688 | let op3 = source.gread_with::(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::(offset, endian)?; 697 | let op2 = source.gread_with::(offset, endian)?; 698 | let op3 = source.gread_with::(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::(offset, endian)?; 707 | let op2 = source.gread_with::(offset, endian)?; 708 | let op3 = source.gread_with::(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::(offset, endian)?; 717 | let op2 = source.gread_with::(offset, endian)?; 718 | let op3 = source.gread_with::(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::(offset, endian)?; 727 | let op2 = source.gread_with::(offset, endian)?; 728 | let op3 = source.gread_with::(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::(offset, endian)?; 737 | let op2 = source.gread_with::(offset, endian)?; 738 | let op3 = source.gread_with::(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::(offset, endian)?; 747 | let op2 = source.gread_with::(offset, endian)?; 748 | let op3 = source.gread_with::(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::(offset, endian)?; 757 | let op2 = source.gread_with::(offset, endian)?; 758 | let op3 = source.gread_with::(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::(offset, endian)?; 767 | let op2 = source.gread_with::(offset, endian)?; 768 | let op3 = source.gread_with::(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::(offset, endian)?; 777 | let op2 = source.gread_with::(offset, endian)?; 778 | let op3 = source.gread_with::(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::(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::(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::(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::(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::(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::(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::(offset, endian)?; 856 | let op2 = source.gread_with::(offset, endian)?; 857 | let op3 = source.gread_with::(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::(offset, endian)?; 866 | let op2 = source.gread_with::(offset, endian)?; 867 | let op3 = source.gread_with::(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 | 880 | impl ctx::TryIntoCtx for Op { 881 | type Error = Error; 882 | 883 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 884 | let offset = &mut 0; 885 | 886 | let name = self.name(); 887 | 888 | sink.gwrite::(name.len().try_into()?, offset)?; 889 | sink.gwrite::<&[u8]>(name.as_bytes(), offset)?; 890 | 891 | sink.gwrite::(self.operands().len().try_into()?, offset)?; 892 | for operand in self.operands() { 893 | sink.gwrite::(*operand, offset)?; 894 | } 895 | 896 | Ok(*offset) 897 | } 898 | } 899 | 900 | impl ctx::SizeWith 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::(); 906 | size += size_of::(); 907 | size += size_of::(); 908 | size 909 | } 910 | } 911 | 912 | impl 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::(offset, endian)?; 919 | let vip = source.gread_with::(offset, endian)?; 920 | let sp_offset = source.gread_with::(offset, endian)?; 921 | let sp_index = source.gread_with::(offset, endian)?; 922 | let sp_reset = source.gread::(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 | 936 | impl ctx::TryIntoCtx for Instruction { 937 | type Error = Error; 938 | 939 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 940 | let offset = &mut 0; 941 | 942 | sink.gwrite::(self.op, offset)?; 943 | sink.gwrite::(self.vip, offset)?; 944 | sink.gwrite::(self.sp_offset, offset)?; 945 | sink.gwrite::(self.sp_index, offset)?; 946 | sink.gwrite::(self.sp_reset.into(), offset)?; 947 | 948 | Ok(*offset) 949 | } 950 | } 951 | 952 | impl ctx::SizeWith 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::(); 958 | size += size_of::(); 959 | size += size_of::(); 960 | 961 | size += size_of::(); 962 | for instr in &basic_block.instructions { 963 | size += Instruction::size_with(instr); 964 | } 965 | 966 | size += size_of::(); 967 | for prev_vip in &basic_block.prev_vip { 968 | size += Vip::size_with(prev_vip); 969 | } 970 | 971 | size += size_of::(); 972 | for next_vip in &basic_block.next_vip { 973 | size += Vip::size_with(next_vip); 974 | } 975 | 976 | size 977 | } 978 | } 979 | 980 | impl 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::(offset, endian)?); 987 | let sp_offset = source.gread_with::(offset, endian)?; 988 | let sp_index = source.gread_with::(offset, endian)?; 989 | let last_temporary_index = source.gread_with::(offset, endian)?; 990 | 991 | let instruction_count = source.gread_with::(offset, endian)?; 992 | let mut instructions = Vec::::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::(offset, endian)?; 998 | let mut prev_vip = Vec::::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::(offset, endian)?; 1004 | let mut next_vip = Vec::::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 | 1023 | impl ctx::TryIntoCtx for BasicBlock { 1024 | type Error = Error; 1025 | 1026 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 1027 | let offset = &mut 0; 1028 | 1029 | sink.gwrite::(self.vip, offset)?; 1030 | sink.gwrite::(self.sp_offset, offset)?; 1031 | sink.gwrite::(self.sp_index, offset)?; 1032 | sink.gwrite::(self.last_temporary_index, offset)?; 1033 | 1034 | sink.gwrite::(self.instructions.len().try_into()?, offset)?; 1035 | for instr in self.instructions { 1036 | sink.gwrite::(instr, offset)?; 1037 | } 1038 | 1039 | sink.gwrite::(self.prev_vip.len().try_into()?, offset)?; 1040 | for vip in self.prev_vip { 1041 | sink.gwrite::(vip, offset)?; 1042 | } 1043 | 1044 | sink.gwrite::(self.next_vip.len().try_into()?, offset)?; 1045 | for vip in self.next_vip { 1046 | sink.gwrite::(vip, offset)?; 1047 | } 1048 | 1049 | Ok(*offset) 1050 | } 1051 | } 1052 | 1053 | impl ctx::SizeWith 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::(); 1062 | for convention in &routine.spec_subroutine_conventions { 1063 | size += SubroutineConvention::size_with(convention); 1064 | } 1065 | 1066 | size += size_of::(); 1067 | for basic_block in routine.explored_blocks.values() { 1068 | size += BasicBlock::size_with(basic_block); 1069 | } 1070 | size 1071 | } 1072 | } 1073 | 1074 | impl 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::
(offset, endian)?; 1081 | let vip = source.gread_with::(offset, endian)?; 1082 | let routine_convention = source.gread_with::(offset, endian)?; 1083 | let subroutine_convention = source.gread_with::(offset, endian)?; 1084 | 1085 | let spec_subroutine_conventions_count = source.gread_with::(offset, endian)?; 1086 | let mut spec_subroutine_conventions = 1087 | Vec::::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::(offset, endian)?; 1093 | let mut explored_blocks = IndexMap::new(); 1094 | for _ in 0..explored_blocks_count { 1095 | let basic_block = source.gread_with::(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 | 1112 | impl ctx::TryIntoCtx for Routine { 1113 | type Error = Error; 1114 | 1115 | fn try_into_ctx(self, sink: &mut [u8], _endian: Endian) -> Result { 1116 | let offset = &mut 0; 1117 | 1118 | sink.gwrite::
(self.header, offset)?; 1119 | sink.gwrite::(self.vip, offset)?; 1120 | sink.gwrite::(self.routine_convention, offset)?; 1121 | sink.gwrite::(self.subroutine_convention, offset)?; 1122 | 1123 | sink.gwrite::(self.spec_subroutine_conventions.len().try_into()?, offset)?; 1124 | for convention in self.spec_subroutine_conventions { 1125 | sink.gwrite::(convention, offset)?; 1126 | } 1127 | 1128 | sink.gwrite::(self.explored_blocks.len().try_into()?, offset)?; 1129 | for (_, basic_block) in self.explored_blocks.into_iter() { 1130 | sink.gwrite::(basic_block, offset)?; 1131 | } 1132 | 1133 | Ok(*offset) 1134 | } 1135 | } 1136 | 1137 | #[cfg(test)] 1138 | mod 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 | } 1151 | --------------------------------------------------------------------------------