关于Frama-C插件生成修改后C文件的技术咨询
Absolutely! You can totally build a Frama-C plugin to tweak source code (clone functions, insert calls) and spit out a clean, modified C file—no messy extra output included. Let’s walk through how to make this happen:
Core Idea
Frama-C’s entire workflow revolves around the AST (Abstract Syntax Tree) of your C code, built using the Cil (C Intermediate Language) library. Instead of redirecting terminal output (which picks up extra logs from other plugins), you’ll directly modify the AST and then print it to a file using Cil’s dedicated printing functions—this gives you full control over what gets written.
Step-by-Step Implementation
1. Get Familiar with Cil’s AST Structures
First, you’ll need to learn the basics of Cil’s types since Frama-C uses them to represent code:
fundec: Represents a function definition (includes name, parameters, body, etc.)stmt: A single statement (like a function call, assignment, or loop)exp: An expression (like a function argument or variable reference)
Frama-C’s internal docs (accessible via frama-c -help api) will be your best friend here—look up functions related to copying functions, creating calls, and manipulating statements.
2. Write Your AST Modification Logic
Cloning a Function
To clone a function, copy its fundec structure, adjust the name, and add the new function to the global list of functions in the AST:
let clone_function (original : Cil.fundec) : Cil.fundec = let cloned = Cil.copyFunction original in cloned.svar.vname <- cloned.svar.vname ^ "_clone"; (* Add the cloned function to the global scope *) Cil.currentFile.globals <- Cil.GFun(cloned, cloned.svar.vdecl) :: Cil.currentFile.globals; cloned
Inserting a Function Call
To insert a call to your cloned function (or any function) into another function’s body, create a call statement and insert it into the target function’s statement list:
let insert_function_call (target_func : Cil.fundec) (call_func : Cil.fundec) = (* Create the function call expression *) let call_exp = Cil.Lval(Cil.Var call_func.svar, Cil.NoOffset) in let call_stmt = Cil.mkStmt (Cil.Instr [Cil.Call(None, call_exp, [], call_func.svar.vdecl)]) in (* Insert the call at the start of the target function's body *) match target_func.body with | Cil.Block(block) -> block.bstmts <- call_stmt :: block.bstmts | _ -> ()
3. Print the Modified AST to a Clean File
The key to avoiding redundant output is to skip Frama-C’s default terminal printing and use Cil’s direct file-printing functions. Here’s how to do it:
let output_modified_file (output_path : string) = (* Ensure for loops are printed as for, not while *) Cil.printForAsFor := true; (* Open the output file and print the AST *) let oc = open_out output_path in Cil.printFile ~out:oc !Cil.currentFile; close_out oc; Printf.printf "Modified code written to %s\n" output_path
4. Wire It All Together in Your Plugin
Register your plugin so it runs the modification and output logic when Frama-C starts:
let () = Db.Main.extend (fun () -> (* Example: Find a function named "foo", clone it, and insert the clone call into "bar" *) let find_func name = List.find_opt (fun g -> match g with | Cil.GFun(f, _) when f.svar.vname = name -> true | _ -> false) Cil.currentFile.globals in match find_func "foo", find_func "bar" with | Some(Cil.GFun(foo, _)), Some(Cil.GFun(bar, _)) -> let cloned_foo = clone_function foo in insert_function_call bar cloned_foo; output_modified_file "modified_code.c" | _ -> Printf.printf "Could not find target functions\n" )
Avoiding Common Pitfalls
- Disable Unnecessary Plugins: When running your plugin, don’t include other analysis plugins (like
valueorconstant-folding) unless you need them—they can modify the AST or add extra terminal output. Run it like:frama-c -load-script your_plugin.cmxs your_source.c - Check Cil’s Print Options: Adjust flags like
Cil.printForAsForto preserve original loop syntax instead of converting for loops to while. - Test with Minimal Code: Start with a tiny C file (e.g., a single function) to test your plugin—this makes debugging way easier than jumping into complex codebases.
Final Tips
If you’re stuck, look at the source code of existing Frama-C plugins that modify the AST (like sparecode or loopext). While their output goes to the terminal, you can adapt their AST manipulation logic and replace the output step with your direct file print.
内容的提问来源于stack exchange,提问作者R. Fomba

