// Panopticon - A libre program analysis library for machine code // Copyright (C) 2014-2018 The Panopticon Developers // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA use std::env; use std::fs::File; use std::io::Write; use std::path::Path; #[derive(Clone,Copy,Debug)] enum Argument { Literal, LiteralWidth, NoOffset, Constant, Undefined, } impl Argument { pub fn match_expr(&self, pos: &'static str) -> String { match self { &Argument::Literal => format!("( ${}:expr )", pos), &Argument::LiteralWidth => format!("( ${}:expr ) : ${}_w:tt", pos, pos), &Argument::NoOffset => format!("${}:tt : ${}_w:tt", pos, pos), &Argument::Constant => format!("[ ${}:tt ] : ${}_w:tt", pos, pos), &Argument::Undefined => "?".to_string(), } } pub fn arg_expr(&self, pos: &'static str) -> String { match self { &Argument::Literal => format!("( ${} )", pos), &Argument::LiteralWidth => format!("( ${} ) : ${}_w", pos, pos), &Argument::NoOffset => format!("${} : ${}_w", pos, pos), &Argument::Constant => format!("[ ${} ] : ${}_w", pos, pos), &Argument::Undefined => "?".to_string(), } } } const BOILERPLATE2: &'static str = " let ret: $crate::Result> = match stmt[0].sanity_check() { Ok(()) => { {let _ = &$segs;} {let _ = &$names;} let mut tail: $crate::Result> = { rreil2!( ($names,$segs) { $($cdr)* } ) }; match tail { Ok(ref mut other) => { stmt.extend(other.drain(..)); Ok(stmt) } Err(e) => Err(e), } } Err(e) => Err(e).into(), }; ret "; const VARIABLES: &'static [Argument] = &[ Argument::Literal, Argument::LiteralWidth, Argument::NoOffset, ]; const VALUES: &'static [Argument] = &[ Argument::Literal, Argument::LiteralWidth, Argument::NoOffset, Argument::Constant, Argument::Undefined, ]; fn write_binary_operations(f: &mut File) { f.write_all( b" #[macro_export] macro_rules! rreil2_binop { " ) .unwrap(); for a in VARIABLES.iter() { for b in VALUES.iter() { for c in VALUES.iter() { f.write_fmt( format_args!( " // {:?} := {:?}, {:?} ( $names:tt # $segs:tt # $op:ident # {}, {} , {} ; $($cdr:tt)*) => {{{{ let mut stmt = vec![$crate::Statement::Expression{{ op: $crate::Operation::$op(rreil_val!($names # {}),rreil_val!($names # {})), result: rreil_var!($names # {}) }}]; {} }}}}; ", a, b, c, a.match_expr("a"), b.match_expr("b"), c.match_expr("c"), b.arg_expr("b"), c.arg_expr("c"), a.arg_expr("a"), BOILERPLATE2 ) ) .unwrap(); } } } f.write_all( b"} " ) .unwrap(); } fn write_unary_operations(f: &mut File) { f.write_all( b" #[macro_export] macro_rules! rreil2_unop { " ) .unwrap(); for a in VARIABLES.iter() { for b in VALUES.iter() { f.write_fmt( format_args!( " // {:?} := {:?} ( $names:tt # $segs:tt # $op:ident # {}, {} ; $($cdr:tt)*) => {{{{ let mut stmt = vec![$crate::Statement::Expression{{ op: $crate::Operation::$op(rreil_val!($names # {})), result: rreil_var!($names # {}) }}]; {} }}}}; ", a, b, a.match_expr("a"), b.match_expr("b"), b.arg_expr("b"), a.arg_expr("a"), BOILERPLATE2 ) ) .unwrap(); } } f.write_all( b"} " ) .unwrap(); } fn write_store_operation(f: &mut File) { f.write_all( b" #[macro_export] macro_rules! rreil_store { " ) .unwrap(); for addr in VALUES.iter() { for val in VALUES.iter() { // Little Endian Store f.write_fmt(format_args!(" // {:?} := {:?} ( $names:tt # $segs:tt # $bank:ident # le # $sz:tt # {} , {} ; $($cdr:tt)*) => {{{{ let mut stmt = vec![$crate::Statement::Memory{{ op: $crate::MemoryOperation::Store{{ segment: $crate::Segment{{ name: $segs.insert(&$crate::Name::new(stringify!($bank).into(),None)), }}, endianess: $crate::Endianess::Little, bytes: rreil_imm!($sz), address: rreil_val!($names # {}), value: rreil_val!($names # {}), }}, result: $crate::Segment{{ name: $segs.insert(&$crate::Name::new(stringify!($bank).into(),None)), }}, }}]; {} }}}}; ",addr,val, addr.match_expr("addr"),val.match_expr("val"), addr.arg_expr("addr"),val.arg_expr("val"), BOILERPLATE2)).unwrap(); // Big Endian Store f.write_fmt(format_args!(" // *({:?}) := {:?} ( $names:tt # $segs:tt # $bank:ident # be # $sz:tt # {} , {} ; $($cdr:tt)*) => {{{{ let mut stmt = vec![$crate::Statement::Memory{{ op: $crate::MemoryOperation::Store{{ segment: $crate::Segment{{ name: $segs.insert(&$crate::Name::new(stringify!($bank).into(),None)), }}, endianess: $crate::Endianess::Big, bytes: rreil_imm!($sz), address: rreil_val!($names # {}), value: rreil_val!($names # {}), }}, result: $crate::Segment{{ name: $segs.insert(&$crate::Name::new(stringify!($bank).into(),None)), }}, }}]; {} }}}}; ",addr,val, addr.match_expr("addr"),val.match_expr("val"), addr.arg_expr("addr"),val.arg_expr("val"), BOILERPLATE2)).unwrap(); } } f.write_all(b"}").unwrap(); } fn write_load_operation(f: &mut File) { f.write_all( b" #[macro_export] macro_rules! rreil_load { " ) .unwrap(); for res in VARIABLES.iter() { for addr in VALUES.iter() { // Little Endian Load f.write_fmt(format_args!(" // {:?} := *({:?}) ( $names:tt # $segs:tt # $bank:ident # le # $sz:tt # {} , {} ; $($cdr:tt)*) => {{{{ let mut stmt = vec![$crate::Statement::Expression{{ op: $crate::Operation::Load( $crate::Segment{{ name: $segs.insert(&$crate::Name::new(stringify!($bank).into(),None)), }}, $crate::Endianess::Little, rreil_imm!($sz), rreil_val!($names # {}) ), result: rreil_var!($names # {}), }}]; {} }}}}; ",res,addr, res.match_expr("res"),addr.match_expr("addr"), addr.arg_expr("addr"),res.arg_expr("res"), BOILERPLATE2)).unwrap(); // Big Endian Store f.write_fmt(format_args!(" // {:?} := *({:?}) ( $names:tt # $segs:tt # $bank:ident # be # $sz:tt # {} , {} ; $($cdr:tt)*) => {{{{ let mut stmt = vec![$crate::Statement::Expression{{ op: $crate::Operation::Load( $crate::Segment{{ name: $segs.insert(&$crate::Name::new(stringify!($bank).into(),None)), }}, $crate::Endianess::Big, rreil_imm!($sz), rreil_val!($names # {}) ), result: rreil_var!($names # {}), }}]; {} }}}}; ",res,addr, res.match_expr("res"),addr.match_expr("addr"), addr.arg_expr("addr"),res.arg_expr("res"), BOILERPLATE2)).unwrap(); } } f.write_all(b"}").unwrap(); } fn write_extraction_operations(f: &mut File) { f.write_all( b" #[macro_export] macro_rules! rreil2_extop { " ) .unwrap(); for a in VARIABLES.iter() { for b in VALUES.iter() { f.write_fmt( format_args!( " // {:?} := {:?} ( $names:tt # $segs:tt # $op:ident # $sz:tt # {}, {} ; $($cdr:tt)*) => {{{{ let mut stmt = vec![$crate::Statement::Expression{{ op: $crate::Operation::$op(rreil_imm!($sz),rreil_val!($names # {})), result: rreil_var!($names # {}) }}]; {} }}}}; ", a, b, a.match_expr("a"), b.match_expr("b"), b.arg_expr("b"), a.arg_expr("a"), BOILERPLATE2 ) ) .unwrap(); } } f.write_all( b"} " ) .unwrap(); } fn write_selection_operations(f: &mut File) { f.write_all( b" #[macro_export] macro_rules! rreil2_selop { " ) .unwrap(); for a in VARIABLES.iter() { for b in VALUES.iter() { f.write_fmt( format_args!( " // {:?} := {:?} ( $names:tt # $segs:tt # $op:ident # $off:tt # $sz:tt # {}, {} ; $($cdr:tt)*) => {{{{ let mut stmt = vec![$crate::Statement::Expression{{ op: $crate::Operation::$op(rreil_imm!($off),rreil_imm!($sz),rreil_val!($names # {})), result: rreil_var!($names # {}) }}]; {} }}}}; ", a, b, a.match_expr("a"), b.match_expr("b"), b.arg_expr("b"), a.arg_expr("a"), BOILERPLATE2 ) ) .unwrap(); } } f.write_all( b"} " ) .unwrap(); } fn write_call_operations(f: &mut File) { f.write_all( b" #[macro_export] macro_rules! rreil2_callop { " ) .unwrap(); for a in VALUES.iter() { f.write_fmt( format_args!( " // call {:?} ( $names:tt # $segs:tt # {} ; $($cdr:tt)* ) => {{{{ let mut stmt = vec![$crate::Statement::Flow{{ op: $crate::FlowOperation::IndirectCall{{ target: rreil_var!($names # {}) }} }}]; {} }}}}; ", a, a.match_expr("a"), a.arg_expr("a"), BOILERPLATE2 ) ) .unwrap(); } f.write_all( b"} " ) .unwrap(); } fn write_ret_operations(f: &mut File) { f.write_fmt( format_args!( " #[macro_export] macro_rules! rreil2_retop {{ // ret ( $names:tt # $segs:tt # ; $($cdr:tt)* ) => {{{{ let mut stmt = vec![$crate::Statement::Flow{{ op: $crate::FlowOperation::Return, }}]; {} }}}}; }} " ,BOILERPLATE2)).unwrap(); } fn main() { let out_dir = env::var("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("rreil.rs"); let mut f = File::create(&dest_path).unwrap(); write_binary_operations(&mut f); write_unary_operations(&mut f); write_store_operation(&mut f); write_load_operation(&mut f); write_ret_operations(&mut f); write_call_operations(&mut f); write_extraction_operations(&mut f); write_selection_operations(&mut f); }