Segmented into categories, implemented copy on write references.

This commit is contained in:
Can Bölük 2020-04-14 16:47:09 +02:00
parent ad7f01ab8b
commit ce193cb8e6
22 changed files with 248 additions and 65 deletions

View file

@ -93,23 +93,27 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="asserts.hpp" />
<ClInclude Include="disassembly.hpp" />
<ClInclude Include="emulator.hpp" />
<ClInclude Include="formatting.hpp" />
<ClInclude Include="includes\vtil\common.hpp" />
<ClInclude Include="assembler.hpp" />
<ClInclude Include="logger.hpp" />
<ClInclude Include="register_details.hpp" />
<ClInclude Include="rwx_allocator.hpp" />
<ClInclude Include="amd64\assembler.hpp" />
<ClInclude Include="amd64\disassembly.hpp" />
<ClInclude Include="amd64\emulator.hpp" />
<ClInclude Include="amd64\register_details.hpp" />
<ClInclude Include="includes\vtil\common" />
<ClInclude Include="includes\vtil\io" />
<ClInclude Include="includes\vtil\memory" />
<ClInclude Include="includes\vtil\amd64" />
<ClInclude Include="io\asserts.hpp" />
<ClInclude Include="io\formatting.hpp" />
<ClInclude Include="io\logger.hpp" />
<ClInclude Include="memory\copy_on_write.hpp" />
<ClInclude Include="memory\rwx_allocator.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="disassembly.cpp" />
<ClCompile Include="emulator.cpp" />
<ClCompile Include="assembler.cpp" />
<ClCompile Include="logger.cpp" />
<ClCompile Include="register_details.cpp" />
<ClCompile Include="rwx_allocator.cpp" />
<ClCompile Include="amd64\assembler.cpp" />
<ClCompile Include="amd64\disassembly.cpp" />
<ClCompile Include="amd64\emulator.cpp" />
<ClCompile Include="amd64\register_details.cpp" />
<ClCompile Include="io\logger.cpp" />
<ClCompile Include="memory\rwx_allocator.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View file

@ -4,61 +4,81 @@
<Filter Include="Memory">
<UniqueIdentifier>{424c679d-7468-453f-8b9d-7d282aaf9470}</UniqueIdentifier>
</Filter>
<Filter Include="x86">
<UniqueIdentifier>{cb6f5bfd-fdca-47fe-bbb7-e91d8e5ba642}</UniqueIdentifier>
</Filter>
<Filter Include="Emulation">
<UniqueIdentifier>{673822af-de5d-4c16-9306-ac6c1441f341}</UniqueIdentifier>
</Filter>
<Filter Include="I/O">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="amd64">
<UniqueIdentifier>{cb6f5bfd-fdca-47fe-bbb7-e91d8e5ba642}</UniqueIdentifier>
</Filter>
<Filter Include="amd64\Emulation">
<UniqueIdentifier>{673822af-de5d-4c16-9306-ac6c1441f341}</UniqueIdentifier>
</Filter>
<Filter Include="Includes">
<UniqueIdentifier>{14333603-a637-4356-854a-db631a744d42}</UniqueIdentifier>
</Filter>
<Filter Include="amd64\Core">
<UniqueIdentifier>{dbf4733d-3814-4218-9474-cf4b4e3c5719}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="formatting.hpp">
<Filter>I/O</Filter>
<ClInclude Include="amd64\register_details.hpp">
<Filter>amd64</Filter>
</ClInclude>
<ClInclude Include="logger.hpp">
<Filter>I/O</Filter>
<ClInclude Include="amd64\assembler.hpp">
<Filter>amd64\Core</Filter>
</ClInclude>
<ClInclude Include="asserts.hpp">
<Filter>I/O</Filter>
<ClInclude Include="amd64\disassembly.hpp">
<Filter>amd64\Core</Filter>
</ClInclude>
<ClInclude Include="rwx_allocator.hpp">
<ClInclude Include="amd64\emulator.hpp">
<Filter>amd64\Emulation</Filter>
</ClInclude>
<ClInclude Include="memory\copy_on_write.hpp">
<Filter>Memory</Filter>
</ClInclude>
<ClInclude Include="register_details.hpp">
<Filter>x86</Filter>
<ClInclude Include="memory\rwx_allocator.hpp">
<Filter>Memory</Filter>
</ClInclude>
<ClInclude Include="emulator.hpp">
<Filter>Emulation</Filter>
<ClInclude Include="io\asserts.hpp">
<Filter>I/O</Filter>
</ClInclude>
<ClInclude Include="includes\vtil\common.hpp" />
<ClInclude Include="disassembly.hpp">
<Filter>x86</Filter>
<ClInclude Include="io\formatting.hpp">
<Filter>I/O</Filter>
</ClInclude>
<ClInclude Include="assembler.hpp">
<Filter>x86</Filter>
<ClInclude Include="io\logger.hpp">
<Filter>I/O</Filter>
</ClInclude>
<ClInclude Include="includes\vtil\amd64">
<Filter>Includes</Filter>
</ClInclude>
<ClInclude Include="includes\vtil\common">
<Filter>Includes</Filter>
</ClInclude>
<ClInclude Include="includes\vtil\io">
<Filter>Includes</Filter>
</ClInclude>
<ClInclude Include="includes\vtil\memory">
<Filter>Includes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="register_details.cpp">
<Filter>x86</Filter>
<ClCompile Include="amd64\register_details.cpp">
<Filter>amd64</Filter>
</ClCompile>
<ClCompile Include="rwx_allocator.cpp">
<ClCompile Include="amd64\assembler.cpp">
<Filter>amd64\Core</Filter>
</ClCompile>
<ClCompile Include="amd64\disassembly.cpp">
<Filter>amd64\Core</Filter>
</ClCompile>
<ClCompile Include="amd64\emulator.cpp">
<Filter>amd64\Emulation</Filter>
</ClCompile>
<ClCompile Include="memory\rwx_allocator.cpp">
<Filter>Memory</Filter>
</ClCompile>
<ClCompile Include="emulator.cpp">
<Filter>Emulation</Filter>
</ClCompile>
<ClCompile Include="disassembly.cpp">
<Filter>x86</Filter>
</ClCompile>
<ClCompile Include="assembler.cpp">
<Filter>x86</Filter>
</ClCompile>
<ClCompile Include="logger.cpp">
<ClCompile Include="io\logger.cpp">
<Filter>I/O</Filter>
</ClCompile>
</ItemGroup>

View file

@ -5,7 +5,7 @@
#include <cstring>
#include <set>
#include <capstone/capstone.h>
#include "formatting.hpp"
#include "..\io\formatting.hpp"
namespace vtil::x86
{

View file

@ -1,4 +1,5 @@
#include "emulator.hpp"
#include "..\io\asserts.hpp"
namespace vtil
{
@ -87,7 +88,6 @@ namespace vtil
// Resolves the offset<0> where the value is saved at for the given register
// and the number of bytes<1> it takes.
//
inline std::pair<int32_t, uint8_t> emulator::resolve( x86_reg reg ) const
{
auto [base_reg, offset, size] = x86::resolve_mapping( reg );
@ -118,7 +118,6 @@ namespace vtil
// Sets the value of a register.
//
inline emulator& emulator::set( x86_reg reg, uint64_t value )
{
auto [off, sz] = resolve( reg );
@ -128,7 +127,6 @@ namespace vtil
// Gets the value of a register.
//
inline uint64_t emulator::get( x86_reg reg ) const
{
uint64_t value = 0;

View file

@ -3,7 +3,7 @@
#include <tuple>
#include <string>
#include "disassembly.hpp"
#include "asserts.hpp"
#include "..\io\asserts.hpp"
namespace vtil::x86
{

View file

@ -0,0 +1,5 @@
#pragma once
#include "..\..\amd64\emulator.hpp"
#include "..\..\amd64\assembler.hpp"
#include "..\..\amd64\disassembly.hpp"
#include "..\..\amd64\register_details.hpp"

View file

@ -0,0 +1,4 @@
#pragma once
#include <vtil/memory>
#include <vtil/io>
#include <vtil/amd64>

View file

@ -1,9 +0,0 @@
#pragma once
#include "..\..\asserts.hpp"
#include "..\..\formatting.hpp"
#include "..\..\logger.hpp"
#include "..\..\rwx_allocator.hpp"
#include "..\..\emulator.hpp"
#include "..\..\assembler.hpp"
#include "..\..\disassembly.hpp"
#include "..\..\register_details.hpp"

View file

@ -0,0 +1,4 @@
#pragma once
#include "..\..\io\asserts.hpp"
#include "..\..\io\formatting.hpp"
#include "..\..\io\logger.hpp"

View file

@ -0,0 +1,3 @@
#pragma once
#include "..\..\memory\rwx_allocator.hpp"
#include "..\..\memory\copy_on_write.hpp"

View file

@ -7,6 +7,12 @@
#define FMT_INS_OPR "%-12s"
#define FMT_INS FMT_INS_MNM " " FMT_INS_OPR " " FMT_INS_OPR " " FMT_INS_OPR " " FMT_INS_OPR
// Billion dollar company yes? (::fix_parameter throws a warning otherwise.)
//
#ifdef __INTEL_COMPILER
#pragma warning (disable:1011)
#endif
namespace vtil::format
{
// Suffixes used to indicate registers of N bytes.

View file

@ -0,0 +1,148 @@
#pragma once
#include <memory>
#include <functional>
#include <type_traits>
#include "..\io\asserts.hpp"
// Thanks visual studio.
//
#ifdef __INTELLISENSE__
#define __builtin_frame_address(level) ((void*)1337)
#endif
// The copy-on-write interface defined here is used to avoid deep duplications of
// containers such as trees when a VTIL routine is working with them.
//
namespace vtil
{
// This structure is used to describe copy-on-write references.
//
template<typename T>
struct shared_reference
{
// The original reference and current state.
//
std::shared_ptr<T> reference;
bool is_owning = false;
bool is_locked = false;
// Null reference construction.
//
shared_reference() {}
shared_reference( std::nullptr_t ) {}
// Owning reference constructor.
//
shared_reference( T&& obj ) : reference( std::make_shared<T>( std::forward<T>( obj ) ) ), is_owning( true ) {}
template<typename... params, typename = std::enable_if_t<std::is_same_v<std::remove_cvref_t<params...>, shared_reference<T>>>>
shared_reference( params&&... p ) : reference( std::make_shared<T>( std::forward<params>( p )... ) ), is_owning( true ) {}
// Copy-on-write reference construction and assignment.
//
shared_reference( const shared_reference& ref ) : reference( ref.reference ), is_locked( ref.is_locked ) {}
shared_reference& operator=( const shared_reference& o ) { reference = o.reference; is_locked = o.is_locked; is_owning = false; return *this; }
// Construction and assignment operator for rvalue references.
//
shared_reference( shared_reference&& ref ) : reference( std::move( ref.reference ) ), is_owning( std::move( ref.is_owning ) ), is_locked( std::move( ref.is_locked ) ) {}
shared_reference& operator=( shared_reference&& o ) { reference = std::move( o.reference ); is_owning = std::move( o.is_owning ); is_locked = std::move( o.is_locked ); return *this; }
// Simple validity checks.
bool is_valid() const { return ( bool ) reference; }
operator bool() const { return is_valid(); }
// Locks the current reference, a locked reference cannot be upgraded
// to a copy-on-write reference as is.
//
shared_reference& lock() { is_locked = true; is_owning = false; return *this; }
// Unlocks the current reference, should be called before storing the reference.
//
shared_reference& unlock()
{
// If reference is locked, we need to copy it.
//
if ( is_locked )
{
// Create a copy and change reference to point at it.
//
reference = std::make_shared<T>( *reference );
// Mark as unlocked and owning.
//
is_locked = true;
is_owning = true;
}
return *this;
}
// Converts this reference to an owning one if it is not one already and
// returns the pointer to the base type with no const-qualifiers.
//
T* own()
{
fassert( is_valid() );
// If copy-on-write, convert to owning first.
//
if ( !is_owning )
{
// If use counter is above 1 or reference is locked, we need
// to make a copy before modifying the reference.
//
if ( reference.use_count() > 1 || is_locked )
reference = std::make_shared<T>( *reference );
// Mark as unlocked and owning.
//
is_owning = true;
is_locked = false;
}
// Redirect the operator to the reference.
//
return reference.operator->();
}
// Basic comparison operators are redirected to the pointer type.
//
bool operator==( const shared_reference& o ) const { return reference == o.reference; }
bool operator<( const shared_reference& o ) const { return reference < o.reference; }
// Redirect pointer and dereferencing operator to the reference and cast to const-qualified equivalent.
//
const T* operator->() const { fassert( is_valid() ); return reference.operator->(); }
const T& operator*() const { fassert( is_valid() ); return *reference; }
// Syntax sugar for ::own() using add operator.
//
T* operator+() { return own(); }
};
// Local references are used to create copy-on-write references to values on stack,
// note that they should not be stored under any condition.
//
template<typename T>
__forceinline shared_reference<T> make_local_reference( T* variable_pointer )
{
// Save current frame address.
//
void* creation_frame = __builtin_frame_address( 0 );
// Create a shared_reference from a custom std::shared_ptr.
//
shared_reference<T> output;
output.reference = std::shared_ptr<T>{ variable_pointer, [ creation_frame ] ( T* ptr )
{
// Should not be destructed above current frame.
//
fassert( creation_frame > __builtin_frame_address( 0 ) );
} };
// Mark as locked and return.
//
output.is_locked = true;
return output;
}
};

View file

@ -5,7 +5,7 @@
#else
#include <sys/mman.h>
#endif
#include "asserts.hpp"
#include "..\io\asserts.hpp"
#include "rwx_allocator.hpp"
namespace vtil