123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* 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). *)(* *)(**************************************************************************)openCil_typesopenOptionsmoduleList=Extends.ListmoduleTyp=Extends.TypmoduleBuild=Cil_builder.Pure(* Types of variadic parameter and argument *)letvpar_typattr=TPtr(TPtr(TVoid[],[Attr("const",[])]),attr)letvpar_name="__va_params"letvpar=(vpar_name,vpar_typ[],[])(* Translation of variadic types (not deeply) *)lettranslate_type=function|TFun(ret_typ,args,is_variadic,attributes)->letnew_args=ifis_variadicthenletng_args,g_args=Cil.argsToPairOfListsargsinSome(ng_args@[vpar]@g_args)elseargsinTFun(ret_typ,new_args,false,attributes)|TBuiltin_va_listattr->vpar_typattr|typ->typ(* Adding the vpar parameter to variadic functions *)letadd_vparvi=letformals=Cil.getFormalsDeclviinletn_formals,g_formals=List.partition(funv->notv.vghost)formalsin(* Add the vpar formal once *)ifnot(List.exists(funvi->vi.vname=vpar_name)formals)thenbegin(* Register the new formal *)letnew_formal=Cil.makeFormalsVarDeclvparinletnew_formals=n_formals@[new_formal]@g_formalsinCil.unsafeSetFormalsDeclvinew_formalsend(* Translation of va_* builtins *)lettranslate_va_builtincallerinst=letvi,args,loc=matchinstwith|Call(_,{enode=Lval(Varvi,_)},args,loc)->vi,args,loc|_->assertfalseinlettranslate_va_start()=letva_list=matchargswith|[{enode=Lvalva_list}]->va_list|_->Self.abort"Unexpected arguments to va_start"andvarg=tryExtlib.last(Cil.getFormalsDeclcaller.svar)withInvalid_argument_->Self.abort"Using va_start macro in a function which is not variadic."in[Set(va_list,Cil.evar~locvarg,loc)]inlettranslate_va_copy()=letdest,src=matchargswith|[{enode=Lvaldest};src]->dest,src|_->Self.abort"Unexpected arguments to va_copy"in[Set(dest,src,loc)]inlettranslate_va_arg()=letva_list,ty,lv=matchargswith|[{enode=Lvalva_list};{enode=SizeOfty};{enode=CastE(_,{enode=AddrOflv})}]->va_list,ty,lv|_->Self.abort"Unexpected arguments to va_arg"in(* Check validity of type *)ifCil.isIntegralTypetythenbeginletpromoted_type=Cil.integralPromotiontyinifpromoted_type<>tythenSelf.warning~current:true~wkey:wkey_typing"Wrong type argument in va_start: %a is promoted to %a when used \
in the variadic part of the arguments. (You should pass %a to \
va_start)"Printer.pp_typtyPrinter.pp_typpromoted_typePrinter.pp_typpromoted_typeend;(* Build the replacing instruction *)letva_list,ty,lv=Build.(of_lvalva_list,of_ctypty,of_lvallv)inList.map(Build.cil_instr~loc)Build.([lv:=mem(cast(ptrty)(memva_list));va_list+=of_int1])inbeginmatchvi.vnamewith|"__builtin_va_start"->translate_va_start()|"__builtin_va_copy"->translate_va_copy()|"__builtin_va_arg"->translate_va_arg()|"__builtin_va_end"->[](* No need to do anything for va_end *)|_->assertfalseend(* Translation of calls to variadic functions *)lettranslate_call~buildercalleepars=letmoduleBuild=(valbuilder:Builder.S)inBuild.start_translation();(* Log translation *)Self.result~current:true~level:2"Generic translation of call to variadic function.";(* Split params into static, variadic and ghost part *)letng_params,g_params=Typ.ghost_partitioned_params(Cil.typeOfcallee)inletstatic_size=List.lengthng_params-1inlets_exps,r_exps=List.breakstatic_sizeparsinletvariadic_size=(List.lengthr_exps)-(List.lengthg_params)inletv_exps,g_exps=List.breakvariadic_sizer_expsin(* Create temporary variables to hold parameters *)letadd_varie=letname="__va_arg"^string_of_intiinBuild.(local'(Cil.typeOfe)name~init:(of_expe))inletvis=List.mapiadd_varv_expsin(* Build an array to store addresses *)letinit=matchviswith(* C standard forbids arrays of size 0 *)|[]->[Build.(of_init(Cil.makeZeroInit~locCil.voidPtrType))]|l->List.mapBuild.addrlinletty=Build.(array(ptrvoid)~size:(List.lengthinit))inletvargs=Build.(localty"__va_args"~init)in(* Translate the call *)letnew_arg=Build.(cast'(vpar_typ[])(addrvargs))inletnew_args=Build.(of_exp_lists_exps@[new_arg]@of_exp_listg_exps)inBuild.(translated_call(of_expcallee)new_args)