aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/cover/backend/pc.go
blob: da8ae6d56daa4e7fb3ec88cadd258bbebf0dbd97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 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 PreviousInstructionPC(target *targets.Target, vm string, pc uint64) uint64 {
	if vm == targets.GVisor {
		// gVisor coverage returns real PCs that don't need adjustment.
		return pc
	}
	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, vm string, pc uint64) uint64 {
	if vm == targets.GVisor {
		return pc
	}
	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
	case targets.TestArch64:
		return 0
	default:
		panic(fmt.Sprintf("unknown arch %q", arch))
	}
}