From f336851f92857588c08dfc9cd9e6d82fcfdacd2a Mon Sep 17 00:00:00 2001 From: Bohdan Trach Date: Thu, 8 Aug 2024 13:39:51 +0200 Subject: [PATCH] module,cmd: allow specifying skip function prefixes on CLI Signed-off-by: Bohdan Trach --- cmd/vsyncer/info.go | 5 +++-- cmd/vsyncer/root.go | 4 ++++ module/config.go | 7 ++++--- module/history.go | 4 ++-- module/visitor.go | 27 ++++++++++++++++++--------- module/wrap_module.go | 2 +- 6 files changed, 32 insertions(+), 17 deletions(-) diff --git a/cmd/vsyncer/info.go b/cmd/vsyncer/info.go index 146dd49..348b679 100644 --- a/cmd/vsyncer/info.go +++ b/cmd/vsyncer/info.go @@ -53,7 +53,8 @@ func Info(fn string, args []string) error { func moduleConfig() module.Config { return module.Config{ - EntryFunc: rootFlags.entryFunc, - Expand: rootFlags.expand, + EntryFunc: rootFlags.entryFunc, + SkipFuncPref: rootFlags.skipFunc, + Expand: rootFlags.expand, } } diff --git a/cmd/vsyncer/root.go b/cmd/vsyncer/root.go index 3df0f7d..effd6ba 100644 --- a/cmd/vsyncer/root.go +++ b/cmd/vsyncer/root.go @@ -49,6 +49,7 @@ var rootCmd = cobra.Command{ func init() { tools.RegEnv("VSYNCER_DEFAULT_CHECKER", "genmc", "Default model checker") tools.RegEnv("VSYNCER_DEFAULT_ENTRY_FUNC", "main", "Default entry functions for analysis") + tools.RegEnv("VSYNCER_DEFAULT_SKIP_FUNC", "pthread_,__assert_fail,llvm.,_VERIFIER", "Default prefixes of functions to skip") helpMessage := `vsyncer -- Verification and optimization of concurrent code on WMM` @@ -70,6 +71,9 @@ func init() { flags.StringSliceVar(&rootFlags.entryFunc, "entry-func", strings.Split(tools.GetEnv("VSYNCER_DEFAULT_ENTRY_FUNC"), ","), "list of entry functions") + flags.StringSliceVar(&rootFlags.skipFunc, "skip-func", + strings.Split(tools.GetEnv("VSYNCER_DEFAULT_SKIP_FUNC"), ","), + "list of function prefixes to skip") rootCmd.SetHelpCommand(&cobra.Command{Hidden: true}) initOptimize() diff --git a/module/config.go b/module/config.go index 92df6e7..6588d08 100644 --- a/module/config.go +++ b/module/config.go @@ -10,15 +10,16 @@ type Config struct { Expand bool // whether it should expand the callgraph ExpandOnly []string // a list of function prefixes to expand IdentifyOnly []string // a list of function prefixes to identify/atomify - IdentifySkip []string // a list of function prefixes to skip identify/atomify + SkipFuncPref []string // a list of function prefixes to skip identify/atomify Args []string // a list of arguments to pass to the command line of the checker } // DefaultConfig returns a default configuration for loading a module func DefaultConfig() Config { return Config{ - EntryFunc: []string{"main"}, - Expand: true, + EntryFunc: []string{"main"}, + SkipFuncPref: []string{"pthread_", "__assert_fail", "llvm.", "_VERIFIER"}, + Expand: true, } } diff --git a/module/history.go b/module/history.go index 2f5ffe6..d4dcd1b 100644 --- a/module/history.go +++ b/module/history.go @@ -31,7 +31,7 @@ type History struct { } } -// Load parses and anlyzes an LLVM IR module. +// Load parses and analyzes an LLVM IR module. func Load(fn string, cfg Config) (*History, error) { var efn = fn @@ -43,7 +43,7 @@ func Load(fn string, cfg Config) (*History, error) { } logger.Infof("Expand '%s'", fn) - if err := visitModule(mod, cfg.EntryFunc, expandVisitor(mod)); err != nil { + if err := visitModule(mod, cfg.EntryFunc, expandVisitor(mod), cfg); err != nil { return nil, err } diff --git a/module/visitor.go b/module/visitor.go index 0a265e0..921a5c4 100644 --- a/module/visitor.go +++ b/module/visitor.go @@ -28,17 +28,17 @@ type meta interface { // VisitCallback is called in every relevant intruction when visiting the module. type VisitCallback func(inst ir.Instruction, f *ir.Func, stack []meta) ir.Instruction -func (w *wrapModule) Visit(fun []string, cb VisitCallback) error { - return visitModule(w.Module, fun, cb) +func (w *wrapModule) Visit(fun []string, cb VisitCallback, cfg Config) error { + return visitModule(w.Module, fun, cb, cfg) } -func visitModule(m *ir.Module, fun []string, cb VisitCallback) error { +func visitModule(m *ir.Module, fun []string, cb VisitCallback, cfg Config) error { for _, foo := range fun { for _, f := range m.Funcs { if f.Ident() != fmt.Sprintf("@%s", foo) { continue } - v := &visitor{visited: make(map[ir.Instruction]bool)} + v := &visitor{visited: make(map[ir.Instruction]bool), skip_prefixes: cfg.SkipFuncPref} v.log("====================== START VISIT ==========================") if err := v.visit(f, []meta{f}, cb); err != nil { return err @@ -49,8 +49,9 @@ func visitModule(m *ir.Module, fun []string, cb VisitCallback) error { } type visitor struct { - dep string - visited map[ir.Instruction]bool + dep string + visited map[ir.Instruction]bool + skip_prefixes []string } func (v *visitor) enter() { @@ -79,6 +80,16 @@ func (v *visitor) logf(str string, args ...any) { logger.Print(fstr(str, args...)) } +func (v *visitor) is_callee_ignored(callee_name string) bool { + for _, prefix := range v.skip_prefixes { + // Skip "@" prefix with [1:] + if strings.Contains(callee_name[1:], prefix) { + return true + } + } + return false +} + func (v *visitor) visitCallee(inst *ir.InstCall, f *ir.Func, stack []meta, cb VisitCallback) error { callee := inst.Callee.Ident() var err error @@ -108,9 +119,7 @@ func (v *visitor) visitCallee(inst *ir.InstCall, f *ir.Func, stack []meta, cb Vi v.enter() err = v.visit(ff, append(stack, inst), cb) v.leave() - } else if !strings.Contains(callee[1:], "__assert_fail") && !strings.Contains(callee[1:], "llvm.") && - !strings.Contains(callee[1:], "_VERIFIER") && !strings.Contains(callee[1:], "pthread_") { - + } else if !v.is_callee_ignored(callee) { switch callee := inst.Callee.(type) { case *ir.InlineAsm: case *ir.InstLoad: diff --git a/module/wrap_module.go b/module/wrap_module.go index 9ee7169..f12cebe 100644 --- a/module/wrap_module.go +++ b/module/wrap_module.go @@ -29,7 +29,7 @@ func loadModule(fn string, cfg Config) (*wrapModule, error) { wmod := newWrapModule(mod) logger.Infof("Analyze '%s'", fn) - if err := wmod.Visit(cfg.EntryFunc, analyze(wmod)); err != nil { + if err := wmod.Visit(cfg.EntryFunc, analyze(wmod), cfg); err != nil { return nil, err } return wmod, nil