├── .gitignore ├── .rustfmt.toml ├── README.md ├── src ├── builder │ ├── formater.rs │ ├── display.rs │ ├── helper.rs │ ├── disassembly.rs │ ├── register.rs │ ├── disassembler │ │ ├── mod.rs │ │ ├── table.rs │ │ └── constructor │ ├── mod.rs │ ├── function.rs │ ├── token.rs │ ├── context.rs │ └── meaning.rs └── lib.rs ├── Cargo.toml ├── LICENSE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 80 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Sleigh2Rust 2 | 3 | The Sleigh2Rust project converts the Ghidra Sleigh code into rust code, capable 4 | of disassemble and (in the future) emulate multiple cpu architetures. It plan to 5 | accomplish that by using the lib [sleigh-rs](https://github.com/rbran/sleigh-rs). 6 | 7 | An output example of this project can be found on [sleigh3rust](https://github.com/rbran/sleigh3rust). 8 | -------------------------------------------------------------------------------- /src/builder/formater.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | 3 | #[derive(Clone, Copy)] 4 | struct SeparateTokens<'a>(&'a str); 5 | 6 | pub fn from_sleigh(input: &str) -> Cow<'_, str> { 7 | input 8 | .find('.') 9 | .map(|_| Cow::Owned(input.replace('.', "_"))) 10 | .unwrap_or(Cow::Borrowed(input)) 11 | //separate Snake case into multiple tokens: 12 | //eg: ArmPCRelImmed12 => [arm, pc, rel, immed12] 13 | //.map(SeparateTokens) 14 | //.flatten() 15 | } 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sleigh2rust" 3 | version = "0.1.6" 4 | edition = "2021" 5 | readme = "README.md" 6 | repository = "https://github.com/rbran/sleigh2rust" 7 | license = "MIT" 8 | description = "Transpile Ghidra Sleigh parser into rust" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | sleigh-rs = { path = "../sleigh-rs", version = "0.1.5" } 14 | quote = "1" 15 | bitvec = "1" 16 | proc-macro2 = "1" 17 | indexmap = "1.9" 18 | ethnum = "1" 19 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | use quote::ToTokens; 4 | 5 | use proc_macro2::TokenStream; 6 | 7 | use sleigh_rs::{file_to_sleigh, SleighError}; 8 | 9 | mod builder; 10 | use builder::Disassembler; 11 | 12 | pub(crate) use sleigh_rs::{DisassemblyType, NonZeroTypeU, NumberSuperSigned}; 13 | pub(crate) const DISASSEMBLY_ALLOW_OVERFLOW: bool = true; 14 | 15 | fn disassembler( 16 | file: impl AsRef, 17 | debug: bool, 18 | ) -> Result { 19 | let sleigh = file_to_sleigh(file.as_ref())?; 20 | Ok(Disassembler::new(sleigh, debug).into_token_stream()) 21 | } 22 | 23 | pub fn generate_disassembler( 24 | file: impl AsRef, 25 | ) -> Result { 26 | disassembler(file, false) 27 | } 28 | 29 | pub fn generate_debug_disassembler( 30 | file: impl AsRef, 31 | ) -> Result { 32 | disassembler(file, true) 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 rbran 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/builder/display.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Ident, TokenStream}; 2 | use quote::{format_ident, quote}; 3 | 4 | use super::{Disassembler, WorkType}; 5 | 6 | pub const DISPLAY_WORK_TYPE: WorkType = 7 | WorkType::new_int_bits(sleigh_rs::NumberSigned::BITS, false); 8 | #[derive(Debug, Clone)] 9 | pub struct DisplayElement { 10 | pub name: Ident, 11 | pub literal_var: Ident, 12 | pub register_var: Ident, 13 | pub number_var: Ident, 14 | } 15 | impl DisplayElement { 16 | pub fn new(name: Ident) -> Self { 17 | Self { 18 | name, 19 | literal_var: format_ident!("Literal"), 20 | register_var: format_ident!("Register"), 21 | number_var: format_ident!("Number"), 22 | } 23 | } 24 | pub fn to_tokens( 25 | &self, 26 | tokens: &mut TokenStream, 27 | disassembler: &Disassembler, 28 | ) { 29 | let Self { 30 | name, 31 | literal_var, 32 | register_var, 33 | number_var, 34 | } = self; 35 | let registers = disassembler.registers.name(); 36 | let number_type = DISPLAY_WORK_TYPE; 37 | tokens.extend(quote! { 38 | #[derive(Clone, Copy, Debug)] 39 | pub enum #name { 40 | #literal_var(&'static str), 41 | #register_var(#registers), 42 | #number_var(bool, bool, #number_type), 43 | } 44 | impl core::fmt::Display for #name { 45 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 46 | match self { 47 | Self::Literal(lit) => lit.fmt(f), 48 | Self::Register(reg) => reg.fmt(f), 49 | Self::Number(true, false, value) => { 50 | write!(f, "0x{:x}", value) 51 | } 52 | Self::Number(true, true, value) => { 53 | write!(f, "-0x{:x}", value) 54 | } 55 | Self::Number(false, false, value) => value.fmt(f), 56 | Self::Number(false, true, value) => { 57 | write!(f, "-{:x}", value) 58 | } 59 | } 60 | } 61 | } 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/builder/helper.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Range; 2 | 3 | use proc_macro2::{Ident, TokenStream}; 4 | 5 | use quote::{format_ident, quote, ToTokens}; 6 | 7 | use sleigh_rs::{pattern::BitConstraint, Endian}; 8 | 9 | use super::{ToLiteral, WorkType}; 10 | 11 | // each bit have four possible states: 12 | // mask 1, value X: bit is restricted to `value` 13 | // mask 0, value 0: bit is unrestricted 14 | // mask 0, value 1: bit is restricted but value can't be defined at compile time 15 | #[derive(Clone, Copy, Default, Debug)] 16 | pub struct PatternByte { 17 | pub(crate) value: u8, 18 | pub(crate) mask: u8, 19 | } 20 | 21 | impl PatternByte { 22 | pub(crate) fn from_bit_constraints(bits: &[BitConstraint]) -> Vec { 23 | let context_bytes = (usize::try_from(bits.len()).unwrap() + 7) / 8; 24 | let mut bytes: Vec = 25 | vec![PatternByte::default(); context_bytes]; 26 | for (bit, bit_constraint) in bits.iter().enumerate() { 27 | match bit_constraint { 28 | BitConstraint::Unrestrained => {} 29 | BitConstraint::Restrained => { 30 | bytes[bit / 8].value |= 1 << (bit % 8); 31 | } 32 | BitConstraint::Defined(value) => { 33 | bytes[bit / 8].value |= (*value as u8) << (bit % 8); 34 | bytes[bit / 8].mask |= 1 << (bit % 8); 35 | } 36 | } 37 | } 38 | bytes 39 | } 40 | pub fn defined_value(&self) -> u8 { 41 | self.value & self.mask 42 | } 43 | 44 | pub fn defined_bits(&self) -> u8 { 45 | self.mask 46 | } 47 | } 48 | 49 | pub fn bytes_from_value( 50 | endian: Endian, 51 | type_bytes: u32, 52 | value_bytes: u32, 53 | ) -> (u32, u32) { 54 | assert!(type_bytes >= value_bytes); 55 | match endian { 56 | // in le, the lsB is first, so we copy from 0 to the value len 57 | Endian::Little => (0, value_bytes), 58 | //in be, the msB is first, so we copy from (len-1) to (len-1-value_len) 59 | Endian::Big => (type_bytes - 1, (type_bytes - 1) - value_bytes), 60 | } 61 | } 62 | 63 | pub fn rotation_and_mask_from_range(bits: Range) -> (u128, u128) { 64 | let bit_lsb = bits.start; 65 | let field_len = bits.len() as u32; 66 | let mask = u128::MAX >> (u128::BITS - field_len); 67 | (bit_lsb.into(), mask) 68 | } 69 | 70 | pub fn bitrange_from_value( 71 | bits: Range, 72 | final_type: WorkType, 73 | raw_value: impl ToTokens, 74 | ) -> TokenStream { 75 | let (rotation, mask) = rotation_and_mask_from_range(bits); 76 | let mask = mask.unsuffixed(); 77 | let rotation = rotation.unsuffixed(); 78 | quote! {(((#raw_value >> #rotation) & #mask) as #final_type)} 79 | } 80 | 81 | pub fn sign_from_value( 82 | len_bits: u32, 83 | final_type: WorkType, 84 | raw_value: impl ToTokens, 85 | ) -> TokenStream { 86 | let sign_bit = 1u128 << (len_bits - 1); 87 | let mask = sign_bit - 1; 88 | 89 | let sign_bit = sign_bit.unsuffixed(); 90 | let mask = mask.unsuffixed(); 91 | quote! {( 92 | // if negative add the negative part 93 | if #raw_value & #sign_bit != 0 { -1 & !#mask } else { 0 } 94 | // or with the value part 95 | | #raw_value as #final_type 96 | )} 97 | } 98 | 99 | pub fn from_endian_bytes(endian: Endian) -> Ident { 100 | match endian { 101 | Endian::Little => format_ident!("from_le_bytes"), 102 | Endian::Big => format_ident!("from_be_bytes"), 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/builder/disassembly.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | 3 | use quote::{quote, ToTokens}; 4 | 5 | use sleigh_rs::disassembly::{ 6 | Assertation, Assignment, Expr, ExprElement, GlobalSet, Op, OpUnary, 7 | ReadScope, Variable, VariableId, 8 | }; 9 | 10 | fn disassembly_op(x: impl ToTokens, op: &Op, y: impl ToTokens) -> TokenStream { 11 | match (crate::DISASSEMBLY_ALLOW_OVERFLOW, op) { 12 | (true, Op::Add) => quote! {#x.wrapping_add(#y)}, 13 | (true, Op::Sub) => quote! {#x.wrapping_sub(#y)}, 14 | (true, Op::Mul) => quote! {#x.wrapping_mul(#y)}, 15 | (true, Op::Div) => quote! {#x.wrapping_div(#y)}, 16 | (true, Op::Asr) => quote! { 17 | u32::try_from(#y).ok().and_then(|shr| #x.checked_shr(shr)).unwrap_or(0) 18 | }, 19 | (true, Op::Lsl) => quote! { 20 | u32::try_from(#y).ok().and_then(|shl| #x.checked_shl(shl)).unwrap_or(0) 21 | }, 22 | (false, Op::Add) => quote! {(#x + #y)}, 23 | (false, Op::Sub) => quote! {(#x - #y)}, 24 | (false, Op::Mul) => quote! {(#x * #y)}, 25 | (false, Op::Div) => quote! {(#x / #y)}, 26 | (false, Op::Asr) => quote! {(#x >> #y)}, 27 | (false, Op::Lsl) => quote! {(#x << #y)}, 28 | //bit op, works the same way unsigned/signed, so use unsigned 29 | (_, Op::And) => quote! {(#x & #y)}, 30 | (_, Op::Or) => quote! {(#x | #y)}, 31 | (_, Op::Xor) => quote! {(#x ^ #y)}, 32 | } 33 | } 34 | fn op_unary(op: &OpUnary, x: impl ToTokens) -> TokenStream { 35 | match op { 36 | OpUnary::Negation => quote! {(!#x)}, 37 | OpUnary::Negative => quote! {(-#x)}, 38 | } 39 | } 40 | pub trait DisassemblyGenerator { 41 | fn global_set(&self, global_set: &GlobalSet) -> TokenStream; 42 | fn value(&self, value: &ReadScope) -> TokenStream; 43 | fn set_context( 44 | &self, 45 | id: &sleigh_rs::ContextId, 46 | value: TokenStream, 47 | ) -> TokenStream; 48 | fn new_variable( 49 | &mut self, 50 | var_id: &VariableId, 51 | variable: &Variable, 52 | ) -> TokenStream; 53 | fn var_name(&self, var: &VariableId) -> TokenStream; 54 | fn expr(&self, expr: &Expr) -> TokenStream { 55 | let mut work_stack: Vec<_> = Vec::with_capacity(2); 56 | for ele in expr.elements().iter() { 57 | //the rpn stack that result in a work_stack bigger then 2 is invalid 58 | match (ele, work_stack.len()) { 59 | (ExprElement::Value { value, location: _ }, _) => { 60 | work_stack.push(self.value(value)) 61 | } 62 | (ExprElement::Op(op), 2..) => { 63 | let y = work_stack.pop().unwrap(); 64 | let x = work_stack.pop().unwrap(); 65 | let op = disassembly_op(x, op, y); 66 | work_stack.push(op); 67 | } 68 | (ExprElement::OpUnary(op), 1..) => { 69 | let x = work_stack.pop().unwrap(); 70 | let op = op_unary(op, x); 71 | work_stack.push(op); 72 | } 73 | _ => unreachable!(), 74 | } 75 | } 76 | assert_eq!(work_stack.len(), 1); 77 | match work_stack.pop() { 78 | Some(out) => out, 79 | _ => unreachable!(), 80 | } 81 | } 82 | fn set_variable( 83 | &self, 84 | var: &VariableId, 85 | value: TokenStream, 86 | ) -> TokenStream { 87 | let var_name = self.var_name(var); 88 | quote! { #var_name = #value; } 89 | } 90 | fn assignment(&self, ass: &Assignment) -> TokenStream { 91 | use sleigh_rs::disassembly::WriteScope::*; 92 | let value = self.expr(&ass.right); 93 | match &ass.left { 94 | Context(context) => self.set_context(context, value), 95 | Local(variable) => self.set_variable(variable, value), 96 | } 97 | } 98 | fn disassembly( 99 | &self, 100 | assertations: &mut dyn Iterator, 101 | ) -> TokenStream { 102 | assertations 103 | .map(|ass| { 104 | use sleigh_rs::disassembly::Assertation::*; 105 | match ass { 106 | GlobalSet(global) => self.global_set(global), 107 | Assignment(ass) => self.assignment(ass), 108 | } 109 | }) 110 | .collect() 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/builder/register.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | use proc_macro2::{Ident, TokenStream}; 4 | use quote::{format_ident, quote}; 5 | 6 | use super::{formater::*, Disassembler}; 7 | 8 | #[derive(Clone, Debug)] 9 | pub struct RegistersEnum { 10 | pub name: Ident, 11 | pub registers: Vec, 12 | } 13 | 14 | impl RegistersEnum { 15 | pub fn from_all(name: Ident, sleigh: &sleigh_rs::Sleigh) -> Self { 16 | Self::from_iterator(name, sleigh.varnodes().iter()) 17 | } 18 | 19 | //enum from only the Registers that can be printed 20 | #[allow(dead_code)] 21 | pub fn from_printable(name: Ident, sleigh: &sleigh_rs::Sleigh) -> Self { 22 | use sleigh_rs::display::DisplayElement::*; 23 | use sleigh_rs::token::TokenFieldAttach; 24 | use sleigh_rs::varnode::ContextAttach; 25 | let mut vars = HashSet::new(); 26 | let add_varnodes = |vars: &mut HashSet<_>, id| { 27 | for (_i, var) in sleigh.attach_varnode(id).0.iter() { 28 | vars.insert(*var); 29 | } 30 | }; 31 | for table in sleigh.tables().iter() { 32 | for constructor in table.constructors().iter() { 33 | for element in constructor.display.elements() { 34 | match element { 35 | Varnode(var) => { 36 | vars.insert(*var); 37 | } 38 | Context(context) => { 39 | match sleigh.context(*context).attach { 40 | ContextAttach::NoAttach(_) 41 | | ContextAttach::Literal(_) => {} 42 | ContextAttach::Varnode(id) => { 43 | add_varnodes(&mut vars, id) 44 | } 45 | } 46 | } 47 | TokenField(token_field) => { 48 | match sleigh.token_field(*token_field).attach { 49 | TokenFieldAttach::NoAttach(_) 50 | | TokenFieldAttach::Literal(_) 51 | | TokenFieldAttach::Number(_, _) => {} 52 | TokenFieldAttach::Varnode(id) => { 53 | add_varnodes(&mut vars, id) 54 | } 55 | } 56 | } 57 | InstStart(_) | InstNext(_) | Disassembly(_) 58 | | Table(_) | Literal(_) | Space => {} 59 | } 60 | } 61 | } 62 | } 63 | //TODO: from meaning, with could use the meaning to display 64 | Self::from_iterator(name, vars.into_iter().map(|id| sleigh.varnode(id))) 65 | } 66 | 67 | pub fn from_iterator<'a>( 68 | name: Ident, 69 | registers: impl Iterator, 70 | ) -> Self { 71 | let registers = registers 72 | .map(|varnode| format_ident!("{}", from_sleigh(varnode.name()))) 73 | .collect(); 74 | Self { name, registers } 75 | } 76 | pub fn name(&self) -> &Ident { 77 | &self.name 78 | } 79 | pub fn registers( 80 | &self, 81 | ) -> impl Iterator { 82 | self.registers 83 | .iter() 84 | .enumerate() 85 | .map(|(i, name)| (name, sleigh_rs::VarnodeId(i))) 86 | } 87 | pub fn register(&self, id: sleigh_rs::VarnodeId) -> &Ident { 88 | &self.registers[id.0] 89 | } 90 | pub fn to_tokens( 91 | &self, 92 | tokens: &mut TokenStream, 93 | disassembler: &Disassembler, 94 | ) { 95 | let name = self.name(); 96 | let elements_names = self.registers.iter(); 97 | let elements_names2 = self.registers.iter(); 98 | let elements_display = self 99 | .registers() 100 | .map(|(_name, id)| disassembler.sleigh.varnode(id).name()); 101 | tokens.extend(quote! { 102 | #[derive(Clone, Copy, Debug)] 103 | pub enum #name { 104 | #(#elements_names),* 105 | } 106 | impl #name { 107 | fn as_str(&self) -> &'static str { 108 | match self { 109 | #(Self::#elements_names2 => #elements_display,)* 110 | } 111 | } 112 | } 113 | impl core::fmt::Display for #name { 114 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result { 115 | write!(f, "{}", self.as_str()) 116 | } 117 | } 118 | }) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "1.1.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 10 | 11 | [[package]] 12 | name = "bitvec" 13 | version = "1.0.1" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 16 | dependencies = [ 17 | "funty", 18 | "radium", 19 | "tap", 20 | "wyz", 21 | ] 22 | 23 | [[package]] 24 | name = "ethnum" 25 | version = "1.3.2" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "0198b9d0078e0f30dedc7acbb21c974e838fc8fae3ee170128658a98cb2c1c04" 28 | 29 | [[package]] 30 | name = "funty" 31 | version = "2.0.0" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 34 | 35 | [[package]] 36 | name = "hashbrown" 37 | version = "0.12.3" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 40 | 41 | [[package]] 42 | name = "indexmap" 43 | version = "1.9.3" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 46 | dependencies = [ 47 | "autocfg", 48 | "hashbrown", 49 | ] 50 | 51 | [[package]] 52 | name = "memchr" 53 | version = "2.5.0" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 56 | 57 | [[package]] 58 | name = "minimal-lexical" 59 | version = "0.2.1" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 62 | 63 | [[package]] 64 | name = "nom" 65 | version = "7.1.3" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 68 | dependencies = [ 69 | "memchr", 70 | "minimal-lexical", 71 | ] 72 | 73 | [[package]] 74 | name = "proc-macro2" 75 | version = "1.0.66" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" 78 | dependencies = [ 79 | "unicode-ident", 80 | ] 81 | 82 | [[package]] 83 | name = "quote" 84 | version = "1.0.31" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" 87 | dependencies = [ 88 | "proc-macro2", 89 | ] 90 | 91 | [[package]] 92 | name = "radium" 93 | version = "0.7.0" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 96 | 97 | [[package]] 98 | name = "sleigh-rs" 99 | version = "0.1.5" 100 | dependencies = [ 101 | "nom", 102 | "thiserror", 103 | ] 104 | 105 | [[package]] 106 | name = "sleigh2rust" 107 | version = "0.1.6" 108 | dependencies = [ 109 | "bitvec", 110 | "ethnum", 111 | "indexmap", 112 | "proc-macro2", 113 | "quote", 114 | "sleigh-rs", 115 | ] 116 | 117 | [[package]] 118 | name = "syn" 119 | version = "2.0.26" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" 122 | dependencies = [ 123 | "proc-macro2", 124 | "quote", 125 | "unicode-ident", 126 | ] 127 | 128 | [[package]] 129 | name = "tap" 130 | version = "1.0.1" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 133 | 134 | [[package]] 135 | name = "thiserror" 136 | version = "1.0.43" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" 139 | dependencies = [ 140 | "thiserror-impl", 141 | ] 142 | 143 | [[package]] 144 | name = "thiserror-impl" 145 | version = "1.0.43" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" 148 | dependencies = [ 149 | "proc-macro2", 150 | "quote", 151 | "syn", 152 | ] 153 | 154 | [[package]] 155 | name = "unicode-ident" 156 | version = "1.0.11" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" 159 | 160 | [[package]] 161 | name = "wyz" 162 | version = "0.5.1" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 165 | dependencies = [ 166 | "tap", 167 | ] 168 | -------------------------------------------------------------------------------- /src/builder/disassembler/mod.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Ident, TokenStream}; 2 | 3 | use quote::{format_ident, quote, ToTokens}; 4 | 5 | use super::{ 6 | ContextMemory, DisplayElement, Meanings, RegistersEnum, TokenFieldFunction, 7 | TokenFieldFunctions, WorkType, 8 | }; 9 | 10 | mod table; 11 | pub use table::*; 12 | 13 | mod constructor; 14 | pub use constructor::*; 15 | 16 | pub struct Disassembler { 17 | pub debug: bool, 18 | //enum with all the registers used (or possibly used) by the to display 19 | pub registers: RegistersEnum, 20 | //all the interger -> interger/name/register translations, 21 | //AKA `attach values/names/variables` 22 | pub meanings: Meanings, 23 | //all possible display elements: Literal/Register/Value 24 | pub display: DisplayElement, 25 | //all tables, that will implement parser/disassembly/display 26 | pub tables: Vec, 27 | pub token_field_functions: TokenFieldFunctions, 28 | pub addr_type: Ident, 29 | pub inst_work_type: WorkType, 30 | pub context: ContextMemory, 31 | //make sure sleigh is not droped, so the inner references are not dropped 32 | pub sleigh: sleigh_rs::Sleigh, 33 | } 34 | 35 | impl Disassembler { 36 | pub fn new(sleigh: sleigh_rs::Sleigh, debug: bool) -> Self { 37 | let registers = 38 | RegistersEnum::from_all(format_ident!("Register"), &sleigh); 39 | //TODO make sleigh to include all the meanings on the struct? 40 | //TODO removing the borrow in attach will simplifi this a lot 41 | let inst_work_type = WorkType::unsigned_from_bytes( 42 | sleigh.addr_bytes().get().try_into().unwrap(), 43 | ); 44 | 45 | let display = DisplayElement::new(format_ident!("DisplayElement")); 46 | 47 | let meanings = Meanings::new(&sleigh); 48 | let tables: Vec = sleigh 49 | .tables() 50 | .iter() 51 | .enumerate() 52 | .map(|(i, table)| { 53 | let table_id = sleigh_rs::TableId(i); 54 | TableEnum::new(&sleigh, table, table_id) 55 | }) 56 | .collect(); 57 | let field_structs = TokenFieldFunctions::new(&sleigh); 58 | let context = 59 | ContextMemory::new(&sleigh, format_ident!("ContextMemory")); 60 | Self { 61 | addr_type: format_ident!("AddrType"), 62 | display, 63 | registers, 64 | tables, 65 | meanings, 66 | inst_work_type, 67 | sleigh, 68 | context, 69 | debug, 70 | token_field_functions: field_structs, 71 | } 72 | } 73 | 74 | pub fn table_struct(&self, table: sleigh_rs::TableId) -> &TableEnum { 75 | &self.tables[table.0] 76 | } 77 | 78 | pub fn token_field_function( 79 | &self, 80 | id: sleigh_rs::TokenFieldId, 81 | ) -> &TokenFieldFunction { 82 | self.token_field_functions.read_function(&self.sleigh, id) 83 | } 84 | } 85 | 86 | impl ToTokens for Disassembler { 87 | fn to_tokens(&self, tokens: &mut TokenStream) { 88 | let display_data_type = &self.display.name; 89 | let instruction_table = 90 | self.table_struct(self.sleigh.instruction_table); 91 | let instruction_table_name = &instruction_table.name; 92 | let instruction_table_parse = &instruction_table.parse_fun; 93 | let instruction_table_display = &instruction_table.display_fun; 94 | let context_struct = &self.context.name; 95 | let globalset_struct = &self.context.globalset.name; 96 | 97 | let addr_type = &self.addr_type; 98 | let inst_work_type = &self.inst_work_type; 99 | tokens.extend(quote! { 100 | pub type #addr_type = #inst_work_type; 101 | }); 102 | self.registers.to_tokens(tokens, self); 103 | self.meanings.to_tokens(tokens, self); 104 | self.display.to_tokens(tokens, self); 105 | self.token_field_functions.to_tokens(tokens, self); 106 | self.context.to_tokens(tokens, self); 107 | for tables in self.tables.iter() { 108 | tables.to_tokens(tokens, self); 109 | } 110 | tokens.extend(quote! { 111 | pub fn parse_instruction( 112 | tokens: &[u8], 113 | context: &mut #context_struct, 114 | inst_start: #addr_type, 115 | global_set: &mut #globalset_struct, 116 | ) -> Option<(#inst_work_type, Vec<#display_data_type>)> { 117 | let (inst_len, instruction) = 118 | #instruction_table_name::#instruction_table_parse( 119 | tokens, 120 | context, 121 | inst_start, 122 | )?; 123 | let inst_next = inst_start + inst_len; 124 | let mut display = vec![]; 125 | instruction.#instruction_table_display( 126 | &mut display, 127 | context, 128 | inst_start, 129 | inst_next, 130 | global_set, 131 | ); 132 | Some((inst_next, display)) 133 | } 134 | }); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/builder/mod.rs: -------------------------------------------------------------------------------- 1 | use sleigh_rs::Number; 2 | 3 | use ethnum::u256; 4 | 5 | pub mod formater; 6 | 7 | pub(crate) mod helper; 8 | 9 | use proc_macro2::{Literal, TokenStream}; 10 | 11 | use quote::{quote, ToTokens}; 12 | 13 | mod context; 14 | mod disassembler; 15 | mod disassembly; 16 | mod display; 17 | mod meaning; 18 | mod register; 19 | mod token; 20 | 21 | pub use context::*; 22 | pub use disassembler::*; 23 | pub use disassembly::*; 24 | pub use display::*; 25 | pub use meaning::*; 26 | pub use register::*; 27 | pub use token::*; 28 | 29 | trait ToLiteral { 30 | fn suffixed(&self) -> Literal; 31 | fn unsuffixed(&self) -> Literal; 32 | } 33 | 34 | impl ToLiteral for Number { 35 | fn suffixed(&self) -> Literal { 36 | self.signed() 37 | .map(Literal::i64_suffixed) 38 | .unwrap_or_else(|| self.unsuffixed()) 39 | } 40 | 41 | fn unsuffixed(&self) -> Literal { 42 | Literal::i128_unsuffixed(self.signed_super()) 43 | } 44 | } 45 | 46 | macro_rules! impl_to_literal { 47 | ($type:ty, $suffixed:ident, $unsuffixed:ident) => { 48 | impl ToLiteral for $type { 49 | fn suffixed(&self) -> Literal { 50 | Literal::$suffixed(*self) 51 | } 52 | fn unsuffixed(&self) -> Literal { 53 | Literal::$unsuffixed(*self) 54 | } 55 | } 56 | }; 57 | } 58 | impl_to_literal!(u8, u8_suffixed, u8_unsuffixed); 59 | impl_to_literal!(u16, u16_suffixed, u16_unsuffixed); 60 | impl_to_literal!(u32, u32_suffixed, u32_unsuffixed); 61 | impl_to_literal!(u64, u64_suffixed, u64_unsuffixed); 62 | impl_to_literal!(u128, u128_suffixed, u128_unsuffixed); 63 | impl_to_literal!(usize, usize_suffixed, usize_unsuffixed); 64 | impl_to_literal!(i8, i8_suffixed, i8_unsuffixed); 65 | impl_to_literal!(i16, i16_suffixed, i16_unsuffixed); 66 | impl_to_literal!(i32, i32_suffixed, i32_unsuffixed); 67 | impl_to_literal!(i64, i64_suffixed, i64_unsuffixed); 68 | impl_to_literal!(i128, i128_suffixed, i128_unsuffixed); 69 | impl_to_literal!(isize, isize_suffixed, isize_unsuffixed); 70 | 71 | //TODO remove the signed/unsigned 72 | #[derive(Clone, Copy, Debug)] 73 | pub enum WorkType { 74 | U8, 75 | U16, 76 | U32, 77 | U64, 78 | U128, 79 | U256, 80 | I8, 81 | I16, 82 | I32, 83 | I64, 84 | I128, 85 | I256, 86 | } 87 | 88 | impl WorkType { 89 | pub const fn new_int_bytes(bytes: u32, signed: bool) -> Self { 90 | match bytes { 91 | 1 if signed => Self::I8, 92 | 2 if signed => Self::I16, 93 | 3..=4 if signed => Self::I32, 94 | 5..=8 if signed => Self::I64, 95 | 9..=16 if signed => Self::I128, 96 | 17..=32 if signed => Self::I256, 97 | 1 /*if !signed*/ => Self::U8, 98 | 2 /*if !signed*/ => Self::U16, 99 | 3..=4 /*if !signed*/ => Self::U32, 100 | 5..=8 /*if !signed*/ => Self::U64, 101 | 9..=16 /*if !signed*/ => Self::U128, 102 | 17..=32 /*if !signed*/ => Self::U256, 103 | _x => unreachable!(), 104 | } 105 | } 106 | 107 | pub const fn new_int_bits(bits: u32, signed: bool) -> Self { 108 | Self::new_int_bytes((bits + 7) / 8, signed) 109 | } 110 | 111 | pub const fn unsigned_from_bytes(bytes: u32) -> Self { 112 | Self::new_int_bytes(bytes, false) 113 | } 114 | 115 | pub const fn unsigned_from_bits(bits: u32) -> Self { 116 | Self::new_int_bits(bits, false) 117 | } 118 | 119 | pub const fn is_signed(&self) -> bool { 120 | match self { 121 | WorkType::U8 122 | | WorkType::U16 123 | | WorkType::U32 124 | | WorkType::U64 125 | | WorkType::U128 126 | | WorkType::U256 => false, 127 | WorkType::I8 128 | | WorkType::I16 129 | | WorkType::I32 130 | | WorkType::I64 131 | | WorkType::I128 132 | | WorkType::I256 => true, 133 | } 134 | } 135 | 136 | pub const fn len_bytes(&self) -> u32 { 137 | match self { 138 | WorkType::I8 | WorkType::U8 => u8::BITS / 8, 139 | WorkType::I16 | WorkType::U16 => u16::BITS / 8, 140 | WorkType::I32 | WorkType::U32 => u32::BITS / 8, 141 | WorkType::I64 | WorkType::U64 => u64::BITS / 8, 142 | WorkType::I128 | WorkType::U128 => u128::BITS / 8, 143 | WorkType::I256 | WorkType::U256 => u256::BITS / 8, 144 | } 145 | } 146 | } 147 | 148 | impl ToTokens for WorkType { 149 | fn to_tokens(&self, tokens: &mut TokenStream) { 150 | match self { 151 | WorkType::U8 => tokens.extend(quote! {u8}), 152 | WorkType::U16 => tokens.extend(quote! {u16}), 153 | WorkType::U32 => tokens.extend(quote! {u32}), 154 | WorkType::U64 => tokens.extend(quote! {u64}), 155 | WorkType::U128 => tokens.extend(quote! {u128}), 156 | WorkType::U256 => tokens.extend(quote! {ethnum::u256}), 157 | WorkType::I8 => tokens.extend(quote! {i8}), 158 | WorkType::I16 => tokens.extend(quote! {i16}), 159 | WorkType::I32 => tokens.extend(quote! {i32}), 160 | WorkType::I64 => tokens.extend(quote! {i64}), 161 | WorkType::I128 => tokens.extend(quote! {i128}), 162 | WorkType::I256 => tokens.extend(quote! {ethnum::i256}), 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/builder/function.rs: -------------------------------------------------------------------------------- 1 | //use indexmap::IndexMap; 2 | //use std::rc::Rc; 3 | // 4 | //use proc_macro2::Ident; 5 | //use quote::format_ident; 6 | // 7 | //use super::{from_sleigh, snake_case, SLEIGH_IDENT}; 8 | // 9 | //pub struct Functions { 10 | // macros: IndexMap<*const sleigh_rs::PcodeMacro, PcodeMacro>, 11 | // functions: IndexMap<*const sleigh_rs::UserFunction, UserFunction>, 12 | //} 13 | // 14 | //impl Functions { 15 | // pub fn new(sleigh: &sleigh_rs::Sleigh) -> Self { 16 | // let macros = sleigh 17 | // .pcode_macros() 18 | // .map(PcodeMacro::new) 19 | // .map(|fuck| (Rc::as_ptr(&fuck.sleigh), fuck)) 20 | // .collect(); 21 | // let functions = sleigh 22 | // .user_functions() 23 | // .map(UserFunction::new) 24 | // .map(|function| (Rc::as_ptr(&function.sleigh), function)) 25 | // .collect(); 26 | // Self { macros, functions } 27 | // } 28 | //} 29 | // 30 | //const MACRO_PREFIX: [&str; 2] = [SLEIGH_IDENT, "macro"]; 31 | //struct PcodeMacro { 32 | // ident: Ident, 33 | // sleigh: Rc, 34 | //} 35 | //impl PcodeMacro { 36 | // pub fn new(sleigh: Rc) -> Self { 37 | // let ident = MACRO_PREFIX.into_iter().chain(from_sleigh(&sleigh.name)); 38 | // let ident = format_ident!("{}", &snake_case(ident)); 39 | // Self { ident, sleigh } 40 | // } 41 | //} 42 | // 43 | //const USER_FUNCTION_PREFIX: [&str; 3] = [SLEIGH_IDENT, "user", "function"]; 44 | //struct UserFunction { 45 | // ident: Ident, 46 | // sleigh: Rc, 47 | //} 48 | //impl UserFunction { 49 | // pub fn new(sleigh: Rc) -> Self { 50 | // let ident = USER_FUNCTION_PREFIX 51 | // .into_iter() 52 | // .chain(from_sleigh(&sleigh.name)); 53 | // let ident = format_ident!("{}", &snake_case(ident)); 54 | // Self { ident, sleigh } 55 | // } 56 | //} 57 | 58 | //struct PcodeMacroBuilder<'a, 'b> { 59 | // builder: &'a mut Builder<'b>, 60 | // pcode_macro: &'a PcodeMacro, 61 | // params: IndexMap, Ident>, 62 | // vars: IndexMap, Ident>, 63 | //} 64 | // 65 | //impl<'a, 'b> PcodeMacroBuilder<'a, 'b> { 66 | // pub fn new( 67 | // builder: &'a mut Builder<'b>, 68 | // pcode_macro: &'a PcodeMacro, 69 | // ) -> Self { 70 | // Self { 71 | // builder, 72 | // pcode_macro, 73 | // params: IndexMap::new(), 74 | // vars: IndexMap::new(), 75 | // } 76 | // } 77 | // pub fn impl_function(&mut self) -> TokenStream { 78 | // let pcode_macros = self.builder.pcode_macros.insert(IndexMap::new()); 79 | // let function_name = Rc::clone(&self.pcode_macro.name); 80 | // let function_ident = pcode_macros 81 | // .entry(Rc::clone(&function_name)) 82 | // .or_insert(format_ident!("macro_{}", *function_name)) 83 | // .clone(); 84 | // let params = self.pcode_macro.params.borrow(); 85 | // self.params = params 86 | // .keys() 87 | // .map(|name| (Rc::clone(name), format_ident!("{}", **name))) 88 | // .collect(); 89 | // let body = self.impl_body(); 90 | // let params = self.params.values(); 91 | // let ident = &self.builder.space_struct().ident; 92 | // quote! { 93 | // impl #ident { 94 | // fn #function_ident(&mut self, #(#params : usize),*) { 95 | // #body 96 | // } 97 | // } 98 | // } 99 | // } 100 | // 101 | // pub fn impl_body(&mut self) -> TokenStream { 102 | // let execution = self.pcode_macro.execution.borrow(); 103 | // 104 | // self.vars = execution 105 | // .vars 106 | // .values() 107 | // .map(|var| (Rc::clone(&var.name), format_ident!("{}", *var.name))) 108 | // .collect(); 109 | // let vars = execution.vars.values().map(|var| { 110 | // let var = self.vars.get(&var.name).unwrap(); 111 | // quote! { 112 | // let #var; 113 | // } 114 | // }); 115 | // 116 | // let entry_next = &execution.entry_block.next.borrow(); 117 | // let entry_next = entry_next 118 | // .as_ref() 119 | // .map(|x| { 120 | // let next = x.name.as_ref().unwrap(); 121 | // quote! {todo!{#next};} 122 | // }) 123 | // .unwrap_or(quote! {todo!("Return");}); 124 | // let entry_statements = execution.entry_block.statements.borrow(); 125 | // let entry_statements = entry_statements.iter().map(|st| { 126 | // use sleigh_rs::parser::semantic::execution::Statement::*; 127 | // match st { 128 | // Delayslot(x) => quote! {todo!("delayslot({})", #x);}, 129 | // Export(_) => quote! {todo!("export");}, 130 | // CpuBranch(_) => quote! {todo!("cpubranch");}, 131 | // LocalGoto(_) => quote! {todo!("localgoto");}, 132 | // Call(_) => quote! {todo!("call");}, 133 | // Build(_) => unreachable!(), 134 | // Declare(x) => { 135 | // let var = self.vars.get(&x.name).unwrap(); 136 | // let var_type = todo!(); 137 | // quote! {let #var: #var_type;} 138 | // } 139 | // Assignment(_) => quote! {todo!();}, 140 | // } 141 | // }); 142 | // quote! { 143 | // #(#vars)* 144 | // #(#entry_statements)* 145 | // #entry_next 146 | // } 147 | // } 148 | //} 149 | // 150 | //pub fn do_the_thing<'a, 'b>( 151 | // builder: &'a mut Builder<'b>, 152 | // pcode_macro: &'a PcodeMacro, 153 | //) -> TokenStream { 154 | // let mut builder = PcodeMacroBuilder::new(builder, pcode_macro); 155 | // builder.impl_function() 156 | //} 157 | -------------------------------------------------------------------------------- /src/builder/token.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use proc_macro2::{Ident, TokenStream}; 4 | use quote::{format_ident, quote}; 5 | use sleigh_rs::{Endian, FieldBits, NumberNonZeroUnsigned}; 6 | 7 | use crate::builder::helper::bytes_from_value; 8 | use crate::builder::WorkType; 9 | 10 | use super::helper::{bitrange_from_value, from_endian_bytes}; 11 | use super::{Disassembler, ToLiteral}; 12 | 13 | #[derive(Hash, PartialEq, Eq)] 14 | struct TokenFieldKey { 15 | token_bytes: NumberNonZeroUnsigned, 16 | token_endian: Endian, 17 | bits: FieldBits, 18 | } 19 | 20 | pub struct TokenFieldFunction { 21 | pub read: Ident, 22 | pub read_type: WorkType, 23 | pub ids: Vec, 24 | } 25 | 26 | pub struct TokenFieldFunctions { 27 | // is very common to have multiple token_fields that are identical, 28 | // so use the HashMap to join then 29 | functions: HashMap, 30 | } 31 | 32 | impl TokenFieldFunctions { 33 | pub fn new<'a>(sleigh: &sleigh_rs::Sleigh) -> Self { 34 | let token_fields = sleigh 35 | .token_fields() 36 | .iter() 37 | .enumerate() 38 | .map(|(i, field)| (sleigh_rs::TokenFieldId(i), field)); 39 | let mut count = 0usize; 40 | let mut functions = HashMap::new(); 41 | for (id, token_field) in token_fields { 42 | let token = sleigh.token(token_field.token); 43 | let key = TokenFieldKey { 44 | token_bytes: token.len_bytes, 45 | token_endian: token.endian, 46 | bits: token_field.bits.clone(), 47 | }; 48 | functions 49 | .entry(key) 50 | .and_modify(|entry: &mut TokenFieldFunction| entry.ids.push(id)) 51 | .or_insert_with(|| { 52 | count += 1; 53 | TokenFieldFunction { 54 | read: format_ident!("token_{}", count), 55 | read_type: WorkType::unsigned_from_bits( 56 | token_field.bits.len().get().try_into().unwrap(), 57 | ), 58 | ids: vec![id], 59 | } 60 | }); 61 | } 62 | Self { functions } 63 | } 64 | 65 | pub fn read_function( 66 | &self, 67 | sleigh: &sleigh_rs::Sleigh, 68 | id: sleigh_rs::TokenFieldId, 69 | ) -> &TokenFieldFunction { 70 | let token_field = sleigh.token_field(id); 71 | let token = sleigh.token(token_field.token); 72 | let key = TokenFieldKey { 73 | bits: token_field.bits.clone(), 74 | token_bytes: token.len_bytes, 75 | token_endian: token.endian, 76 | }; 77 | &self.functions.get(&key).unwrap() 78 | } 79 | 80 | pub fn to_tokens( 81 | &self, 82 | tokens: &mut TokenStream, 83 | disassembler: &Disassembler, 84 | ) { 85 | for (key, value) in self.functions.iter() { 86 | let TokenFieldKey { 87 | bits, 88 | token_bytes, 89 | token_endian, 90 | } = key; 91 | let TokenFieldFunction { 92 | read, 93 | ids, 94 | read_type, 95 | } = value; 96 | let from_endian_call = from_endian_bytes(*token_endian); 97 | let token_type = WorkType::unsigned_from_bytes( 98 | token_bytes.get().try_into().unwrap(), 99 | ); 100 | let token_bytes_un = token_bytes.get().unsuffixed(); 101 | let tokens_param = format_ident!("tokens"); 102 | 103 | let mut doc = "Create token_fields:".to_string(); 104 | for id in ids.iter() { 105 | doc.push(' '); 106 | doc.push_str(disassembler.sleigh.token_field(*id).name()); 107 | } 108 | //TODO attach value should be converted here or in execution? 109 | let body = if u32::try_from(token_bytes.get()).unwrap() 110 | != token_type.len_bytes() 111 | { 112 | let bytes = format_ident!("bytes"); 113 | let value = format_ident!("value"); 114 | let token_type_bytes = token_type.len_bytes().unsuffixed(); 115 | let (bytes_start, bytes_end) = bytes_from_value( 116 | *token_endian, 117 | token_type.len_bytes(), 118 | token_bytes.get().try_into().unwrap(), 119 | ); 120 | let convert = bitrange_from_value( 121 | bits.start().try_into().unwrap() 122 | ..bits.end().get().try_into().unwrap(), 123 | *read_type, 124 | &value, 125 | ); 126 | let bytes_start = bytes_start.unsuffixed(); 127 | let bytes_end = bytes_end.unsuffixed(); 128 | quote! { 129 | let mut #bytes = [0u8; #token_type_bytes]; 130 | #bytes[#bytes_start..#bytes_end] 131 | .copy_from_slice(&#tokens_param[0..#token_bytes_un]); 132 | let #value = #token_type::#from_endian_call(#bytes); 133 | #convert 134 | } 135 | } else { 136 | bitrange_from_value( 137 | bits.start().try_into().unwrap() 138 | ..bits.end().get().try_into().unwrap(), 139 | *read_type, 140 | quote! {#token_type::#from_endian_call( 141 | #tokens_param[0..#token_bytes_un].try_into().unwrap() 142 | )}, 143 | ) 144 | }; 145 | tokens.extend(quote! { 146 | #[doc = #doc] 147 | fn #read(#tokens_param: &[u8]) -> #read_type { 148 | #body 149 | } 150 | }); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/builder/disassembler/table.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Ident, TokenStream}; 2 | use quote::{format_ident, quote}; 3 | 4 | use super::{ConstructorStruct, Disassembler}; 5 | use crate::builder::formater::*; 6 | use crate::builder::helper::PatternByte; 7 | use crate::builder::ToLiteral; 8 | 9 | pub struct TableEnum { 10 | //enum declaration ident 11 | pub name: Ident, 12 | //parse function ident 13 | pub parse_fun: Ident, 14 | //disassembly (pos) function ident 15 | //pub disassembly_fun: Ident, 16 | //display_extend function ident 17 | pub display_fun: Ident, 18 | //constructors are mapped from the sleigh_rs constructors by index 19 | pub constructors: Vec, 20 | pub table_id: sleigh_rs::TableId, 21 | } 22 | 23 | impl TableEnum { 24 | pub fn new( 25 | sleigh: &sleigh_rs::Sleigh, 26 | table: &sleigh_rs::table::Table, 27 | table_id: sleigh_rs::TableId, 28 | ) -> Self { 29 | let constructors = table 30 | .constructors() 31 | .iter() 32 | .enumerate() 33 | .map(|(index, constructor)| { 34 | ConstructorStruct::new( 35 | sleigh, 36 | table_id, 37 | constructor, 38 | sleigh_rs::table::ConstructorId(index), 39 | &from_sleigh(table.name()), 40 | index, 41 | ) 42 | }) 43 | .collect(); 44 | //only non root tables have a disassembly function 45 | Self { 46 | name: format_ident!("Table{}", from_sleigh(table.name())), 47 | parse_fun: format_ident!("parse"), 48 | //disassembly_fun: format_ident!("disassembly"), 49 | display_fun: format_ident!("display_extend"), 50 | constructors, 51 | table_id, 52 | } 53 | } 54 | 55 | pub fn to_tokens( 56 | &self, 57 | tokens: &mut TokenStream, 58 | disassembler: &Disassembler, 59 | ) { 60 | let Self { 61 | name: enum_name, 62 | parse_fun, 63 | display_fun, 64 | constructors, 65 | table_id, 66 | } = self; 67 | let table = disassembler.sleigh.table(*table_id); 68 | let constructors_structs = constructors.iter(); 69 | let constructor_enum_name_1 = constructors.iter().map(|con| &con.enum_name); 70 | let constructor_enum_name_2 = constructor_enum_name_1.clone(); 71 | let constructor_struct = constructors.iter().map(|con| &con.struct_name); 72 | let display_struct_name = &disassembler.display.name; 73 | let variant_names = table.matcher_order.iter().map(|matcher| { 74 | &self.constructors[matcher.constructor.0].enum_name 75 | }); 76 | let variant_structs = table.matcher_order.iter().map(|matcher| { 77 | &self.constructors[matcher.constructor.0].struct_name 78 | }); 79 | let variant_display_fun = table.matcher_order.iter().map(|matcher| { 80 | &self.constructors[matcher.constructor.0].display_fun 81 | }); 82 | let variants_parser_fun = table.matcher_order.iter().map(|matcher| { 83 | &self.constructors[matcher.constructor.0].parser_fun 84 | }); 85 | let variants_min_len = table.matcher_order.iter().map(|matcher| { 86 | table 87 | .constructor(matcher.constructor) 88 | .pattern 89 | .len 90 | .min() 91 | .unsuffixed() 92 | }); 93 | 94 | //only verify constructors byte_pattern if not in debug mode 95 | let variants_constraint = table.matcher_order.iter().map(|matcher| { 96 | (!disassembler.debug).then(|| { 97 | let constructor = table.constructor(matcher.constructor); 98 | let (context, token) = constructor.variant(matcher.variant_id); 99 | let context = PatternByte::from_bit_constraints(context); 100 | let token = PatternByte::from_bit_constraints(token); 101 | let (context_value, context_mask) = context.into_iter().enumerate().fold( 102 | (0u128, 0u128), 103 | |(acc_value, acc_mask), (byte_num, byte)| { 104 | ( 105 | acc_value | ((byte.defined_value() as u128) << (byte_num * 8)), 106 | acc_mask | ((byte.defined_bits() as u128) << (byte_num * 8)), 107 | ) 108 | }, 109 | ); 110 | //only constraint if mask != 0 111 | let pattern_constraint = token 112 | .into_iter() 113 | .enumerate() 114 | .filter(|(_, byte)| byte.defined_bits() != 0) 115 | .map(|(i, byte)| { 116 | let i = i.unsuffixed(); 117 | let value = byte.defined_value().unsuffixed(); 118 | let mask = byte.defined_bits().unsuffixed(); 119 | quote! { (tokens_param[#i] & #mask) == #value} 120 | }); 121 | let context_constraint = (context_mask != 0) 122 | .then(|| { 123 | let context_value = context_value.unsuffixed(); 124 | let context_mask = context_mask.unsuffixed(); 125 | quote! { context_param.0 & #context_mask == #context_value } 126 | }) 127 | .into_iter(); 128 | 129 | context_constraint 130 | .chain(pattern_constraint) 131 | .fold(quote! {}, |mut acc, x| { 132 | acc.extend(quote! {&& #x}); 133 | acc 134 | }) 135 | }) 136 | }); 137 | let addr_type = &disassembler.addr_type; 138 | let context_struct = &disassembler.context.name; 139 | let globalset_struct = &disassembler.context.globalset.name; 140 | for constructor in constructors_structs { 141 | constructor.to_tokens(tokens, disassembler); 142 | } 143 | tokens.extend(quote! { 144 | #[derive(Clone, Debug)] 145 | enum #enum_name { 146 | #(#constructor_enum_name_1(#constructor_struct)),* 147 | } 148 | impl #enum_name { 149 | fn #display_fun( 150 | &self, 151 | display: &mut Vec<#display_struct_name>, 152 | context: &#context_struct, 153 | inst_start: #addr_type, 154 | inst_next: #addr_type, 155 | global_set_param: &mut #globalset_struct, 156 | ) { 157 | match self { 158 | #(Self::#constructor_enum_name_2(x) => x.#variant_display_fun( 159 | display, 160 | context, 161 | inst_start, 162 | inst_next, 163 | global_set_param, 164 | )),* 165 | } 166 | } 167 | fn #parse_fun( 168 | tokens_param: &[u8], 169 | context_param: &mut #context_struct, 170 | inst_start: #addr_type, 171 | ) -> Option<(#addr_type, Self)> { 172 | //clone context, so we updated it only if we found the 173 | //correct match variant 174 | let mut context_current = context_param.clone(); 175 | //try to parse each of the constructors, return if success 176 | #(if tokens_param.len() >= #variants_min_len #variants_constraint { 177 | if let Some((inst_len, parsed)) = 178 | #variant_structs::#variants_parser_fun( 179 | tokens_param, 180 | &mut context_current, 181 | inst_start, 182 | ) { 183 | *context_param = context_current; 184 | return Some((inst_len, Self::#variant_names(parsed))); 185 | } 186 | })* 187 | None 188 | } 189 | } 190 | }) 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/builder/context.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Ident, TokenStream}; 2 | 3 | use quote::{format_ident, quote, ToTokens}; 4 | use sleigh_rs::NumberUnsigned; 5 | 6 | use super::formater::from_sleigh; 7 | use super::helper::{bitrange_from_value, rotation_and_mask_from_range}; 8 | use super::{Disassembler, ToLiteral, WorkType}; 9 | 10 | #[derive(Debug, Clone)] 11 | pub struct ContextMemory { 12 | pub name: Ident, 13 | pub context_bytes: NumberUnsigned, 14 | //TODO clone taking the noflow in consideration 15 | contexts: Vec, 16 | pub globalset: GlobalSet, 17 | } 18 | 19 | #[derive(Debug, Clone)] 20 | pub struct ContextFunctions { 21 | pub read: Ident, 22 | pub write: Ident, 23 | pub context: sleigh_rs::ContextId, 24 | } 25 | 26 | #[derive(Debug, Clone)] 27 | pub struct GlobalSet { 28 | pub name: Ident, 29 | pub set_fun: Ident, 30 | pub new_fun: Ident, 31 | } 32 | 33 | //TODO for now only allow the context to be a single varnode 34 | impl ContextMemory { 35 | fn contexts(sleigh: &sleigh_rs::Sleigh) -> Vec { 36 | sleigh 37 | .contexts() 38 | .iter() 39 | .enumerate() 40 | .map(|(i, context)| { 41 | ContextFunctions::new(sleigh_rs::ContextId(i), context) 42 | }) 43 | .collect() 44 | } 45 | 46 | pub fn new(sleigh: &sleigh_rs::Sleigh, name: Ident) -> Self { 47 | let context_bytes = (sleigh.context_memory.memory_bits + 7) / 8; 48 | let contexts = Self::contexts(sleigh); 49 | let globalset = GlobalSet { 50 | name: format_ident!("GlobalSet"), 51 | set_fun: format_ident!("set"), 52 | new_fun: format_ident!("new"), 53 | }; 54 | Self { 55 | name, 56 | context_bytes, 57 | contexts, 58 | globalset, 59 | } 60 | } 61 | 62 | pub fn context_functions( 63 | &self, 64 | context: sleigh_rs::ContextId, 65 | ) -> &ContextFunctions { 66 | &self.contexts[context.0] 67 | } 68 | 69 | pub fn read_call( 70 | &self, 71 | context: sleigh_rs::ContextId, 72 | instance: &Ident, 73 | ) -> TokenStream { 74 | let read_fun = &self.context_functions(context).read; 75 | quote! { #instance.#read_fun() } 76 | } 77 | 78 | pub fn write_call( 79 | &self, 80 | disassembler: &Disassembler, 81 | instance: &Ident, 82 | context_id: sleigh_rs::ContextId, 83 | value: impl ToTokens, 84 | ) -> TokenStream { 85 | let context = disassembler.sleigh.context(context_id); 86 | let signed = context.is_signed(); 87 | let context = self.context_functions(context_id); 88 | let write_fun = &context.write; 89 | let value_type = context.value_type(disassembler); 90 | if signed { 91 | quote! { 92 | #instance.#write_fun(#value_type::try_from(#value).unwrap()) 93 | } 94 | } else { 95 | let mask = context.value_mask(disassembler).unsuffixed(); 96 | quote! { 97 | #instance.#write_fun(#value_type::try_from(#value & #mask).unwrap()) 98 | } 99 | } 100 | } 101 | 102 | pub fn display_call( 103 | &self, 104 | disassembler: &Disassembler, 105 | instance: &Ident, 106 | id: sleigh_rs::ContextId, 107 | ) -> TokenStream { 108 | let read = &self.context_functions(id).read; 109 | let context = disassembler.sleigh.context(id); 110 | disassembler.meanings.display_function_call( 111 | context.bitrange.bits.len().get().try_into().unwrap(), 112 | quote! {#instance.#read()}, 113 | context.meaning(), 114 | ) 115 | } 116 | 117 | pub fn to_tokens( 118 | &self, 119 | tokens: &mut TokenStream, 120 | disassembler: &Disassembler, 121 | ) { 122 | let Self { 123 | name: context_name, 124 | context_bytes: context_len, 125 | contexts, 126 | globalset, 127 | } = self; 128 | let (context_type, impl_block) = if *context_len == 0 { 129 | (quote! {()}, None) 130 | } else { 131 | let context_type = WorkType::unsigned_from_bytes( 132 | (*context_len).try_into().unwrap(), 133 | ); 134 | let functions = contexts.iter().map(|context| { 135 | context.functions_from_type(disassembler, context_type) 136 | }); 137 | let impl_block = quote! { 138 | impl #context_name { 139 | #(#functions)* 140 | } 141 | }; 142 | (context_type.into_token_stream(), Some(impl_block)) 143 | }; 144 | let globalset = globalset.tokens(disassembler, self); 145 | tokens.extend(quote! { 146 | #[derive(Clone, Copy, Default)] 147 | pub struct #context_name(pub #context_type); 148 | #impl_block 149 | 150 | #globalset 151 | }); 152 | } 153 | } 154 | 155 | impl ContextFunctions { 156 | fn new( 157 | id: sleigh_rs::ContextId, 158 | context: &sleigh_rs::varnode::Context, 159 | ) -> Self { 160 | Self { 161 | read: format_ident!("read_{}", from_sleigh(context.name())), 162 | write: format_ident!("write_{}", from_sleigh(context.name())), 163 | context: id, 164 | } 165 | } 166 | fn value_type(&self, disassembler: &Disassembler) -> WorkType { 167 | let context = disassembler.sleigh.context(self.context); 168 | let signed = context.is_signed(); 169 | let len: u32 = context.bitrange.bits.len().get().try_into().unwrap(); 170 | WorkType::new_int_bits(len, signed) 171 | } 172 | fn value_mask(&self, disassembler: &Disassembler) -> u128 { 173 | let context = disassembler.sleigh.context(self.context); 174 | let len: u32 = context.bitrange.bits.len().get().try_into().unwrap(); 175 | u128::MAX >> (u128::BITS - len) 176 | } 177 | fn functions_from_type( 178 | &self, 179 | disassembler: &Disassembler, 180 | context_type: WorkType, 181 | ) -> TokenStream { 182 | let Self { 183 | read, 184 | write, 185 | context: _, 186 | } = self; 187 | // NOTE context bit endian is always msb (index 0) -> lsb (index len - 1) 188 | // the byte endian can be the native CPU, because we are using the 189 | // context memory mapping, and not the raw context bits from sleigh. 190 | // To make this work, all we need to do is invert the bit order, 191 | // so bit_0 => bit_(len-1) and bit_(len_1) => bit_0 192 | let value_type = self.value_type(disassembler); 193 | let context_memory = 194 | disassembler.sleigh.context_memory.context(self.context); 195 | let bit_end = 196 | (context_type.len_bytes() as u64 * 8) - context_memory.start(); 197 | let bit_start = 198 | (context_type.len_bytes() as u64 * 8) - context_memory.end().get(); 199 | let bits = bit_start.try_into().unwrap()..bit_end.try_into().unwrap(); 200 | let convert = bitrange_from_value( 201 | bits.clone(), 202 | value_type, 203 | quote! {self.0.reverse_bits()}, 204 | ); 205 | let (rotation, mask) = rotation_and_mask_from_range(bits); 206 | let rotation = rotation.unsuffixed(); 207 | let mask = mask.unsuffixed(); 208 | quote! { 209 | pub fn #read(&self) -> #value_type { 210 | #convert 211 | } 212 | pub fn #write(&mut self, value: #value_type) { 213 | self.0 = ((self.0.reverse_bits() & !(#mask << #rotation)) | ((value as #context_type & #mask) << #rotation)).reverse_bits(); 214 | } 215 | } 216 | } 217 | } 218 | 219 | impl GlobalSet { 220 | fn tokens( 221 | &self, 222 | disassembler: &Disassembler, 223 | context: &ContextMemory, 224 | ) -> TokenStream { 225 | let addr_type = &disassembler.addr_type; 226 | let Self { 227 | name, 228 | set_fun, 229 | new_fun, 230 | } = self; 231 | let context_name = &context.name; 232 | if context.context_bytes == 0 { 233 | quote! { 234 | #[derive(Clone, Copy, Default)] 235 | pub struct #name(()); 236 | impl #name { 237 | pub fn #new_fun(_: #context_name) -> Self { 238 | Self(()) 239 | } 240 | pub fn #set_fun(&mut self, _: Option<#addr_type>, _: impl FnOnce(&mut #context_name)) { 241 | unreachable!() 242 | } 243 | } 244 | } 245 | } else { 246 | quote! { 247 | #[derive(Clone)] 248 | pub struct #name { 249 | default: #context_name, 250 | branches: std::collections::HashMap<#addr_type, #context_name>, 251 | } 252 | impl #name { 253 | pub fn #new_fun(default: #context_name) -> Self { 254 | Self { 255 | default, 256 | branches: std::collections::HashMap::new(), 257 | } 258 | } 259 | pub fn #set_fun(&mut self, address: Option<#addr_type>, set: impl FnOnce(&mut #context_name)) { 260 | let Some(address) = address else { return }; 261 | //TODO use the noflow clone instead of simple clone. 262 | let entry = self.branches.entry(address).or_insert_with(|| self.default.clone()); 263 | set(entry); 264 | } 265 | } 266 | } 267 | } 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /src/builder/disassembler/constructor/disassembly.rs: -------------------------------------------------------------------------------- 1 | use indexmap::IndexMap; 2 | use std::cell::RefCell; 3 | 4 | use proc_macro2::{Ident, TokenStream}; 5 | use quote::{format_ident, quote, ToTokens}; 6 | use sleigh_rs::disassembly::{Assertation, GlobalSet, Variable, VariableId}; 7 | 8 | use crate::builder::formater::from_sleigh; 9 | use crate::builder::{Disassembler, DisassemblyGenerator, ToLiteral, WorkType}; 10 | 11 | use super::ConstructorStruct; 12 | 13 | pub const DISASSEMBLY_WORK_TYPE: WorkType = 14 | WorkType::new_int_bits(crate::DisassemblyType::BITS, true); 15 | pub struct DisassemblyDisplay<'a> { 16 | pub disassembler: &'a Disassembler, 17 | pub constructor: &'a ConstructorStruct, 18 | pub display_param: &'a Ident, 19 | pub context_param: &'a Ident, 20 | pub inst_start: &'a Ident, 21 | pub inst_next: &'a Ident, 22 | pub global_set_param: &'a Ident, 23 | pub vars: RefCell>, 24 | } 25 | 26 | impl DisassemblyDisplay<'_> { 27 | fn inst_start(&self) -> TokenStream { 28 | let inst_start = &self.inst_start; 29 | quote! {#DISASSEMBLY_WORK_TYPE::try_from(#inst_start).unwrap()} 30 | } 31 | fn inst_next(&self) -> TokenStream { 32 | let inst_next = &self.inst_next; 33 | quote! {#DISASSEMBLY_WORK_TYPE::try_from(#inst_next).unwrap()} 34 | } 35 | //get var name on that contains the this assembly field value 36 | fn ass_field(&self, ass: sleigh_rs::TokenFieldId) -> TokenStream { 37 | //can't create new ass fields during disassembly, all 38 | //fields used need to be declared on the pattern 39 | let field = self.constructor.ass_fields.get(&ass).unwrap(); 40 | let token_field = self.disassembler.sleigh.token_field(ass); 41 | let field = self.disassembler.meanings.disassembly_function_call( 42 | token_field.bits.len().get().try_into().unwrap(), 43 | quote! {self.#field}, 44 | token_field.meaning(), 45 | ); 46 | quote! {#DISASSEMBLY_WORK_TYPE::try_from(#field).unwrap()} 47 | } 48 | 49 | fn context_field(&self, context: &sleigh_rs::ContextId) -> TokenStream { 50 | let read_call = self 51 | .disassembler 52 | .context 53 | .read_call(*context, self.context_param); 54 | quote! { #DISASSEMBLY_WORK_TYPE::try_from(#read_call).unwrap()} 55 | } 56 | //get var name on that contains the this assembly field value 57 | fn table_field(&self, table: &sleigh_rs::TableId) -> Option { 58 | let field = self.constructor.table_fields.get(table).unwrap(); 59 | use sleigh_rs::table::ExecutionExport; 60 | let table = self.disassembler.sleigh.table(*table); 61 | match table.export { 62 | ExecutionExport::Const(_len) => { 63 | //TODO allow table to export value with addr diff from addr_len 64 | //and auto convert using try_from? 65 | //assert_eq!(len, addr_type.len_bytes()) 66 | } 67 | ExecutionExport::None 68 | | ExecutionExport::Value(_) 69 | | ExecutionExport::Reference(_) 70 | | ExecutionExport::Multiple(_) => return None, 71 | } 72 | Some(quote! {self.#field}) 73 | } 74 | } 75 | 76 | impl ToTokens for DisassemblyDisplay<'_> { 77 | fn to_tokens(&self, tokens: &mut TokenStream) { 78 | let constructor = self 79 | .disassembler 80 | .sleigh 81 | .table(self.constructor.table_id) 82 | .constructor(self.constructor.constructor_id); 83 | let mut asses = constructor 84 | .pattern 85 | .blocks() 86 | .iter() 87 | .flat_map(|block| match block { 88 | sleigh_rs::pattern::Block::And { pre, pos, .. } => { 89 | pre.iter().chain(pos.iter()) 90 | } 91 | sleigh_rs::pattern::Block::Or { pos, .. } => { 92 | pos.iter().chain([/*LOL*/].iter()) 93 | } 94 | }) 95 | .chain(constructor.pattern.disassembly_pos_match()); 96 | tokens.extend(self.disassembly(&mut asses)); 97 | } 98 | } 99 | 100 | impl<'a> DisassemblyGenerator for DisassemblyDisplay<'a> { 101 | fn global_set(&self, global_set: &GlobalSet) -> TokenStream { 102 | let addr_type = &self.disassembler.addr_type; 103 | use sleigh_rs::disassembly::AddrScope::*; 104 | let address = match &global_set.address { 105 | Integer(value) => { 106 | let value = value.unsuffixed(); 107 | quote! { Some(#value) } 108 | } 109 | Local(var) => { 110 | let name = self.var_name(var); 111 | quote! { Some(#addr_type::try_from(#name).unwrap()) } 112 | } 113 | Table(table) => { 114 | //TODO is None required? 115 | self.table_field(table) 116 | .map(|table| quote! {Some(#table)}) 117 | .unwrap_or(quote! {None}) 118 | } 119 | InstNext(_) => { 120 | let name = self.inst_next; 121 | quote! { Some(#name) } 122 | } 123 | InstStart(_) => { 124 | let name = self.inst_start; 125 | quote! { Some(#name) } 126 | } 127 | }; 128 | let global_set_param = self.global_set_param; 129 | let context = &self.disassembler.context; 130 | let set_fun = &context.globalset.set_fun; 131 | let context_param = format_ident!("context"); 132 | let value = self.context_field(&global_set.context); 133 | let write_call = context.write_call( 134 | self.disassembler, 135 | &context_param, 136 | global_set.context, 137 | &value, 138 | ); 139 | quote! { 140 | #global_set_param.#set_fun(#address, |#context_param| #write_call); 141 | } 142 | } 143 | 144 | fn value(&self, value: &sleigh_rs::disassembly::ReadScope) -> TokenStream { 145 | use sleigh_rs::disassembly::ReadScope; 146 | match value { 147 | ReadScope::Integer(value) => { 148 | value.signed_super().suffixed().into_token_stream() 149 | } 150 | ReadScope::Context(context) => { 151 | self.context_field(context).to_token_stream() 152 | } 153 | ReadScope::TokenField(ass) => self.ass_field(*ass), 154 | ReadScope::Local(var) => self.var_name(var), 155 | ReadScope::InstStart(_) => self.inst_start().to_token_stream(), 156 | ReadScope::InstNext(_) => self.inst_next().to_token_stream(), 157 | } 158 | } 159 | 160 | fn set_context( 161 | &self, 162 | _context: &sleigh_rs::ContextId, 163 | _value: TokenStream, 164 | ) -> TokenStream { 165 | //TODO what if we modify the context and the result is used in the 166 | //global_set? check for that and find solutions! 167 | //for now, we just ignore context writes 168 | quote! {} 169 | } 170 | 171 | fn new_variable( 172 | &mut self, 173 | var_id: &VariableId, 174 | var: &Variable, 175 | ) -> TokenStream { 176 | let mut vars = self.vars.borrow_mut(); 177 | use indexmap::map::Entry::*; 178 | let Vacant(entry) = vars.entry(*var_id) else { 179 | unreachable!("Variable duplicated") 180 | }; 181 | let var_name = format_ident!("calc_{}", from_sleigh(var.name())); 182 | let name = entry.insert(var_name); 183 | quote! {let mut #name: #DISASSEMBLY_WORK_TYPE = 0;} 184 | } 185 | 186 | fn var_name(&self, var: &VariableId) -> TokenStream { 187 | let vars = self.vars.borrow(); 188 | let Some(name) = vars.get(var) else { 189 | unreachable!("Variable not created") 190 | }; 191 | name.into_token_stream() 192 | } 193 | } 194 | 195 | pub struct DisassemblyPattern<'a> { 196 | pub disassembler: &'a Disassembler, 197 | pub context_instance: &'a Ident, 198 | pub tokens: &'a Ident, 199 | pub inst_start: &'a Ident, 200 | pub root_tables: &'a IndexMap, 201 | pub root_token_fields: &'a IndexMap, 202 | pub vars: &'a mut IndexMap, 203 | } 204 | 205 | impl DisassemblyPattern<'_> { 206 | fn inst_start(&self) -> TokenStream { 207 | let inst_start = &self.inst_start; 208 | quote! {#DISASSEMBLY_WORK_TYPE::try_from(#inst_start).unwrap()} 209 | } 210 | //get var name on that contains the this assembly field value 211 | fn ass_field(&self, ass: &sleigh_rs::TokenFieldId) -> TokenStream { 212 | let tokens = self.tokens; 213 | let token_field_new = 214 | &self.disassembler.token_field_function(*ass).read; 215 | quote! { #DISASSEMBLY_WORK_TYPE::try_from(#token_field_new(#tokens)).unwrap() } 216 | } 217 | //get var name on that contains the this context value 218 | fn context_field(&self, context: &sleigh_rs::ContextId) -> TokenStream { 219 | let read_call = self 220 | .disassembler 221 | .context 222 | .read_call(*context, self.context_instance); 223 | quote! { #DISASSEMBLY_WORK_TYPE::try_from(#read_call).unwrap()} 224 | } 225 | fn can_execute(&self, expr: &sleigh_rs::disassembly::Expr) -> bool { 226 | use sleigh_rs::disassembly::ExprElement::*; 227 | use sleigh_rs::disassembly::ReadScope::*; 228 | expr.elements().iter().all(|element| match element { 229 | Op(_) | OpUnary(_) => true, 230 | Value { value, location: _ } => match value { 231 | Integer(_) | Context(_) | InstStart(_) | Local(_) 232 | | TokenField(_) => true, 233 | InstNext(_) => false, 234 | }, 235 | }) 236 | } 237 | } 238 | 239 | impl DisassemblyGenerator for DisassemblyPattern<'_> { 240 | //TODO identify disassembly that can't be executed separated between pre/pos 241 | fn disassembly( 242 | &self, 243 | assertations: &mut dyn Iterator, 244 | ) -> TokenStream { 245 | let mut tokens = TokenStream::new(); 246 | for ass in assertations { 247 | use sleigh_rs::disassembly::Assertation::*; 248 | match ass { 249 | GlobalSet(_) => (), 250 | Assignment(ass) => { 251 | if !self.can_execute(&ass.right) { 252 | break; 253 | } 254 | tokens.extend(self.assignment(ass)); 255 | } 256 | } 257 | } 258 | tokens 259 | } 260 | fn global_set(&self, _global_set: &GlobalSet) -> TokenStream { 261 | //global set is not done yet, only in display 262 | unreachable!() 263 | } 264 | 265 | fn value(&self, value: &sleigh_rs::disassembly::ReadScope) -> TokenStream { 266 | use sleigh_rs::disassembly::ReadScope; 267 | match value { 268 | ReadScope::Integer(value) => { 269 | value.signed_super().suffixed().into_token_stream() 270 | } 271 | ReadScope::Context(context) => { 272 | self.context_field(context).to_token_stream() 273 | } 274 | ReadScope::TokenField(ass) => self.ass_field(ass), 275 | ReadScope::Local(var) => self.var_name(var), 276 | ReadScope::InstStart(_) => self.inst_start().to_token_stream(), 277 | ReadScope::InstNext(_) => unreachable!(), 278 | } 279 | } 280 | 281 | fn set_context( 282 | &self, 283 | context: &sleigh_rs::ContextId, 284 | value: TokenStream, 285 | ) -> TokenStream { 286 | let write = self.disassembler.context.write_call( 287 | self.disassembler, 288 | self.context_instance, 289 | *context, 290 | &value, 291 | ); 292 | quote! { #write; } 293 | } 294 | 295 | fn new_variable( 296 | &mut self, 297 | var_id: &VariableId, 298 | var: &Variable, 299 | ) -> TokenStream { 300 | use indexmap::map::Entry::*; 301 | let Vacant(entry) = self.vars.entry(*var_id) else { 302 | unreachable!("Variable duplicated") 303 | }; 304 | let var_name = format_ident!("calc_{}", from_sleigh(var.name())); 305 | let name = entry.insert(var_name); 306 | quote! {let mut #name: #DISASSEMBLY_WORK_TYPE = 0;} 307 | } 308 | 309 | fn var_name(&self, var: &VariableId) -> TokenStream { 310 | let var = self.vars.get(var).unwrap(); 311 | var.to_token_stream() 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /src/builder/meaning.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Ident, TokenStream}; 2 | use quote::{format_ident, quote, ToTokens}; 3 | 4 | use super::{Disassembler, ToLiteral, WorkType, DISPLAY_WORK_TYPE}; 5 | use crate::{NonZeroTypeU, NumberSuperSigned}; 6 | 7 | #[derive(Debug, Clone)] 8 | pub struct VarMeaning { 9 | id: sleigh_rs::AttachVarnodeId, 10 | pub display_func: Ident, 11 | pub value_func: Ident, 12 | pub index_type: WorkType, 13 | pub varnode_bytes: NonZeroTypeU, 14 | } 15 | impl VarMeaning { 16 | pub fn new( 17 | sleigh: &sleigh_rs::Sleigh, 18 | id: sleigh_rs::AttachVarnodeId, 19 | attach: &sleigh_rs::meaning::AttachVarnode, 20 | fun_count: usize, 21 | ) -> Self { 22 | let index_max = attach 23 | .0 24 | .iter() 25 | .map(|(index, _varnode)| *index) 26 | .max() 27 | .unwrap(); 28 | let index_bits = (usize::BITS - index_max.leading_zeros()) + 1; 29 | let index_type = WorkType::new_int_bits(index_bits, false); 30 | let varnode_bytes = attach 31 | .0 32 | .first() 33 | .map(|(_index, varnode)| sleigh.varnode(*varnode).len_bytes) 34 | .unwrap(); 35 | Self { 36 | display_func: format_ident!("meaning_{}_display", fun_count), 37 | value_func: format_ident!("meaning_{}_value", fun_count), 38 | index_type, 39 | varnode_bytes, 40 | id, 41 | } 42 | } 43 | 44 | pub fn to_tokens( 45 | &self, 46 | tokens: &mut TokenStream, 47 | disassembler: &Disassembler, 48 | ) { 49 | let Self { 50 | id, 51 | display_func, 52 | value_func, 53 | index_type, 54 | varnode_bytes: _, 55 | } = self; 56 | let sleigh = disassembler.sleigh.attach_varnode(*id); 57 | let display_element = &disassembler.display.name; 58 | let ele_index = sleigh.0.iter().map(|(i, _v)| i.unsuffixed()); 59 | let ele_value = sleigh.0.iter().map(|(_i, v)| { 60 | let regs = disassembler.registers.name(); 61 | let variant = disassembler.registers.register(*v); 62 | quote! { #regs::#variant } 63 | }); 64 | let registers_enum = disassembler.registers.name(); 65 | tokens.extend(quote! { 66 | fn #value_func(num: T) -> #registers_enum 67 | where 68 | #index_type: TryFrom, 69 | <#index_type as TryFrom>::Error: core::fmt::Debug, 70 | { 71 | match #index_type::try_from(num).unwrap() { 72 | #(#ele_index => #ele_value,)* 73 | _ => unreachable!("Invalid Attach Value"), 74 | } 75 | } 76 | fn #display_func(num: T) -> #display_element 77 | where 78 | #index_type: TryFrom, 79 | <#index_type as TryFrom>::Error: core::fmt::Debug, 80 | { 81 | let value = #value_func(num.try_into().unwrap()); 82 | <#display_element>::Register(value) 83 | } 84 | }); 85 | } 86 | } 87 | 88 | #[derive(Debug, Clone)] 89 | pub struct NameMeaning { 90 | id: sleigh_rs::AttachLiteralId, 91 | pub display_func: Ident, 92 | pub index_type: WorkType, 93 | } 94 | impl NameMeaning { 95 | pub fn new( 96 | id: sleigh_rs::AttachLiteralId, 97 | attach: &sleigh_rs::meaning::AttachLiteral, 98 | fun_count: usize, 99 | ) -> Self { 100 | let index_max = attach 101 | .0 102 | .iter() 103 | .map(|(index, _varnode)| *index) 104 | .max() 105 | .unwrap(); 106 | let index_bits = (usize::BITS - index_max.leading_zeros()) + 1; 107 | let index_type = WorkType::new_int_bits(index_bits, false); 108 | Self { 109 | id, 110 | display_func: format_ident!("meaning_{}_display", fun_count), 111 | index_type, 112 | } 113 | } 114 | pub fn to_tokens( 115 | &self, 116 | tokens: &mut TokenStream, 117 | disassembler: &Disassembler, 118 | ) { 119 | let param_type = &self.index_type; 120 | let display_element = &disassembler.display.name; 121 | let attach = disassembler.sleigh.attach_literal(self.id); 122 | let ele_index = attach.0.iter().map(|(i, _v)| i.unsuffixed()); 123 | let ele_value = attach.0.iter().map(|(_i, v)| v); 124 | let display_func = &self.display_func; 125 | let index_type = &self.index_type; 126 | tokens.extend(quote! { 127 | fn #display_func(num: T) -> #display_element 128 | where 129 | #param_type: TryFrom, 130 | <#param_type as TryFrom>::Error: core::fmt::Debug, 131 | { 132 | match #index_type::try_from(num).unwrap() { 133 | #(#ele_index => <#display_element>::Literal(#ele_value),)* 134 | _ => unreachable!("Invalid Attach Value"), 135 | } 136 | } 137 | }); 138 | } 139 | } 140 | #[derive(Debug, Clone)] 141 | pub struct ValueMeaning { 142 | id: sleigh_rs::AttachNumberId, 143 | pub display_func: Ident, 144 | pub value_func: Ident, 145 | pub index_type: WorkType, 146 | pub value_type: WorkType, 147 | } 148 | impl ValueMeaning { 149 | pub fn new( 150 | id: sleigh_rs::AttachNumberId, 151 | attach: &sleigh_rs::meaning::AttachNumber, 152 | fun_count: usize, 153 | ) -> Self { 154 | let index_max = attach 155 | .0 156 | .iter() 157 | .map(|(index, _varnode)| *index) 158 | .max() 159 | .unwrap(); 160 | let index_bits = (usize::BITS - index_max.leading_zeros()) + 1; 161 | let index_type = WorkType::new_int_bits(index_bits, false); 162 | let (min, max) = attach.0.iter().map(|(_i, value)| *value).fold( 163 | (0, 0), 164 | |(min, max), value| { 165 | let min = min.min(value.signed_super()); 166 | let max = max.max(value.signed_super()); 167 | (min, max) 168 | }, 169 | ); 170 | //TODO this is not TOTALLY true, but good enough for now 171 | let mut value_bits = 172 | NumberSuperSigned::BITS - min.abs().max(max.abs()).leading_zeros(); 173 | let signed = min.is_negative(); 174 | if min.is_negative() { 175 | value_bits += 1; 176 | } 177 | let value_type = WorkType::new_int_bits(value_bits, signed); 178 | Self { 179 | id, 180 | display_func: format_ident!("meaning_{}_display", fun_count), 181 | value_func: format_ident!("meaning_{}_value", fun_count), 182 | index_type, 183 | value_type, 184 | } 185 | } 186 | 187 | pub fn to_tokens( 188 | &self, 189 | tokens: &mut TokenStream, 190 | disassembler: &Disassembler, 191 | ) { 192 | let param_type = &self.index_type; 193 | let display_element = &disassembler.display.name; 194 | let sleigh = disassembler.sleigh.attach_number(self.id); 195 | let ele_index = sleigh.0.iter().map(|(i, _v)| i.unsuffixed()); 196 | let ele_value = 197 | sleigh.0.iter().map(|(_i, v)| v.signed_super().unsuffixed()); 198 | let display_func = &self.display_func; 199 | let value_func = &self.value_func; 200 | let value_type = &self.value_type; 201 | let index_type = &self.index_type; 202 | 203 | let number_ele = &disassembler.display.number_var; 204 | let into_display = if value_type.is_signed() { 205 | quote! { 206 | <#display_element>::#number_ele(hex, value.is_negative(), value.abs() as #DISPLAY_WORK_TYPE) 207 | } 208 | } else { 209 | quote! { 210 | <#display_element>::#number_ele(hex, false, value as #DISPLAY_WORK_TYPE) 211 | } 212 | }; 213 | tokens.extend(quote! { 214 | fn #value_func(num: T) -> #value_type 215 | where 216 | #param_type: TryFrom, 217 | <#param_type as TryFrom>::Error: core::fmt::Debug, 218 | { 219 | match #index_type::try_from(num).unwrap() { 220 | #(#ele_index => #ele_value,)* 221 | _ => unreachable!("Invalid Attach Value"), 222 | } 223 | } 224 | fn #display_func(hex: bool, num: T) -> #display_element 225 | where 226 | #param_type: TryFrom, 227 | <#param_type as TryFrom>::Error: core::fmt::Debug, 228 | { 229 | let value = #value_func(num); 230 | #into_display 231 | } 232 | }); 233 | } 234 | } 235 | 236 | #[derive(Debug, Clone)] 237 | pub struct Meanings { 238 | pub vars: Vec, 239 | pub names: Vec, 240 | pub values: Vec, 241 | } 242 | 243 | impl Meanings { 244 | pub fn new(sleigh: &sleigh_rs::Sleigh) -> Self { 245 | let mut counter = 0usize; 246 | let mut counter_value = || { 247 | let value = counter; 248 | counter += 1; 249 | value 250 | }; 251 | let vars = sleigh 252 | .attach_varnodes() 253 | .iter() 254 | .enumerate() 255 | .map(|(i, var)| { 256 | VarMeaning::new( 257 | sleigh, 258 | sleigh_rs::AttachVarnodeId(i), 259 | var, 260 | counter_value(), 261 | ) 262 | }) 263 | .collect(); 264 | let names = sleigh 265 | .attach_literals() 266 | .iter() 267 | .enumerate() 268 | .map(|(i, var)| { 269 | NameMeaning::new( 270 | sleigh_rs::AttachLiteralId(i), 271 | var, 272 | counter_value(), 273 | ) 274 | }) 275 | .collect(); 276 | let values = sleigh 277 | .attach_numbers() 278 | .iter() 279 | .enumerate() 280 | .map(|(i, var)| { 281 | ValueMeaning::new( 282 | sleigh_rs::AttachNumberId(i), 283 | var, 284 | counter_value(), 285 | ) 286 | }) 287 | .collect(); 288 | Self { 289 | vars, 290 | names, 291 | values, 292 | } 293 | } 294 | pub fn display_function_call( 295 | &self, 296 | len_bits: u32, 297 | value: impl ToTokens, 298 | meaning: sleigh_rs::meaning::Meaning, 299 | ) -> TokenStream { 300 | use sleigh_rs::meaning::Meaning; 301 | match meaning { 302 | Meaning::NoAttach(print_fmt) => { 303 | let hex = print_fmt.base.is_hex(); 304 | if !print_fmt.signed { 305 | quote! { DisplayElement::Number(#hex, false, #value as #DISPLAY_WORK_TYPE) } 306 | } else { 307 | let final_type = WorkType::new_int_bits(len_bits, true); 308 | let value = crate::builder::helper::sign_from_value( 309 | len_bits, final_type, value, 310 | ); 311 | quote! { DisplayElement::Number(#hex, #value.is_negative(), #value.abs() as #DISPLAY_WORK_TYPE) } 312 | } 313 | } 314 | Meaning::Varnode(vars) => { 315 | let function = &self.vars[vars.0].display_func; 316 | quote! { #function(#value) } 317 | } 318 | Meaning::Literal(vars) => { 319 | let function = &self.names[vars.0].display_func; 320 | quote! { #function(#value) } 321 | } 322 | Meaning::Number(base, vars) => { 323 | let function = &self.values[vars.0].display_func; 324 | let hex = base.is_hex(); 325 | quote! { 326 | #function(#hex, #value) 327 | } 328 | } 329 | } 330 | } 331 | 332 | pub fn disassembly_function_call( 333 | &self, 334 | len_bits: u32, 335 | value: impl ToTokens, 336 | meaning: sleigh_rs::meaning::Meaning, 337 | ) -> TokenStream { 338 | use sleigh_rs::meaning::Meaning; 339 | match meaning { 340 | Meaning::NoAttach(print_fmt) if print_fmt.signed => { 341 | let final_type = WorkType::new_int_bits(len_bits, true); 342 | crate::builder::helper::sign_from_value( 343 | len_bits, final_type, value, 344 | ) 345 | } 346 | Meaning::Number(_base, vars) => { 347 | let function = &self.values[vars.0].value_func; 348 | quote! { #function(#value) } 349 | } 350 | _ => value.into_token_stream(), 351 | } 352 | } 353 | 354 | //TODO 355 | //pub fn execution_function_call( 356 | // todo!(); 357 | //} 358 | 359 | pub fn to_tokens( 360 | &self, 361 | tokens: &mut TokenStream, 362 | disassembler: &Disassembler, 363 | ) { 364 | for variable in self.vars.iter() { 365 | variable.to_tokens(tokens, disassembler); 366 | } 367 | for name in self.names.iter() { 368 | name.to_tokens(tokens, disassembler); 369 | } 370 | for value in self.values.iter() { 371 | value.to_tokens(tokens, disassembler); 372 | } 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /src/builder/disassembler/constructor/mod.rs: -------------------------------------------------------------------------------- 1 | use indexmap::IndexMap; 2 | use std::cell::RefCell; 3 | 4 | use proc_macro2::{Ident, TokenStream}; 5 | use quote::{format_ident, quote, ToTokens}; 6 | 7 | use crate::builder::formater::from_sleigh; 8 | use crate::builder::{DisassemblyGenerator, DISPLAY_WORK_TYPE, ToLiteral}; 9 | 10 | use super::Disassembler; 11 | 12 | mod disassembly; 13 | pub use disassembly::*; 14 | 15 | mod pattern; 16 | pub use pattern::*; 17 | 18 | pub struct ConstructorStruct { 19 | pub constructor_id: sleigh_rs::table::ConstructorId, 20 | pub table_id: sleigh_rs::TableId, 21 | //struct name 22 | pub struct_name: Ident, 23 | //variant name in the enum 24 | pub enum_name: Ident, 25 | //display function 26 | pub display_fun: Ident, 27 | pub disassembly_fun: Ident, 28 | pub parser_fun: Ident, 29 | pub table_fields: IndexMap, 30 | pub ass_fields: IndexMap, 31 | //TODO instead of having calc fields, have a constructor phase 1/2, with 32 | //the display/execution values in phase2 and values required by the 33 | //disassembly in phase1 34 | //Alternativally, having the having display call execute all the disassembly 35 | //as this will never be in the disassembly_pre 36 | //pub calc_fields: IndexMap<*const Variable, ParsedField>>, 37 | } 38 | impl ConstructorStruct { 39 | pub fn new( 40 | sleigh: &sleigh_rs::Sleigh, 41 | table_id: sleigh_rs::TableId, 42 | constructor: &sleigh_rs::table::Constructor, 43 | constructor_id: sleigh_rs::table::ConstructorId, 44 | table_name: &str, 45 | number: usize, 46 | ) -> Self { 47 | //let mut calc_fields = IndexMap::new(); 48 | let mut ass_fields: IndexMap<_, _> = IndexMap::new(); 49 | //tables are always included to the struct, used or not 50 | let table_fields = constructor 51 | .pattern 52 | .produced_tables() 53 | .map(|produced_table| { 54 | let table = sleigh.table(produced_table.table); 55 | ( 56 | produced_table.table, 57 | format_ident!("{}", from_sleigh(table.name())), 58 | ) 59 | }) 60 | .collect(); 61 | 62 | //include on the enum all the required fields from the display 63 | for display in constructor.display.elements() { 64 | use sleigh_rs::display::DisplayElement::*; 65 | match display { 66 | Context(_) | InstStart(_) | InstNext(_) | Varnode(_) 67 | | Literal(_) | Space => (), 68 | TokenField(ass) => { 69 | ass_fields.entry(*ass).or_insert_with(|| { 70 | let ass = sleigh.token_field(*ass); 71 | format_ident!("{}", from_sleigh(ass.name())) 72 | }); 73 | } 74 | // disassembly is all done durint the display call 75 | Disassembly(_var) => {} 76 | //table is added independed if it shows up on display 77 | Table(_display_table) => {} 78 | } 79 | } 80 | //TODO only add fields required by the display, not all fields required 81 | //by the disassembly 82 | for field in constructor 83 | .pattern 84 | .blocks() 85 | .iter() 86 | .flat_map(|block| match block { 87 | sleigh_rs::pattern::Block::And { pre, pos, .. } => { 88 | pre.iter().chain(pos.iter()) 89 | } 90 | sleigh_rs::pattern::Block::Or { pos, .. } => { 91 | pos.iter().chain([/*LOL*/].iter()) 92 | } 93 | }) 94 | .chain(constructor.pattern.disassembly_pos_match()) 95 | { 96 | use sleigh_rs::disassembly; 97 | match field { 98 | disassembly::Assertation::GlobalSet( 99 | disassembly::GlobalSet { .. }, 100 | ) => (), 101 | disassembly::Assertation::Assignment( 102 | disassembly::Assignment { left: _, right }, 103 | ) => { 104 | let fields = right.elements().iter().filter_map(|ele| { 105 | use sleigh_rs::disassembly::ExprElement::*; 106 | use sleigh_rs::disassembly::ReadScope::*; 107 | match ele { 108 | Value { 109 | value: TokenField(ass), 110 | location: _, 111 | } => Some(*ass), 112 | _ => None, 113 | } 114 | }); 115 | for ass in fields { 116 | ass_fields.entry(ass).or_insert_with(|| { 117 | let ass = sleigh.token_field(ass); 118 | format_ident!("{}", from_sleigh(ass.name())) 119 | }); 120 | } 121 | } 122 | } 123 | } 124 | 125 | let struct_name = 126 | if let Some(mneumonic) = &constructor.display.mneumonic { 127 | format_ident!( 128 | "{}_{}Var{}", 129 | from_sleigh(mneumonic), 130 | table_name, 131 | number 132 | ) 133 | } else { 134 | format_ident!("{}Var{}", table_name, number) 135 | }; 136 | 137 | Self { 138 | enum_name: format_ident!("Var{}", number), 139 | struct_name, 140 | display_fun: format_ident!("display_extend"), 141 | disassembly_fun: format_ident!("disassembly"), 142 | parser_fun: format_ident!("parse"), 143 | ass_fields, 144 | table_fields, 145 | constructor_id, 146 | table_id, 147 | } 148 | } 149 | 150 | pub fn gen_display(&self, disassembler: &Disassembler) -> TokenStream { 151 | let Self { 152 | display_fun, 153 | struct_name: _, 154 | enum_name: _, 155 | disassembly_fun: _, 156 | parser_fun: _, 157 | constructor_id, 158 | table_id, 159 | table_fields: _, 160 | ass_fields: _, 161 | } = self; 162 | let display_param = format_ident!("display"); 163 | let context_param = format_ident!("context"); 164 | let inst_start = format_ident!("inst_start"); 165 | let inst_next = format_ident!("inst_next"); 166 | let global_set_param = format_ident!("global_set"); 167 | let display_struct = &disassembler.display.name; 168 | let register_enum = &disassembler.registers.name; 169 | 170 | use sleigh_rs::display::DisplayElement as DisplayScope; 171 | let mut disassembly = DisassemblyDisplay { 172 | constructor: self, 173 | display_param: &display_param, 174 | context_param: &context_param, 175 | inst_start: &inst_start, 176 | inst_next: &inst_next, 177 | global_set_param: &global_set_param, 178 | vars: RefCell::new(IndexMap::new()), 179 | disassembler, 180 | }; 181 | let constructor = disassembler 182 | .sleigh 183 | .table(*table_id) 184 | .constructor(*constructor_id); 185 | let mut disassembly_body: TokenStream = constructor 186 | .pattern 187 | .disassembly_vars() 188 | .iter() 189 | .enumerate() 190 | .map(|(i, var)| { 191 | disassembly 192 | .new_variable(&sleigh_rs::disassembly::VariableId(i), var) 193 | }) 194 | .collect(); 195 | disassembly_body.extend(disassembly.to_token_stream()); 196 | let add_mneumonic = 197 | constructor.display.mneumonic.as_ref().map(|mneumonic| { 198 | let display_element = &disassembler.display.name; 199 | let literal = &disassembler.display.literal_var; 200 | quote! { #display_param.push(#display_element::#literal(#mneumonic)); } 201 | }); 202 | let elements: Vec<_> = constructor.display.elements().collect(); 203 | let displays = elements 204 | .split_inclusive(|ele| matches!(ele, DisplayScope::Table(_))) 205 | .map(|eles| { 206 | let (ele, table) = match eles { 207 | [ele @ .., DisplayScope::Table(table)] => { 208 | (ele, Some(table)) 209 | } 210 | _ => (eles, None), 211 | }; 212 | let extend = (!ele.is_empty()).then(|| { 213 | let display = ele.iter().map(|ele| match ele { 214 | DisplayScope::Varnode(varnode) => { 215 | let reg_var = 216 | disassembler.registers.register(*varnode); 217 | quote! { 218 | <#display_struct>::Register( 219 | #register_enum::#reg_var 220 | ) 221 | } 222 | } 223 | DisplayScope::Context(context) => { 224 | disassembler.context.display_call( 225 | disassembler, 226 | &context_param, 227 | *context, 228 | ) 229 | } 230 | DisplayScope::TokenField(ass) => { 231 | let var_name = self.ass_fields.get(ass).unwrap(); 232 | let token_field = 233 | disassembler.sleigh.token_field(*ass); 234 | disassembler.meanings.display_function_call( 235 | token_field.bits.len().get().try_into().unwrap(), 236 | quote! {self.#var_name}, 237 | token_field.meaning(), 238 | ) 239 | } 240 | DisplayScope::Disassembly(var) => { 241 | let vars = disassembly.vars.borrow(); 242 | let var_name = vars.get(var).unwrap(); 243 | let number_ele = &disassembler.display.number_var; 244 | use sleigh_rs::disassembly::VariableType; 245 | match constructor.pattern.disassembly_var(*var).value_type { 246 | VariableType::Reference(space_id) => { 247 | let space = disassembler.sleigh.space(space_id); 248 | let space_addr_len = space.addr_bytes.get() * 8; 249 | let mask = (u128::MAX >> (u128::BITS as u64 - space_addr_len)).unsuffixed(); 250 | quote! {<#display_struct>::#number_ele(true, false, (#var_name.abs() & #mask) as #DISPLAY_WORK_TYPE)} 251 | }, 252 | VariableType::Value(Some(len)) => { 253 | let mask = (u128::MAX >> (u128::BITS as u64 - len.get())).unsuffixed(); 254 | quote! {<#display_struct>::#number_ele(true, false, (#var_name.bas() & #mask) as #DISPLAY_WORK_TYPE)} 255 | }, 256 | VariableType::Value(None) => { 257 | quote! {<#display_struct>::#number_ele(true, #var_name.is_negative(), #var_name.abs() as #DISPLAY_WORK_TYPE)} 258 | } 259 | } 260 | } 261 | DisplayScope::Space => { 262 | quote! {<#display_struct>::Literal(" ")} 263 | } 264 | DisplayScope::Literal(literal) => { 265 | quote! {<#display_struct>::Literal(#literal)} 266 | } 267 | DisplayScope::Table(_) => unreachable!(), 268 | DisplayScope::InstStart(_) => { 269 | inst_start.to_token_stream() 270 | } 271 | DisplayScope::InstNext(_) => { 272 | inst_next.to_token_stream() 273 | } 274 | }); 275 | let display_out_len = ele.len(); 276 | quote! { 277 | let extend: [#display_struct; #display_out_len] = [ 278 | #(#display),* 279 | ]; 280 | #display_param.extend_from_slice(&extend); 281 | } 282 | }); 283 | let build_table = table.map(|table_id| { 284 | let field_name = self.table_fields.get(table_id).unwrap(); 285 | let table = disassembler.table_struct(*table_id); 286 | let produced_table = constructor 287 | .pattern 288 | .produced_tables() 289 | .find(|prod| prod.table == *table_id) 290 | .unwrap(); 291 | let display_fun = &table.display_fun; 292 | if produced_table.always { 293 | quote! { 294 | self.#field_name.#display_fun( 295 | #display_param, 296 | #context_param, 297 | #inst_start, 298 | #inst_next, 299 | #global_set_param, 300 | ); 301 | } 302 | } else { 303 | quote! { 304 | self.#field_name.as_ref().map(|table| { 305 | table.#display_fun( 306 | #display_param, 307 | #context_param, 308 | #inst_start, 309 | #inst_next, 310 | #global_set_param, 311 | ); 312 | }); 313 | } 314 | } 315 | }); 316 | quote! { 317 | #extend 318 | #build_table 319 | } 320 | }); 321 | let context_struct = &disassembler.context.name; 322 | let globalset_struct = &disassembler.context.globalset.name; 323 | let addr_type = &disassembler.addr_type; 324 | quote! { 325 | fn #display_fun( 326 | &self, 327 | #display_param: &mut Vec<#display_struct>, 328 | #context_param: &#context_struct, 329 | #inst_start: #addr_type, 330 | #inst_next: #addr_type, 331 | #global_set_param: &mut #globalset_struct, 332 | ) { 333 | #disassembly_body 334 | #add_mneumonic 335 | #(#displays)* 336 | } 337 | } 338 | } 339 | 340 | pub fn to_tokens( 341 | &self, 342 | tokens: &mut TokenStream, 343 | disassembler: &Disassembler, 344 | ) { 345 | let Self { 346 | struct_name, 347 | table_fields, 348 | ass_fields, 349 | parser_fun, 350 | enum_name: _, 351 | display_fun: _, 352 | disassembly_fun: _, 353 | constructor_id, 354 | table_id, 355 | } = self; 356 | let constructor = disassembler 357 | .sleigh 358 | .table(*table_id) 359 | .constructor(*constructor_id); 360 | let doc = format!("Constructor at {}", &constructor.location); 361 | let ass_fields = ass_fields.iter().map(|(field_id, name)| { 362 | let data_type = 363 | &disassembler.token_field_function(*field_id).read_type; 364 | quote! { #name: #data_type } 365 | }); 366 | let table_fields = table_fields.iter().map(|(table_id, name)| { 367 | let produced_table = constructor 368 | .pattern 369 | .produced_tables() 370 | .find(|produced| produced.table == *table_id) 371 | .unwrap(); 372 | let table_struct_name = &disassembler.table_struct(*table_id).name; 373 | let mut table_data = table_struct_name.into_token_stream(); 374 | if produced_table.recursive { 375 | table_data = quote! {Box<#table_data>}; 376 | } 377 | if !produced_table.always { 378 | table_data = quote! {Option<#table_data>}; 379 | } 380 | quote! { #name: #table_data } 381 | }); 382 | let display_impl = self.gen_display(disassembler); 383 | let parser_function = 384 | root_pattern_function(parser_fun, self, disassembler); 385 | tokens.extend(quote! { 386 | #[doc = #doc] 387 | #[derive(Clone, Debug)] 388 | struct #struct_name { 389 | #(#ass_fields,)* 390 | #(#table_fields,)* 391 | } 392 | impl #struct_name { 393 | #display_impl 394 | #parser_function 395 | } 396 | }) 397 | } 398 | } 399 | -------------------------------------------------------------------------------- /src/builder/disassembler/constructor/pattern.rs: -------------------------------------------------------------------------------- 1 | use indexmap::IndexMap; 2 | 3 | use crate::builder::formater::from_sleigh; 4 | use crate::builder::{ 5 | Disassembler, DisassemblyGenerator, ToLiteral, DISASSEMBLY_WORK_TYPE, 6 | }; 7 | use proc_macro2::{Ident, TokenStream}; 8 | use quote::{format_ident, quote, ToTokens}; 9 | use sleigh_rs::disassembly::{self, Assertation, GlobalSet}; 10 | use sleigh_rs::pattern::{ 11 | ConstraintValue, ProducedTable, ProducedTokenField, Verification, 12 | }; 13 | 14 | use super::{ConstructorStruct, DisassemblyPattern}; 15 | 16 | pub fn root_pattern_function( 17 | parse_fun: &Ident, 18 | constructor_struct: &ConstructorStruct, 19 | disassembler: &Disassembler, 20 | ) -> TokenStream { 21 | let context_memory = &disassembler.context.name; 22 | let addr_type = &disassembler.addr_type; 23 | let inst_start = format_ident!("inst_start"); 24 | let pattern_len = format_ident!("pattern_len"); 25 | let tokens_current = format_ident!("tokens_current"); 26 | let context_instance = format_ident!("context_instance"); 27 | let mut disassembly_vars = IndexMap::new(); 28 | let mut root_tables = IndexMap::new(); 29 | let mut root_token_fields = IndexMap::new(); 30 | 31 | //TODO remove this 32 | let mut disassembly = DisassemblyPattern { 33 | disassembler, 34 | context_instance: &context_instance, 35 | inst_start: &inst_start, 36 | root_tables: &root_tables, 37 | root_token_fields: &root_token_fields, 38 | vars: &mut disassembly_vars, 39 | tokens: &tokens_current, 40 | }; 41 | let constructor = disassembler 42 | .sleigh 43 | .table(constructor_struct.table_id) 44 | .constructor(constructor_struct.constructor_id); 45 | let variables: TokenStream = constructor 46 | .pattern 47 | .disassembly_vars() 48 | .iter() 49 | .enumerate() 50 | .map(|(i, var)| { 51 | disassembly 52 | .new_variable(&sleigh_rs::disassembly::VariableId(i), var) 53 | }) 54 | .collect(); 55 | 56 | // dissable flat pattern if in debug mode 57 | let mut part_of_flat = !disassembler.debug; 58 | let blocks_parse: TokenStream = constructor 59 | .pattern 60 | .blocks() 61 | .iter() 62 | // mark blocks that are part of the calculated flat pattern 63 | .map(move |block| { 64 | let this_is_flat = part_of_flat; 65 | part_of_flat &= block.len().single_len().is_some(); 66 | (block, this_is_flat) 67 | }) 68 | .enumerate() 69 | .map(|(index, (block, part_of_flat))| { 70 | body_block( 71 | constructor_struct, 72 | index, 73 | part_of_flat, 74 | block, 75 | &pattern_len, 76 | &inst_start, 77 | &context_instance, 78 | &tokens_current, 79 | &IndexMap::new(), 80 | &IndexMap::new(), 81 | &mut disassembly_vars, 82 | &mut root_tables, 83 | &mut root_token_fields, 84 | disassembler, 85 | ) 86 | }) 87 | .collect(); 88 | 89 | //all tables produced are stored, always 90 | let table_fields = constructor_struct.table_fields.values(); 91 | //only pass the token fields that need to be stored 92 | let token_fields = constructor_struct.ass_fields.values(); 93 | let fields = table_fields.chain(token_fields); 94 | quote! { 95 | fn #parse_fun( 96 | mut #tokens_current: &[u8], 97 | context: &mut #context_memory, 98 | #inst_start: #addr_type, 99 | ) -> Option<(#addr_type, Self)> { 100 | //each block will increment this value by its size 101 | let mut #pattern_len = 0; 102 | let mut #context_instance = context.clone(); 103 | 104 | //disassembly_vars 105 | #variables 106 | 107 | //the current_token will be increseased by each block, so the 108 | //next block knows when to start parsing 109 | #blocks_parse 110 | //only on instruction table, otherwise this is on a function 111 | *context = #context_instance; 112 | Some(( 113 | #pattern_len, 114 | Self{ #(#fields),* }, 115 | )) 116 | } 117 | } 118 | } 119 | 120 | fn sub_pattern_closure( 121 | constructor: &ConstructorStruct, 122 | pattern: &sleigh_rs::pattern::Pattern, 123 | inst_start: &Ident, 124 | disassembly_vars: &mut IndexMap, 125 | root_tables: &IndexMap, 126 | root_token_fields: &IndexMap, 127 | disassembler: &Disassembler, 128 | ) -> TokenStream { 129 | let tokens_current = format_ident!("tokens"); 130 | let pattern_len = format_ident!("pattern_len"); 131 | let context_instance = format_ident!("context_instance"); 132 | let mut produced_tables = IndexMap::new(); 133 | let mut produced_token_fields = IndexMap::new(); 134 | 135 | let blocks_parse: TokenStream = pattern 136 | .blocks() 137 | .iter() 138 | .enumerate() 139 | .map(|(index, block)| { 140 | body_block( 141 | constructor, 142 | index, 143 | false, 144 | block, 145 | &pattern_len, 146 | inst_start, 147 | &context_instance, 148 | &tokens_current, 149 | root_tables, 150 | root_token_fields, 151 | disassembly_vars, 152 | &mut produced_tables, 153 | &mut produced_token_fields, 154 | disassembler, 155 | ) 156 | }) 157 | .collect(); 158 | let table_fields = pattern.produced_tables().map(|table_field| { 159 | produced_tables 160 | .get(&table_field.table) 161 | .expect("LOGIC_EROR: Table not produced") 162 | }); 163 | let token_fields = pattern.produced_token_fields().map(|token_field| { 164 | produced_token_fields 165 | .get(&token_field.field) 166 | .expect("LOGIC_EROR: TokenField not produced") 167 | }); 168 | let context_struct = &disassembler.context.name; 169 | quote! { 170 | |tokens: &[u8], context_param: &mut #context_struct| { 171 | //each block will increment this value by its size 172 | let mut #pattern_len = 0; 173 | let mut #context_instance = context_param.clone(); 174 | //the current_token will be increseased by each block, so the next 175 | //block knows when to start parsing 176 | let mut #tokens_current = tokens; 177 | #blocks_parse 178 | *context_param = #context_instance; 179 | Some(( 180 | (#(#table_fields),*), 181 | (#(#token_fields),*), 182 | #pattern_len 183 | )) 184 | } 185 | } 186 | } 187 | 188 | fn body_block( 189 | constructor: &ConstructorStruct, 190 | block_index: usize, 191 | part_of_flat: bool, 192 | block: &sleigh_rs::pattern::Block, 193 | pattern_len: &Ident, 194 | inst_start: &Ident, 195 | context_param: &Ident, 196 | tokens: &Ident, 197 | root_tables: &IndexMap, 198 | root_token_fields: &IndexMap, 199 | disassembly_vars: &mut IndexMap, 200 | produced_tables: &mut IndexMap, 201 | produced_fields: &mut IndexMap, 202 | disassembler: &Disassembler, 203 | ) -> TokenStream { 204 | match block { 205 | sleigh_rs::pattern::Block::And { 206 | len, 207 | token_fields, 208 | tables, 209 | verifications, 210 | pre, 211 | pos, 212 | variants_prior: _, 213 | variants_number: _, 214 | } => body_block_and( 215 | constructor, 216 | block_index, 217 | part_of_flat, 218 | len, 219 | token_fields, 220 | tables, 221 | verifications, 222 | pre, 223 | pos, 224 | pattern_len, 225 | inst_start, 226 | context_param, 227 | tokens, 228 | root_tables, 229 | root_token_fields, 230 | disassembly_vars, 231 | produced_tables, 232 | produced_fields, 233 | disassembler, 234 | ), 235 | sleigh_rs::pattern::Block::Or { 236 | len, 237 | token_fields, 238 | tables, 239 | branches, 240 | pos, 241 | variants_prior: _, 242 | variants_number: _, 243 | } => { 244 | let block_closure = block_or_closure( 245 | constructor, 246 | len, 247 | token_fields, 248 | tables, 249 | branches, 250 | pattern_len, 251 | inst_start, 252 | disassembly_vars, 253 | root_tables, 254 | root_token_fields, 255 | disassembler, 256 | ); 257 | //create the fields produced by this closure 258 | let fields = block.token_fields().iter().map(|field| { 259 | let token_field = disassembler.sleigh.token_field(field.field); 260 | let name = format_ident!("{}", from_sleigh(token_field.name())); 261 | produced_fields 262 | .entry(field.field) 263 | .and_modify(|_| unreachable!()) 264 | .or_insert_with(|| name.clone()); 265 | name 266 | }); 267 | let tables = block.tables().iter().map(|field| { 268 | let table = disassembler.sleigh.table(field.table); 269 | let name = format_ident!("{}", from_sleigh(table.name())); 270 | produced_tables 271 | .entry(field.table) 272 | .and_modify(|_| unreachable!()) 273 | .or_insert_with(|| name.clone()); 274 | name 275 | }); 276 | let block_name = format_ident!("block_{}", block_index); 277 | let block_len = format_ident!("block_{}_len", block_index); 278 | let disassembly = DisassemblyPattern { 279 | disassembler, 280 | context_instance: context_param, 281 | inst_start, 282 | root_tables, 283 | root_token_fields, 284 | vars: disassembly_vars, 285 | tokens, 286 | }; 287 | let disassembly = disassembly.disassembly(&mut pos.iter()); 288 | quote! { 289 | let #block_name = #block_closure; 290 | let ( 291 | (#(#tables),*), 292 | (#(#fields),*), 293 | #block_len, 294 | ) = #block_name(#tokens, &mut #context_param)?; 295 | #disassembly 296 | #pattern_len += #block_len; 297 | #tokens = &#tokens[usize::try_from(#block_len).unwrap()..]; 298 | } 299 | } 300 | } 301 | } 302 | 303 | fn body_block_and( 304 | constructor: &ConstructorStruct, 305 | block_index: usize, 306 | part_of_flat: bool, 307 | len: &sleigh_rs::pattern::PatternLen, 308 | sleigh_token_fields: &[ProducedTokenField], 309 | sleigh_tables: &[ProducedTable], 310 | verifications: &[Verification], 311 | pre: &[Assertation], 312 | pos: &[Assertation], 313 | pattern_len: &Ident, 314 | inst_start: &Ident, 315 | context: &Ident, 316 | tokens: &Ident, 317 | root_tables: &IndexMap, 318 | root_token_fields: &IndexMap, 319 | disassembly_vars: &mut IndexMap, 320 | produced_tables: &mut IndexMap, 321 | produced_token_fields: &mut IndexMap, 322 | disassembler: &Disassembler, 323 | ) -> TokenStream { 324 | let block_len = format_ident!("block_{}_len", block_index); 325 | 326 | let code_pre = body_block_and_pre( 327 | constructor, 328 | len, 329 | part_of_flat, 330 | sleigh_token_fields, 331 | sleigh_tables, 332 | verifications, 333 | pre, 334 | &block_len, 335 | inst_start, 336 | root_tables, 337 | root_token_fields, 338 | disassembly_vars, 339 | tokens, 340 | context, 341 | disassembler, 342 | ); 343 | let code_pos = body_block_and_pos( 344 | constructor, 345 | len, 346 | sleigh_token_fields, 347 | sleigh_tables, 348 | verifications, 349 | pos, 350 | &block_len, 351 | inst_start, 352 | root_tables, 353 | root_token_fields, 354 | disassembly_vars, 355 | tokens, 356 | context, 357 | produced_tables, 358 | produced_token_fields, 359 | disassembler, 360 | ); 361 | let this_block_min_len = len.min().unsuffixed(); 362 | quote! { 363 | let mut #block_len = #this_block_min_len; 364 | #code_pre 365 | #code_pos 366 | #pattern_len += #block_len; 367 | #tokens = &#tokens[usize::try_from(#block_len).unwrap()..]; 368 | } 369 | } 370 | 371 | fn body_block_and_pre( 372 | _constructor: &ConstructorStruct, 373 | _len: &sleigh_rs::pattern::PatternLen, 374 | part_of_flat: bool, 375 | _sleigh_token_fields: &[ProducedTokenField], 376 | _sleigh_tables: &[ProducedTable], 377 | verifications: &[Verification], 378 | pre: &[Assertation], 379 | _block_len: &Ident, 380 | inst_start: &Ident, 381 | root_tables: &IndexMap, 382 | root_token_fields: &IndexMap, 383 | vars: &mut IndexMap, 384 | tokens: &Ident, 385 | context_instance: &Ident, 386 | disassembler: &Disassembler, 387 | ) -> TokenStream { 388 | //verify all the values and build all the tables 389 | let verifications = verifications.iter().filter_map(|ver| match ver { 390 | // simple eq verifications can be ignored if part of the flat pattern 391 | Verification::TokenFieldCheck { 392 | field: _, 393 | op: sleigh_rs::pattern::CmpOp::Eq, 394 | value, 395 | } 396 | | Verification::ContextCheck { 397 | context: _, 398 | op: sleigh_rs::pattern::CmpOp::Eq, 399 | value, 400 | } if part_of_flat 401 | && matches!( 402 | value.expr().elements(), 403 | [sleigh_rs::disassembly::ExprElement::Value { 404 | value: sleigh_rs::disassembly::ReadScope::Integer(_number), 405 | location: _, 406 | }] 407 | ) => 408 | { 409 | None 410 | } 411 | Verification::ContextCheck { context, op, value } => { 412 | Some(context_verification( 413 | true, 414 | *context, 415 | op, 416 | value, 417 | disassembler, 418 | tokens, 419 | context_instance, 420 | inst_start, 421 | root_token_fields, 422 | )) 423 | } 424 | Verification::TokenFieldCheck { field, op, value } => { 425 | Some(field_verification( 426 | true, 427 | *field, 428 | op, 429 | value, 430 | disassembler, 431 | tokens, 432 | context_instance, 433 | inst_start, 434 | root_token_fields, 435 | )) 436 | } 437 | //table and sub_pattern is done on pos 438 | Verification::TableBuild { .. } | Verification::SubPattern { .. } => { 439 | None 440 | } 441 | }); 442 | 443 | let disassembly = DisassemblyPattern { 444 | disassembler, 445 | context_instance, 446 | inst_start, 447 | root_tables, 448 | root_token_fields, 449 | vars, 450 | tokens, 451 | }; 452 | let disassembly = disassembly.disassembly(&mut pre.iter()); 453 | 454 | let code = quote! { 455 | #(if #verifications { 456 | return None; 457 | })* 458 | #disassembly 459 | }; 460 | code 461 | } 462 | 463 | fn body_block_and_pos( 464 | constructor: &ConstructorStruct, 465 | _len: &sleigh_rs::pattern::PatternLen, 466 | sleigh_token_fields: &[ProducedTokenField], 467 | _sleigh_tables: &[ProducedTable], 468 | verifications: &[Verification], 469 | pos: &[Assertation], 470 | block_len: &Ident, 471 | inst_start: &Ident, 472 | root_tables: &IndexMap, 473 | root_token_fields: &IndexMap, 474 | vars: &mut IndexMap, 475 | tokens: &Ident, 476 | context_instance: &Ident, 477 | produced_tables: &mut IndexMap, 478 | produced_token_fields: &mut IndexMap, 479 | disassembler: &Disassembler, 480 | ) -> TokenStream { 481 | //verify all the values and build all the tables 482 | let verifications: TokenStream = verifications 483 | .iter() 484 | .filter_map(|ver| match ver { 485 | //done in pre 486 | Verification::ContextCheck { .. } 487 | | Verification::TokenFieldCheck { .. } => None, 488 | Verification::TableBuild { 489 | produced_table, 490 | verification, 491 | } => { 492 | if verification.is_some() { 493 | //TODO implement this 494 | todo!("implement table return value verification") 495 | } 496 | let table = disassembler.sleigh.table(produced_table.table); 497 | let table_name = format_ident!("{}", from_sleigh(table.name())); 498 | produced_tables 499 | .entry(produced_table.table) 500 | .and_modify(|_| unreachable!()) 501 | .or_insert_with(|| table_name.clone()); 502 | let table_parsing = call_parser( 503 | disassembler, 504 | context_instance, 505 | tokens, 506 | inst_start, 507 | produced_table.table, 508 | ); 509 | let addr_type = &disassembler.addr_type; 510 | let table_inner = format_ident!("table"); 511 | let table_inner_output = if produced_table.recursive { 512 | //recursive need to go inside a box 513 | quote! {Box::new(#table_inner)} 514 | } else { 515 | table_inner.to_token_stream() 516 | }; 517 | Some(quote! { 518 | let #table_name = if let Some((len, #table_inner)) = 519 | #table_parsing { 520 | #block_len = #block_len.max(len as #addr_type); 521 | #table_inner_output 522 | } else { 523 | return None; 524 | }; 525 | }) 526 | } 527 | Verification::SubPattern { location, pattern } => { 528 | //TODO check recursive/always for table 529 | let sub_func = sub_pattern_closure( 530 | constructor, 531 | pattern, 532 | inst_start, 533 | vars, 534 | root_tables, 535 | root_token_fields, 536 | disassembler, 537 | ); 538 | let tables = pattern.produced_tables().map(|table_field| { 539 | let table = disassembler.sleigh.table(table_field.table); 540 | let table_name = 541 | format_ident!("{}", from_sleigh(table.name())); 542 | produced_tables 543 | .entry(table_field.table) 544 | .and_modify(|_| unreachable!()) 545 | .or_insert_with(|| table_name.clone()); 546 | 547 | if table_field.recursive { 548 | //recursive need to go inside a box 549 | quote! {Box::new(#table_name)} 550 | } else { 551 | table_name.to_token_stream() 552 | } 553 | }); 554 | let fields = 555 | pattern.produced_token_fields().map(|prod_field| { 556 | let token_field = 557 | disassembler.sleigh.token_field(prod_field.field); 558 | let field_name = format_ident!( 559 | "{}", 560 | from_sleigh(token_field.name()) 561 | ); 562 | produced_token_fields 563 | .entry(prod_field.field) 564 | .and_modify(|_| unreachable!()) 565 | .or_insert_with(|| field_name.clone()); 566 | field_name 567 | }); 568 | let sub_pattern_name = 569 | format_ident!("sub_pattern_c{}", location.start_column()); 570 | Some(quote! { 571 | let mut #sub_pattern_name = #sub_func; 572 | let ( 573 | (#(mut #tables),*), 574 | (#(#fields),*), 575 | sub_len 576 | ) = #sub_pattern_name(#tokens, &mut #context_instance)?; 577 | #block_len = #block_len.max(sub_len); 578 | }) 579 | } 580 | }) 581 | .collect(); 582 | 583 | let fields = sleigh_token_fields 584 | .iter() 585 | .filter(|prod_field| prod_field.local) 586 | .map(|prod_field| { 587 | let token_field = disassembler.sleigh.token_field(prod_field.field); 588 | let token_field_name = 589 | format_ident!("{}", from_sleigh(token_field.name())); 590 | let token_field = 591 | &disassembler.token_field_function(prod_field.field).read; 592 | produced_token_fields 593 | .entry(prod_field.field) 594 | .and_modify(|_| unreachable!()) 595 | .or_insert_with(|| token_field_name.clone()); 596 | quote! { let #token_field_name = #token_field(#tokens); } 597 | }); 598 | 599 | let disassembly = DisassemblyPattern { 600 | disassembler, 601 | context_instance, 602 | inst_start, 603 | root_tables, 604 | root_token_fields, 605 | vars, 606 | tokens, 607 | }; 608 | let disassembly = disassembly.disassembly(&mut pos.iter()); 609 | 610 | quote! { 611 | #verifications 612 | #(#fields)* 613 | #disassembly 614 | } 615 | } 616 | 617 | fn block_or_closure( 618 | constructor: &ConstructorStruct, 619 | _len: &sleigh_rs::pattern::PatternLen, 620 | sleigh_token_fields: &[ProducedTokenField], 621 | sleigh_tables: &[ProducedTable], 622 | branches: &[Verification], 623 | _block_len: &Ident, 624 | inst_start: &Ident, 625 | vars: &mut IndexMap, 626 | root_tables: &IndexMap, 627 | root_token_fields: &IndexMap, 628 | disassembler: &Disassembler, 629 | ) -> TokenStream { 630 | let tokens_param = format_ident!("tokens_param"); 631 | let context_instance = format_ident!("context_param"); 632 | let branches = branches.iter().map(|verification| { 633 | match verification { 634 | Verification::ContextCheck { context, op, value } => { 635 | let verification = context_verification( 636 | false, 637 | *context, 638 | op, 639 | value, 640 | disassembler, 641 | &tokens_param, 642 | &context_instance, 643 | inst_start, 644 | root_token_fields, 645 | ); 646 | let tables = sleigh_tables.iter().map(|table_field| { 647 | if table_field.always { 648 | unreachable!() 649 | } else { 650 | quote! {None} 651 | } 652 | }); 653 | quote! { 654 | if #verification { 655 | return Some(( 656 | (#(#tables),*), 657 | (/*no fields*/), 658 | 0, 659 | )); 660 | } 661 | } 662 | } 663 | Verification::TokenFieldCheck { field, op, value } => { 664 | //generate the token parser, if any 665 | let token_field = disassembler.sleigh.token_field(*field); 666 | let token = disassembler.sleigh.token(token_field.token); 667 | let token_len = token.len_bytes; 668 | 669 | let verification = field_verification( 670 | false, 671 | *field, 672 | op, 673 | value, 674 | disassembler, 675 | &tokens_param, 676 | &context_instance, 677 | inst_start, 678 | root_token_fields, 679 | ); 680 | //token fields is only exported if in the produced list 681 | let token_field_export = match sleigh_token_fields { 682 | [prod] => { 683 | if prod.field == *field 684 | { 685 | let token_field_new = &disassembler 686 | .token_field_function(*field).read; 687 | quote! { #token_field_new(#tokens_param) } 688 | } else { 689 | unreachable!() 690 | } 691 | } 692 | [] => quote! {}, 693 | [..] => { 694 | todo!("implicit field production in or pattern") 695 | } 696 | }; 697 | let tables = sleigh_tables.iter().map(|table_field| { 698 | if table_field.always { 699 | unreachable!() 700 | } else { 701 | quote! {None} 702 | } 703 | }); 704 | let token_len = token_len.get().unsuffixed(); 705 | quote! { 706 | //verify the value, if true, return it 707 | if #verification { 708 | return Some(( 709 | (#(#tables),*), 710 | (#token_field_export), 711 | #token_len, 712 | )); 713 | } 714 | } 715 | } 716 | Verification::SubPattern { location, pattern } => { 717 | let sub_func = sub_pattern_closure( 718 | constructor, 719 | pattern, 720 | inst_start, 721 | vars, 722 | root_tables, 723 | root_token_fields, 724 | disassembler, 725 | ); 726 | let sub_pattern_name = 727 | format_ident!("sub_pattern_c{}", location.start_column()); 728 | let tables: IndexMap<_, _> = pattern 729 | .produced_tables() 730 | .map(|field_table| { 731 | let table = field_table.table; 732 | let table_name = disassembler.sleigh.table(table).name(); 733 | let table_name = format_ident!( 734 | "{}", 735 | from_sleigh(table_name) 736 | ); 737 | (field_table.table, (field_table, table_name)) 738 | }) 739 | .collect(); 740 | let fields: IndexMap<_, _> = pattern 741 | .produced_token_fields() 742 | .map(|field| { 743 | let token_field = disassembler.sleigh.token_field(field.field); 744 | let name = format_ident!( 745 | "{}", 746 | from_sleigh(token_field.name()) 747 | ); 748 | (field.field, name) 749 | }) 750 | .collect(); 751 | let sub_tables = tables.values().map(|(_, name)| name); 752 | let sub_fields = fields.values(); 753 | let tables = sleigh_tables.iter().map(|table_produced| { 754 | //TODO what if the table have multiple levels of Option? 755 | if let Some((table_sub, table_sub_name)) = 756 | tables.get(&table_produced.table) 757 | { 758 | produced_table( 759 | table_sub_name, 760 | table_sub.recursive, 761 | table_sub.always, 762 | table_produced.recursive, 763 | table_produced.always, 764 | ) 765 | } else if table_produced.always { 766 | unreachable!() 767 | } else { 768 | quote! {None} 769 | } 770 | }); 771 | let fields = sleigh_token_fields.iter().map(|field| { 772 | fields.get(&field.field).unwrap() 773 | }); 774 | quote! { 775 | let mut #sub_pattern_name = #sub_func; 776 | let mut context_current = #context_instance.clone(); 777 | if let Some(( 778 | (#(#sub_tables),*), 779 | (#(#sub_fields),*), 780 | sub_pattern_len, 781 | )) = #sub_pattern_name(#tokens_param, &mut context_current) { 782 | *#context_instance = context_current; 783 | return Some(( 784 | (#(#tables),*), 785 | (#(#fields),*), 786 | sub_pattern_len, 787 | )); 788 | } 789 | } 790 | } 791 | Verification::TableBuild { .. } => { 792 | todo!("Table production in Or pattern directly") 793 | } 794 | } 795 | }); 796 | let context_struct = &disassembler.context.name; 797 | quote! { 798 | |#tokens_param: &[u8], #context_instance: &mut #context_struct| { 799 | //used to calculate the current block len 800 | #(#branches)* 801 | None 802 | } 803 | } 804 | } 805 | 806 | fn produced_table( 807 | value: impl ToTokens, 808 | produced_recursive: bool, 809 | produced_always: bool, 810 | output_recursive: bool, 811 | output_always: bool, 812 | ) -> TokenStream { 813 | //if the source is recursive, the output is also recursive 814 | if produced_recursive != output_recursive { 815 | unreachable!(); 816 | } 817 | let mut output = value.to_token_stream(); 818 | if produced_recursive { 819 | //recursive need to go inside a box 820 | output = quote! {Box::new(#output)}; 821 | } 822 | match (produced_always, output_always) { 823 | //source and output both always/sometimes produce 824 | (false, false) | (true, true) => output, 825 | //the source always produce, output sometimes produce 826 | (true, false) => quote! {Some(#output)}, 827 | //the source sometimes produces, output always produce 828 | (false, true) => unreachable!(), 829 | } 830 | } 831 | 832 | fn pattern_cmp_token(value: &sleigh_rs::pattern::CmpOp) -> TokenStream { 833 | match value { 834 | sleigh_rs::pattern::CmpOp::Eq => quote!(==), 835 | sleigh_rs::pattern::CmpOp::Ne => quote!(!=), 836 | sleigh_rs::pattern::CmpOp::Lt => quote!(<), 837 | sleigh_rs::pattern::CmpOp::Gt => quote!(>), 838 | sleigh_rs::pattern::CmpOp::Le => quote!(<=), 839 | sleigh_rs::pattern::CmpOp::Ge => quote!(>=), 840 | } 841 | } 842 | fn pattern_cmp_token_neg(value: &sleigh_rs::pattern::CmpOp) -> TokenStream { 843 | match value { 844 | sleigh_rs::pattern::CmpOp::Eq => quote!(!=), 845 | sleigh_rs::pattern::CmpOp::Ne => quote!(==), 846 | sleigh_rs::pattern::CmpOp::Lt => quote!(>=), 847 | sleigh_rs::pattern::CmpOp::Gt => quote!(<=), 848 | sleigh_rs::pattern::CmpOp::Le => quote!(>), 849 | sleigh_rs::pattern::CmpOp::Ge => quote!(<), 850 | } 851 | } 852 | 853 | fn call_parser( 854 | disassembler: &Disassembler, 855 | context_instance: &Ident, 856 | tokens: &Ident, 857 | inst_start: &Ident, 858 | table: sleigh_rs::TableId, 859 | ) -> TokenStream { 860 | let table = disassembler.table_struct(table); 861 | let table_enum = &table.name; 862 | let table_parser = &table.parse_fun; 863 | quote! { 864 | #table_enum::#table_parser( 865 | #tokens, 866 | &mut #context_instance, 867 | #inst_start, 868 | ) 869 | } 870 | } 871 | 872 | struct BlockParserValuesDisassembly<'a> { 873 | disassembler: &'a Disassembler, 874 | tokens: &'a Ident, 875 | context_instance: &'a Ident, 876 | inst_start: &'a Ident, 877 | produced_fields: &'a IndexMap, 878 | } 879 | //Block parser only use Disassembly for the pattern value, so only value is used 880 | impl DisassemblyGenerator for BlockParserValuesDisassembly<'_> { 881 | fn global_set(&self, _global_set: &GlobalSet) -> TokenStream { 882 | unreachable!() 883 | } 884 | fn value(&self, value: &sleigh_rs::disassembly::ReadScope) -> TokenStream { 885 | use sleigh_rs::disassembly::*; 886 | match value { 887 | ReadScope::Integer(value) => { 888 | value.signed_super().suffixed().into_token_stream() 889 | } 890 | ReadScope::Context(context) => { 891 | let read_call = self 892 | .disassembler 893 | .context 894 | .read_call(*context, self.context_instance); 895 | quote! { #DISASSEMBLY_WORK_TYPE::try_from(#read_call).unwrap()} 896 | } 897 | ReadScope::TokenField(ass) => { 898 | let token_field_value = if let Some(token_field_name) = 899 | self.produced_fields.get(ass) 900 | { 901 | token_field_name.to_token_stream() 902 | } else { 903 | let token_field_new = 904 | &self.disassembler.token_field_function(*ass).read; 905 | let tokens = self.tokens; 906 | quote! { #token_field_new(#tokens) } 907 | }; 908 | let token_field = self.disassembler.sleigh.token_field(*ass); 909 | let token_field_value = 910 | self.disassembler.meanings.disassembly_function_call( 911 | token_field.bits.len().get().try_into().unwrap(), 912 | token_field_value, 913 | token_field.meaning(), 914 | ); 915 | quote! {#DISASSEMBLY_WORK_TYPE::try_from(#token_field_value).unwrap()} 916 | } 917 | ReadScope::InstStart(_) => self.inst_start.to_token_stream(), 918 | ReadScope::InstNext(_) | ReadScope::Local(_) => unreachable!(), 919 | } 920 | } 921 | fn set_context( 922 | &self, 923 | _context: &sleigh_rs::ContextId, 924 | _value: TokenStream, 925 | ) -> TokenStream { 926 | unreachable!() 927 | } 928 | fn new_variable( 929 | &mut self, 930 | _var_id: &disassembly::VariableId, 931 | _var: &disassembly::Variable, 932 | ) -> TokenStream { 933 | unreachable!() 934 | } 935 | fn var_name(&self, _var: &disassembly::VariableId) -> TokenStream { 936 | unreachable!() 937 | } 938 | } 939 | 940 | fn value_disassembly( 941 | value: &ConstraintValue, 942 | disassembler: &Disassembler, 943 | tokens: &Ident, 944 | context_instance: &Ident, 945 | inst_start: &Ident, 946 | produced_fields: &IndexMap, 947 | ) -> TokenStream { 948 | BlockParserValuesDisassembly { 949 | disassembler, 950 | context_instance, 951 | inst_start, 952 | produced_fields, 953 | tokens, 954 | } 955 | .expr(value.expr()) 956 | } 957 | 958 | fn verification( 959 | inverted: bool, 960 | field: TokenStream, 961 | op: &sleigh_rs::pattern::CmpOp, 962 | value: &ConstraintValue, 963 | disassembler: &Disassembler, 964 | tokens: &Ident, 965 | context_instance: &Ident, 966 | inst_start: &Ident, 967 | produced_fields: &IndexMap, 968 | ) -> TokenStream { 969 | let cons_op = if inverted { 970 | pattern_cmp_token_neg(op) 971 | } else { 972 | pattern_cmp_token(op) 973 | }; 974 | match value.expr().elements() { 975 | // if the value is a simple number, just compare it directly 976 | [disassembly::ExprElement::Value { 977 | value: disassembly::ReadScope::Integer(number), 978 | location: _, 979 | }] => { 980 | let value = number.unsuffixed(); 981 | quote! {#field #cons_op #value} 982 | } 983 | //otherwise make a full disassembly and compare it 984 | _ => { 985 | let value = value_disassembly( 986 | value, 987 | disassembler, 988 | tokens, 989 | context_instance, 990 | inst_start, 991 | produced_fields, 992 | ); 993 | quote! { #DISASSEMBLY_WORK_TYPE::try_from(#field).unwrap() #cons_op #value } 994 | } 995 | } 996 | } 997 | 998 | fn field_verification( 999 | inverted: bool, 1000 | field: sleigh_rs::TokenFieldId, 1001 | op: &sleigh_rs::pattern::CmpOp, 1002 | value: &ConstraintValue, 1003 | disassembler: &Disassembler, 1004 | tokens: &Ident, 1005 | context_instance: &Ident, 1006 | inst_start: &Ident, 1007 | produced_fields: &IndexMap, 1008 | ) -> TokenStream { 1009 | let token_field_new = &disassembler.token_field_function(field).read; 1010 | let field = quote! {#token_field_new(#tokens)}; 1011 | verification( 1012 | inverted, 1013 | field, 1014 | op, 1015 | value, 1016 | disassembler, 1017 | tokens, 1018 | context_instance, 1019 | inst_start, 1020 | produced_fields, 1021 | ) 1022 | } 1023 | 1024 | fn context_verification( 1025 | inverted: bool, 1026 | context: sleigh_rs::ContextId, 1027 | op: &sleigh_rs::pattern::CmpOp, 1028 | value: &ConstraintValue, 1029 | disassembler: &Disassembler, 1030 | tokens: &Ident, 1031 | context_instance: &Ident, 1032 | inst_start: &Ident, 1033 | produced_fields: &IndexMap, 1034 | ) -> TokenStream { 1035 | let field = disassembler.context.read_call(context, context_instance); 1036 | verification( 1037 | inverted, 1038 | field, 1039 | op, 1040 | value, 1041 | disassembler, 1042 | tokens, 1043 | context_instance, 1044 | inst_start, 1045 | produced_fields, 1046 | ) 1047 | } 1048 | --------------------------------------------------------------------------------