aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-08-22 12:47:27 +0200
committerDmitry Vyukov <dvyukov@google.com>2020-08-22 21:26:42 +0200
commit49a5a1ab2f94353aa29edebdabc9eda5b168020b (patch)
treea41e5bcf1d41c464187c6d8b87ef18cb58dde2b1
parent7288521c2ab2ce481a739e2f9d5dc0ec4642fc66 (diff)
pkg/cover: fix calculation of prev PC for i386
Make the report generation test more realistic to use PCs we will use in real life. This shows that PreviousInstructionPC for 386 is broken. Fix it. Reported-by: Alexander Lochmann <flipreverse> See #2067
-rw-r--r--pkg/cover/report.go2
-rw-r--r--pkg/cover/report_test.go77
2 files changed, 50 insertions, 29 deletions
diff --git a/pkg/cover/report.go b/pkg/cover/report.go
index a56e7f14c..a302b7013 100644
--- a/pkg/cover/report.go
+++ b/pkg/cover/report.go
@@ -475,7 +475,7 @@ func PreviousInstructionPC(target *targets.Target, pc uint64) uint64 {
case "amd64":
return pc - 5
case "386":
- return pc - 1
+ return pc - 5
case "arm64":
return pc - 4
case "arm":
diff --git a/pkg/cover/report_test.go b/pkg/cover/report_test.go
index 3ce76ed3e..d7a893352 100644
--- a/pkg/cover/report_test.go
+++ b/pkg/cover/report_test.go
@@ -9,10 +9,12 @@ package cover
import (
"bytes"
+ "io/ioutil"
"os"
"path/filepath"
"regexp"
"runtime"
+ "strconv"
"strings"
"testing"
"time"
@@ -102,28 +104,25 @@ func testReportGenerator(t *testing.T, target *targets.Target, test Test) {
_ = rep
}
-func generateReport(t *testing.T, target *targets.Target, test Test) ([]byte, error) {
- src, err := osutil.TempFile("syz-cover-test-src")
- if err != nil {
+func buildTestBinary(t *testing.T, target *targets.Target, test Test, dir string) string {
+ kcovSrc := filepath.Join(dir, "kcov.c")
+ kcovObj := filepath.Join(dir, "kcov.o")
+ if err := osutil.WriteFile(kcovSrc, []byte(`
+#include <stdio.h>
+void __sanitizer_cov_trace_pc() { printf("%llu", (long long)__builtin_return_address(0)); }
+`)); err != nil {
t.Fatal(err)
}
- defer os.Remove(src)
- if err := osutil.WriteFile(src, []byte(`
-void __sanitizer_cov_trace_pc() {}
-int main() {}
-`)); err != nil {
+ kcovFlags := append([]string{"-c", "-w", "-x", "c", "-o", kcovObj, kcovSrc}, target.CFlags...)
+ src := filepath.Join(dir, "main.c")
+ bin := filepath.Join(dir, "bin")
+ if err := osutil.WriteFile(src, []byte(`int main() {}`)); err != nil {
t.Fatal(err)
}
- bin, err := osutil.TempFile("syz-cover-test-bin")
- if err != nil {
+ if _, err := osutil.RunCmd(time.Hour, "", target.CCompiler, kcovFlags...); err != nil {
t.Fatal(err)
}
- defer os.Remove(bin)
- flags := append(append([]string{
- "-w",
- "-o", bin,
- "-x", "c", src,
- }, target.CFlags...), test.CFlags...)
+ flags := append(append([]string{"-w", "-o", bin, src, kcovObj}, target.CFlags...), test.CFlags...)
if _, err := osutil.RunCmd(time.Hour, "", target.CCompiler, flags...); err != nil {
errText := err.Error()
errText = strings.ReplaceAll(errText, "‘", "'")
@@ -134,23 +133,45 @@ int main() {}
}
t.Fatal(err)
}
- rg, err := MakeReportGenerator(target, bin, filepath.Dir(src), filepath.Dir(src))
+ return bin
+}
+
+func generateReport(t *testing.T, target *targets.Target, test Test) ([]byte, error) {
+ dir, err := ioutil.TempDir("", "syz-cover-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ bin := buildTestBinary(t, target, test, dir)
+ rg, err := MakeReportGenerator(target, bin, dir, dir)
if err != nil {
return nil, err
}
if test.Result == "" {
- symb := symbolizer.NewSymbolizer(target)
- text, err := symb.ReadTextSymbols(bin)
- if err != nil {
- t.Fatal(err)
- }
- if nmain := len(text["main"]); nmain != 1 {
- t.Fatalf("got %v main symbols", nmain)
- }
- main := text["main"][0]
var pcs []uint64
- for off := 0; off < main.Size; off++ {
- pcs = append(pcs, main.Addr+uint64(off))
+ if output, err := osutil.RunCmd(time.Minute, "", bin); err == nil {
+ pc, err := strconv.ParseUint(string(output), 10, 64)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pcs = append(pcs, PreviousInstructionPC(target, pc))
+ t.Logf("using exact coverage PC 0x%x", pcs[0])
+ } else if target.OS == runtime.GOOS && (target.Arch == runtime.GOARCH || target.VMArch == runtime.GOARCH) {
+ t.Fatal(err)
+ } else {
+ symb := symbolizer.NewSymbolizer(target)
+ text, err := symb.ReadTextSymbols(bin)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if nmain := len(text["main"]); nmain != 1 {
+ t.Fatalf("got %v main symbols", nmain)
+ }
+ main := text["main"][0]
+ for off := 0; off < main.Size; off++ {
+ pcs = append(pcs, main.Addr+uint64(off))
+ }
+ t.Logf("using inexact coverage range 0x%x-0x%x", main.Addr, main.Addr+uint64(main.Size))
}
test.Progs = append(test.Progs, Prog{Data: "main", PCs: pcs})
}