From 476b8ca98716212439618bda7ae66d7c0dcf24b7 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 27 Apr 2018 14:14:03 +0200 Subject: 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. --- syz-manager/cover.go | 29 +++++++++++++++++++++++------ syz-manager/html.go | 6 ++++-- 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] -- cgit mrf-deployment