diff --git a/VTIL-Architecture/VTIL-Architecture.vcxproj b/VTIL-Architecture/VTIL-Architecture.vcxproj
index c7d1271..2174a1a 100644
--- a/VTIL-Architecture/VTIL-Architecture.vcxproj
+++ b/VTIL-Architecture/VTIL-Architecture.vcxproj
@@ -15,7 +15,6 @@
-
@@ -24,6 +23,9 @@
+
+
+
@@ -36,6 +38,9 @@
+
+
+
diff --git a/VTIL-Architecture/VTIL-Architecture.vcxproj.filters b/VTIL-Architecture/VTIL-Architecture.vcxproj.filters
index 68c7cdd..3359c50 100644
--- a/VTIL-Architecture/VTIL-Architecture.vcxproj.filters
+++ b/VTIL-Architecture/VTIL-Architecture.vcxproj.filters
@@ -19,6 +19,9 @@
{b070980d-a30d-421e-82c6-0298cfe01c0e}
+
+ {6ba6b482-58aa-46cd-ad58-c0eef36c9333}
+
@@ -63,12 +66,18 @@
Virtual Machine
-
- Includes
-
Virtual Machine
+
+ Value Tracing
+
+
+ Value Tracing
+
+
+ Value Tracing
+
@@ -98,6 +107,15 @@
Virtual Machine
+
+ Value Tracing
+
+
+ Value Tracing
+
+
+ Value Tracing
+
diff --git a/VTIL-Architecture/includes/vtil/arch b/VTIL-Architecture/includes/vtil/arch
index 2f147bc..1a932f5 100644
--- a/VTIL-Architecture/includes/vtil/arch
+++ b/VTIL-Architecture/includes/vtil/arch
@@ -7,4 +7,10 @@
#include "../../routine/routine.hpp"
#include "../../routine/basic_block.hpp"
#include "../../routine/instruction.hpp"
-#include "../../routine/serialization.hpp"
\ No newline at end of file
+#include "../../routine/serialization.hpp"
+#include "../../vm/interface.hpp"
+#include "../../vm/symbolic.hpp"
+#include "../../vm/lambda.hpp"
+#include "../../trace/auxiliaries.hpp"
+#include "../../trace/tracer.hpp"
+#include "../../trace/cached_tracer.hpp"
\ No newline at end of file
diff --git a/VTIL-Architecture/includes/vtil/trace b/VTIL-Architecture/includes/vtil/trace
new file mode 100644
index 0000000..87d19d3
--- /dev/null
+++ b/VTIL-Architecture/includes/vtil/trace
@@ -0,0 +1,3 @@
+#include "../../trace/auxiliaries.hpp"
+#include "../../trace/tracer.hpp"
+#include "../../trace/cached_tracer.hpp"
\ No newline at end of file
diff --git a/VTIL-Architecture/includes/vtil/vm b/VTIL-Architecture/includes/vtil/vm
deleted file mode 100644
index e06595c..0000000
--- a/VTIL-Architecture/includes/vtil/vm
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "../../vm/interface.hpp"
-#include "../../vm/symbolic.hpp"
-#include "../../vm/lambda.hpp"
\ No newline at end of file
diff --git a/VTIL-Architecture/trace/auxiliaries.cpp b/VTIL-Architecture/trace/auxiliaries.cpp
new file mode 100644
index 0000000..78fe485
--- /dev/null
+++ b/VTIL-Architecture/trace/auxiliaries.cpp
@@ -0,0 +1,155 @@
+#include "auxiliaries.hpp"
+
+namespace vtil
+{
+ // Checks if the instruction given accesses the variable, optionally filtering to the
+ // access type specified, tracer passed will be used to generate pointers when needed.
+ //
+ access_details test_access( const il_const_iterator& it, const symbolic::variable::descriptor_t& var, tracer* tracer, access_type type )
+ {
+ // If variable is of register type:
+ //
+ if ( auto reg = std::get_if( &var ) )
+ {
+ // Iterate each operand:
+ //
+ for ( int i = 0; i < it->base->operand_count(); i++ )
+ {
+ // Skip if not register.
+ //
+ if ( !it->operands[ i ].is_register() )
+ continue;
+
+ // Skip if access type does not match.
+ //
+ switch ( type )
+ {
+ // ::read will filter to read or read/write.
+ //
+ case access_type::read:
+ if ( it->base->operand_types[ i ] == operand_type::write )
+ continue;
+ break;
+ // ::write will filter to write or read/write.
+ //
+ case access_type::write:
+ if ( it->base->operand_types[ i ] < operand_type::write )
+ continue;
+ break;
+ // ::readwrite will filter to only read/write.
+ //
+ case access_type::readwrite:
+ if ( it->base->operand_types[ i ] != operand_type::readwrite )
+ continue;
+ break;
+ // ::none accepts any access.
+ //
+ case access_type::none:
+ break;
+ }
+
+ // Skip if no overlap.
+ //
+ auto& ref_reg = it->operands[ i ].reg();
+ if ( !ref_reg.overlaps( *reg ) )
+ continue;
+
+ // Return access details.
+ //
+ access_type type_found;
+ if ( it->base->operand_types[ i ] == operand_type::readwrite )
+ type_found = access_type::readwrite;
+ else if ( it->base->operand_types[ i ] == operand_type::write )
+ type_found = access_type::write;
+ else
+ type_found = access_type::read;
+
+ return {
+ type_found,
+ ref_reg.bit_offset - reg->bit_offset,
+ ref_reg.bit_count
+ };
+ }
+ }
+ // If variable is of memory type:
+ //
+ else if( auto mem = std::get_if( &var ) )
+ {
+ // If instruction accesses memory:
+ //
+ if ( it->base->accesses_memory() )
+ {
+ // Skip if access type does not match.
+ //
+ switch ( type )
+ {
+ // ::read will filter to read.
+ //
+ case access_type::read:
+ if ( it->base->writes_memory() )
+ return { access_type::none };
+ break;
+ // ::write will filter to write.
+ //
+ case access_type::write:
+ if ( !it->base->writes_memory() )
+ return { access_type::none };
+ break;
+ // Read/write does not exist for memory operations.
+ //
+ case access_type::readwrite:
+ unreachable();
+ // ::none accepts any access.
+ //
+ case access_type::none:
+ // Determine the type and set it.
+ //
+ type = it->base->writes_memory() ? access_type::write : access_type::read;
+ break;
+ }
+
+ // Generate an expression for the pointer.
+ //
+ auto [base, offset] = it->get_mem_loc();
+ symbolic::pointer ptr = { tracer->trace( { it, base } ) + offset };
+
+ // If the two pointers can overlap (not restrict qualified against each other):
+ //
+ if ( ptr.can_overlap( mem->base ) )
+ {
+ // If it can be expressed as a constant:
+ //
+ if ( auto disp = ( ptr - mem->base ) )
+ {
+ // Check if within boundaries:
+ //
+ int64_t low_offset = *disp;
+ int64_t high_offset = low_offset + it->access_size();
+ if ( low_offset < ( mem->bit_count / 8 ) && high_offset > 0 )
+ {
+ // Can safely multiply by 8 and shrink to bitcnt_t type from int64_t
+ // since variables are of maximum 64-bit size which means both offset
+ // and size will be small numbers.
+ //
+ return {
+ type,
+ bitcnt_t( low_offset * 8 ),
+ bitcnt_t( ( high_offset - low_offset ) * 8 )
+ };
+ }
+ }
+ // Otherwise, return unknown.
+ //
+ else
+ {
+ return { type, 0, -1 };
+ }
+ }
+ }
+ }
+
+ // No access case.
+ //
+ return { access_type::none };
+ }
+};
\ No newline at end of file
diff --git a/VTIL-Optimizer/analysis/variable_aux.hpp b/VTIL-Architecture/trace/auxiliaries.hpp
similarity index 73%
rename from VTIL-Optimizer/analysis/variable_aux.hpp
rename to VTIL-Architecture/trace/auxiliaries.hpp
index d2c2a57..90a819c 100644
--- a/VTIL-Optimizer/analysis/variable_aux.hpp
+++ b/VTIL-Architecture/trace/auxiliaries.hpp
@@ -26,18 +26,14 @@
// POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
-#include
#include
#include
-#include "trace.hpp"
-#include
+#include "tracer.hpp"
+#include "../routine/basic_block.hpp"
+#include "../symex/variable.hpp"
-namespace vtil::optimizer
+namespace vtil
{
- // Callback typedefs.
- //
- using partial_tracer_t = std::function;
-
// Enumeration used to describe the type of access to a variable.
//
enum class access_type
@@ -74,24 +70,10 @@ namespace vtil::optimizer
bool is_unknown() const { return bit_count == -1; }
};
- // Makes a memory variable from the given instruction's src/dst, uses the tracer
- // passed to resolve the absolute pointer.
- //
- symbolic::variable reference_memory( const il_const_iterator& it,
- const trace_function_t& tracer = [ ] ( auto x ) { return trace( x ); } );
-
// Checks if the instruction given accesses the variable, optionally filtering to the
// access type specified, tracer passed will be used to generate pointers when needed.
//
access_details test_access( const il_const_iterator& it,
const symbolic::variable::descriptor_t& var,
- access_type type = access_type::none,
- const trace_function_t& tracer = [ ] ( auto x ) { return trace( x ); } );
-
- // Given a partial tracer, this routine will determine the full value of the variable
- // at the given position where a partial write was found.
- //
- symbolic::expression resolve_partial( const access_details& access,
- bitcnt_t bit_count,
- const partial_tracer_t& ptracer );
+ tracer* tracer, access_type type = access_type::none );
};
\ No newline at end of file
diff --git a/VTIL-Architecture/trace/cached_tracer.cpp b/VTIL-Architecture/trace/cached_tracer.cpp
new file mode 100644
index 0000000..e6bfa52
--- /dev/null
+++ b/VTIL-Architecture/trace/cached_tracer.cpp
@@ -0,0 +1,109 @@
+#include "cached_tracer.hpp"
+
+namespace vtil
+{
+ // Hooks default tracer and does a cache lookup before invokation.
+ //
+ symbolic::expression cached_tracer::trace( symbolic::variable lookup )
+ {
+ using namespace logger;
+
+ #if VTIL_OPT_TRACE_VERBOSE
+ // Log the beginning of the trace.
+ //
+ log( "CcTrace(%s)\n", lookup );
+ scope_padding _p( 1 );
+ #endif
+ // Handle base case.
+ //
+ if ( lookup.at.is_begin() )
+ {
+ symbolic::expression result = lookup.to_expression();
+ #if VTIL_OPT_TRACE_VERBOSE
+ // Log result.
+ //
+ log( "= %s [Base case]\n", result );
+ #endif
+ return result;
+ }
+
+ // Try lookup the exact variable in the map in a fast manner.
+ //
+ auto it = cache.find( lookup );
+ if ( it != cache.end() )
+ {
+ const symbolic::expression& result = *it->second;
+ #if VTIL_OPT_TRACE_VERBOSE
+ // Log result.
+ //
+ log( "= %s [Cached result]\n", result );
+ #endif
+ return result;
+ }
+ // Declare a predicate for the search of the variable in the cache.
+ //
+ std::function predicate;
+
+ // If memory variable:
+ //
+ if ( lookup.is_memory() )
+ {
+ predicate = [ & ] ( const cache_entry& pair )
+ {
+ // Key must be of memory type at the same position.
+ //
+ if ( !pair.first.is_memory() ) return false;
+ if ( pair.first.at != lookup.at ) return false;
+
+ // Must be the same pointer and have a larger or equal size.
+ //
+ auto& self = lookup.mem();
+ auto& other = pair.first.mem();
+ return self.decay().equals( other.decay() ) &&
+ self.bit_count >= other.bit_count;
+ };
+ }
+ // If register variable:
+ //
+ else
+ {
+ fassert( lookup.is_register() );
+ predicate = [ & ] ( const cache_entry& pair )
+ {
+ // Key must be of memory type at the same position.
+ //
+ if ( !pair.first.is_register() ) return false;
+ if ( pair.first.at != lookup.at ) return false;
+
+ // Must be the same register and have a larger or equal size.
+ //
+ auto& self = lookup.reg();
+ auto& other = pair.first.reg();
+ return self.flags == other.flags &&
+ self.local_id == other.local_id &&
+ self.bit_offset == other.bit_offset &&
+ self.bit_count >= other.bit_count;
+ };
+ }
+
+ // Search the map, if we find a matching entry shrink and use as the result.
+ //
+ symbolic::expression result;
+ it = std::find_if( cache.begin(), cache.end(), predicate );
+ if ( it != cache.end() )
+ result = symbolic::expression{ *it->second }.resize( lookup.bit_count() );
+ else
+ result = tracer::trace( lookup );
+
+ // Insert a cache entry for the exact variable we're looking up and return.
+ //
+ cache.emplace( lookup, result );
+
+ #if VTIL_OPT_TRACE_VERBOSE
+ // Log result.
+ //
+ log( "= %s\n", result );
+ #endif
+ return result;
+ }
+};
\ No newline at end of file
diff --git a/VTIL-Optimizer/analysis/cached_tracer.hpp b/VTIL-Architecture/trace/cached_tracer.hpp
similarity index 77%
rename from VTIL-Optimizer/analysis/cached_tracer.hpp
rename to VTIL-Architecture/trace/cached_tracer.hpp
index 90f5e62..d573559 100644
--- a/VTIL-Optimizer/analysis/cached_tracer.hpp
+++ b/VTIL-Architecture/trace/cached_tracer.hpp
@@ -26,19 +26,18 @@
// POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
-#include
-#include