From 268dec55a9b0d0ba1f5917d339ff35cec4a2ff5c Mon Sep 17 00:00:00 2001 From: Virgile Prevosto <virgile.prevosto@m4x.org> Date: Fri, 11 Feb 2022 18:26:44 +0100 Subject: [PATCH] [options] refactor unmangling options and allow unmangling even on C files --- frama_Clang_option.ml | 104 ++++++++++++++++++------------ frama_Clang_option.mli | 20 +++--- frama_Clang_register.ml | 14 ++-- mangling.ml | 7 +- tests/basic/oracle/printer.res.c | 50 ++++++++++++++ tests/basic/oracle/printer.res2.c | 50 ++++++++++++++ tests/basic/printer.cpp | 4 +- 7 files changed, 190 insertions(+), 59 deletions(-) create mode 100644 tests/basic/oracle/printer.res.c create mode 100644 tests/basic/oracle/printer.res2.c diff --git a/frama_Clang_option.ml b/frama_Clang_option.ml index ee81e6e5..2e806ff3 100644 --- a/frama_Clang_option.ml +++ b/frama_Clang_option.ml @@ -42,48 +42,69 @@ module Clang_command = let () = Parameter_customize.no_category () module Clang_extra_args = String_list( - struct - let option_name = "-fclang-cpp-extra-args" - let help = - "pass additional options to clang. If not set, the content of \ - -cpp-extra-args (if any) is used instead" - let arg_name = "opt" - end) - -module Unmangling: -sig - val add_hook_on_update: (unit -> unit) -> unit - val set: string -> unit - val get: unit -> string - val clear: unit -> unit - val get_val: unit -> (string -> string) - val register_mangling_func: string -> (string->string) -> unit -end -= struct - module Rep = - State_builder.Ref(Datatype.String) - (struct let dependencies = [] - let name = "Unmangling" - let default () = "short" - end) - let add_hook_on_update f = Rep.add_hook_on_update (fun _ -> f ()) - let available_opt = Hashtbl.create 7 - let set s = if Hashtbl.mem available_opt s then Rep.set s - let clear () = Rep.clear () - let get () = Rep.get () - let get_val () = Hashtbl.find available_opt (Rep.get ()) - let register_mangling_func s f = Hashtbl.add available_opt s f - let () = - register_mangling_func "id" (fun s -> s); - set "short" + let option_name = "-fclang-cpp-extra-args" + let help = + "pass additional options to clang. If not set, the content of \ + -cpp-extra-args (if any) is used instead" + let arg_name = "opt" + end) + +let unmangling_functions: (string*(string->string)) Datatype.String.Hashtbl.t = + Datatype.String.Hashtbl.create 7 + +let pp_unmangling_functions fmt = + Datatype.String.Hashtbl.iter + (fun key (help, _) -> Format.fprintf fmt "%s: %s@\n" key help) + unmangling_functions + +let () = + Datatype.String.Hashtbl.add + unmangling_functions "none" ("keep mangled names", fun id -> id) + +module Unmangling = + String( + struct + let option_name = "-cxx-unmangling" + let help = + "how to pretty-print mangled symbols. Use -unmangling help to list \ + available options" + let arg_name = "s" + let default = "none" end +) + +let unmangling_help () = + feedback "Possible unmangling functions are:@\n%t" pp_unmangling_functions; + Cmdline.nop + +let unmangling_hook _ v = + if Datatype.String.equal v "help" then + Cmdline.run_after_exiting_stage unmangling_help + +let () = Unmangling.add_set_hook unmangling_hook + +let () = Unmangling.set_possible_values [ "none"; "help" ] +let add_unmangling_function key descr f = + let l = Unmangling.get_possible_values () in + Unmangling.set_possible_values (key :: l); + Datatype.String.Hashtbl.add unmangling_functions key (descr,f) + +let get_unmangling_function () = + let v = Unmangling.get () in + if v <> "help" then + snd (Datatype.String.Hashtbl.find unmangling_functions v) + else + fatal + "cannot get current unmangling function: \ + Frama-C is not supposed to run analyses if `-unmangling help' is set " module UnmanglingFull = Bool(struct let default = false let option_name = "-cxx-demangling-full" - let help= "displays identifiers with their full C++ name" + let help= "displays identifiers with their full C++ name. \ + OBSOLETE: use -unmangling fully-qualified instead)" end) let () = Parameter_customize.set_negative_option_name "" @@ -94,7 +115,8 @@ module UnmanglingShort = let option_name = "-cxx-demangling-short" let help= "displays identifiers with their C++ short name \ - (without qualifiers)" + (without qualifiers). \ + OBSOLETE: use -unmangling without-qualifier instead" end) let () = Parameter_customize.set_negative_option_name "" @@ -103,17 +125,17 @@ module UnmanglingNo = Bool(struct let default = false let option_name= "-cxx-keep-mangling" - let help= "displays identifiers with their mangled name" + let help= "displays identifiers with their mangled name \ + OBSOLETE: use -unmangling none instead" end) let add_unmangling_option s _ new_flag = if new_flag then Unmangling.set s - else if Unmangling.get () = s then Unmangling.clear () let () = - UnmanglingFull.add_set_hook (add_unmangling_option "full"); - UnmanglingShort.add_set_hook (add_unmangling_option "short"); - UnmanglingNo.add_set_hook (add_unmangling_option "id"); + UnmanglingFull.add_set_hook (add_unmangling_option "fully-qualified"); + UnmanglingShort.add_set_hook (add_unmangling_option "without-qualifier"); + UnmanglingNo.add_set_hook (add_unmangling_option "none") module ParseableOutput = False(struct diff --git a/frama_Clang_option.mli b/frama_Clang_option.mli index 1310d797..16f00806 100644 --- a/frama_Clang_option.mli +++ b/frama_Clang_option.mli @@ -27,14 +27,18 @@ module Clang_command: Parameter_sig.String module Clang_extra_args: Parameter_sig.String_list -(** state of the demangling options. *) -module Unmangling: -sig - val add_hook_on_update: (unit -> unit) -> unit - val set: string -> unit - val get_val: unit -> (string -> string) - val register_mangling_func: string -> (string->string) -> unit -end +(** state of the -unmangling option. *) +module Unmangling: Parameter_sig.String + +(** [add_unmangling_function key descr f] registers [f] as an unmangling + function, activated by [-unmangling key]. [descr] will be displayed + along with [key] in the [-unmangling help] output. + *) +val add_unmangling_function: string -> string -> (string -> string) -> unit + +(** gets the unmangling function corresponding + to the current value of [Unmangling] *) +val get_unmangling_function: unit -> (string -> string) (** -cxx-parseable-output *) module ParseableOutput: Parameter_sig.Bool diff --git a/frama_Clang_register.ml b/frama_Clang_register.ml index 1c753b84..5c7dcfcb 100644 --- a/frama_Clang_register.ml +++ b/frama_Clang_register.ml @@ -120,7 +120,8 @@ struct class printer = object inherit M.printer method! varname fmt name = - Format.pp_print_string fmt (Frama_Clang_option.Unmangling.get_val() name) + Format.pp_print_string fmt + (Frama_Clang_option.get_unmangling_function () name) end end @@ -129,8 +130,9 @@ end let is_cxx_printer_initialized = ref false -let init_cxx_printer () = - if not !is_cxx_printer_initialized then begin +let init_cxx_printer _ v = + if v <> "help" && not !is_cxx_printer_initialized then + begin is_cxx_printer_initialized := true; Cil_printer.register_shallow_attribute Convert.fc_implicit_attr; Cil_printer.register_shallow_attribute Convert.fc_pure_template_decl_attr; @@ -138,14 +140,16 @@ let init_cxx_printer () = end let () = - Frama_Clang_option.Unmangling.add_hook_on_update init_cxx_printer + Frama_Clang_option.Unmangling.add_set_hook init_cxx_printer let is_initialized = ref false let init_cxx_normalization () = if not !is_initialized then begin is_initialized:=true; - init_cxx_printer (); + (* If unmangling has not been set, default to short. *) + if not (Frama_Clang_option.Unmangling.is_set ()) then + Frama_Clang_option.Unmangling.set "without-qualifier"; (* enable exception removal unless it has explicitely been set to false on the command line. *) diff --git a/mangling.ml b/mangling.ml index cee5981b..51b84c99 100644 --- a/mangling.ml +++ b/mangling.ml @@ -801,6 +801,7 @@ let short_name name = let is_constructor_name name = basename name = "Ctor" let () = - Frama_Clang_option.Unmangling.register_mangling_func "short" short_name; - Frama_Clang_option.Unmangling.register_mangling_func "full" unmangle; - Frama_Clang_option.Unmangling.set "short" + Frama_Clang_option.add_unmangling_function + "without-qualifier" "short version of the symbol" short_name; + Frama_Clang_option.add_unmangling_function + "fully-qualified" "fully qualified symbol" unmangle diff --git a/tests/basic/oracle/printer.res.c b/tests/basic/oracle/printer.res.c new file mode 100644 index 00000000..8a05f771 --- /dev/null +++ b/tests/basic/oracle/printer.res.c @@ -0,0 +1,50 @@ +/* Generated by Frama-C */ +struct _Z20_frama_c_vmt_content { + void (*method_ptr)() ; + int shift_this ; +}; +struct _Z28_frama_c_rtti_name_info_node; +struct _Z12_frama_c_vmt { + struct _Z20_frama_c_vmt_content *table ; + int table_size ; + struct _Z28_frama_c_rtti_name_info_node *rtti_info ; +}; +struct _Z31_frama_c_rtti_name_info_content { + struct _Z28_frama_c_rtti_name_info_node *value ; + int shift_object ; + int shift_vmt ; +}; +struct _Z28_frama_c_rtti_name_info_node { + char const *name ; + struct _Z31_frama_c_rtti_name_info_content *base_classes ; + int number_of_base_classes ; + struct _Z12_frama_c_vmt *pvmt ; +}; +struct _ZN1AE1B; +struct _ZN1AE1B { + int x ; +}; +struct _Z28_frama_c_rtti_name_info_node _ZN1A1BE23_frama_c_rtti_name_info; + +/*@ requires \valid_read(this); */ +void _ZN1A1BEC1(struct _ZN1AE1B const *this __attribute__((____fc_initialized_object__))) +{ + this->x = 42; + return; +} + +struct _Z28_frama_c_rtti_name_info_node _ZN1A1BE23_frama_c_rtti_name_info = + {.name = "B", + .base_classes = (struct _Z31_frama_c_rtti_name_info_content *)0, + .number_of_base_classes = 0, + .pvmt = (struct _Z12_frama_c_vmt *)0}; +int main(void) +{ + int __retres; + struct _ZN1AE1B b; + _ZN1A1BEC1(& b); + __retres = b.x; + return __retres; +} + + diff --git a/tests/basic/oracle/printer.res2.c b/tests/basic/oracle/printer.res2.c new file mode 100644 index 00000000..7429be90 --- /dev/null +++ b/tests/basic/oracle/printer.res2.c @@ -0,0 +1,50 @@ +/* Generated by Frama-C */ +struct _frama_c_vmt_content { + void (*method_ptr)() ; + int shift_this ; +}; +struct _frama_c_rtti_name_info_node; +struct _frama_c_vmt { + struct _frama_c_vmt_content *table ; + int table_size ; + struct _frama_c_rtti_name_info_node *rtti_info ; +}; +struct _frama_c_rtti_name_info_content { + struct _frama_c_rtti_name_info_node *value ; + int shift_object ; + int shift_vmt ; +}; +struct _frama_c_rtti_name_info_node { + char const *name ; + struct _frama_c_rtti_name_info_content *base_classes ; + int number_of_base_classes ; + struct _frama_c_vmt *pvmt ; +}; +struct B; +struct B { + int x ; +}; +struct _frama_c_rtti_name_info_node _frama_c_rtti_name_info; + +/*@ requires \valid_read(this); */ +void B::Ctor(struct B const *this) +{ + this->x = 42; + return; +} + +struct _frama_c_rtti_name_info_node _frama_c_rtti_name_info = + {.name = "B", + .base_classes = (struct _frama_c_rtti_name_info_content *)0, + .number_of_base_classes = 0, + .pvmt = (struct _frama_c_vmt *)0}; +int main(void) +{ + int __retres; + struct B b; + B::Ctor((struct B const *)(& b)); + __retres = b.x; + return __retres; +} + + diff --git a/tests/basic/printer.cpp b/tests/basic/printer.cpp index b442d7f8..88e4eea8 100644 --- a/tests/basic/printer.cpp +++ b/tests/basic/printer.cpp @@ -1,7 +1,7 @@ /* run.config NOFRAMAC: -EXECNOW: LOG printer.res.c @frama-c@ @PTEST_FILE@ @CXX@ @MACHDEP@ -cxx-keep-mangling -print-as-is -ocode printer.res.c -print -EXECNOW: @frama-c@ @CXX@ @MACHDEP@ -cxx-demangling-short printer.res.c -print +EXECNOW: LOG printer.res.c @frama-c@ @PTEST_FILE@ @CXX@ @MACHDEP@ -cxx-unmangling none -kernel-msg-key printer:attrs -ocode @PTEST_RESULT@/printer.res.c -print +EXECNOW: LOG printer.res2.c @frama-c@ @CXX@ @MACHDEP@ -cxx-unmangling without-qualifier @PTEST_RESULT@/printer.res.c -ocode @PTEST_RESULT@/printer.res2.c -print */ namespace A { -- GitLab