123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344(**************************************************************************)(* This file is part of BINSEC. *)(* *)(* Copyright (C) 2016-2024 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)moduleBv=Sexpr.BvmoduleExpr=Sexpr.ExprmoduleStore=Sexpr.StoremoduleMemory=Sexpr.MemorymoduleStTbl=Sexpr.StTblmoduleBvTbl=Sexpr.BvTblmoduleAxTbl=Sexpr.AxTblmoduleNiTbl=Basic_types.Int.HtblmoduleBiMap=Basic_types.BigInt.Mapletbyte_size=Natural.to_intBasic_types.Constants.bytesizemoduletypeCONTEXT=sigtypebltypebvtypeaxvaladdr_space:intvalvisit_bl:Expr.t->blvalvisit_bv:Expr.t->bvvalvisit_ax:Memory.t->axvaliter_free_variables:(string->Expr.t->unit)->unitvaliter_free_arrays:(string->Memory.t->unit)->unitvalget:Expr.t->bvendtype('bl,'bv,'ax)context=(moduleCONTEXTwithtypebl='blandtypebv='bvandtypeax='ax)moduletypeAXHOOK=sigvalvisit_load:([`Mem],string,Memory.t)Term.t->unitvalvisit_ax:Memory.t->unitendmoduleContext(H:AXHOOK)(S:Libsolver.S):CONTEXTwithtypebl=S.Bl.tandtypebv=S.Bv.tandtypeax=S.Ax.t=structopenStypebl=Bl.ttypebv=Bv.ttypeax=Ax.tletfvariables=StTbl.create16letfarrays=StTbl.create4letbl_cons=BvTbl.create128letbv_cons=BvTbl.create128letax_cons=AxTbl.create64letaddr_space=Kernel_options.Machine.word_size()letarray_sort=Ax.sort~idx:addr_spacebyte_sizeletvisit_select=letreciterlenconcatindexarrayres=iflen=0thenreselseiter(len-1)concat(Bv.succindex)array(concat(Ax.selectarrayindex)res)infunlendirindexarray->letconcat=matchdirwith|Machine.LittleEndian->Bv.append|Machine.BigEndian->Fun.flipBv.appendiniter(len-1)concat(Bv.succindex)array(Ax.selectarrayindex)letrecunroll_storearrayindexxs=ifs=8thenAx.storearrayindexxelseunroll_store(Ax.storearrayindex(Bv.extract~hi:7~lo:0x))(Bv.succindex)(Bv.extract~hi:(s-1)~lo:8x)(s-8)letrecvisit_blbl=tryBvTbl.findbl_consblwithNot_found->lete=matchblwith|Cstbv->ifTerm.Bv.is_zerobvthenBl.botelseBl.top|Load_(* cannot be a bl<1> *)->assertfalse|Unary{f=Not;x;_}->Bl.lognot(visit_blx)|Binary{f=And;x;y;_}->Bl.logand(visit_blx)(visit_bly)|Binary{f=Or;x;y;_}->Bl.logor(visit_blx)(visit_bly)|Binary{f=Xor;x;y;_}->Bl.logxor(visit_blx)(visit_bly)|Binary{f=Eq;x;y;_}->Bv.equal(visit_bvx)(visit_bvy)|Binary{f=Diff;x;y;_}->Bv.diff(visit_bvx)(visit_bvy)|Binary{f=Uge;x;y;_}->Bv.uge(visit_bvx)(visit_bvy)|Binary{f=Ule;x;y;_}->Bv.ule(visit_bvx)(visit_bvy)|Binary{f=Ugt;x;y;_}->Bv.ugt(visit_bvx)(visit_bvy)|Binary{f=Ult;x;y;_}->Bv.ult(visit_bvx)(visit_bvy)|Binary{f=Sge;x;y;_}->Bv.sge(visit_bvx)(visit_bvy)|Binary{f=Sle;x;y;_}->Bv.sle(visit_bvx)(visit_bvy)|Binary{f=Sgt;x;y;_}->Bv.sgt(visit_bvx)(visit_bvy)|Binary{f=Slt;x;y;_}->Bv.slt(visit_bvx)(visit_bvy)|Ite{c;t;e;_}->Bl.ite(visit_blc)(visit_blt)(visit_ble)|Var_|Unary_|Binary_->Bv.to_bl(visit_bvbl)inBvTbl.addbl_consble;eandvisit_bvbv=tryBvTbl.findbv_consbvwithNot_found->lete=matchbvwith|Var{name;size;_}->StTbl.addfvariablesnamebv;Bv.constsizename|Load{len;dir;addr;label;_}->letindex=visit_bvaddrandarray=visit_axlabelinH.visit_load(Term.to_mem_exnbv);visit_selectlendirindexarray|Cstbv->Bv.value(Bitvector.size_ofbv)(Bitvector.value_ofbv)|Unary{f=Not;x;_}->Bv.lognot(visit_bvx)|Unary{f=Minus;x;_}->Bv.neg(visit_bvx)|Unary{f=Uextn;x;_}->Bv.uextn(visit_bvx)|Unary{f=Sextn;x;_}->Bv.sextn(visit_bvx)|Unary{f=Restrict{lo;hi};x;_}->Bv.extract~hi~lo(visit_bvx)|Binary{f=Plus;x;y;_}->Bv.add(visit_bvx)(visit_bvy)|Binary{f=Minus;x;y;_}->Bv.sub(visit_bvx)(visit_bvy)|Binary{f=Mul;x;y;_}->Bv.mul(visit_bvx)(visit_bvy)|Binary{f=Udiv;x;y;_}->Bv.udiv(visit_bvx)(visit_bvy)|Binary{f=Sdiv;x;y;_}->Bv.sdiv(visit_bvx)(visit_bvy)|Binary{f=Umod;x;y;_}->Bv.umod(visit_bvx)(visit_bvy)|Binary{f=Smod;x;y;_}->Bv.smod(visit_bvx)(visit_bvy)|Binary{f=Or;x;y;_}->Bv.logor(visit_bvx)(visit_bvy)|Binary{f=And;x;y;_}->Bv.logand(visit_bvx)(visit_bvy)|Binary{f=Xor;x;y;_}->Bv.logxor(visit_bvx)(visit_bvy)|Binary{f=Concat;x;y;_}->Bv.append(visit_bvx)(visit_bvy)|Binary{f=Lsl;x;y;_}->Bv.shift_left(visit_bvx)(visit_bvy)|Binary{f=Lsr;x;y;_}->Bv.shift_right(visit_bvx)(visit_bvy)|Binary{f=Asr;x;y;_}->Bv.shift_right_signed(visit_bvx)(visit_bvy)|Binary{f=Rol;x;y;_}->Bv.rotate_left(visit_bvx)(visit_bvy)|Binary{f=Ror;x;y;_}->Bv.rotate_right(visit_bvx)(visit_bvy)|Binary{f=Eq|Diff|Ule|Ult|Uge|Ugt|Sle|Slt|Sge|Sgt;_}->Bl.to_bv(visit_blbv)|Ite{c;t;e;_}->Bv.ite(visit_blc)(visit_bvt)(visit_bve)inBvTbl.addbv_consbve;eandvisit_ax(ax:Memory.t)=tryAxTbl.findax_consaxwithNot_found->leta=matchaxwith|Root->Ax.constarray_sortSuid.(to_stringzero)|Symbolname->StTbl.addfarraysnameax;Ax.constarray_sortname|Layer{addr;store;over;_}->letbase=visit_bvaddrandarray=visit_axoverinStore.fold_term(funivaluearray->lets=Expr.sizeofvalueinletx=visit_bvvalueandindex=Bv.addbase(Bv.valueaddr_spacei)inunroll_storearrayindexxs)arraystoreinH.visit_axax;AxTbl.addax_consaxa;aletiter_free_variablesf=StTbl.iterffvariablesletiter_free_arraysf=StTbl.iterffarraysletgete=BvTbl.findbv_conseendmoduleNoHook=structletvisit_load_=()letvisit_ax_=()endmoduleMake(F:Libsolver.F)=structmoduleOpen():Solver.S=structmoduleSolver=F()moduleContext=Context(NoHook)(Solver)letvisit_formula_=()letiter_free_variables=Context.iter_free_variablesletiter_free_arrays=Context.iter_free_arraysletassert_formulabl=Solver.assert_formula(Context.visit_blbl)letassert_distinctxy=Solver.assert_formula(Solver.Bv.diff(Context.visit_bvx)(Context.visit_bvy))letcheck_sat=Solver.check_satletcheck_sat_assuming?timeoutbl=Solver.check_sat_assuming?timeout(Context.visit_blbl)letget_valuebv=Solver.get_bv_value(Context.visit_bvbv)letfold_array_valuesfarx=Solver.fold_ax_valuesf(Context.visit_axar)xletpush=Solver.pushletpop=Solver.popletclose=Solver.closeendendmoduleBiTbl=Sexpr.BiTblmoduleSafeArray(F:Libsolver.F)=struct(* Some SMT solvers use a default value when they build array models.
Yet, the default value is not necessarily handled by the 'fold_ax_values'
function.
Moreover, the default value conflicts with the lazy initialization of
large segments of memory because, either we ignore it and thus, we can
miss an address that is constrained but share the same value than default
one, either we will have to check for all initialized addresses -- that
is what lazy initialization tries to avoid.
This module proposes an alternative way to query the array models based
on the one used in 'Smt2_solver'.
*)moduleOpen():Solver.S=structmoduleSolver=F()typeaccess=SelectofExpr.t*int|StoreofExpr.t*intletax_root:Memory.tAxTbl.t=AxTbl.create64letordered_mem:accessQueue.tAxTbl.t=AxTbl.create4moduleHook=structletvisit_load(Load{len;addr;label;_}:([`Mem],string,Memory.t)Term.t)=letroot=AxTbl.findax_rootlabelinletordered_mem=AxTbl.findordered_memrootinQueue.push(Select(addr,len))ordered_memletvisit_ax(ax:Memory.t)=matchaxwith|Root|Symbol_->AxTbl.addax_rootaxax;AxTbl.addordered_memax(Queue.create())|Layer{addr;store;over;_}->letroot=AxTbl.findax_rootoverinAxTbl.addax_rootaxroot;letordered_mem=AxTbl.findordered_memrootinStore.iter_term(funibv->Queue.push(Store(Expr.addzaddri,Expr.sizeofbvlsr3))ordered_mem)storeendmoduleContext=Context(Hook)(Solver)letvisit_formula_=()letiter_free_variables=Context.iter_free_variablesletiter_free_arrays=Context.iter_free_arraysletassert_formulabl=Solver.assert_formula(Context.visit_blbl)letassert_distinctxy=Solver.assert_formula(Solver.Bv.diff(Context.visit_bvx)(Context.visit_bvy))letcheck_sat=Solver.check_satletcheck_sat_assuming?timeoutbl=Solver.check_sat_assuming?timeout(Context.visit_blbl)letget_valuebv=Solver.get_bv_value(Context.visit_bvbv)letfold_array_valuesfarx=matchAxTbl.findordered_memarwith|exceptionNot_found->x|history->ifQueue.is_emptyhistorythenxelseletdirty=BiTbl.create(Queue.lengthhistory)inQueue.fold(funxaccess->matchaccesswith|Select(index,len)->letindex=get_valueindexinletrecfoldindexlenx=iflen=0thenxelseifBiTbl.memdirtyindexthenfold(Z.succindex)(len-1)xelseletk=get_value(Expr.load1LittleEndian(Expr.constant(Bitvector.createindexContext.addr_space))ar)infold(Z.succindex)(len-1)(findexkx)infoldindexlenx|Store(index,len)->letindex=get_valueindexinletrecloopindexlen=iflen<>0then(BiTbl.replacedirtyindex();loop(Z.succindex)(len-1))inloopindexlen;x)xhistoryletpush=Solver.pushletpop=Solver.popletclose=Solver.closeendend