├── .gitignore ├── .rustfmt.toml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── annotations └── pattern_lens.svg └── src ├── lib.rs ├── preprocessor ├── ifs.rs ├── macros.rs ├── mod.rs ├── parser.rs └── token.rs ├── semantic ├── disassembly.rs ├── display.rs ├── execution.rs ├── inner │ ├── attach.rs │ ├── disassembly.rs │ ├── display.rs │ ├── execution │ │ ├── assignment.rs │ │ ├── block.rs │ │ ├── builder.rs │ │ ├── cpu_branch.rs │ │ ├── export.rs │ │ ├── expr.rs │ │ ├── len.rs │ │ ├── local_goto.rs │ │ ├── mod.rs │ │ ├── op.rs │ │ ├── user_call.rs │ │ └── variables.rs │ ├── mod.rs │ ├── pattern │ │ ├── block.rs │ │ ├── constraint.rs │ │ ├── mod.rs │ │ ├── pattern_len.rs │ │ └── verification.rs │ ├── pcode_macro.rs │ ├── space.rs │ ├── table │ │ ├── execution.rs │ │ └── mod.rs │ ├── token.rs │ ├── varnode.rs │ └── with_block.rs ├── meaning.rs ├── mod.rs ├── pattern.rs ├── space.rs ├── table.rs ├── token.rs ├── user_function.rs └── varnode.rs └── syntax ├── attach.rs ├── block ├── disassembly.rs ├── display.rs ├── execution │ ├── assignment.rs │ ├── branch.rs │ ├── export.rs │ ├── expr.rs │ ├── mod.rs │ └── op.rs ├── mod.rs ├── pattern.rs ├── pcode_macro.rs ├── table.rs └── with_block.rs ├── define ├── alignment.rs ├── bitrange.rs ├── context.rs ├── mod.rs ├── space.rs ├── token.rs ├── user_function.rs └── varnode.rs ├── mod.rs └── parser.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 80 2 | -------------------------------------------------------------------------------- /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 = "memchr" 7 | version = "2.4.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 10 | 11 | [[package]] 12 | name = "minimal-lexical" 13 | version = "0.2.1" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 16 | 17 | [[package]] 18 | name = "nom" 19 | version = "7.1.1" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" 22 | dependencies = [ 23 | "memchr", 24 | "minimal-lexical", 25 | ] 26 | 27 | [[package]] 28 | name = "once_cell" 29 | version = "1.19.0" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 32 | 33 | [[package]] 34 | name = "pin-project-lite" 35 | version = "0.2.13" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 38 | 39 | [[package]] 40 | name = "proc-macro2" 41 | version = "1.0.78" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" 44 | dependencies = [ 45 | "unicode-ident", 46 | ] 47 | 48 | [[package]] 49 | name = "quote" 50 | version = "1.0.35" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 53 | dependencies = [ 54 | "proc-macro2", 55 | ] 56 | 57 | [[package]] 58 | name = "sleigh-rs" 59 | version = "0.1.5" 60 | dependencies = [ 61 | "nom", 62 | "thiserror", 63 | "tracing", 64 | ] 65 | 66 | [[package]] 67 | name = "syn" 68 | version = "1.0.89" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" 71 | dependencies = [ 72 | "proc-macro2", 73 | "quote", 74 | "unicode-xid", 75 | ] 76 | 77 | [[package]] 78 | name = "syn" 79 | version = "2.0.52" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" 82 | dependencies = [ 83 | "proc-macro2", 84 | "quote", 85 | "unicode-ident", 86 | ] 87 | 88 | [[package]] 89 | name = "thiserror" 90 | version = "1.0.30" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 93 | dependencies = [ 94 | "thiserror-impl", 95 | ] 96 | 97 | [[package]] 98 | name = "thiserror-impl" 99 | version = "1.0.30" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 102 | dependencies = [ 103 | "proc-macro2", 104 | "quote", 105 | "syn 1.0.89", 106 | ] 107 | 108 | [[package]] 109 | name = "tracing" 110 | version = "0.1.40" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 113 | dependencies = [ 114 | "pin-project-lite", 115 | "tracing-attributes", 116 | "tracing-core", 117 | ] 118 | 119 | [[package]] 120 | name = "tracing-attributes" 121 | version = "0.1.27" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 124 | dependencies = [ 125 | "proc-macro2", 126 | "quote", 127 | "syn 2.0.52", 128 | ] 129 | 130 | [[package]] 131 | name = "tracing-core" 132 | version = "0.1.32" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 135 | dependencies = [ 136 | "once_cell", 137 | ] 138 | 139 | [[package]] 140 | name = "unicode-ident" 141 | version = "1.0.12" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 144 | 145 | [[package]] 146 | name = "unicode-xid" 147 | version = "0.2.2" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 150 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "sleigh-rs" 4 | version = "0.1.5" 5 | readme = "README.md" 6 | repository = "https://github.com/rbran/sleigh-rs" 7 | license = "MIT" 8 | description = "Ghidra Sleigh parser" 9 | 10 | [features] 11 | thread = [] 12 | # don't allow any overflow in inline operations 13 | no_overflow_inline = [] 14 | 15 | [dependencies] 16 | nom = "7" 17 | thiserror = "1" 18 | tracing = "0.1.40" 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Sleigh-rs 2 | 3 | This project is a Ghidra Sleigh parser. 4 | 5 | The project is unfinished, and is not ready for use. 6 | 7 | For an example on how this lib can be used, checkout 8 | [sleigh2rust](https://github.com/rbran/sleigh2rust) and [sleigh3rust](https://github.com/rbran/sleigh3rust). 9 | 10 | ## Ghidra Sleigh 11 | 12 | The Sleigh language used by Ghidra, describes CPU instructions sets, 13 | designed to facilitate the reverse-engineering and and emulate cpu architectures. 14 | 15 | ## TODO 16 | 17 | * Unit tests. 18 | * Implement the final version of the instruction execution parser. 19 | 20 | -------------------------------------------------------------------------------- /src/preprocessor/ifs.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::bytes::complete::tag; 3 | use nom::character::complete::{line_ending, space0}; 4 | use nom::combinator::{map, peek, value}; 5 | use nom::sequence::{delimited, pair, preceded, terminated, tuple}; 6 | use nom::IResult; 7 | 8 | use super::parser::{end_of_line, ident, string}; 9 | 10 | #[derive(Debug, Eq, PartialEq, Clone)] 11 | pub enum IfCheckOwned { 12 | Defined(String), 13 | NotDefined(String), 14 | Cmp { 15 | name: String, 16 | op: CmpOp, 17 | value: String, 18 | }, 19 | Op { 20 | left: Box, 21 | op: BoolOp, 22 | right: Box, 23 | }, 24 | } 25 | 26 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] 27 | pub enum CmpOp { 28 | Eq, 29 | Ne, 30 | } 31 | 32 | impl CmpOp { 33 | pub fn cmp(&self, op1: &str, op2: &str) -> bool { 34 | match self { 35 | CmpOp::Eq => op1 == op2, 36 | CmpOp::Ne => op1 != op2, 37 | } 38 | } 39 | } 40 | 41 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] 42 | pub enum BoolOp { 43 | And, 44 | Or, 45 | Xor, 46 | } 47 | 48 | impl BoolOp { 49 | //TODO make the verification lazy, so we can short circuit this 50 | pub fn check(&self, cond1: bool, cond2: bool) -> bool { 51 | match self { 52 | BoolOp::And => cond1 && cond2, 53 | BoolOp::Or => cond1 || cond2, 54 | BoolOp::Xor => cond1 ^ cond2, 55 | } 56 | } 57 | } 58 | 59 | fn bool_op(input: &str) -> IResult<&str, BoolOp> { 60 | alt(( 61 | value(BoolOp::Or, tag("||")), 62 | value(BoolOp::And, tag("&&")), 63 | value(BoolOp::Xor, tag("^^")), 64 | ))(input) 65 | } 66 | 67 | pub(crate) fn if_cond_check(input: &str) -> IResult<&str, IfCheckOwned> { 68 | alt(( 69 | map( 70 | tuple(( 71 | map(ident, |x| x.to_owned()), 72 | delimited( 73 | space0, 74 | alt(( 75 | value(CmpOp::Eq, tag("==")), 76 | value(CmpOp::Ne, tag("!=")), 77 | )), 78 | space0, 79 | ), 80 | string, 81 | )), 82 | |(name, op, value)| IfCheckOwned::Cmp { name, op, value }, 83 | ), 84 | map( 85 | preceded( 86 | pair(tag("defined"), space0), 87 | delimited(tag("("), map(ident, |x| x.to_owned()), tag(")")), 88 | ), 89 | IfCheckOwned::Defined, 90 | ), 91 | //if `(` then call recursive 92 | preceded(tag("("), if_cond_not_root), 93 | ))(input) 94 | } 95 | 96 | //TODO: improve this 97 | pub(crate) fn if_cond(input: &str) -> IResult<&str, IfCheckOwned> { 98 | map( 99 | pair( 100 | terminated(if_cond_check, space0), 101 | alt(( 102 | // end of the if, only if we are root and not recursive 103 | map(pair(end_of_line, peek(line_ending)), |_| None), 104 | map( 105 | pair(terminated(bool_op, space0), if_cond), 106 | |(op, cond2)| Some((op, cond2)), 107 | ), 108 | )), 109 | ), 110 | |(cond1, rest)| match rest { 111 | Some((op, cond2)) => IfCheckOwned::Op { 112 | op, 113 | left: Box::new(cond1), 114 | right: Box::new(cond2), 115 | }, 116 | None => cond1, 117 | }, 118 | )(input) 119 | } 120 | 121 | pub(crate) fn if_cond_not_root(input: &str) -> IResult<&str, IfCheckOwned> { 122 | map( 123 | pair( 124 | terminated(if_cond_check, space0), 125 | alt(( 126 | map( 127 | pair(terminated(bool_op, space0), if_cond_not_root), 128 | |(op, cond2)| Some((op, cond2)), 129 | ), 130 | // if ')' mean end of this recursice, only happen if not root 131 | map(tag(")"), |_| None), 132 | )), 133 | ), 134 | |(cond1, rest)| match rest { 135 | Some((op, cond2)) => IfCheckOwned::Op { 136 | op, 137 | left: Box::new(cond1), 138 | right: Box::new(cond2), 139 | }, 140 | None => cond1, 141 | }, 142 | )(input) 143 | } 144 | -------------------------------------------------------------------------------- /src/preprocessor/macros.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::bytes::complete::tag; 3 | use nom::character::complete::{space0, space1}; 4 | use nom::combinator::{map, opt, recognize, value}; 5 | use nom::sequence::{delimited, pair, preceded}; 6 | use nom::IResult; 7 | 8 | use super::ifs::{if_cond, IfCheckOwned}; 9 | use super::parser::{end_of_line, ident, number, string}; 10 | use super::{ 11 | MACRO_DEFINE, MACRO_ELIF, MACRO_ELSE, MACRO_ENDIF, MACRO_IF, MACRO_IFDEF, 12 | MACRO_IFNDEF, MACRO_INCLUDE, MACRO_UNDEFINE, 13 | }; 14 | 15 | pub(crate) fn expansion(input: &str) -> IResult<&str, &str> { 16 | delimited(pair(tag("$("), space0), ident, pair(space0, tag(")")))(input) 17 | } 18 | 19 | #[derive(Debug, Eq, PartialEq, Clone)] 20 | pub enum DefineDataOwned { 21 | Alias(String), 22 | Value(String), 23 | } 24 | impl DefineDataOwned { 25 | fn parse(input: &str) -> IResult<&str, Self> { 26 | alt(( 27 | map(ident, |ident| Self::Alias(ident.to_owned())), 28 | //TODO number to string? What about a Number type??? 29 | map( 30 | alt((string, map(recognize(number), str::to_string))), 31 | Self::Value, 32 | ), 33 | ))(input) 34 | } 35 | } 36 | 37 | #[derive(Debug, Eq, PartialEq, Clone)] 38 | pub enum MacroLine { 39 | Define { 40 | name: String, 41 | value: Option, 42 | }, 43 | Undefine(String), 44 | Include(String), 45 | If(IfCheckOwned), 46 | ElIf(IfCheckOwned), 47 | Else, 48 | EndIf, 49 | } 50 | impl MacroLine { 51 | pub fn parse_define(input: &str) -> IResult<&str, Self> { 52 | map( 53 | delimited( 54 | pair(tag(MACRO_DEFINE), space1), 55 | pair(ident, opt(preceded(space1, DefineDataOwned::parse))), 56 | end_of_line, 57 | ), 58 | |(name, value)| Self::Define { 59 | name: name.to_owned(), 60 | value, 61 | }, 62 | )(input) 63 | } 64 | fn parse_undefine(input: &str) -> IResult<&str, Self> { 65 | map( 66 | delimited(pair(tag(MACRO_UNDEFINE), space1), ident, end_of_line), 67 | |x| Self::Undefine(x.to_owned()), 68 | )(input) 69 | } 70 | fn parse_include(input: &str) -> IResult<&str, Self> { 71 | map( 72 | delimited(pair(tag(MACRO_INCLUDE), space0), string, end_of_line), 73 | |x| Self::Include(x.to_owned()), 74 | )(input) 75 | } 76 | fn parse_if(input: &str) -> IResult<&str, Self> { 77 | map(preceded(pair(tag(MACRO_IF), space1), if_cond), Self::If)(input) 78 | } 79 | fn parse_ifdef(input: &str) -> IResult<&str, Self> { 80 | map( 81 | delimited(pair(tag(MACRO_IFDEF), space1), ident, end_of_line), 82 | |x| Self::If(IfCheckOwned::Defined(x.to_owned())), 83 | )(input) 84 | } 85 | fn parse_ifndef(input: &str) -> IResult<&str, Self> { 86 | map( 87 | delimited(pair(tag(MACRO_IFNDEF), space1), ident, end_of_line), 88 | |x| Self::If(IfCheckOwned::NotDefined(x.to_owned())), 89 | )(input) 90 | } 91 | fn parse_elif(input: &str) -> IResult<&str, Self> { 92 | map(preceded(pair(tag(MACRO_ELIF), space1), if_cond), Self::ElIf)(input) 93 | } 94 | fn parse_else(input: &str) -> IResult<&str, Self> { 95 | value(Self::Else, pair(tag(MACRO_ELSE), end_of_line))(input) 96 | } 97 | fn parse_endif(input: &str) -> IResult<&str, Self> { 98 | value(Self::EndIf, pair(tag(MACRO_ENDIF), end_of_line))(input) 99 | } 100 | pub fn parse(input: &str) -> IResult<&str, Self> { 101 | preceded( 102 | space0, 103 | alt(( 104 | Self::parse_define, 105 | Self::parse_undefine, 106 | Self::parse_include, 107 | Self::parse_if, 108 | Self::parse_ifdef, 109 | Self::parse_ifndef, 110 | Self::parse_elif, 111 | Self::parse_else, 112 | Self::parse_endif, 113 | )), 114 | )(input) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/preprocessor/parser.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::bytes::complete::{tag, take_while, take_while1}; 3 | use nom::character::complete::{ 4 | digit1, hex_digit1, not_line_ending, satisfy, space0, 5 | }; 6 | use nom::combinator::{eof, map, map_res, opt, recognize, value}; 7 | use nom::sequence::{delimited, pair, preceded, tuple}; 8 | use nom::{AsChar, IResult, InputIter, InputTake}; 9 | 10 | use crate::NumberUnsigned; 11 | 12 | #[macro_export] 13 | macro_rules! parse_or_else { 14 | ( , ) => { 15 | compile_error!(); 16 | }; 17 | ($parser:expr, $input:expr $(,)?) => { 18 | match $parser($input) { 19 | Ok((input, value)) => { 20 | $input = input; 21 | Some(value) 22 | } 23 | Err(x @ nom::Err::Failure(_)) => return Err(x), 24 | Err(nom::Err::Error(_)) => None, 25 | Err(nom::Err::Incomplete(_)) => unreachable!(), 26 | } 27 | }; 28 | } 29 | 30 | pub fn is_ident_first(c: char) -> bool { 31 | c.is_ascii_alphabetic() || c == '_' || c == '.' 32 | } 33 | 34 | pub fn is_ident_middle(c: char) -> bool { 35 | is_ident_first(c) || c.is_ascii_digit() 36 | } 37 | 38 | pub(crate) fn ident(input: &str) -> IResult<&str, &str> { 39 | recognize(pair( 40 | take_while1(is_ident_first), 41 | take_while(is_ident_middle), 42 | ))(input) 43 | } 44 | //TODO octal, hex and unicode code escape 45 | fn in_quotes(buf: &str) -> IResult<&str, String> { 46 | let mut ret = String::new(); 47 | let mut skip_delimiter = false; 48 | for (i, ch) in buf.iter_indices() { 49 | //TODO expand \n, \t, etc? 50 | let ch = ch.as_char(); 51 | if ch == '\\' && !skip_delimiter { 52 | skip_delimiter = true; 53 | } else if ch == '"' && !skip_delimiter { 54 | return Ok((buf.take_split(i).0, ret)); 55 | } else { 56 | ret.push(ch.as_char()); 57 | skip_delimiter = false; 58 | } 59 | } 60 | Err(nom::Err::Error(nom::error::Error { 61 | input: buf, 62 | code: nom::error::ErrorKind::Fix, 63 | })) 64 | } 65 | pub(crate) fn string(input: &str) -> IResult<&str, String> { 66 | delimited(tag("\""), in_quotes, tag("\""))(input) 67 | } 68 | 69 | fn number_unsig_hex(input: &str) -> IResult<&str, NumberUnsigned> { 70 | map_res(preceded(tag("0x"), hex_digit1), |x: &str| { 71 | NumberUnsigned::from_str_radix(x, 16) 72 | })(input) 73 | } 74 | fn number_unsig_bin(input: &str) -> IResult<&str, NumberUnsigned> { 75 | map_res( 76 | preceded(tag("0b"), take_while1(|c| matches!(c, '0' | '1'))), 77 | |x| NumberUnsigned::from_str_radix(x, 2), 78 | )(input) 79 | } 80 | fn number_unsig_dec(input: &str) -> IResult<&str, NumberUnsigned> { 81 | map_res(digit1, |x| NumberUnsigned::from_str_radix(x, 10))(input) 82 | } 83 | pub fn number(input: &str) -> IResult<&str, NumberUnsigned> { 84 | alt((number_unsig_hex, number_unsig_bin, number_unsig_dec))(input) 85 | } 86 | 87 | pub(crate) fn comment(input: &str) -> IResult<&str, &str> { 88 | recognize(pair(tag("#"), not_line_ending))(input) 89 | } 90 | 91 | //TODO delete the others and rename this 92 | pub(crate) fn empty_space0(input: &str) -> IResult<&str, &str> { 93 | recognize(pair(space0, opt(comment)))(input) 94 | } 95 | 96 | pub(crate) fn end_of_line(input: &str) -> IResult<&str, &str> { 97 | recognize(tuple((opt(space0), opt(comment))))(input) 98 | } 99 | 100 | #[derive(Clone, Debug)] 101 | pub enum Display { 102 | End, 103 | Concat, 104 | Ident(String), 105 | Other(char), 106 | Literal(String), 107 | } 108 | //Never fails, IResult only for convenience 109 | pub fn display_token(input: &str) -> IResult<&str, Option> { 110 | alt(( 111 | value(Some(Display::Concat), tag("^")), 112 | map(string, |string| Some(Display::Literal(string))), 113 | map(ident, |ident| match ident { 114 | "is" => Some(Display::End), 115 | x => Some(Display::Ident(x.to_owned())), 116 | }), 117 | // if something else, just consume it until a possible ident is found 118 | map( 119 | satisfy(|c| !c.is_ascii_control() || c.is_whitespace()), 120 | |x| Some(Display::Other(x)), 121 | ), 122 | value(None, eof), 123 | ))(input) 124 | } 125 | -------------------------------------------------------------------------------- /src/preprocessor/token.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::bytes::complete::tag; 3 | use nom::combinator::map; 4 | use nom::combinator::value; 5 | use nom::IResult; 6 | 7 | use crate::preprocessor::parser::ident; 8 | use crate::NumberUnsigned; 9 | 10 | use super::parser::{number, string}; 11 | use super::Span; 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct Token { 15 | pub location: Span, 16 | pub token_type: TokenType, 17 | } 18 | impl Token { 19 | pub(crate) fn new(location: Span, token_type: TokenType) -> Self { 20 | Self { 21 | location, 22 | token_type, 23 | } 24 | } 25 | } 26 | 27 | #[derive(Debug, Clone, PartialEq, Eq)] 28 | pub enum TokenType { 29 | OpNotequal, 30 | OpBoolAnd, 31 | OpLeft, 32 | OpLessequal, 33 | OpEqual, 34 | OpGreatequal, 35 | OpRight, 36 | OpBoolXor, 37 | OpBoolOr, 38 | OpAbs, 39 | OpBorrow, 40 | CallKey, 41 | OpCarry, 42 | OpCeil, 43 | OpFnotequal, 44 | OpFmult, 45 | OpFadd, 46 | OpFsub, 47 | OpFdiv, 48 | OpFless, 49 | OpFlessequal, 50 | OpFequal, 51 | OpFgreat, 52 | OpFgreatequal, 53 | OpFloat2float, 54 | OpFloatSqrt, 55 | OpFloor, 56 | GotoKey, 57 | IfKey, 58 | OpInt2float, 59 | LocalKey, 60 | OpNan, 61 | ReturnKey, 62 | OpPopcount, 63 | OpLzcount, 64 | OpRound, 65 | OpSrem, 66 | OpSdiv, 67 | OpSless, 68 | OpSlessequal, 69 | OpSgreat, 70 | OpSgreatequal, 71 | OpSright, 72 | OpSborrow, 73 | OpScarry, 74 | OpSext, 75 | OpTrunc, 76 | OpZext, 77 | OpGreat, 78 | OpLess, 79 | OpXor, 80 | OpAnd, 81 | OpOr, 82 | OpNeg, 83 | OpBitNeg, 84 | OpAdd, 85 | OpSub, 86 | OpMul, 87 | OpDiv, 88 | OpRem, 89 | OpAssign, 90 | DeliOpenParenteses, 91 | DeliCloseParenteses, 92 | DeliOpenBrackets, 93 | DeliCloseBrackets, 94 | DeliOpenCurly, 95 | DeliCloseCurly, 96 | Comma, 97 | DubleDot, 98 | StatementEnd, 99 | Ellipsis, 100 | Unimpl, 101 | SpaceConst, 102 | SpaceUnique, 103 | Underline, 104 | Number(NumberUnsigned), 105 | String(String), 106 | Ident(String), 107 | } 108 | impl TokenType { 109 | pub fn parse(data: &str) -> IResult<&str, Self> { 110 | //NOTE order is important, otherwise a `<<` could be consumed as two `<` 111 | //NOTE at the time of writing alt only allow tuples with 21 elements 112 | alt(( 113 | map(number, Self::Number), 114 | // logic op for disassembly 115 | alt(( 116 | value(Self::OpBoolAnd, tag("$and")), 117 | value(Self::OpBoolXor, tag("$xor")), 118 | value(Self::OpBoolOr, tag("$or")), 119 | )), 120 | // float operations 121 | alt(( 122 | //3 chars 123 | value(Self::OpFnotequal, tag("f!=")), 124 | value(Self::OpFlessequal, tag("f<=")), 125 | value(Self::OpFequal, tag("f==")), 126 | value(Self::OpFgreatequal, tag("f>=")), 127 | //2 chars 128 | value(Self::OpFmult, tag("f*")), 129 | value(Self::OpFadd, tag("f+")), 130 | value(Self::OpFsub, tag("f-")), 131 | value(Self::OpFdiv, tag("f/")), 132 | value(Self::OpFless, tag("f<")), 133 | value(Self::OpFgreat, tag("f>")), 134 | )), 135 | // signed operations 136 | alt(( 137 | //3 chars 138 | value(Self::OpSlessequal, tag("s<=")), 139 | value(Self::OpSgreatequal, tag("s>=")), 140 | value(Self::OpSright, tag("s>>")), 141 | //2 chars 142 | value(Self::OpSrem, tag("s%")), 143 | value(Self::OpSdiv, tag("s/")), 144 | value(Self::OpSless, tag("s<")), 145 | value(Self::OpSgreat, tag("s>")), 146 | )), 147 | // other operations, 2 chars 148 | alt(( 149 | //2 chars 150 | value(Self::OpNotequal, tag("!=")), 151 | value(Self::OpLeft, tag("<<")), 152 | value(Self::OpLessequal, tag("<=")), 153 | value(Self::OpEqual, tag("==")), 154 | value(Self::OpGreatequal, tag(">=")), 155 | value(Self::OpRight, tag(">>")), 156 | value(Self::OpBoolAnd, tag("&&")), 157 | value(Self::OpBoolXor, tag("^^")), 158 | value(Self::OpBoolOr, tag("||")), 159 | )), 160 | // other operations, 1 char 161 | alt(( 162 | value(Self::OpGreat, tag(">")), 163 | value(Self::OpLess, tag("<")), 164 | value(Self::OpXor, tag("^")), 165 | value(Self::OpAnd, tag("&")), 166 | value(Self::OpOr, tag("|")), 167 | value(Self::OpNeg, tag("~")), 168 | value(Self::OpBitNeg, tag("!")), 169 | value(Self::OpAdd, tag("+")), 170 | value(Self::OpSub, tag("-")), 171 | value(Self::OpMul, tag("*")), 172 | value(Self::OpDiv, tag("/")), 173 | value(Self::OpRem, tag("%")), 174 | value(Self::OpAssign, tag("=")), 175 | )), 176 | //other other 177 | alt(( 178 | value(Self::DeliOpenParenteses, tag("(")), 179 | value(Self::DeliCloseParenteses, tag(")")), 180 | value(Self::DeliOpenBrackets, tag("[")), 181 | value(Self::DeliCloseBrackets, tag("]")), 182 | value(Self::DeliOpenCurly, tag("{")), 183 | value(Self::DeliCloseCurly, tag("}")), 184 | value(Self::Comma, tag(",")), 185 | value(Self::DubleDot, tag(":")), 186 | value(Self::StatementEnd, tag(";")), 187 | value(Self::Ellipsis, tag("...")), 188 | )), 189 | map(string, Self::String), 190 | Self::parse_words, 191 | ))(data) 192 | } 193 | fn parse_words(input: &str) -> IResult<&str, Self> { 194 | use TokenType::*; 195 | let (rest, name) = alt((ident, tag("_")))(input)?; 196 | #[rustfmt::skip] 197 | let token = match name { 198 | "_" => Underline, 199 | //reserved keywords 200 | "if" => IfKey, 201 | "abs" => OpAbs, 202 | "nan" => OpNan, 203 | "call" => CallKey, 204 | "ceil" => OpCeil, 205 | "goto" => GotoKey, 206 | "sqrt" => OpFloatSqrt, 207 | "sext" => OpSext, 208 | "zext" => OpZext, 209 | "const" => SpaceConst, 210 | "trunc" => OpTrunc, 211 | "carry" => OpCarry, 212 | "floor" => OpFloor, 213 | "local" => LocalKey, 214 | "round" => OpRound, 215 | "unimpl" => Unimpl, 216 | "unique" => SpaceUnique, 217 | "return" => ReturnKey, 218 | "scarry" => OpScarry, 219 | "borrow" => OpBorrow, 220 | "sborrow" => OpSborrow, 221 | "popcount" => OpPopcount, 222 | "lzcount" => OpLzcount, 223 | "int2float" => OpInt2float, 224 | "float2float" => OpFloat2float, 225 | //Generic Ident 226 | other => Ident(other.to_owned()), 227 | }; 228 | Ok((rest, token)) 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/semantic/disassembly.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::{ 2 | ContextId, InstNext, InstStart, Span, TableId, TokenFieldId, 3 | }; 4 | use crate::{Number, NumberUnsigned}; 5 | 6 | #[derive(Clone, Debug, Copy)] 7 | pub enum OpUnary { 8 | Negation, 9 | Negative, 10 | } 11 | 12 | #[derive(Clone, Debug, Copy, PartialEq, Eq)] 13 | pub enum Op { 14 | Add, 15 | Sub, 16 | Mul, 17 | Div, 18 | And, 19 | Or, 20 | Xor, 21 | Asr, 22 | Lsl, 23 | } 24 | 25 | #[derive(Clone, Copy, Debug)] 26 | pub enum ReadScope { 27 | //TODO: table??? Handle tables that the execution is just export Disassembly 28 | //Table(TableId), 29 | Integer(Number), 30 | Context(ContextId), 31 | TokenField(TokenFieldId), 32 | InstStart(InstStart), 33 | InstNext(InstNext), 34 | Local(VariableId), 35 | } 36 | 37 | #[derive(Clone, Debug)] 38 | pub enum WriteScope { 39 | Context(ContextId), 40 | Local(VariableId), 41 | } 42 | 43 | #[derive(Clone, Debug)] 44 | pub enum AddrScope { 45 | Integer(NumberUnsigned), 46 | Table(TableId), 47 | //Varnode(VarnodeId), 48 | //TokenField(TokenFieldId), 49 | InstStart(InstStart), 50 | InstNext(InstNext), 51 | Local(VariableId), 52 | } 53 | 54 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 55 | pub struct VariableId(pub usize); 56 | 57 | #[derive(Clone, Debug)] 58 | pub struct Variable { 59 | pub(crate) name: Box, 60 | pub location: Span, 61 | // TODO: a disassembly variable could have a defined len, defined by the export 62 | //pub value_type: Cell, 63 | } 64 | 65 | impl Variable { 66 | pub fn name(&self) -> &str { 67 | &self.name 68 | } 69 | } 70 | 71 | #[derive(Clone, Debug)] 72 | pub enum Expr { 73 | Value(ExprElement), 74 | Op(Span, Op, Box, Box), 75 | } 76 | 77 | #[derive(Clone, Debug)] 78 | pub enum ExprElement { 79 | Value { value: ReadScope, location: Span }, 80 | Op(Span, OpUnary, Box), 81 | } 82 | 83 | #[derive(Clone, Debug)] 84 | pub struct GlobalSet { 85 | pub location: Span, 86 | pub address: AddrScope, 87 | pub context: ContextId, 88 | } 89 | 90 | #[derive(Clone, Debug)] 91 | pub struct Assignment { 92 | pub left: WriteScope, 93 | pub right: Expr, 94 | } 95 | 96 | #[derive(Clone, Debug)] 97 | pub enum Assertation { 98 | GlobalSet(GlobalSet), 99 | Assignment(Assignment), 100 | } 101 | -------------------------------------------------------------------------------- /src/semantic/display.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::{ 2 | disassembly, ContextId, InstNext, InstStart, TableId, TokenFieldId, 3 | VarnodeId, 4 | }; 5 | 6 | #[derive(Clone, Debug, Default)] 7 | pub struct Display { 8 | pub mneumonic: Option, 9 | pub(crate) elements: Box<[DisplayElement]>, 10 | } 11 | 12 | impl Display { 13 | pub fn elements(&self) -> impl Iterator { 14 | self.elements.iter() 15 | } 16 | } 17 | 18 | #[derive(Clone, Debug)] 19 | pub enum DisplayElement { 20 | Varnode(VarnodeId), 21 | Context(ContextId), 22 | //Bitrange(BitrangeId), 23 | TokenField(TokenFieldId), 24 | InstStart(InstStart), 25 | InstNext(InstNext), 26 | Table(TableId), 27 | Disassembly(disassembly::VariableId), 28 | Literal(String), 29 | Space, 30 | } 31 | 32 | impl DisplayElement { 33 | pub fn is_space(&self) -> bool { 34 | matches!(self, Self::Space) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/semantic/inner/attach.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::meaning::{ 2 | AttachLiteral, AttachNumber, AttachVarnode, Meaning, 3 | }; 4 | use crate::semantic::{ 5 | AttachLiteralId, AttachNumberId, AttachVarnodeId, PrintBase, VarnodeId, 6 | }; 7 | use crate::{syntax, SleighError, Span}; 8 | 9 | use super::{GlobalScope, Sleigh}; 10 | 11 | impl Sleigh { 12 | fn attach_meaning_fields( 13 | &mut self, 14 | fields: Vec<(String, Span)>, 15 | meaning: Meaning, 16 | ) -> Result<(), Box> { 17 | for (field_name, field_src) in fields.into_iter() { 18 | match self.get_global(&field_name) { 19 | Some(GlobalScope::TokenField(token_field)) => { 20 | let token_field = self.token_field_mut(token_field); 21 | token_field.attach(meaning)?; 22 | } 23 | Some(GlobalScope::Context(context)) => { 24 | let context = self.context_mut(context); 25 | context.attach(meaning)?; 26 | } 27 | _ => { 28 | return Err(Box::new(SleighError::AttachInvalidVariable( 29 | field_src.clone(), 30 | ))) 31 | } 32 | } 33 | } 34 | Ok(()) 35 | } 36 | pub fn attach_meaning( 37 | &mut self, 38 | attach: syntax::attach::Attach, 39 | ) -> Result<(), Box> { 40 | let syntax::attach::Attach { 41 | src, 42 | fields, 43 | meaning, 44 | } = attach; 45 | match meaning { 46 | syntax::attach::Meaning::Variable(input_vars) => { 47 | let vars: Box<[(usize, VarnodeId)]> = input_vars 48 | .into_iter() 49 | .enumerate() 50 | .filter_map(|(i, (name, s))| Some((i, name?, s))) 51 | .map( 52 | |(index, var_name, var_src)| -> Result<_, Box> { 53 | let var_id = self 54 | .get_global(&var_name) 55 | .ok_or_else(|| { 56 | Box::new(SleighError::VarnodeUndefined( 57 | var_src.clone(), 58 | )) 59 | })? 60 | .varnode() 61 | .ok_or_else(|| { 62 | Box::new(SleighError::VarnodeInvalid(var_src.clone())) 63 | })?; 64 | Ok((index, var_id)) 65 | }, 66 | ) 67 | .collect::>()?; 68 | // all varnodes need to have the same size 69 | let mut var_iter = 70 | vars.iter().map(|(_i, var)| self.varnode(*var).len_bytes); 71 | let varnode_len = var_iter.next().unwrap(); 72 | for var in var_iter { 73 | if var != varnode_len { 74 | return Err(Box::new(SleighError::VarnodeInvalid( 75 | src.clone(), 76 | ))); 77 | } 78 | } 79 | self.attach_varnodes.push(AttachVarnode(vars)); 80 | let meaning = Meaning::Varnode(AttachVarnodeId( 81 | self.attach_varnodes.len() - 1, 82 | )); 83 | self.attach_meaning_fields(fields, meaning)?; 84 | } 85 | syntax::attach::Meaning::Name(x) => { 86 | let names = x 87 | .into_iter() 88 | .enumerate() 89 | .filter_map(|(i, (x, _s))| Some((i, x?))) 90 | .collect(); 91 | self.attach_literals.push(AttachLiteral(names)); 92 | let meaning = Meaning::Literal(AttachLiteralId( 93 | self.attach_literals.len() - 1, 94 | )); 95 | self.attach_meaning_fields(fields, meaning)?; 96 | } 97 | syntax::attach::Meaning::Number(x) => { 98 | let values = x 99 | .into_iter() 100 | .enumerate() 101 | .filter_map(|(i, (x, _s))| Some((i, x?))) 102 | .collect(); 103 | self.attach_numbers.push(AttachNumber(values)); 104 | let meaning = Meaning::Number( 105 | PrintBase::Hex, 106 | AttachNumberId(self.attach_numbers.len() - 1), 107 | ); 108 | self.attach_meaning_fields(fields, meaning)?; 109 | } 110 | } 111 | Ok(()) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/semantic/inner/disassembly.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::disassembly::{ 2 | AddrScope, Assertation, Expr, ExprElement, GlobalSet, ReadScope, WriteScope, 3 | }; 4 | use crate::semantic::disassembly::{Assignment, Variable, VariableId}; 5 | use crate::semantic::{ContextId, Span}; 6 | use crate::{syntax, DisassemblyError}; 7 | 8 | use super::pattern::Pattern; 9 | use super::Sleigh; 10 | 11 | pub trait ExprBuilder { 12 | fn read_scope( 13 | &mut self, 14 | name: &str, 15 | src: &Span, 16 | ) -> Result>; 17 | fn new_expr( 18 | &mut self, 19 | input: syntax::block::disassembly::Expr, 20 | ) -> Result> { 21 | match input { 22 | syntax::block::disassembly::Expr::Value(expr_element) => { 23 | self.new_expr_element(expr_element).map(Expr::Value) 24 | } 25 | syntax::block::disassembly::Expr::Op(span, op, left, right) => { 26 | let left = self.new_expr(*left).map(Box::new)?; 27 | let right = self.new_expr(*right).map(Box::new)?; 28 | Ok(Expr::Op(span, op, left, right)) 29 | } 30 | } 31 | } 32 | fn new_expr_element( 33 | &mut self, 34 | input: syntax::block::disassembly::ExprElement, 35 | ) -> Result> { 36 | match input { 37 | syntax::block::disassembly::ExprElement::Value( 38 | syntax::Value::Number(src, int), 39 | ) => Ok(ExprElement::Value { 40 | value: ReadScope::Integer(int), 41 | location: src, 42 | }), 43 | 44 | syntax::block::disassembly::ExprElement::Value( 45 | syntax::Value::Ident(src, ident), 46 | ) => { 47 | self.read_scope(&ident, &src) 48 | .map(|value| ExprElement::Value { 49 | value, 50 | location: src, 51 | }) 52 | } 53 | 54 | syntax::block::disassembly::ExprElement::Op(span, op, expr) => Ok( 55 | ExprElement::Op(span, op, self.new_expr(*expr).map(Box::new)?), 56 | ), 57 | } 58 | } 59 | } 60 | //block number, but the last bit is if it pre/pos, None means after the 61 | //whole pattern is matched 62 | #[derive(Debug)] 63 | struct BlockCounter(Option); 64 | impl BlockCounter { 65 | fn disassembly_at(&mut self, pos: bool, num: usize) { 66 | let num = num << 1 | usize::from(pos); 67 | match &mut self.0 { 68 | None => (), 69 | Some(current) => *current = num.max(*current), 70 | } 71 | } 72 | fn pre_disassembly_at(&mut self, num: usize) { 73 | self.disassembly_at(false, num) 74 | } 75 | fn pos_disassembly_at(&mut self, num: usize) { 76 | self.disassembly_at(true, num) 77 | } 78 | fn post_match(&mut self) { 79 | self.0 = None; 80 | } 81 | } 82 | impl Default for BlockCounter { 83 | fn default() -> Self { 84 | //first block on pre disassembly 85 | Self(Some(0)) 86 | } 87 | } 88 | 89 | #[derive(Debug)] 90 | pub struct Builder<'a, 'b> { 91 | sleigh: &'b Sleigh, 92 | pattern: &'a mut Pattern, 93 | block_counter: BlockCounter, 94 | } 95 | 96 | impl<'a, 'b> ExprBuilder for Builder<'a, 'b> { 97 | fn read_scope( 98 | &mut self, 99 | name: &str, 100 | src: &Span, 101 | ) -> Result> { 102 | use super::GlobalScope; 103 | self.pattern 104 | .disassembly_variable_names 105 | .get(name) 106 | .map(|local| Ok(ReadScope::Local(*local))) 107 | .unwrap_or_else(|| { 108 | match self.sleigh.get_global(name).ok_or_else(|| { 109 | Box::new(DisassemblyError::MissingRef(src.clone())) 110 | })? { 111 | GlobalScope::InstNext(x) => { 112 | //inst_next can only be known after the pattern is 113 | //completly match 114 | self.block_counter.post_match(); 115 | Ok(ReadScope::InstNext(x)) 116 | } 117 | GlobalScope::InstStart(x) => Ok(ReadScope::InstStart(x)), 118 | GlobalScope::TokenField(x) => { 119 | //check the pattern will produce this field 120 | let Ok(Some(block_num)) = 121 | self.pattern.produce_token_field(self.sleigh, x) 122 | else { 123 | return Err(Box::new( 124 | DisassemblyError::InvalidRef(src.clone()), 125 | )); 126 | }; 127 | self.block_counter.pre_disassembly_at(block_num); 128 | Ok(ReadScope::TokenField(x)) 129 | } 130 | GlobalScope::Context(x) => Ok(ReadScope::Context(x)), 131 | _ => { 132 | Err(Box::new(DisassemblyError::InvalidRef(src.clone()))) 133 | } 134 | } 135 | }) 136 | } 137 | } 138 | 139 | impl<'a, 'b> Builder<'a, 'b> { 140 | pub fn new(sleigh: &'b Sleigh, pattern: &'a mut Pattern) -> Self { 141 | Self { 142 | sleigh, 143 | pattern, 144 | block_counter: BlockCounter::default(), 145 | } 146 | } 147 | fn insert_assertation(&mut self, ass: Assertation) { 148 | let ass_pos = match self.block_counter.0 { 149 | None => &mut self.pattern.pos, 150 | Some(block_counter) => { 151 | let block_num = block_counter >> 1; 152 | let block_pre = block_counter & 1 == 0; 153 | let block = &mut self.pattern.blocks[block_num]; 154 | if block_pre { 155 | &mut block.base.pre 156 | } else { 157 | &mut block.base.pos 158 | } 159 | } 160 | }; 161 | ass_pos.push(ass); 162 | } 163 | fn addr_scope( 164 | &mut self, 165 | name: &str, 166 | src: &Span, 167 | ) -> Result> { 168 | use super::GlobalScope::*; 169 | //get from local, otherwise get from global 170 | self.pattern 171 | .disassembly_variable_names 172 | .get(name) 173 | .map(|local| Ok(AddrScope::Local(*local))) 174 | .unwrap_or_else(|| { 175 | match self.sleigh.get_global(name).ok_or_else(|| { 176 | Box::new(DisassemblyError::MissingRef(src.clone())) 177 | })? { 178 | //TODO make sure the pattern will produce this table 179 | Table(x) => { 180 | //TODO error 181 | let block_num = 182 | self.pattern.is_table_produced(x).unwrap(); 183 | self.block_counter.pos_disassembly_at(block_num); 184 | Ok(AddrScope::Table(x)) 185 | } 186 | InstStart(x) => Ok(AddrScope::InstStart(x)), 187 | InstNext(x) => { 188 | //inst_next can only be known after the pattern is 189 | //completly match 190 | self.block_counter.post_match(); 191 | Ok(AddrScope::InstNext(x)) 192 | } 193 | _ => { 194 | Err(Box::new(DisassemblyError::InvalidRef(src.clone()))) 195 | } 196 | } 197 | }) 198 | } 199 | //TODO Write Scope shold never fail, leave the Result just in case 200 | fn write_scope( 201 | &mut self, 202 | name: &str, 203 | src: &Span, 204 | ) -> Result> { 205 | //if variable exists, return it 206 | if let Some(var) = self.pattern.disassembly_variable_names.get(name) { 207 | return Ok(WriteScope::Local(*var)); 208 | } 209 | //check the global context, if context return it 210 | //NOTE if other thing with the same name, but is not context, 211 | //create the variable to shadow global context 212 | if let Some(context) = self 213 | .sleigh 214 | .get_global(name) 215 | .and_then(|global| global.context()) 216 | { 217 | return Ok(WriteScope::Context(context)); 218 | } 219 | //otherwise create the variable 220 | let var = Variable { 221 | location: src.clone(), 222 | name: name.to_owned().into(), 223 | }; 224 | self.pattern.disassembly_variables.push(var); 225 | let var_id = VariableId(self.pattern.disassembly_variables.len() - 1); 226 | self.pattern 227 | .disassembly_variable_names 228 | .insert(name.to_owned(), var_id); 229 | Ok(WriteScope::Local(var_id)) 230 | } 231 | fn context( 232 | &mut self, 233 | name: &str, 234 | src: &Span, 235 | ) -> Result> { 236 | let context = self 237 | .sleigh 238 | .get_global(name) 239 | .ok_or_else(|| Box::new(DisassemblyError::MissingRef(src.clone())))? 240 | .context() 241 | .ok_or_else(|| { 242 | Box::new(DisassemblyError::InvalidRef(src.clone())) 243 | })?; 244 | Ok(context) 245 | } 246 | 247 | fn new_globalset( 248 | &mut self, 249 | input: syntax::block::disassembly::GlobalSet, 250 | ) -> Result> { 251 | let (_src, address) = match input.address { 252 | syntax::Value::Number(src, int) => { 253 | let addr = AddrScope::Integer(int.unsigned().unwrap()); 254 | (src, addr) 255 | } 256 | syntax::Value::Ident(src, ident) => { 257 | let addr = self.addr_scope(&ident, &src)?; 258 | (src, addr) 259 | } 260 | }; 261 | Ok(GlobalSet { 262 | address, 263 | context: self.context(&input.context, &input.src)?, 264 | location: input.src, 265 | }) 266 | } 267 | fn new_assignment( 268 | &mut self, 269 | input: syntax::block::disassembly::Assignment, 270 | ) -> Result> { 271 | let left = self.write_scope(&input.left, &input.left_span)?; 272 | let right = self.new_expr(input.right)?; 273 | Ok(Assignment { left, right }) 274 | } 275 | fn new_assertation( 276 | &mut self, 277 | input: syntax::block::disassembly::Assertation, 278 | ) -> Result> { 279 | match input { 280 | syntax::block::disassembly::Assertation::GlobalSet(globalset) => { 281 | self.new_globalset(*globalset).map(Assertation::GlobalSet) 282 | } 283 | syntax::block::disassembly::Assertation::Assignment(assignment) => { 284 | self.new_assignment(assignment).map(Assertation::Assignment) 285 | } 286 | } 287 | } 288 | pub fn build( 289 | mut self, 290 | input: syntax::block::disassembly::Disassembly, 291 | ) -> Result<(), Box> { 292 | input.assertations.into_iter().try_for_each(|input| { 293 | self.new_assertation(input) 294 | .map(|ass| self.insert_assertation(ass)) 295 | }) 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /src/semantic/inner/display.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::display::{Display, DisplayElement}; 2 | use crate::syntax::block; 3 | use crate::{DisplayError, Span}; 4 | 5 | use super::{Pattern, Sleigh}; 6 | 7 | impl Sleigh { 8 | fn get_display_ref( 9 | &self, 10 | pattern: &mut Pattern, 11 | name: &str, 12 | src: &Span, 13 | ) -> Result> { 14 | use crate::semantic::inner::GlobalScope::*; 15 | if let Some(disassembly_var) = 16 | pattern.disassembly_variable_names.get(name) 17 | { 18 | return Ok(DisplayElement::Disassembly(*disassembly_var)); 19 | } 20 | match self 21 | .get_global(name) 22 | .ok_or_else(|| Box::new(DisplayError::MissingRef(src.clone())))? 23 | { 24 | TokenField(x) => { 25 | if pattern 26 | .produce_token_field(self, x) 27 | .map(|block_num| block_num.is_none()) 28 | .unwrap() 29 | { 30 | //TODO error here 31 | todo!() 32 | } 33 | Ok(DisplayElement::TokenField(x)) 34 | } 35 | Varnode(x) => Ok(DisplayElement::Varnode(x)), 36 | Table(x) => Ok(DisplayElement::Table(x)), 37 | Context(x) => Ok(DisplayElement::Context(x)), 38 | _ => Err(Box::new(DisplayError::InvalidRef(src.clone()))), 39 | } 40 | } 41 | 42 | pub fn new_display( 43 | &self, 44 | display: block::display::Display, 45 | pattern: &mut Pattern, 46 | is_root: bool, 47 | ) -> Result> { 48 | use block::display::DisplayElement::*; 49 | //solve the idents 50 | let mut elements = vec![]; 51 | let mut iter = display.0.into_iter(); 52 | //in root table first element is the mneumonic 53 | let mneumonic = if !is_root { 54 | None 55 | } else { 56 | let Some(ele) = iter.next() else { 57 | return Ok(Display::default()); 58 | }; 59 | match ele { 60 | Concat => None, 61 | Ident(_src, mneumonic) => Some(mneumonic), 62 | //TODO: a single char can be a mneumonic? 63 | Other(c) => Some(c.to_string()), 64 | Literal(x) => { 65 | elements.push(DisplayElement::Literal(x)); 66 | None 67 | } 68 | } 69 | }; 70 | 71 | for ele in iter { 72 | match ele { 73 | Concat => (), 74 | Ident(src, name) => { 75 | elements.push(self.get_display_ref(pattern, &name, &src)?) 76 | } 77 | // Multiple spaces should be combined into a single one 78 | // NOTE: a literal with a space in the end, followed by 79 | // Other(' ') should NOT be condensated. 80 | Other(x) if x.is_whitespace() => match elements.last() { 81 | // spaces should be trimmed at the start 82 | None if mneumonic.is_none() => {} 83 | // if last was space, don't add other one 84 | Some(DisplayElement::Space) => {} 85 | Some(_) | None => elements.push(DisplayElement::Space), 86 | }, 87 | // if the previous entry was a literal, just add to it. 88 | Literal(value) => match elements.last_mut() { 89 | Some(DisplayElement::Literal(lit)) => lit.push_str(&value), 90 | _ => elements.push(DisplayElement::Literal(value)), 91 | }, 92 | Other(c) => match elements.last_mut() { 93 | Some(DisplayElement::Literal(lit)) => lit.push(c), 94 | _ => elements.push(DisplayElement::Literal(c.into())), 95 | }, 96 | } 97 | } 98 | 99 | //remove the space at the end 100 | if matches!(elements.last().map(DisplayElement::is_space), Some(true)) { 101 | elements.pop(); 102 | } 103 | Ok(Display { 104 | mneumonic, 105 | elements: elements.into(), 106 | }) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/semantic/inner/execution/block.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | 3 | use crate::semantic::execution::{Block as FinalBlock, BlockId}; 4 | use crate::semantic::inner::{Sleigh, SolverStatus}; 5 | use crate::ExecutionError; 6 | 7 | use super::{Execution, Statement}; 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct Block { 11 | //None is entry block 12 | pub name: Option>, 13 | // empty means the entry point 14 | //parent: RefCell>>, 15 | // None means the block is an return 16 | pub next: Option, 17 | pub statements: Vec>, 18 | } 19 | 20 | impl Block { 21 | pub fn new_empty(name: Option>) -> Self { 22 | Block { 23 | name, 24 | next: None, 25 | statements: vec![], 26 | } 27 | } 28 | 29 | pub fn solve( 30 | &self, 31 | sleigh: &Sleigh, 32 | execution: &Execution, 33 | solved: &mut T, 34 | ) -> Result<(), Box> { 35 | self.statements.iter().try_for_each(|statements| { 36 | statements.borrow_mut().solve(sleigh, execution, solved) 37 | }) 38 | } 39 | 40 | pub fn convert(self) -> FinalBlock { 41 | let statements = self 42 | .statements 43 | .into_iter() 44 | .map(|statement| statement.into_inner().convert()) 45 | .collect(); 46 | let statements = statements; 47 | FinalBlock { 48 | name: self.name, 49 | next: self.next, 50 | statements, 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/semantic/inner/execution/cpu_branch.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::execution::BranchCall; 2 | use crate::semantic::execution::CpuBranch as FinalCpuBranch; 3 | use crate::semantic::inner::{Sleigh, SolverStatus}; 4 | use crate::ExecutionError; 5 | use crate::VarSizeError; 6 | 7 | use super::{Execution, Expr}; 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct CpuBranch { 11 | pub cond: Option, 12 | pub call: BranchCall, 13 | //TODO delete direct? 14 | pub(crate) direct: bool, 15 | pub dst: Expr, 16 | } 17 | 18 | impl CpuBranch { 19 | pub fn new( 20 | sleigh: &Sleigh, 21 | execution: &Execution, 22 | mut cond: Option, 23 | call: BranchCall, 24 | direct: bool, 25 | dst: Expr, 26 | ) -> Self { 27 | //condition can have any size, preferencially 1 bit for true/false 28 | cond.iter_mut().for_each(|cond| { 29 | cond.size_mut(sleigh, execution) 30 | .update_action(|size| Some(size.set_possible_min())) 31 | .unwrap(); 32 | }); 33 | CpuBranch { 34 | cond, 35 | call, 36 | direct, 37 | dst, 38 | } 39 | } 40 | pub fn solve( 41 | &mut self, 42 | sleigh: &Sleigh, 43 | execution: &Execution, 44 | solved: &mut impl SolverStatus, 45 | ) -> Result<(), Box> { 46 | if let Some(cond) = self.cond.as_mut() { 47 | cond.solve(sleigh, execution, solved)?; 48 | } 49 | // jmp dst addr can be equal or smaller then space address size 50 | let modified = 51 | self.dst.size_mut(sleigh, execution).update_action(|size| { 52 | size.set_max_bytes(sleigh.addr_bytes().unwrap()) 53 | }); 54 | 55 | if modified.ok_or_else(|| VarSizeError::AddressTooBig { 56 | address_size: self.dst.size(sleigh, execution), 57 | space_bytes: sleigh.addr_bytes().unwrap(), 58 | location: self.dst.src().clone(), 59 | })? { 60 | solved.i_did_a_thing(); 61 | } 62 | 63 | self.dst.solve(sleigh, execution, solved)?; 64 | Ok(()) 65 | } 66 | pub fn convert(self) -> FinalCpuBranch { 67 | let cond = self.cond.map(|cond| cond.convert()); 68 | let dst = self.dst.convert(); 69 | FinalCpuBranch { 70 | cond, 71 | call: self.call, 72 | direct: self.direct, 73 | dst, 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/semantic/inner/execution/local_goto.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::execution::LocalGoto as FinalLocalGoto; 2 | use crate::semantic::inner::{Sleigh, SolverStatus}; 3 | use crate::{semantic::execution::BlockId, ExecutionError}; 4 | 5 | use super::{Execution, Expr}; 6 | 7 | #[derive(Clone, Debug)] 8 | pub struct LocalGoto { 9 | pub cond: Option, 10 | pub dst: BlockId, 11 | } 12 | 13 | impl LocalGoto { 14 | pub fn new( 15 | sleigh: &Sleigh, 16 | execution: &Execution, 17 | mut cond: Option, 18 | dst: BlockId, 19 | ) -> Result> { 20 | //condition can have any size, preferencially 1 bit for true/false 21 | cond.iter_mut().for_each(|cond| { 22 | cond.size_mut(sleigh, execution) 23 | .update_action(|size| Some(size.set_possible_min())) 24 | .unwrap(); 25 | }); 26 | Ok(LocalGoto { cond, dst }) 27 | } 28 | pub fn solve( 29 | &mut self, 30 | sleigh: &Sleigh, 31 | execution: &Execution, 32 | solved: &mut impl SolverStatus, 33 | ) -> Result<(), Box> { 34 | if let Some(cond) = self.cond.as_mut() { 35 | cond.solve(sleigh, execution, solved)?; 36 | if cond.size(sleigh, execution).is_undefined() { 37 | solved.iam_not_finished(cond.src(), file!(), line!()); 38 | } 39 | } 40 | Ok(()) 41 | } 42 | 43 | pub fn convert(self) -> FinalLocalGoto { 44 | let cond = self.cond.map(|x| x.convert()); 45 | let dst = self.dst; 46 | FinalLocalGoto { cond, dst } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/semantic/inner/execution/mod.rs: -------------------------------------------------------------------------------- 1 | use std::cell::{Ref, RefMut}; 2 | 3 | use crate::semantic::execution::{ 4 | BlockId, BranchCall, Build, Execution as FinalExecution, 5 | Statement as FinalStatement, VariableId, 6 | }; 7 | use crate::{ExecutionError, NumberUnsigned, Span}; 8 | 9 | use super::{Sleigh, SolverStatus}; 10 | 11 | mod builder; 12 | pub use builder::*; 13 | mod expr; 14 | pub use expr::*; 15 | mod op; 16 | pub use op::*; 17 | pub(crate) mod len; 18 | pub use len::*; 19 | mod export; 20 | pub use export::*; 21 | mod block; 22 | pub use block::*; 23 | mod assignment; 24 | pub use assignment::*; 25 | mod user_call; 26 | pub use user_call::*; 27 | mod local_goto; 28 | pub use local_goto::*; 29 | mod cpu_branch; 30 | pub use cpu_branch::*; 31 | mod variables; 32 | pub use variables::*; 33 | 34 | #[derive(Clone, Debug)] 35 | pub struct Execution { 36 | pub src: Span, 37 | pub variables: Vec, 38 | pub blocks: Vec, 39 | 40 | pub return_value: TableExportType, 41 | 42 | //entry_block have no name and is not on self.labels 43 | pub entry_block: BlockId, 44 | } 45 | 46 | #[derive(Clone, Debug)] 47 | pub enum Statement { 48 | Delayslot(NumberUnsigned), 49 | Export(Export), 50 | CpuBranch(CpuBranch), 51 | LocalGoto(LocalGoto), 52 | UserCall(UserCall), 53 | Build(Build), 54 | Declare(VariableId), 55 | Assignment(Assignment), 56 | // NOTE this only exits to facilitate the inlining of macros 57 | MacroParamAssignment(MacroParamAssignment), 58 | } 59 | 60 | impl Statement { 61 | pub fn solve( 62 | &mut self, 63 | sleigh: &Sleigh, 64 | execution: &Execution, 65 | solved: &mut T, 66 | ) -> Result<(), Box> 67 | where 68 | T: SolverStatus, 69 | { 70 | match self { 71 | Self::Build(_x) => (), 72 | Self::Delayslot(_) => (), 73 | Self::Export(x) => x.solve(sleigh, execution, solved)?, 74 | Self::Declare(_x) => (), 75 | Self::CpuBranch(x) => x.solve(sleigh, execution, solved)?, 76 | Self::LocalGoto(x) => x.solve(sleigh, execution, solved)?, 77 | Self::UserCall(x) => x.solve(sleigh, execution, solved)?, 78 | Self::Assignment(x) => x.solve(sleigh, execution, solved)?, 79 | Self::MacroParamAssignment(x) => { 80 | x.solve(sleigh, execution, solved)? 81 | } 82 | } 83 | Ok(()) 84 | } 85 | pub fn convert(self) -> FinalStatement { 86 | use FinalStatement as New; 87 | match self { 88 | Self::Delayslot(x) => New::Delayslot(x), 89 | Self::Export(x) => New::Export(x.convert()), 90 | Self::CpuBranch(x) => New::CpuBranch(x.convert()), 91 | Self::LocalGoto(x) => New::LocalGoto(x.convert()), 92 | Self::UserCall(x) => New::UserCall(x.convert()), 93 | Self::Build(x) => New::Build(x), 94 | Self::Declare(x) => New::Declare(x), 95 | Self::Assignment(x) => New::Assignment(x.convert()), 96 | Self::MacroParamAssignment(x) => New::Assignment(x.convert()), 97 | } 98 | } 99 | } 100 | 101 | impl Execution { 102 | pub fn src(&self) -> &Span { 103 | &self.src 104 | } 105 | pub fn new_empty(src: Span) -> Self { 106 | let entry_block = Block::new_empty(None); 107 | Execution { 108 | src, 109 | blocks: vec![entry_block], 110 | variables: vec![], 111 | return_value: TableExportType::None, 112 | entry_block: BlockId(0), 113 | } 114 | } 115 | pub fn solve( 116 | &mut self, 117 | sleigh: &Sleigh, 118 | solved: &mut T, 119 | ) -> Result<(), Box> { 120 | self.blocks 121 | .iter() 122 | .try_for_each(|block| block.solve(sleigh, self, solved))?; 123 | 124 | //get the export sizes, otherwise we are finished 125 | let Some(mut return_size) = self.return_value.size().cloned() else { 126 | return Ok(()); 127 | }; 128 | 129 | // calculate the new exported value 130 | let mut inputs: Vec = self 131 | .export_statements_mut() 132 | .map(|x| x.output_size(sleigh, self)) 133 | .collect(); 134 | let modified = 135 | len::n_generate_a(inputs.as_mut_slice(), &mut return_size) 136 | .ok_or_else(|| Box::new(ExecutionError::InvalidExport))?; 137 | 138 | if modified { 139 | solved.i_did_a_thing(); 140 | for (new_size, mut old_size) in 141 | inputs.into_iter().zip(self.export_statements_mut()) 142 | { 143 | old_size.output_size_mut(sleigh, self).set(new_size); 144 | } 145 | *self.return_value.size_mut().unwrap() = return_size; 146 | } 147 | 148 | if return_size.is_undefined() { 149 | solved.iam_not_finished(&self.src, file!(), line!()); 150 | } 151 | 152 | Ok(()) 153 | } 154 | pub fn convert(self) -> FinalExecution { 155 | FinalExecution { 156 | variables: self 157 | .variables 158 | .into_iter() 159 | .map(|x| x.convert()) 160 | .collect(), 161 | blocks: self 162 | .blocks 163 | .into_iter() 164 | .map(|block| block.convert()) 165 | .collect(), 166 | entry_block: self.entry_block, 167 | export: self.return_value.convert(), 168 | } 169 | } 170 | pub fn block(&self, id: BlockId) -> &Block { 171 | &self.blocks[id.0] 172 | } 173 | pub fn block_mut(&mut self, id: BlockId) -> &mut Block { 174 | &mut self.blocks[id.0] 175 | } 176 | pub fn block_by_name(&self, name: &str) -> Option { 177 | self.blocks 178 | .iter() 179 | .position(|block| { 180 | block 181 | .name 182 | .as_ref() 183 | .map(|block_name| block_name.as_ref() == name) 184 | .unwrap_or(false) 185 | }) 186 | .map(BlockId) 187 | } 188 | pub fn new_block(&mut self, name: String) -> Option<()> { 189 | if self.block_by_name(&name).is_some() { 190 | return None; 191 | } 192 | let block = Block::new_empty(Some(name.into())); 193 | self.blocks.push(block); 194 | Some(()) 195 | } 196 | pub fn variable(&self, id: VariableId) -> &Variable { 197 | &self.variables[id.0] 198 | } 199 | pub fn variable_mut(&mut self, id: VariableId) -> &mut Variable { 200 | &mut self.variables[id.0] 201 | } 202 | pub fn variable_by_name(&self, name: &str) -> Option { 203 | for (var_id, var) in self.variables.iter().enumerate() { 204 | if var.name == name { 205 | return Some(VariableId(var_id)); 206 | } 207 | } 208 | None 209 | } 210 | pub fn create_variable( 211 | &mut self, 212 | name: String, 213 | src: Span, 214 | size: Option, 215 | explicit: bool, 216 | ) -> Result> { 217 | //// don't allow duplicated name 218 | //if self.variable_by_name(&name).is_some() { 219 | // return Err(Box::new(ExecutionError::InvalidRef(src))); 220 | //} 221 | //TODO src 222 | let var_id = self.variables.len(); 223 | let var = Variable::new(name, src, size, explicit); 224 | self.variables.push(var); 225 | Ok(VariableId(var_id)) 226 | } 227 | 228 | pub fn export_statements(&self) -> impl Iterator> { 229 | self.blocks 230 | .iter() 231 | .filter(|block| block.next.is_none()) 232 | .filter_map(|block| { 233 | let last = block.statements.last()?.borrow(); 234 | if !matches!(&*last, Statement::Export(_)) { 235 | return None; 236 | } 237 | Some(Ref::map(last, |last| { 238 | let Statement::Export(exp) = last else { 239 | unreachable!(); 240 | }; 241 | exp 242 | })) 243 | }) 244 | } 245 | 246 | pub fn export_statements_mut( 247 | &self, 248 | ) -> impl Iterator> { 249 | self.blocks 250 | .iter() 251 | .filter(|block| block.next.is_none()) 252 | .filter_map(|block| { 253 | let last = block.statements.last()?.borrow_mut(); 254 | if !matches!(&*last, Statement::Export(_)) { 255 | return None; 256 | } 257 | Some(RefMut::map(last, |last| { 258 | let Statement::Export(exp) = last else { 259 | unreachable!(); 260 | }; 261 | exp 262 | })) 263 | }) 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /src/semantic/inner/execution/op.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::execution::{ 2 | Binary, MemoryLocation as FinalMemoryLocation, 3 | }; 4 | use crate::semantic::inner::SolverStatus; 5 | use crate::semantic::SpaceId; 6 | use crate::{FloatType, NumberSigned, NumberUnsigned, Span}; 7 | 8 | use super::FieldSize; 9 | 10 | #[derive(Clone, Debug)] 11 | pub struct MemoryLocation { 12 | pub space: SpaceId, 13 | pub size: FieldSize, 14 | pub location: Span, 15 | } 16 | impl MemoryLocation { 17 | pub fn solve(&self, solved: &mut impl SolverStatus) { 18 | if !self.size.is_final() { 19 | solved.iam_not_finished(&self.location, file!(), line!()) 20 | } 21 | } 22 | pub fn convert(self) -> FinalMemoryLocation { 23 | FinalMemoryLocation { 24 | len_bytes: self.size.possible_value().unwrap(), 25 | space: self.space, 26 | location: self.location, 27 | } 28 | } 29 | } 30 | 31 | impl Binary { 32 | #[cfg(feature = "no_overflow_inline")] 33 | pub fn execute( 34 | &self, 35 | left: NumberUnsigned, 36 | right: NumberUnsigned, 37 | ) -> Option { 38 | //COMPILER please optimize this 39 | let (left_s, right_s) = (left as NumberSigned, right as NumberSigned); 40 | let sig = |x: NumberSigned| x as NumberUnsigned; 41 | let (left_f, right_f) = (left as FloatType, right as FloatType); 42 | let float = |x: FloatType| x as NumberUnsigned; 43 | match self { 44 | Self::Add => left.checked_add(right), 45 | Self::Sub => left.checked_sub(right), 46 | Self::Mult => left.checked_mul(right), 47 | Self::Div => left.checked_div(right), 48 | Self::SigDiv => left_s.checked_div(right_s).map(sig), 49 | Self::Rem => Some(left % right), 50 | Self::SigRem => Some(sig(left_s % right_s)), 51 | Self::FloatAdd => Some(float(left_f + right_f)), 52 | Self::FloatSub => Some(float(left_f - right_f)), 53 | Self::FloatMult => Some(float(left_f * right_f)), 54 | Self::FloatDiv => Some(float(left_f / right_f)), 55 | Self::Lsl => left.checked_shl(right.try_into().ok()?), 56 | Self::Lsr => left.checked_shr(right.try_into().ok()?), 57 | Self::Asr => left_s.checked_shr(right.try_into().ok()?).map(sig), 58 | Self::BitAnd => Some(left & right), 59 | Self::BitXor => Some(left ^ right), 60 | Self::BitOr => Some(left | right), 61 | Self::Less => Some((left < right) as NumberUnsigned), 62 | Self::Greater => Some((left > right) as NumberUnsigned), 63 | Self::LessEq => Some((left <= right) as NumberUnsigned), 64 | Self::GreaterEq => Some((left >= right) as NumberUnsigned), 65 | Self::SigLess => Some((left_s < right_s) as NumberUnsigned), 66 | Self::SigGreater => Some((left_s > right_s) as NumberUnsigned), 67 | Self::SigLessEq => Some((left_s <= right_s) as NumberUnsigned), 68 | Self::SigGreaterEq => Some((left_s >= right_s) as NumberUnsigned), 69 | Self::FloatLess => Some((left_f < right_f) as NumberUnsigned), 70 | Self::FloatGreater => Some((left_f > right_f) as NumberUnsigned), 71 | Self::FloatLessEq => Some((left_f <= right_f) as NumberUnsigned), 72 | Self::FloatGreaterEq => Some((left_f >= right_f) as NumberUnsigned), 73 | Self::And => Some((left != 0 && right != 0) as NumberUnsigned), 74 | Self::Xor => Some(((left != 0) ^ (right != 0)) as NumberUnsigned), 75 | Self::Or => Some((left != 0 || right != 0) as NumberUnsigned), 76 | Self::Eq => Some((left == right) as NumberUnsigned), 77 | Self::Ne => Some((left != right) as NumberUnsigned), 78 | Self::FloatEq => Some((left_f == right_f) as NumberUnsigned), 79 | Self::FloatNe => Some((left_f != right_f) as NumberUnsigned), 80 | //TODO make IntTypeU Ref sized for this reason? 81 | //carry borrow can only be calculated if the type size is known 82 | Self::Carry | Self::SCarry | Self::SBorrow => None, 83 | } 84 | } 85 | #[cfg(not(feature = "no_overflow_inline"))] 86 | pub fn execute( 87 | &self, 88 | left: NumberUnsigned, 89 | right: NumberUnsigned, 90 | ) -> Option { 91 | //COMPILER please optimize this 92 | let (left_s, right_s) = (left as NumberSigned, right as NumberSigned); 93 | let sig = |x: NumberSigned| x as NumberUnsigned; 94 | let (left_f, right_f) = (left as FloatType, right as FloatType); 95 | let float = |x: FloatType| x as NumberUnsigned; 96 | match self { 97 | Self::Add => Some(left.wrapping_add(right)), 98 | Self::Sub => Some(left.wrapping_sub(right)), 99 | Self::Mult => left.checked_mul(right), 100 | Self::Div => left.checked_div(right), 101 | Self::SigDiv => left_s.checked_div(right_s).map(sig), 102 | Self::Rem => Some(left % right), 103 | Self::SigRem => Some(sig(left_s % right_s)), 104 | Self::FloatAdd => Some(float(left_f + right_f)), 105 | Self::FloatSub => Some(float(left_f - right_f)), 106 | Self::FloatMult => Some(float(left_f * right_f)), 107 | Self::FloatDiv => Some(float(left_f / right_f)), 108 | Self::Lsl => Some(left.wrapping_shl(right.try_into().ok()?)), 109 | Self::Lsr => Some(left.wrapping_shr(right.try_into().ok()?)), 110 | Self::Asr => left_s.checked_shr(right.try_into().ok()?).map(sig), 111 | Self::BitAnd => Some(left & right), 112 | Self::BitXor => Some(left ^ right), 113 | Self::BitOr => Some(left | right), 114 | Self::Less => Some((left < right) as NumberUnsigned), 115 | Self::Greater => Some((left > right) as NumberUnsigned), 116 | Self::LessEq => Some((left <= right) as NumberUnsigned), 117 | Self::GreaterEq => Some((left >= right) as NumberUnsigned), 118 | Self::SigLess => Some((left_s < right_s) as NumberUnsigned), 119 | Self::SigGreater => Some((left_s > right_s) as NumberUnsigned), 120 | Self::SigLessEq => Some((left_s <= right_s) as NumberUnsigned), 121 | Self::SigGreaterEq => Some((left_s >= right_s) as NumberUnsigned), 122 | Self::FloatLess => Some((left_f < right_f) as NumberUnsigned), 123 | Self::FloatGreater => Some((left_f > right_f) as NumberUnsigned), 124 | Self::FloatLessEq => Some((left_f <= right_f) as NumberUnsigned), 125 | Self::FloatGreaterEq => Some((left_f >= right_f) as NumberUnsigned), 126 | Self::And => Some((left != 0 && right != 0) as NumberUnsigned), 127 | Self::Xor => Some(((left != 0) ^ (right != 0)) as NumberUnsigned), 128 | Self::Or => Some((left != 0 || right != 0) as NumberUnsigned), 129 | Self::Eq => Some((left == right) as NumberUnsigned), 130 | Self::Ne => Some((left != right) as NumberUnsigned), 131 | Self::FloatEq => Some((left_f == right_f) as NumberUnsigned), 132 | Self::FloatNe => Some((left_f != right_f) as NumberUnsigned), 133 | //TODO make IntTypeU Ref sized for this reason? 134 | //carry borrow can only be calculated if the type size is known 135 | Self::Carry | Self::SCarry | Self::SBorrow => None, 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/semantic/inner/execution/user_call.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::execution::UserCall as FinalUserCall; 2 | use crate::semantic::UserFunctionId; 3 | use crate::ExecutionError; 4 | use crate::Span; 5 | 6 | use super::{Execution, Expr, FieldSize, Sleigh, SolverStatus}; 7 | 8 | #[derive(Clone, Debug)] 9 | pub struct UserCall { 10 | pub location: Span, 11 | pub output_size: FieldSize, 12 | pub function: UserFunctionId, 13 | pub params: Vec, 14 | } 15 | 16 | impl UserCall { 17 | pub fn new( 18 | sleigh: &Sleigh, 19 | execution: &Execution, 20 | mut params: Vec, 21 | function: UserFunctionId, 22 | location: Span, 23 | ) -> Self { 24 | //TODO how to handle user functions with variable number of parameter??? 25 | //function.set_param_num(params.len()).unwrap(/*TODO*/); 26 | 27 | //params size is not very relevant 28 | params.iter_mut().for_each(|param| { 29 | //TODO improve the size speculation 30 | param 31 | .size_mut(sleigh, execution) 32 | .update_action(|size| Some(size.set_possible_min())) 33 | .unwrap(); 34 | }); 35 | Self { 36 | params, 37 | output_size: FieldSize::new_unsized(), 38 | function, 39 | location, 40 | } 41 | } 42 | pub fn solve( 43 | &mut self, 44 | sleigh: &Sleigh, 45 | execution: &Execution, 46 | solved: &mut impl SolverStatus, 47 | ) -> Result<(), Box> { 48 | self.params 49 | .iter_mut() 50 | .try_for_each(|x| x.solve(sleigh, execution, solved)) 51 | } 52 | pub fn convert(self) -> FinalUserCall { 53 | let params = self.params.into_iter().map(|x| x.convert()).collect(); 54 | FinalUserCall { 55 | location: self.location, 56 | function: self.function, 57 | params, 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/semantic/inner/execution/variables.rs: -------------------------------------------------------------------------------- 1 | use std::cell::Cell; 2 | 3 | use crate::semantic::execution::Variable as FinalVariable; 4 | use crate::Span; 5 | 6 | use super::FieldSize; 7 | 8 | #[derive(Clone, Debug)] 9 | pub struct Variable { 10 | // note variable in macros get the name of their alias 11 | pub name: String, 12 | //pub scope: RefCell, 13 | pub size: Cell, 14 | ///location of the variable declaration, if declared explicitly 15 | /// NOTE: PcodeMacro Params src is located in `Parameter` 16 | pub src: Span, 17 | pub explicit: bool, 18 | } 19 | 20 | impl Variable { 21 | pub fn new( 22 | name: String, 23 | src: Span, 24 | size: Option, 25 | explicit: bool, 26 | ) -> Self { 27 | Self { 28 | name, 29 | //scope, 30 | size: Cell::new(size.unwrap_or(FieldSize::new_unsized())), 31 | src, 32 | explicit, 33 | } 34 | } 35 | pub fn convert(self) -> FinalVariable { 36 | FinalVariable { 37 | name: self.name.into(), 38 | len_bits: self.size.get().possible_value().unwrap(), 39 | location: self.explicit.then_some(self.src), 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/semantic/inner/pattern/constraint.rs: -------------------------------------------------------------------------------- 1 | use crate::pattern::BitConstraint; 2 | use crate::semantic::pattern::{CmpOp, ConstraintValue}; 3 | use crate::FieldBits; 4 | 5 | impl BitConstraint { 6 | pub fn define(self, bit: bool) -> Option { 7 | match self { 8 | Self::Unrestrained => Some(Self::Defined(bit)), 9 | Self::Defined(old_bit) if old_bit == bit => Some(self), 10 | Self::Defined(_old_bit) => None, 11 | // TODO this may not be possible, we are unable to verify that now 12 | Self::Restrained => Some(Self::Defined(bit)), 13 | } 14 | } 15 | /// select the most restrictive from both, None if they conflict 16 | pub fn most_restrictive(self, other: Self) -> Option { 17 | match (self, other) { 18 | //if one is unrestrained, just return the other 19 | (Self::Unrestrained, other) | (other, Self::Unrestrained) => { 20 | Some(other) 21 | } 22 | // both have the same value 23 | (Self::Restrained, Self::Restrained) => Some(self), 24 | (Self::Defined(self_value), Self::Defined(other_value)) 25 | if self_value == other_value => 26 | { 27 | Some(self) 28 | } 29 | // conflicting values 30 | (Self::Defined(_), Self::Defined(_)) => None, 31 | // TODO this may not be possible, we are unable to verify that now 32 | (other @ Self::Defined(_), Self::Restrained) 33 | | (Self::Restrained, other @ Self::Defined(_)) => Some(other), 34 | } 35 | } 36 | /// select the least restrictive from both 37 | pub fn least_restrictive(self, other: Self) -> Self { 38 | match (self, other) { 39 | (Self::Unrestrained, _other) | (_other, Self::Unrestrained) => { 40 | Self::Unrestrained 41 | } 42 | (Self::Defined(self_value), Self::Defined(other_value)) 43 | if self_value != other_value => 44 | { 45 | Self::Restrained 46 | } 47 | //both have the same value 48 | (Self::Defined(_), Self::Defined(_)) => self, 49 | (Self::Restrained, Self::Restrained) 50 | | (Self::Defined(_), Self::Restrained) 51 | | (Self::Restrained, Self::Defined(_)) => Self::Restrained, 52 | } 53 | } 54 | } 55 | 56 | pub fn apply_value( 57 | constraint: &mut [BitConstraint], 58 | field_order: fn(usize, usize) -> usize, 59 | value_order: fn(usize, usize) -> usize, 60 | field_bits: FieldBits, 61 | op: CmpOp, 62 | value: &ConstraintValue, 63 | ) -> Option<()> { 64 | //only set the value, if its Eq and the value is known at compile time 65 | use crate::semantic::disassembly::{ExprElement, ReadScope}; 66 | // TODO allow multiple expressions that can be evaulated at compile time, 67 | // or make sure the optimations prior to this only produces values 68 | let value = match (op, value.expr()) { 69 | ( 70 | CmpOp::Eq, 71 | crate::disassembly::Expr::Value(ExprElement::Value { 72 | value: ReadScope::Integer(value), 73 | location: _, 74 | }), 75 | ) => Some(value.signed_super()), 76 | _ => None, 77 | }; 78 | 79 | let field_bits_len = field_bits.len().get().try_into().unwrap(); 80 | for (value_bit, field_bit) in field_bits.0.enumerate() { 81 | let field_bit = field_bit.try_into().unwrap(); 82 | let field_bit = field_order(field_bit, constraint.len()); 83 | let bit = &mut constraint[field_bit]; 84 | if let Some(value) = value { 85 | let value_bit = value_order(value_bit, field_bits_len); 86 | let value_bit = (value >> value_bit) & 1 != 0; 87 | *bit = bit.define(value_bit)?; 88 | } else { 89 | //error never happen with `BitConstraint::Restrained` 90 | *bit = bit.most_restrictive(BitConstraint::Restrained).unwrap(); 91 | } 92 | } 93 | Some(()) 94 | } 95 | -------------------------------------------------------------------------------- /src/semantic/inner/pattern/pattern_len.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::pattern::PatternLen; 2 | use crate::NumberUnsigned; 3 | 4 | //Describe a Block/Pattern possible len 5 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 6 | pub enum ConstructorPatternLen { 7 | /// Cases with the pattern call it own table, NOTE: the table can only call 8 | /// itself once. 9 | /// self-Recursive, non-growing, basically unrestricted, but indicating 10 | /// to tables that this don't change the table.pattern_len directly. 11 | /// Value is the len that this constructor will generate, not including 12 | /// the recursive itself 13 | NonGrowingRecursive(PatternLen), 14 | /// self-Recrusive, growing, similat to NonGrowing, but is possible that this 15 | /// keep calling itself, in a infinite growing patter. It is the context job 16 | /// to limit the size of it. 17 | /// grow, is the len of the size that will be added to the len, and non_grow, 18 | /// is the value that was taken from NonGrowing Recursive 19 | GrowingRecursive { 20 | grow: PatternLen, 21 | non_grow: PatternLen, 22 | }, 23 | 24 | /// the final state, this means the len have a possible final value, 25 | /// although it could be restricted further, eg: len is 2-8bytes, but is 26 | /// found that the len is never bigger then 6, so len is update to 2-6bytes. 27 | Basic(PatternLen), 28 | } 29 | impl ConstructorPatternLen { 30 | pub fn single_len(&self) -> Option { 31 | match self { 32 | Self::Basic(basic) => basic.single_len(), 33 | Self::NonGrowingRecursive(_) | Self::GrowingRecursive { .. } => { 34 | None 35 | } 36 | } 37 | } 38 | pub fn is_basic(&self) -> bool { 39 | matches!(self, Self::Basic(_)) 40 | } 41 | pub fn basic(&self) -> Option { 42 | match self { 43 | Self::Basic(basic) => Some(*basic), 44 | Self::NonGrowingRecursive(_) | Self::GrowingRecursive { .. } => { 45 | None 46 | } 47 | } 48 | } 49 | ///if is some kind of recursive 50 | pub fn is_recursive(&self) -> bool { 51 | match self { 52 | Self::Basic(basic) => basic.is_recursive(), 53 | Self::NonGrowingRecursive(_) | Self::GrowingRecursive { .. } => { 54 | true 55 | } 56 | } 57 | } 58 | ///the min possible pattern len size, None means the min can't be calculated 59 | ///because this is a recursive and the len depends on the other constructors 60 | pub fn min(&self) -> Option { 61 | self.basic().map(|len| len.min()) 62 | } 63 | ///the max possible pattern len size, None is infinite maximum possible len 64 | pub fn max(&self) -> Option { 65 | self.basic().and_then(|len| len.max()) 66 | } 67 | //TODO replace Option with Result? 68 | pub fn add(self, other: Self) -> Option { 69 | match (self, other) { 70 | (Self::Basic(x), Self::Basic(y)) => Some(Self::Basic(x.concat(y))), 71 | //NonGrowingRecursize concat with a basic block, result in a 72 | //GrowingRecursive 73 | (Self::NonGrowingRecursive(non_grow), Self::Basic(basic)) 74 | | (Self::Basic(basic), Self::NonGrowingRecursive(non_grow)) => { 75 | Some(Self::GrowingRecursive { 76 | grow: basic, 77 | non_grow, 78 | }) 79 | } 80 | //Growing Recursive concat with a basic, just grows 81 | (Self::GrowingRecursive { grow, non_grow }, Self::Basic(basic)) 82 | | (Self::Basic(basic), Self::GrowingRecursive { grow, non_grow }) => { 83 | Some(Self::GrowingRecursive { 84 | grow: grow.concat(basic), 85 | non_grow, 86 | }) 87 | } 88 | //a pattern can only have one SelfRecursive, so this is invalid 89 | ( 90 | Self::GrowingRecursive { .. } | Self::NonGrowingRecursive(_), 91 | Self::GrowingRecursive { .. } | Self::NonGrowingRecursive(_), 92 | ) => None, 93 | } 94 | } 95 | pub fn greater(self, other: Self) -> Option { 96 | match (self, other) { 97 | ( 98 | Self::GrowingRecursive { .. } | Self::NonGrowingRecursive(_), 99 | Self::GrowingRecursive { .. } | Self::NonGrowingRecursive(_), 100 | ) => None, 101 | (Self::Basic(x), Self::Basic(y)) => Some(Self::Basic(x.greater(y))), 102 | ( 103 | Self::Basic(x) | Self::NonGrowingRecursive(x), 104 | Self::Basic(y) | Self::NonGrowingRecursive(y), 105 | ) => Some(Self::NonGrowingRecursive(x.greater(y))), 106 | (Self::Basic(_), Self::GrowingRecursive { .. }) 107 | | (Self::GrowingRecursive { .. }, Self::Basic(_)) => { 108 | //This only happen if recursive block is in a sub_pattern 109 | //what i think is not allowed 110 | unimplemented!() 111 | } 112 | } 113 | } 114 | } 115 | impl From for ConstructorPatternLen { 116 | fn from(value: PatternLen) -> Self { 117 | Self::Basic(value) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/semantic/inner/pattern/verification.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::inner::GlobalScope; 2 | use crate::semantic::pattern::{ 3 | CmpOp, PatternLen, Verification as FinalVerification, 4 | }; 5 | use crate::semantic::{ContextId, TableId, TokenFieldId}; 6 | use crate::{syntax, PatternError, Span}; 7 | 8 | use super::{ 9 | ConstraintValue, ConstructorPatternLen, DisassemblyBuilder, Pattern, 10 | ProducedTable, Sleigh, 11 | }; 12 | 13 | #[derive(Clone, Debug)] 14 | pub enum Verification { 15 | ContextCheck { 16 | context: ContextId, 17 | op: CmpOp, 18 | value: ConstraintValue, 19 | }, 20 | TableBuild { 21 | produced_table: ProducedTable, 22 | verification: Option<(CmpOp, ConstraintValue)>, 23 | }, 24 | TokenFieldCheck { 25 | field: TokenFieldId, 26 | op: CmpOp, 27 | value: ConstraintValue, 28 | }, 29 | SubPattern { 30 | location: Span, 31 | pattern: Pattern, 32 | }, 33 | } 34 | impl Verification { 35 | pub fn from_constraint( 36 | sleigh: &Sleigh, 37 | field: String, 38 | src: Span, 39 | constraint: syntax::block::pattern::Constraint, 40 | this_table: TableId, 41 | ) -> Result> { 42 | let syntax::block::pattern::Constraint { op: cmp_op, value } = 43 | constraint; 44 | let value = ConstraintValue::new(DisassemblyBuilder::parse_expr( 45 | sleigh, value.expr, 46 | )?); 47 | let field = sleigh 48 | .get_global(&field) 49 | .ok_or_else(|| Box::new(PatternError::MissingRef(src.clone())))?; 50 | match field { 51 | GlobalScope::TokenField(x) => Ok(Self::TokenFieldCheck { 52 | field: x, 53 | op: cmp_op, 54 | value, 55 | }), 56 | //TODO create InstStart? Does start_start exists? 57 | GlobalScope::Context(x) => Ok(Self::ContextCheck { 58 | context: x, 59 | op: cmp_op, 60 | value, 61 | }), 62 | GlobalScope::Table(x) => Ok({ 63 | let verification = Some((cmp_op, value)); 64 | let recursive = x == this_table; 65 | let table = x; 66 | Self::TableBuild { 67 | produced_table: ProducedTable { 68 | table, 69 | always: true, 70 | recursive, 71 | location: src.clone(), 72 | }, 73 | verification, 74 | } 75 | }), 76 | _ => Err(Box::new(PatternError::InvalidRef(src))), 77 | } 78 | } 79 | pub fn new_context( 80 | context: ContextId, 81 | _src: Span, 82 | op: CmpOp, 83 | value: ConstraintValue, 84 | ) -> Self { 85 | Self::ContextCheck { context, op, value } 86 | } 87 | pub fn new_table( 88 | this_table: TableId, 89 | table: TableId, 90 | location: Span, 91 | verification: Option<(CmpOp, ConstraintValue)>, 92 | ) -> Self { 93 | let recursive = table == this_table; 94 | Self::TableBuild { 95 | produced_table: ProducedTable { 96 | table, 97 | always: true, 98 | recursive, 99 | location, 100 | }, 101 | verification, 102 | } 103 | } 104 | pub fn new_token_field( 105 | field: TokenFieldId, 106 | _src: Span, 107 | op: CmpOp, 108 | value: ConstraintValue, 109 | ) -> Self { 110 | Self::TokenFieldCheck { field, op, value } 111 | } 112 | pub fn root_len(&self, sleigh: &Sleigh) -> usize { 113 | match self { 114 | Verification::ContextCheck { .. } 115 | | Verification::TableBuild { .. } => 0, 116 | Verification::TokenFieldCheck { 117 | field, 118 | op: _, 119 | value: _, 120 | } => { 121 | let field = sleigh.token_field(*field); 122 | let token = sleigh.token(field.token); 123 | let bytes: usize = token.len_bytes.get().try_into().unwrap(); 124 | bytes * 8usize 125 | } 126 | Verification::SubPattern { 127 | location: _, 128 | pattern, 129 | } => pattern.root_len(sleigh), 130 | } 131 | } 132 | pub fn tables<'a>( 133 | &'a self, 134 | ) -> Option + 'a> { 135 | match self { 136 | Self::TokenFieldCheck { .. } | Self::ContextCheck { .. } => None, 137 | Self::TableBuild { 138 | produced_table, 139 | verification: _, 140 | } => { 141 | let iter: Box> = 142 | Box::new([produced_table].into_iter()); 143 | Some(iter) 144 | } 145 | Self::SubPattern { 146 | location: _, 147 | pattern, 148 | } => { 149 | let iter: Box> = Box::new( 150 | pattern 151 | .blocks 152 | .iter() 153 | .flat_map(|block| block.base.tables.values()), 154 | ); 155 | Some(iter) 156 | } 157 | } 158 | } 159 | pub fn token_field_check(&self) -> Option { 160 | match self { 161 | Self::TokenFieldCheck { field, .. } => Some(*field), 162 | Self::ContextCheck { .. } 163 | | Self::TableBuild { .. } 164 | | Self::SubPattern { .. } => None, 165 | } 166 | } 167 | pub fn sub_pattern(&self) -> Option<&Pattern> { 168 | match self { 169 | Self::TokenFieldCheck { .. } 170 | | Self::ContextCheck { .. } 171 | | Self::TableBuild { .. } => None, 172 | Self::SubPattern { 173 | location: _, 174 | pattern, 175 | } => Some(pattern), 176 | } 177 | } 178 | pub fn sub_pattern_mut(&mut self) -> Option<&mut Pattern> { 179 | match self { 180 | Self::TokenFieldCheck { .. } 181 | | Self::ContextCheck { .. } 182 | | Self::TableBuild { .. } => None, 183 | Self::SubPattern { 184 | location: _, 185 | pattern, 186 | } => Some(pattern), 187 | } 188 | } 189 | pub fn pattern_len( 190 | &self, 191 | sleigh: &Sleigh, 192 | ) -> Option { 193 | match self { 194 | Self::ContextCheck { .. } => { 195 | Some(ConstructorPatternLen::Basic(PatternLen::Defined(0))) 196 | } 197 | Self::TableBuild { 198 | produced_table: 199 | ProducedTable { 200 | table, 201 | location: _, 202 | always: _, 203 | recursive: true, 204 | }, 205 | verification: _, 206 | } => match sleigh.table(*table).pattern_len() { 207 | //if the table len is known, return it 208 | Some(table_len) => Some(table_len.into()), 209 | //otherwise the indication that this is a recursive 210 | None => Some(ConstructorPatternLen::NonGrowingRecursive( 211 | PatternLen::Defined(0), 212 | )), 213 | }, 214 | Self::TableBuild { 215 | produced_table: 216 | ProducedTable { 217 | table, 218 | location: _, 219 | always: _, 220 | recursive: false, 221 | }, 222 | verification: _, 223 | } => sleigh 224 | .table(*table) 225 | .pattern_len() 226 | .map(ConstructorPatternLen::Basic), 227 | Self::TokenFieldCheck { 228 | field, 229 | op: _, 230 | value: _, 231 | } => { 232 | let field = sleigh.token_field(*field); 233 | let token = sleigh.token(field.token); 234 | Some(ConstructorPatternLen::Basic(PatternLen::Defined( 235 | token.len_bytes.get(), 236 | ))) 237 | } 238 | Self::SubPattern { 239 | location: _, 240 | pattern, 241 | } => pattern.len, 242 | } 243 | } 244 | pub fn variants_number(&self) -> usize { 245 | match self { 246 | Self::SubPattern { pattern, .. } => pattern.variants_num(), 247 | _ => 1, 248 | } 249 | } 250 | pub fn convert(self) -> FinalVerification { 251 | match self { 252 | Verification::ContextCheck { context, op, value } => { 253 | FinalVerification::ContextCheck { context, op, value } 254 | } 255 | Verification::TableBuild { 256 | produced_table, 257 | verification, 258 | } => FinalVerification::TableBuild { 259 | produced_table, 260 | verification, 261 | }, 262 | Verification::TokenFieldCheck { field, op, value } => { 263 | FinalVerification::TokenFieldCheck { field, op, value } 264 | } 265 | Verification::SubPattern { location, pattern } => { 266 | FinalVerification::SubPattern { 267 | location, 268 | pattern: pattern.convert(), 269 | } 270 | } 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/semantic/inner/pcode_macro.rs: -------------------------------------------------------------------------------- 1 | use crate::execution::DynamicValueType; 2 | use crate::semantic::execution::{BlockId, Build, VariableId}; 3 | use crate::varnode::ContextAttach; 4 | use crate::{syntax, ExecutionError, PcodeMacroError, SleighError, Span}; 5 | 6 | use super::execution::{Execution, ExecutionBuilder, ReadScope, WriteValue}; 7 | use super::pattern::Pattern; 8 | use super::{GlobalScope, PcodeMacroId, Sleigh}; 9 | 10 | #[derive(Clone, Debug)] 11 | pub struct PcodeMacro { 12 | pub name: String, 13 | pub params: Vec, 14 | pub execution: Execution, 15 | pub location: Span, 16 | //TODO: export macro is a thing? 17 | } 18 | 19 | impl PcodeMacro { 20 | pub fn new( 21 | name: String, 22 | src: Span, 23 | params: Vec, 24 | execution: Execution, 25 | ) -> Self { 26 | Self { 27 | name, 28 | params, 29 | execution, 30 | location: src, 31 | } 32 | } 33 | } 34 | 35 | pub struct Builder<'a, 'b> { 36 | execution: &'b mut Execution, 37 | current_block: BlockId, 38 | 39 | sleigh: &'a Sleigh, 40 | } 41 | 42 | impl<'a, 'b> Builder<'a, 'b> { 43 | fn parse( 44 | sleigh: &'a Sleigh, 45 | execution: &'b mut Execution, 46 | body: syntax::block::execution::Execution, 47 | ) -> Result<(), Box> { 48 | let current_block = execution.entry_block; 49 | let mut builder = Self { 50 | execution, 51 | current_block, 52 | sleigh, 53 | }; 54 | builder.extend(body)?; 55 | Ok(()) 56 | } 57 | } 58 | 59 | impl ExecutionBuilder for Builder<'_, '_> { 60 | fn sleigh(&self) -> &Sleigh { 61 | self.sleigh 62 | } 63 | fn pattern(&self) -> &Pattern { 64 | unreachable!() 65 | } 66 | fn execution(&self) -> &Execution { 67 | self.execution 68 | } 69 | fn execution_mut(&mut self) -> &mut Execution { 70 | self.execution 71 | } 72 | fn read_scope( 73 | &mut self, 74 | name: &str, 75 | src: &Span, 76 | ) -> Result> { 77 | //check local scope 78 | if let Some(var) = self.execution().variable_by_name(name) { 79 | return Ok(ReadScope::ExeVar(var)); 80 | } 81 | 82 | // check global scope 83 | use super::GlobalScope::*; 84 | match self 85 | .sleigh 86 | .get_global(name) 87 | .ok_or_else(|| Box::new(ExecutionError::MissingRef(src.clone())))? 88 | { 89 | TokenField(x) => Ok(ReadScope::TokenField(x)), 90 | InstStart(_) => Ok(ReadScope::InstStart), 91 | InstNext(_) => Ok(ReadScope::InstNext), 92 | Varnode(x) => Ok(ReadScope::Varnode(x)), 93 | Context(x) => Ok(ReadScope::Context(x)), 94 | Bitrange(x) => Ok(ReadScope::Bitrange(x)), 95 | _ => Err(Box::new(ExecutionError::InvalidRef(src.clone()))), 96 | } 97 | } 98 | 99 | fn write_scope( 100 | &mut self, 101 | name: &str, 102 | src: &Span, 103 | ) -> Result> { 104 | //check local scope 105 | if let Some(var) = self.execution().variable_by_name(name) { 106 | return Ok(WriteValue::Local { 107 | id: var, 108 | creation: false, 109 | }); 110 | } 111 | // 112 | //at last check the global scope 113 | use super::GlobalScope::*; 114 | match self 115 | .sleigh 116 | .get_global(name) 117 | .ok_or_else(|| Box::new(ExecutionError::MissingRef(src.clone())))? 118 | { 119 | GlobalScope::Context(context_id) => { 120 | //filter field with meaning to variable 121 | let meaning = self.sleigh().context(context_id).attach; 122 | let Some(ContextAttach::Varnode(attach_id)) = meaning else { 123 | return Err(Box::new(ExecutionError::InvalidRef( 124 | src.clone(), 125 | ))); 126 | }; 127 | Ok(WriteValue::DynVarnode { 128 | value_id: DynamicValueType::Context(context_id), 129 | attach_id, 130 | }) 131 | } 132 | Varnode(x) => Ok(WriteValue::Varnode(x)), 133 | Bitrange(x) => Ok(WriteValue::Bitrange(x)), 134 | _ => Err(Box::new(ExecutionError::InvalidRef(src.clone()))), 135 | } 136 | } 137 | 138 | fn current_block(&self) -> BlockId { 139 | self.current_block 140 | } 141 | 142 | fn set_current_block(&mut self, block: BlockId) { 143 | self.current_block = block 144 | } 145 | 146 | //macro have no build statement, so if try to parse it, is always error 147 | fn new_build( 148 | &mut self, 149 | _input: syntax::block::execution::Build, 150 | ) -> Result> { 151 | Err(Box::new(ExecutionError::MacroBuildInvalid)) 152 | } 153 | 154 | fn inner_set_curent_block(&mut self, block: BlockId) { 155 | self.current_block = block 156 | } 157 | } 158 | 159 | impl Sleigh { 160 | pub fn create_pcode_macro( 161 | &mut self, 162 | pcode: syntax::block::pcode_macro::PcodeMacro, 163 | ) -> Result<(), Box> { 164 | let mut execution = Execution::new_empty(pcode.src.clone()); 165 | //create variables for each param 166 | let params = pcode 167 | .params 168 | .into_iter() 169 | .map(|(name, src)| { 170 | execution.create_variable(name, src.clone(), None, false) 171 | }) 172 | .collect::>() 173 | .map_err(|e| { 174 | Box::new(SleighError::new_pcode_macro(pcode.src.clone(), *e)) 175 | })?; 176 | Builder::parse(self, &mut execution, pcode.body).map_err(|e| { 177 | Box::new(SleighError::new_pcode_macro(pcode.src.clone(), *e)) 178 | })?; 179 | let pcode_macro = PcodeMacro::new( 180 | pcode.name.clone(), 181 | pcode.src.clone(), 182 | params, 183 | execution, 184 | ); 185 | self.pcode_macros.push(pcode_macro); 186 | let pcode_macro_id = PcodeMacroId(self.pcode_macros.len() - 1); 187 | self.global_scope 188 | .insert(pcode.name, GlobalScope::PcodeMacro(pcode_macro_id)) 189 | .map(|_| Err(Box::new(SleighError::NameDuplicated))) 190 | .unwrap_or(Ok(())) 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/semantic/inner/space.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::space::SpaceType; 2 | use crate::semantic::{Space, SpaceId}; 3 | use crate::{syntax, SleighError}; 4 | 5 | use super::{GlobalScope, Sleigh}; 6 | 7 | impl Sleigh { 8 | pub fn create_space( 9 | &mut self, 10 | input: syntax::define::Space, 11 | ) -> Result<(), Box> { 12 | let src = input.src; 13 | let (mut default, mut addr_size, mut wordsize, mut space_type) = 14 | (false, None, None, None); 15 | for att in input.attributes.into_iter() { 16 | use syntax::define::Attribute::*; 17 | match att { 18 | Type(x) if space_type.is_none() => space_type = Some(x), 19 | Size(x) if addr_size.is_none() => addr_size = Some(x), 20 | WordSize(x) if wordsize.is_none() => wordsize = Some(x), 21 | Default if !default => default = true, 22 | _ => return Err(Box::new(SleighError::SpaceInvalidAtt(src))), 23 | } 24 | } 25 | let word_size = wordsize.unwrap_or(1).try_into().map_err(|_| { 26 | Box::new(SleighError::SpaceMissingSize(src.clone())) 27 | })?; 28 | let addr_size = match addr_size.ok_or_else(|| { 29 | Box::new(SleighError::SpaceMissingSize(src.clone())) 30 | })? { 31 | 0 => { 32 | return Err(Box::new(SleighError::SpaceInvalidSize( 33 | src.clone(), 34 | ))) 35 | } 36 | x => x.try_into().map_err(|_| { 37 | Box::new(SleighError::SpaceInvalidSize(src.clone())) 38 | })?, 39 | }; 40 | let space_type = space_type.unwrap_or(SpaceType::Register); 41 | let space = Space { 42 | src, 43 | space_type, 44 | wordsize: word_size, 45 | addr_bytes: addr_size, 46 | }; 47 | self.spaces.push(space); 48 | let space_id = SpaceId(self.spaces.len() - 1); 49 | if default { 50 | self.default_space 51 | .replace(space_id) 52 | .map(|_| Err(Box::new(SleighError::SpaceMultipleDefault))) 53 | .unwrap_or(Ok(()))?; 54 | } 55 | self.global_scope 56 | .insert(input.name, GlobalScope::Space(space_id)) 57 | .map(|_| Err(Box::new(SleighError::NameDuplicated))) 58 | .unwrap_or(Ok(())) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/semantic/inner/table/execution.rs: -------------------------------------------------------------------------------- 1 | use crate::execution::DynamicValueType; 2 | use crate::semantic::execution::BlockId; 3 | use crate::semantic::inner::execution::{ 4 | Execution, ExecutionBuilder, ReadScope, WriteValue, 5 | }; 6 | use crate::semantic::inner::pattern::Pattern; 7 | use crate::semantic::inner::Sleigh; 8 | use crate::semantic::token::TokenFieldAttach; 9 | use crate::varnode::ContextAttach; 10 | use crate::{ExecutionError, Span}; 11 | 12 | #[derive(Debug)] 13 | pub struct Builder<'a> { 14 | execution: Execution, 15 | current_block: BlockId, 16 | 17 | sleigh: &'a Sleigh, 18 | pattern: &'a mut Pattern, 19 | } 20 | 21 | impl<'a> Builder<'a> { 22 | pub fn new( 23 | sleigh: &'a Sleigh, 24 | pattern: &'a mut Pattern, 25 | src: Span, 26 | ) -> Self { 27 | let execution = Execution::new_empty(src); 28 | let current_block = execution.entry_block; 29 | Self { 30 | execution, 31 | current_block, 32 | sleigh, 33 | pattern, 34 | } 35 | } 36 | } 37 | 38 | impl<'a> From> for Execution { 39 | fn from(input: Builder<'a>) -> Self { 40 | input.execution 41 | } 42 | } 43 | 44 | impl ExecutionBuilder for Builder<'_> { 45 | fn sleigh(&self) -> &Sleigh { 46 | self.sleigh 47 | } 48 | fn execution(&self) -> &Execution { 49 | &self.execution 50 | } 51 | fn execution_mut(&mut self) -> &mut Execution { 52 | &mut self.execution 53 | } 54 | fn pattern(&self) -> &Pattern { 55 | self.pattern 56 | } 57 | fn read_scope( 58 | &mut self, 59 | name: &str, 60 | src: &Span, 61 | ) -> Result> { 62 | //check local scope 63 | if let Some(var) = self.execution().variable_by_name(name) { 64 | return Ok(ReadScope::ExeVar(var)); 65 | } 66 | 67 | //check the disassembly scope 68 | if let Some(var) = self.pattern.disassembly_variable_names.get(name) { 69 | return Ok(ReadScope::DisVar(*var)); 70 | } 71 | 72 | //lastly check the global scope 73 | use super::GlobalScope::*; 74 | match self 75 | .sleigh 76 | .get_global(name) 77 | .ok_or_else(|| Box::new(ExecutionError::MissingRef(src.clone())))? 78 | { 79 | //TODO make sure all fields used on execution can be 80 | //produced by the pattern 81 | TokenField(x) => Ok(ReadScope::TokenField(x)), 82 | InstStart(_) => Ok(ReadScope::InstStart), 83 | InstNext(_) => Ok(ReadScope::InstNext), 84 | Varnode(x) => Ok(ReadScope::Varnode(x)), 85 | Bitrange(x) => Ok(ReadScope::Bitrange(x)), 86 | Context(x) => Ok(ReadScope::Context(x)), 87 | //only if table export some kind of value 88 | Table(table_id) 89 | if self 90 | .sleigh() 91 | .table(table_id) 92 | .export 93 | .borrow() 94 | .as_ref() 95 | .map(|x| !x.export_nothing()) 96 | .unwrap_or(false) => 97 | { 98 | Ok(ReadScope::Table(table_id)) 99 | } 100 | _ => Err(Box::new(ExecutionError::InvalidRef(src.clone()))), 101 | } 102 | } 103 | 104 | fn write_scope( 105 | &mut self, 106 | name: &str, 107 | src: &Span, 108 | ) -> Result> { 109 | if let Some(var) = self.execution().variable_by_name(name) { 110 | return Ok(WriteValue::Local { 111 | id: var, 112 | creation: false, 113 | }); 114 | } 115 | use super::GlobalScope; 116 | match self 117 | .sleigh 118 | .get_global(name) 119 | .ok_or_else(|| Box::new(ExecutionError::MissingRef(src.clone())))? 120 | { 121 | GlobalScope::Varnode(varnode) => Ok(WriteValue::Varnode(varnode)), 122 | GlobalScope::TokenField(token_field_id) => { 123 | //filter field with meaning to variable 124 | let meaning = self.sleigh().token_field(token_field_id).attach; 125 | let Some(TokenFieldAttach::Varnode(attach_id)) = meaning else { 126 | return Err(Box::new(ExecutionError::InvalidRef( 127 | src.clone(), 128 | ))); 129 | }; 130 | Ok(WriteValue::DynVarnode { 131 | value_id: DynamicValueType::TokenField(token_field_id), 132 | attach_id, 133 | }) 134 | } 135 | GlobalScope::Context(context_id) => { 136 | //filter field with meaning to variable 137 | let meaning = self.sleigh().context(context_id).attach; 138 | let Some(ContextAttach::Varnode(attach_id)) = meaning else { 139 | return Err(Box::new(ExecutionError::InvalidRef( 140 | src.clone(), 141 | ))); 142 | }; 143 | Ok(WriteValue::DynVarnode { 144 | value_id: DynamicValueType::Context(context_id), 145 | attach_id, 146 | }) 147 | } 148 | GlobalScope::Table(table_id) => { 149 | Ok(WriteValue::TableExport(table_id)) 150 | } 151 | _ => Err(Box::new(ExecutionError::InvalidRef(src.clone()))), 152 | } 153 | } 154 | 155 | fn current_block(&self) -> BlockId { 156 | self.current_block 157 | } 158 | fn inner_set_curent_block(&mut self, block: BlockId) { 159 | self.current_block = block 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/semantic/inner/token.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::meaning::Meaning; 2 | use crate::semantic::token::{TokenField as FinalTokenField, TokenFieldAttach}; 3 | use crate::semantic::{ 4 | NumberNonZeroUnsigned, PrintBase, SleighError, Span, Token, TokenFieldId, 5 | TokenId, 6 | }; 7 | use crate::{syntax, FieldBits}; 8 | 9 | use super::{GlobalScope, PrintFlags, Sleigh}; 10 | 11 | pub struct TokenField { 12 | pub name: String, 13 | pub location: Span, 14 | pub bits: FieldBits, 15 | pub token: TokenId, 16 | pub print_flags: PrintFlags, 17 | pub attach: Option, 18 | } 19 | 20 | impl std::fmt::Debug for TokenField { 21 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 22 | write!(f, "TokenField bit_range: ({:?})", self.bits,) 23 | } 24 | } 25 | 26 | impl TokenField { 27 | pub fn attach(&mut self, meaning: Meaning) -> Result<(), Box> { 28 | if self.attach.is_some() { 29 | //once attached, can't attach again 30 | return Err(Box::new(SleighError::AttachMultiple( 31 | self.location.clone(), 32 | ))); 33 | } 34 | if self.print_flags.signed_set { 35 | todo!("Is allowed to attach to signed value?"); 36 | } 37 | if meaning.is_number() && self.print_flags.base.is_some() { 38 | todo!("Is allowed to attach varnode/literal if base is set?"); 39 | } 40 | let attach = match meaning { 41 | Meaning::NoAttach(_) => unreachable!(), 42 | Meaning::Varnode(x) => TokenFieldAttach::Varnode(x), 43 | Meaning::Literal(x) => TokenFieldAttach::Literal(x), 44 | // use the default print base for TokenField with attach number: Hex 45 | Meaning::Number(_, x) => TokenFieldAttach::Number( 46 | self.print_flags.base.unwrap_or(PrintBase::Hex), 47 | x, 48 | ), 49 | }; 50 | //TODO what if print_flags are set? 51 | self.attach = Some(attach); 52 | Ok(()) 53 | } 54 | 55 | pub fn convert(self) -> FinalTokenField { 56 | //default to literal if unset 57 | let attach = self 58 | .attach 59 | .unwrap_or(TokenFieldAttach::NoAttach(self.print_flags.into())); 60 | FinalTokenField { 61 | name: self.name.into(), 62 | location: self.location, 63 | bits: self.bits, 64 | token: self.token, 65 | attach, 66 | } 67 | } 68 | } 69 | 70 | impl Sleigh { 71 | pub fn create_token( 72 | &mut self, 73 | input: syntax::define::Token, 74 | ) -> Result<(), Box> { 75 | let size = input 76 | .size 77 | .checked_div(8) 78 | .and_then(NumberNonZeroUnsigned::new) 79 | .ok_or_else(|| { 80 | SleighError::TokenFieldSizeInvalid(input.src.clone()) 81 | })?; 82 | let endian = input 83 | .endian 84 | .or(self.endian) 85 | .expect("Global endian undefined at this point is a logical error"); 86 | let token = Token { 87 | location: input.src.clone(), 88 | len_bytes: size, 89 | endian, 90 | name: input.name.clone().into(), 91 | }; 92 | self.tokens.push(token); 93 | let token_id = TokenId(self.tokens.len() - 1); 94 | self.global_scope 95 | .insert(input.name, GlobalScope::Token(token_id)) 96 | .map(|_| Err(SleighError::NameDuplicated)) 97 | .unwrap_or(Ok(()))?; 98 | 99 | for field in input.token_fields.into_iter() { 100 | let range: FieldBits = field.range.try_into()?; 101 | let print_flags = PrintFlags::from_token_att( 102 | &input.src, 103 | field.attributes.iter(), 104 | )?; 105 | //default into print in hex format 106 | let token_field = TokenField { 107 | name: field.name.clone(), 108 | location: field.name_span, 109 | bits: range, 110 | token: token_id, 111 | print_flags, 112 | attach: None, 113 | }; 114 | self.token_fields.push(token_field); 115 | let token_field_id = TokenFieldId(self.token_fields.len() - 1); 116 | self.global_scope 117 | .insert(field.name, GlobalScope::TokenField(token_field_id)) 118 | .map(|_| Err(SleighError::NameDuplicated)) 119 | .unwrap_or(Ok(()))?; 120 | } 121 | Ok(()) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/semantic/inner/varnode.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::meaning::Meaning; 2 | use crate::semantic::varnode::ContextAttach; 3 | use crate::semantic::Context as FinalContext; 4 | use crate::semantic::{ 5 | syntax, Bitrange, BitrangeId, ContextId, UserFunction, UserFunctionId, 6 | Varnode, VarnodeId, 7 | }; 8 | use crate::{FieldBits, NumberNonZeroUnsigned, NumberUnsigned, SleighError}; 9 | 10 | use super::{GlobalScope, PrintFlags, Sleigh}; 11 | 12 | #[derive(Debug)] 13 | pub struct Context { 14 | pub name: String, 15 | pub bitrange: Bitrange, 16 | pub noflow_set: bool, 17 | pub print_flags: PrintFlags, 18 | pub attach: Option, 19 | } 20 | 21 | impl Context { 22 | pub fn attach(&mut self, meaning: Meaning) -> Result<(), Box> { 23 | if self.attach.is_some() { 24 | //once attached, can't attach again 25 | return Err(Box::new(SleighError::AttachMultiple( 26 | self.bitrange.location.clone(), 27 | ))); 28 | } 29 | if self.print_flags.signed_set { 30 | todo!("Is allowed to attach to signed value?"); 31 | } 32 | if meaning.is_number() && self.print_flags.base.is_some() { 33 | todo!("Is allowed to attach varnode/literal if base is set?"); 34 | } 35 | let attach = match meaning { 36 | Meaning::NoAttach(_) => unreachable!(), 37 | Meaning::Varnode(x) => ContextAttach::Varnode(x), 38 | Meaning::Literal(x) => ContextAttach::Literal(x), 39 | Meaning::Number(_, _x) => { 40 | // attach to number is uncessary, probably a mistake 41 | return Err(Box::new(SleighError::ContextAttachNumber( 42 | self.bitrange.location.clone(), 43 | ))); 44 | } 45 | }; 46 | //TODO what if print_flags are set? 47 | self.attach = Some(attach); 48 | Ok(()) 49 | } 50 | 51 | pub fn convert(self) -> FinalContext { 52 | //default to literal if unset 53 | let attach = self 54 | .attach 55 | .unwrap_or(ContextAttach::NoAttach(self.print_flags.into())); 56 | FinalContext { 57 | name: self.name.into(), 58 | bitrange: self.bitrange, 59 | noflow: self.noflow_set, 60 | attach, 61 | } 62 | } 63 | } 64 | 65 | impl Sleigh { 66 | pub fn create_memory( 67 | &mut self, 68 | varnode: syntax::define::Varnode, 69 | ) -> Result<(), Box> { 70 | let space = self 71 | .get_global(&varnode.space_name) 72 | .ok_or_else(|| { 73 | Box::new(SleighError::SpaceUndefined( 74 | varnode.space_span.clone(), 75 | )) 76 | })? 77 | .space() 78 | .ok_or_else(|| { 79 | Box::new(SleighError::SpaceInvalid(varnode.space_span.clone())) 80 | })?; 81 | let varnode_bytes = NumberNonZeroUnsigned::new(varnode.value_bytes) 82 | .ok_or_else(|| { 83 | Box::new(SleighError::VarnodeInvalidSize( 84 | varnode.space_span.clone(), 85 | )) 86 | })?; 87 | 88 | if varnode.names.is_empty() { 89 | //TODO verify that on syntax parsing? 90 | todo!("TODO ERROR here") 91 | } 92 | for (index, (varnode_name, location)) in 93 | varnode.names.into_iter().enumerate() 94 | { 95 | let Some(varnode_name) = varnode_name else { 96 | // no varnode at this address, next one 97 | continue; 98 | }; 99 | let address = varnode.offset 100 | + (index as NumberUnsigned * varnode_bytes.get()); 101 | let location = location.clone(); 102 | let varnode = Varnode { 103 | name: varnode_name.clone().into(), 104 | location, 105 | address, 106 | len_bytes: varnode_bytes, 107 | space, 108 | }; 109 | self.varnodes.push(varnode); 110 | let varnode_id = 111 | unsafe { VarnodeId::from_raw(self.varnodes.len() - 1) }; 112 | self.global_scope 113 | .insert(varnode_name, GlobalScope::Varnode(varnode_id)) 114 | .map(|_| Err(Box::new(SleighError::NameDuplicated))) 115 | .unwrap_or(Ok(()))?; 116 | } 117 | Ok(()) 118 | } 119 | pub fn create_bitrange( 120 | &mut self, 121 | bitrange: syntax::define::BitRangeDef, 122 | ) -> Result<(), Box> { 123 | for field in bitrange.into_iter() { 124 | let varnode_id = self 125 | .get_global(&field.varnode_name) 126 | .ok_or_else(|| { 127 | Box::new(SleighError::VarnodeUndefined(field.src.clone())) 128 | })? 129 | .varnode() 130 | .ok_or_else(|| { 131 | Box::new(SleighError::VarnodeInvalid(field.src.clone())) 132 | })?; 133 | let varnode = self.varnode(varnode_id); 134 | let bits: FieldBits = field.range.try_into()?; 135 | 136 | //bitrange need to point to a varnode, we allow anything that have a 137 | //value_size, but tecnicatly we need to verify if this point to a 138 | //varnode, but I'm not doing this right now... 139 | let varnode_size = varnode.len_bytes.get() * 8; 140 | //bitrange can't be bigger than the varnode 141 | if bits.field_min_len().get() > varnode_size { 142 | return Err(Box::new(SleighError::VarnodeInvalidSize( 143 | field.src.clone(), 144 | ))); 145 | } 146 | 147 | let bitrange = Bitrange { 148 | location: field.src, 149 | bits, 150 | varnode: varnode_id, 151 | }; 152 | 153 | self.bitranges.push(bitrange); 154 | let bitrange_id = BitrangeId(self.bitranges.len() - 1); 155 | self.global_scope 156 | .insert(field.name, GlobalScope::Bitrange(bitrange_id)) 157 | .map(|_| Err(Box::new(SleighError::NameDuplicated))) 158 | .unwrap_or(Ok(()))?; 159 | } 160 | Ok(()) 161 | } 162 | pub fn create_user_function( 163 | &mut self, 164 | input: syntax::define::UserFunction, 165 | ) -> Result<(), Box> { 166 | let user_function = 167 | UserFunction::new(input.name.clone().into(), input.src); 168 | self.user_functions.push(user_function); 169 | let user_function_id = UserFunctionId(self.user_functions.len() - 1); 170 | self.global_scope 171 | .insert(input.name, GlobalScope::UserFunction(user_function_id)) 172 | .map(|_| Err(Box::new(SleighError::NameDuplicated))) 173 | .unwrap_or(Ok(())) 174 | } 175 | pub fn create_context( 176 | &mut self, 177 | input: syntax::define::Context, 178 | ) -> Result<(), Box> { 179 | let varnode_id = self 180 | .get_global(&input.varnode_name) 181 | .ok_or_else(|| { 182 | Box::new(SleighError::VarnodeUndefined( 183 | input.varnode_span.clone(), 184 | )) 185 | })? 186 | .varnode() 187 | .ok_or_else(|| { 188 | Box::new(SleighError::VarnodeInvalid( 189 | input.varnode_span.clone(), 190 | )) 191 | })?; 192 | let varnode_len_bits = self.varnode(varnode_id).len_bytes.get() * 8; 193 | for field in input.fields.into_iter() { 194 | //check for valid range 195 | let bits: FieldBits = field.range.try_into()?; 196 | //don't need make checked add/sub, don't question it 197 | //range can't be bigger than the varnode 198 | if bits.field_min_len().get() > varnode_len_bits { 199 | return Err(Box::new(SleighError::ContextInvalidSize( 200 | field.src.clone(), 201 | ))); 202 | } 203 | let print_flags = PrintFlags::from_token_att( 204 | &field.src, 205 | field.attributes.iter().filter_map(|att| match att { 206 | syntax::define::ContextFieldAttribute::Token(att) => { 207 | Some(att) 208 | } 209 | syntax::define::ContextFieldAttribute::Noflow => None, 210 | }), 211 | )?; 212 | //make sure that multiple noflow declaration is detected 213 | let noflow = field 214 | .attributes 215 | .iter() 216 | .filter(|att| { 217 | matches!(att, syntax::define::ContextFieldAttribute::Noflow) 218 | }) 219 | .count(); 220 | let noflow_set = match noflow { 221 | 0 => false, 222 | 1 => true, 223 | _ => { 224 | return Err(Box::new(SleighError::ContextAttDup( 225 | field.src.clone(), 226 | ))) 227 | } 228 | }; 229 | 230 | //default to hex print fmt 231 | let context = Context { 232 | name: field.name.clone(), 233 | bitrange: Bitrange { 234 | location: field.src, 235 | bits, 236 | varnode: varnode_id, 237 | }, 238 | noflow_set, 239 | print_flags, 240 | attach: None, 241 | }; 242 | self.contexts.push(context); 243 | let context_id = ContextId(self.contexts.len() - 1); 244 | self.global_scope 245 | .insert(field.name, GlobalScope::Context(context_id)) 246 | .map(|_| Err(Box::new(SleighError::NameDuplicated))) 247 | .unwrap_or(Ok(()))?; 248 | } 249 | Ok(()) 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/semantic/inner/with_block.rs: -------------------------------------------------------------------------------- 1 | use crate::{syntax, IDENT_INSTRUCTION}; 2 | 3 | //multiple with_blocks are combined into this one during the processing 4 | #[derive(Clone, Debug, Default)] 5 | pub(crate) struct WithBlockCurrent( 6 | Vec<( 7 | String, 8 | syntax::block::pattern::Pattern, 9 | Option, 10 | )>, 11 | ); 12 | 13 | impl WithBlockCurrent { 14 | pub fn push( 15 | &mut self, 16 | with_block: syntax::block::with_block::WithBlock, 17 | ) -> syntax::Sleigh { 18 | //Inside a with block that has a table header, a nested with block may 19 | //specify the instruction table by name, as in 20 | //"with instruction : {...}". Inside such a block, the rule regarding 21 | //mnemonic literals is restored (see Section 7.3.1, “Mnemonic”). 22 | self.0.push(( 23 | with_block.table_name().to_owned(), 24 | with_block.pattern, 25 | with_block.disassembly, 26 | )); 27 | with_block.body 28 | } 29 | pub fn pop(&mut self) { 30 | self.0.pop(); 31 | } 32 | 33 | pub fn table_name<'a>(&'a self, current_table_name: &'a str) -> &'a str { 34 | //From ghidra docs: 35 | //Note that when a with block has a table header specifying a table 36 | //that does not yet exist, the table is created immediately. Inside a 37 | //with block that has a table header, a nested with block may specify 38 | //the instruction table by name, as in "with instruction : {...}". 39 | //Inside such a block, the rule regarding mnemonic literals is restored. 40 | 41 | //if the name is specified, use it. 42 | if !current_table_name.is_empty() { 43 | return current_table_name; 44 | } 45 | 46 | //otherwise, if the table name is not specified, the table name will 47 | //depent on the block last table name, there are two possibilities: 48 | let with_block_table_name = self.0.last().map(|x| &x.0); 49 | match with_block_table_name { 50 | //there is a table name, so use it 51 | Some(name) => name, 52 | //there is no block, so the table default into the instruction 53 | //table 54 | None => IDENT_INSTRUCTION, 55 | } 56 | } 57 | fn pattern_iter( 58 | &self, 59 | ) -> impl ExactSizeIterator { 60 | self.0 61 | .iter() 62 | .map(|(_table_name, pattern, _disassembly)| pattern) 63 | } 64 | //Merge multiple patterns into a single one, obs: merge, not concat. 65 | //the last block of the first pattern is merged with the first block of 66 | //the second patter using the `And` operation. 67 | pub fn pattern( 68 | &self, 69 | constructor_pattern: &syntax::block::pattern::Pattern, 70 | ) -> syntax::block::pattern::Pattern { 71 | use syntax::block::pattern::Op; 72 | let patterns = self.pattern_iter().chain([constructor_pattern]); 73 | let block_number = 74 | self.pattern_iter().map(|p| p.blocks.len()).sum::() 75 | + constructor_pattern.blocks.len(); 76 | let mut final_pattern = syntax::block::pattern::Pattern { 77 | blocks: Vec::with_capacity(block_number), 78 | src: constructor_pattern.src.clone(), 79 | }; 80 | for pattern in patterns { 81 | let mut blocks = pattern.blocks.iter(); 82 | let first_block = blocks.next(); 83 | let last_block = final_pattern.blocks.last_mut(); 84 | //if there is a last_block on the final_pattern and a first_block 85 | //on the new_pattern, merge both into a single block 86 | match (first_block, last_block) { 87 | //no blocks to merge into the final pattern, do nothing 88 | (None, _) => continue, 89 | //there is no last block to be merged with the new blocks. 90 | //so just add this new block into the final pattern. 91 | (Some(first_block), None) => { 92 | final_pattern.blocks.extend([first_block.clone()]); 93 | } 94 | //merge the first_block (final_pattern) with the last_block 95 | //(new_pattern) 96 | (Some(first_block), Some(last_block)) => { 97 | //if the first and second blocks have diferent OPs, make the 98 | //second block a subpattern to avoid conflict. 99 | if first_block.op() != last_block.op() { 100 | last_block.elements.push(( 101 | Op::And, 102 | syntax::block::pattern::Element { 103 | field: 104 | syntax::block::pattern::Field::SubPattern( 105 | pattern.clone(), 106 | ), 107 | ellipsis: None, 108 | }, 109 | )); 110 | continue; 111 | } else { 112 | //last block will include all the elements from the first block of 113 | //the new pattern 114 | last_block 115 | .elements 116 | .extend([(Op::And, first_block.first.clone())]); 117 | last_block 118 | .elements 119 | .extend(first_block.elements.iter().cloned()); 120 | } 121 | } 122 | } 123 | //add all the other blocks without merging 124 | final_pattern.blocks.extend(blocks.cloned()); 125 | } 126 | final_pattern 127 | } 128 | pub fn disassembly( 129 | &self, 130 | current_pattern: Option, 131 | ) -> Option { 132 | self.0 133 | .iter() 134 | .filter_map(|x| x.2.as_ref()) 135 | .cloned() 136 | .chain([current_pattern].into_iter().flatten()) 137 | .reduce(|mut acc, x| { 138 | acc.assertations.extend(x.assertations); 139 | acc 140 | }) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/semantic/meaning.rs: -------------------------------------------------------------------------------- 1 | use crate::semantic::{ 2 | AttachLiteralId, AttachNumberId, AttachVarnodeId, VarnodeId, 3 | }; 4 | use crate::{Number, NumberNonZeroUnsigned, Sleigh}; 5 | 6 | use super::inner::execution::FieldSize; 7 | use super::{PrintBase, ValueFmt}; 8 | 9 | /// The value is translated with a varnode using this value as index. 10 | /// In Display, print the varnode name. 11 | /// In Disassembly, TODO: is unknown. 12 | /// In Execution, read/write are done on the underlying varnode. 13 | #[derive(Clone, Debug)] 14 | pub struct AttachVarnode(pub Box<[(usize, VarnodeId)]>); 15 | impl AttachVarnode { 16 | pub fn find_value(&self, index: usize) -> Option { 17 | self.0 18 | .iter() 19 | .find(|(value_index, _value)| *value_index == index) 20 | .map(|(_, value)| *value) 21 | } 22 | 23 | pub fn len_bytes(&self, sleigh: &Sleigh) -> NumberNonZeroUnsigned { 24 | sleigh.varnode(self.0[0].1).len_bytes 25 | } 26 | } 27 | 28 | /// The Value is translated into this string. Only affect the value when it's 29 | /// printed 30 | #[derive(Clone, Debug)] 31 | pub struct AttachLiteral(pub Box<[(usize, String)]>); 32 | impl AttachLiteral { 33 | pub fn find_value(&self, index: usize) -> Option<&str> { 34 | self.0 35 | .iter() 36 | .find(|(value_index, _value)| *value_index == index) 37 | .map(|(_, value)| value.as_str()) 38 | } 39 | } 40 | 41 | /// The Value is translated into a signed value with this Format. 42 | /// In Display, print the translated value using this index. 43 | /// In Disassembly, TODO: is unknown. 44 | /// In Execution, the value is translanted and is automatically expanded to 45 | /// the required len. 46 | #[derive(Clone, Debug)] 47 | pub struct AttachNumber(pub Box<[(usize, Number)]>); 48 | impl AttachNumber { 49 | pub fn is_signed(&self) -> bool { 50 | self.0.iter().any(|(_i, v)| v.is_negative()) 51 | } 52 | 53 | pub fn find_value(&self, index: usize) -> Option { 54 | self.0 55 | .iter() 56 | .find(|(value_index, _value)| *value_index == index) 57 | .map(|(_, value)| *value) 58 | } 59 | 60 | pub fn bits_required(&self) -> u32 { 61 | self.0 62 | .iter() 63 | .map(|(_value_index, value)| value.bits_required()) 64 | .min() 65 | .unwrap() 66 | } 67 | } 68 | 69 | #[derive(Clone, Copy, Debug)] 70 | pub enum Meaning { 71 | NoAttach(ValueFmt), 72 | Varnode(AttachVarnodeId), 73 | Literal(AttachLiteralId), 74 | Number(PrintBase, AttachNumberId), 75 | } 76 | 77 | impl Meaning { 78 | pub fn is_varnode(&self) -> bool { 79 | matches!(self, Self::Varnode(_)) 80 | } 81 | pub fn is_literal(&self) -> bool { 82 | matches!(self, Self::Literal(_)) 83 | } 84 | pub fn is_number(&self) -> bool { 85 | matches!(self, Self::Number(_, _)) 86 | } 87 | #[deprecated] 88 | pub fn execution_len( 89 | &self, 90 | sleigh: &super::inner::Sleigh, 91 | ) -> Option { 92 | match self { 93 | // name don't change the value size 94 | Meaning::NoAttach(_) | Meaning::Literal(_) => None, 95 | Meaning::Varnode(vars_id) => { 96 | let vars = sleigh.attach_varnode(*vars_id); 97 | let varnode_bits = 98 | sleigh.varnode(vars.0[0].1).len_bytes.get() * 8; 99 | Some(FieldSize::new_bits(varnode_bits.try_into().unwrap())) 100 | } 101 | Meaning::Number(_, values_id) => { 102 | let values = sleigh.attach_number(*values_id); 103 | let len_bits = values 104 | .0 105 | .iter() 106 | .map(|(_i, v)| v.bits_required()) 107 | .max() 108 | .unwrap(); 109 | let len_bits = 110 | NumberNonZeroUnsigned::new(len_bits.into()).unwrap(); 111 | Some(FieldSize::default().set_min_bits(len_bits).unwrap()) 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/semantic/space.rs: -------------------------------------------------------------------------------- 1 | use crate::{NumberNonZeroUnsigned, Span}; 2 | 3 | #[derive(Clone, Debug)] 4 | pub struct Space { 5 | pub src: Span, 6 | pub space_type: SpaceType, 7 | ///wordsize len in bytes, AKA number of bytes that each address store, 8 | ///usually memory store only a u8 for each address, but kinds of memory 9 | ///can store more that one byte for each address. 10 | pub wordsize: NumberNonZeroUnsigned, 11 | ///address len in bytes, eg 4bytes in 32bits arch and 8bytes in a 64bits 12 | pub addr_bytes: NumberNonZeroUnsigned, 13 | } 14 | impl Space { 15 | pub fn can_write(&self) -> bool { 16 | self.space_type.can_write() 17 | } 18 | } 19 | 20 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] 21 | pub enum SpaceType { 22 | Ram, 23 | Rom, 24 | Register, 25 | } 26 | 27 | impl SpaceType { 28 | pub fn can_write(&self) -> bool { 29 | match self { 30 | SpaceType::Rom => false, 31 | SpaceType::Ram | SpaceType::Register => true, 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/semantic/table.rs: -------------------------------------------------------------------------------- 1 | use super::execution::ExportLen; 2 | use crate::pattern::BitConstraint; 3 | use crate::semantic::display::Display; 4 | use crate::semantic::execution::Execution; 5 | use crate::semantic::pattern::{Pattern, PatternLen}; 6 | use crate::Span; 7 | 8 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 9 | pub struct ConstructorId(pub usize); 10 | 11 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 12 | pub struct VariantId(pub usize); 13 | 14 | #[derive(Clone, Debug)] 15 | pub struct Constructor { 16 | pub pattern: Pattern, 17 | pub display: Display, 18 | pub execution: Option, 19 | pub location: Span, 20 | // the bit pattern for all possible variants in the pattern, 21 | // impossible variants are simply not present here 22 | // TODO VariantId is the position on the vector, just use the index 23 | #[allow(clippy::type_complexity)] 24 | pub(crate) variants_bits: 25 | Box<[(VariantId, Box<[BitConstraint]>, Box<[BitConstraint]>)]>, 26 | } 27 | 28 | impl Constructor { 29 | pub fn variants( 30 | &self, 31 | ) -> impl Iterator 32 | { 33 | self.variants_bits 34 | .iter() 35 | .map(|(id, context, token)| (*id, context.as_ref(), token.as_ref())) 36 | } 37 | /// return the variant constraint for the context and pattern 38 | pub fn variant( 39 | &self, 40 | id: VariantId, 41 | ) -> (&[BitConstraint], &[BitConstraint]) { 42 | self.variants_bits 43 | .iter() 44 | .find(|(current, _, _)| *current == id) 45 | .map(|(_, c, t)| (c.as_ref(), t.as_ref())) 46 | .unwrap() 47 | } 48 | } 49 | 50 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 51 | pub struct Matcher { 52 | pub constructor: ConstructorId, 53 | pub variant_id: VariantId, 54 | } 55 | 56 | #[derive(Clone, Debug)] 57 | pub struct Table { 58 | pub(crate) name: Box, 59 | pub(crate) is_root: bool, 60 | pub(crate) constructors: Box<[Constructor]>, 61 | pub matcher_order: Box<[Matcher]>, 62 | pub export: Option, 63 | pub pattern_len: PatternLen, 64 | } 65 | 66 | impl Table { 67 | pub fn is_root(&self) -> bool { 68 | self.is_root 69 | } 70 | pub fn name(&self) -> &str { 71 | &self.name 72 | } 73 | pub fn constructors(&self) -> &[Constructor] { 74 | &self.constructors 75 | } 76 | pub fn constructor(&self, id: ConstructorId) -> &Constructor { 77 | &self.constructors[id.0] 78 | } 79 | pub fn matcher_order(&self) -> &[Matcher] { 80 | &self.matcher_order 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/semantic/token.rs: -------------------------------------------------------------------------------- 1 | use crate::meaning::Meaning; 2 | use crate::semantic::{ 3 | AttachLiteralId, AttachNumberId, AttachVarnodeId, PrintBase, TokenId, 4 | ValueFmt, 5 | }; 6 | use crate::{Endian, FieldBits, NumberNonZeroUnsigned, Sleigh, Span}; 7 | 8 | #[derive(Clone, Debug)] 9 | pub struct Token { 10 | pub(crate) name: Box, 11 | pub location: Span, 12 | pub len_bytes: NumberNonZeroUnsigned, 13 | pub endian: Endian, 14 | } 15 | 16 | #[derive(Clone, Debug)] 17 | pub struct TokenField { 18 | pub(crate) name: Box, 19 | pub location: Span, 20 | pub bits: FieldBits, 21 | pub token: TokenId, 22 | pub attach: TokenFieldAttach, 23 | } 24 | 25 | impl Token { 26 | pub fn name(&self) -> &str { 27 | &self.name 28 | } 29 | pub fn endian(&self) -> Endian { 30 | self.endian 31 | } 32 | pub fn len_bytes(&self) -> NumberNonZeroUnsigned { 33 | self.len_bytes 34 | } 35 | } 36 | 37 | impl TokenField { 38 | pub fn name(&self) -> &str { 39 | &self.name 40 | } 41 | pub fn raw_value_is_signed(&self) -> bool { 42 | match self.attach { 43 | TokenFieldAttach::NoAttach(fmt) => fmt.signed, 44 | TokenFieldAttach::Varnode(_) 45 | | TokenFieldAttach::Literal(_) 46 | | TokenFieldAttach::Number(_, _) => false, 47 | } 48 | } 49 | pub fn execution_value_is_signed(&self, sleigh: &Sleigh) -> bool { 50 | match self.attach { 51 | TokenFieldAttach::NoAttach(fmt) => fmt.signed, 52 | TokenFieldAttach::Varnode(_) | TokenFieldAttach::Literal(_) => { 53 | false 54 | } 55 | TokenFieldAttach::Number(_, value) => { 56 | sleigh.attach_number(value).is_signed() 57 | } 58 | } 59 | } 60 | 61 | pub fn meaning(&self) -> Meaning { 62 | match self.attach { 63 | TokenFieldAttach::NoAttach(fmt) => Meaning::NoAttach(fmt), 64 | TokenFieldAttach::Varnode(id) => Meaning::Varnode(id), 65 | TokenFieldAttach::Literal(id) => Meaning::Literal(id), 66 | TokenFieldAttach::Number(base, id) => Meaning::Number(base, id), 67 | } 68 | } 69 | } 70 | 71 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 72 | pub enum TokenFieldAttach { 73 | /// No attach, just use the raw value 74 | NoAttach(ValueFmt), 75 | Varnode(AttachVarnodeId), 76 | Literal(AttachLiteralId), 77 | Number(PrintBase, AttachNumberId), 78 | } 79 | -------------------------------------------------------------------------------- /src/semantic/user_function.rs: -------------------------------------------------------------------------------- 1 | use crate::Span; 2 | 3 | #[derive(Clone, Debug)] 4 | pub struct UserFunction { 5 | name: Box, 6 | location: Span, 7 | } 8 | 9 | impl UserFunction { 10 | pub(crate) fn new(name: Box, location: Span) -> Self { 11 | Self { name, location } 12 | } 13 | pub fn name(&self) -> &str { 14 | &self.name 15 | } 16 | pub fn location(&self) -> &Span { 17 | &self.location 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/semantic/varnode.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::meaning::Meaning; 4 | use crate::semantic::{ 5 | AttachLiteralId, AttachVarnodeId, SpaceId, ValueFmt, VarnodeId, 6 | }; 7 | use crate::{ 8 | ContextId, FieldBits, NumberNonZeroUnsigned, NumberUnsigned, Span, 9 | }; 10 | 11 | use super::inner::Sleigh; 12 | 13 | #[derive(Clone, Debug)] 14 | pub struct Bitrange { 15 | pub location: Span, 16 | pub bits: FieldBits, 17 | pub varnode: VarnodeId, 18 | } 19 | 20 | // Context is just bitrange with noflow and maybe attach 21 | #[derive(Clone, Debug)] 22 | pub struct Context { 23 | pub(crate) name: Box, 24 | pub bitrange: Bitrange, 25 | pub noflow: bool, 26 | pub attach: ContextAttach, 27 | } 28 | 29 | impl Context { 30 | pub fn name(&self) -> &str { 31 | &self.name 32 | } 33 | 34 | pub fn is_signed(&self) -> bool { 35 | match self.attach { 36 | ContextAttach::NoAttach(fmt) => fmt.signed, 37 | ContextAttach::Varnode(_) | ContextAttach::Literal(_) => false, 38 | } 39 | } 40 | 41 | pub fn meaning(&self) -> Meaning { 42 | match self.attach { 43 | ContextAttach::NoAttach(fmt) => Meaning::NoAttach(fmt), 44 | ContextAttach::Varnode(id) => Meaning::Varnode(id), 45 | ContextAttach::Literal(id) => Meaning::Literal(id), 46 | } 47 | } 48 | } 49 | 50 | #[derive(Clone, Copy, Debug)] 51 | pub enum ContextAttach { 52 | /// No attach, just use the raw value 53 | NoAttach(ValueFmt), 54 | /// The value translate into a varnode 55 | Varnode(AttachVarnodeId), 56 | /// The value translate into a string for printing 57 | Literal(AttachLiteralId), 58 | // NOTE AttachNumber don't make seense, just assign the correct value to 59 | // the context 60 | } 61 | 62 | #[derive(Clone, Debug)] 63 | pub struct Varnode { 64 | pub(crate) name: Box, 65 | pub location: Span, 66 | /// Address of this varnode in the Address Space 67 | pub address: NumberUnsigned, 68 | /// Size of the varnode in bytes 69 | pub len_bytes: NumberNonZeroUnsigned, 70 | /// AddressSpace this varnode belongs to 71 | pub space: SpaceId, 72 | } 73 | 74 | impl Varnode { 75 | pub fn name(&self) -> &str { 76 | &self.name 77 | } 78 | } 79 | 80 | /// Create a single and packed type for Context memory and it's mapping to the 81 | /// original memory. 82 | #[derive(Debug, Clone)] 83 | pub struct ContextMemoryMapping { 84 | pub(crate) mapping: HashMap, 85 | pub memory_bits: NumberUnsigned, 86 | } 87 | 88 | impl ContextMemoryMapping { 89 | pub(crate) fn map_all(sleigh: &Sleigh) -> Self { 90 | // 1. get all the contexts, separated by varnode 91 | let mut context_mapping: HashMap> = 92 | HashMap::new(); 93 | for (i, context) in sleigh.contexts.iter().enumerate() { 94 | context_mapping 95 | .entry(context.bitrange.varnode) 96 | .or_default() 97 | .push(ContextId(i)); 98 | } 99 | 100 | // 2. sort all the context by bit start, if same, sort by len 101 | for contexts in context_mapping.values_mut() { 102 | contexts.sort_unstable_by(|x, y| { 103 | let x = &sleigh.context(*x).bitrange.bits; 104 | let y = &sleigh.context(*y).bitrange.bits; 105 | match x.start().cmp(&y.start()) { 106 | std::cmp::Ordering::Equal => { 107 | x.len().get().cmp(&y.len().get()) 108 | } 109 | x => x, 110 | } 111 | }); 112 | } 113 | 114 | // 3. map all the bits into a single memory block, one varnode after the 115 | // other, removing empty spaces in between. 116 | let mut mem_mapping: Vec<(ContextId, FieldBits)> = 117 | Vec::with_capacity(sleigh.contexts.len()); 118 | for (_varnode_id, contexts) in context_mapping.into_iter() { 119 | for current_context_id in contexts.into_iter() { 120 | let current_context = 121 | &sleigh.context(current_context_id).bitrange.bits; 122 | let Some((last_context_id, last_bits)) = mem_mapping.last() 123 | else { 124 | // first mapping is just added at bit 0 125 | mem_mapping.push(( 126 | current_context_id, 127 | FieldBits::new(0, current_context.len().get()), 128 | )); 129 | continue; 130 | }; 131 | let last_context = 132 | &sleigh.context(*last_context_id).bitrange.bits; 133 | let current_context_start_bit = current_context.start(); 134 | //if the last entry intersect with the current, add using 135 | //the last position as offset, otherwise add from the end of the 136 | //last context 137 | let new_start = 138 | if last_context.end().get() > current_context_start_bit { 139 | let offset = 140 | current_context_start_bit - last_context.start(); 141 | last_bits.start() + offset 142 | } else { 143 | last_bits.end().get() 144 | }; 145 | mem_mapping.push(( 146 | current_context_id, 147 | FieldBits::new( 148 | new_start, 149 | new_start + current_context.len().get(), 150 | ), 151 | )); 152 | } 153 | } 154 | let memory_bits = mem_mapping 155 | .last() 156 | .map(|(_, last)| last.end().get()) 157 | .unwrap_or(0); 158 | Self { 159 | mapping: mem_mapping.into_iter().collect(), 160 | memory_bits, 161 | } 162 | } 163 | pub fn context(&self, id: ContextId) -> FieldBits { 164 | self.mapping.get(&id).unwrap().to_owned() 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/syntax/attach.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::combinator::{cut, eof, map}; 3 | use nom::sequence::{pair, preceded, terminated}; 4 | use nom::IResult; 5 | 6 | use crate::preprocessor::token::Token; 7 | use crate::{Number, SleighError, Span}; 8 | 9 | use super::parser::{ 10 | fieldlist, numberlist, registerlist, stringlist, this_ident, 11 | }; 12 | 13 | #[derive(Clone, Debug)] 14 | pub struct Attach { 15 | pub src: Span, 16 | pub fields: Vec<(String, Span)>, 17 | pub meaning: Meaning, 18 | } 19 | 20 | #[derive(Clone, Debug)] 21 | pub enum Meaning { 22 | Variable(Vec<(Option, Span)>), 23 | Name(Vec<(Option, Span)>), 24 | Number(Vec<(Option, Span)>), 25 | } 26 | impl Attach { 27 | pub fn parse(input: &[Token]) -> Result> { 28 | let (_eof, (src, (fields, meaning))) = pair( 29 | this_ident("attach"), 30 | cut(terminated( 31 | alt(( 32 | Attach::attach_lists( 33 | "variables", 34 | map(registerlist, Meaning::Variable), 35 | ), 36 | Attach::attach_lists( 37 | "names", 38 | map(stringlist, Meaning::Name), 39 | ), 40 | Attach::attach_lists( 41 | "values", 42 | map(numberlist, Meaning::Number), 43 | ), 44 | )), 45 | pair(tag!(";"), eof), 46 | )), 47 | )(input)?; 48 | Ok(Attach { 49 | src: src.clone(), 50 | fields, 51 | meaning, 52 | }) 53 | } 54 | fn attach_lists<'a, O, E>( 55 | name: &'a str, 56 | element: E, 57 | ) -> impl FnMut( 58 | &'a [Token], 59 | ) -> IResult< 60 | &'a [Token], 61 | (Vec<(String, Span)>, O), 62 | Box, 63 | > 64 | where 65 | E: FnMut(&'a [Token]) -> IResult<&'a [Token], O, Box>, 66 | { 67 | preceded(this_ident(name), pair(fieldlist, element)) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/syntax/block/disassembly.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::combinator::{map, opt}; 3 | use nom::multi::many0; 4 | use nom::sequence::{delimited, pair, separated_pair, terminated, tuple}; 5 | use nom::IResult; 6 | 7 | use crate::preprocessor::token::Token; 8 | use crate::semantic::disassembly::{Op, OpUnary}; 9 | use crate::syntax::parser::{ident, this_ident}; 10 | use crate::syntax::Value; 11 | use crate::{SleighError, Span}; 12 | 13 | #[derive(Clone, Debug)] 14 | pub enum Expr { 15 | Value(ExprElement), 16 | Op(Span, Op, Box, Box), 17 | } 18 | 19 | #[derive(Clone, Debug)] 20 | pub enum ExprElement { 21 | Value(Value), 22 | Op(Span, OpUnary, Box), 23 | } 24 | 25 | macro_rules! op_parser { 26 | ($name:ident, $op:ident, $tag:tt) => { 27 | pub fn $name( 28 | input: &[Token], 29 | ) -> IResult<&[Token], (Self, &Span), Box> { 30 | map(tag!($tag), |span| (Self::$op, span))(input) 31 | } 32 | }; 33 | } 34 | 35 | //used to define precedence 36 | macro_rules! op_parser_levels { 37 | ($level:ident, $(($name:ident, $op:ident, $tag:tt)),* $(,)? ) => { 38 | $(op_parser!($name, $op, $tag);)* 39 | pub fn $level(input: &[Token]) -> IResult<&[Token], (Self, &Span), Box> { 40 | alt(($(Self::$name),*))(input) 41 | } 42 | }; 43 | } 44 | 45 | macro_rules! declare_expr_level { 46 | ($name:ident, $next:ident, $op:path) => { 47 | fn $name(input: &[Token]) -> IResult<&[Token], Self, Box> { 48 | Self::parse_op(Self::$name, Self::$next, $op)(input) 49 | } 50 | }; 51 | } 52 | 53 | impl OpUnary { 54 | fn parse( 55 | input: &[Token], 56 | ) -> IResult<&[Token], (Self, &Span), Box> { 57 | use OpUnary::*; 58 | alt(( 59 | map(tag!("~"), |x| (Negation, x)), 60 | map(tag!("-"), |x| (Negative, x)), 61 | ))(input) 62 | } 63 | } 64 | 65 | impl Op { 66 | op_parser_levels!(parse_level1, (add, Add, "+"), (sub, Sub, "-")); 67 | op_parser_levels!(parse_level2, (mul, Mul, "*"), (div, Div, "/")); 68 | op_parser_levels!(parse_level3, (asr, Asr, ">>"), (lsl, Lsl, "<<")); 69 | 70 | // logical operations in the pattern value part, AKA not in brackets 71 | op_parser_levels!( 72 | parse_unsafe_level4, 73 | (and_unsafe, And, "$and"), 74 | (or_unsafe, Or, "$or"), 75 | (xor_unsafe, Xor, "$xor") 76 | ); 77 | // logical operations inside the square and round brackets 78 | op_parser_levels!( 79 | parse_safe_level4, 80 | (and, And, "&"), 81 | (or, Or, "|"), 82 | (xor, Xor, "^"), 83 | ); 84 | } 85 | 86 | impl ExprElement { 87 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 88 | alt(( 89 | map( 90 | pair(OpUnary::parse, Expr::parse_rec_or_ele), 91 | |((op, op_span), ele)| { 92 | // TODO span shold combine the start of op and end of ele 93 | Self::Op(op_span.clone(), op, Box::new(ele)) 94 | }, 95 | ), 96 | map(Value::parse_unsigned, Self::Value), 97 | ))(input) 98 | } 99 | } 100 | 101 | impl Expr { 102 | fn parse_rec_or_ele( 103 | input: &[Token], 104 | ) -> IResult<&[Token], Self, Box> { 105 | alt(( 106 | delimited(tag!("("), Self::parse_safe, tag!(")")), 107 | map(ExprElement::parse, Self::Value), 108 | ))(input) 109 | } 110 | 111 | #[allow(clippy::type_complexity)] 112 | fn parse_op( 113 | this_level: fn(&[Token]) -> IResult<&[Token], Expr, Box>, 114 | next_level: fn(&[Token]) -> IResult<&[Token], Expr, Box>, 115 | op: fn(&[Token]) -> IResult<&[Token], (Op, &Span), Box>, 116 | ) -> impl FnMut(&[Token]) -> IResult<&[Token], Expr, Box> { 117 | move |input: &[Token]| { 118 | let (input, (left, rest)) = 119 | pair(next_level, opt(pair(op, this_level)))(input)?; 120 | let expr = if let Some(((op, op_src), rest)) = rest { 121 | Self::Op(op_src.clone(), op, Box::new(left), Box::new(rest)) 122 | } else { 123 | left 124 | }; 125 | Ok((input, expr)) 126 | } 127 | } 128 | 129 | // parse with precedence 130 | // safe, things around brackets 131 | declare_expr_level!( 132 | parse_safe_lv1, 133 | parse_safe_unsafe_lv1, 134 | Op::parse_safe_level4 135 | ); 136 | declare_expr_level!( 137 | parse_safe_unsafe_lv1, 138 | parse_lv2, 139 | Op::parse_unsafe_level4 140 | ); 141 | // unsafe, things not around brackets 142 | declare_expr_level!(parse_unsafe_lv1, parse_lv2, Op::parse_unsafe_level4); 143 | declare_expr_level!(parse_lv2, parse_lv3, Op::parse_level3); 144 | declare_expr_level!(parse_lv3, parse_lv4, Op::parse_level2); 145 | declare_expr_level!(parse_lv4, parse_rec_or_ele, Op::parse_level1); 146 | 147 | pub fn parse_safe( 148 | input: &[Token], 149 | ) -> IResult<&[Token], Self, Box> { 150 | Self::parse_safe_lv1(input) 151 | } 152 | 153 | pub fn parse_unsafe( 154 | input: &[Token], 155 | ) -> IResult<&[Token], Self, Box> { 156 | Self::parse_unsafe_lv1(input) 157 | } 158 | } 159 | 160 | #[derive(Clone, Debug)] 161 | pub struct GlobalSet { 162 | pub src: Span, 163 | pub address: Value, 164 | pub context: String, 165 | } 166 | impl GlobalSet { 167 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 168 | map( 169 | tuple(( 170 | terminated(this_ident("globalset"), tag!("(")), 171 | terminated(Value::parse_unsigned, tag!(",")), 172 | terminated(ident, tag!(")")), 173 | tag!(";"), 174 | )), 175 | |(start, address, (context, _), end)| Self { 176 | src: Span::combine(start.clone().start(), end.clone().end()), 177 | address, 178 | context, 179 | }, 180 | )(input) 181 | } 182 | } 183 | 184 | #[derive(Clone, Debug)] 185 | pub struct Assignment { 186 | pub left_span: Span, 187 | pub left: String, 188 | pub right: Expr, 189 | } 190 | 191 | impl Assignment { 192 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 193 | map( 194 | terminated( 195 | separated_pair(ident, tag!("="), |x| Expr::parse_safe(x)), 196 | tag!(";"), 197 | ), 198 | |((left, left_span), right)| Self { 199 | left_span: left_span.clone(), 200 | left, 201 | right, 202 | }, 203 | )(input) 204 | } 205 | } 206 | 207 | #[derive(Clone, Debug)] 208 | pub enum Assertation { 209 | GlobalSet(Box), 210 | Assignment(Assignment), 211 | } 212 | 213 | impl Assertation { 214 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 215 | alt(( 216 | map(GlobalSet::parse, |x| Self::GlobalSet(Box::new(x))), 217 | map(Assignment::parse, Self::Assignment), 218 | ))(input) 219 | } 220 | } 221 | 222 | #[derive(Clone, Debug, Default)] 223 | pub struct Disassembly { 224 | pub assertations: Vec, 225 | } 226 | 227 | impl IntoIterator for Disassembly { 228 | type Item = Assertation; 229 | type IntoIter = std::vec::IntoIter; 230 | 231 | fn into_iter(self) -> Self::IntoIter { 232 | self.assertations.into_iter() 233 | } 234 | } 235 | 236 | impl Disassembly { 237 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 238 | map(many0(Assertation::parse), |assertations| Self { 239 | assertations, 240 | })(input) 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/syntax/block/display.rs: -------------------------------------------------------------------------------- 1 | use crate::preprocessor::DisplayToken; 2 | use crate::preprocessor::FilePreProcessor; 3 | use crate::SleighError; 4 | use crate::Span; 5 | 6 | #[derive(Clone, Debug)] 7 | pub enum DisplayElement { 8 | Concat, 9 | Ident(Span, String), 10 | Literal(String), 11 | Other(char), 12 | } 13 | 14 | #[derive(Clone, Debug)] 15 | pub struct Display(pub Vec); 16 | 17 | impl Display { 18 | pub fn parse( 19 | input: &mut FilePreProcessor, 20 | ) -> Result> { 21 | let mut display = vec![]; 22 | loop { 23 | let token = input.parse_display()?; 24 | match token { 25 | DisplayToken::End => break, 26 | DisplayToken::Concat => display.push(DisplayElement::Concat), 27 | DisplayToken::Ident(src, ident) => { 28 | display.push(DisplayElement::Ident(src, ident)) 29 | } 30 | DisplayToken::Literal(lit) => { 31 | display.push(DisplayElement::Literal(lit)) 32 | } 33 | DisplayToken::Other(c) => { 34 | display.push(DisplayElement::Other(c)) 35 | } 36 | } 37 | } 38 | Ok(Self(display)) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/syntax/block/execution/assignment.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::combinator::map; 3 | use nom::combinator::opt; 4 | use nom::sequence::delimited; 5 | use nom::sequence::pair; 6 | use nom::sequence::terminated; 7 | use nom::sequence::tuple; 8 | use nom::IResult; 9 | 10 | use crate::preprocessor::token::Token; 11 | use crate::syntax::parser::ident; 12 | use crate::syntax::BitRangeLsbLen; 13 | use crate::SleighError; 14 | use crate::Span; 15 | 16 | use super::op::ByteRangeLsb; 17 | use super::op::ByteRangeMsb; 18 | use super::{expr, op}; 19 | 20 | #[derive(Clone, Debug)] 21 | pub struct Declare { 22 | pub src: Span, 23 | pub name: String, 24 | pub size: Option, 25 | } 26 | impl Declare { 27 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 28 | map( 29 | delimited( 30 | tag!("local"), 31 | pair(ident, opt(ByteRangeLsb::parse)), 32 | tag!(";"), 33 | ), 34 | |((name, name_src), op)| Self { 35 | name, 36 | src: name_src.clone(), 37 | size: op, 38 | }, 39 | )(input) 40 | } 41 | } 42 | 43 | #[derive(Clone, Debug)] 44 | pub struct MemWrite { 45 | pub src: Span, 46 | pub mem: op::AddrDereference, 47 | pub addr: expr::Expr, 48 | pub right: expr::Expr, 49 | } 50 | impl MemWrite { 51 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 52 | map( 53 | tuple(( 54 | op::AddrDereference::parse, 55 | expr::Expr::parse, 56 | tag!("="), 57 | expr::Expr::parse, 58 | tag!(";"), 59 | )), 60 | |(mem, addr, src, right, _end)| Self { 61 | src: src.clone(), 62 | mem, 63 | addr, 64 | right, 65 | }, 66 | )(input) 67 | } 68 | } 69 | 70 | #[derive(Clone, Debug)] 71 | pub struct Assignment { 72 | pub local: bool, 73 | pub ident: String, 74 | pub src: Span, 75 | pub op: Option, 76 | pub right: expr::Expr, 77 | } 78 | impl Assignment { 79 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 80 | map( 81 | terminated( 82 | tuple(( 83 | map(opt(tag!("local")), |x| x.is_some()), 84 | ident, 85 | opt(OpLeft::parse), 86 | tag!("="), 87 | expr::Expr::parse, 88 | )), 89 | tag!(";"), 90 | ), 91 | |(local, (ident, _), op, src, right)| Self { 92 | local, 93 | ident, 94 | src: src.clone(), 95 | op, 96 | right, 97 | }, 98 | )(input) 99 | } 100 | } 101 | 102 | #[derive(Clone, Debug)] 103 | pub enum OpLeft { 104 | //assign to variable 105 | BitRange(BitRangeLsbLen), 106 | ByteRangeMsb(ByteRangeMsb), 107 | ByteRangeLsb(ByteRangeLsb), 108 | } 109 | 110 | impl OpLeft { 111 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 112 | alt(( 113 | map(BitRangeLsbLen::parse, Self::BitRange), 114 | map(ByteRangeMsb::parse, |_x| { 115 | todo!("MSB assignment is a thing?"); 116 | //Self::ByteRangeMsb(x) 117 | }), 118 | map(ByteRangeLsb::parse, Self::ByteRangeLsb), 119 | ))(input) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/syntax/block/execution/branch.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::combinator::{map, opt, value}; 3 | use nom::sequence::{delimited, preceded, terminated, tuple}; 4 | use nom::IResult; 5 | 6 | use crate::preprocessor::token::Token; 7 | use crate::semantic::execution::BranchCall; 8 | use crate::SleighError; 9 | 10 | use super::expr::Expr; 11 | use super::{expr, Label}; 12 | 13 | #[derive(Clone, Debug)] 14 | pub struct Branch { 15 | pub cond: Option, 16 | pub call: BranchCall, 17 | pub dst: BranchDst, 18 | } 19 | impl Branch { 20 | pub fn parse_cond( 21 | input: &[Token], 22 | ) -> IResult<&[Token], Expr, Box> { 23 | preceded(tag!("if"), expr::Expr::parse)(input) 24 | } 25 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 26 | map( 27 | terminated( 28 | tuple(( 29 | opt(Self::parse_cond), 30 | BranchCall::parse, 31 | BranchDst::parse, 32 | )), 33 | tag!(";"), 34 | ), 35 | |(cond, call, dst)| Self { cond, call, dst }, 36 | )(input) 37 | } 38 | } 39 | 40 | impl BranchCall { 41 | pub fn parse( 42 | input: &[Token], 43 | ) -> IResult<&[Token], BranchCall, Box> { 44 | alt(( 45 | value(BranchCall::Goto, tag!("goto")), 46 | value(BranchCall::Call, tag!("call")), 47 | value(BranchCall::Return, tag!("return")), 48 | ))(input) 49 | } 50 | } 51 | 52 | #[derive(Clone, Debug)] 53 | pub enum BranchDst { 54 | Label(Label), 55 | Cpu { direct: bool, expr: expr::Expr }, 56 | } 57 | impl BranchDst { 58 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 59 | alt(( 60 | map(Label::parse, Self::Label), 61 | map(expr::Expr::parse, |expr| Self::Cpu { direct: true, expr }), 62 | map(delimited(tag!("["), expr::Expr::parse, tag!("]")), |expr| { 63 | Self::Cpu { 64 | direct: false, 65 | expr, 66 | } 67 | }), 68 | ))(input) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/syntax/block/execution/export.rs: -------------------------------------------------------------------------------- 1 | use crate::preprocessor::token::Token; 2 | use crate::syntax::parser::{ident, this_ident}; 3 | use crate::{SleighError, Span}; 4 | use nom::branch::alt; 5 | use nom::combinator::map; 6 | use nom::sequence::{delimited, pair, preceded, tuple}; 7 | use nom::IResult; 8 | 9 | use super::op::ByteRangeLsb; 10 | use super::{expr, op}; 11 | 12 | #[derive(Clone, Debug)] 13 | pub enum Export { 14 | Value(expr::Expr), 15 | Reference { 16 | space: op::AddrDereference, 17 | addr: expr::Expr, 18 | }, 19 | Const { 20 | size: ByteRangeLsb, 21 | src: Span, 22 | value: String, 23 | }, 24 | //TODO Unique 25 | //Unique{ 26 | // value: &[Token], 27 | //} 28 | } 29 | 30 | impl Export { 31 | fn parse_value( 32 | input: &[Token], 33 | ) -> IResult<&[Token], Self, Box> { 34 | map(expr::Expr::parse, Self::Value)(input) 35 | } 36 | fn parse_reference( 37 | input: &[Token], 38 | ) -> IResult<&[Token], Self, Box> { 39 | map( 40 | pair(op::AddrDereference::parse, expr::Expr::parse), 41 | |(space, addr)| Self::Reference { space, addr }, 42 | )(input) 43 | } 44 | fn parse_const( 45 | input: &[Token], 46 | ) -> IResult<&[Token], Self, Box> { 47 | map( 48 | preceded( 49 | tuple((tag!("*"), tag!("["), tag!("const"), tag!("]"))), 50 | pair(ByteRangeLsb::parse, ident), 51 | ), 52 | |(size, (value, value_src))| Self::Const { 53 | size, 54 | value, 55 | src: value_src.clone(), 56 | }, 57 | )(input) 58 | } 59 | fn parse_unique( 60 | input: &[Token], 61 | ) -> IResult<&[Token], Self, Box> { 62 | map( 63 | preceded( 64 | tuple((tag!("*"), tag!("["), tag!("unique"), tag!("]"))), 65 | pair(ByteRangeLsb::parse, ident), 66 | ), 67 | |_| todo!(), 68 | )(input) 69 | } 70 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 71 | delimited( 72 | this_ident("export"), 73 | //NOTE order is important 74 | alt(( 75 | Self::parse_unique, 76 | Self::parse_const, 77 | Self::parse_reference, 78 | Self::parse_value, 79 | )), 80 | tag!(";"), 81 | )(input) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/syntax/block/execution/expr.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::combinator::{map, map_opt, opt}; 3 | use nom::multi::separated_list0; 4 | use nom::sequence::{ 5 | delimited, pair, preceded, separated_pair, terminated, tuple, 6 | }; 7 | use nom::IResult; 8 | 9 | use super::op::{ByteRangeLsb, Unary}; 10 | use super::UserCall; 11 | use crate::preprocessor::token::Token; 12 | use crate::semantic::execution::Binary; 13 | use crate::syntax::parser::{ident, number, this_ident}; 14 | use crate::syntax::Value; 15 | use crate::{NumberUnsigned, SleighError, Span}; 16 | 17 | #[derive(Clone, Debug)] 18 | pub enum Expr { 19 | Value(ExprElement), 20 | Op(Span, Binary, Box, Box), 21 | } 22 | 23 | macro_rules! declare_expr_level { 24 | ($name:ident, $next:ident, $op:path) => { 25 | fn $name(input: &[Token]) -> IResult<&[Token], Self, Box> { 26 | Self::parse_op(Self::$name, Self::$next, $op)(input) 27 | } 28 | }; 29 | } 30 | 31 | impl Expr { 32 | fn parse_call( 33 | input: &[Token], 34 | ) -> IResult<&[Token], Self, Box> { 35 | map( 36 | pair( 37 | Binary::parse_call_name, 38 | delimited( 39 | tag!("("), 40 | separated_pair(Expr::parse, tag!(","), Expr::parse), 41 | tag!(")"), 42 | ), 43 | ), 44 | |((op, op_src), (param1, param2))| { 45 | Self::Op(op_src.clone(), op, Box::new(param1), Box::new(param2)) 46 | }, 47 | )(input) 48 | } 49 | fn value_or_rec( 50 | input: &[Token], 51 | ) -> IResult<&[Token], Self, Box> { 52 | alt((Self::parse_rec, map(ExprElement::parse_ele, Self::Value)))(input) 53 | } 54 | fn eleme_rec(input: &[Token]) -> IResult<&[Token], Self, Box> { 55 | alt((Self::parse_rec, map(ExprElement::parse, Self::Value)))(input) 56 | } 57 | pub fn parse_rec( 58 | input: &[Token], 59 | ) -> IResult<&[Token], Self, Box> { 60 | alt(( 61 | delimited(tag!("("), Self::parse, tag!(")")), 62 | Self::parse_call, 63 | ))(input) 64 | } 65 | #[allow(clippy::type_complexity)] 66 | fn parse_op( 67 | this_level: fn(&[Token]) -> IResult<&[Token], Expr, Box>, 68 | next_level: fn(&[Token]) -> IResult<&[Token], Expr, Box>, 69 | op: fn( 70 | &[Token], 71 | ) -> IResult<&[Token], (Binary, &Span), Box>, 72 | ) -> impl FnMut(&[Token]) -> IResult<&[Token], Expr, Box> { 73 | move |input: &[Token]| { 74 | let (input, (left, rest)) = 75 | pair(next_level, opt(pair(op, this_level)))(input)?; 76 | let expr = if let Some(((op, op_src), rest)) = rest { 77 | Self::Op(op_src.clone(), op, Box::new(left), Box::new(rest)) 78 | } else { 79 | left 80 | }; 81 | Ok((input, expr)) 82 | } 83 | } 84 | //parse with precedence 85 | declare_expr_level!(parse_lv1, parse_lv2, Binary::level6); 86 | declare_expr_level!(parse_lv2, parse_lv3, Binary::level5); 87 | declare_expr_level!(parse_lv3, parse_lv4, Binary::level4); 88 | declare_expr_level!(parse_lv4, parse_lv5, Binary::level3); 89 | declare_expr_level!(parse_lv5, parse_lv6, Binary::level2); 90 | declare_expr_level!(parse_lv6, eleme_rec, Binary::level1); 91 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 92 | Self::parse_lv1(input) 93 | } 94 | } 95 | 96 | #[derive(Clone, Debug)] 97 | pub enum ExprElement { 98 | Value(Value), 99 | Reference(Span, Option, String), 100 | Op(Span, Box, Box), 101 | New(Span, Box, Option>), 102 | CPool(Span, Vec), 103 | UserCall(UserCall), 104 | //unable to differ a UserCall(one param)/Op(Msb) eg: `ident(1)`, 105 | //so ambiguous1 106 | Ambiguous1 { 107 | name: String, 108 | param: NumberUnsigned, 109 | param_src: Span, 110 | }, 111 | } 112 | 113 | impl ExprElement { 114 | fn parse_value( 115 | input: &[Token], 116 | ) -> IResult<&[Token], Self, Box> { 117 | map(Value::parse_signed, Self::Value)(input) 118 | } 119 | fn parse_op_call( 120 | input: &[Token], 121 | ) -> IResult<&[Token], Self, Box> { 122 | map( 123 | pair( 124 | Unary::parse_call_name, 125 | delimited(tag!("("), Expr::parse, tag!(")")), 126 | ), 127 | |((op, src), param)| { 128 | Self::Op(src.clone(), Box::new(op), Box::new(param)) 129 | }, 130 | )(input) 131 | } 132 | fn parse_new_call( 133 | input: &[Token], 134 | ) -> IResult<&[Token], Self, Box> { 135 | map( 136 | tuple(( 137 | terminated(this_ident("newobject"), tag!("(")), 138 | pair(Expr::parse, opt(preceded(tag!(","), Expr::parse))), 139 | tag!(")"), 140 | )), 141 | |(start, (param0, param1), end)| { 142 | let location = 143 | Span::combine(start.clone().start(), end.clone().end()); 144 | Self::New(location, Box::new(param0), param1.map(Box::new)) 145 | }, 146 | )(input) 147 | } 148 | fn parse_cpool_call( 149 | input: &[Token], 150 | ) -> IResult<&[Token], Self, Box> { 151 | map_opt( 152 | pair( 153 | this_ident("cpool"), 154 | delimited( 155 | tag!("("), 156 | separated_list0(tag!(","), Expr::parse), 157 | tag!(")"), 158 | ), 159 | ), 160 | |(src, params)| { 161 | (params.len() >= 2).then(|| Self::CPool(src.clone(), params)) 162 | }, 163 | )(input) 164 | } 165 | fn parse_amb1( 166 | input: &[Token], 167 | ) -> IResult<&[Token], Self, Box> { 168 | map( 169 | pair(ident, delimited(tag!("("), number, tag!(")"))), 170 | |((name, _name_src), (param, param_src))| Self::Ambiguous1 { 171 | name, 172 | param, 173 | param_src: param_src.clone(), 174 | }, 175 | )(input) 176 | } 177 | fn parse_user_call( 178 | input: &[Token], 179 | ) -> IResult<&[Token], Self, Box> { 180 | map(UserCall::parse_expr, Self::UserCall)(input) 181 | } 182 | fn parse_reference( 183 | input: &[Token], 184 | ) -> IResult<&[Token], Self, Box> { 185 | map( 186 | tuple((tag!("&"), opt(ByteRangeLsb::parse), ident)), 187 | |(src, ref_size, (value, _))| { 188 | Self::Reference(src.clone(), ref_size, value) 189 | }, 190 | )(input) 191 | } 192 | fn parse_user_call_or_amb1( 193 | input: &[Token], 194 | ) -> IResult<&[Token], Self, Box> { 195 | //NOTE order is importante here 196 | alt((Self::parse_amb1, Self::parse_user_call))(input) 197 | } 198 | fn parse_ele(input: &[Token]) -> IResult<&[Token], Self, Box> { 199 | //NOTE order is importante here 200 | alt(( 201 | Self::parse_op_call, 202 | Self::parse_new_call, 203 | Self::parse_cpool_call, 204 | Self::parse_user_call_or_amb1, 205 | Self::parse_value, 206 | ))(input) 207 | } 208 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 209 | //this can be a reference or op_before/ele/op_after 210 | if let Ok((input, reference)) = Self::parse_reference(input) { 211 | return Ok((input, reference)); 212 | } 213 | 214 | let (input, (op_before, value, op_after)) = tuple(( 215 | opt(Unary::parse_before), 216 | Expr::value_or_rec, 217 | opt(Unary::parse_after), 218 | ))(input)?; 219 | //op after have higher precedence, so it goes first 220 | let mut expr = value; 221 | for (unary, src) in [op_after, op_before].into_iter().flatten() { 222 | expr = Expr::Value(Self::Op(src, Box::new(unary), Box::new(expr))); 223 | } 224 | 225 | //in case we got an value an not op, simplify the expr to only a value 226 | //otherwise have the Self::Op(Expr) returned 227 | let expr = match expr { 228 | Expr::Value(value @ Self::Value(_)) => value, 229 | Expr::Value(op) => op, 230 | _ => unreachable!(), 231 | }; 232 | Ok((input, expr)) 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/syntax/block/execution/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod assignment; 2 | pub mod branch; 3 | pub mod export; 4 | pub mod expr; 5 | pub mod op; 6 | 7 | use crate::preprocessor::token::Token; 8 | use crate::syntax::block::execution::assignment::{ 9 | Assignment, Declare, MemWrite, 10 | }; 11 | use crate::syntax::parser::{ident, number, this_ident}; 12 | use crate::{NumberUnsigned, SleighError, Span}; 13 | use nom::branch::alt; 14 | use nom::combinator::map; 15 | use nom::multi::{many0, separated_list0}; 16 | use nom::sequence::{delimited, pair, terminated}; 17 | use nom::IResult; 18 | 19 | use self::branch::Branch; 20 | use self::export::Export; 21 | 22 | #[derive(Clone, Debug)] 23 | pub enum Statement { 24 | Delayslot(Delayslot), 25 | Label(Label), 26 | Export(Export), 27 | Branch(Branch), 28 | Build(Build), 29 | Call(UserCall), 30 | Declare(Declare), 31 | Assignment(Assignment), 32 | MemWrite(MemWrite), 33 | } 34 | 35 | impl Statement { 36 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 37 | alt(( 38 | //Move label out of statement? 39 | map(Label::parse, Self::Label), 40 | map(Delayslot::parse, Self::Delayslot), 41 | map(Export::parse, Self::Export), 42 | map(Branch::parse, Self::Branch), 43 | map(Build::parse, Self::Build), 44 | map(UserCall::parse_statement, Self::Call), 45 | map(Declare::parse, Self::Declare), 46 | map(Assignment::parse, Self::Assignment), 47 | map(MemWrite::parse, Self::MemWrite), 48 | ))(input) 49 | } 50 | } 51 | 52 | #[derive(Clone, Debug)] 53 | pub struct Delayslot(pub NumberUnsigned); 54 | 55 | impl Delayslot { 56 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 57 | map( 58 | terminated( 59 | delimited( 60 | pair(this_ident("delayslot"), tag!("(")), 61 | number, 62 | tag!(")"), 63 | ), 64 | tag!(";"), 65 | ), 66 | |(value, _)| Self(value), 67 | )(input) 68 | } 69 | } 70 | 71 | #[derive(Clone, Debug)] 72 | pub struct Label { 73 | pub src: Span, 74 | pub name: String, 75 | } 76 | 77 | impl Label { 78 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 79 | map( 80 | delimited(tag!("<"), ident, tag!(">")), 81 | |(name, name_src)| Self { 82 | name, 83 | src: name_src.clone(), 84 | }, 85 | )(input) 86 | } 87 | } 88 | 89 | #[derive(Clone, Debug)] 90 | pub struct Build { 91 | pub src: Span, 92 | pub table_name: String, 93 | } 94 | impl Build { 95 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 96 | map( 97 | delimited(this_ident("build"), ident, tag!(";")), 98 | |(table_name, name_src)| Self { 99 | table_name, 100 | src: name_src.clone(), 101 | }, 102 | )(input) 103 | } 104 | } 105 | 106 | #[derive(Clone, Debug)] 107 | pub struct UserCall { 108 | //top of the stack contains the call (op::Op) 109 | pub params: Vec, 110 | pub src: Span, 111 | pub name: String, 112 | } 113 | 114 | impl UserCall { 115 | pub fn new(function: String, src: Span, params: Vec) -> Self { 116 | Self { 117 | name: function, 118 | src, 119 | params, 120 | } 121 | } 122 | pub fn parse_statement( 123 | input: &[Token], 124 | ) -> IResult<&[Token], Self, Box> { 125 | terminated(UserCall::parse_expr, tag!(";"))(input) 126 | } 127 | pub fn parse_expr( 128 | input: &[Token], 129 | ) -> IResult<&[Token], Self, Box> { 130 | map( 131 | pair( 132 | ident, 133 | delimited( 134 | tag!("("), 135 | separated_list0(tag!(","), expr::Expr::parse), 136 | tag!(")"), 137 | ), 138 | ), 139 | |((name, name_src), params)| Self { 140 | params, 141 | src: name_src.clone(), 142 | name, 143 | }, 144 | )(input) 145 | } 146 | } 147 | 148 | #[derive(Clone, Debug, Default)] 149 | pub struct Execution { 150 | pub statements: Vec, 151 | } 152 | 153 | impl Execution { 154 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 155 | map(many0(Statement::parse), |statements| Self { statements })(input) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/syntax/block/execution/op.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Ordering; 2 | 3 | use nom::branch::alt; 4 | use nom::combinator::{map, opt}; 5 | use nom::sequence::{delimited, preceded, tuple}; 6 | use nom::IResult; 7 | 8 | use crate::preprocessor::token::Token; 9 | use crate::semantic::execution::Binary; 10 | use crate::syntax::parser::{ident, number}; 11 | use crate::syntax::BitRangeLsbLen; 12 | use crate::{NumberUnsigned, SleighError, Span}; 13 | 14 | #[derive(Clone, Debug)] 15 | pub struct ByteRangeMsb { 16 | pub value: NumberUnsigned, 17 | pub src: Span, 18 | } 19 | impl ByteRangeMsb { 20 | pub fn parse( 21 | input: &[Token], 22 | ) -> IResult<&[Token], ByteRangeMsb, Box> { 23 | map(delimited(tag!("("), number, tag!(")")), |(value, src)| { 24 | Self { 25 | src: src.clone(), 26 | value, 27 | } 28 | })(input) 29 | } 30 | } 31 | #[derive(Clone, Debug)] 32 | pub struct ByteRangeLsb { 33 | // TODO NumberNonZeroUnsigned? 34 | pub value: NumberUnsigned, 35 | pub src: Span, 36 | } 37 | impl ByteRangeLsb { 38 | pub fn parse( 39 | input: &[Token], 40 | ) -> IResult<&[Token], ByteRangeLsb, Box> { 41 | map(preceded(tag!(":"), number), |(value, src)| Self { 42 | src: src.clone(), 43 | value, 44 | })(input) 45 | } 46 | } 47 | 48 | #[allow(clippy::large_enum_variant)] 49 | #[derive(Clone, Debug)] 50 | pub enum Unary { 51 | //NOTE: ByteRangeMsb is part of the expr::ExprElement::Ambiguous1 52 | ByteRangeMsb(ByteRangeMsb), 53 | ByteRangeLsb(ByteRangeLsb), 54 | BitRange(BitRangeLsbLen), 55 | Dereference(AddrDereference), 56 | //Reference(AddrReference), 57 | Negation, 58 | BitNegation, 59 | Negative, 60 | FloatNegative, 61 | Popcount, 62 | Lzcount, 63 | Zext, 64 | Sext, 65 | FloatNan, 66 | FloatAbs, 67 | FloatSqrt, 68 | Int2Float, 69 | Float2Float, 70 | SignTrunc, 71 | FloatCeil, 72 | FloatFloor, 73 | FloatRound, 74 | } 75 | 76 | impl Unary { 77 | pub fn precedence(&self, other: &Self) -> Ordering { 78 | macro_rules! order_enum { 79 | ($a:ident, $b:ident, $($elem:pat),* $(,)?) => { 80 | #[allow(unreachable_patterns)] 81 | match ($a, $b) { 82 | $( 83 | ($elem, $elem) => std::cmp::Ordering::Equal, 84 | ($elem, _) => std::cmp::Ordering::Greater, 85 | (_, $elem) => std::cmp::Ordering::Less, 86 | )* 87 | } 88 | }; 89 | } 90 | use Unary::*; 91 | order_enum!( 92 | self, 93 | other, 94 | ByteRangeMsb { .. } | ByteRangeLsb { .. }, 95 | BitRange(_), 96 | Dereference(_), 97 | //Reference(_), 98 | Negation, 99 | BitNegation, 100 | Negative, 101 | FloatNegative, 102 | Popcount, 103 | Lzcount, 104 | Zext, 105 | Sext, 106 | FloatNan, 107 | FloatAbs, 108 | FloatSqrt, 109 | Int2Float, 110 | Float2Float, 111 | SignTrunc, 112 | FloatCeil, 113 | FloatFloor, 114 | FloatRound, 115 | ) 116 | } 117 | pub fn parse_after( 118 | input: &[Token], 119 | ) -> IResult<&[Token], (Self, Span), Box> { 120 | alt(( 121 | map(BitRangeLsbLen::parse, |x| { 122 | let location = x.src.clone(); 123 | (Self::BitRange(x), location) 124 | }), 125 | map(ByteRangeMsb::parse, |x| { 126 | let location = x.src.clone(); 127 | (Self::ByteRangeMsb(x), location) 128 | }), 129 | map(ByteRangeLsb::parse, |x| { 130 | let location = x.src.clone(); 131 | (Self::ByteRangeLsb(x), location) 132 | }), 133 | ))(input) 134 | } 135 | pub fn parse_before( 136 | input: &[Token], 137 | ) -> IResult<&[Token], (Self, Span), Box> { 138 | alt(( 139 | map(tag!("!"), |span| (Self::Negation, span.clone())), 140 | map(tag!("~"), |span| (Self::BitNegation, span.clone())), 141 | map(tag!("-"), |span| (Self::Negative, span.clone())), 142 | map(tag!("f-"), |span| (Self::FloatNegative, span.clone())), 143 | map(AddrDereference::parse, |x| { 144 | let location = x.src.clone(); 145 | (Self::Dereference(x), location) 146 | }), 147 | ))(input) 148 | } 149 | pub fn parse_call_name( 150 | input_ori: &[Token], 151 | ) -> IResult<&[Token], (Self, &Span), Box> { 152 | alt(( 153 | map(tag!("popcount"), |span| (Self::Popcount, span)), 154 | map(tag!("lzcount"), |span| (Self::Lzcount, span)), 155 | map(tag!("zext"), |span| (Self::Zext, span)), 156 | map(tag!("sext"), |span| (Self::Sext, span)), 157 | map(tag!("nan"), |span| (Self::FloatNan, span)), 158 | map(tag!("abs"), |span| (Self::FloatAbs, span)), 159 | map(tag!("sqrt"), |span| (Self::FloatSqrt, span)), 160 | map(tag!("int2float"), |span| (Self::Int2Float, span)), 161 | map(tag!("float2float"), |span| (Self::Float2Float, span)), 162 | map(tag!("trunc"), |span| (Self::SignTrunc, span)), 163 | map(tag!("ceil"), |span| (Self::FloatCeil, span)), 164 | map(tag!("floor"), |span| (Self::FloatFloor, span)), 165 | map(tag!("round"), |span| (Self::FloatRound, span)), 166 | ))(input_ori) 167 | } 168 | } 169 | 170 | macro_rules! op_parser { 171 | ($name:ident, $op:ident, $tag:tt) => { 172 | pub fn $name( 173 | input: &[Token], 174 | ) -> IResult<&[Token], (Self, &Span), Box> { 175 | map(tag!($tag), |span| (Self::$op, span))(input) 176 | } 177 | }; 178 | } 179 | //used to define precedence 180 | macro_rules! op_parser_levels { 181 | ($level:ident, $(($name:ident, $op:ident, $tag:tt)),* $(,)? ) => { 182 | $(op_parser!($name, $op, $tag);)* 183 | pub fn $level(input: &[Token]) -> IResult<&[Token], (Self, &Span), Box> { 184 | alt(($(Self::$name),*))(input) 185 | } 186 | }; 187 | } 188 | impl Binary { 189 | //NOTE: the bigger operands need to come first otherwise the smallest 190 | //version will be consumend before the biggest one is checked. 191 | //eg: "<<" is consument with as "<" 192 | op_parser_levels!( 193 | level1, 194 | (sig_div, SigDiv, "s/"), 195 | (sig_rem, SigRem, "s%"), 196 | (float_div, FloatDiv, "f/"), 197 | (float_mult, FloatMult, "f*"), 198 | (mult, Mult, "*"), 199 | (div, Div, "/"), 200 | (rem, Rem, "%"), 201 | ); 202 | 203 | op_parser_levels!( 204 | level2, 205 | (float_add, FloatAdd, "f+"), 206 | (float_sub, FloatSub, "f-"), 207 | (add, Add, "+"), 208 | (sub, Sub, "-"), 209 | ); 210 | 211 | op_parser_levels!( 212 | level3, 213 | (asr, Asr, "s>>"), 214 | (lsl, Lsl, "<<"), 215 | (lsr, Lsr, ">>"), 216 | ); 217 | 218 | op_parser_levels!( 219 | level4, 220 | (float_less_eq, FloatLessEq, "f<="), 221 | (float_greater_eq, FloatGreaterEq, "f>="), 222 | (sig_less_eq, SigLessEq, "s<="), 223 | (sig_greater_eq, SigGreaterEq, "s>="), 224 | (less_eq, LessEq, "<="), 225 | (greater_eq, GreaterEq, ">="), 226 | (float_less, FloatLess, "f<"), 227 | (float_greater, FloatGreater, "f>"), 228 | (sig_less, SigLess, "s<"), 229 | (sig_greater, SigGreater, "s>"), 230 | (less, Less, "<"), 231 | (greater, Greater, ">"), 232 | ); 233 | 234 | op_parser_levels!( 235 | level5, 236 | (float_eq, FloatEq, "f=="), 237 | (float_ne, FloatNe, "f!="), 238 | (eq, Eq, "=="), 239 | (ne, Ne, "!="), 240 | ); 241 | 242 | op_parser_levels!( 243 | level6, 244 | (and, And, "&&"), 245 | (xor, Xor, "^^"), 246 | (or, Or, "||"), 247 | (bit_and, BitAnd, "&"), 248 | (bit_xor, BitXor, "^"), 249 | (bit_or, BitOr, "|"), 250 | ); 251 | pub fn parse_call_name( 252 | input_ori: &[Token], 253 | ) -> IResult<&[Token], (Self, &Span), Box> { 254 | alt(( 255 | map(tag!("carry"), |src| (Self::Carry, src)), 256 | map(tag!("scarry"), |src| (Self::SCarry, src)), 257 | map(tag!("sborrow"), |src| (Self::SBorrow, src)), 258 | ))(input_ori) 259 | } 260 | } 261 | 262 | #[derive(Clone, Debug)] 263 | pub struct SpaceReference { 264 | pub src: Span, 265 | pub name: String, 266 | } 267 | impl SpaceReference { 268 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 269 | map( 270 | delimited(tag!("["), ident, tag!("]")), 271 | |(name, name_src)| Self { 272 | name, 273 | src: name_src.clone(), 274 | }, 275 | )(input) 276 | } 277 | } 278 | 279 | #[derive(Clone, Debug)] 280 | pub struct AddrDereference { 281 | pub src: Span, 282 | pub space: Option, 283 | pub size: Option, 284 | } 285 | 286 | impl AddrDereference { 287 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 288 | map( 289 | tuple(( 290 | tag!("*"), 291 | opt(SpaceReference::parse), 292 | opt(ByteRangeLsb::parse), 293 | )), 294 | |(src, space, size)| Self { 295 | src: src.clone(), 296 | space, 297 | size, 298 | }, 299 | )(input) 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /src/syntax/block/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod disassembly; 2 | pub mod display; 3 | pub mod execution; 4 | pub mod pattern; 5 | pub mod pcode_macro; 6 | pub mod table; 7 | pub mod with_block; 8 | -------------------------------------------------------------------------------- /src/syntax/block/pattern.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::combinator::{map, map_res, opt, value}; 3 | use nom::multi::{many0, separated_list0}; 4 | use nom::sequence::{delimited, pair, tuple}; 5 | use nom::IResult; 6 | 7 | use super::disassembly; 8 | use crate::preprocessor::token::Token; 9 | use crate::semantic::pattern::{CmpOp, Ellipsis}; 10 | use crate::syntax::parser::ident; 11 | use crate::{SleighError, Span}; 12 | 13 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 14 | pub enum Op { 15 | And, 16 | Or, 17 | } 18 | 19 | impl Op { 20 | pub fn parse(input: &[Token]) -> IResult<&[Token], Op, Box> { 21 | alt((value(Op::Or, tag!("|")), value(Op::And, tag!("&"))))(input) 22 | } 23 | } 24 | 25 | impl CmpOp { 26 | pub fn parse( 27 | input: &[Token], 28 | ) -> IResult<&[Token], CmpOp, Box> { 29 | alt(( 30 | value(CmpOp::Le, tag!("<=")), 31 | value(CmpOp::Ge, tag!(">=")), 32 | value(CmpOp::Ne, tag!("!=")), 33 | //TODO order is important, so ">=" is not consumed as ">" 34 | value(CmpOp::Eq, tag!("=")), 35 | value(CmpOp::Lt, tag!("<")), 36 | value(CmpOp::Gt, tag!(">")), 37 | ))(input) 38 | } 39 | } 40 | 41 | #[derive(Clone, Debug)] 42 | pub struct ConstraintValue { 43 | pub expr: disassembly::Expr, 44 | } 45 | 46 | impl ConstraintValue { 47 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 48 | map( 49 | alt(( 50 | delimited( 51 | tag!("("), 52 | |x| disassembly::Expr::parse_safe(x), 53 | tag!(")"), 54 | ), 55 | |x| disassembly::Expr::parse_unsafe(x), 56 | )), 57 | |expr| ConstraintValue { expr }, 58 | )(input) 59 | } 60 | } 61 | 62 | #[derive(Clone, Debug)] 63 | pub struct Constraint { 64 | pub op: CmpOp, 65 | pub value: ConstraintValue, 66 | } 67 | 68 | impl Constraint { 69 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 70 | map(pair(CmpOp::parse, ConstraintValue::parse), |(op, value)| { 71 | Self { op, value } 72 | })(input) 73 | } 74 | } 75 | 76 | #[derive(Clone, Debug)] 77 | pub enum Field { 78 | Field { 79 | field: String, 80 | src: Span, 81 | constraint: Option, 82 | }, 83 | SubPattern(Pattern), 84 | } 85 | impl Field { 86 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 87 | alt(( 88 | map(delimited(tag!("("), Pattern::parse, tag!(")")), |sub| { 89 | Field::SubPattern(sub) 90 | }), 91 | map( 92 | pair(ident, opt(Constraint::parse)), 93 | |((field, field_src), constraint)| Field::Field { 94 | field, 95 | src: field_src.clone(), 96 | constraint, 97 | }, 98 | ), 99 | ))(input) 100 | } 101 | } 102 | 103 | #[derive(Clone, Debug)] 104 | pub struct Element { 105 | pub field: Field, 106 | pub ellipsis: Option, 107 | } 108 | 109 | impl Element { 110 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 111 | map_res( 112 | tuple(( 113 | opt(map(tag!("..."), |span| (Ellipsis::Left, span))), 114 | Field::parse, 115 | opt(map(tag!("..."), |span| (Ellipsis::Right, span))), 116 | )), 117 | |(left, field, right)| { 118 | let ellipsis = match (left, right) { 119 | (Some((_, left)), Some((_, right))) => { 120 | let location = Span::combine( 121 | left.clone().start(), 122 | right.clone().end(), 123 | ); 124 | return Err(Box::new(SleighError::DualEllipsis( 125 | location, 126 | ))); 127 | } 128 | (left, right) => left.or(right).map(|(e, _)| e), 129 | }; 130 | Ok(Element { field, ellipsis }) 131 | }, 132 | )(input) 133 | } 134 | } 135 | 136 | #[derive(Clone, Debug)] 137 | pub struct Block { 138 | pub src: Span, 139 | pub first: Element, 140 | pub elements: Vec<(Op, Element)>, 141 | } 142 | 143 | impl Block { 144 | pub fn op(&self) -> Op { 145 | self.elements.first().map(|(op, _)| *op).unwrap_or(Op::And) 146 | } 147 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 148 | map( 149 | tuple((Element::parse, many0(pair(Op::parse, Element::parse)))), 150 | |(first, elements)| { 151 | //TODO improve this src 152 | let src = match &first.field { 153 | Field::SubPattern(pat) => pat.src.clone(), 154 | Field::Field { src, .. } => src.clone(), 155 | }; 156 | Self { 157 | first, 158 | elements, 159 | src, 160 | } 161 | }, 162 | )(input) 163 | } 164 | } 165 | 166 | #[derive(Clone, Debug)] 167 | pub struct Pattern { 168 | //NOTE point after the `is` in the constructor, pattern itself don't have a 169 | //start, thats because it could be mixed with the `with_block` pattern 170 | pub src: Span, 171 | //NOTE: point after the `is` 172 | pub blocks: Vec, 173 | } 174 | impl IntoIterator for Pattern { 175 | type Item = Block; 176 | type IntoIter = std::vec::IntoIter; 177 | 178 | fn into_iter(self) -> Self::IntoIter { 179 | self.blocks.into_iter() 180 | } 181 | } 182 | 183 | impl Pattern { 184 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 185 | let (rest, pattern) = 186 | map(separated_list0(tag!(";"), Block::parse), |blocks| Pattern { 187 | //TODO improve the src here 188 | src: input.first().unwrap().location.clone(), 189 | blocks, 190 | })(input)?; 191 | Ok((rest, pattern)) 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/syntax/block/pcode_macro.rs: -------------------------------------------------------------------------------- 1 | use nom::combinator::eof; 2 | use nom::multi::separated_list0; 3 | use nom::sequence::{delimited, terminated, tuple}; 4 | 5 | use crate::preprocessor::token::Token; 6 | use crate::syntax::parser::{ident, this_ident}; 7 | use crate::{SleighError, Span}; 8 | 9 | use super::execution::Execution; 10 | 11 | //TODO impl correctly the PCode Macro 12 | #[derive(Clone, Debug)] 13 | pub struct PcodeMacro { 14 | pub src: Span, 15 | pub name: String, 16 | pub params: Vec<(String, Span)>, 17 | pub body: Execution, 18 | } 19 | 20 | impl PcodeMacro { 21 | pub fn parse(input: &[Token]) -> Result> { 22 | let (_eof, (_, (name, src), params, body)) = terminated( 23 | tuple(( 24 | this_ident("macro"), 25 | ident, 26 | delimited( 27 | tag!("("), 28 | separated_list0(tag!(","), ident), 29 | tag!(")"), 30 | ), 31 | delimited(tag!("{"), Execution::parse, tag!("}")), 32 | )), 33 | eof, 34 | )(input)?; 35 | Ok(Self { 36 | name, 37 | params: params.into_iter().map(|(x, s)| (x, s.clone())).collect(), 38 | body, 39 | src: src.clone(), 40 | }) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/syntax/block/table.rs: -------------------------------------------------------------------------------- 1 | use crate::preprocessor::token::Token; 2 | use crate::preprocessor::FilePreProcessor; 3 | use crate::syntax::parser::{ident, Parser}; 4 | use crate::{SleighError, Span, DISABLE_EXECUTION_PARSING}; 5 | 6 | use nom::branch::alt; 7 | use nom::combinator::{cut, eof, map, opt, value}; 8 | use nom::sequence::{delimited, tuple}; 9 | 10 | use super::disassembly::Disassembly; 11 | use super::display::Display; 12 | use super::execution::Execution; 13 | use super::pattern::Pattern; 14 | 15 | #[derive(Clone, Debug)] 16 | pub struct Constructor { 17 | pub src: Span, 18 | pub table_name: String, 19 | pub display: Display, 20 | pub pattern: Pattern, 21 | pub disassembly: Option, 22 | pub execution: Option, 23 | } 24 | 25 | impl Constructor { 26 | pub fn table_name(&self) -> &str { 27 | &self.table_name 28 | } 29 | pub fn parse( 30 | input: &mut FilePreProcessor, 31 | buf: &mut Vec, 32 | ) -> Result> { 33 | input.parse_until(buf, |x| x.token_type == token_type!(":"))?; 34 | let (_eof, ((table_name, table_src), _, _)) = 35 | tuple((ident, tag!(":"), eof))(buf)?; 36 | let table_src = table_src.clone(); 37 | 38 | buf.clear(); 39 | Self::parse_table(input, buf, table_name, table_src) 40 | } 41 | 42 | pub fn parse_table( 43 | input: &mut FilePreProcessor, 44 | buf: &mut Vec, 45 | table_name: String, 46 | src: Span, 47 | ) -> Result> { 48 | let display = Display::parse(input)?; 49 | 50 | input.parse_until(buf, |token| { 51 | matches!( 52 | &token.token_type, 53 | token_type!("}") | token_type!("unimpl") 54 | ) 55 | })?; 56 | let (_eof, (pattern, disassembly, execution)) = tuple(( 57 | cut(Pattern::parse), 58 | //disassembly is optional 59 | opt(delimited(tag!("["), Disassembly::parse, tag!("]"))), 60 | //semantic could be empty or unimplemented (None) 61 | cut(alt(( 62 | value(None, tag!("unimpl")), 63 | delimited( 64 | tag!("{"), 65 | map(Execution::parse, Option::Some), 66 | tag!("}"), 67 | ), 68 | ))), 69 | ))(buf)?; 70 | 71 | let execution = if DISABLE_EXECUTION_PARSING { 72 | None 73 | } else { 74 | execution 75 | }; 76 | Ok(Self { 77 | src, 78 | table_name, 79 | display, 80 | pattern, 81 | execution, 82 | disassembly, 83 | }) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/syntax/block/with_block.rs: -------------------------------------------------------------------------------- 1 | use nom::combinator::{eof, opt}; 2 | use nom::sequence::{delimited, pair, terminated, tuple}; 3 | 4 | use crate::preprocessor::token::Token; 5 | use crate::preprocessor::FilePreProcessor; 6 | use crate::syntax::parser::{ident, this_ident, Parser}; 7 | use crate::syntax::Sleigh; 8 | use crate::{SleighError, IDENT_INSTRUCTION}; 9 | 10 | use super::disassembly::Disassembly; 11 | use super::pattern::Pattern; 12 | 13 | #[derive(Clone, Debug)] 14 | pub struct WithBlock { 15 | table_name: Option, 16 | pub pattern: Pattern, 17 | pub disassembly: Option, 18 | pub body: Sleigh, 19 | } 20 | 21 | impl WithBlock { 22 | pub fn table_name(&self) -> &str { 23 | self.table_name.as_deref().unwrap_or(IDENT_INSTRUCTION) 24 | } 25 | pub fn parse( 26 | input: &mut FilePreProcessor, 27 | buf: &mut Vec, 28 | ) -> Result> { 29 | input.parse_until(buf, |x| x.token_type == token_type!("{"))?; 30 | let (_eof, (table, pattern, disassembly)) = terminated( 31 | tuple(( 32 | delimited(this_ident("with"), opt(ident), tag!(":")), 33 | Pattern::parse, 34 | opt(delimited(tag!("["), Disassembly::parse, tag!("]"))), 35 | )), 36 | pair(tag!("{"), eof), 37 | )(buf)?; 38 | let table_name = table.map(|(name, _span)| name); 39 | 40 | //parse assertations until find a lonely } 41 | buf.clear(); 42 | let body = Sleigh::parse(input, buf, true)?; 43 | 44 | Ok(Self { 45 | table_name, 46 | pattern, 47 | disassembly, 48 | body, 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/syntax/define/alignment.rs: -------------------------------------------------------------------------------- 1 | use nom::combinator::map; 2 | use nom::sequence::{pair, preceded}; 3 | use nom::IResult; 4 | 5 | use crate::preprocessor::token::Token; 6 | use crate::syntax::parser::{number, this_ident}; 7 | use crate::{NumberUnsigned, SleighError}; 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct Alignment(pub NumberUnsigned); 11 | 12 | impl Alignment { 13 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 14 | preceded( 15 | pair(this_ident("alignment"), tag!("=")), 16 | map(number, |(num, _span)| Self(num)), 17 | )(input) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/syntax/define/bitrange.rs: -------------------------------------------------------------------------------- 1 | use nom::combinator::{cut, map}; 2 | use nom::multi::many0; 3 | use nom::sequence::{preceded, terminated, tuple}; 4 | use nom::IResult; 5 | 6 | use crate::preprocessor::token::Token; 7 | use crate::syntax::parser::{ident, this_ident}; 8 | use crate::syntax::BitRangeLsbLen; 9 | use crate::{SleighError, Span}; 10 | 11 | #[derive(Clone, Debug)] 12 | pub struct BitRangeDef { 13 | ranges: Vec, 14 | } 15 | 16 | impl BitRangeDef { 17 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 18 | map( 19 | preceded(this_ident("bitrange"), cut(many0(VarnodeField::parse))), 20 | |ranges| BitRangeDef { ranges }, 21 | )(input) 22 | } 23 | } 24 | 25 | impl IntoIterator for BitRangeDef { 26 | type Item = VarnodeField; 27 | type IntoIter = std::vec::IntoIter; 28 | 29 | fn into_iter(self) -> Self::IntoIter { 30 | self.ranges.into_iter() 31 | } 32 | } 33 | 34 | #[derive(Clone, Debug)] 35 | pub struct VarnodeField { 36 | pub src: Span, 37 | pub name: String, 38 | pub varnode_name: String, 39 | pub varnode_name_span: Span, 40 | pub range: BitRangeLsbLen, 41 | } 42 | 43 | impl VarnodeField { 44 | fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 45 | map( 46 | tuple((terminated(ident, tag!("=")), ident, BitRangeLsbLen::parse)), 47 | |((name, name_span), (varnode_name, varnode_name_span), range)| { 48 | VarnodeField { 49 | name, 50 | src: name_span.clone(), 51 | varnode_name, 52 | varnode_name_span: varnode_name_span.clone(), 53 | range, 54 | } 55 | }, 56 | )(input) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/syntax/define/context.rs: -------------------------------------------------------------------------------- 1 | use nom::combinator::{cut, map}; 2 | use nom::multi::many0; 3 | use nom::sequence::{pair, preceded, terminated, tuple}; 4 | use nom::IResult; 5 | 6 | use crate::preprocessor::token::Token; 7 | use crate::syntax::parser::{ident, this_ident}; 8 | use crate::syntax::BitRangeLsbMsb; 9 | use crate::{SleighError, Span}; 10 | 11 | use super::TokenFieldAttribute; 12 | 13 | #[derive(Clone, Debug)] 14 | pub struct Context { 15 | pub varnode_name: String, 16 | pub varnode_span: Span, 17 | pub fields: Vec, 18 | } 19 | 20 | impl Context { 21 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 22 | map( 23 | preceded( 24 | this_ident("context"), 25 | cut(pair(ident, many0(ContextField::parse))), 26 | ), 27 | |((varnode_name, varnode_span), fields)| Context { 28 | varnode_name, 29 | varnode_span: varnode_span.clone(), 30 | fields, 31 | }, 32 | )(input) 33 | } 34 | } 35 | 36 | #[derive(Clone, Debug)] 37 | pub struct ContextField { 38 | pub src: Span, 39 | pub name: String, 40 | pub range: BitRangeLsbMsb, 41 | pub attributes: Vec, 42 | } 43 | 44 | impl ContextField { 45 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 46 | map( 47 | tuple(( 48 | terminated(ident, tag!("=")), 49 | BitRangeLsbMsb::parse, 50 | many0(ContextFieldAttribute::parse), 51 | )), 52 | |((name, name_src), range, attributes)| Self { 53 | src: name_src.clone(), 54 | name, 55 | range, 56 | attributes, 57 | }, 58 | )(input) 59 | } 60 | } 61 | 62 | #[derive(Clone, Copy, Debug)] 63 | pub enum ContextFieldAttribute { 64 | Token(TokenFieldAttribute), 65 | Noflow, 66 | } 67 | 68 | impl ContextFieldAttribute { 69 | pub(crate) fn from_str(name: &str) -> Option { 70 | TokenFieldAttribute::from_str(name) 71 | .map(Self::Token) 72 | .or(match name { 73 | "noflow" => Some(Self::Noflow), 74 | _ => None, 75 | }) 76 | } 77 | fn parse(input_ori: &[Token]) -> IResult<&[Token], Self, Box> { 78 | let (input, (att, location)) = ident(input_ori)?; 79 | Self::from_str(&att) 80 | .map(|att| (input, att)) 81 | .ok_or(nom::Err::Error(Box::new(SleighError::StatementInvalid( 82 | location.clone(), 83 | )))) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/syntax/define/mod.rs: -------------------------------------------------------------------------------- 1 | mod alignment; 2 | mod bitrange; 3 | mod context; 4 | mod space; 5 | mod token; 6 | mod user_function; 7 | mod varnode; 8 | 9 | use nom::branch::alt; 10 | use nom::combinator::{cut, eof, map, value}; 11 | use nom::sequence::{pair, preceded, terminated}; 12 | use nom::IResult; 13 | 14 | use crate::{Endian, SleighError}; 15 | 16 | use crate::preprocessor::token::Token as ParserToken; 17 | 18 | pub use self::alignment::Alignment; 19 | pub use self::bitrange::BitRangeDef; 20 | pub use self::context::{Context, ContextFieldAttribute}; 21 | pub use self::space::{Attribute, Space}; 22 | pub use self::token::{Token, TokenFieldAttribute}; 23 | pub use self::user_function::UserFunction; 24 | pub use self::varnode::Varnode; 25 | 26 | use super::parser::this_ident; 27 | 28 | #[derive(Clone, Debug)] 29 | pub enum Define { 30 | Endian(Endian), 31 | Alignment(Alignment), 32 | Varnode(Varnode), 33 | Bitrange(BitRangeDef), 34 | Token(Token), 35 | UserFunction(UserFunction), 36 | Context(Context), 37 | Space(Space), 38 | } 39 | 40 | pub fn parse_endian( 41 | input: &[ParserToken], 42 | ) -> IResult<&[ParserToken], Endian, Box> { 43 | preceded( 44 | pair(this_ident("endian"), tag!("=")), 45 | cut(alt(( 46 | value(Endian::Little, this_ident("little")), 47 | value(Endian::Big, this_ident("big")), 48 | ))), 49 | )(input) 50 | } 51 | 52 | impl Define { 53 | pub fn parse(input: &[ParserToken]) -> Result> { 54 | let (_eof, define) = preceded( 55 | this_ident("define"), 56 | cut(terminated( 57 | alt(( 58 | map(parse_endian, Define::Endian), 59 | map(Alignment::parse, Define::Alignment), 60 | map(UserFunction::parse, Define::UserFunction), 61 | map(Space::parse, Define::Space), 62 | map(Token::parse, Define::Token), 63 | map(BitRangeDef::parse, Define::Bitrange), 64 | map(Context::parse, Define::Context), 65 | //NOTE Varnode need to be the last 66 | map(Varnode::parse, Define::Varnode), 67 | )), 68 | pair(tag!(";"), eof), 69 | )), 70 | )(input)?; 71 | Ok(define) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/syntax/define/space.rs: -------------------------------------------------------------------------------- 1 | use nom::branch::alt; 2 | use nom::combinator::{cut, map, value}; 3 | use nom::multi::many0; 4 | use nom::sequence::{pair, preceded}; 5 | use nom::IResult; 6 | 7 | use crate::preprocessor::token::Token; 8 | use crate::semantic::space::SpaceType; 9 | use crate::syntax::parser::{ident, number, this_ident}; 10 | use crate::{NumberUnsigned, SleighError, Span}; 11 | 12 | impl SpaceType { 13 | fn parse( 14 | input: &[Token], 15 | ) -> IResult<&[Token], SpaceType, Box> { 16 | alt(( 17 | value(SpaceType::Ram, this_ident("ram_space")), 18 | value(SpaceType::Rom, this_ident("rom_space")), 19 | value(SpaceType::Register, this_ident("register_space")), 20 | ))(input) 21 | } 22 | } 23 | 24 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] 25 | pub enum Attribute { 26 | Type(SpaceType), 27 | Size(NumberUnsigned), 28 | WordSize(NumberUnsigned), 29 | Default, 30 | } 31 | impl Attribute { 32 | fn parse( 33 | input: &[Token], 34 | ) -> IResult<&[Token], Attribute, Box> { 35 | alt(( 36 | value(Attribute::Default, this_ident("default")), 37 | map( 38 | preceded(pair(this_ident("type"), tag!("=")), SpaceType::parse), 39 | Attribute::Type, 40 | ), 41 | map( 42 | preceded(pair(this_ident("size"), tag!("=")), number), 43 | |(x, _span)| Attribute::Size(x), 44 | ), 45 | map( 46 | preceded(pair(this_ident("wordsize"), tag!("=")), number), 47 | |(x, _span)| Attribute::WordSize(x), 48 | ), 49 | ))(input) 50 | } 51 | } 52 | 53 | #[derive(Clone, Debug)] 54 | pub struct Space { 55 | pub name: String, 56 | pub src: Span, 57 | pub attributes: Vec, 58 | } 59 | 60 | impl Space { 61 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 62 | map( 63 | preceded( 64 | this_ident("space"), 65 | cut(pair(ident, many0(Attribute::parse))), 66 | ), 67 | |((name, name_span), attributes)| Space { 68 | name, 69 | src: name_span.clone(), 70 | attributes, 71 | }, 72 | )(input) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/syntax/define/token.rs: -------------------------------------------------------------------------------- 1 | use nom::combinator::{cut, map, opt}; 2 | use nom::multi::many0; 3 | use nom::sequence::{delimited, preceded, terminated, tuple}; 4 | use nom::IResult; 5 | 6 | use crate::preprocessor::token::Token as ParserToken; 7 | 8 | use crate::syntax::define::Endian; 9 | use crate::syntax::parser::{ident, number, this_ident}; 10 | use crate::syntax::BitRangeLsbMsb; 11 | use crate::{NumberUnsigned, SleighError, Span}; 12 | 13 | use super::parse_endian; 14 | 15 | #[derive(Clone, Debug)] 16 | pub struct Token { 17 | pub name: String, 18 | pub src: Span, 19 | pub size: NumberUnsigned, 20 | pub endian: Option, 21 | pub token_fields: Vec, 22 | } 23 | 24 | impl Token { 25 | pub fn parse( 26 | input: &[ParserToken], 27 | ) -> IResult<&[ParserToken], Self, Box> { 28 | map( 29 | preceded( 30 | this_ident("token"), 31 | cut(tuple(( 32 | ident, 33 | delimited(tag!("("), number, tag!(")")), 34 | opt(parse_endian), 35 | many0(TokenField::parse), 36 | ))), 37 | ), 38 | |((name, name_span), (size, _), endian, token_fields)| Token { 39 | name, 40 | src: name_span.clone(), 41 | size, 42 | endian, 43 | token_fields, 44 | }, 45 | )(input) 46 | } 47 | } 48 | 49 | #[derive(Clone, Debug)] 50 | pub struct TokenField { 51 | pub name: String, 52 | pub name_span: Span, 53 | pub range: BitRangeLsbMsb, 54 | pub attributes: Vec, 55 | } 56 | 57 | impl TokenField { 58 | pub fn parse( 59 | input: &[ParserToken], 60 | ) -> IResult<&[ParserToken], Self, Box> { 61 | map( 62 | tuple(( 63 | terminated(ident, tag!("=")), 64 | BitRangeLsbMsb::parse, 65 | many0(TokenFieldAttribute::parse), 66 | )), 67 | |((name, name_span), range, attributes)| TokenField { 68 | name, 69 | name_span: name_span.clone(), 70 | range, 71 | attributes, 72 | }, 73 | )(input) 74 | } 75 | } 76 | 77 | #[derive(Clone, Debug, Copy)] 78 | pub enum TokenFieldAttribute { 79 | Hex, 80 | Dec, 81 | Signed, 82 | } 83 | 84 | impl TokenFieldAttribute { 85 | pub(crate) fn from_str(name: &str) -> Option { 86 | match name { 87 | "signed" => Some(Self::Signed), 88 | "hex" => Some(Self::Hex), 89 | "dec" => Some(Self::Dec), 90 | _ => None, 91 | } 92 | } 93 | fn parse( 94 | input_ori: &[ParserToken], 95 | ) -> IResult<&[ParserToken], TokenFieldAttribute, Box> { 96 | let (input, (att, span)) = ident(input_ori)?; 97 | Self::from_str(&att) 98 | .map(|att| (input, att)) 99 | .ok_or(nom::Err::Error(Box::new(SleighError::StatementInvalid( 100 | span.clone(), 101 | )))) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/syntax/define/user_function.rs: -------------------------------------------------------------------------------- 1 | use nom::combinator::{cut, map}; 2 | use nom::sequence::preceded; 3 | use nom::IResult; 4 | 5 | use crate::preprocessor::token::Token; 6 | use crate::syntax::parser::{ident, this_ident}; 7 | use crate::{SleighError, Span}; 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct UserFunction { 11 | pub src: Span, 12 | pub name: String, 13 | } 14 | 15 | impl UserFunction { 16 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 17 | map( 18 | preceded(this_ident("pcodeop"), cut(ident)), 19 | |(name, name_src)| Self { 20 | name, 21 | src: name_src.clone(), 22 | }, 23 | )(input) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/syntax/define/varnode.rs: -------------------------------------------------------------------------------- 1 | use nom::combinator::map; 2 | use nom::sequence::{pair, preceded, tuple}; 3 | use nom::IResult; 4 | 5 | use crate::preprocessor::token::Token; 6 | use crate::syntax::parser::{ident, number, registerlist, this_ident}; 7 | use crate::{NumberUnsigned, SleighError, Span}; 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct Varnode { 11 | pub space_name: String, 12 | pub space_span: Span, 13 | pub offset: NumberUnsigned, 14 | pub value_bytes: NumberUnsigned, 15 | pub names: Vec<(Option, Span)>, 16 | } 17 | 18 | impl Varnode { 19 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 20 | map( 21 | tuple(( 22 | ident, 23 | preceded(pair(this_ident("offset"), tag!("=")), number), 24 | preceded(pair(this_ident("size"), tag!("=")), number), 25 | registerlist, 26 | )), 27 | |( 28 | (space_name, space_span), 29 | (offset, _), 30 | (value_bytes, _), 31 | names, 32 | )| Varnode { 33 | space_name, 34 | space_span: space_span.clone(), 35 | offset, 36 | value_bytes, 37 | names, 38 | }, 39 | )(input) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/syntax/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | pub mod parser; 3 | 4 | pub mod attach; 5 | pub mod block; 6 | pub mod define; 7 | 8 | use nom::branch::alt; 9 | use nom::combinator::map; 10 | use nom::sequence::{separated_pair, tuple}; 11 | use nom::IResult; 12 | 13 | use crate::preprocessor::token::{Token, TokenType}; 14 | use crate::preprocessor::FilePreProcessor; 15 | use crate::syntax::parser::Parser; 16 | use crate::{Number, NumberUnsigned, SleighError, Span}; 17 | 18 | use self::attach::Attach; 19 | use self::block::pcode_macro::PcodeMacro; 20 | use self::block::table::Constructor; 21 | use self::block::with_block::WithBlock; 22 | use self::define::Define; 23 | use self::parser::{ident, number, number_signed, number_unsigned}; 24 | 25 | #[derive(Clone, Debug)] 26 | pub enum Value { 27 | Number(Span, Number), 28 | Ident(Span, String), 29 | } 30 | 31 | impl Value { 32 | pub fn location(&self) -> &Span { 33 | match self { 34 | Value::Number(location, _) | Value::Ident(location, _) => location, 35 | } 36 | } 37 | pub fn parse_unsigned( 38 | input: &[Token], 39 | ) -> IResult<&[Token], Self, Box> { 40 | alt(( 41 | map(number_unsigned, |(x, span)| Self::Number(span.clone(), x)), 42 | map(ident, |(x, span)| Self::Ident(span.clone(), x)), 43 | ))(input) 44 | } 45 | pub fn parse_signed( 46 | input: &[Token], 47 | ) -> IResult<&[Token], Self, Box> { 48 | alt(( 49 | map(number_signed, |(x, span)| Self::Number(span.clone(), x)), 50 | map(ident, |(x, span)| Self::Ident(span.clone(), x)), 51 | ))(input) 52 | } 53 | } 54 | 55 | //TODO move this 56 | #[derive(Clone, Debug)] 57 | pub struct BitRangeLsbMsb { 58 | pub src: Span, 59 | pub lsb_bit: NumberUnsigned, 60 | pub msb_bit: NumberUnsigned, 61 | } 62 | impl BitRangeLsbMsb { 63 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 64 | map( 65 | tuple(( 66 | tag!("("), 67 | separated_pair(number, tag!(","), number), 68 | tag!(")"), 69 | )), 70 | |(start, ((lsb_bit, _), (msb_bit, _)), end)| Self { 71 | src: Span::combine(start.clone().start(), end.clone().end()), 72 | lsb_bit, 73 | msb_bit, 74 | }, 75 | )(input) 76 | } 77 | } 78 | #[derive(Clone, Debug)] 79 | pub struct BitRangeLsbLen { 80 | pub src: Span, 81 | pub lsb_bit: NumberUnsigned, 82 | pub n_bits: NumberUnsigned, 83 | } 84 | impl BitRangeLsbLen { 85 | pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box> { 86 | map( 87 | tuple(( 88 | tag!("["), 89 | separated_pair(number, tag!(","), number), 90 | tag!("]"), 91 | )), 92 | |(start, ((lsb_bit, _), (n_bits, _)), end)| Self { 93 | src: Span::combine(start.clone().start(), end.clone().end()), 94 | lsb_bit, 95 | n_bits, 96 | }, 97 | )(input) 98 | } 99 | } 100 | 101 | #[derive(Clone, Debug)] 102 | pub enum Assertation { 103 | Define(Define), 104 | Attach(Attach), 105 | TableConstructor(Constructor), 106 | PcodeMacro(PcodeMacro), 107 | WithBlock(WithBlock), 108 | } 109 | impl Assertation { 110 | fn parse( 111 | input: &mut FilePreProcessor, 112 | buf: &mut Vec, 113 | inside_with_block: bool, 114 | ) -> Result, Box> { 115 | assert!(buf.is_empty()); 116 | let token = match input.parse() { 117 | Ok(Some(token)) => token, 118 | Ok(None) => return Ok(None), 119 | Err(e) => return Err(e.into()), 120 | }; 121 | buf.push(token); 122 | let token_ref = &buf[0]; 123 | let assertation = match &token_ref.token_type { 124 | //TODO make those reserved words into tokens? 125 | TokenType::Ident(x) if x == "define" => { 126 | input.parse_until(buf, |x| x.token_type == token_type!(";"))?; 127 | Define::parse(buf).map(Self::Define)? 128 | } 129 | TokenType::Ident(x) if x == "attach" => { 130 | input.parse_until(buf, |x| x.token_type == token_type!(";"))?; 131 | Attach::parse(buf).map(Self::Attach)? 132 | } 133 | TokenType::Ident(x) if x == "macro" => { 134 | input.parse_until(buf, |x| x.token_type == token_type!("}"))?; 135 | PcodeMacro::parse(buf).map(Self::PcodeMacro)? 136 | } 137 | TokenType::Ident(x) if x == "with" => { 138 | WithBlock::parse(input, buf).map(Self::WithBlock)? 139 | } 140 | TokenType::Ident(_table) => { 141 | Constructor::parse(input, buf).map(Self::TableConstructor)? 142 | } 143 | //instruction table 144 | TokenType::DubleDot => { 145 | let src = token_ref.location.clone(); 146 | buf.clear(); 147 | Constructor::parse_table(input, buf, "".to_string(), src) 148 | .map(Self::TableConstructor)? 149 | } 150 | //close with_block 151 | TokenType::DeliCloseCurly if inside_with_block => return Ok(None), 152 | _ => { 153 | return Err(Box::new(SleighError::StatementInvalid( 154 | token_ref.location.clone(), 155 | ))) 156 | } 157 | }; 158 | Ok(Some(assertation)) 159 | } 160 | } 161 | 162 | #[derive(Clone, Debug)] 163 | pub struct Sleigh { 164 | pub assertations: Vec, 165 | } 166 | impl Sleigh { 167 | pub fn parse( 168 | input: &mut FilePreProcessor, 169 | buf: &mut Vec, 170 | inside_with_block: bool, 171 | ) -> Result>> { 172 | let mut assertations = vec![]; 173 | loop { 174 | buf.clear(); 175 | let Some(ass) = Assertation::parse(input, buf, inside_with_block)? 176 | else { 177 | break; 178 | }; 179 | assertations.push(ass); 180 | } 181 | Ok(Self { assertations }) 182 | } 183 | } 184 | --------------------------------------------------------------------------------