aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-04-27 14:14:03 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-04-27 14:33:01 +0200
commit476b8ca98716212439618bda7ae66d7c0dcf24b7 (patch)
tree3207f1ca4e91133400abec27513787b6432f38db
parentd0b7645387ebebc6a4eb298e1905f5ac8f60688f (diff)
syz-manager: properly calculate previous instruction PC
We used to subtract 5 which is length of call instruction on amd64. Do proper per-arch calculation.
-rw-r--r--syz-manager/cover.go29
-rw-r--r--syz-manager/html.go6
2 files changed, 27 insertions, 8 deletions
diff --git a/syz-manager/cover.go b/syz-manager/cover.go
index a2663314f..dde9ef93a 100644
--- a/syz-manager/cover.go
+++ b/syz-manager/cover.go
@@ -60,10 +60,6 @@ var (
vmOffsets = make(map[string]uint32)
)
-const (
- callLen = 5 // length of a call instruction, x86-ism
-)
-
func initAllCover(os, arch, vmlinux string) {
// Running objdump on vmlinux takes 20-30 seconds, so we do it asynchronously on start.
// Running nm on vmlinux may takes 200 microsecond and being called during symbolization of every crash,
@@ -91,7 +87,7 @@ func initAllCover(os, arch, vmlinux string) {
}()
}
-func generateCoverHTML(w io.Writer, vmlinux string, cov cover.Cover) error {
+func generateCoverHTML(w io.Writer, vmlinux, arch string, cov cover.Cover) error {
if len(cov) == 0 {
return fmt.Errorf("No coverage data available")
}
@@ -102,7 +98,9 @@ func generateCoverHTML(w io.Writer, vmlinux string, cov cover.Cover) error {
}
pcs := make([]uint64, 0, len(cov))
for pc := range cov {
- pcs = append(pcs, cover.RestorePC(pc, base)-callLen)
+ fullPC := cover.RestorePC(pc, base)
+ prevPC := previousInstructionPC(arch, fullPC)
+ pcs = append(pcs, prevPC)
}
uncovered, err := uncoveredPcsInFuncs(vmlinux, pcs)
if err != nil {
@@ -393,6 +391,25 @@ func symbolize(vmlinux string, pcs []uint64) ([]symbolizer.Frame, string, error)
return frames, prefix, nil
}
+func previousInstructionPC(arch string, pc uint64) uint64 {
+ switch arch {
+ case "amd64":
+ return pc - 5
+ case "386":
+ return pc - 1
+ case "arm64":
+ return pc - 4
+ case "arm":
+ // THUMB instructions are 2 or 4 bytes with low bit set.
+ // ARM instructions are always 4 bytes.
+ return (pc - 3) & ^uint64(1)
+ case "ppc64le":
+ return pc - 4
+ default:
+ panic("unknown arch")
+ }
+}
+
type templateData struct {
Files []*templateFile
}
diff --git a/syz-manager/html.go b/syz-manager/html.go
index 08a91ea8e..126ec715a 100644
--- a/syz-manager/html.go
+++ b/syz-manager/html.go
@@ -211,7 +211,7 @@ func (mgr *Manager) httpCover(w http.ResponseWriter, r *http.Request) {
}
}
- if err := generateCoverHTML(w, mgr.cfg.Vmlinux, cov); err != nil {
+ if err := generateCoverHTML(w, mgr.cfg.Vmlinux, mgr.cfg.TargetVMArch, cov); err != nil {
http.Error(w, fmt.Sprintf("failed to generate coverage profile: %v", err), http.StatusInternalServerError)
return
}
@@ -322,7 +322,9 @@ func (mgr *Manager) httpRawCover(w http.ResponseWriter, r *http.Request) {
}
pcs := make([]uint64, 0, len(cov))
for pc := range cov {
- pcs = append(pcs, cover.RestorePC(pc, base)-callLen)
+ fullPC := cover.RestorePC(pc, base)
+ prevPC := previousInstructionPC(mgr.cfg.TargetVMArch, fullPC)
+ pcs = append(pcs, prevPC)
}
sort.Slice(pcs, func(i, j int) bool {
return pcs[i] < pcs[j]