Slight changes to symbolic::context/memory interface.

This commit is contained in:
Can Bölük 2020-07-30 02:42:35 +02:00
parent 230c51470f
commit d5a7ace029
5 changed files with 53 additions and 32 deletions

View file

@ -30,9 +30,9 @@
namespace vtil::symbolic
{
// Checks if the symbolic context contains any writes to the given region described by the register desc.
// Returns the absolute mask of known/unknown bits of the given register.
//
bool context::contains( const register_desc& desc ) const
uint64_t context::known_mask( const register_desc& desc ) const
{
// If identifier is not in the store, return false.
//
@ -42,27 +42,35 @@ namespace vtil::symbolic
// Enumerate each bit set within (size+offset, 0]:
//
bool found = false;
uint64_t known_mask = 0;
math::bit_enum( it->second.bitmap & math::fill( desc.bit_count + desc.bit_offset ), [ & ] ( bitcnt_t i )
{
// If value extends into the region, declare found.
// If value extends into the region, declare found, set known mask.
//
const expression::reference& value = it->second.linear_store[ i ];
if ( ( value.size() + i ) > desc.bit_offset )
found = true;
known_mask |= math::fill( value.size(), i );
} );
return found;
return known_mask & desc.get_mask();
}
uint64_t context::unknown_mask( const register_desc& desc ) const
{
return desc.get_mask() & ~known_mask( desc );
}
// Reads the value of the given region described by the register desc.
// - Will output the mask of bits contained in the state into contains.
//
expression::reference context::read( const register_desc& desc, const il_const_iterator& reference_iterator ) const
expression::reference context::read( const register_desc& desc, const il_const_iterator& reference_iterator, uint64_t* contains ) const
{
uint64_t tmp;
if ( !contains ) contains = &tmp;
// If identifier is not in the store, return default.
//
auto it = value_map.find( desc );
if ( it == value_map.end() )
return CTX( reference_iterator )[ desc ];
return *contains = 0, CTX( reference_iterator )[ desc ];
// Allocate storage for result and create masks.
//
@ -99,7 +107,8 @@ namespace vtil::symbolic
// If no bits set in known mask, return default.
//
if ( !known_mask )
*contains = known_mask & read_mask;
if ( !*contains )
return CTX( reference_iterator )[ desc ];
// If all bits set in known mask, return as is.

View file

@ -65,13 +65,15 @@ namespace vtil::symbolic
size_t size() const { return value_map.size(); }
void reset() { value_map.clear(); }
// Checks if the symbolic context contains any writes to the given region described by the register desc.
// Returns the absolute mask of known/unknown bits of the given register.
//
bool contains( const register_desc& desc ) const;
uint64_t known_mask( const register_desc& desc ) const;
uint64_t unknown_mask( const register_desc& desc ) const;
// Reads the value of the given region described by the register desc.
// - Will output the mask of bits contained in the state into contains.
//
expression::reference read( const register_desc& desc, const il_const_iterator& reference_iterator = symbolic::free_form_iterator ) const;
expression::reference read( const register_desc& desc, const il_const_iterator& reference_iterator = symbolic::free_form_iterator, uint64_t* contains = nullptr ) const;
// Writes the given value to the region described by the register desc.
//

View file

@ -30,15 +30,22 @@
namespace vtil::symbolic
{
// Checks if the symbolic memory contains any writes to the given memory region.
// Returns the mask of known/unknown bits of the given region, if alias failure occurs returns nullopt.
//
trilean memory::contains( const pointer& ptr, bitcnt_t size ) const
std::optional<uint64_t> memory::known_mask( const pointer& ptr, bitcnt_t size ) const
{
uint64_t mask_value = math::fill( size );
if ( auto value = unknown_mask( ptr, size ) )
return math::fill( size ) & ~*value;
else
return std::nullopt;
}
std::optional<uint64_t> memory::unknown_mask( const pointer& ptr, bitcnt_t size ) const
{
uint64_t mask_pending = math::fill( size );
// For each entry, iterating backwards:
//
for ( auto it = value_map.rbegin(); it != value_map.rend(); it++ )
for ( auto it = value_map.rbegin(); it != value_map.rend() && mask_pending; it++ )
{
// If pointer cannot overlap lookup, skip.
//
@ -49,25 +56,25 @@ namespace vtil::symbolic
//
std::optional byte_distance = it->first - ptr;
if ( !byte_distance )
return trilean::unknown;
return std::nullopt;
// Calculate relative mask, return true if overlapping.
// Calculate relative mask, clear pending mask.
//
bitcnt_t bit_distance = math::narrow_cast< bitcnt_t >( *byte_distance * 8 );
bitcnt_t bit_distance = math::narrow_cast<bitcnt_t>( *byte_distance * 8 );
uint64_t relative_mask = math::fill( it->second.size(), bit_distance );
if ( relative_mask & mask_value )
return true;
mask_pending &= ~relative_mask;
}
// None found, return false.
//
return false;
return mask_pending;
}
// Reads N bits from the given pointer, returns null reference if alias failure occurs.
// - Will output the mask of bits contained in the state into contains if it does not fail.
//
expression::reference memory::read( const pointer& ptr, bitcnt_t size, const il_const_iterator& reference_iterator ) const
expression::reference memory::read( const pointer& ptr, bitcnt_t size, const il_const_iterator& reference_iterator, uint64_t* contains ) const
{
uint64_t tmp;
if ( !contains ) contains = &tmp;
uint64_t mask_pending = math::fill( size );
stack_vector<std::pair<bitcnt_t, expression::reference>, 8> merge_list;
@ -111,7 +118,8 @@ namespace vtil::symbolic
// If no overlapping keys found, return default.
//
if ( merge_list.empty() )
*contains = math::fill( size ) & ~mask_pending;
if ( !*contains )
return MEMORY( reference_iterator )( ptr, size );
// Declare common bit selector.

View file

@ -67,13 +67,15 @@ namespace vtil::symbolic
size_t size() const { return value_map.size(); }
void reset() { value_map.clear(); }
// Checks if the symbolic memory contains any writes to the given memory region.
//
trilean contains( const pointer& ptr, bitcnt_t size ) const;
// Returns the mask of known/unknown bits of the given region, if alias failure occurs returns nullopt.
//
std::optional<uint64_t> known_mask( const pointer& ptr, bitcnt_t size ) const;
std::optional<uint64_t> unknown_mask( const pointer& ptr, bitcnt_t size ) const;
// Reads N bits from the given pointer, returns null reference if alias failure occurs.
// - Will output the mask of bits contained in the state into contains if it does not fail.
//
expression::reference read( const pointer& ptr, bitcnt_t size, const il_const_iterator& reference_iterator = symbolic::free_form_iterator ) const;
expression::reference read( const pointer& ptr, bitcnt_t size, const il_const_iterator& reference_iterator = symbolic::free_form_iterator, uint64_t* contains = nullptr ) const;
// Writes the given value to the pointer, returns null reference if alias failure occurs.
//

View file

@ -66,7 +66,7 @@ namespace vtil
//
symbolic::expression::reference read_memory( const symbolic::expression::reference& pointer, size_t byte_count ) override
{
return memory_state.read( pointer, math::narrow_cast< bitcnt_t >( byte_count * 8 ), reference_iterator );
return memory_state.read( pointer, math::narrow_cast<bitcnt_t>( byte_count * 8 ), reference_iterator );
}
// Writes the given expression to the memory.