diff --git a/pkg/cover/backend/backend.go b/pkg/cover/backend/backend.go index 119c8f369c36..8c088070c476 100644 --- a/pkg/cover/backend/backend.go +++ b/pkg/cover/backend/backend.go @@ -67,7 +67,7 @@ type SecRange struct { const LineEnd = 1 << 30 func Make(target *targets.Target, vm string, kernelDirs *mgrconfig.KernelDirs, splitBuild bool, - moduleObj []string, modules []*vminfo.KernelModule) (*Impl, error) { + moduleObj []string, modules []*vminfo.KernelModule, cleanRules []string) (*Impl, error) { if kernelDirs.Obj == "" { return nil, fmt.Errorf("kernel obj directory is not specified") } @@ -84,7 +84,7 @@ func Make(target *targets.Target, vm string, kernelDirs *mgrconfig.KernelDirs, s // details. delimiters = []string{"/aosp/", "/private/"} } - return makeELF(target, kernelDirs, delimiters, moduleObj, modules) + return makeELF(target, kernelDirs, delimiters, moduleObj, modules, cleanRules) } func GetPCBase(cfg *mgrconfig.Config) (uint64, error) { diff --git a/pkg/cover/backend/dwarf.go b/pkg/cover/backend/dwarf.go index 2ace50ce6135..147cbbc3d007 100644 --- a/pkg/cover/backend/dwarf.go +++ b/pkg/cover/backend/dwarf.go @@ -37,6 +37,7 @@ type dwarfParams struct { readModuleCoverPoints func(*targets.Target, *vminfo.KernelModule, *symbolInfo) ([2][]uint64, error) readTextRanges func(*vminfo.KernelModule) ([]pcRange, []*CompileUnit, error) getCompilerVersion func(string) string + cleanRules []string } type Arch struct { @@ -141,6 +142,7 @@ func makeDWARFUnsafe(params *dwarfParams) (*Impl, error) { kernelDirs := params.kernelDirs splitBuildDelimiters := params.splitBuildDelimiters modules := params.hostModules + cleanRules := params.cleanRules // Here and below index 0 refers to coverage callbacks (__sanitizer_cov_trace_pc(_guard)) // and index 1 refers to comparison callbacks (__sanitizer_cov_trace_cmp*). @@ -228,7 +230,7 @@ func makeDWARFUnsafe(params *dwarfParams) (*Impl, error) { continue // drop the unit } // TODO: objDir won't work for out-of-tree modules. - unit.Name, unit.Path = CleanPath(unit.Name, kernelDirs, splitBuildDelimiters) + unit.Name, unit.Path = CleanPath(unit.Name, kernelDirs, splitBuildDelimiters, cleanRules) allUnits[nunit] = unit nunit++ } @@ -241,7 +243,7 @@ func makeDWARFUnsafe(params *dwarfParams) (*Impl, error) { Units: allUnits, Symbols: allSymbols, Symbolize: func(pcs map[*vminfo.KernelModule][]uint64) ([]*Frame, error) { - return symbolize(target, &interner, kernelDirs, splitBuildDelimiters, pcs) + return symbolize(target, &interner, kernelDirs, splitBuildDelimiters, pcs, cleanRules) }, CallbackPoints: allCoverPoints[0], PreciseCoverage: preciseCoverage, @@ -399,7 +401,7 @@ func readTextRanges(debugInfo *dwarf.Data, module *vminfo.KernelModule, pcFix pc } func symbolizeModule(target *targets.Target, interner *symbolizer.Interner, kernelDirs *mgrconfig.KernelDirs, - splitBuildDelimiters []string, mod *vminfo.KernelModule, pcs []uint64) ([]*Frame, error) { + splitBuildDelimiters []string, mod *vminfo.KernelModule, pcs []uint64, cleanRules []string) ([]*Frame, error) { procs := min(runtime.GOMAXPROCS(0)/2, len(pcs)/1000) const ( minProcs = 1 @@ -450,7 +452,7 @@ func symbolizeModule(target *targets.Target, interner *symbolizer.Interner, kern err0 = res.err } for _, frame := range res.frames { - name, path := CleanPath(frame.File, kernelDirs, splitBuildDelimiters) + name, path := CleanPath(frame.File, kernelDirs, splitBuildDelimiters, cleanRules) pc := frame.PC if mod.Name != "" { pc = frame.PC + mod.Addr @@ -478,7 +480,7 @@ func symbolizeModule(target *targets.Target, interner *symbolizer.Interner, kern } func symbolize(target *targets.Target, interner *symbolizer.Interner, kernelDirs *mgrconfig.KernelDirs, - splitBuildDelimiters []string, pcs map[*vminfo.KernelModule][]uint64) ([]*Frame, error) { + splitBuildDelimiters []string, pcs map[*vminfo.KernelModule][]uint64, cleanRules []string) ([]*Frame, error) { var frames []*Frame type frameResult struct { frames []*Frame @@ -487,7 +489,7 @@ func symbolize(target *targets.Target, interner *symbolizer.Interner, kernelDirs frameC := make(chan frameResult, len(pcs)) for mod, pcs1 := range pcs { go func(mod *vminfo.KernelModule, pcs []uint64) { - frames, err := symbolizeModule(target, interner, kernelDirs, splitBuildDelimiters, mod, pcs) + frames, err := symbolizeModule(target, interner, kernelDirs, splitBuildDelimiters, mod, pcs, cleanRules) frameC <- frameResult{frames: frames, err: err} }(mod, pcs1) } @@ -582,9 +584,22 @@ func cleanPathAndroid(path, srcDir string, delimiters []string, existFn func(str return "", "" } -func CleanPath(path string, kernelDirs *mgrconfig.KernelDirs, splitBuildDelimiters []string) (string, string) { +func CleanPath(path string, kernelDirs *mgrconfig.KernelDirs, splitBuildDelimiters, + cleanRules []string) (string, string) { filename := "" + // Assume out-of-tree modules need to apply clean rules. + for _, rule := range cleanRules { + tokens := strings.Split(rule, ":") + old := tokens[0] + new := tokens[1] + if strings.HasPrefix(path, old) { + path = strings.Replace(path, old, new, 1) + filename = filepath.Join(kernelDirs.Src, path) + return strings.TrimLeft(filepath.Clean(path), "/\\"), filename + } + } + path = filepath.Clean(path) aname, apath := cleanPathAndroid(path, kernelDirs.Src, splitBuildDelimiters, osutil.IsExist) if aname != "" { diff --git a/pkg/cover/backend/elf.go b/pkg/cover/backend/elf.go index 88b8302c4f2b..ed2c975c44bc 100644 --- a/pkg/cover/backend/elf.go +++ b/pkg/cover/backend/elf.go @@ -18,7 +18,7 @@ import ( ) func makeELF(target *targets.Target, kernelDirs *mgrconfig.KernelDirs, splitBuildDelimiters, moduleObj []string, - hostModules []*vminfo.KernelModule) (*Impl, error) { + hostModules []*vminfo.KernelModule, cleanRules []string) (*Impl, error) { return makeDWARF(&dwarfParams{ target: target, kernelDirs: kernelDirs, @@ -30,6 +30,7 @@ func makeELF(target *targets.Target, kernelDirs *mgrconfig.KernelDirs, splitBuil readModuleCoverPoints: elfReadModuleCoverPoints, readTextRanges: elfReadTextRanges, getCompilerVersion: elfGetCompilerVersion, + cleanRules: cleanRules, }) } diff --git a/pkg/cover/report.go b/pkg/cover/report.go index 2db00df6d38c..65a9bf5d3b9e 100644 --- a/pkg/cover/report.go +++ b/pkg/cover/report.go @@ -34,7 +34,8 @@ func GetPCBase(cfg *mgrconfig.Config) (uint64, error) { } func MakeReportGenerator(cfg *mgrconfig.Config, modules []*vminfo.KernelModule) (*ReportGenerator, error) { - impl, err := backend.Make(cfg.SysTarget, cfg.Type, cfg.KernelDirs(), cfg.AndroidSplitBuild, cfg.ModuleObj, modules) + impl, err := backend.Make(cfg.SysTarget, cfg.Type, cfg.KernelDirs(), cfg.AndroidSplitBuild, cfg.ModuleObj, + modules, cfg.CleanRules) if err != nil { return nil, err } diff --git a/pkg/mgrconfig/config.go b/pkg/mgrconfig/config.go index 6bf88c5742b9..235323dde7c9 100644 --- a/pkg/mgrconfig/config.go +++ b/pkg/mgrconfig/config.go @@ -230,6 +230,17 @@ type Config struct { // Implementation details beyond this point. Filled after parsing. Derived `json:"-"` + + // cleanPath rules like "old_path:new_path" which replaces old_path by new_path + // it's especially useful for out-of-tree kernel modules symbol path + // old_path is relative path to kernel_src, for example in Android S + // "clean_rules" : [ + // "/proc/self/cwd/common:kernel_platform/common" + // ] + // in cleanPath function, if path in elf is /proc/self/cwd/common/drivers/something.c + // then path will be changed to kernel_platform/common/drivers/something.c, + // and filename will be kernel_src + /kernel_platform/common/drivers/something.c + CleanRules []string `json:"clean_rules,omitempty"` } // These options are not guaranteed to be backward/forward compatible and diff --git a/pkg/report/linux.go b/pkg/report/linux.go index 598543e6bdad..4ea20efc7833 100644 --- a/pkg/report/linux.go +++ b/pkg/report/linux.go @@ -487,7 +487,7 @@ func symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, err } var symbolized []byte for _, frame := range frames { - path, _ := backend.CleanPath(frame.File, &ctx.kernelDirs, nil) + path, _ := backend.CleanPath(frame.File, &ctx.kernelDirs, nil, ctx.config.cleanRules) info := fmt.Sprintf(" %v:%v", path, frame.Line) modified := append([]byte{}, line...) if buildID != "" { diff --git a/pkg/report/report.go b/pkg/report/report.go index d91bf35aae9e..b5dd3a1a9ba5 100644 --- a/pkg/report/report.go +++ b/pkg/report/report.go @@ -122,6 +122,7 @@ func NewReporter(cfg *mgrconfig.Config) (*Reporter, error) { kernelDirs: *cfg.KernelDirs(), ignores: ignores, kernelModules: localModules, + cleanRules: cfg.CleanRules, } rep, suppressions, err := ctor(config) if err != nil { @@ -172,6 +173,7 @@ type config struct { kernelDirs mgrconfig.KernelDirs ignores []*regexp.Regexp kernelModules []*vminfo.KernelModule + cleanRules []string } type fn func(cfg *config) (reporterImpl, []string, error)