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<Vec<$crate::Statement>> = match stmt[0].sanity_check() {
Ok(()) => {
{let _ = &$segs;}
{let _ = &$names;}
let mut tail: $crate::Result<Vec<$crate::Statement>> = { 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() {
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();
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() {
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();
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);
}