From 063d1761a6208b44ddd25c19e8d6a90acb886731 Mon Sep 17 00:00:00 2001 From: Joey Jiao Date: Thu, 4 Jul 2024 11:18:06 +0800 Subject: pkg/report: support to symbolize line with module+offset --- pkg/mgrconfig/load.go | 3 ++ pkg/report/linux.go | 39 +++++++++++++++++----- pkg/report/linux_test.go | 83 ++++++++++++++++++++++++++++++++++++++++------ pkg/report/report.go | 13 ++++++++ pkg/rpcserver/rpcserver.go | 7 +--- 5 files changed, 120 insertions(+), 25 deletions(-) diff --git a/pkg/mgrconfig/load.go b/pkg/mgrconfig/load.go index 05ba38a98..eb20b6b68 100644 --- a/pkg/mgrconfig/load.go +++ b/pkg/mgrconfig/load.go @@ -13,6 +13,7 @@ import ( "github.com/google/syzkaller/pkg/config" "github.com/google/syzkaller/pkg/osutil" + "github.com/google/syzkaller/pkg/vminfo" "github.com/google/syzkaller/prog" _ "github.com/google/syzkaller/sys" // most mgrconfig users want targets too "github.com/google/syzkaller/sys/targets" @@ -40,6 +41,8 @@ type Derived struct { // In this mode syz-manager does not start any VMs, but instead a user is supposed // to start syz-executor process in a VM manually. VMLess bool + + LocalModules []*vminfo.KernelModule } func LoadData(data []byte) (*Config, error) { diff --git a/pkg/report/linux.go b/pkg/report/linux.go index 596c834ce..816c40fa7 100644 --- a/pkg/report/linux.go +++ b/pkg/report/linux.go @@ -16,13 +16,14 @@ import ( "github.com/google/syzkaller/pkg/report/crash" "github.com/google/syzkaller/pkg/symbolizer" "github.com/google/syzkaller/pkg/vcs" + "github.com/google/syzkaller/pkg/vminfo" "github.com/google/syzkaller/sys/targets" ) type linux struct { *config vmlinux string - symbols map[string][]symbolizer.Symbol + symbols map[string]map[string][]symbolizer.Symbol consoleOutputRe *regexp.Regexp taskContext *regexp.Regexp cpuContext *regexp.Regexp @@ -36,16 +37,26 @@ type linux struct { } func ctorLinux(cfg *config) (reporterImpl, []string, error) { - var symbols map[string][]symbolizer.Symbol + symbols := make(map[string]map[string][]symbolizer.Symbol) vmlinux := "" if cfg.kernelObj != "" { vmlinux = filepath.Join(cfg.kernelObj, cfg.target.KernelObject) var err error symb := symbolizer.NewSymbolizer(cfg.target) - symbols, err = symb.ReadTextSymbols(vmlinux) + symbols[""], err = symb.ReadTextSymbols(vmlinux) if err != nil { return nil, nil, err } + for _, mod := range cfg.kernelModules { + if mod.Name == "" { + continue + } + ss, err := symb.ReadTextSymbols(mod.Path) + if err != nil { + continue + } + symbols[mod.Name] = ss + } } ctx := &linux{ config: cfg, @@ -405,7 +416,7 @@ func (ctx *linux) symbolize(rep *Report) error { prefix := rep.reportPrefixLen for _, line := range bytes.SplitAfter(rep.Report, []byte("\n")) { line := bytes.Clone(line) - newLine := symbolizeLine(symbFunc, ctx.symbols, ctx.vmlinux, ctx.kernelBuildSrc, line) + newLine := symbolizeLine(symbFunc, ctx.symbols, ctx.config.kernelModules, ctx.kernelBuildSrc, ctx, line) if prefix > len(symbolized) { prefix += len(newLine) - len(line) } @@ -426,7 +437,8 @@ func (ctx *linux) symbolize(rep *Report) error { } func symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error), - symbols map[string][]symbolizer.Symbol, vmlinux, strip string, line []byte) []byte { + symbols map[string]map[string][]symbolizer.Symbol, modules []*vminfo.KernelModule, strip string, + ctx *linux, line []byte) []byte { match := linuxSymbolizeRe.FindSubmatchIndex(line) if match == nil { return line @@ -440,7 +452,11 @@ func symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, err if err != nil { return line } - symb := symbols[string(fn)] + modName := "" + if match[10] != -1 && match[11] != -1 { + modName = string(line[match[10]:match[11]]) + } + symb := symbols[modName][string(fn)] if len(symb) == 0 { return line } @@ -456,7 +472,14 @@ func symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, err // But RIP lines contain the exact faulting PC. pc-- } - frames, err := symbFunc(vmlinux, pc) + var bin string + for _, mod := range modules { + if mod.Name == modName { + bin = mod.Path + break + } + } + frames, err := symbFunc(bin, pc) if err != nil || len(frames) == 0 { return line } @@ -1023,7 +1046,7 @@ var linuxStallAnchorFrames = []*regexp.Regexp{ // nolint: lll var ( - linuxSymbolizeRe = regexp.MustCompile(`(?:\[\<(?:(?:0x)?[0-9a-f]+)\>\])?[ \t]+\(?(?:[0-9]+:)?([a-zA-Z0-9_.]+)\+0x([0-9a-f]+)/0x([0-9a-f]+)\)?`) + linuxSymbolizeRe = regexp.MustCompile(`(?:\[\<(?:(?:0x)?[0-9a-f]+)\>\])?[ \t]+\(?(?:[0-9]+:)?([a-zA-Z0-9_.]+)\+0x([0-9a-f]+)/0x([0-9a-f]+)( ?\[([a-zA-Z0-9_.]+)\])?\)?`) linuxRipFrame = compile(`(?:IP|NIP|pc |PC is at):? (?:(?:[0-9]+:)?(?:{{PC}} +){0,2}{{FUNC}}|(?:[0-9]+:)?0x[0-9a-f]+|(?:[0-9]+:)?{{PC}} +\[< *\(null\)>\] +\(null\)|[0-9]+: +\(null\))`) linuxCallTrace = compile(`(?:Call (?:T|t)race:)|(?:Backtrace:)`) linuxCodeRe = regexp.MustCompile(`(?m)^\s*Code\:\s+((?:[A-Fa-f0-9\(\)\<\>]{2,8}\s*)*)\s*$`) diff --git a/pkg/report/linux_test.go b/pkg/report/linux_test.go index 258efb271..756576e98 100644 --- a/pkg/report/linux_test.go +++ b/pkg/report/linux_test.go @@ -16,6 +16,7 @@ import ( "github.com/google/syzkaller/pkg/mgrconfig" "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/pkg/symbolizer" + "github.com/google/syzkaller/pkg/vminfo" "github.com/google/syzkaller/sys/targets" ) @@ -145,21 +146,61 @@ func TestLinuxSymbolizeLine(t *testing.T) { "[] baz+0x101/0x200\n", "[] baz+0x101/0x200 baz.c:100\n", }, - } - symbols := map[string][]symbolizer.Symbol{ - "foo": { - {Addr: 0x1000000, Size: 0x190}, + // Frame format with module+offset. + { + "[ 50.419727][ T3822] baz+0x101/0x200 [beep]\n", + "[ 50.419727][ T3822] baz+0x101/0x200 baz.c:100 [beep]\n", + }, + // Frame format with module+offset for invalid module. + { + "[ 50.419727][ T3822] baz+0x101/0x200 [invalid_module]\n", + "[ 50.419727][ T3822] baz+0x101/0x200 [invalid_module]\n", }, - "do_ipv6_setsockopt.isra.7.part.3": { - {Addr: 0x2000000, Size: 0x2830}, + // Frame format with module+offset for missing symbol. + { + "[ 50.419727][ T3822] missing_symbol+0x101/0x200 [beep]\n", + "[ 50.419727][ T3822] missing_symbol+0x101/0x200 [beep]\n", }, - "baz": { - {Addr: 0x3000000, Size: 0x100}, - {Addr: 0x4000000, Size: 0x200}, - {Addr: 0x5000000, Size: 0x300}, + // Frame format with module+offset for invalid offset. + { + "[ 50.419727][ T3822] baz+0x300/0x200 [beep]\n", + "[ 50.419727][ T3822] baz+0x300/0x200 [beep]\n", + }, + } + symbols := map[string]map[string][]symbolizer.Symbol{ + "": { + "foo": { + {Addr: 0x1000000, Size: 0x190}, + }, + "do_ipv6_setsockopt.isra.7.part.3": { + {Addr: 0x2000000, Size: 0x2830}, + }, + "baz": { + {Addr: 0x3000000, Size: 0x100}, + {Addr: 0x4000000, Size: 0x200}, + {Addr: 0x5000000, Size: 0x300}, + }, + }, + "beep": { + "baz": { + {Addr: 0x4000000, Size: 0x200}, + }, }, } symb := func(bin string, pc uint64) ([]symbolizer.Frame, error) { + if bin == "beep" { + switch pc { + case 0x4000100: + return []symbolizer.Frame{ + { + File: "/linux/baz.c", + Line: 100, + }, + }, nil + default: + return nil, fmt.Errorf("unknown pc 0x%x", pc) + } + } if bin != "vmlinux" { return nil, fmt.Errorf("unknown pc 0x%x", pc) } @@ -228,9 +269,29 @@ func TestLinuxSymbolizeLine(t *testing.T) { return nil, fmt.Errorf("unknown pc 0x%x", pc) } } + modules := []*vminfo.KernelModule{ + { + Name: "", + Path: "vmlinux", + }, + { + Name: "beep", + Path: "beep", + }, + } + + cfg := &config{ + kernelObj: "/linux", + kernelModules: modules, + } + ctx := &linux{ + config: cfg, + vmlinux: "vmlinux", + symbols: symbols, + } for i, test := range tests { t.Run(fmt.Sprint(i), func(t *testing.T) { - result := symbolizeLine(symb, symbols, "vmlinux", "/linux", []byte(test.line)) + result := symbolizeLine(symb, symbols, modules, "/linux", ctx, []byte(test.line)) if test.result != string(result) { t.Errorf("want %q\n\t get %q", test.result, string(result)) } diff --git a/pkg/report/report.go b/pkg/report/report.go index b211a140e..97b2e6aed 100644 --- a/pkg/report/report.go +++ b/pkg/report/report.go @@ -11,9 +11,11 @@ import ( "regexp" "strings" + "github.com/google/syzkaller/pkg/cover/backend" "github.com/google/syzkaller/pkg/mgrconfig" "github.com/google/syzkaller/pkg/report/crash" "github.com/google/syzkaller/pkg/vcs" + "github.com/google/syzkaller/pkg/vminfo" "github.com/google/syzkaller/sys/targets" ) @@ -82,6 +84,15 @@ const unspecifiedType = crash.Type("UNSPECIFIED") // NewReporter creates reporter for the specified OS/Type. func NewReporter(cfg *mgrconfig.Config) (*Reporter, error) { + var localModules []*vminfo.KernelModule + if cfg.KernelObj != "" { + var err error + localModules, err = backend.DiscoverModules(cfg.SysTarget, cfg.KernelObj, cfg.ModuleObj) + if err != nil { + return nil, err + } + cfg.LocalModules = localModules + } typ := cfg.TargetOS if cfg.Type == targets.GVisor || cfg.Type == targets.Starnix { typ = cfg.Type @@ -105,6 +116,7 @@ func NewReporter(cfg *mgrconfig.Config) (*Reporter, error) { kernelBuildSrc: cfg.KernelBuildSrc, kernelObj: cfg.KernelObj, ignores: ignores, + kernelModules: localModules, } rep, suppressions, err := ctor(config) if err != nil { @@ -156,6 +168,7 @@ type config struct { kernelBuildSrc string kernelObj string ignores []*regexp.Regexp + kernelModules []*vminfo.KernelModule } type fn func(cfg *config) (reporterImpl, []string, error) diff --git a/pkg/rpcserver/rpcserver.go b/pkg/rpcserver/rpcserver.go index 57abafdc9..0d50695f6 100644 --- a/pkg/rpcserver/rpcserver.go +++ b/pkg/rpcserver/rpcserver.go @@ -86,7 +86,6 @@ type Server struct { } func New(cfg *mgrconfig.Config, mgr Manager, debug bool) (*Server, error) { - var modules []*vminfo.KernelModule var pcBase uint64 if cfg.KernelObj != "" { var err error @@ -94,10 +93,6 @@ func New(cfg *mgrconfig.Config, mgr Manager, debug bool) (*Server, error) { if err != nil { return nil, err } - modules, err = backend.DiscoverModules(cfg.SysTarget, cfg.KernelObj, cfg.ModuleObj) - if err != nil { - return nil, err - } } sandbox, err := flatrpc.SandboxToFlags(cfg.Sandbox) if err != nil { @@ -128,7 +123,7 @@ func New(cfg *mgrconfig.Config, mgr Manager, debug bool) (*Server, error) { Procs: cfg.Procs, Slowdown: cfg.Timeouts.Slowdown, pcBase: pcBase, - localModules: modules, + localModules: cfg.LocalModules, }, mgr) } -- cgit mrf-deployment