aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorJoey Jiao <joeyjiaojg@gmail.com>2021-05-26 08:20:59 +0800
committerDmitry Vyukov <dvyukov@google.com>2021-05-26 15:10:14 +0200
commit858ea628800647d5e5b68b11441e42b8ef5652c1 (patch)
tree57bbff5937bcc1ed13cfafed85aa26dd106b8755 /pkg
parent076dbcb04d07743faf5fe058f73af1678d8868c9 (diff)
pkg/cover: fix mismatch frame and progs PC for arm64
Diffstat (limited to 'pkg')
-rw-r--r--pkg/cover/backend/dwarf.go63
-rw-r--r--pkg/cover/backend/elf.go4
-rw-r--r--pkg/cover/backend/mach-o.go2
3 files changed, 37 insertions, 32 deletions
diff --git a/pkg/cover/backend/dwarf.go b/pkg/cover/backend/dwarf.go
index 79a0fb304..23a1e8ce9 100644
--- a/pkg/cover/backend/dwarf.go
+++ b/pkg/cover/backend/dwarf.go
@@ -25,10 +25,40 @@ import (
type containerFns struct {
readSymbols func(*Module, *symbolInfo) ([]*Symbol, error)
readTextData func(*Module) ([]byte, error)
- readModuleCoverPoints func(*Module, *symbolInfo) ([2][]uint64, error)
+ readModuleCoverPoints func(*targets.Target, *Module, *symbolInfo) ([2][]uint64, error)
readTextRanges func(*Module) ([]pcRange, []*CompileUnit, error)
}
+type Arch struct {
+ callLen int
+ opcodeOffset int
+ opcodes [2]byte
+ target func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64
+}
+
+var arches = map[string]Arch{
+ targets.AMD64: {
+ callLen: 5,
+ opcodes: [2]byte{0xe8, 0xe8},
+ target: func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64 {
+ off := uint64(int64(int32(binary.LittleEndian.Uint32(insn[1:]))))
+ return pc + off + uint64(arch.callLen)
+ },
+ },
+ targets.ARM64: {
+ callLen: 4,
+ opcodeOffset: 3,
+ opcodes: [2]byte{0x94, 0x97},
+ target: func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64 {
+ off := uint64(binary.LittleEndian.Uint32(insn)) & ((1 << 24) - 1)
+ if opcode == arch.opcodes[1] {
+ off |= 0xffffffffff000000
+ }
+ return pc + 4*off
+ },
+ },
+}
+
func makeDWARF(target *targets.Target, objDir, srcDir, buildDir string,
moduleObj []string, hostModules []host.KernelModule, fn *containerFns) (
*Impl, error) {
@@ -73,7 +103,7 @@ func makeDWARF(target *targets.Target, objDir, srcDir, buildDir string,
}
coverPoints, err = readCoverPoints(target, info, data)
} else {
- coverPoints, err = fn.readModuleCoverPoints(module, info)
+ coverPoints, err = fn.readModuleCoverPoints(target, module, info)
}
allCoverPoints[0] = append(allCoverPoints[0], coverPoints[0]...)
allCoverPoints[1] = append(allCoverPoints[1], coverPoints[1]...)
@@ -359,38 +389,11 @@ func readCoverPoints(target *targets.Target, info *symbolInfo, data []byte) ([2]
return pcs, fmt.Errorf("no __sanitizer_cov_trace_pc symbol in the object file")
}
- type Arch struct {
- callLen int
- opcodeOffset int
- opcodes [2]byte
- target func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64
- }
- arch := map[string]Arch{
- targets.AMD64: {
- callLen: 5,
- opcodes: [2]byte{0xe8, 0xe8},
- target: func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64 {
- off := uint64(int64(int32(binary.LittleEndian.Uint32(insn[1:]))))
- return pc + off + uint64(arch.callLen)
- },
- },
- targets.ARM64: {
- callLen: 4,
- opcodeOffset: 3,
- opcodes: [2]byte{0x94, 0x97},
- target: func(arch *Arch, insn []byte, pc uint64, opcode byte) uint64 {
- off := uint64(binary.LittleEndian.Uint32(insn)) & ((1 << 24) - 1)
- if opcode == arch.opcodes[1] {
- off |= 0xffffffffff000000
- }
- return pc + 4*off
- },
- },
- }[target.Arch]
// Loop that's checking each instruction for the current architectures call
// opcode. When found, it compares the call target address with those of the
// __sanitizer_cov_trace_* functions we previously collected. When found,
// we collect the pc as a coverage point.
+ arch := arches[target.Arch]
for i, opcode := range data {
if opcode != arch.opcodes[0] && opcode != arch.opcodes[1] {
continue
diff --git a/pkg/cover/backend/elf.go b/pkg/cover/backend/elf.go
index 214e42353..94e6fdd8c 100644
--- a/pkg/cover/backend/elf.go
+++ b/pkg/cover/backend/elf.go
@@ -127,12 +127,13 @@ func elfReadTextData(module *Module) ([]byte, error) {
return text.Data()
}
-func elfReadModuleCoverPoints(module *Module, info *symbolInfo) ([2][]uint64, error) {
+func elfReadModuleCoverPoints(target *targets.Target, module *Module, info *symbolInfo) ([2][]uint64, error) {
var pcs [2][]uint64
file, err := elf.Open(module.Path)
if err != nil {
return pcs, err
}
+ offset := uint64(arches[target.Arch].opcodeOffset)
for _, s := range file.Sections {
if s.Type != elf.SHT_RELA { // nolint: misspell
continue
@@ -148,6 +149,7 @@ func elfReadModuleCoverPoints(module *Module, info *symbolInfo) ([2][]uint64, er
// Note: this assumes that call instruction is 1 byte.
pc := module.Addr + rel.Off - 1
index := int(elf.R_SYM64(rel.Info)) - 1
+ pc -= offset
if info.tracePCIdx[index] {
pcs[0] = append(pcs[0], pc)
} else if info.traceCmpIdx[index] {
diff --git a/pkg/cover/backend/mach-o.go b/pkg/cover/backend/mach-o.go
index a6f25fd05..666d4c3f0 100644
--- a/pkg/cover/backend/mach-o.go
+++ b/pkg/cover/backend/mach-o.go
@@ -111,7 +111,7 @@ func machoReadTextData(module *Module) ([]byte, error) {
return text.Data()
}
-func machoReadModuleCoverPoints(module *Module, info *symbolInfo) ([2][]uint64, error) {
+func machoReadModuleCoverPoints(target *targets.Target, module *Module, info *symbolInfo) ([2][]uint64, error) {
// TODO: Linux/ELF supports module symbols. We should probably also do that
// for XNU/Mach-O. To maximize code re-use we already have a lot of the
// plumbing for module support. I think we mainly miss an equivalent to