diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-04-27 14:14:03 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-04-27 14:33:01 +0200 |
| commit | 476b8ca98716212439618bda7ae66d7c0dcf24b7 (patch) | |
| tree | 3207f1ca4e91133400abec27513787b6432f38db | |
| parent | d0b7645387ebebc6a4eb298e1905f5ac8f60688f (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.go | 29 | ||||
| -rw-r--r-- | 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] |
