From 49a5a1ab2f94353aa29edebdabc9eda5b168020b Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sat, 22 Aug 2020 12:47:27 +0200 Subject: 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 See #2067 --- pkg/cover/report.go | 2 +- pkg/cover/report_test.go | 77 ++++++++++++++++++++++++++++++------------------ 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 +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}) } -- cgit mrf-deployment