1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** C front-end to translate parser AST into MOPSA AST *)openMopsa_c_parseropenC_ASTopenMopsaopenUniversal.AstopenStubs.AstopenAstletdebugfmt=Debug.debug~channel:"c.frontend"fmt(** {2 Command-line options} *)(** ======================== *)letopt_clang=ref[](** Extra options to pass to clang when parsing *)letopt_include_dirs=ref[](** List of include directories *)letopt_make_target=ref""(** Name of the target binary to analyze *)letopt_without_libc=reffalse(** Disable stubs of the standard library *)letopt_enable_cache=reftrue(** Enable the parser cache. *)letopt_warn_all=reffalse(** Display all compiler warnings *)letopt_use_stub=ref[](** Lists of functions that the body will be replaced by a stub *)letopt_library_only=reffalse(** Allow library-only targets in the .db files (used for multilanguage analysis) *)letopt_target_triple=ref""(** Target architecture triple to analyze for (host if left empty) *)letopt_stubs_files=ref[](** Additional stub files to parse *)letopt_ignored_translation_units=ref[](** List of translation units to ignore during linking *)letopt_save_preprocessed_file=ref""(** Where to save the preprocessed file *)letopt_store_project=reftrue(** Store project in memory for automated testcase reduction capabilities *)let()=register_language_option"c"{key="-I";category="C";doc=" add the directory to the search path for include files in C analysis";spec=String(ArgExt.set_string_list_lifteropt_include_dirs,ArgExt.empty);default="";};register_language_option"c"{key="-ccopt";category="C";doc=" pass the option to the Clang frontend";spec=String(ArgExt.set_string_list_lifteropt_clang,ArgExt.empty);default="";};register_language_option"c"{key="-make-target";category="C";doc=" binary target to analyze; used only when the Makefile builds multiple targets.";spec=Set_string(opt_make_target,ArgExt.empty);(* FIXME BASH *)default="";};register_language_option"c"{key="-without-libc";category="C";doc=" disable stubs of the standard C library.";spec=Setopt_without_libc;default="false";};register_language_option"c"{key="-disable-parser-cache";category="C";doc=" disable the cache of the Clang parser.";spec=Clearopt_enable_cache;default="unset";};register_language_option"c"{key="-Wall";category="C";doc=" display compiler warnings.";spec=Setopt_warn_all;default="unset";};register_language_option"c"{key="-use-stub";category="C";doc=" list of functions for which the stub is used instead of the declaration.";spec=String(ArgExt.set_string_list_lifteropt_use_stub,ArgExt.empty);default="";};register_language_option"c"{key="-library-only";category="C";doc=" allow library-only targets in the .db files (used for multilanguage analysis)";spec=Setopt_library_only;default="false";};register_language_option"c"{key="-additional-stubs";category="C";doc=" additional stubs file";spec=String(ArgExt.set_string_list_lifteropt_stubs_files,ArgExt.empty);default="";};register_language_option"c"{key="-target-triple";category="C";doc=" target architecture to analyze, as a triple (host if left empty).";spec=Set_string(opt_target_triple,ArgExt.empty);(* FIXME BASH completion *)default="";};register_language_option"c"{key="-c-ignore-translation-units";category="C";doc=" list of translation units ignored during linking.";spec=String(ArgExt.set_string_list_lifteropt_ignored_translation_units,ArgExt.empty);default="";};register_language_option"c"{key="-c-preprocess-and-exit";category="C";doc=" save the whole analyzed project into a single preprocessed file passed as argument to this option; then exit";spec=ArgExt.Set_string(opt_save_preprocessed_file,ArgExt.empty);default="";};register_language_option"c"{key="-c-no-project-storage";category="C";doc=" do not keep the full project in memory (used for automated testcase reduction, but may consume memory)";spec=ArgExt.Clearopt_store_project;default="";};()(** {2 Contexts} *)(** ============ *)typetype_space=TS_TYPEDEF|TS_RECORD|TS_ENUMtypectx={ctx_prj:C_AST.project;(* project descriptor *)ctx_fun:Ast.c_fundecStringMap.t;(* cache of functions of the project *)ctx_type:(type_space*string,typ)Hashtbl.t;(* cache the translation of all named types;
this is required for records defining recursive data-types
*)ctx_vars:(int*string,var*C_AST.variable)Hashtbl.t;(* cache of variables of the project *)ctx_macros:C_AST.macroStringMap.t;(* cache of macros of the project *)ctx_predicates:Mopsa_c_stubs_parser.Passes.Preprocessor.predicateStringMap.t;(* cache of stub predicates *)ctx_stubs:(string,Mopsa_c_stubs_parser.Cst.stub)Hashtbl.t;(* cache of stubs CST, used for resolving aliases *)ctx_enums:Z.tStringMap.t;(* cache of enum values of the project *)}letinput_files:stringlistref=ref[](** List of input files *)lettarget_info=refhost_target_info(** Target information used for parsing *)leto_prj:Mopsa_c_parser.C_AST.projectoptionref=refNone(** Saved project *)letfind_function_in_contextctxrange(f:C_AST.func)=tryStringMap.findf.func_unique_namectx.ctx_funwithNot_found->Exceptions.panic_atrange"Could not find function %s in context"f.func_unique_name(* Get the list of system headers encountered during parsing *)letget_parsed_system_headers(ctx:Clang_to_C.context):stringlist=letis_headerf=Filename.extensionf=".h"inletis_system_headerf=is_headerf&¬(List.memf!input_files)inList.filteris_system_header(Clang_to_C.get_parsed_filesctx)(* Get the list of all stub source files *)letget_all_stubs()=letreciterdir=ifnot(Sys.is_directorydir)then[]elseSys.readdirdir|>Array.fold_left(funaccf->letff=Filename.concatdirfinifSys.is_directoryfftheniterff@accelseff::acc)[]initer(Filename.concat(Params.Paths.get_lang_stubs_dir"c"())"libc")(* Find the stub of a given header file *)letfind_stubs_of_headerheaderstubs=letstubs_dir=Filename.concat(Params.Paths.get_lang_stubs_dir"c"())"libc"inletstubd_dir_len=String.lengthstubs_dirinList.filter(funstub->leth=Filename.chop_extensionstub^".h"inletrelative_h=String.subhstubd_dir_len(String.lengthh-stubd_dir_len)inletregexp=Str.regexp(".*"^relative_h^"$")inStr.string_matchregexpheader0)stubs(* Check if the source file is to be ignored *)letis_ignored_translation_unitfile=letn=String.lengthfileinList.exists(funfile'->letn'=String.lengthfile'inn>=n'&&(String.equalfile'(String.subfile(n-n')n')))!opt_ignored_translation_units(* Save prj into single preprocessed file at output_file. Returns the list of stub files that need to be used when analyzing the preprocessed file *)letsave_preprocessed_fileprjoutput_file=letoutch=open_outoutput_fileinlet()=C_print.print_project~verbose:falseoutchprjinlet()=close_outoutchin!opt_stubs_files@List.filter(funf->Filename.check_suffix(Filename.dirnamef)"share/mopsa/stubs/c/libc")prj.proj_files(** {2 Entry point} *)(** =============== *)letrecparse_program(files:stringlist)=letopenClang_parserinletopenClang_to_Cinif!opt_save_preprocessed_file<>""thenClang_to_C.simplify:=false;iffiles=[]thenpanic"no input file";(* let's initialize target from the option *)if!opt_target_triple<>""thentarget_info:=get_target_info({Clang_AST.empty_target_optionswithtarget_triple=!opt_target_triple});Mopsa_c_stubs_parser.Cst.target_info:=!target_info;letctx=Clang_to_C.create_context"project"!target_infoinletnb=List.lengthfilesininput_files:=[];let()=tryListExt.iteri(funifile->matchfile,Filename.extensionfilewith|_,(".c"|".h"|".i")->parse_file"clang"~nb:(i,nb)[]filefalsefalsectx|_,(".cpp"|".cc"|".c++")->parse_file"clang++"~nb:(i,nb)[]filefalsetruectx|_,".db"|".db",_->parse_dbfilectx|_,x->Exceptions.panic"unknown C extension %s"x)files;withExceptions.SyntaxErrorListes->panic"Parsing error raised:@.%a"(Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt"@.")(funfmt(range,msg)->Format.fprintffmt"%a: %s"pp_rangerangemsg))esinlet()=parse_stubsctx()inletprj=Clang_to_C.link_projectctxinif!opt_store_projecttheno_prj:=Someprj;let()=if!opt_save_preprocessed_file<>""thenletstub_files=save_preprocessed_fileprj!opt_save_preprocessed_fileinletppl=Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt" ")Format.pp_print_stringinlet()=warn"Preprocessed file generated to %s."!opt_save_preprocessed_fileinlet()=ifList.lengthstub_files>0thenwarn"If you want to run Mopsa on this file, do not forget to keep libc stubs (%a), e.g@\n%a"pplstub_filesppl(List.append(List.filter(funa->not@@List.memafiles&¬@@String.starts_with~prefix:"-make-target="a&¬@@String.starts_with~prefix:"-c-preprocess-and-exit="a)(Array.to_listSys.argv))(!opt_save_preprocessed_file::stub_files));inexit0in{prog_kind=from_projectprj;prog_range=mk_program_rangefiles;}andparse_db(dbfile:string)ctx:unit=ifnot(Sys.file_existsdbfile)thenpanic"file %s not found"dbfile;letopenClang_parserinletopenClang_to_CinletopenMopsa_build_dbinletdb=load_dbdbfileinletsrcs=if!opt_library_onlythenletlibs=get_librariesdbinletlib=ifList.lengthlibs=1thenList.hdlibselseiflibs=[]thenpanic"no library in database"elseif!opt_make_target=""thenpanic"a target is required in a multi-library Makefile@.Possible targets:@\n@[%a@]"(Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt"@\n")Format.pp_print_string)libselsetryfind_target!opt_make_targetlibswithNot_found->panic"library target %s not found"!opt_make_targetinget_library_sourcesdblibelseletexecs=get_executablesdbinletexec=(* No need for target selection if there is only one binary *)ifList.lengthexecs=1thenList.hdexecselseifexecs=[]thenpanic"no binary in database"elseif!opt_make_target=""thenpanic"a target is required in a multi-binary database, use the -make-target option.@\nPossible targets:@\n @[%a@]"(Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt"@\n")Format.pp_print_string)execselsetryfind_target!opt_make_targetexecswithNot_found->panic"binary target %s not found"!opt_make_targetinget_executable_sourcesdbexecinletnb=List.lengthsrcsininput_files:=[];letcwd=Sys.getcwd()inListExt.iteri(funisrc->matchsrc.source_kindwith|SOURCE_C|SOURCE_CXX->letcmd=ifsrc.source_kind=SOURCE_Cthen"clang"else"clang++"in(* parse file in the original compilation directory *)Sys.chdirsrc.source_cwd;parse_filecmd~nb:(i,nb)src.source_optssrc.source_path!opt_enable_cache(src.source_kind=SOURCE_CXX)ctx;|_->if!opt_warn_allthenwarn"ignoring file %s"src.source_path)srcs;(* make sure we get back to cwd in all cases *)Sys.chdircwdandparse_file(cmd:string)?nb?(stub=false)(opts:stringlist)(file:string)enable_cacheignorectx=ifnot(Sys.file_existsfile)thenpanic"file %s not found"file;debug"parsing file %s"file;(* clang does not like -MT and -MD options *)letopts=List.filter(funx->x!="-MT"&&x!="-MD")optsinletopts'=("-I"^(Paths.resolve_stub"c""mopsa"))::("-include"^"mopsa.h")::"-Wall"::(* recent versions of Clang promote warnings as errors
-> we revert them to warnings
*)"-Wno-error=incompatible-function-pointer-types"::"-Wno-error=implicit-function-declaration"::"-Qunused-arguments"::(List.map(fundir->"-I"^dir)!opt_include_dirs)@opts@!opt_clangininput_files:=file::!input_files;(* if adding a stub file, keep all static functions as they may be used
by stub annotations
*)C_parser.parse_filecmdfileopts'~target_options:!target_info.target_options!opt_warn_allenable_cachestub(ignore||is_ignored_translation_unitfile)ctx!opt_use_stubandparse_stubsctx()=(** Add Mopsa stubs *)parse_file~stub:true"clang"[](Params.Paths.resolve_stub"c""mopsa/mopsa.c")falsefalsectx;(** Add compiler builtins *)parse_file~stub:true"clang"[](Params.Paths.resolve_stub"c""mopsa/compiler_builtins.c")falsefalsectx;List.iter(funstub_file->tryparse_file~stub:true"clang"[](Filename.concat(Paths.get_stubs_dir())stub_file)falsefalsectx;withSyntaxErrorListes->panic"Parsing error raised:@.%a"(Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt"@.")(funfmt(range,msg)->Format.fprintffmt"%a: %s"pp_rangerangemsg))es)!opt_stubs_files;if!opt_without_libcthen()else(** Add stubs of the included headers *)letheaders=get_parsed_system_headersctxinifheaders=[]then()elseletmoduleSet=SetExt.StringSetinletall_stubs=get_all_stubs()inletreciterpast_headerspast_stubswq=ifSet.is_emptywqthen()elseleth=Set.choosewqinletwq'=Set.removehwqinifSet.memhpast_headerstheniterpast_headerspast_stubswq'else(* Get the stubs of the header *)letstubs=find_stubs_of_headerhall_stubsinletnew_headers=List.fold_left(funaccstub->ifSet.memstubpast_stubsthenaccelse(* Parse the stub and collect new parsed headers *)letbefore=Clang_to_C.get_parsed_filesctx|>Set.of_listinparse_file~stub:true"clang"[]stubfalsefalsectx;letafter=Clang_to_C.get_parsed_filesctx|>Set.of_listinSet.diffafterbefore|>Set.unionacc)Set.emptystubsiniter(Set.addhpast_headers)(Set.union(Set.of_liststubs)past_stubs)(Set.unionnew_headerswq)initerSet.emptySet.empty(Set.of_listheaders)andfrom_projectprj=(* Preliminary parsing of functions *)letfuncs_and_origins=StringMap.bindingsprj.proj_funcs|>List.mapsnd|>List.map(funf->from_functionf,f)inletfuncs=List.fold_left(funmap(f,o)->StringMap.addo.func_unique_namefmap)StringMap.emptyfuncs_and_originsin(* Prepare the parsing context *)letctx={ctx_fun=funcs;ctx_type=Hashtbl.create16;ctx_prj=prj;ctx_vars=Hashtbl.create16;ctx_macros=prj.proj_macros;ctx_predicates=from_stub_predicatesprj.proj_comments;ctx_enums=StringMap.fold(fun_enumacc->enum.enum_values|>List.fold_left(funaccv->StringMap.addv.enum_val_org_namev.enum_val_valueacc)acc)prj.proj_enumsStringMap.empty;ctx_stubs=Hashtbl.create16;}in(* Parse functions *)List.iter(fun(f,o)->debug"parsing function %s"o.func_org_name;f.c_func_uid<-o.func_uid;f.c_func_org_name<-o.func_org_name;f.c_func_unique_name<-o.func_unique_name;f.c_func_return<-from_typctxo.func_return;f.c_func_parameters<-Array.to_listo.func_parameters|>List.map(from_varctx);f.c_func_static_vars<-List.map(from_varctx)o.func_static_vars;f.c_func_local_vars<-List.map(from_varctx)o.func_local_vars;f.c_func_body<-from_body_optionctx(from_rangeo.func_range)o.func_body;(* Parse stub of functions that don't have a body or when they are
selected by the option '-use-stub' *)iff.c_func_body=None||List.memf.c_func_org_name!opt_use_stubthenf.c_func_stub<-from_stub_commentctxo)funcs_and_origins;(* Parse stub directives *)letdirectives=from_stub_directivesctxprj.proj_commentsinletglobals=StringMap.bindingsprj.proj_vars|>List.mapsnd|>List.map(funv->from_varctxv,from_var_initctxv)inAst.C_program{c_globals=globals;c_functions=StringMap.bindingsfuncs|>List.split|>snd;c_stub_directives=directives;}andfind_targettargettargets=tryList.find(funt->String.equal(Filename.basenamet)target)targetswithNot_found->letre_permissive=Str.regexp("^"^target^".*")inlett=List.find(funt->Str.string_matchre_permissive(Filename.basenamet)0)targetsinwarn"permissive search selected target %s (initial target: %s)"ttarget;t(** {2 functions} *)(** ============= *)andfrom_function=funfunc->{c_func_org_name=func.func_org_name;c_func_unique_name=func.func_unique_name;c_func_uid=func.func_uid;c_func_is_static=func.func_is_static;c_func_return=T_any;c_func_parameters=[];c_func_body=None;c_func_static_vars=[];c_func_local_vars=[];c_func_variadic=func.func_variadic;c_func_stub=None;c_func_range=from_rangefunc.func_range;c_func_name_range=from_rangefunc.func_name_range;}(** {2 Scope update} *)(** **************** *)andfrom_scope_updatectx(upd:C_AST.scope_update):Ast.c_scope_update={c_scope_var_added=List.map(from_varctx)upd.scope_var_added;c_scope_var_removed=List.map(from_varctx)upd.scope_var_removed;}(** {2 Statements} *)(** ============== *)andfrom_stmtctx((skind,range):C_AST.statement):stmt=letsrange=from_rangerangeinletstart_range=set_range_endsrange(get_range_startsrange)inletend_range=set_range_startsrange(get_range_endsrange)inletskind=matchskindwith|C_AST.S_local_declarationv->letvv=from_varctxvinletinit=from_init_optionctxv.var_initinAst.S_c_declaration(vv,init,from_var_scopectxv.var_kind)|C_AST.S_expressione->Universal.Ast.S_expression(from_exprctxe)|C_AST.S_blockblock->from_blockctxsrangeblock|>Framework.Core.Ast.Stmt.skind|C_AST.S_if(cond,body,orelse)->Universal.Ast.S_if(from_exprctxcond,from_blockctxend_rangebody,from_blockctxend_rangeorelse)|C_AST.S_while(cond,body)->Universal.Ast.S_while(from_exprctxcond,from_blockctxend_rangebody)|C_AST.S_do_while(body,cond)->S_c_do_while(from_blockctxend_rangebody,from_exprctxcond)|C_AST.S_for(init,test,increm,body)->S_c_for(from_blockctxstart_rangeinit,from_expr_optionctxtest,from_expr_optionctxincrem,from_blockctxend_rangebody)|C_AST.S_jump(C_AST.S_goto(label,upd))->S_c_goto(label,from_scope_updatectxupd)|C_AST.S_jump(C_AST.S_breakupd)->S_c_break(from_scope_updatectxupd)|C_AST.S_jump(C_AST.S_continueupd)->S_c_continue(from_scope_updatectxupd)|C_AST.S_jump(C_AST.S_return(None,upd))->S_c_return(None,from_scope_updatectxupd)|C_AST.S_jump(C_AST.S_return(Somee,upd))->S_c_return(Some(from_exprctxe),from_scope_updatectxupd)|C_AST.S_jump(C_AST.S_switch(cond,body))->Ast.S_c_switch(from_exprctxcond,from_blockctxend_rangebody)|C_AST.S_target(C_AST.S_case(es,upd))->letes'=List.map(from_exprctx)esinlettry_bundle_into_rangees=(* we can safely assume List.length es > 0 *)letefirst,estl=List.hdes,List.tlesinlettfirst=etypefirstinmatchekindefirstwith|E_constant(C_intfirst)->letrecprocessopaccl=matchlwith|[]->ifZ.equalaccfirstthenNoneelseif(Z.(first<=acc))thenSome(mk_int_general_interval(ItvUtils.IntBound.Finitefirst)(ItvUtils.IntBound.Finiteacc)efirst.erange)elseSome(mk_int_general_interval(ItvUtils.IntBound.Finiteacc)(ItvUtils.IntBound.Finitefirst)efirst.erange)|{ekind=E_constant(C_inth);etyp=th}::tlwhenZ.(h=(opaccone))&&compare_typthtfirst=0->processophtl|hd::tl->let()=debug"first=%a, acc=%s, hd=%a, skipping"pp_exprefirst(Z.to_stringacc)pp_exprhdinNoneinletoitv_increasing=processZ.addfirstestlinifoitv_increasing=NonethenprocessZ.subfirstestlelseoitv_increasing|_->Noneinbeginmatchtry_bundle_into_rangees'with|None->let()=debug"failed to bundle switch at range %a"pp_rangesrangeinS_c_switch_case(es',from_scope_updatectxupd)|Someitv->let()=debug"bundled switch at range %a into %a"pp_rangesrangepp_expritvinS_c_switch_case([itv],from_scope_updatectxupd)end|C_AST.S_target(C_AST.S_defaultupd)->S_c_switch_default(from_scope_updatectxupd)|C_AST.S_target(C_AST.S_labell)->Ast.S_c_labell|C_AST.S_asma->Ast.S_c_asm(C_print.string_of_statement(skind,range))in{skind;srange}andfrom_blockctxempty_range(block:C_AST.block):stmt=letblock_range=matchblock.blk_stmtswith|[]->empty_range|l->let_,first=ListExt.hdlinlet_,last=ListExt.lastlinmk_orig_range(get_range_start(from_rangefirst))(get_range_end(from_rangelast))inmk_block(List.map(from_stmtctx)block.blk_stmts)~vars:(List.map(from_varctx)block.blk_local_vars)block_rangeandfrom_body_option(ctx)empty_range(block:C_AST.blockoption):stmtoption=matchblockwith|None->None|Somestmtl->Some(from_blockctxempty_rangestmtl)(** {2 Expressions} *)(** =============== *)andfrom_exprctx((ekind,tc,range):C_AST.expr):expr=leterange=from_rangerangeinletetyp=from_typctxtcinletekind=matchekindwith|C_AST.E_integer_literaln->Universal.Ast.(E_constant(C_intn))|C_AST.E_float_literalf->Universal.Ast.(E_constant(C_float(float_of_stringf)))|C_AST.E_character_literal(c,k)->E_constant(Ast.C_c_character(c,from_character_kindk))|C_AST.E_string_literal(s,k)->Universal.Ast.(E_constant(C_c_string(s,from_character_kindk)))|C_AST.E_variablev->E_var(from_varctxv,None)|C_AST.E_functionf->Ast.E_c_function(find_function_in_contextctxerangef)|C_AST.E_call(f,args)->Universal.Ast.E_call(from_exprctxf,Array.map(from_exprctx)args|>Array.to_list)|C_AST.E_unary(op,e)->E_unop(from_unary_operatoropetyp,from_exprctxe)|C_AST.E_binary(op,e1,e2)->E_binop(from_binary_operatoropetyp,from_exprctxe1,from_exprctxe2)|C_AST.E_cast(e,C_AST.EXPLICIT)->Ast.E_c_cast(from_exprctxe,true)|C_AST.E_cast(e,C_AST.IMPLICIT)->Ast.E_c_cast(from_exprctxe,false)|C_AST.E_assign(lval,rval)->Ast.E_c_assign(from_exprctxlval,from_exprctxrval)|C_AST.E_address_of(e)->Ast.E_c_address_of(from_exprctxe)|C_AST.E_deref(p)->Ast.E_c_deref(from_exprctxp)|C_AST.E_array_subscript(a,i)->Ast.E_c_array_subscript(from_exprctxa,from_exprctxi)|C_AST.E_member_access(r,i,f)->Ast.E_c_member_access(from_exprctxr,i,f)|C_AST.E_arrow_access(r,i,f)->Ast.E_c_arrow_access(from_exprctxr,i,f)|C_AST.E_statements->Ast.E_c_statement(from_blockctxeranges)|C_AST.E_predefineds->Universal.Ast.(E_constant(C_c_string(s,Ast.C_char_ascii)))|C_AST.E_var_argse->Ast.E_c_var_args(from_exprctxe)|C_AST.E_conditional(cond,e1,e2)->Ast.E_c_conditional(from_exprctxcond,from_exprctxe1,from_exprctxe2)(* the following operations are removed from the AST by simplification
in the parser, before calling the frontend
*)|C_AST.E_binary_conditional(_,_)->Exceptions.panic_aterange"E_binary_conditional not supported"|C_AST.E_compound_assign(_,_,_,_,_)->Exceptions.panic_aterange"E_compound_assign not supported"|C_AST.E_comma(_,_)->Exceptions.panic_aterange"E_comma not supported"|C_AST.E_increment(_,_,_)->Exceptions.panic_aterange"E_increment not supported"|C_AST.E_compound_literal_->Exceptions.panic_aterange"E_compound_literal not supported"(* atomic builtins are stubbed in .h header and should not be encountered
here
*)|C_AST.E_atomic(op,e1,e2)->Ast.E_c_atomic(op,from_exprctxe1,from_exprctxe2)(* vector builtins are not supported
we display a warning but output an AST so that we can analyzer programs
which include headers and libraries with vector builtins but do
not actually use them
*)|C_AST.E_convert_vectore->if!opt_warn_allthenwarn_aterange"__builtin_convertvector not supported";(from_exprctxe).ekind|C_AST.E_vector_element(e,s)->if!opt_warn_allthenwarn_aterange"__builtin_vectorelement not supported";(from_exprctxe).ekind|C_AST.E_shuffle_vectora->if!opt_warn_allthenwarn_aterange"__builtin_shufflevector not supported";(from_exprctxa.(0)).ekindinmk_exprekinderange~etypandfrom_expr_optionctx:C_AST.exproption->exproption=function|None->None|Somee->Some(from_exprctxe)andfrom_unary_operatoropt=matchopwith|C_AST.NEG->O_minus|C_AST.BIT_NOT->O_bit_invert|C_AST.LOGICAL_NOT->O_log_notandfrom_binary_operatoropt=matchopwith|C_AST.O_arithmetic(C_AST.ADD)->O_plus|C_AST.O_arithmetic(C_AST.SUB)->O_minus|C_AST.O_arithmetic(C_AST.MUL)->O_mult|C_AST.O_arithmetic(C_AST.DIV)->O_div|C_AST.O_arithmetic(C_AST.MOD)->O_mod|C_AST.O_arithmetic(C_AST.LEFT_SHIFT)->O_bit_lshift|C_AST.O_arithmetic(C_AST.RIGHT_SHIFT)->O_bit_rshift|C_AST.O_arithmetic(C_AST.BIT_AND)->O_bit_and|C_AST.O_arithmetic(C_AST.BIT_OR)->O_bit_or|C_AST.O_arithmetic(C_AST.BIT_XOR)->O_bit_xor|C_AST.O_logical(C_AST.LESS)->O_lt|C_AST.O_logical(C_AST.LESS_EQUAL)->O_le|C_AST.O_logical(C_AST.GREATER)->O_gt|C_AST.O_logical(C_AST.GREATER_EQUAL)->O_ge|C_AST.O_logical(C_AST.EQUAL)->O_eq|C_AST.O_logical(C_AST.NOT_EQUAL)->O_ne|C_AST.O_logical(C_AST.LOGICAL_AND)->Ast.O_c_and|C_AST.O_logical(C_AST.LOGICAL_OR)->Ast.O_c_orandfrom_character_kind:C_AST.character_kind->Ast.c_character_kind=function|Clang_AST.Char_Ascii->Ast.C_char_ascii|Clang_AST.Char_Wide->Ast.C_char_wide|Clang_AST.Char_UTF8->Ast.C_char_utf8|Clang_AST.Char_UTF16->Ast.C_char_utf16|Clang_AST.Char_UTF32->Ast.C_char_utf8|Clang_AST.Char_Unevaluated->Ast.C_char_unevaluated(** {2 Variables} *)(** ============= *)andfrom_varctx(v:C_AST.variable):var=tryHashtbl.findctx.ctx_vars(v.var_uid,v.var_unique_name)|>fstwithNot_found->letv'=mkv(v.var_org_name^":"^(string_of_intv.var_uid))(V_cvar{cvar_orig_name=v.var_org_name;cvar_uniq_name=v.var_unique_name;cvar_scope=from_var_scopectxv.var_kind;cvar_range=from_rangev.var_range;cvar_uid=v.var_uid;cvar_before_stmts=List.map(from_stmtctx)v.var_before_stmts;cvar_after_stmts=List.map(from_stmtctx)v.var_after_stmts;})(from_typctxv.var_type)inletv''=patch_array_parametersv'inHashtbl.addctx.ctx_vars(v.var_uid,v.var_unique_name)(v'',v);v''(* Formal parameters of functions having array types should be
considered as pointers *)andpatch_array_parametersv=ifnot(is_c_array_typev.vtyp)||not(is_c_function_parameterv)thenvelselett=under_array_typev.vtypin{vwithvtyp=T_c_pointert}andfrom_var_scopectx=function|C_AST.Variable_global->Ast.Variable_global|Variable_extern->Variable_extern|Variable_localf->Variable_local(from_functionf)|C_AST.Variable_parameterf->Variable_parameter(from_functionf)|C_AST.Variable_file_statictu->Variable_file_statictu.tu_name|C_AST.Variable_func_staticf->Variable_func_static(from_functionf)andfrom_var_initctxv=matchv.var_initwith|Somei->Some(from_initctxi)|None->Noneandfrom_init_optionctxinit=matchinitwith|Somei->Some(from_initctxi)|None->Noneandfrom_initctxinit=matchinitwith|I_init_expre->C_init_expr(from_exprctxe)|I_init_list(il,i)->C_init_list(List.map(from_initctx)il,from_init_optionctxi)|I_init_implicitt->C_init_implicit(from_typctxt)(** {2 Types} *)(** ========= *)andfrom_typctx(tc:C_AST.type_qual):typ=lettyp,qual=tcinlettyp'=from_unqual_typctxtypinifqual.C_AST.qual_is_constthenT_c_qualified({c_qual_is_const=true;c_qual_is_restrict=false;c_qual_is_volatile=false},typ')elsetyp'andfrom_unqual_typctx(tc:C_AST.typ):typ=matchtcwith|C_AST.T_void->Ast.T_c_void|C_AST.T_bool->Ast.T_c_bool|C_AST.T_integert->Ast.T_c_integer(from_integer_typet)|C_AST.T_floatt->Ast.T_c_float(from_float_typet)|C_AST.T_pointert->Ast.T_c_pointer(from_typctxt)|C_AST.T_array(t,l)->Ast.T_c_array(from_typctxt,from_array_lengthctxl)|C_AST.T_functionNone->Ast.T_c_functionNone|C_AST.T_function(Somet)->Ast.T_c_function(Some(from_function_typectxt))|C_AST.T_builtin_fn->Ast.T_c_builtin_fn|C_AST.T_typedeft->ifHashtbl.memctx.ctx_type(TS_TYPEDEF,t.typedef_unique_name)thenHashtbl.findctx.ctx_type(TS_TYPEDEF,t.typedef_unique_name)elseletx={c_typedef_org_name=t.typedef_org_name;c_typedef_unique_name=t.typedef_unique_name;c_typedef_def=Ast.T_c_void;c_typedef_range=from_ranget.typedef_range;}inlety=Ast.T_c_typedefxinHashtbl.addctx.ctx_type(TS_TYPEDEF,t.typedef_unique_name)y;x.c_typedef_def<-from_typctxt.typedef_def;y|C_AST.T_recordr->ifHashtbl.memctx.ctx_type(TS_RECORD,r.record_unique_name)thenHashtbl.findctx.ctx_type(TS_RECORD,r.record_unique_name)elseletx={c_record_kind=(matchr.record_kindwithC_AST.STRUCT->C_struct|C_AST.UNION->C_union);c_record_org_name=r.record_org_name;c_record_unique_name=r.record_unique_name;c_record_defined=r.record_defined;c_record_sizeof=r.record_sizeof;c_record_alignof=r.record_alignof;c_record_fields=[];c_record_range=from_ranger.record_range;}inlety=Ast.T_c_recordxinHashtbl.addctx.ctx_type(TS_RECORD,r.record_unique_name)y;x.c_record_fields<-List.map(funf->{c_field_org_name=f.field_org_name;c_field_name=f.field_name;c_field_offset=f.field_offset;c_field_bit_offset=f.field_bit_offset;c_field_type=from_typctxf.field_type;c_field_range=from_rangef.field_range;c_field_index=f.field_index;})(Array.to_listr.record_fields);y|C_AST.T_enume->ifHashtbl.memctx.ctx_type(TS_ENUM,e.enum_unique_name)thenHashtbl.findctx.ctx_type(TS_ENUM,e.enum_unique_name)elseletx=Ast.T_c_enum{c_enum_org_name=e.enum_org_name;c_enum_unique_name=e.enum_unique_name;c_enum_defined=e.enum_defined;c_enum_values=List.map(funv->{c_enum_val_org_name=v.enum_val_org_name;c_enum_val_unique_name=v.enum_val_unique_name;c_enum_val_value=v.enum_val_value;c_enum_val_range=from_rangev.enum_val_range;})e.enum_values;c_enum_integer_type=from_integer_type(OptionExt.none_to_exne.enum_integer_type);c_enum_range=from_rangee.enum_range;}inHashtbl.addctx.ctx_type(TS_ENUM,e.enum_unique_name)x;x|C_AST.T_bitfield(t,n)->Ast.T_c_bitfield(from_unqual_typctxt,n)|C_AST.T_complex_->failwith"C_AST.T_complex not supported"|C_AST.T_vectorv->(* translate vector into array type *)lett=from_typctxv.vector_typein(* size is in bytes, length is in units of t *)letlen=Z.div(Z.of_intv.vector_size)(sizeof_type_in_targett!target_info)inAst.T_c_array(t,Ast.C_array_length_cstlen)|C_AST.T_unknown_builtins->Ast.T_c_unknown_builtinsandfrom_integer_type:C_AST.integer_type->Ast.c_integer_type=function|C_AST.CharSIGNED->Ast.C_signed_char|C_AST.CharUNSIGNED->Ast.C_unsigned_char|C_AST.SIGNED_CHAR->Ast.C_signed_char|C_AST.UNSIGNED_CHAR->Ast.C_unsigned_char|C_AST.SIGNED_SHORT->Ast.C_signed_short|C_AST.UNSIGNED_SHORT->Ast.C_unsigned_short|C_AST.SIGNED_INT->Ast.C_signed_int|C_AST.UNSIGNED_INT->Ast.C_unsigned_int|C_AST.SIGNED_LONG->Ast.C_signed_long|C_AST.UNSIGNED_LONG->Ast.C_unsigned_long|C_AST.SIGNED_LONG_LONG->Ast.C_signed_long_long|C_AST.UNSIGNED_LONG_LONG->Ast.C_unsigned_long_long|C_AST.SIGNED_INT128->Ast.C_signed_int128|C_AST.UNSIGNED_INT128->Ast.C_unsigned_int128andfrom_float_type:C_AST.float_type->Ast.c_float_type=function|C_AST.FLOAT->Ast.C_float|C_AST.DOUBLE->Ast.C_double|C_AST.LONG_DOUBLE->Ast.C_long_double|C_AST.FLOAT128->Ast.C_float128andfrom_array_lengthctxal=matchalwith|C_AST.No_length->Ast.C_array_no_length|C_AST.Length_cstn->Ast.C_array_length_cstn|C_AST.Length_expre->Ast.C_array_length_expr(from_exprctxe)andfrom_function_typectxf={c_ftype_return=from_typctxf.ftype_return;c_ftype_params=List.map(from_typctx)f.ftype_params;c_ftype_variadic=f.ftype_variadic;}andfind_field_indextf=trymatchfsttwith|T_record{record_fields}->letfield=Array.to_listrecord_fields|>List.find(funfield->field.field_org_name=f)infield.field_index|T_typedeftd->find_field_indextd.typedef_deff|_->Exceptions.panic"find_field_index: called on a non-record type %s"(C_print.string_of_type_qualt)withNot_found->Exceptions.panic"find_field_index: field %s not found in type %s"f(C_print.string_of_type_qualt)andunder_typet=matchfsttwith|T_pointert'->t'|T_array(t',_)->t'|T_typedeftd->under_typetd.typedef_def|_->Exceptions.panic"under_type: unsupported type %s"(C_print.string_of_type_qualt)(** {2 Ranges and locations} *)(** ======================== *)andfrom_range(range:C_AST.range)=letopenClang_ASTinletopenLocationinmk_orig_range{pos_file=range.range_begin.loc_file;pos_line=range.range_begin.loc_line;pos_column=range.range_begin.loc_column;}{pos_file=range.range_end.loc_file;pos_line=range.range_end.loc_line;pos_column=range.range_end.loc_column;}(** {2 Stubs annotations} *)(** ===================== *)andfrom_stub_commentctxf=tryletstub=Mopsa_c_stubs_parser.Main.parse_function_commentfctx.ctx_prjctx.ctx_enumsctx.ctx_predicatesctx.ctx_stubsinSome(from_stub_funcctxfstub)withMopsa_c_stubs_parser.Main.StubNotFound->Noneandfrom_stub_funcctxfstub=debug"parsing stub %s"f.func_org_name;{stub_func_name=stub.stub_name;stub_func_params=List.map(from_varctx)(Array.to_listf.func_parameters);stub_func_body=List.map(from_stub_sectionctx)stub.stub_body;stub_func_range=stub.stub_range;stub_func_locals=List.map(from_stub_localctx)stub.stub_locals;stub_func_assigns=List.map(from_stub_assignsctx)stub.stub_assigns;stub_func_return_type=matchf.func_returnwith|(T_void,_)->None|t->Some(from_typctxt);}andfrom_stub_sectionctxsection=matchsectionwith|S_leafleaf->S_leaf(from_stub_leafctxleaf)|S_casecase->S_case(from_stub_casectxcase)andfrom_stub_leafctxleaf=matchleafwith|S_locallocal->S_local(from_stub_localctxlocal)|S_assumesassumes->S_assumes(from_stub_assumesctxassumes)|S_requiresrequires->S_requires(from_stub_requiresctxrequires)|S_assignsassigns->S_assigns(from_stub_assignsctxassigns)|S_ensuresensures->S_ensures(from_stub_ensuresctxensures)|S_freefree->S_free(from_stub_freectxfree)|S_messagemsg->S_message(from_stub_messagectxmsg)andfrom_stub_casectxcase={case_label=case.Mopsa_c_stubs_parser.Ast.case_label;case_body=List.map(from_stub_leafctx)case.case_body;case_locals=List.map(from_stub_localctx)case.case_locals;case_assigns=List.map(from_stub_assignsctx)case.case_assigns;case_range=case.case_range;}andfrom_stub_requiresctxreq=bind_rangereq@@funreq->from_stub_formulactxreqandfrom_stub_freectxfree=bind_rangefree@@funfree->from_stub_exprctxfreeandfrom_stub_messagectxmsg=bind_rangemsg@@funm->{message_kind=from_stub_message_kindm.message_kind;message_body=m.message_body;}andfrom_stub_message_kind=function|WARN->WARN|UNSOUND->UNSOUNDandfrom_stub_assignsctxassign=bind_rangeassign@@funassign->{assign_target=from_stub_exprctxassign.assign_target;assign_offset=List.map(from_stub_intervalctx)assign.assign_offset;}andfrom_stub_localctxloc=bind_rangeloc@@funloc->{lvar=from_varctxloc.lvar;lval=from_stub_local_valuectxloc.lval}andfrom_stub_local_valuectxlval=matchlvalwith|L_newres->L_newres|L_call(f,args)->letff=find_function_in_contextctxf.rangef.contentinlett=T_c_function(Some{c_ftype_return=from_typctxf.content.func_return;c_ftype_params=Array.to_listf.content.func_parameters|>List.map(funp->from_typctxp.var_type);c_ftype_variadic=f.content.func_variadic;})inletfff=mk_expr(Ast.E_c_functionff)f.range~etyp:tinL_call(fff,List.map(from_stub_exprctx)args)andfrom_stub_ensuresctxens=bind_rangeens@@funens->from_stub_formulactxensandfrom_stub_assumesctxasm=bind_rangeasm@@funasm->from_stub_formulactxasmandfrom_stub_formulactxf=bind_rangef@@function|F_expre->F_expr(from_stub_exprctxe)|F_boolb->F_expr(mk_boolbf.range)|F_binop(op,f1,f2)->F_binop(from_stub_log_binopop,from_stub_formulactxf1,from_stub_formulactxf2)|F_notf->F_not(from_stub_formulactxf)|F_forall(v,s,f)->F_forall(from_varctxv,from_stub_setctxs,from_stub_formulactxf)|F_exists(v,s,f)->F_exists(from_varctxv,from_stub_setctxs,from_stub_formulactxf)|F_in(v,s)->F_in(from_stub_exprctxv,from_stub_setctxs)|F_otherwise(f,e)->F_otherwise(from_stub_formulactxf,from_stub_exprctxe)|F_if(c,f1,f2)->F_if(from_stub_formulactxc,from_stub_formulactxf1,from_stub_formulactxf2)andfrom_stub_setctxs=matchswith|S_intervali->S_interval(from_stub_intervalctxi)|S_resourcer->S_resourcerandfrom_stub_intervalctxi=letlb=from_stub_exprctxi.itv_lbinletub=from_stub_exprctxi.itv_ubin(* We can use operations on mathematical integers without worrying about overflows *)letlb=ifi.itv_open_lbthen(addlbone~typ:T_intlb.erange)elselbinletub=ifi.itv_open_ubthen(sububone~typ:T_intub.erange)elseubin(lb,ub)andfrom_stub_exprctxexp=letbind_range_expr(exp:Mopsa_c_stubs_parser.Ast.exprwith_range)f=letekind=fexp.content.kindinmk_exprekindexp.range~etyp:(from_typctxexp.content.typ)inbind_range_exprexp@@function|E_topt->E_constant(C_top(from_typctxt))|E_intn->E_constant(C_intn)|E_floatf->E_constant(C_floatf)|E_strings->E_constant(C_c_string(s,C_char_ascii))(* FIXME: support other character kinds *)|E_charc->E_constant(C_c_character(Z.of_intc,Ast.C_char_ascii))(* FIXME: support other character kinds *)|E_invalid->E_constantC_c_invalid|E_varv->E_var(from_varctxv,None)|E_unop(op,e)->E_unop(from_stub_expr_unopop,from_stub_exprctxe)|E_binop(op,e1,e2)->E_binop(from_stub_expr_binopop,from_stub_exprctxe1,from_stub_exprctxe2)|E_addr_ofe->E_c_address_of(from_stub_exprctxe)|E_derefp->E_c_deref(from_stub_exprctxp)|E_cast(t,explicit,e)->E_c_cast(from_stub_exprctxe,explicit)|E_subscript(a,i)->E_c_array_subscript(from_stub_exprctxa,from_stub_exprctxi)|E_member(s,i,f)->E_c_member_access(from_stub_exprctxs,i,f)|E_arrow(p,i,f)->E_c_arrow_access(from_stub_exprctxp,i,f)|E_conditional(c,e1,e2)->E_c_conditional(from_stub_exprctxc,from_stub_exprctxe1,from_stub_exprctxe2)|E_builtin_call(PRIMED,[arg])->E_stub_primed(from_stub_exprctxarg)|E_builtin_call(f,args)->E_stub_builtin_call(f,List.map(from_stub_exprctx)args)|E_return->E_stub_return|E_raises->E_stub_raisesandfrom_stub_log_binop=function|AND->AND|OR->OR|IMPLIES->IMPLIESandfrom_stub_expr_binop=function|Mopsa_c_stubs_parser.Cst.ADD->O_plus|SUB->O_minus|MUL->O_mult|DIV->O_div|MOD->O_mod|RSHIFT->O_bit_rshift|LSHIFT->O_bit_lshift|LOR->O_c_and|LAND->O_c_or|LT->O_lt|LE->O_le|GT->O_gt|GE->O_ge|EQ->O_eq|NEQ->O_ne|BOR->O_bit_or|BAND->O_bit_and|BXOR->O_bit_xorandfrom_stub_expr_unop=function|Mopsa_c_stubs_parser.Cst.PLUS->O_plus|MINUS->O_minus|LNOT->O_log_not|BNOT->O_bit_invertandfrom_stub_directivesctxcom_map=C_AST.RangeMap.fold(funrangecomacc->tryletstub=Mopsa_c_stubs_parser.Main.parse_directive_commentcomrangectx.ctx_prjctx.ctx_enumsctx.ctx_predicatesctx.ctx_stubsinfrom_stub_directivectxstub::accwithMopsa_c_stubs_parser.Main.StubNotFound->acc)com_map[]andfrom_stub_directivectxstub={stub_directive_body=List.map(from_stub_sectionctx)stub.stub_body;stub_directive_range=stub.stub_range;stub_directive_locals=List.map(from_stub_localctx)stub.stub_locals;stub_directive_assigns=List.map(from_stub_assignsctx)stub.stub_assigns;}andfrom_stub_predicatescom_map=C_AST.RangeMap.fold(funrangecomacc->Mopsa_c_stubs_parser.Main.parse_predicates_commentcom|>List.fold_left(funaccpred->letname=pred.Mopsa_c_stubs_parser.Passes.Preprocessor.pred_nameinStringMap.addnamepredacc)acc)com_mapStringMap.emptyleton_panicexnfilestime=(* Provide automated testcase reduction hints if possible *)matchexnwith|Exceptions.Panic(msg,_)|Exceptions.PanicAtLocation(_,msg,_)|Exceptions.PanicAtFrame(_,_,msg,_)->(* we can simplify now that we're in the frontend *)letmultiple_files=List.length(List.filter(funs->not@@(trylet_=Str.search_forward(Str.regexp"share/mopsa/stubs/c/")s0intruewithNot_found->false))files)>1||List.exists(funf->Filename.extensionf=".db")filesinifmultiple_files&¬!opt_store_projectthenFormat.printf"@\nTo benefit from Mopsa's automated testcase reduction capabilities, please remove command-line option `-c-no-project-storage`@\n"elseletmopsa_command,stub_files,file_to_reduce=letmopsa_command=Format.asprintf"%a"(Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt" ")Format.pp_print_string)(List.filter(funs->not@@List.memsfiles)(Array.to_listSys.argv))inmatchmultiple_files,List.find_opt(String.ends_with~suffix:".i")fileswith|false,None->(* single file: easy *)mopsa_command,[],List.hdfiles|true,None->(* multiple files, but no preprocessed one: to generate *)ifUnix.isattyUnix.stdin&&Unix.isattyUnix.stdoutthenlet()=Format.printf"@\n%a Do you want to try automated testcase reduction (using creduce/cvise) to find/report a minimal program that still crashes Mopsa? If yes, Mopsa will generate a preprocessed C file of your project. [Y/n]@."(Debug.color_strDebug.magenta)"Mopsa encountered a fatal error."inletanswer=input_linestdininifanswer=""||(String.lowercase_asciianswer).[0]='y'thenletpreprocessed_file=assert(!opt_make_target<>"");!opt_make_target^".i"inletpreprocessed_file=ifSys.file_existspreprocessed_filethenFilename.basename@@Filename.temp_file~temp_dir:(Sys.getcwd())""".i"elsepreprocessed_fileinletstub_files=save_preprocessed_file(OptionExt.none_to_exn!o_prj)preprocessed_fileinmopsa_command,stub_files,preprocessed_fileelseexit2elselet()=Format.printf"@\n%a@\n"(Debug.color_strDebug.magenta)"Hint: to get automated testcase reduction instructions, launch the analysis again in a TTY (without redirections, etc)."inexit2|_,Somes->(* multiple files, including a preprocessed one: no preprocessing to generate again *)mopsa_command,List.filter(funs->trylet_=Str.search_forward(Str.regexp"share/mopsa/stubs/c/")s0intruewithNot_found->false)files,sin(* Large timeout due to potential slowdown with large parallelization *)lettimeout=int_of_float(5.+.4.*.time)inFormat.printf"@\n%a using the following command (you may need to generalize a bit the MOPSA_ERR_STRING):@\nMOPSA_ERR_STRING=\"%s\" MOPSA_COMMAND=\"%s\" MOPSA_STUBS=\"%a\" FILE_TO_REDUCE=%s bash -c 'cvise --timeout %d %s $FILE_TO_REDUCE'@\n"(Debug.color_strDebug.magenta)"Hint: try automated testcase reduction using creduce or cvise"(String.escapedmsg)mopsa_command(Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt" ")Format.pp_print_string)stub_filesfile_to_reducetimeout(!Paths.opt_share_dir^"/../../tools/reducer-oracle.sh")|_->()(* Front-end registration *)let()=register_frontend{lang="c";parse=parse_program;on_panic=on_panic;}