Commit c95a7186 authored by Henrich Lauko's avatar Henrich Lauko

lart: Introduce map to track pairs of dual abstract/concrete operations.

parent 5d874e0c
......@@ -2,6 +2,9 @@
#include <lart/abstract/operation.h>
#include <lart/abstract/stash.h>
#include <lart/abstract/meta.h>
namespace lart::abstract
{
const Bimap< Operation::Type, std::string > Operation::TypeTable = {
......@@ -9,8 +12,6 @@ namespace lart::abstract
,{ Operation::Type::GEP , "gep" }
,{ Operation::Type::Thaw , "thaw" }
,{ Operation::Type::Freeze , "freeze" }
,{ Operation::Type::Stash , "stash" }
,{ Operation::Type::Unstash, "unstash" }
,{ Operation::Type::ToBool , "tobool" }
,{ Operation::Type::Assume , "assume" }
,{ Operation::Type::Store , "store" }
......@@ -18,13 +19,13 @@ namespace lart::abstract
,{ Operation::Type::Cmp , "cmp" }
,{ Operation::Type::Cast , "cast" }
,{ Operation::Type::Binary , "binary" }
,{ Operation::Type::BinaryFaultable, "binary.faultabel" }
,{ Operation::Type::Lift , "lift" }
,{ Operation::Type::Lower , "lower" }
,{ Operation::Type::Call , "call" }
,{ Operation::Type::Memcpy , "memcpy" }
,{ Operation::Type::Memmove, "memmove" }
,{ Operation::Type::Memset , "memset" }
,{ Operation::Type::Union , "union" }
};
Operation OperationBuilder::construct( llvm::Instruction * inst )
......@@ -52,6 +53,7 @@ namespace lart::abstract
else
return construct< Type::Store >( store );
}*/
UNREACHABLE( "not implemented" );
}
if ( auto load = llvm::dyn_cast< llvm::LoadInst >( inst ) ) {
......@@ -71,6 +73,7 @@ namespace lart::abstract
else
return construct< Type::Load >( load );
}*/
UNREACHABLE( "not implemented" );
}
if ( auto cmp = llvm::dyn_cast< llvm::CmpInst >( inst ) ) {
......@@ -82,11 +85,13 @@ namespace lart::abstract
}
if ( auto bin = llvm::dyn_cast< llvm::BinaryOperator >( inst ) ) {
return construct< Type::Binary >( bin );
if ( is_faultable( inst ) )
return construct< Type::BinaryFaultable >( bin );
else
return construct< Type::Binary >( bin );
}
if ( auto call = llvm::dyn_cast< llvm::CallInst >( inst ) ) {
// ASSERT( is_transformable( call ) );
if ( llvm::isa< llvm::MemSetInst >( call ) )
return construct< Type::Memset >( call );
if ( llvm::isa< llvm::MemCpyInst >( call ) )
......@@ -96,11 +101,62 @@ namespace lart::abstract
return construct< Type::Call >( call );
}
if ( auto ret = llvm::dyn_cast< llvm::ReturnInst >( inst ) ) {
return construct< Type::Stash >( ret );
UNREACHABLE( "Unsupported operation type" );
}
void Matched::init( llvm::Module & m )
{
for ( auto call : abstract_calls( m ) ) {
auto dual = call->getNextNonDebugInstruction();
concrete[ dual ] = call;
abstract[ call ] = dual;
}
UNREACHABLE( "Unsupported operation type" );
for ( auto op : operations( m ) ) {
match( op.type, op.inst, op.inst->getPrevNode() );
}
for ( auto intr : unpacked_arguments( &m ) ) {
auto call = llvm::cast< llvm::CallInst >( intr );
auto c = call->getArgOperand( 0 );
auto a = call->getArgOperand( 1 );
abstract[ c ] = a;
concrete[ a ] = c;
}
auto tag = meta::tag::operation::thaw;
for ( auto load : meta::enumerate< llvm::LoadInst >( m, tag ) ) {
auto c = load;
auto a = load->getNextNode()->getNextNode();
ASSERT( llvm::isa< llvm::CallInst >( a ) ); // is thaw
abstract[ c ] = a;
concrete[ a ] = c;
}
}
void Matched::match( Operation::Type type, llvm::Value * a, llvm::Value * c )
{
if ( type == Operation::Type::Assume )
return;
if ( type == Operation::Type::ToBool ) {
concrete[ a ] = concrete[ c ];
} else {
auto ai = llvm::cast< llvm::Instruction >( a );
auto ci = llvm::cast< llvm::Instruction >( c );
if ( is_faultable( ci ) ) {
concrete[ a ] = c;
auto unstash = ai->getNextNode();
abstract[ c ] = unstash;
concrete[ unstash ] = c;
} else {
concrete[ a ] = c;
abstract[ c ] = a;
}
}
}
} // namespace lart::abstract
......@@ -23,8 +23,6 @@ namespace lart::abstract {
GEP,
Thaw,
Freeze,
Stash,
Unstash,
ToBool,
Assume,
Store,
......@@ -32,38 +30,40 @@ namespace lart::abstract {
Cmp,
Cast,
Binary,
BinaryFaultable,
Lift,
Lower,
Call,
Memcpy,
Memmove,
Memset,
Union
Memset
};
static const Bimap< Type, std::string > TypeTable;
explicit Operation( llvm::Instruction * inst, Type type )
: inst( inst ), type( type )
explicit Operation( llvm::Instruction * inst, Type type, bool taint )
: inst( inst ), type( type ), taint( taint )
{
meta::set( inst, meta::tag::operation::type, TypeTable[ type ] );
}
explicit Operation( llvm::Instruction * inst )
: Operation( inst, TypeTable[ meta::get( inst, meta::tag::operation::type ).value() ] )
explicit Operation( llvm::Instruction * inst, bool taint = false )
: Operation( inst, TypeTable[ meta::get( inst, meta::tag::operation::type ).value() ], taint )
{ }
bool is_taint() const { return taint; }
static bool is( llvm::Instruction * inst )
{
return meta::has( inst, meta::tag::operation::type );
}
static std::vector< Operation > enumerate( llvm::Module & m )
static std::vector< Operation > enumerate( llvm::Module & m, bool taints = false )
{
return query::query( m ).flatten().flatten()
.map( query::refToPtr )
.filter( Operation::is )
.map( [] ( auto * inst ) { return Operation( inst ); } )
.map( [taints] ( auto * inst ) { return Operation( inst, taints ); } )
.freeze();
}
......@@ -89,8 +89,49 @@ namespace lart::abstract {
return os;
}
template< Operation::Type... Ts >
static constexpr bool is_one_of( Operation::Type type )
{
return ( (Ts == type) || ... );
}
static constexpr bool binary( Operation::Type type )
{
return is_one_of< Type::Cmp, Type::Binary, Type::BinaryFaultable >( type );
}
static constexpr bool arith( Operation::Type type ) {
return Type::Binary == type || Type::BinaryFaultable == type;
}
static constexpr bool gep( Operation::Type type ) { return Type::GEP == type; }
static constexpr bool store( Operation::Type type ) { return Type::Store == type; }
static constexpr bool load( Operation::Type type ) { return Type::Load == type; }
static constexpr bool cmp( Operation::Type type ) { return Type::Cmp == type; }
static constexpr bool cast( Operation::Type type ) { return Type::Cast == type; }
static constexpr bool assume( Operation::Type type ) { return Type::Assume == type; }
static constexpr bool toBool( Operation::Type type ) { return Type::ToBool == type; }
static constexpr bool freeze( Operation::Type type ) { return Type::Freeze == type; }
static constexpr bool thaw( Operation::Type type ) { return Type::Thaw == type; }
static constexpr bool call( Operation::Type type ) { return Type::Call == type; }
static constexpr bool lift( Operation::Type type ) { return Type::Lift == type; }
static constexpr bool lower( Operation::Type type ) { return Type::Lower == type; }
static constexpr bool mem( Operation::Type type )
{
return is_one_of< Type::Memcpy, Type::Memmove, Type::Memset >( type );
}
static constexpr bool faultable( Operation::Type type )
{
// TODO memory operations
return is_one_of< Type::Store, Type::Load, Type::BinaryFaultable, Type::Call >( type );
}
llvm::Instruction * inst;
Type type;
bool taint;
};
template< Operation::Type T >
......@@ -134,26 +175,9 @@ namespace lart::abstract {
}
};
static inline constexpr bool to_concrete( Operation::Type T )
{
return T == Operation::Type::ToBool || T == Operation::Type::Lower;
}
template< Operation::Type... Ts >
constexpr bool is_any_of( Operation::Type type )
{
return ( (Ts == type) || ... );
}
static inline constexpr bool is_mem_intrinsic( Operation::Type T )
{
using Type = Operation::Type;
return is_any_of< Type::Memset, Type::Memcpy, Type::Memmove >( T );
}
static inline auto operations( llvm::Module & m )
{
return Operation::enumerate( m );
return Operation::enumerate( m, false /* taint */ );
}
template< typename Filter >
......@@ -168,6 +192,17 @@ namespace lart::abstract {
return operations( m, [] ( const auto & ph ) { return ph.type == T; } );
}
struct Matched
{
void init( llvm::Module & m );
void match( Operation::Type type, llvm::Value * a, llvm::Value * c );
std::map< llvm::Value *, llvm::Value * > concrete;
std::map< llvm::Value *, llvm::Value * > abstract;
};
} // namespace lart::abstract
#include <lart/abstract/operation.tpp>
......@@ -4,20 +4,21 @@
namespace lart::abstract
{
template< Operation::Type T >
template< Operation::Type type >
template< typename Value, typename Builder >
Operation Construct< T >::operation( Value * val, Builder & builder )
Operation Construct< type >::operation( Value * val, Builder & builder )
{
auto m = util::get_module( val );
auto fn = util::get_or_insert_function( m, function_type( val ), name( val ) );
return Operation{ builder.CreateCall( fn, arguments( val ) ), T };
auto call = builder.CreateCall( fn, arguments( val ) );
return Operation( call, type, false /* placeholder */ );
}
template< Operation::Type T >
Operation Construct< T >::operation( llvm::Instruction * inst )
{
assert( !llvm::isa< llvm::ReturnInst >( inst ) );
llvm::IRBuilder<> irb{ inst->getContext() };
if constexpr ( T == Type::PHI ) {
irb.SetInsertPoint( inst->getParent()->getFirstNonPHI() );
} else {
......@@ -30,27 +31,18 @@ namespace lart::abstract
ph.inst->moveAfter( inst );
}
if constexpr ( T != Type::ToBool && T != Type::Union ) {
meta::make_duals( inst, ph.inst );
}
return ph;
}
template< Operation::Type T >
Operation Construct< T >::operation( llvm::Argument * arg )
{
static_assert( Type::Stash == T || Type::Unstash == T );
auto & entry = arg->getParent()->getEntryBlock();
llvm::IRBuilder<> irb{ &entry, entry.getFirstInsertionPt() };
return operation( arg, irb );
}
template< Operation::Type T >
llvm::Type * Construct< T >::output( llvm::Value * val )
{
auto m = util::get_module( val );
if ( auto inst = llvm::dyn_cast< llvm::Instruction >( val ); inst )
if ( !Operation::is( inst ) && is_faultable( inst ) )
return val->getType();
if constexpr ( T == Type::ToBool ) {
return llvm::Type::getInt1Ty( m->getContext() );
} else {
......@@ -73,13 +65,13 @@ namespace lart::abstract
return { l->getPointerOperand() };
}
if constexpr ( is_mem_intrinsic( T ) ) {
/*if constexpr ( is_mem_intrinsic( T ) ) {
auto mem = llvm::cast< llvm::MemIntrinsic >( val );
auto dst = mem->getArgOperand( 0 );
auto val = mem->getArgOperand( 1 );
auto len = mem->getArgOperand( 2 );
return { dst, val, len };
}
}*/
return { val };
}
......@@ -95,13 +87,16 @@ namespace lart::abstract
{
std::string suffix = Operation::TypeTable[ T ];
suffix += "." + llvm_name( output( val ) );
if constexpr ( T == Type::Store || T == Type::Freeze ) {
auto s = llvm::cast< llvm::StoreInst >( val );
return suffix + "." + llvm_name( s->getValueOperand()->getType() );
} else if constexpr ( is_mem_intrinsic( T ) ) {
auto intr = llvm::cast< llvm::MemIntrinsic >( val );
auto dst = intr->getRawDest()->getType();
return suffix + "." + llvm_name( dst->getPointerElementType() );
// } else if constexpr ( is_mem_intrinsic( T ) ) {
// auto intr = llvm::cast< llvm::MemIntrinsic >( val );
// auto dst = intr->getRawDest()->getType();
// return suffix + "." + llvm_name( dst->getPointerElementType() );
//
} else {
if ( auto aggr = llvm::dyn_cast< llvm::StructType >( val->getType() ) ) {
return suffix + "." + aggr->getName().str();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment