123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2019 The MOPSA Project. *)(* *)(* This program is free software: 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, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program 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. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(** Base storage of scalar values. *)openMopsaopenUniversal.AstopenAst(** Kinds of bases *)typebase_kind=|Varofvar(** Stack variable *)|Addrofaddr(** Heap address *)|Stringofstring*c_character_kind*typ(** String literal, with character kind and type of character *)(** Bases *)typebase={base_kind:base_kind;base_valid:bool;base_invalidation_range:rangeoption;}letpp_base_kindfmt=function|Varv->pp_varfmtv|Addr(a)->pp_addrfmta|String(s,k,_)->Format.fprintffmt"%a\"%s\""Pp.pp_character_kindk(String.escapeds)letpp_basefmtb=Format.fprintffmt"%s%a"(ifb.base_validthen""else"✗")pp_base_kindb.base_kindletcompare_base_kindbb'=matchb,b'with|Varv,Varv'->compare_varvv'|Addra,Addra'->compare_addraa'|String(s,k,t),String(s',k',t')->Compare.triplecomparecomparecompare_typ(s,k,t)(s',k',t')|_->comparebb'letcompare_basebb'=Compare.compose[(fun()->compare_base_kindb.base_kindb'.base_kind);(fun()->compareb.base_validb'.base_valid);(fun()->Compare.optioncompare_rangeb.base_invalidation_rangeb'.base_invalidation_range)]letmk_base?(valid=true)?(invalidation_range=None)kind={base_kind=kind;base_valid=valid;base_invalidation_range=invalidation_range;}letmk_var_base?(valid=true)?(invalidation_range=None)v=mk_base(Varv)~valid~invalidation_rangeletmk_addr_base?(valid=true)?(invalidation_range=None)a=mk_base(Addra)~valid~invalidation_rangeletmk_string_base?(kind=C_char_ascii)?(typ=(T_c_integerC_unsigned_char))s=mk_base(String(s,kind,typ))~valid:true~invalidation_range:Noneletbase_kind_uniq_nameb=matchbwith|Varv->v.vname|Addra->addr_uniq_namea|String(s,_,_)->sletbase_uniq_nameb=letname=base_kind_uniq_nameb.base_kindinifb.base_validthennameelse"✗"^nameletbase_sizebflow=matchb.base_kindwith|Varv->sizeof_typev.vtypflow|String(s,_,_)->Z.of_int@@String.lengths|Addra->panic~loc:__LOC__"base_size: addresses not supported"letbase_modeb=matchb.base_kindwith|Varv->v.vmode|Addra->a.addr_mode|String_->STRONGtypeaddr_opacity=|NotOpaque|OpaqueFromofint(* offset *)letaddr_opaque_chain:(addr_kind->addr_opacity)ref=ref(funak->NotOpaque)letaddr_opaquea=!addr_opaque_chainaletregister_addr_opaquef=addr_opaque_chain:=f!addr_opaque_chainletis_base_readonlyb=matchb.base_kindwith|String_->true|_->falseletis_var_base_expre=matchekindewith|E_var(v,_)->is_c_typev.vtyp|_->falseletis_addr_base_expre=matchekindewith|E_addr_->true|_->falseletis_base_expre=matchekindewith|E_var(v,_)->is_c_typev.vtyp|E_addr_->true|E_constant(C_c_string_)->true|_->falseletexpr_to_basee=matchekindewith|E_var(v,_)->mk_var_basev|E_addr(a,_)->mk_addr_basea|E_constant(C_c_string(s,_))->mk_string_bases|_->assertfalseletbase_to_exprbrange=matchb.base_kindwith|Varv->mk_varvrange|Addra->mk_addrarange~etyp:(T_c_pointervoid)|String(s,c,_)->mk_c_strings~kind:crange(** Evaluate the size of a base in bytes *)leteval_base_size?(route=toplevel)baserange(man:('a,'t)man)flow=matchbase.base_kindwith|Varvarwhenis_c_variable_length_array_typevar.vtyp||is_c_no_length_array_typevar.vtyp->letbytes_expr=mk_expr(Stubs.Ast.E_stub_builtin_call(BYTES,[mk_varvarrange]))range~etyp:ulinman.eval~routebytes_exprflow~translate:"Universal"|Varvar->Cases.singleton(mk_z(sizeof_typevar.vtypflow)range)flow|String(str,_,t)->(* length of the terminal 0 character *)letchar_len=Z.to_int(sizeof_typetflow)inCases.singleton(mk_int(String.lengthstr+char_len)range)flow|Addraddr->letbytes_expr=mk_expr(Stubs.Ast.E_stub_builtin_call(BYTES,[mk_addraddrrange]))range~etyp:ulin(* XXX for backward compatibility, the size is converted to Universal, but maybe it should be a C expression? *)man.eval~routebytes_exprflow~translate:"Universal"moduleBase=structtypet=baseletcompare=compare_baseletprint=unformatpp_baseendmoduleBaseSet=SetExt.Make(Base)moduleBaseMap=MapExt.Make(Base)letmk_lvalbaseoffsettypmoderange=letbase_addr=matchbase.base_kindwith|Varv->mk_c_address_of(mk_varv~moderange)range|Addra->mk_addr~modearange|String(s,kind,t)->mk_c_strings~kindrangeinletaddr=mk_c_cast(add(mk_c_castbase_addr(T_c_pointers8)range)offset~typ:(T_c_pointers8)range)(T_c_pointertyp)rangeinmk_c_derefaddrrange