diff options
| author | Joey Jiao <joeyjiaojg@gmail.com> | 2021-05-26 08:20:59 +0800 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2021-05-26 15:10:14 +0200 |
| commit | 858ea628800647d5e5b68b11441e42b8ef5652c1 (patch) | |
| tree | 57bbff5937bcc1ed13cfafed85aa26dd106b8755 /pkg | |
| parent | 076dbcb04d07743faf5fe058f73af1678d8868c9 (diff) | |
pkg/cover: fix mismatch frame and progs PC for arm64
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/cover/backend/dwarf.go | 63 | ||||
| -rw-r--r-- | pkg/cover/backend/elf.go | 4 | ||||
| -rw-r--r-- | pkg/cover/backend/mach-o.go | 2 |
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 |
