From d0d624444f8c925c99f29ff0deff2a2ce8c951d9 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sat, 12 Dec 2020 08:45:06 +0100 Subject: pkg/cover: provide ReportGenerator.RestorePC Better encapsulate all of this logic instead of exposing raw .text offset and a bunch of functions. Also allows to support gvisor coverage where PCs don't need to be rewound to previous instruction. --- pkg/cover/backend/backend.go | 10 ++++---- pkg/cover/backend/elf.go | 8 +++--- pkg/cover/backend/pc.go | 59 ++++++++++++++++++++++++++++++++++++++++++++ pkg/cover/cover.go | 4 --- pkg/cover/pc.go | 55 ----------------------------------------- pkg/cover/report.go | 5 ++++ 6 files changed, 74 insertions(+), 67 deletions(-) create mode 100644 pkg/cover/backend/pc.go delete mode 100644 pkg/cover/pc.go (limited to 'pkg') diff --git a/pkg/cover/backend/backend.go b/pkg/cover/backend/backend.go index 7da6abfc5..405cbaa3f 100644 --- a/pkg/cover/backend/backend.go +++ b/pkg/cover/backend/backend.go @@ -9,11 +9,11 @@ import ( ) type Impl struct { - Units []*CompileUnit - Symbols []*Symbol - Frames []symbolizer.Frame - TextOffset uint32 // high 32 bits of PCs - Symbolize func(pcs []uint64) ([]symbolizer.Frame, error) + Units []*CompileUnit + Symbols []*Symbol + Frames []symbolizer.Frame + Symbolize func(pcs []uint64) ([]symbolizer.Frame, error) + RestorePC func(pc uint32) uint64 } type CompileUnit struct { diff --git a/pkg/cover/backend/elf.go b/pkg/cover/backend/elf.go index 0821f331a..c8e0879b0 100644 --- a/pkg/cover/backend/elf.go +++ b/pkg/cover/backend/elf.go @@ -74,12 +74,14 @@ func makeELF(target *targets.Target, objDir string) (*Impl, error) { return nil, fmt.Errorf("failed to parse DWARF (set CONFIG_DEBUG_INFO=y?)") } impl := &Impl{ - Units: units, - Symbols: symbols, - TextOffset: uint32(textAddr >> 32), + Units: units, + Symbols: symbols, Symbolize: func(pcs []uint64) ([]symbolizer.Frame, error) { return symbolize(target, kernelObject, pcs) }, + RestorePC: func(pc uint32) uint64 { + return PreviousInstructionPC(target, RestorePC(pc, uint32(textAddr>>32))) + }, } return impl, nil } diff --git a/pkg/cover/backend/pc.go b/pkg/cover/backend/pc.go new file mode 100644 index 000000000..ae92f9298 --- /dev/null +++ b/pkg/cover/backend/pc.go @@ -0,0 +1,59 @@ +// Copyright 2020 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package backend + +import ( + "fmt" + + "github.com/google/syzkaller/sys/targets" +) + +func RestorePC(pc, base uint32) uint64 { + return uint64(base)<<32 + uint64(pc) +} + +func PreviousInstructionPC(target *targets.Target, pc uint64) uint64 { + offset := instructionLen(target.Arch) + pc -= offset + // THUMB instructions are 2 or 4 bytes with low bit set. + // ARM instructions are always 4 bytes. + if target.Arch == targets.ARM { + return pc & ^uint64(1) + } + return pc +} + +func NextInstructionPC(target *targets.Target, pc uint64) uint64 { + offset := instructionLen(target.Arch) + pc += offset + // THUMB instructions are 2 or 4 bytes with low bit set. + // ARM instructions are always 4 bytes. + if target.Arch == targets.ARM { + return pc & ^uint64(1) + } + return pc +} + +func instructionLen(arch string) uint64 { + switch arch { + case targets.AMD64: + return 5 + case targets.I386: + return 5 + case targets.ARM64: + return 4 + case targets.ARM: + return 3 + case targets.PPC64LE: + return 4 + case targets.MIPS64LE: + return 8 + case targets.S390x: + return 6 + case targets.RiscV64: + return 4 + default: + panic(fmt.Sprintf("unknown arch %q", arch)) + } +} diff --git a/pkg/cover/cover.go b/pkg/cover/cover.go index 40c806fd7..814ae4fb6 100644 --- a/pkg/cover/cover.go +++ b/pkg/cover/cover.go @@ -43,7 +43,3 @@ func (cov Cover) Serialize() []uint32 { } return res } - -func RestorePC(pc, base uint32) uint64 { - return uint64(base)<<32 + uint64(pc) -} diff --git a/pkg/cover/pc.go b/pkg/cover/pc.go deleted file mode 100644 index 5987e8846..000000000 --- a/pkg/cover/pc.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2020 syzkaller project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -package cover - -import ( - "fmt" - - "github.com/google/syzkaller/sys/targets" -) - -func PreviousInstructionPC(target *targets.Target, pc uint64) uint64 { - offset := instructionLen(target.Arch) - pc -= offset - // THUMB instructions are 2 or 4 bytes with low bit set. - // ARM instructions are always 4 bytes. - if target.Arch == targets.ARM { - return pc & ^uint64(1) - } - return pc -} - -func NextInstructionPC(target *targets.Target, pc uint64) uint64 { - offset := instructionLen(target.Arch) - pc += offset - // THUMB instructions are 2 or 4 bytes with low bit set. - // ARM instructions are always 4 bytes. - if target.Arch == targets.ARM { - return pc & ^uint64(1) - } - return pc -} - -func instructionLen(arch string) uint64 { - switch arch { - case targets.AMD64: - return 5 - case targets.I386: - return 5 - case targets.ARM64: - return 4 - case targets.ARM: - return 3 - case targets.PPC64LE: - return 4 - case targets.MIPS64LE: - return 8 - case targets.S390x: - return 6 - case targets.RiscV64: - return 4 - default: - panic(fmt.Sprintf("unknown arch %q", arch)) - } -} diff --git a/pkg/cover/report.go b/pkg/cover/report.go index 9b515905f..14c0b7422 100644 --- a/pkg/cover/report.go +++ b/pkg/cover/report.go @@ -26,6 +26,11 @@ type Prog struct { PCs []uint64 } +var ( + RestorePC = backend.RestorePC + PreviousInstructionPC = backend.PreviousInstructionPC +) + func MakeReportGenerator(target *targets.Target, vm, objDir, srcDir, buildDir string) (*ReportGenerator, error) { impl, err := backend.Make(target, vm, objDir) if err != nil { -- cgit mrf-deployment