aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorJoey Jiao <joeyjiaojg@gmail.com>2021-03-18 16:39:15 +0800
committerDmitry Vyukov <dvyukov@google.com>2021-03-19 15:49:02 +0100
commitdab435a79a291c51c8d0b5bbdcf3e097e7e60825 (patch)
treec83e172188ff2fecdc8f473812b8691792c5bb23 /pkg
parent2af9d324c1bc7d0486122df201cf67590564ae4c (diff)
pkg/cover: support opcode search for arm64
arm64 has different opcode and instruction bytes' order. Example: ffffffd0100a2a60: 9407e172 bl ffffffd01029b028 <__sanitizer_cov_trace_const_cmp4> ffffffd0100a2a6c: 9407e09f bl ffffffd01029ace8 <__sanitizer_cov_trace_pc> ffffffd01029c42c: 97fffa2f bl ffffffd01029ace8 <__sanitizer_cov_trace_pc> Above ffffffd0100a2a60 is address of 0x72 in 9407e172, so position of 0x94 needs to minus 3 to get address of 0x72.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/cover/backend/elf.go53
1 files changed, 38 insertions, 15 deletions
diff --git a/pkg/cover/backend/elf.go b/pkg/cover/backend/elf.go
index c337a6f5d..2b4f41733 100644
--- a/pkg/cover/backend/elf.go
+++ b/pkg/cover/backend/elf.go
@@ -55,10 +55,10 @@ func makeELF(target *targets.Target, objDir, srcDir, buildDir string,
pcBase = info.textAddr
}
var coverPoints [2][]uint64
- if target.Arch != targets.AMD64 {
+ if target.Arch != targets.AMD64 && target.Arch != targets.ARM64 {
coverPoints, err = objdump(target, module)
} else if module.Name == "" {
- coverPoints, err = readCoverPoints(file, info)
+ coverPoints, err = readCoverPoints(file, info, target.Arch)
} else {
coverPoints, err = readModuleCoverPoints(file, info, module)
}
@@ -401,14 +401,19 @@ func symbolizeModule(target *targets.Target, objDir, srcDir, buildDir string,
}
// 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.
+// Currently it is [amd64|arm64]-specific: looks for opcode and correct offset.
// Running objdump on the whole object file is too slow.
-func readCoverPoints(file *elf.File, info *symbolInfo) ([2][]uint64, error) {
+func readCoverPoints(file *elf.File, info *symbolInfo, arch string) ([2][]uint64, error) {
var pcs [2][]uint64
if info.tracePC == 0 {
return pcs, fmt.Errorf("no __sanitizer_cov_trace_pc symbol in the object file")
}
- const callLen = 5
+ callLen := 5
+ opcodes := [2]byte{0xe8, 0xe8}
+ if arch == targets.ARM64 {
+ callLen = 4
+ opcodes = [2]byte{0x94, 0x97}
+ }
text := file.Section(".text")
if text == nil {
return pcs, fmt.Errorf("no .text section in the object file")
@@ -417,17 +422,35 @@ func readCoverPoints(file *elf.File, info *symbolInfo) ([2][]uint64, error) {
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
+ for i := 0; i < len(data); i++ {
+ if arch == targets.AMD64 {
+ if i > len(data)-callLen {
+ break
+ }
+ } else if arch == targets.ARM64 {
+ if i < callLen-1 {
+ continue
+ }
+ }
+ if data[i] != opcodes[0] && data[i] != opcodes[1] {
+ continue
+ }
+ pc := text.Addr + uint64(i)
+ var target uint64
+ if arch == targets.AMD64 {
+ d := data[i+1 : i+callLen]
+ off := uint64(int64(int32(binary.LittleEndian.Uint32(d))))
+ target = pc + off + uint64(callLen)
+ } else if arch == targets.ARM64 {
+ d := data[i+1-callLen : i+1]
+ off := uint64(binary.LittleEndian.Uint32(d) & ((1 << 24) - 1))
+ if data[i] == opcodes[1] {
+ off = uint64(binary.LittleEndian.Uint32(d)) | 0xffffffffff000000
+ }
+ off = 4 * off
+ pc -= (uint64(callLen) - 1)
+ target = pc + off
}
- 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 == info.tracePC {
pcs[0] = append(pcs[0], pc)
} else if info.traceCmp[target] {