123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357(* Yoann Padioleau
*
* Copyright (C) 2014 Facebook
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library 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 file
* license.txt for more details.
*)openCommon(*****************************************************************************)(* Prelude *)(*****************************************************************************)(*
* See also prolog_code.ml!
*
* datalog engines:
* - toy datalog using lua
* - bddbddb, a scalabe engine!
* - TODO: pydatalog, embedded DSL in python that can import data from
* SQL
* - ciao? xsb?
* - http://www.learndatalogtoday.org/ and datomic.com
*
* TODO: https://yanniss.github.io/points-to-tutorial15.pdf
*)(*****************************************************************************)(* Types *)(*****************************************************************************)(* for locals, but also right now for fields, globals, constants, enum, ... *)typevar=stringtypefunc=stringtypefld=string(* _cst_xxx, _str_line_xxx, _malloc_in_xxx_line, ... *)typeheap=string(* _in_xxx_line_xxx_col_xxx *)typecallsite=string(* mimics datalog_code.dl top comment *)typefact=|PointToofvar*heap|Assignofvar*var|AssignContentofvar*var|AssignAddressofvar*var|AssignDerefofvar*var|AssignLoadFieldofvar*var*fld|AssignStoreFieldofvar*fld*var|AssignFieldAddressofvar*var*fld|AssignArrayEltofvar*var|AssignArrayDerefofvar*var|AssignArrayElementAddressofvar*var|Parameteroffunc*int*var|Returnoffunc*var(* ret_xxx convention *)|Argumentofcallsite*int*var|ReturnValueofcallsite*var|CallDirectofcallsite*func|CallIndirectofcallsite*var(*****************************************************************************)(* Meta *)(*****************************************************************************)(* see datalog_code.dl domain *)typevalue=|Vofvar|Foffld|Noffunc|Iofcallsite|Zofintletstring_of_value=function|Vx|Fx|Nx|Ix->x|Z_->raiseImpossibletype_rule=stringtype_meta_fact=string*valuelistletmeta_fact=function|PointTo(a,b)->"point_to",[Va;Vb;]|Assign(a,b)->"assign",[Va;Vb;]|AssignContent(a,b)->"assign_content",[Va;Vb;]|AssignAddress(a,b)->"assign_address",[Va;Vb;]|AssignDeref(a,b)->"assign_deref",[Va;Vb;]|AssignLoadField(a,b,c)->"assign_load_field",[Va;Vb;Fc]|AssignStoreField(a,b,c)->"assign_store_field",[Va;Fb;Vc]|AssignFieldAddress(a,b,c)->"assign_field_address",[Va;Vb;Fc]|AssignArrayElt(a,b)->"assign_array_elt",[Va;Vb;]|AssignArrayDeref(a,b)->"assign_array_deref",[Va;Vb;]|AssignArrayElementAddress(a,b)->"assign_array_element_address",[Va;Vb;]|Parameter(a,b,c)->"parameter",[Na;Zb;Vc]|Return(a,b)->"return",[Na;Vb;]|Argument(a,b,c)->"argument",[Ia;Zb;Vc]|ReturnValue(a,b)->"call_ret",[Ia;Vb;]|CallDirect(a,b)->"call_direct",[Ia;Nb;]|CallIndirect(a,b)->"call_indirect",[Ia;Vb;](*****************************************************************************)(* Toy datalog *)(*****************************************************************************)letstring_of_factfact=letstr,xs=meta_factfactinspf"%s(%s)"str(xs|>List.map(function|Vx|Fx|Nx|Ix->spf"'%s'"x|Zi->spf"%d"i)|>Common.join", ")(*****************************************************************************)(* Bddbddb *)(*****************************************************************************)(* "V", "F", ... *)type_domain=stringletdomain_of_value=function|V_->"V"|F_->"F"|N_->"N"|I_->"I"|Z_->"Z"type_idx=(string(* metadomain*),valueCommon.hashset)Hashtbl.tletbddbddb_of_factsfactsdir=letmetas=facts|>List.mapmeta_factinlethvalues=Hashtbl.create6inlethrules=Hashtbl.create30in(* build sets *)metas|>List.iter(fun(arule,xs)->letlistref=tryHashtbl.findhrulesarulewithNot_found->letaref=ref[]inHashtbl.addhrulesarulearef;arefinlistref:=xs::!listref;xs|>List.iter(funv->letadd_vv=letdomain=domain_of_valuevinlethdomain=tryHashtbl.findhvaluesdomainwithNot_found->leth=Hashtbl.create10001inHashtbl.addhvaluesdomainh;hinHashtbl.replacehdomainvtrue;inadd_vv;(* for field_to_var and var_to_func *)(matchvwith|Fs->add_v(Vs)|Ns->add_v(Vs)|_->())));(* now build integer indexes *)letdomains_idx=hvalues|>Common.hash_to_list|>List.map(fun(domain,hdomain)->letconv=hdomain|>Common.hashset_to_list|>Common.index_list_0indomain,(conv,conv|>Common.hash_of_list))inCommon.command2(spf"rm -f %s/*"dir);(* generate .map *)domains_idx|>List.iter(fun(domain,(map,_idx))->ifdomain<>"Z"thenbeginletfile=Filename.concatdir(domain^".map")inCommon.with_open_outfilefile(fun(pr_no_nl,_chan)->letprs=pr_no_nl(s^"\n")inmap|>List.iter(fun(v,_int)->pr(string_of_valuev)))end);(* generate .tuples *)hrules|>Common.hash_to_list|>List.iter(fun(arule,xxs)->letarule=matcharulewith|"point_to"->"point_to0"|"assign"->"assign0"|s->sinletfile=Filename.concatdir(arule^".tuples")inCommon.with_open_outfilefile(fun(pr_no_nl,_chan)->letprs=pr_no_nl(s^"\n")in(* todo: header?? *)(match!xxswith|[]->()|xs::_xxs->lethcnt=Hashtbl.create6inpr(spf"# %s"(xs|>List.map(funv->letdomain=domain_of_valuevinletcnt=tryHashtbl.findhcntdomainwithNot_found->letcnt=ref0inHashtbl.addhcntdomaincnt;cntinleti=!cntinincrcnt;(* less: size? *)spf"%s%d:18"domaini)|>Common.join" ")));!xxs|>List.iter(funxs->letints=xs|>List.map(funv->leti=matchvwith|Zi->i|_->letdomain=domain_of_valuevinlet(_,hdomainconv)=List.assocdomaindomains_idxinHashtbl.findhdomainconvvini)inpr(ints|>List.mapi_to_s|>Common.join" "));));(* generate extra .tuples *)letfvals=tryList.assoc"F"domains_idx|>fstwithNot_found->[]inletnvals=tryList.assoc"N"domains_idx|>fstwithNot_found->[]inlet(_vvals,vconv)=List.assoc"V"domains_idxinletarule="field_to_var"inletfile=Filename.concatdir(arule^".tuples")inCommon.with_open_outfilefile(fun(pr_no_nl,_chan)->letprs=pr_no_nl(s^"\n")inpr"# F0:18 V0:18";fvals|>List.iter(fun(fld,idx)->matchfldwith|Fs->letv=Vsinletidx2=Hashtbl.findvconvvinpr(spf"%d %d"idxidx2)|_->pr2_gen(fld,idx);raiseImpossible));letarule="var_to_func"inletfile=Filename.concatdir(arule^".tuples")inCommon.with_open_outfilefile(fun(pr_no_nl,_chan)->letprs=pr_no_nl(s^"\n")inpr"# V0:18 N0:18";nvals|>List.iter(fun(n,idx)->matchnwith|Ns->letv=Vsinletidx2=Hashtbl.findvconvvin(* subtle, different order than for field_to_var, idx2 before *)pr(spf"%d %d"idx2idx)|_->pr2_gen(n,idx);raiseImpossible));()letbddbddb_explain_tuplesfile=let(d,b,_e)=Common2.dbe_of_filenamefileinletdst=Common2.filename_of_dbe(d,b,"explain")inCommon.with_open_outfiledst(fun(pr_no_nl,_chan)->letprs=pr_no_nl(s^"\n")inletxs=Common.catfilein(matchxswith|header::xs->ifheader=~"# \\(.*\\)"thenlets=Common.matched1headerinletflds=Common.split"[ \t]"sinletfld_domains=flds|>List.map(funs->ifs=~"\\([A-Z]\\)[0-9]?:"thenCommon.matched1selsefailwith(spf"could not find header in %s"file))inletfld_translates=fld_domains|>List.map(funs->letmapfile=Common2.filename_of_dbe(d,s,"map")inCommon.catmapfile|>Array.of_list)inxs|>List.iter(funs->letvs=Common.split"[ \t]"s|>List.maps_to_iinletargs=Common2.zipvsfld_translates|>List.map(fun(i,arr)->arr.(i))inpr(spf"%s(%s)"b(Common.join", "args)))elsefailwith(spf"could not find header in %s"file)|[]->pr2(spf"empty file %s"file)));dst