diff --git a/zipr_xeon_plugin/README.md b/zipr_xeon_plugin/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2d22d3137141c091512b10f9612fd5b597b9295f --- /dev/null +++ b/zipr_xeon_plugin/README.md @@ -0,0 +1 @@ +M. McGill to provide. \ No newline at end of file diff --git a/zipr_xeon_plugin/SConscript b/zipr_xeon_plugin/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..1b275c8a82fa5d3d3756fab35f79456f9c12ca3a --- /dev/null +++ b/zipr_xeon_plugin/SConscript @@ -0,0 +1,61 @@ +import shutil +import os +import tarfile + +Import('env') + + +#print 'env=' +#print env.Dump() + + + +myenv=env.Clone() +myenv.Replace(SECURITY_TRANSFORMS_HOME=os.environ['SECURITY_TRANSFORMS_HOME']) +myenv.Replace(ZIPR_HOME=os.environ['ZIPR_HOME']) +myenv.Replace(ZIPR_SDK=os.environ['ZIPR_SDK']) +myenv.Replace(IRDB_SDK=os.environ['IRDB_SDK']) +myenv.Replace(ZIPR_INSTALL=os.environ['ZIPR_INSTALL']) + + + +files= ''' + Xeon_relocs.cpp + ''' + +# ELFIO needs to be first so we get the zipr version instead of the sectrans version. the zipr version is modified to include get_offset. +cpppath=''' + . + $IRDB_SDK/include/ + $ZIPR_SDK/include/ + $SECURITY_TRANSFORMS_HOME/libtransform/include + $SECURITY_TRANSFORMS_HOME/third_party/elfio-code + ''' +''' + $SECURITY_TRANSFORMS_HOME/include/ + $SECURITY_TRANSFORMS_HOME/libIRDB/include/ + $SECURITY_TRANSFORMS_HOME/beaengine/include + $SECURITY_TRANSFORMS_HOME/beaengine/beaengineSources/Includes/ + $ZIPR_HOME/include/ + $ZIPR_SDK/include/ + ''' + +libs=''' + ''' + +libpath=''' + $SECURITY_TRANSFORMS_HOME/lib + ''' + +myenv.Append(CCFLAGS=" -Wall -Werror -std=c++11 -fmax-errors=2 ") +myenv=myenv.Clone(CPPPATH=Split(cpppath), LIBPATH=Split(libpath), SHLIBSUFFIX=".zpi", SHLIBPREFIX="") +lib=myenv.SharedLibrary("Xeon_relocs", Split(files)) + +install=myenv.Install("$ZIPR_INSTALL/plugins/", lib) +Default(install) + +pedi = Command( target = "./testoutput", + source = "./SConscript", + action = "cd "+os.environ['ZIPR_INSTALL']+" ; " +os.environ['PEDI_HOME']+"/pedi -m manifest.txt ; cd -" ) +Default( pedi ) + diff --git a/zipr_xeon_plugin/SConstruct b/zipr_xeon_plugin/SConstruct new file mode 100644 index 0000000000000000000000000000000000000000..66f12e3d96c0decea989b3c27b466247b865978d --- /dev/null +++ b/zipr_xeon_plugin/SConstruct @@ -0,0 +1,37 @@ +import os +import sys + + +env=Environment() + +# default build options +env.Replace(CFLAGS="-fPIC -w ") +env.Replace(CXXFLAGS="-fPIC -w ") +env.Replace(LINKFLAGS="-fPIC ") + +# parse arguments +env.Replace(SECURITY_TRANSFORMS_HOME=os.environ['SECURITY_TRANSFORMS_HOME']) +env.Replace(ZIPR_HOME=os.environ['ZIPR_HOME']) +env.Replace(ZIPR_INSTALL=os.environ['ZIPR_INSTALL']) +env.Replace(ZIPR_SDK=os.environ['ZIPR_SDK']) +env.Replace(debug=ARGUMENTS.get("debug",0)) +env.Replace(do_64bit_build=ARGUMENTS.get("do_64bit_build",0)) + + +if int(env['debug']) == 1: + print "Setting debug mode" + env.Append(CFLAGS=" -g") + env.Append(CXXFLAGS=" -g") + env.Append(LINKFLAGS=" -g") +else: + print "Setting release mode" + env.Append(CFLAGS=" -O3") + env.Append(CXXFLAGS=" -O3") + env.Append(LINKFLAGS=" -O3") + +env['build_appfw']=0 +env['build_tools']=0 + +Export('env') +SConscript("SConscript", variant_dir='build') + diff --git a/zipr_xeon_plugin/Xeon_relocs.cpp b/zipr_xeon_plugin/Xeon_relocs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0cc7307ad6b0409066cc46c7be870893f7085bf --- /dev/null +++ b/zipr_xeon_plugin/Xeon_relocs.cpp @@ -0,0 +1,493 @@ +#include "Xeon_relocs.hpp" +#include <algorithm> + +using namespace IRDB_SDK; +using namespace Zipr_SDK; +using namespace std; + + +// use this to determine whether a scoop has a given name. +static struct ScoopFinder : binary_function<const DataScoop_t*,const string,bool> +{ + // declare a simple scoop finder function that finds scoops by name + bool operator()(const DataScoop_t* scoop, const string& name) const + { + return (scoop->getName() == name); + }; +} scoop_finder; + + +static DataScoop_t* find_scoop(FileIR_t *firp,const string &name) +{ + auto it=find_if(firp->getDataScoops().begin(), firp->getDataScoops().end(), bind2nd(scoop_finder, name)) ; + if( it != firp->getDataScoops().end() ) + return *it; + return NULL; +}; + + +static void extract_fields(const string &reloc_string, int &sz, int &pos, string &val) +{ + sz=pos=0; + val=""; + + size_t loc=reloc_string.find('='); + string nonce_value=reloc_string.substr(loc+1,reloc_string.size()-loc-1); + + // trying to parse a triple of form (a,b,c) into strings a,b,c + // cfi_nonce=(pos=2,nv=0,sz=1) + + // find first comma + size_t comma_pos=nonce_value.find(','); + + // parse out A + string first=nonce_value.substr(5,comma_pos-1-4); // 1== strlen(","), 5==strlen("(pos=") + + // parse out "b,c)" + string rest=nonce_value.substr(comma_pos+1, string::npos); // 1 == strlen(",") + + // find next comma + comma_pos=rest.find(','); + + // parse out B + string second=rest.substr(3,comma_pos-3); // 3=strlen("nv=") + + // parse out "c)" + rest=rest.substr(comma_pos+1, string::npos); // 1==sizeof(",") + + // find closing paren. + size_t paren_pos=rest.find(')'); + + // pares out C + string third=rest.substr(3,paren_pos-3); // 3==strlen("sz=") + + + pos=(int)strtol(first.c_str(),0,10); + val=second; + sz=(int)strtol(third.c_str(),0,10); +} + +static string GetNonceValue(Relocation_t& reloc) +{ + int sz, pos; + string val; + extract_fields(reloc.getType(), sz, pos, val); + return val; +} + +static int GetNonceSize(Relocation_t& reloc) +{ + int sz, pos; + string val; + extract_fields(reloc.getType(), sz, pos, val); + return sz; +} + +static int GetNonceOffset(Relocation_t& reloc) +{ + int sz, pos; + string val; + extract_fields(reloc.getType(), sz, pos, val); + return pos; +} + + +// TODO: BAD COUPLING, SHOULD PASS REG WITH RELOC +void Xeon_relocs::AddDynLibCheckCode() +{ + // Decide what register to use + string reg="ecx"; // 32-bit reg + if(firp->getArchitectureBitWidth()==64) + reg="r11"; // 64-bit reg. + + for( auto it=firp->getInstructions().begin(); it!=firp->getInstructions().end(); ++it) + { + const auto insn=*it; + if(FindRelocation(insn, "insert_dynlib_check")) + { + Instruction_t* old_target = insn->getTarget(); + insn->setTarget(GetDynLibCheckCode(reg, old_target)); + } + } + firp->assembleRegistry(); // resolve all assembly into actual bits. + firp->setBaseIDS(); // assign a unique ID to each insn. +} + + +void Xeon_relocs::UpdateAddrRanges() +{ + RangeAddress_t min_addr=m_memory_space->getMinPlopped(); + RangeAddress_t max_addr=m_memory_space->getMaxPlopped(); + + int offset=0; // deal with REX prefix for 64-bit mode. + if(firp->getArchitectureBitWidth()==64) + offset=1; + + InstructionSet_t::iterator it; + for(it=min_addr_update.begin(); it!=min_addr_update.end(); ++it) + { + Instruction_t& insn=*(*it); + RangeAddress_t insn_addr=(*final_insn_locations)[&insn]; + if(insn_addr) + { + // if(m_elfio->get_type() == ET_EXEC) + if(firp->getArchitecture()->getFileType()==adftELFEXE) + { + cout<<"Updating min_addr for cmp at "<<hex<<insn_addr<<" to compare to "<<min_addr<<endl; + m_memory_space->plopBytes(insn_addr+2+offset,(const char*)&min_addr,4); // cmp insn has a 4 byte immed. + } + // else if(m_elfio->get_type() == ET_DYN) + else if(firp->getArchitecture()->getFileType()==adftELFSO) + { + // pcrel addressing is always trick. + // effective address == instruction address + instruction size + offset + // so we need offset=effective_addr-instruction_address-insn_size; + RangeAddress_t offset=min_addr-insn_addr-insn.getDataBits().size(); + // lea trick doesn't work on 32-bit. + assert(firp->getArchitectureBitWidth()==64); + cout<<"Updating min_addr for "<<hex<<insn.getBaseID()<<":lea at "<<hex<<insn_addr<<" to compare to "<<min_addr<<", offset="<<offset<<endl; + m_memory_space->plopBytes(insn_addr+3,(const char*)&offset,4); // cmp insn has a 4 byte immed. + } + else + assert(0); + } + else + { + cout<<"No addr for min_addr at "<<hex<<insn_addr<<" to compare to "<<min_addr<<endl; + } + } + + for(it=max_addr_update.begin(); it!=max_addr_update.end(); ++it) + { + Instruction_t& insn=*(*it); + RangeAddress_t insn_addr=(*final_insn_locations)[&insn]; + assert(insn_addr); + if(insn_addr) + { + // if(m_elfio->get_type() == ET_EXEC) + if(firp->getArchitecture()->getFileType()==adftELFEXE) + { + cout<<"Updating max_addr at "<<hex<<insn_addr<<" to compare to "<<max_addr<<endl; + m_memory_space->plopBytes(insn_addr+2+offset,(const char*)&max_addr,4); // cmp insn with a 4-byte immed + } + else if(firp->getArchitecture()->getFileType()==adftELFSO) + // else if(m_elfio->get_type() == ET_DYN) + { + // pcrel addressing is always trick. + // effective address == instruction address + instruction size + offset + // so we need offset=effective_addr-instruction_address-insn_size; + RangeAddress_t offset=max_addr-insn_addr-insn.getDataBits().size(); + // lea trick doesn't work on 32-bit. + assert(firp->getArchitectureBitWidth()==64); + cout<<"Updating max_addr for "<<hex<<insn.getBaseID()<<":lea at "<<hex<<insn_addr<<" to compare to "<<max_addr<<", offset="<<offset<<endl; + m_memory_space->plopBytes(insn_addr+3,(const char*)&offset,4); // cmp insn has a 4 byte immed. + } + else + assert(0); + } + else + { + cout<<"No addr for max_addr at "<<hex<<insn_addr<<" to compare to "<<max_addr<<endl; + } + } +} + +#if 0 +ZiprOptionsNamespace_t *Xeon_relocs::registerOptions(Zipr_SDK::ZiprOptionsNamespace_t *global) +{ + global->addOption(&m_verbose); + return NULL; +} +#endif + + +bool Xeon_relocs::willPluginPlop(IRDB_SDK::Instruction_t* insn) +{ + if(!m_on) + return false; + + bool will_plop = false; + + if(FindExeNonceRelocation(insn)) + will_plop = true; + + if (*m_verbose) + { + + cout << "Xeon_relocs::WillPluginPlop:WillPlop=" <<std::boolalpha <<will_plop<<" for " + << hex << insn->getBaseID()<<":"<<insn->getDisassembly()<<endl; + } + return will_plop; +} + + +size_t Xeon_relocs::getDollopEntryOpeningSize(DollopEntry_t* entry) +{ + return 0; +} + + +size_t Xeon_relocs::getDollopEntryClosingSize(DollopEntry_t* entry) +{ + + if(!m_on) + return 0; + + Instruction_t* insn=entry->getInstruction(); + int exeNonceSize = 0; + for( + RelocationSet_t::iterator rit=insn->getRelocations().begin(); + rit!=insn->getRelocations().end(); + rit++ + ) + { + Relocation_t& reloc=*(*rit); + if(IsExeNonceRelocation(reloc)) + { + exeNonceSize += GetNonceSize(reloc); + } + } + + return exeNonceSize; +} + + +RangeAddress_t Xeon_relocs::plopDollopEntry(Zipr_SDK::DollopEntry_t *de, + RangeAddress_t & placed_addr, + RangeAddress_t & target_addr, + size_t instruction_size, + bool &instruction_placed) +{ + + //placed_addr=de->Place(); + RangeAddress_t ret=placed_addr; // relocs currently account for instruction size in offset + // TODO: Need to update ret to =instruction size + placed addr for calls if plopping on calls + Instruction_t* insn=de->getInstruction(); + if(DecodedInstruction_t::factory(insn)->isCall()) + { + ret += instruction_size; + } + + if (*m_verbose) + { + cout << "Xeon_relocs::Plopping Instruction : " << hex + << de->getInstruction()->getBaseID() <<":"<<de->getInstruction()->getDisassembly()<<endl; + cout << "placed_address : " << std::hex << placed_addr << endl; + cout << "de->Place() : " << std::hex << de->getPlace() << endl; + cout << "instruction_size: " << std::dec << instruction_size << endl; + } + + cout<<"Xeon_relocs::plopping "<<de->getInstruction()->getDisassembly()<<" at "<<hex<<placed_addr<<endl; + + RangeAddress_t baseOffset = ret; + for( + RelocationSet_t::iterator rit=insn->getRelocations().begin(); + rit!=insn->getRelocations().end(); + rit++ + ) + { + Relocation_t& reloc=*(*rit); + if(IsExeNonceRelocation(reloc)) + { + int offset=GetNonceOffset(reloc); + int size=GetNonceSize(reloc); + if(offset+size+baseOffset > ret) + { + ret = offset+size+baseOffset; + } + + string value=GetNonceValue(reloc); + + cout<<"Xeon_relocs::Placing nonce:"<<std::hex<<value<<" at "<<hex<<ret<<endl; + // Places in big endian order (it assumes the reloc has value in little-endian where appropriate) + for(int i = 0; i < size; ++i) + { + (*m_memory_space)[baseOffset+offset]=value.at(i); + ++offset; + } + } + } + + return ret; +} + + +//////////////////////////////////////////////////////////////////////////////// + +// minor helpers + +Relocation_t* Xeon_relocs::FindRelocation(Instruction_t* insn, string type) +{ + RelocationSet_t::iterator rit; + for( rit=insn->getRelocations().begin(); rit!=insn->getRelocations().end(); ++rit) + { + Relocation_t& reloc=*(*rit); + if(reloc.getType()==type) + { + return &reloc; + } + } + return NULL; +} + + +Relocation_t* Xeon_relocs::FindExeNonceRelocation(Instruction_t* insn) +{ + RelocationSet_t::iterator rit; + for( rit=insn->getRelocations().begin(); rit!=insn->getRelocations().end(); ++rit) + { + Relocation_t* reloc=*rit; + if(strstr(reloc->getType().c_str(),"cfi_exe_nonce=")!=NULL) + return reloc; + } + return NULL; +} + + +bool Xeon_relocs::IsExeNonceRelocation(Relocation_t& reloc) +{ + if(strstr(reloc.getType().c_str(),"cfi_exe_nonce=")==NULL) + return false; + return true; +} + + +//////////////////////////////////////////////////////////////////////////////// + +// main workers + +Instruction_t* Xeon_relocs::GetDynLibCheckCode(string reg, Instruction_t* target) +{ + string rspreg="esp"; // 32-bit reg + if(firp->getArchitectureBitWidth()==64) + rspreg="rsp"; // 64-bit reg. + + static Instruction_t* bounds_start=NULL; + Instruction_t* bounds_end=NULL; + + if(bounds_start != NULL) + return bounds_start; + + // we need a dispatch handler in case the range check fails + // this range check should be working with multimodule support enabled. + Instruction_t* out_of_range_handler=NULL; + out_of_range_handler = GenerateOutOfRangeHandler(); + + // before the individual checks on the slow path + // we want to insert a range check. + // cmp ecx/r11, start_segement_addr + // jlt out_of_range_handler + // cmp ecx/r11, end_segment_addr + // jgt out_of_range_handler + + // statically loaded exe. + // if(m_elfio->get_type() == ET_EXEC) + if(firp->getArchitecture()->getFileType()==adftELFEXE) + { + Instruction_t* tmp=NULL; + bounds_start = + tmp = addNewAssembly(firp,NULL,"cmp "+reg+", 0x12345678"); + min_addr_update.insert(tmp); + // cross library jump detected + tmp = insertAssemblyAfter(firp,tmp,"jl 0",out_of_range_handler); + // cross library jump detected + tmp = insertAssemblyAfter(firp,tmp,"cmp "+reg+", 0x87654321"); + max_addr_update.insert(tmp); + tmp = insertAssemblyAfter(firp,tmp,"jg 0",out_of_range_handler); // cross library jump detected + bounds_end=tmp; + } + // dynamically loaded object (pie exec or pic) + // else if(m_elfio->get_type() == ET_DYN) + else if(firp->getArchitecture()->getFileType()==adftELFSO) + { + Instruction_t* tmp=NULL; + Instruction_t* oor_pop=addNewAssembly(firp, NULL, "pop "+reg); // SYS_exit + oor_pop->setFallthrough(out_of_range_handler); + + string leastring1("\x4c\x8d\x1d\x78\x56\x34\x12",7); + string leastring2("\x4c\x8d\x1d\x12\x34\x56\x78",7); + + bounds_start= + tmp = addNewAssembly(firp,NULL,"push "+reg); // save target on stack + tmp = insertDataBitsAfter(firp,tmp, leastring1); // load lower bound + min_addr_update.insert(tmp); + tmp = insertAssemblyAfter(firp,tmp,"cmp [rsp], "+reg); // cmp to lower bound to target. + tmp = insertAssemblyAfter(firp,tmp,"jl 0", oor_pop); // cross library jump detected + tmp = insertDataBitsAfter(firp,tmp, leastring2); // load upper bound + max_addr_update.insert(tmp); + tmp = insertAssemblyAfter(firp,tmp,"cmp [rsp], "+reg); // compare upper bound to target. + tmp = insertAssemblyAfter(firp,tmp,"jg 0", oor_pop); // cross lib jmp detected. + tmp = insertAssemblyAfter(firp,tmp,"pop "+reg); // restore ecx/r11. + bounds_end=tmp; + } + else + assert(0); // what? + + assert(bounds_start && bounds_end); + Instruction_t* jmp = addNewAssembly(firp, NULL, "jmp 0"); + jmp->setTarget(target); + bounds_end->setFallthrough(jmp); + return bounds_start; +} + + +Instruction_t* Xeon_relocs::GenerateOutOfRangeHandler(void) +{ + string reg="ecx"; + if(firp->getArchitectureBitWidth()==64) + reg="r11"; + unsigned ptrsize=firp->getArchitectureBitWidth()/8; + + // find some scoops we'll need + DataScoop_t* dynstr_scoop=find_scoop(firp, ".dynstr"); + DataScoop_t* dispatch_scoop =find_scoop(firp, "zest_cfi_dispatch"); + + // if we can't find the cfi multimodule support, don't do multimodule protection + if(!dynstr_scoop || dynstr_scoop->getContents().find("zestcfi") == string::npos) + { + Instruction_t *jmp=addNewAssembly(firp, NULL, "jmp "+reg); // jmp ecx/r11 + return jmp; + } + + // if it was transformed with multimodule support, all these scoops better exist. + assert(dispatch_scoop); + + + // for now, just do the simple thing of calling zest_cfi_dispatch to check if the transfer is allowed. + // if the function returns, then the transfer is OK, and we should cache it. + // again, for now, just allow the xfer. + if(ptrsize==8) + { + // call <pc-6> is "call 0" in pcrel-ness. we'll hang a reloc off this to indicate + // which scoop it should really go to. + char jmp_neg6[]="\xff\x25\xfa\xff\xff\xff"; + string jmp_neg6_str(jmp_neg6,sizeof(jmp_neg6)-1); + + auto dispatchjmp=addNewDataBits(firp, NULL, jmp_neg6_str); // jmp zest_cfi_dispatch with r11==target + auto dispatchjmp_reloc=firp->addNewRelocation(dispatchjmp, 0, "pcrel", dispatch_scoop); + (void)dispatchjmp_reloc; // just giving to the IR + + + // need to update the calls to use pcrel addressing + return dispatchjmp; + } + else if(ptrsize==4) + { + // fixme later. + assert(0); + } + else + assert(0); +} + + +extern "C" +Zipr_SDK::ZiprPluginInterface_t* GetPluginInterface( + Zipr_SDK::Zipr_t* zipr_object) +{ + Zipr_SDK::MemorySpace_t *p_ms=zipr_object->getMemorySpace(); + IRDB_SDK::FileIR_t *p_firp=zipr_object->getFileIR(); + Zipr_SDK::InstructionLocationMap_t *p_fil=zipr_object->getLocationMap(); + + return new Xeon_relocs(p_ms,p_firp,p_fil,zipr_object); +} diff --git a/zipr_xeon_plugin/Xeon_relocs.hpp b/zipr_xeon_plugin/Xeon_relocs.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ccb233353a122f997a87e1ccba0325d008d8df08 --- /dev/null +++ b/zipr_xeon_plugin/Xeon_relocs.hpp @@ -0,0 +1,97 @@ +#ifndef Xeon_relocs_hpp +#define Xeon_relocs_hpp + +#include <irdb-core> +#include <irdb-transform> +#include <zipr-sdk> +#include <dlfcn.h> + +using namespace Zipr_SDK; +using namespace IRDB_SDK; + +class Xeon_relocs : public ZiprPluginInterface_t +{ + public: + // The plugin constructor + Xeon_relocs(MemorySpace_t *p_ms, + FileIR_t *p_firp, + InstructionLocationMap_t *p_fil, + Zipr_t *p_zipr) : + firp(p_firp), + m_memory_space(p_ms), + final_insn_locations(p_fil), + m_zipr(p_zipr), + m_on(false) + { + if(p_firp==NULL) + return; + // optimization + // find out if slow path insns are even needed! + if(p_firp!=NULL) + { + for( auto it=firp->getInstructions().begin(); it!=firp->getInstructions().end(); ++it) + { + const auto insn=*it; + if(FindRelocation(insn, "nonce_miscomp_path")) + { + m_on=true; + break; + } + } + } + if(m_on) + cout<<"Xeon_relocs plugin: Turning plugin on."<<endl; + + auto global=p_zipr->getOptionsManager()->getNamespace("global"); + m_verbose=global->getBooleanOption("verbose"); + + + } + + virtual void doPinningEnd() override + { + if(!m_on) return; + cout<<"Xeon_relocs: Inserting bounds check."<<endl; + AddDynLibCheckCode(); + } + virtual void doCallbackLinkingEnd() override + { + if(!m_on) return; + cout<<"Xeon_relocs: Updating bounds check" <<endl; + UpdateAddrRanges(); + } + // virtual ZiprOptionsNamespace_t *registerOptions(ZiprOptionsNamespace_t *); + virtual bool willPluginPlop(Instruction_t*); + virtual RangeAddress_t plopDollopEntry(DollopEntry_t *, + RangeAddress_t &, + RangeAddress_t &, + size_t, + bool &)override ; + + size_t getDollopEntryOpeningSize(DollopEntry_t*)override ; + size_t getDollopEntryClosingSize(DollopEntry_t*)override ; + virtual string toString() override { return "Xeon_relocs"; } + + private: //methods + bool IsExeNonceRelocation(Relocation_t& reloc); + Relocation_t* FindExeNonceRelocation(Instruction_t* insn); + Relocation_t* FindRelocation(Instruction_t* insn, std::string type); + Instruction_t* GenerateOutOfRangeHandler(void); + void UpdateAddrRanges(); + void AddDynLibCheckCode(); + Instruction_t* GetDynLibCheckCode(std::string reg, Instruction_t* fall_through); + + private: //data + FileIR_t* firp; + MemorySpace_t *m_memory_space; + InstructionLocationMap_t *final_insn_locations; + Zipr_t *m_zipr; + ZiprBooleanOption_t *m_verbose; + bool m_on; + // bounds check updates + InstructionSet_t max_addr_update; + InstructionSet_t min_addr_update; +}; + +#endif +