aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/cover/backend/backend.go19
-rw-r--r--pkg/cover/backend/elf.go360
-rw-r--r--pkg/cover/report.go34
-rw-r--r--pkg/cover/report_test.go2
-rw-r--r--pkg/mgrconfig/config.go18
-rw-r--r--pkg/symbolizer/symbolizer.go14
-rw-r--r--pkg/symbolizer/symbolizer_test.go13
7 files changed, 339 insertions, 121 deletions
diff --git a/pkg/cover/backend/backend.go b/pkg/cover/backend/backend.go
index 22823021d..bbb526865 100644
--- a/pkg/cover/backend/backend.go
+++ b/pkg/cover/backend/backend.go
@@ -9,11 +9,17 @@ import (
"github.com/google/syzkaller/sys/targets"
)
+type KernelModule struct {
+ Name string `json:"name"`
+ Path string `json:"path"`
+ Addr uint64 `json:"addr"`
+}
+
type Impl struct {
Units []*CompileUnit
Symbols []*Symbol
Frames []Frame
- Symbolize func(pcs []uint64) ([]Frame, error)
+ Symbolize func(pcs []uint64, modules []KernelModule) ([]Frame, error)
RestorePC func(pc uint32) uint64
}
@@ -38,9 +44,10 @@ type ObjectUnit struct {
}
type Frame struct {
- PC uint64
- Name string
- Path string
+ Module string
+ PC uint64
+ Name string
+ Path string
Range
}
@@ -53,12 +60,12 @@ type Range struct {
const LineEnd = 1 << 30
-func Make(target *targets.Target, vm, objDir, srcDir, buildDir string) (*Impl, error) {
+func Make(target *targets.Target, vm, objDir, srcDir, buildDir string, modules []KernelModule) (*Impl, error) {
if objDir == "" {
return nil, fmt.Errorf("kernel obj directory is not specified")
}
if vm == "gvisor" {
return makeGvisor(target, objDir, srcDir, buildDir)
}
- return makeELF(target, objDir, srcDir, buildDir)
+ return makeELF(target, objDir, srcDir, buildDir, modules)
}
diff --git a/pkg/cover/backend/elf.go b/pkg/cover/backend/elf.go
index eba6fd7ca..c1eca5211 100644
--- a/pkg/cover/backend/elf.go
+++ b/pkg/cover/backend/elf.go
@@ -16,74 +16,115 @@ import (
"sort"
"strconv"
"strings"
+ "unsafe"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/pkg/symbolizer"
"github.com/google/syzkaller/sys/targets"
)
-func makeELF(target *targets.Target, objDir, srcDir, buildDir string) (*Impl, error) {
- kernelObject := filepath.Join(objDir, target.KernelObject)
- file, err := elf.Open(kernelObject)
- if err != nil {
- return nil, err
- }
- // Here and below index 0 refers to coverage callbacks (__sanitizer_cov_trace_pc)
- // and index 1 refers to comparison callbacks (__sanitizer_cov_trace_cmp*).
- var coverPoints [2][]uint64
- var symbols []*Symbol
- var textAddr uint64
- errc := make(chan error, 1)
- go func() {
- symbols1, textAddr1, tracePC, traceCmp, err := readSymbols(file)
+const KERNEL string = "kernel"
+
+func makeELF(target *targets.Target, objDir, srcDir, buildDir string, modules []KernelModule) (*Impl, error) {
+ var allCoverPoints [2][]uint64
+ var allSymbols []*Symbol
+ var allRanges []pcRange
+ var allUnits []*CompileUnit
+ var kernelTextAddr uint64
+
+ for i := len(modules) - 1; i >= 0; i-- {
+ module := modules[i]
+ file, err := elf.Open(module.Path)
if err != nil {
+ return nil, err
+ }
+
+ // Here and below index 0 refers to coverage callbacks (__sanitizer_cov_trace_pc)
+ // and index 1 refers to comparison callbacks (__sanitizer_cov_trace_cmp*).
+ var coverPoints [2][]uint64
+ var symbols []*Symbol
+ var textAddr uint64
+ errc := make(chan error, 1)
+ go func() {
+ symbols1, textAddr1, tracePC, traceCmp, err := readSymbols(file, module)
+ if err != nil {
+ errc <- err
+ return
+ }
+ symbols, textAddr = symbols1, textAddr1
+ if target.OS == targets.FreeBSD {
+ // On FreeBSD .text address in ELF is 0, but .text is actually mapped at 0xffffffff.
+ textAddr = ^uint64(0)
+ }
+ if module.Name == KERNEL {
+ kernelTextAddr = textAddr
+ }
+ if target.Arch == targets.AMD64 {
+ if module.Name == KERNEL {
+ coverPoints, err = readCoverPoints(file, tracePC, traceCmp, module)
+ } else {
+ coverPoints, err = readCoverPoints(file, 0, nil, module)
+ }
+ } else {
+ coverPoints, err = objdump(target, module.Path)
+ if module.Name != KERNEL {
+ for i, pcs := range coverPoints {
+ for j, pc := range pcs {
+ coverPoints[i][j] = module.Addr + pc
+ }
+ }
+ }
+ }
errc <- err
- return
+ }()
+ ranges, units, err := readTextRanges(file, module)
+ if err != nil {
+ return nil, err
}
- symbols, textAddr = symbols1, textAddr1
- if target.OS == targets.FreeBSD {
- // On FreeBSD .text address in ELF is 0, but .text is actually mapped at 0xffffffff.
- textAddr = ^uint64(0)
+ if err := <-errc; err != nil {
+ return nil, err
}
- if target.Arch == targets.AMD64 {
- coverPoints, err = readCoverPoints(file, tracePC, traceCmp)
- } else {
- coverPoints, err = objdump(target, kernelObject)
+
+ if module.Name == KERNEL && len(coverPoints[0]) == 0 {
+ return nil, fmt.Errorf("%v doesn't contain coverage callbacks (set CONFIG_KCOV=y)", module.Path)
}
- errc <- err
- }()
- ranges, units, err := readTextRanges(file)
- if err != nil {
- return nil, err
- }
- if err := <-errc; err != nil {
- return nil, err
- }
- if len(coverPoints[0]) == 0 {
- return nil, fmt.Errorf("%v doesn't contain coverage callbacks (set CONFIG_KCOV=y)", kernelObject)
+
+ allCoverPoints[0] = append(allCoverPoints[0], coverPoints[0]...)
+ allCoverPoints[1] = append(allCoverPoints[1], coverPoints[1]...)
+ allSymbols = append(allSymbols, symbols...)
+ allRanges = append(allRanges, ranges...)
+ allUnits = append(allUnits, units...)
}
- symbols = buildSymbols(symbols, ranges, coverPoints)
+
+ sort.Slice(allSymbols, func(i, j int) bool {
+ return allSymbols[i].Start < allSymbols[j].Start
+ })
+ sort.Slice(allRanges, func(i, j int) bool {
+ return allRanges[i].start < allRanges[j].start
+ })
+
+ allSymbols = buildSymbols(allSymbols, allRanges, allCoverPoints)
nunit := 0
- for _, unit := range units {
+ for _, unit := range allUnits {
if len(unit.PCs) == 0 {
continue // drop the unit
}
unit.Name, unit.Path = cleanPath(unit.Name, objDir, srcDir, buildDir)
- units[nunit] = unit
+ allUnits[nunit] = unit
nunit++
}
- units = units[:nunit]
- if len(symbols) == 0 || len(units) == 0 {
+ allUnits = allUnits[:nunit]
+ if len(allSymbols) == 0 || len(allUnits) == 0 {
return nil, fmt.Errorf("failed to parse DWARF (set CONFIG_DEBUG_INFO=y?)")
}
impl := &Impl{
- Units: units,
- Symbols: symbols,
- Symbolize: func(pcs []uint64) ([]Frame, error) {
- return symbolize(target, objDir, srcDir, buildDir, kernelObject, pcs)
+ Units: allUnits,
+ Symbols: allSymbols,
+ Symbolize: func(pcs []uint64, modules []KernelModule) ([]Frame, error) {
+ return symbolize(target, objDir, srcDir, buildDir, modules, pcs)
},
RestorePC: func(pc uint32) uint64 {
- return PreviousInstructionPC(target, RestorePC(pc, uint32(textAddr>>32)))
+ return PreviousInstructionPC(target, RestorePC(pc, uint32(kernelTextAddr>>32)))
},
}
return impl, nil
@@ -155,7 +196,7 @@ func buildSymbols(symbols []*Symbol, ranges []pcRange, coverPoints [2][]uint64)
return symbols
}
-func readSymbols(file *elf.File) ([]*Symbol, uint64, uint64, map[uint64]bool, error) {
+func readSymbols(file *elf.File, module KernelModule) ([]*Symbol, uint64, uint64, map[uint64]bool, error) {
text := file.Section(".text")
if text == nil {
return nil, 0, 0, nil, fmt.Errorf("no .text section in the object file")
@@ -171,14 +212,20 @@ func readSymbols(file *elf.File) ([]*Symbol, uint64, uint64, map[uint64]bool, er
if symb.Value < text.Addr || symb.Value+symb.Size > text.Addr+text.Size {
continue
}
+ var start uint64
+ if module.Name == KERNEL {
+ start = symb.Value
+ } else {
+ start = symb.Value + module.Addr
+ }
symbols = append(symbols, &Symbol{
ObjectUnit: ObjectUnit{
Name: symb.Name,
},
- Start: symb.Value,
- End: symb.Value + symb.Size,
+ Start: start,
+ End: start + symb.Size,
})
- if strings.HasPrefix(symb.Name, "__sanitizer_cov_trace_") {
+ if module.Name == KERNEL && strings.HasPrefix(symb.Name, "__sanitizer_cov_trace_") {
if symb.Name == "__sanitizer_cov_trace_pc" {
tracePC = symb.Value
} else {
@@ -186,7 +233,7 @@ func readSymbols(file *elf.File) ([]*Symbol, uint64, uint64, map[uint64]bool, er
}
}
}
- if tracePC == 0 {
+ if module.Name == KERNEL && tracePC == 0 {
return nil, 0, 0, nil, fmt.Errorf("no __sanitizer_cov_trace_pc symbol in the object file")
}
sort.Slice(symbols, func(i, j int) bool {
@@ -195,7 +242,7 @@ func readSymbols(file *elf.File) ([]*Symbol, uint64, uint64, map[uint64]bool, er
return symbols, text.Addr, tracePC, traceCmp, nil
}
-func readTextRanges(file *elf.File) ([]pcRange, []*CompileUnit, error) {
+func readTextRanges(file *elf.File, module KernelModule) ([]pcRange, []*CompileUnit, error) {
text := file.Section(".text")
if text == nil {
return nil, nil, fmt.Errorf("no .text section in the object file")
@@ -249,7 +296,11 @@ func readTextRanges(file *elf.File) ([]pcRange, []*CompileUnit, error) {
}
}
}
- ranges = append(ranges, pcRange{r[0], r[1], unit})
+ if module.Name == KERNEL {
+ ranges = append(ranges, pcRange{r[0], r[1], unit})
+ } else {
+ ranges = append(ranges, pcRange{r[0] + module.Addr, r[1] + module.Addr, unit})
+ }
}
r.SkipChildren()
}
@@ -259,7 +310,36 @@ func readTextRanges(file *elf.File) ([]pcRange, []*CompileUnit, error) {
return ranges, units, nil
}
-func symbolize(target *targets.Target, objDir, srcDir, buildDir, obj string, pcs []uint64) ([]Frame, error) {
+func groupPCsByModule(pcs []uint64, modules []KernelModule) map[string][]uint64 {
+ groupPCs := make(map[string][]uint64)
+ for _, module := range modules {
+ groupPCs[module.Name] = make([]uint64, 0)
+ }
+ for _, pc := range pcs {
+ if pc > modules[0].Addr {
+ if modules[0].Name == KERNEL {
+ groupPCs[modules[0].Name] = append(groupPCs[modules[0].Name], pc)
+ } else {
+ groupPCs[modules[0].Name] = append(groupPCs[modules[0].Name], pc-modules[0].Addr)
+ }
+ } else {
+ for i := 0; i < len(modules)-1; i++ {
+ if pc < modules[i].Addr && pc >= modules[i+1].Addr {
+ if modules[i+1].Name == KERNEL {
+ groupPCs[modules[i+1].Name] = append(groupPCs[modules[i+1].Name], pc)
+ } else {
+ groupPCs[modules[i+1].Name] = append(groupPCs[modules[i+1].Name], pc-modules[i+1].Addr)
+ }
+ break
+ }
+ }
+ }
+ }
+ return groupPCs
+}
+
+func symbolize(target *targets.Target, objDir, srcDir, buildDir string,
+ modules []KernelModule, pcs []uint64) ([]Frame, error) {
procs := runtime.GOMAXPROCS(0) / 2
if need := len(pcs) / 1000; procs > need {
procs = need
@@ -280,31 +360,46 @@ func symbolize(target *targets.Target, objDir, srcDir, buildDir, obj string, pcs
err error
}
symbolizerC := make(chan symbolizerResult, procs)
- pcchan := make(chan []uint64, procs)
- for p := 0; p < procs; p++ {
- go func() {
- symb := symbolizer.NewSymbolizer(target)
- defer symb.Close()
- var res symbolizerResult
- for pcs := range pcchan {
- frames, err := symb.SymbolizeArray(obj, pcs)
- if err != nil {
- res.err = fmt.Errorf("failed to symbolize: %v", err)
+
+ groupPCs := groupPCsByModule(pcs, modules)
+ for name, pcs := range groupPCs {
+ if len(pcs) == 0 {
+ continue
+ }
+ var module KernelModule
+ for _, m := range modules {
+ if name == m.Name {
+ module = m
+ break
+ }
+ }
+ pcchan := make(chan []uint64, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ symb := symbolizer.NewSymbolizer(target)
+ defer symb.Close()
+ var res symbolizerResult
+ for pcs := range pcchan {
+ frames, err := symb.SymbolizeArray(module.Name, module.Path, pcs)
+ if err != nil {
+ res.err = fmt.Errorf("failed to symbolize: %v", err)
+ }
+ res.frames = append(res.frames, frames...)
}
- res.frames = append(res.frames, frames...)
+ symbolizerC <- res
+ }()
+ }
+ for i := 0; i < len(pcs); {
+ end := i + 100
+ if end > len(pcs) {
+ end = len(pcs)
}
- symbolizerC <- res
- }()
- }
- for i := 0; i < len(pcs); {
- end := i + 100
- if end > len(pcs) {
- end = len(pcs)
+ pcchan <- pcs[i:end]
+ i = end
}
- pcchan <- pcs[i:end]
- i = end
+ close(pcchan)
}
- close(pcchan)
+
var err0 error
var frames []Frame
for p := 0; p < procs; p++ {
@@ -315,9 +410,10 @@ func symbolize(target *targets.Target, objDir, srcDir, buildDir, obj string, pcs
for _, frame := range res.frames {
name, path := cleanPath(frame.File, objDir, srcDir, buildDir)
frames = append(frames, Frame{
- PC: frame.PC,
- Name: name,
- Path: path,
+ Module: frame.Module,
+ PC: frame.PC,
+ Name: name,
+ Path: path,
Range: Range{
StartLine: frame.Line,
StartCol: 0,
@@ -333,35 +429,99 @@ func symbolize(target *targets.Target, objDir, srcDir, buildDir, obj string, pcs
return frames, nil
}
-// readCoverPoints finds all coverage points (calls of __sanitizer_cov_trace_pc) in the object file.
-// Currently it is amd64-specific: looks for e8 opcode and correct offset.
-// Running objdump on the whole object file is too slow.
-func readCoverPoints(file *elf.File, tracePC uint64, traceCmp map[uint64]bool) ([2][]uint64, error) {
- var pcs [2][]uint64
- text := file.Section(".text")
- if text == nil {
- return pcs, fmt.Errorf("no .text section in the object file")
+func getRelocations(file *elf.File) ([]elf.Rela64, error) {
+ var allRels []elf.Rela64
+
+ for _, s := range file.Sections {
+ if s.Type == 4 {
+ var rel elf.Rela64
+ r := s.Open()
+ rels := make([]elf.Rela64, s.Size/uint64(unsafe.Sizeof(rel)))
+ if err := binary.Read(r, binary.LittleEndian, rels); err != nil {
+ return allRels, err
+ }
+ allRels = append(allRels, rels...)
+ }
+ }
+ return allRels, nil
+}
+
+func getRelSymbolName(file *elf.File, index uint32) (string, error) {
+ symbols, err := file.Symbols()
+ if err != nil {
+ return "", err
}
- data, err := text.Data()
+ if uint64(index-1) < uint64(len(symbols)) {
+ return symbols[index-1].Name, nil
+ }
+ return "", fmt.Errorf("out of array access index")
+}
+
+func getCovRels(file *elf.File) ([2][]elf.Rela64, error) {
+ var rRels [2][]elf.Rela64
+ rels, err := getRelocations(file)
if err != nil {
- return pcs, fmt.Errorf("failed to read .text: %v", err)
+ return rRels, err
}
+ for _, rel := range rels {
+ name, err := getRelSymbolName(file, elf.R_SYM64(rel.Info))
+ if err != nil {
+ return rRels, err
+ }
+ if strings.Contains(name, "__sanitizer_cov_trace_pc") {
+ rRels[0] = append(rRels[0], rel)
+ } else if strings.Contains(name, "__sanitizer_cov_trace_") {
+ rRels[1] = append(rRels[1], rel)
+ }
+ }
+ return rRels, nil
+}
+
+// readCoverPoints finds all coverage points (calls of __sanitizer_cov_trace_*) in the object file.
+// Currently it is amd64-specific: looks for e8 opcode and correct offset.
+// Running objdump on the whole object file is too slow.
+func readCoverPoints(file *elf.File, tracePC uint64, traceCmp map[uint64]bool,
+ module KernelModule) ([2][]uint64, error) {
+ var pcs [2][]uint64
const callLen = 5
- end := len(data) - callLen + 1
- for i := 0; i < end; i++ {
- pos := bytes.IndexByte(data[i:end], 0xe8)
- if pos == -1 {
- break
+ if module.Name == KERNEL {
+ text := file.Section(".text")
+ if text == nil {
+ return pcs, fmt.Errorf("no .text section in the object file")
}
- pos += i
- i = pos
- off := uint64(int64(int32(binary.LittleEndian.Uint32(data[pos+1:]))))
- pc := text.Addr + uint64(pos)
- target := pc + off + callLen
- if target == tracePC {
- pcs[0] = append(pcs[0], pc)
- } else if traceCmp[target] {
- pcs[1] = append(pcs[1], pc)
+ data, err := text.Data()
+ if err != nil {
+ return pcs, fmt.Errorf("failed to read .text: %v", err)
+ }
+ end := len(data) - callLen + 1
+ for i := 0; i < end; i++ {
+ pos := bytes.IndexByte(data[i:end], 0xe8)
+ if pos == -1 {
+ break
+ }
+ pos += i
+ i = pos
+ off := uint64(int64(int32(binary.LittleEndian.Uint32(data[pos+1:]))))
+ pc := text.Addr + uint64(pos)
+ target := pc + off + callLen
+ if target == tracePC {
+ pcs[0] = append(pcs[0], pc)
+ } else if traceCmp[target] {
+ pcs[1] = append(pcs[1], pc)
+ }
+ }
+ } else {
+ _ = tracePC
+ _ = traceCmp
+ rels, err := getCovRels(file)
+ if err != nil {
+ return pcs, err
+ }
+ for _, rel := range rels[0] {
+ pcs[0] = append(pcs[0], module.Addr+rel.Off-1)
+ }
+ for _, rel := range rels[1] {
+ pcs[1] = append(pcs[1], module.Addr+rel.Off-1)
}
}
return pcs, nil
diff --git a/pkg/cover/report.go b/pkg/cover/report.go
index d8f2115e3..bd2c25e66 100644
--- a/pkg/cover/report.go
+++ b/pkg/cover/report.go
@@ -5,6 +5,7 @@ package cover
import (
"fmt"
+ "path/filepath"
"sort"
"github.com/google/syzkaller/pkg/cover/backend"
@@ -17,6 +18,7 @@ type ReportGenerator struct {
objDir string
buildDir string
subsystem []Subsystem
+ modules []backend.KernelModule
*backend.Impl
}
@@ -28,8 +30,18 @@ type Prog struct {
var RestorePC = backend.RestorePC
func MakeReportGenerator(target *targets.Target, vm, objDir, srcDir, buildDir string,
- subsystem []Subsystem) (*ReportGenerator, error) {
- impl, err := backend.Make(target, vm, objDir, srcDir, buildDir)
+ subsystem []Subsystem, modules []backend.KernelModule) (*ReportGenerator, error) {
+ kernelObject := filepath.Join(objDir, target.KernelObject)
+ modules = append(modules, backend.KernelModule{
+ Name: "kernel",
+ Addr: 0,
+ Path: kernelObject,
+ })
+ sort.Slice(modules, func(i, j int) bool {
+ return modules[i].Addr > modules[j].Addr
+ })
+
+ impl, err := backend.Make(target, vm, objDir, srcDir, buildDir, modules)
if err != nil {
return nil, err
}
@@ -43,6 +55,7 @@ func MakeReportGenerator(target *targets.Target, vm, objDir, srcDir, buildDir st
objDir: objDir,
buildDir: buildDir,
subsystem: subsystem,
+ modules: modules,
Impl: impl,
}
return rg, nil
@@ -94,7 +107,20 @@ func (rg *ReportGenerator) prepareFileMap(progs []Prog) (map[string]*file, error
for _, frame := range rg.Frames {
f := getFile(files, frame.Name, frame.Path)
ln := f.lines[frame.StartLine]
- coveredBy := progPCs[frame.PC]
+ var pc uint64
+ if frame.Module == backend.KERNEL {
+ pc = frame.PC
+ } else {
+ idx := 0
+ for i, module := range rg.modules {
+ if module.Name == frame.Module {
+ idx = i
+ break
+ }
+ }
+ pc = frame.PC + rg.modules[idx].Addr
+ }
+ coveredBy := progPCs[pc]
if len(coveredBy) == 0 {
f.uncovered = append(f.uncovered, frame.Range)
continue
@@ -175,7 +201,7 @@ func (rg *ReportGenerator) lazySymbolize(progs []Prog) error {
if len(pcs) == 0 {
return nil
}
- frames, err := rg.Symbolize(pcs)
+ frames, err := rg.Symbolize(pcs, rg.modules)
if err != nil {
return err
}
diff --git a/pkg/cover/report_test.go b/pkg/cover/report_test.go
index 0707eab64..b1962c599 100644
--- a/pkg/cover/report_test.go
+++ b/pkg/cover/report_test.go
@@ -190,7 +190,7 @@ func generateReport(t *testing.T, target *targets.Target, test Test) ([]byte, []
},
}
- rg, err := MakeReportGenerator(target, "", dir, dir, dir, subsystem)
+ rg, err := MakeReportGenerator(target, "", dir, dir, dir, subsystem, nil)
if err != nil {
return nil, nil, err
}
diff --git a/pkg/mgrconfig/config.go b/pkg/mgrconfig/config.go
index e4bfc46f8..a5ab47590 100644
--- a/pkg/mgrconfig/config.go
+++ b/pkg/mgrconfig/config.go
@@ -5,7 +5,9 @@ package mgrconfig
import (
"encoding/json"
+
"github.com/google/syzkaller/pkg/cover"
+ "github.com/google/syzkaller/pkg/cover/backend"
)
type Config struct {
@@ -40,6 +42,22 @@ type Config struct {
// Directory with kernel object files (e.g. `vmlinux` for linux)
// (used for report symbolization and coverage reports, optional).
KernelObj string `json:"kernel_obj"`
+ // Map of kernel modules' symbol files and load address.
+ // path is unstripped module obj path and
+ // addr (uint64) is the module load address on target,
+ // like 'button 16384 0 - Live 0xffffffffc0163000',
+ // addr is 18446744072637263872 of 0xffffffffc0163000 above.
+ // For linux target, the addr is getting from /proc/modules
+ // automatically during instance run.
+ // Example config:
+ // "kernel_modules": [
+ // {
+ // "name": "wlan",
+ // "path": "../../wlan.ko.unstripped",
+ // "addr": 18446744072637911040
+ // }
+ // ]
+ KernelModules []backend.KernelModule `json:"kernel_modules"`
// Kernel source directory (if not set defaults to KernelObj).
KernelSrc string `json:"kernel_src,omitempty"`
// Location of the driectory where the kernel was built (if not set defaults to KernelSrc)
diff --git a/pkg/symbolizer/symbolizer.go b/pkg/symbolizer/symbolizer.go
index 96b62fb95..87342e750 100644
--- a/pkg/symbolizer/symbolizer.go
+++ b/pkg/symbolizer/symbolizer.go
@@ -23,6 +23,7 @@ type Symbolizer struct {
}
type Frame struct {
+ Module string
PC uint64
Func string
File string
@@ -43,15 +44,15 @@ func NewSymbolizer(target *targets.Target) *Symbolizer {
}
func (s *Symbolizer) Symbolize(bin string, pc uint64) ([]Frame, error) {
- return s.SymbolizeArray(bin, []uint64{pc})
+ return s.SymbolizeArray("kernel", bin, []uint64{pc})
}
-func (s *Symbolizer) SymbolizeArray(bin string, pcs []uint64) ([]Frame, error) {
+func (s *Symbolizer) SymbolizeArray(module, bin string, pcs []uint64) ([]Frame, error) {
sub, err := s.getSubprocess(bin)
if err != nil {
return nil, err
}
- return symbolize(sub.input, sub.scanner, pcs)
+ return symbolize(sub.input, sub.scanner, pcs, module)
}
func (s *Symbolizer) Close() {
@@ -100,7 +101,7 @@ func (s *Symbolizer) getSubprocess(bin string) (*subprocess, error) {
return sub, nil
}
-func symbolize(input *bufio.Writer, scanner *bufio.Scanner, pcs []uint64) ([]Frame, error) {
+func symbolize(input *bufio.Writer, scanner *bufio.Scanner, pcs []uint64, module string) ([]Frame, error) {
var frames []Frame
done := make(chan error, 1)
go func() {
@@ -116,7 +117,7 @@ func symbolize(input *bufio.Writer, scanner *bufio.Scanner, pcs []uint64) ([]Fra
}
for range pcs {
var frames1 []Frame
- frames1, err = parse(scanner)
+ frames1, err = parse(scanner, module)
if err != nil {
return
}
@@ -145,7 +146,7 @@ func symbolize(input *bufio.Writer, scanner *bufio.Scanner, pcs []uint64) ([]Fra
return frames, nil
}
-func parse(s *bufio.Scanner) ([]Frame, error) {
+func parse(s *bufio.Scanner, module string) ([]Frame, error) {
pc, err := strconv.ParseUint(s.Text(), 0, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse pc '%v' in addr2line output: %v", s.Text(), err)
@@ -182,6 +183,7 @@ func parse(s *bufio.Scanner) ([]Frame, error) {
continue
}
frames = append(frames, Frame{
+ Module: module,
PC: pc,
Func: fn,
File: file,
diff --git a/pkg/symbolizer/symbolizer_test.go b/pkg/symbolizer/symbolizer_test.go
index 0bddb2f71..cdbef8e6c 100644
--- a/pkg/symbolizer/symbolizer_test.go
+++ b/pkg/symbolizer/symbolizer_test.go
@@ -25,6 +25,7 @@ func TestParse(t *testing.T) {
"mm/kasan/report.c:320\n",
[]Frame{
{
+ Module: "kernel",
PC: 0xffffffff8180a42e,
Func: "__asan_report_load2_noabort",
File: "mm/kasan/report.c",
@@ -42,6 +43,7 @@ func TestParse(t *testing.T) {
"mm/kasan/report.c:320\n",
[]Frame{
{
+ Module: "kernel",
PC: 0xffffffff8180a42d,
Func: "kasan_report",
File: "mm/kasan/report.c",
@@ -49,6 +51,7 @@ func TestParse(t *testing.T) {
Inline: true,
},
{
+ Module: "kernel",
PC: 0xffffffff8180a42d,
Func: "__asan_report_load2_noabort",
File: "mm/kasan/report.c",
@@ -64,6 +67,7 @@ func TestParse(t *testing.T) {
"drivers/video/console/fbcon.c:2750\n",
[]Frame{
{
+ Module: "kernel",
PC: 0xffffffff82fdbe0b,
Func: "fbcon_invert_region",
File: "drivers/video/console/fbcon.c",
@@ -93,6 +97,7 @@ func TestParse(t *testing.T) {
"fs/devpts/inode.c:588 (discriminator 3)\n",
[]Frame{
{
+ Module: "kernel",
PC: 0xffffffff81a2aff9,
Func: "devpts_get_priv",
File: "fs/devpts/inode.c",
@@ -153,7 +158,7 @@ func TestParse(t *testing.T) {
var allPCs []uint64
var allFrames []Frame
for _, addr := range addresses {
- frames, err := symbolize(input, scanner, []uint64{addr.pc})
+ frames, err := symbolize(input, scanner, []uint64{addr.pc}, "kernel")
if err != nil {
t.Fatalf("got error: %v", err)
}
@@ -166,11 +171,11 @@ func TestParse(t *testing.T) {
// Symbolize PCs in 2 groups.
for i := 0; i <= len(addresses); i++ {
- frames, err := symbolize(input, scanner, allPCs[:i])
+ frames, err := symbolize(input, scanner, allPCs[:i], "kernel")
if err != nil {
t.Fatalf("got error: %v", err)
}
- frames2, err := symbolize(input, scanner, allPCs[i:])
+ frames2, err := symbolize(input, scanner, allPCs[i:], "kernel")
if err != nil {
t.Fatalf("got error: %v", err)
}
@@ -185,7 +190,7 @@ func TestParse(t *testing.T) {
for i := range lots {
lots[i] = addresses[0].pc
}
- frames, err := symbolize(input, scanner, lots)
+ frames, err := symbolize(input, scanner, lots, "kernel")
if err != nil {
t.Fatalf("got error: %v", err)
}