├── .gitignore ├── fuzz ├── .gitignore ├── Cargo.toml └── fuzzers │ └── parser.rs ├── rustfmt.toml ├── Cargo.toml ├── src ├── lib.rs ├── vm.rs ├── lexer.rs └── parser.rs ├── appveyor.yml ├── .travis.yml ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | *.swp 4 | *.swo 5 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | target 3 | corpus 4 | artifacts 5 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | format_strings = false 2 | reorder_imports = true 3 | take_source_hints = false 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "esil" 3 | version = "0.1.0" 4 | authors = ["Sushant "] 5 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, The Radare Project. All rights reserved. 2 | // See the COPYING file at the top-level directory of this distribution. 3 | // Licensed under the BSD 3-Clause License: 4 | // 5 | // This file may not be copied, modified, or distributed 6 | // except according to those terms. 7 | 8 | pub mod lexer; 9 | pub mod parser; 10 | //pub mod memory; 11 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "esil-fuzz" 4 | version = "0.0.1" 5 | authors = ["Radeco Developers"] 6 | publish = false 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [dependencies.esil] 12 | path = ".." 13 | [dependencies.libfuzzer-sys] 14 | git = "https://github.com/rust-fuzz/libfuzzer-sys.git" 15 | 16 | # Prevent this from interfering with workspaces 17 | [workspace] 18 | members = ["."] 19 | 20 | [[bin]] 21 | name = "parser" 22 | path = "fuzzers/parser.rs" 23 | -------------------------------------------------------------------------------- /src/vm.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, The Radare Project. All rights reserved. 2 | // See the COPYING file at the top-level directory of this distribution. 3 | // Licensed under the BSD 3-Clause License: 4 | // 5 | // This file may not be copied, modified, or distributed 6 | // except according to those terms. 7 | 8 | /// Design decisions for Parser and VM. 9 | /// 10 | /// Idea1: 11 | /// ``` 12 | /// evaluator = Evaluator::new(); 13 | /// p = Parser::init(&evaluator); 14 | /// p.parse("eax, ebx, +="); 15 | /// p.parse("ecx, eax, ="); 16 | /// p.results(); 17 | /// ``` 18 | /// 19 | /// Idea2: 20 | /// ``` 21 | /// p = Parser::new(); 22 | /// evaluator = Evaluator::init(&p); 23 | /// evaluator.run() 24 | /// 25 | /// impl Evaluator { 26 | /// fn run() { 27 | /// self.p.parse(&self, insts); 28 | /// // "a,b,+=,$z,zf,=" 29 | /// } 30 | /// } 31 | /// ``` 32 | /// 33 | /// 34 | /// 35 | /// 36 | /// ----------- 37 | /// | Evaluator| <-> | Parser | 38 | /// ____________ 39 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | clone_depth: 1 2 | environment: 3 | matrix: 4 | - channel: stable 5 | target: i686-pc-windows-msvc 6 | - channel: stable 7 | target: x86_64-pc-windows-msvc 8 | - channel: beta 9 | target: i686-pc-windows-msvc 10 | - channel: beta 11 | target: x86_64-pc-windows-msvc 12 | - channel: nightly 13 | target: i686-pc-windows-msvc 14 | - channel: nightly 15 | target: x86_64-pc-windows-msvc 16 | 17 | - channel: stable 18 | target: i686-pc-windows-gnu 19 | - channel: stable 20 | target: x86_64-pc-windows-gnu 21 | - channel: beta 22 | target: i686-pc-windows-gnu 23 | - channel: beta 24 | target: x86_64-pc-windows-gnu 25 | - channel: nightly 26 | target: i686-pc-windows-gnu 27 | - channel: nightly 28 | target: x86_64-pc-windows-gnu 29 | install: 30 | - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 31 | - rustup-init -yv --default-toolchain %channel% --default-host %target% 32 | - set PATH=%PATH%;%USERPROFILE%\.cargo\bin 33 | - rustc -vV 34 | - cargo -vV 35 | build_script: 36 | - cargo build -vv 37 | test_script: 38 | - cargo test -vv 39 | deploy: off 40 | -------------------------------------------------------------------------------- /fuzz/fuzzers/parser.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] extern crate libfuzzer_sys; 3 | extern crate esil; 4 | 5 | use std::collections::HashMap; 6 | use std::str; 7 | 8 | use esil::parser::{Parse, Parser}; 9 | use esil::lexer::{Token, Tokenizer}; 10 | 11 | fuzz_target!(|data: &[u8]| { 12 | if let Ok(esil) = str::from_utf8(data) { 13 | let regset: HashMap = { 14 | let mut regset = HashMap::new(); 15 | regset.insert("rax".to_owned(), 64); 16 | regset.insert("rbx".to_owned(), 64); 17 | regset.insert("rcx".to_owned(), 64); 18 | regset.insert("eax".to_owned(), 32); 19 | regset.insert("ebx".to_owned(), 32); 20 | regset.insert("ecx".to_owned(), 32); 21 | regset.insert("zf".to_owned(), 1); 22 | regset.insert("pf".to_owned(), 1); 23 | regset.insert("cf".to_owned(), 1); 24 | regset.insert("of".to_owned(), 1); 25 | regset.insert("sf".to_owned(), 1); 26 | regset 27 | }; 28 | let mut parser = Parser::init(Some(regset), Some(64)); 29 | parser.lastsz = Some(Token::EConstant(64)); 30 | while let Ok(Some(ref token)) = parser.parse::<_, Tokenizer>(esil) { 31 | let _ = parser.fetch_operands(token); 32 | } 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: trusty 3 | language: rust 4 | addons: 5 | apt: 6 | packages: 7 | - libcurl4-openssl-dev 8 | - libelf-dev 9 | - libdw-dev 10 | - binutils-dev 11 | matrix: 12 | fast_finish: true 13 | allow_failures: 14 | - rust: nightly 15 | rust: 16 | - nightly 17 | - beta 18 | - stable 19 | os: 20 | - linux 21 | before_script: 22 | - | 23 | pip install 'travis-cargo<0.2' --user && 24 | export PATH=$HOME/.local/bin:$PATH 25 | script: 26 | - | 27 | travis-cargo build && 28 | travis-cargo test && 29 | travis-cargo bench 30 | after_success: 31 | - travis-cargo --only stable coveralls --no-sudo --verify 32 | - travis-cargo --only stable doc-upload 33 | env: 34 | global: 35 | - TRAVIS_CARGO_NIGHTLY_FEATURE="" 36 | - secure: "agLyQ0uc9RGB8CUfOiXCOSykWk84HE8MxeWJiJkUzgwN/aeCWY6vqrzoItwCmtRTbj2CqbPdaRit94IL8LzdJY70HIyvyO1o5j7u6l/qWvBofzUxc1EcVrKO0HodiDVgkc64APDLRI8QSeLPF7mVBtQcrJgAsG/d9sCe6soHAX8t84JUbHSJUXiMyS9mtxmTwRDiw/MPB+FMTU3PoNEJ/WYDOU7mqAeOtjLS0pynNtXWEkmYPy1zi8myhFT9dj/g4mtgiLLcwPrqFYnQc0kR/+w9VI5WBaH5zH/UncK0L9eS/jUteXLl/4Xk9N0cDogQXrk+Nkl/3RLChQ7yc5uN2VVojnYJXQJA/Cq5FyeJBmhD96YydZ/61CB9PRJw0XOv7HyOsgKRH+RGwSW3e3KfzOfYBsPFiWg0DCxc4RmsOkexWlQ7h5VSm8aXP9pxBoGU/T4Ai3puRVeiVEJyF9mo6Cs6jaGqnmqhQJ673NudH5VYECVNT+DRo0UmqmIhm/JbpihkL/8h3TeS1hmZusuNq0flx+BnoPgqFMDs5Iaz4kxbPZe/07OjxovKIbPkVU8puGDAjVj5c7HN/nFU2ohKF2E7QLrVytYPfVv6b6x7j8/3YNrsihBPGSMzR1//QIWD52v3Zw8/0qvHcbcH24Wpr4Y8BIXdZ8XgPrVUJAO2GuA=" 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, The Radare Project 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or 5 | without modification, are permitted provided that the following 6 | conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and / or other materials provided 14 | with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esil.rs 2 | [![Build Status](https://travis-ci.org/radareorg/esil-rs.svg)](https://travis-ci.org/radareorg/esil-rs) 3 | [![Build status](https://ci.appveyor.com/api/projects/status/7mawhhr97nhb17vs?svg=true)](https://ci.appveyor.com/project/radare/esil-rs) 4 | [![Coverage Status](https://coveralls.io/repos/github/radare/esil-rs/badge.svg?branch=master)](https://coveralls.io/github/radare/esil-rs?branch=master) 5 | 6 | An ESIL Toolchain written in rust. For more information on ESIL, its usage and 7 | semantics, please check [documentation](https://github.com/radare/radare2book/blob/master/src/disassembling/esil.md). 8 | 9 | ## Design 10 | 11 | This repository is mainly divided into three modules. With very specific 12 | function for each. The ideal end-goal is to be able to use ESIL for a specific 13 | purpose by implementing only a particular component and reuse every other. 14 | Below is the outline for the same. 15 | 16 | - lexer.rs: Used to break up input ESIL string into `Tokens`. If ESIL is the 17 | `Input` Language of your choice, then this lexer can be reused. A new lexer 18 | has to be written only if the input language is something other than ESIL. 19 | 20 | - parser.rs: Used to parse the `Tokens` generated by the lexer. The `InType` 21 | of `Parse` should match the `Token` type for `Tokenize`. As long as your 22 | lexer outputs `Tokens` (as defined in lexer.rs), this component can be 23 | reused to process the tokens that your lexer produces. The parser does not 24 | work as a standalone as a standalone and is to be embeded into an 25 | `Evaluator`. The parser does most of the heavy work in translating ESIL, 26 | leaving the `Evaluator` to only evaluate the Tokens that it returns to it. 27 | 28 | - evaluator: The evaluator is the most interesting part of all. The evaluator 29 | can be anything from an ESIL-VM, to a ESIL to REIL converter, Symbolic 30 | Execution engine etc. It is upto the evaluator to decide what to do with the 31 | tokens that are returned by the parser. The implementation of the evaluator 32 | depends on the use case. Usually, this is the only component that is to be 33 | implemented when using ESIL for any analysis. 34 | 35 | (TODO) To see a sample usage of an evaluator, check vm.rs or radeco-lib 36 | 37 | 38 | ## Todo 39 | 40 | * Default Evaluator (ESIL-VM) implementation 41 | * More usage examples and auto-documentation 42 | 43 | ## License 44 | 45 | The code in this repository is licensed under the 3-clause BSD. Check 46 | [LICENSE](https://github.com/sushant94/esil-rs/blob/master/LICENSE) for a copy of the same. 47 | -------------------------------------------------------------------------------- /src/lexer.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, The Radare Project. All rights reserved. 2 | // See the COPYING file at the top-level directory of this distribution. 3 | // Licensed under the BSD 3-Clause License: 4 | // 5 | // This file may not be copied, modified, or distributed 6 | // except according to those terms. 7 | 8 | use std::fmt::Debug; 9 | use std::collections::VecDeque; 10 | 11 | const ESIL_INTERNAL_PREFIX: char = '$'; 12 | const DEFAULT_SIZE: u8 = 64; 13 | 14 | #[derive(Debug, Clone, PartialEq)] 15 | pub enum Token { 16 | // Esil Opcodes 17 | EInterrupt, 18 | ECmp, 19 | ELt, 20 | EGt, 21 | EEq, 22 | EIf, 23 | EEndIf, 24 | ELsl, 25 | ELsr, 26 | ERor, 27 | ERol, 28 | EAnd, 29 | EOr, 30 | ENop, 31 | ENeg, 32 | EMul, 33 | EXor, 34 | EAdd, 35 | ESub, 36 | EDiv, 37 | EMod, 38 | EPoke(u8), 39 | EPeek(u8), 40 | EDump, 41 | EPop, 42 | ETodo, 43 | EGoto, 44 | EBreak, 45 | EClear, 46 | EDup, 47 | ETrap, 48 | // Invalid 49 | EInvalid, 50 | // Parser Instructions. 51 | PCopy(usize), 52 | PPop(usize), 53 | PSync, 54 | // Esil Internal Vars 55 | IZero(u8), 56 | ICarry(u8), 57 | IParity(u8), 58 | IOverflow(u8), 59 | ISign(u8), 60 | IBorrow(u8), 61 | ISize(u8), 62 | IAddress(u8), 63 | IConstant(u64), 64 | // Esil Operands 65 | EConstant(u64), 66 | EIdentifier(String), 67 | // Custom type to allow pushing symbol table entries. 68 | // (entry_id, size - optional. Used to set lastsz.) 69 | // If no size is specified for the entry, then the default size from the parser is used to set 70 | // the lastsz. 71 | EEntry(usize, Option), 72 | ERegister(String), 73 | // Meta-variables 74 | // These are not emmitted by the lexer, but is used by the parser to communicate special 75 | // variables to the `Evaluator`. 76 | EOld, 77 | EOld_, 78 | ECur, 79 | ELastsz, 80 | EAddress, 81 | } 82 | 83 | impl Token { 84 | pub fn is_binary(&self) -> bool { 85 | match *self { 86 | Token::ECmp | 87 | Token::ELt | 88 | Token::EGt | 89 | Token::EEq | 90 | Token::ELsl | 91 | Token::ELsr | 92 | Token::ERor | 93 | Token::ERol | 94 | Token::EAnd | 95 | Token::EOr | 96 | Token::EMul | 97 | Token::EXor | 98 | Token::EAdd | 99 | Token::ESub | 100 | Token::EDiv | 101 | Token::EMod | 102 | Token::EPoke(_) => true, 103 | _ => false, 104 | } 105 | } 106 | 107 | pub fn is_unary(&self) -> bool { 108 | match *self { 109 | Token::EPop | Token::ENeg | Token::EIf | Token::EPeek(_) => true, 110 | _ => false, 111 | } 112 | } 113 | 114 | pub fn is_arity_zero(&self) -> bool { 115 | match *self { 116 | Token::EDump | Token::ENop | Token::EEndIf => true, 117 | _ => false, 118 | } 119 | } 120 | 121 | pub fn is_implemented(&self) -> bool { 122 | match *self { 123 | Token::ETodo | 124 | Token::EInterrupt | 125 | Token::EGoto | 126 | Token::EBreak | 127 | Token::EClear | 128 | Token::ETrap => false, 129 | _ => true, 130 | } 131 | } 132 | 133 | pub fn is_meta(&self) -> bool { 134 | match *self { 135 | Token::EOld | 136 | Token::EOld_ | 137 | Token::ECur | 138 | Token::ELastsz | 139 | Token::EAddress => true, 140 | _ => false, 141 | } 142 | } 143 | 144 | pub fn should_set_vars(&self) -> bool { 145 | match *self { 146 | Token::ECmp | Token::EEq | Token::EPoke(_) | Token::EGt | Token::ELt => true, 147 | _ => false, 148 | } 149 | } 150 | 151 | pub fn updates_result(&self) -> bool { 152 | // If it an operator 153 | if self.is_binary() || self.is_unary() || self.is_arity_zero() { 154 | match *self { 155 | Token::EEq | Token::EPoke(_) => false, 156 | _ => true, 157 | } 158 | } else { 159 | false 160 | } 161 | } 162 | } 163 | 164 | pub trait Tokenize { 165 | type Token: Clone + Debug + PartialEq; 166 | fn tokenize>(esil: T) -> VecDeque; 167 | } 168 | 169 | pub struct Tokenizer; 170 | 171 | impl Tokenize for Tokenizer { 172 | type Token = Token; 173 | fn tokenize>(esil: T) -> VecDeque { 174 | let mut tokens = VecDeque::new(); 175 | for t in esil.as_ref().split(",").into_iter() { 176 | tokens.extend( 177 | match t { 178 | "$" => vec![Token::EInterrupt], 179 | "==" => vec![Token::ECmp], 180 | 181 | "<" => vec![Token::ELt], 182 | ">" => vec![Token::EGt], 183 | "<=" => vec![Token::PCopy(2), Token::ELt, Token::PPop(2), 184 | Token::ECmp, Token::EOr], 185 | ">=" => vec![Token::PCopy(2), Token::EGt, Token::PPop(2), 186 | Token::ECmp, Token::EOr], 187 | 188 | "?{" => vec![Token::EIf], 189 | 190 | "<<" => vec![Token::ELsl], 191 | "<<=" => vec![Token::PCopy(1), Token::ELsl, Token::PPop(1), 192 | Token::EEq], 193 | 194 | ">>" => vec![Token::ELsr], 195 | ">>=" => vec![Token::PCopy(1), Token::ELsr, Token::PPop(1), 196 | Token::EEq], 197 | 198 | ">>>" => vec![Token::ERor], 199 | "<<<" => vec![Token::ERol], 200 | 201 | "&" => vec![Token::EAnd], 202 | "&=" => vec![Token::PCopy(1), Token::EAnd, Token::PPop(1), 203 | Token::EEq], 204 | 205 | "}" => vec![Token::EEndIf], 206 | 207 | "|" => vec![Token::EOr], 208 | "|=" => vec![Token::PCopy(1), Token::EOr, Token::PPop(1), 209 | Token::EEq], 210 | 211 | "!" => vec![Token::ENeg], 212 | "!=" => vec![Token::PCopy(1), Token::ENeg, Token::PPop(1), Token::EEq], 213 | 214 | "=" => vec![Token::EEq], 215 | 216 | "*" => vec![Token::EMul], 217 | "*=" => vec![Token::PCopy(1), Token::EMul, Token::PPop(1), 218 | Token::EEq], 219 | 220 | "^" => vec![Token::EXor], 221 | "^=" => vec![Token::PCopy(1), Token::EXor, Token::PPop(1), 222 | Token::EEq], 223 | 224 | "+" => vec![Token::EAdd], 225 | "+=" => vec![Token::PCopy(1), Token::EAdd, Token::PPop(1), 226 | Token::EEq], 227 | 228 | "++" => vec![Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), 229 | Token::EAdd], 230 | "++=" => vec![Token::PCopy(1), Token::PCopy(1), Token::EPop, 231 | Token::EConstant(1), Token::PPop(1), Token::EAdd, Token::PPop(1), Token::EEq], 232 | 233 | "-" => vec![Token::ESub], 234 | "-=" => vec![Token::PCopy(1), Token::ESub, Token::PPop(1), 235 | Token::EEq], 236 | 237 | "--" => vec![Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), 238 | Token::ESub], 239 | "--=" => vec![Token::PCopy(1), Token::PCopy(1), Token::EPop, 240 | Token::EConstant(1), Token::PPop(1), Token::ESub, Token::PPop(1), Token::EEq], 241 | 242 | "/" => vec![Token::EDiv], 243 | "/=" => vec![Token::PCopy(1), Token::EDiv, Token::PPop(1), 244 | Token::EEq], 245 | 246 | "%" => vec![Token::EMod], 247 | "%=" => vec![Token::PCopy(1), Token::EMod, Token::PPop(1), 248 | Token::EEq], 249 | 250 | "=[]" => vec![Token::EPoke(64)], 251 | "=[1]" => vec![Token::EPoke(8)], 252 | "=[2]" => vec![Token::EPoke(16)], 253 | "=[4]" => vec![Token::EPoke(32)], 254 | "=[8]" => vec![Token::EPoke(64)], 255 | 256 | "|=[]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EOr, 257 | Token::PPop(1), Token::EPoke(64)], 258 | "|=[1]" => vec![Token::PCopy(1), Token::EPeek(8), Token::EOr, 259 | Token::PPop(1), Token::EPoke(8)], 260 | "|=[2]" => vec![Token::PCopy(1), Token::EPeek(16), Token::EOr, 261 | Token::PPop(1), Token::EPoke(16)], 262 | "|=[4]" => vec![Token::PCopy(1), Token::EPeek(32), Token::EOr, 263 | Token::PPop(1), Token::EPoke(32)], 264 | "|=[8]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EOr, 265 | Token::PPop(1), Token::EPoke(64)], 266 | 267 | "^=[]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EXor, 268 | Token::PPop(1), Token::EPoke(64)], 269 | "^=[1]" => vec![Token::PCopy(1), Token::EPeek(8), Token::EXor, 270 | Token::PPop(1), Token::EPoke(8)], 271 | "^=[2]" => vec![Token::PCopy(1), Token::EPeek(16), Token::EXor, 272 | Token::PPop(1), Token::EPoke(16)], 273 | "^=[4]" => vec![Token::PCopy(1), Token::EPeek(32), Token::EXor, 274 | Token::PPop(1), Token::EPoke(32)], 275 | "^=[8]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EXor, 276 | Token::PPop(1), Token::EPoke(64)], 277 | 278 | "&=[]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EAnd, 279 | Token::PPop(1), Token::EPoke(64)], 280 | "&=[1]" => vec![Token::PCopy(1), Token::EPeek(8), Token::EAnd, 281 | Token::PPop(1), Token::EPoke(8)], 282 | "&=[2]" => vec![Token::PCopy(1), Token::EPeek(16), Token::EAnd, 283 | Token::PPop(1), Token::EPoke(16)], 284 | "&=[4]" => vec![Token::PCopy(1), Token::EPeek(32), Token::EAnd, 285 | Token::PPop(1), Token::EPoke(32)], 286 | "&=[8]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EAnd, 287 | Token::PPop(1), Token::EPoke(64)], 288 | 289 | "+=[]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EAdd, 290 | Token::PPop(1), Token::EPoke(64)], 291 | "+=[1]" => vec![Token::PCopy(1), Token::EPeek(8), Token::EAdd, 292 | Token::PPop(1), Token::EPoke(8)], 293 | "+=[2]" => vec![Token::PCopy(1), Token::EPeek(16), Token::EAdd, 294 | Token::PPop(1), Token::EPoke(16)], 295 | "+=[4]" => vec![Token::PCopy(1), Token::EPeek(32), Token::EAdd, 296 | Token::PPop(1), Token::EPoke(32)], 297 | "+=[8]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EAdd, 298 | Token::PPop(1), Token::EPoke(64)], 299 | 300 | "-=[]" => vec![Token::PCopy(1), Token::EPeek(64), Token::ESub, 301 | Token::PPop(1), Token::EPoke(64)], 302 | "-=[1]" => vec![Token::PCopy(1), Token::EPeek(8), Token::ESub, 303 | Token::PPop(1), Token::EPoke(8)], 304 | "-=[2]" => vec![Token::PCopy(1), Token::EPeek(16), Token::ESub, 305 | Token::PPop(1), Token::EPoke(16)], 306 | "-=[4]" => vec![Token::PCopy(1), Token::EPeek(32), Token::ESub, 307 | Token::PPop(1), Token::EPoke(32)], 308 | "-=[8]" => vec![Token::PCopy(1), Token::EPeek(64), Token::ESub, 309 | Token::PPop(1), Token::EPoke(64)], 310 | 311 | "%=[]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EMod, 312 | Token::PPop(1), Token::EPoke(64)], 313 | "%=[1]" => vec![Token::PCopy(1), Token::EPeek(8), Token::EMod, 314 | Token::PPop(1), Token::EPoke(8)], 315 | "%=[2]" => vec![Token::PCopy(1), Token::EPeek(16), Token::EMod, 316 | Token::PPop(1), Token::EPoke(16)], 317 | "%=[4]" => vec![Token::PCopy(1), Token::EPeek(32), Token::EMod, 318 | Token::PPop(1), Token::EPoke(32)], 319 | "%=[8]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EMod, 320 | Token::PPop(1), Token::EPoke(64)], 321 | 322 | "/=[]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EDiv, 323 | Token::PPop(1), Token::EPoke(64)], 324 | "/=[1]" => vec![Token::PCopy(1), Token::EPeek(8), Token::EDiv, 325 | Token::PPop(1), Token::EPoke(8)], 326 | "/=[2]" => vec![Token::PCopy(1), Token::EPeek(16), Token::EDiv, 327 | Token::PPop(1), Token::EPoke(16)], 328 | "/=[4]" => vec![Token::PCopy(1), Token::EPeek(32), Token::EDiv, 329 | Token::PPop(1), Token::EPoke(32)], 330 | "/=[8]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EDiv, 331 | Token::PPop(1), Token::EPoke(64)], 332 | 333 | "*=[]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EMul, 334 | Token::PPop(1), Token::EPoke(64)], 335 | "*=[1]" => vec![Token::PCopy(1), Token::EPeek(8), Token::EMul, 336 | Token::PPop(1), Token::EPoke(8)], 337 | "*=[2]" => vec![Token::PCopy(1), Token::EPeek(16), Token::EMul, 338 | Token::PPop(1), Token::EPoke(16)], 339 | "*=[4]" => vec![Token::PCopy(1), Token::EPeek(32), Token::EMul, 340 | Token::PPop(1), Token::EPoke(32)], 341 | "*=[8]" => vec![Token::PCopy(1), Token::EPeek(64), Token::EMul, 342 | Token::PPop(1), Token::EPoke(64)], 343 | 344 | "++=[]" => vec![Token::PCopy(1), Token::EPeek(64), 345 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::EAdd, 346 | Token::PPop(1), Token::EPoke(64)], 347 | "++=[1]" => vec![Token::PCopy(1), Token::EPeek(8), 348 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::EAdd, 349 | Token::PPop(1), Token::EPoke(8)], 350 | "++=[2]" => vec![Token::PCopy(1), Token::EPeek(16), 351 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::EAdd, 352 | Token::PPop(1), Token::EPoke(16)], 353 | "++=[4]" => vec![Token::PCopy(1), Token::EPeek(32), 354 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::EAdd, 355 | Token::PPop(1), Token::EPoke(32)], 356 | "++=[8]" => vec![Token::PCopy(1), Token::EPeek(64), 357 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::EAdd, 358 | Token::PPop(1), Token::EPoke(64)], 359 | 360 | "--=[]" => vec![Token::PCopy(1), Token::EPeek(64), 361 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::ESub, 362 | Token::PPop(1), Token::EPoke(64)], 363 | "--=[1]" => vec![Token::PCopy(1), Token::EPeek(8), 364 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::ESub, 365 | Token::PPop(1), Token::EPoke(8)], 366 | "--=[2]" => vec![Token::PCopy(1), Token::EPeek(16), 367 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::ESub, 368 | Token::PPop(1), Token::EPoke(16)], 369 | "--=[4]" => vec![Token::PCopy(1), Token::EPeek(32), 370 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::ESub, 371 | Token::PPop(1), Token::EPoke(32)], 372 | "--=[8]" => vec![Token::PCopy(1), Token::EPeek(64), 373 | Token::PCopy(1), Token::EPop, Token::EConstant(1), Token::PPop(1), Token::ESub, 374 | Token::PPop(1), Token::EPoke(64)], 375 | 376 | "[]" => vec![Token::EPeek(64)], 377 | "[*]" => vec![Token::EPeek(64)], 378 | "=[*]" => vec![Token::EPoke(64)], 379 | "[1]" => vec![Token::EPeek(8)], 380 | "[2]" => vec![Token::EPeek(16)], 381 | "[4]" => vec![Token::EPeek(32)], 382 | "[8]" => vec![Token::EPeek(64)], 383 | 384 | "STACK" => vec![Token::EDump], 385 | "POP" => vec![Token::EPop], 386 | "TODO" => vec![Token::ETodo], 387 | "GOTO" => vec![Token::EGoto], 388 | "BREAK" => vec![Token::EBreak], 389 | "CLEAR" => vec![Token::EClear], 390 | "DUP" => vec![Token::EDup], 391 | "TRAP" => vec![Token::ETrap], 392 | _ => { 393 | // Handle internal vars 394 | if Some(ESIL_INTERNAL_PREFIX) == t.chars().nth(0) { 395 | let bit = if t.len() < 3 || !t.is_char_boundary(2) { 396 | DEFAULT_SIZE 397 | } else { 398 | t[2..].parse::().unwrap_or(DEFAULT_SIZE) 399 | }; 400 | match t.chars().nth(1).unwrap_or('\0') { 401 | '$' => vec![Token::IAddress(bit)], 402 | 'z' => vec![Token::IZero(bit)], 403 | 'b' => vec![Token::IBorrow(bit)], 404 | 'c' => vec![Token::ICarry(bit)], 405 | 'p' => vec![Token::IParity(bit)], 406 | 'r' => vec![Token::ISize(bit)], 407 | 'o' => vec![Token::IOverflow(bit)], 408 | 's' => vec![Token::ISign(bit)], 409 | _ => { 410 | if let Ok(num) = t[1..].parse::() { 411 | vec![Token::IConstant(num)] 412 | } else { 413 | vec![Token::EInvalid] 414 | } 415 | } 416 | } 417 | } else if t.starts_with("0x") { 418 | match u64::from_str_radix(t.trim_start_matches("0x"), 16) { 419 | Ok(v) => vec![Token::EConstant(v)], 420 | Err(_) => vec![Token::EInvalid], 421 | } 422 | } else if let Ok(v) = t.parse::() { 423 | vec![Token::EConstant(v as u64)] 424 | } else if let Ok(v) = t.parse::() { 425 | vec![Token::EConstant(v)] 426 | } else { 427 | // Just returns it as an identifier. It is upto the 428 | // parser to decide if it is a valid token. 429 | vec![Token::EIdentifier(t.to_owned())] 430 | } 431 | } 432 | }); 433 | } 434 | tokens 435 | } 436 | } 437 | 438 | #[cfg(test)] 439 | mod test { 440 | use std::str; 441 | use super::*; 442 | 443 | #[test] 444 | fn esil_basic() { 445 | let op = vec![Token::EAdd]; 446 | assert_eq!(op[0], Tokenizer::tokenize("+")[0]); 447 | } 448 | 449 | #[test] 450 | fn negative_int() { 451 | assert_eq!(Token::EConstant(0xFFFFFFFFFFFFFFFF), 452 | Tokenizer::tokenize("-1")[0]); 453 | } 454 | 455 | #[test] 456 | fn u64_max_int() { 457 | assert_eq!(Token::EConstant(u64::max_value()), 458 | Tokenizer::tokenize("18446744073709551615")[0]); 459 | } 460 | 461 | #[test] 462 | fn u64_min_int() { 463 | assert_eq!(Token::EConstant(0), 464 | Tokenizer::tokenize(format!("{}", u64::min_value()))[0]); 465 | } 466 | 467 | #[test] 468 | fn i64_min_int() { 469 | assert_eq!(Token::EConstant(i64::min_value() as u64), 470 | Tokenizer::tokenize(format!("{}", i64::min_value()))[0]); 471 | } 472 | 473 | #[test] 474 | fn i64_max_int() { 475 | assert_eq!(Token::EConstant(i64::max_value() as u64), 476 | Tokenizer::tokenize(format!("{}", i64::max_value()))[0]); 477 | } 478 | 479 | #[test] 480 | fn utf8_internal_prefix() { 481 | Tokenizer::tokenize(str::from_utf8(&vec![0x24,0xda,0x91]).unwrap()); 482 | } 483 | } 484 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, The Radare Project. All rights reserved. 2 | // See the COPYING file at the top-level directory of this distribution. 3 | // Licensed under the BSD 3-Clause License: 4 | // 5 | // This file may not be copied, modified, or distributed 6 | // except according to those terms. 7 | 8 | use lexer::{Token, Tokenize}; 9 | 10 | use std::fmt::Debug; 11 | use std::collections::{HashMap, VecDeque}; 12 | 13 | /// Enumeration of errors that occur in the ESIL parser 14 | #[derive(Debug, Clone)] 15 | pub enum ParserError { 16 | InvalidPop, 17 | InvalidDup, 18 | TooMany(Token), 19 | InvalidOpcode, 20 | InsufficientOperands, 21 | Unimplemented, 22 | UnknownOperandSize, 23 | } 24 | 25 | impl ToString for ParserError { 26 | fn to_string(&self) -> String { 27 | match self { 28 | ParserError::InvalidPop => "Invalid ESIL pop!".to_string(), 29 | ParserError::TooMany(Token::PCopy(_)) => "Request to `PCopy` too many elements!".to_string(), 30 | ParserError::TooMany(Token::PPop(_)) => "Request to `PPop` too many elements!".to_string(), 31 | ParserError::TooMany(t) => format!("Request to `{:?}` too many elements!", t), 32 | ParserError::InvalidOpcode => "Invalid ESIL opcode!".to_string(), 33 | ParserError::InsufficientOperands => "Insufficient operands!".to_string(), 34 | ParserError::Unimplemented => "Unimplemented".to_string(), 35 | ParserError::InvalidDup => "Invalid use of EDup!".to_string(), 36 | ParserError::UnknownOperandSize => "Unknown operand size".to_string(), 37 | } 38 | } 39 | } 40 | 41 | #[derive(Debug, Clone)] 42 | pub struct Parser { 43 | stack: Vec, 44 | tstack: Vec, 45 | tokens: Option>, 46 | // Number of instructions to ignore setting of ESIL variables, i.e., 47 | // esil_cur, esil_old_, esil_old, lastsz. 48 | skip_esil_set: usize, 49 | // Map of identifiers and their sizes. Used to automatically set lastsz correctly. 50 | ident_map: Option>, 51 | // Default size for the arch. Used if the identifier is not found in the ident_map. 52 | default_size: u64, 53 | // Last ESIL operation that was returned to the consumer. 54 | last_op: Option, 55 | // Last two pop operations performed by the consumer. 56 | last_pop: (Option, Option), 57 | // Allow access for the consumer to set these. If these are set, then the parser automatically 58 | // returns the value of old, cur and lastsz when required rather than returning the tokens to 59 | // indicate the same. 60 | pub eold: Option, 61 | pub eold_: Option, 62 | pub ecur: Option, 63 | pub lastsz: Option, 64 | } 65 | 66 | pub trait Parse { 67 | type InType: Clone + Debug + PartialEq; 68 | type OutType: Clone + Debug; 69 | type ParseError: ToString + Debug; 70 | 71 | fn parse(&mut self, S) -> Result, Self::ParseError> 72 | where S: AsRef, 73 | T: Tokenize; 74 | 75 | fn fetch_operands(&mut self, 76 | t: &Self::InType) 77 | -> Result<(Option, Option), 78 | Self::ParseError>; 79 | 80 | fn push(&mut self, t: Self::InType); 81 | } 82 | 83 | impl Parse for Parser { 84 | type InType = Token; 85 | type OutType = Token; 86 | type ParseError = ParserError; 87 | 88 | fn parse(&mut self, esil: S) -> Result, Self::ParseError> 89 | where S: AsRef, 90 | T: Tokenize 91 | { 92 | // TODO: Add notes about mechanism. 93 | if self.tokens.is_none() { 94 | self.skip_esil_set = 0; 95 | self.tokens = Some(T::tokenize(esil)); 96 | } 97 | 98 | // Set ESIL meta-variable 99 | if self.skip_esil_set == 0 { 100 | if let Some(ref token) = self.last_op { 101 | if token.should_set_vars() && token.updates_result() { 102 | self.ecur = self.stack.last().cloned(); 103 | } 104 | } 105 | } 106 | 107 | while let Some(token) = self.tokens.as_mut().unwrap().pop_front() { 108 | match token { 109 | // Esil Internal Vars 110 | Token::IZero(_) | 111 | Token::ICarry(_) | 112 | Token::IParity(_) | 113 | Token::IOverflow(_) | 114 | Token::ISign(_) | 115 | Token::IBorrow(_) | 116 | Token::ISize(_) | 117 | Token::IConstant(_) | 118 | Token::IAddress(_) => { 119 | let mut internal_q = self.evaluate_internal(&token)?; 120 | //self.skip_esil_set += internal_q.len() + 1; 121 | while let Some(i) = internal_q.pop_back() { 122 | // count the number of operations to skip for. 123 | self.tokens.as_mut().map(|v| v.push_front(i)); 124 | } 125 | } 126 | // Esil Operands 127 | Token::EConstant(_) | 128 | Token::EIdentifier(_) | 129 | Token::ECur | 130 | Token::EOld | 131 | Token::EOld_ | 132 | Token::ELastsz | 133 | Token::EAddress | 134 | Token::EEntry(_, _) => { 135 | self.push(token); 136 | } 137 | // Parser Instructions. 138 | Token::PCopy(ref n) => { 139 | // Copy 'n' elements from esil stack onto tstack. 140 | // _Maintains_ order. 141 | let len = self.stack.len(); 142 | if *n > len { 143 | return Err(ParserError::TooMany(Token::PCopy(*n))); 144 | } 145 | self.tstack.extend((&self.stack[len - n..]).iter().cloned()); 146 | } 147 | Token::PPop(ref n) => { 148 | // Pops 'n' elements from the tstack to the esil stack. 149 | // _Maintains_ order 150 | let len = self.tstack.len(); 151 | if *n > len { 152 | return Err(ParserError::TooMany(Token::PPop(*n))); 153 | } 154 | self.stack.extend((&self.tstack[len - n..]).iter().cloned()); 155 | self.tstack.truncate(len - n); 156 | } 157 | // Not in use _yet_. 158 | Token::PSync => return Err(ParserError::Unimplemented), 159 | Token::EPop => { 160 | if self.stack.pop().is_none() { 161 | return Err(ParserError::InvalidPop); 162 | } 163 | } 164 | Token::EDup => { 165 | let top = match self.stack.last().cloned() { 166 | Some(top) => top, 167 | None => return Err(ParserError::InvalidDup), 168 | }; 169 | self.push(top); 170 | } 171 | // Invalid. Let the Evaluator decide what to do with it. 172 | // Esil Opcodes. Return to the Evaluator. 173 | _ => { 174 | if self.skip_esil_set == 0 { 175 | self.last_op = Some(token.clone()); 176 | } else { 177 | self.skip_esil_set -= 1; 178 | } 179 | return Ok(Some(token)); 180 | } 181 | } 182 | } 183 | // This means that the parser is empty and there are no more tokens 184 | // to be processed. So we set tokens to None and return None. 185 | self.tokens = None; 186 | Ok(None) 187 | } 188 | 189 | fn push(&mut self, t: Self::InType) { 190 | self.stack.push(t); 191 | } 192 | 193 | fn fetch_operands(&mut self, t: &Token) -> Result<(Option, Option), Self::ParseError> { 194 | let result = if t.is_binary() { 195 | match (self.pop_op(), self.pop_op()) { 196 | (Ok(lhs), Ok(rhs)) => (lhs, rhs), 197 | (Err(e), _) | (_, Err(e)) => return Err(e), 198 | } 199 | } else if t.is_unary() { 200 | match self.pop_op() { 201 | Ok(op) => (op, None), 202 | Err(e) => return Err(e), 203 | } 204 | } else if t.is_arity_zero() || t.is_meta() { 205 | (None, None) 206 | } else if !t.is_implemented() { 207 | return Err(ParserError::Unimplemented); 208 | } else { 209 | return Err(ParserError::InvalidOpcode); 210 | }; 211 | 212 | if self.skip_esil_set == 0 { 213 | if t.should_set_vars() { 214 | // For ECmp, last_pop should be the operands we to the ECmp. 215 | if t.updates_result() { 216 | self.last_pop = result.clone(); 217 | } 218 | self.eold = self.last_pop.0.clone(); 219 | self.eold_ = self.last_pop.1.clone(); 220 | if !t.updates_result() { 221 | self.ecur = result.1.clone(); 222 | } 223 | self.lastsz = Some(Token::EConstant(match self.eold { 224 | None => self.default_size, 225 | Some(Token::EIdentifier(ref s)) => { 226 | if let Some(ref map) = self.ident_map { 227 | map.get(s).cloned().unwrap_or(self.default_size) 228 | } else { 229 | self.default_size 230 | } 231 | } 232 | Some(Token::EConstant(_)) => self.default_size, 233 | Some(Token::EEntry(_, n)) => n.unwrap_or(self.default_size), 234 | _ => unreachable!(), 235 | })); 236 | } else { 237 | self.last_pop = result.clone(); 238 | } 239 | } 240 | 241 | Ok(result) 242 | } 243 | } 244 | 245 | // Implementation of the parser where the input type is lexer::Token 246 | impl Parser { 247 | pub fn init(ident_map: Option>, default_size: Option) -> Parser { 248 | Parser { 249 | stack: Vec::new(), 250 | tstack: Vec::new(), 251 | ident_map: ident_map, 252 | skip_esil_set: 0, 253 | default_size: default_size.unwrap_or(64), 254 | last_op: None, 255 | last_pop: (None, None), 256 | tokens: None, 257 | eold: None, 258 | eold_: None, 259 | ecur: None, 260 | lastsz: None, 261 | } 262 | } 263 | 264 | fn get_meta(&self, t: Token) -> Token { 265 | match t { 266 | Token::EOld => self.eold.as_ref().unwrap_or(&t), 267 | Token::EOld_ => self.eold_.as_ref().unwrap_or(&t), 268 | Token::ECur => self.ecur.as_ref().unwrap_or(&t), 269 | Token::ELastsz => self.lastsz.as_ref().unwrap_or(&t), 270 | _ => panic!("Improper usage of function."), 271 | } 272 | .clone() 273 | } 274 | 275 | fn evaluate_internal(&mut self, t: &Token) -> Result, ParserError> { 276 | let mut result = VecDeque::new(); 277 | // Set the lower most `bit` bits to 1. 278 | let genmask = |bit: u64| { 279 | // ( 1 << bit ) - 1 280 | if bit == 64 { 281 | u64::max_value() 282 | } else { 283 | (1 << bit) - 1 284 | } 285 | }; 286 | 287 | // Initialize esil vars. 288 | let esil_old = self.get_meta(Token::EOld); 289 | let esil_old_ = self.get_meta(Token::EOld_); 290 | let esil_cur = self.get_meta(Token::ECur); 291 | let lastsz = match self.get_meta(Token::ELastsz) { 292 | Token::ELastsz => None, 293 | Token::EConstant(size) => Some(size), 294 | _ => panic!("lastsz cannot be something other than a constant!"), 295 | }; 296 | 297 | // NOTE: self.skip_esil_set must be set to the number of operations that you are 298 | // introducing as a part of the internal evaluation. This is also equal to the number of 299 | // tokens that will be returned from the parser to the consumer. 300 | match *t { 301 | Token::IZero(_) => { 302 | let lastsz = match lastsz { 303 | Some(lastsz_) => lastsz_, 304 | None => return Err(ParserError::UnknownOperandSize), 305 | }; 306 | 307 | result.extend([Token::EConstant(genmask(lastsz)), 308 | esil_cur, 309 | Token::EAnd, 310 | Token::EConstant(1), 311 | Token::EXor].iter().cloned()); 312 | self.skip_esil_set = 4; 313 | } 314 | Token::ICarry(_bit) => { 315 | let bit: u64 = u64::from(_bit)+1; 316 | result.extend([Token::EConstant(genmask(bit)), 317 | esil_old, 318 | Token::EAnd, 319 | Token::EConstant(genmask(bit)), 320 | esil_cur, 321 | Token::EAnd, 322 | Token::ELt].iter().cloned()); 323 | self.skip_esil_set = 5; 324 | } 325 | Token::IParity(_) => { 326 | // Parity flag computation as described in: 327 | // - https://graphics.stanford.edu/~seander/bithacks.html#ParityWith64Bits 328 | let c1: u64 = 0x0101010101010101; 329 | let c2: u64 = 0x8040201008040201; 330 | let c3: u64 = 0x1FF; 331 | result.extend([Token::EConstant(1), 332 | Token::EConstant(c3), 333 | Token::EConstant(c2), 334 | Token::EConstant(c1), 335 | Token::EConstant(0xFF), 336 | esil_cur, 337 | Token::EAnd, 338 | Token::EMul, 339 | Token::EAnd, 340 | Token::EMod, 341 | Token::EAnd] 342 | .iter() 343 | .cloned()); 344 | self.skip_esil_set = 7; 345 | } 346 | Token::IOverflow(_) => { 347 | // of = ((((~eold ^ eold_) & (enew ^ eold)) >> (lastsz - 1)) & 1) == 1 348 | let lastsz = match lastsz { 349 | Some(lastsz_) => lastsz_, 350 | None => return Err(ParserError::UnknownOperandSize), 351 | }; 352 | 353 | result.extend([Token::EConstant(1), 354 | Token::EConstant(1), 355 | Token::EConstant(lastsz - 1), 356 | Token::EConstant(genmask(lastsz)), 357 | esil_old.clone(), 358 | Token::EAnd, 359 | Token::EConstant(genmask(lastsz)), 360 | esil_cur, 361 | Token::EAnd, 362 | Token::EXor, 363 | Token::EConstant(genmask(lastsz)), 364 | esil_old_, 365 | Token::EAnd, 366 | Token::EConstant(genmask(lastsz)), 367 | esil_old.clone(), 368 | Token::EAnd, 369 | Token::ENeg, 370 | Token::EXor, 371 | Token::EAnd, 372 | Token::ELsr, 373 | Token::EAnd, 374 | Token::ECmp] 375 | .iter() 376 | .cloned()); 377 | self.skip_esil_set = 13; 378 | } 379 | Token::ISign(_) => { 380 | result.extend([Token::EConstant(1), 381 | self.get_meta(Token::ELastsz), 382 | Token::ESub, 383 | self.get_meta(Token::ECur), 384 | Token::ELsr] 385 | .iter() 386 | .cloned()); 387 | self.skip_esil_set = 4; 388 | } 389 | Token::IBorrow(_bit) => { 390 | let bit: u64 = _bit.into(); 391 | result.extend([Token::EConstant(genmask(bit)), 392 | esil_cur, 393 | Token::EAnd, 394 | Token::EConstant(genmask(bit)), 395 | esil_old, 396 | Token::EAnd, 397 | Token::ELt].iter().cloned()); 398 | self.skip_esil_set = 5; 399 | } 400 | Token::ISize(_) => { 401 | result.push_front(Token::EConstant(self.default_size)); 402 | self.skip_esil_set = 2; 403 | } 404 | Token::IAddress(_) => { 405 | result.push_front(Token::EAddress); 406 | self.skip_esil_set = 2; 407 | } 408 | Token::IConstant(n) => { 409 | result.push_front(Token::EConstant(n)); 410 | self.skip_esil_set = 2; 411 | } 412 | _ => unreachable!(), 413 | } 414 | Ok(result) 415 | } 416 | 417 | fn pop_op(&mut self) -> Result, ParserError> { 418 | if self.stack.len() > 0 { 419 | Ok(self.stack.pop()) 420 | } else { 421 | Err(ParserError::InsufficientOperands) 422 | } 423 | } 424 | } 425 | 426 | #[cfg(test)] 427 | mod test { 428 | use super::*; 429 | use lexer::*; 430 | 431 | use std::collections::HashMap; 432 | 433 | // Construct a prefix expression. 434 | struct ExpressionConstructor; 435 | impl ExpressionConstructor { 436 | fn get_inner_or_null(t: Option) -> String { 437 | if t.is_none() { 438 | return "-".to_owned(); 439 | } 440 | match t.unwrap() { 441 | Token::EIdentifier(s) => s, 442 | Token::EConstant(c) => format!("{:#X}", c), 443 | Token::EOld => "rax_old".to_owned(), 444 | Token::EOld_ => "rbx_old".to_owned(), 445 | Token::ECur => "rax_cur".to_owned(), 446 | _ => "".to_owned(), 447 | } 448 | } 449 | 450 | pub fn run>(esil: T, parser: Option<&mut Parser>) -> Result { 451 | let mut pp = Parser::init(None, None); 452 | let p = parser.unwrap_or(&mut pp); 453 | p.lastsz = Some(Token::EConstant(64)); 454 | let mut expression = String::new(); 455 | loop { 456 | match p.parse::<_, Tokenizer>(&esil) { 457 | Ok(Some(ref token)) => match p.fetch_operands(token) { 458 | Ok((lhs, rhs)) => { 459 | let lhs = ExpressionConstructor::get_inner_or_null(lhs); 460 | let rhs = ExpressionConstructor::get_inner_or_null(rhs); 461 | expression = format!("({:?} {}, {})", token, lhs, rhs); 462 | p.push(Token::EIdentifier(expression.clone())); 463 | }, 464 | Err(e) => return Err(e), 465 | }, 466 | Ok(None) => break, 467 | Err(e) => return Err(e), 468 | } 469 | } 470 | 471 | expression.clear(); 472 | for expr in &p.stack { 473 | if let &Token::EIdentifier(ref s) = expr { 474 | expression.push_str(s); 475 | } 476 | } 477 | Ok(expression) 478 | } 479 | } 480 | 481 | fn sample_regset() -> HashMap { 482 | let mut regset = HashMap::new(); 483 | regset.insert("rax".to_owned(), 64); 484 | regset.insert("rbx".to_owned(), 64); 485 | regset.insert("rcx".to_owned(), 64); 486 | regset.insert("eax".to_owned(), 32); 487 | regset.insert("ebx".to_owned(), 32); 488 | regset.insert("ecx".to_owned(), 32); 489 | regset.insert("zf".to_owned(), 1); 490 | regset.insert("pf".to_owned(), 1); 491 | regset.insert("cf".to_owned(), 1); 492 | regset.insert("of".to_owned(), 1); 493 | regset.insert("sf".to_owned(), 1); 494 | regset 495 | } 496 | 497 | macro_rules! construct { 498 | ($s: expr) => { 499 | ExpressionConstructor::run($s, None).unwrap() 500 | } 501 | } 502 | 503 | #[test] 504 | fn parser_basic_1() { 505 | let expression = construct!("6,rax,+="); 506 | assert_eq!("(EEq rax, (EAdd rax, 0x6))", expression); 507 | } 508 | 509 | #[test] 510 | fn parser_zf() { 511 | let expression = construct!("$z,zf,="); 512 | assert_eq!("(EEq zf, (EXor 0x1, (EAnd rax_cur, 0xFFFFFFFFFFFFFFFF)))", 513 | expression); 514 | } 515 | 516 | #[test] 517 | fn parser_pf() { 518 | let expression = construct!("$p,pf,="); 519 | assert_eq!("(EEq pf, (EAnd (EMod (EAnd (EMul (EAnd rax_cur, 0xFF), 0x101010101010101), 0x8040201008040201), 0x1FF), 0x1))", expression); 520 | } 521 | 522 | #[test] 523 | fn parser_cf() { 524 | let expression = construct!("$c63,cf,="); 525 | let expected = "(EEq cf, (ELt (EAnd rax_cur, 0xFFFFFFFFFFFFFFFF), (EAnd rax_old, 0xFFFFFFFFFFFFFFFF)))"; 526 | assert_eq!(expected, expression); 527 | } 528 | 529 | #[test] 530 | fn parser_cf2() { 531 | let expression = construct!("$c31,cf,="); 532 | let expected = "(EEq cf, (ELt (EAnd rax_cur, 0xFFFFFFFF), (EAnd rax_old, 0xFFFFFFFF)))"; 533 | assert_eq!(expected, expression); 534 | } 535 | 536 | #[test] 537 | fn parser_of() { 538 | // of = ((((~eold ^ eold_) & (enew ^ eold)) >> (lastsz - 1)) & 1) == 1 539 | let expression = construct!("$o,of,="); 540 | let expected = "(EEq of, (ECmp (EAnd (ELsr (EAnd (EXor (ENeg (EAnd rax_old, 0xFFFFFFFFFFFFFFFF), -), (EAnd rbx_old, 0xFFFFFFFFFFFFFFFF)), (EXor (EAnd rax_cur, 0xFFFFFFFFFFFFFFFF), (EAnd rax_old, 0xFFFFFFFFFFFFFFFF))), 0x3F), 0x1), 0x1))"; 541 | assert_eq!(expected, expression); 542 | } 543 | 544 | #[test] 545 | fn parser_bf() { 546 | let expression = construct!("$b64,cf,="); 547 | let expected = "(EEq cf, (ELt (EAnd rax_old, 0xFFFFFFFFFFFFFFFF), (EAnd rax_cur, 0xFFFFFFFFFFFFFFFF)))"; 548 | assert_eq!(expected, expression); 549 | } 550 | 551 | #[test] 552 | fn parser_bf2() { 553 | let expression = construct!("$b32,cf,="); 554 | let expected = "(EEq cf, (ELt (EAnd rax_old, 0xFFFFFFFF), (EAnd rax_cur, 0xFFFFFFFF)))"; 555 | assert_eq!(expected, expression); 556 | } 557 | 558 | #[test] 559 | fn parser_composite_1() { 560 | assert_eq!("(EEq rax, (ESub rax, 0x1))", construct!("rax,--=")); 561 | } 562 | 563 | #[test] 564 | fn parser_composite_2() { 565 | assert_eq!("(EPoke(64) 0x800, (EAnd (EPeek(64) 0x800, -), rax))", 566 | construct!("rax,0x800,&=[8]")); 567 | } 568 | 569 | #[test] 570 | fn parser_composite_3() { 571 | assert_eq!("(EPoke(64) 0x800, (ESub (EPeek(64) 0x800, -), 0x1))", 572 | construct!("0x800,--=[8]")); 573 | } 574 | 575 | #[test] 576 | fn parser_composite_4() { 577 | assert_eq!("(EEq rax, (EAdd rax, 0x1))", construct!("rax,++=")); 578 | } 579 | 580 | #[test] 581 | fn parser_test_esil_vars() { 582 | let regset = sample_regset(); 583 | let mut parser = Parser::init(Some(regset), Some(64)); 584 | let expr = ExpressionConstructor::run("rbx,rax,+=,$0,cf,=", Some(&mut parser)).unwrap(); 585 | assert_eq!(parser.eold, Some(Token::EIdentifier("rax".to_owned()))); 586 | assert_eq!(parser.eold_, Some(Token::EIdentifier("rbx".to_owned()))); 587 | assert_eq!(parser.ecur, 588 | Some(Token::EIdentifier("(EAdd rax, rbx)".to_owned()))); 589 | let expected = "(EEq rax, (EAdd rax, rbx))(EEq cf, 0x0)"; 590 | assert_eq!(expected, &expr); 591 | } 592 | 593 | #[test] 594 | fn parser_x86_add64() { 595 | let regset = sample_regset(); 596 | let mut parser = Parser::init(Some(regset), Some(64)); 597 | let expr = ExpressionConstructor::run("rbx,rax,+=,$o,of,=,$s,sf,=,$z,zf,=,$c63,cf,=,$p,pf,=", 598 | Some(&mut parser)).unwrap(); 599 | 600 | let expected = "(EEq rax, (EAdd rax, rbx))\ 601 | (EEq of, (ECmp (EAnd (ELsr (EAnd (EXor (ENeg (EAnd rax, 0xFFFFFFFFFFFFFFFF), -), (EAnd rbx, 0xFFFFFFFFFFFFFFFF)), (EXor (EAnd (EAdd rax, rbx), 0xFFFFFFFFFFFFFFFF), (EAnd rax, 0xFFFFFFFFFFFFFFFF))), 0x3F), 0x1), 0x1))\ 602 | (EEq sf, (ELsr (EAdd rax, rbx), (ESub 0x40, 0x1)))\ 603 | (EEq zf, (EXor 0x1, (EAnd (EAdd rax, rbx), 0xFFFFFFFFFFFFFFFF)))\ 604 | (EEq cf, (ELt (EAnd (EAdd rax, rbx), 0xFFFFFFFFFFFFFFFF), (EAnd rax, 0xFFFFFFFFFFFFFFFF)))\ 605 | (EEq pf, (EAnd (EMod (EAnd (EMul (EAnd (EAdd rax, rbx), 0xFF), 0x101010101010101), 0x8040201008040201), 0x1FF), 0x1))"; 606 | 607 | assert_eq!(expected, &expr); 608 | } 609 | 610 | #[test] 611 | fn parser_x86_add32() { 612 | let regset = sample_regset(); 613 | let mut parser = Parser::init(Some(regset), Some(64)); 614 | let expr = ExpressionConstructor::run("ebx,eax,+=,$o,of,=,$s,sf,=,$z,zf,=,$c31,cf,=,$p,pf,=", 615 | Some(&mut parser)).unwrap(); 616 | let expected = "(EEq eax, (EAdd eax, ebx))\ 617 | (EEq of, (ECmp (EAnd (ELsr (EAnd (EXor (ENeg (EAnd eax, 0xFFFFFFFF), -), (EAnd ebx, 0xFFFFFFFF)), (EXor (EAnd (EAdd eax, ebx), 0xFFFFFFFF), (EAnd eax, 0xFFFFFFFF))), 0x1F), 0x1), 0x1))\ 618 | (EEq sf, (ELsr (EAdd eax, ebx), (ESub 0x20, 0x1)))\ 619 | (EEq zf, (EXor 0x1, (EAnd (EAdd eax, ebx), 0xFFFFFFFF)))\ 620 | (EEq cf, (ELt (EAnd (EAdd eax, ebx), 0xFFFFFFFF), (EAnd eax, 0xFFFFFFFF)))\ 621 | (EEq pf, (EAnd (EMod (EAnd (EMul (EAnd (EAdd eax, ebx), 0xFF), 0x101010101010101), 0x8040201008040201), 0x1FF), 0x1))"; 622 | 623 | assert_eq!(expected, &expr); 624 | } 625 | 626 | #[test] 627 | fn parser_x86_cmp() { 628 | let regset = sample_regset(); 629 | let mut parser = Parser::init(Some(regset), Some(64)); 630 | let expr = 631 | ExpressionConstructor::run("0,rax,rax,&,==,$0,of,=,$s,sf,=,$z,zf,=,$0,cf,=,$p,pf,=", 632 | Some(&mut parser)).unwrap(); 633 | 634 | let expected = "(ECmp (EAnd rax, rax), 0x0)\ 635 | (EEq of, 0x0)\ 636 | (EEq sf, (ELsr (ECmp (EAnd rax, rax), 0x0), (ESub 0x40, 0x1)))\ 637 | (EEq zf, (EXor 0x1, (EAnd (ECmp (EAnd rax, rax), 0x0), 0xFFFFFFFFFFFFFFFF)))\ 638 | (EEq cf, 0x0)\ 639 | (EEq pf, (EAnd (EMod (EAnd (EMul (EAnd (ECmp (EAnd rax, rax), 0x0), 0xFF), 0x101010101010101), 0x8040201008040201), 0x1FF), 0x1))"; 640 | 641 | assert_eq!(expected, &expr); 642 | } 643 | 644 | #[test] 645 | fn parser_x86_sub64() { 646 | let regset = sample_regset(); 647 | let mut parser = Parser::init(Some(regset), Some(64)); 648 | let expr = ExpressionConstructor::run("rbx,rax,-=,$o,of,=,$s,sf,=,$z,zf,=,$b64,cf,=,$p,pf,=", 649 | Some(&mut parser)); 650 | 651 | let expected = "(EEq rax, (ESub rax, rbx))\ 652 | (EEq of, (ECmp (EAnd (ELsr (EAnd (EXor (ENeg (EAnd rax, 0xFFFFFFFFFFFFFFFF), -), (EAnd rbx, 0xFFFFFFFFFFFFFFFF)), (EXor (EAnd (ESub rax, rbx), 0xFFFFFFFFFFFFFFFF), (EAnd rax, 0xFFFFFFFFFFFFFFFF))), 0x3F), 0x1), 0x1))\ 653 | (EEq sf, (ELsr (ESub rax, rbx), (ESub 0x40, 0x1)))\ 654 | (EEq zf, (EXor 0x1, (EAnd (ESub rax, rbx), 0xFFFFFFFFFFFFFFFF)))\ 655 | (EEq cf, (ELt (EAnd rax, 0xFFFFFFFFFFFFFFFF), (EAnd (ESub rax, rbx), 0xFFFFFFFFFFFFFFFF)))\ 656 | (EEq pf, (EAnd (EMod (EAnd (EMul (EAnd (ESub rax, rbx), 0xFF), 0x101010101010101), 0x8040201008040201), 0x1FF), 0x1))"; 657 | 658 | assert_eq!(expected, &expr.unwrap()); 659 | } 660 | 661 | #[test] 662 | fn parser_lt_gt() { 663 | let regset = sample_regset(); 664 | let mut parser = Parser::init(Some(regset), Some(64)); 665 | let _expr = ExpressionConstructor::run("rax,rbx,<", Some(&mut parser)).unwrap(); 666 | 667 | assert_eq!(parser.eold, Some(Token::EIdentifier("rbx".to_owned()))); 668 | assert_eq!(parser.eold_, Some(Token::EIdentifier("rax".to_owned()))); 669 | assert_eq!(parser.ecur, 670 | Some(Token::EIdentifier("(ELt rbx, rax)".to_owned()))); 671 | assert_eq!(parser.lastsz, Some(Token::EConstant(64))); 672 | 673 | let _expr = ExpressionConstructor::run("rbx,rax,>", Some(&mut parser)).unwrap(); 674 | 675 | assert_eq!(parser.eold, Some(Token::EIdentifier("rax".to_owned()))); 676 | assert_eq!(parser.eold_, Some(Token::EIdentifier("rbx".to_owned()))); 677 | assert_eq!(parser.ecur, 678 | Some(Token::EIdentifier("(EGt rax, rbx)".to_owned()))); 679 | assert_eq!(parser.lastsz, Some(Token::EConstant(64))); 680 | } 681 | 682 | #[test] 683 | fn parser_x86_adc() { 684 | let regset = sample_regset(); 685 | let mut parser = Parser::init(Some(regset), Some(64)); 686 | let expr = 687 | ExpressionConstructor::run("cf,eax,+,eax,+=,$o,of,=,$s,sf,=,$z,zf,=,$c31,cf,=,$p,pf,=", 688 | Some(&mut parser)).unwrap(); 689 | 690 | let expected = "(EEq eax, (EAdd eax, (EAdd eax, cf)))\ 691 | (EEq of, (ECmp (EAnd (ELsr (EAnd (EXor (ENeg (EAnd eax, 0xFFFFFFFF), -), (EAnd (EAdd eax, cf), 0xFFFFFFFF)), (EXor (EAnd (EAdd eax, (EAdd eax, cf)), 0xFFFFFFFF), (EAnd eax, 0xFFFFFFFF))), 0x1F), 0x1), 0x1))\ 692 | (EEq sf, (ELsr (EAdd eax, (EAdd eax, cf)), (ESub 0x20, 0x1)))\ 693 | (EEq zf, (EXor 0x1, (EAnd (EAdd eax, (EAdd eax, cf)), 0xFFFFFFFF)))\ 694 | (EEq cf, (ELt (EAnd (EAdd eax, (EAdd eax, cf)), 0xFFFFFFFF), (EAnd eax, 0xFFFFFFFF)))\ 695 | (EEq pf, (EAnd (EMod (EAnd (EMul (EAnd (EAdd eax, (EAdd eax, cf)), 0xFF), 0x101010101010101), 0x8040201008040201), 0x1FF), 0x1))"; 696 | 697 | assert_eq!(expected, &expr); 698 | } 699 | 700 | #[test] 701 | fn parser_multiple_insts() { 702 | let regset = sample_regset(); 703 | let mut parser = Parser::init(Some(regset), Some(64)); 704 | let expr = ExpressionConstructor::run("cf,eax,+,eax,+=,$o,of,=,$s,sf,=,$z,zf,=,$c31,cf,=,$p,pf,=", 705 | Some(&mut parser)).unwrap(); 706 | 707 | let expected = "(EEq eax, (EAdd eax, (EAdd eax, cf)))\ 708 | (EEq of, (ECmp (EAnd (ELsr (EAnd (EXor (ENeg (EAnd eax, 0xFFFFFFFF), -), (EAnd (EAdd eax, cf), 0xFFFFFFFF)), (EXor (EAnd (EAdd eax, (EAdd eax, cf)), 0xFFFFFFFF), (EAnd eax, 0xFFFFFFFF))), 0x1F), 0x1), 0x1))\ 709 | (EEq sf, (ELsr (EAdd eax, (EAdd eax, cf)), (ESub 0x20, 0x1)))\ 710 | (EEq zf, (EXor 0x1, (EAnd (EAdd eax, (EAdd eax, cf)), 0xFFFFFFFF)))\ 711 | (EEq cf, (ELt (EAnd (EAdd eax, (EAdd eax, cf)), 0xFFFFFFFF), (EAnd eax, 0xFFFFFFFF)))\ 712 | (EEq pf, (EAnd (EMod (EAnd (EMul (EAnd (EAdd eax, (EAdd eax, cf)), 0xFF), 0x101010101010101), 0x8040201008040201), 0x1FF), 0x1))"; 713 | 714 | assert_eq!(expected, &expr); 715 | assert_eq!(parser.skip_esil_set, 1); 716 | 717 | let _ = ExpressionConstructor::run("rax,rbx,-=,$0,cf,=", Some(&mut parser)).unwrap(); 718 | assert_eq!(parser.eold, Some(Token::EIdentifier("rbx".to_owned()))); 719 | assert_eq!(parser.eold_, Some(Token::EIdentifier("rax".to_owned()))); 720 | assert_eq!(parser.ecur, Some(Token::EIdentifier("(ESub rbx, rax)".to_owned()))); 721 | assert_eq!(parser.skip_esil_set, 1); 722 | } 723 | 724 | #[test] 725 | fn parser_follow_false() { 726 | // TODO 727 | } 728 | 729 | #[test] 730 | fn parser_follow_true() { 731 | // TODO 732 | } 733 | } 734 | --------------------------------------------------------------------------------