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
This commit is contained in:
Dmitry Vyukov 2020-08-22 12:47:27 +02:00
parent 7288521c2a
commit 49a5a1ab2f
2 changed files with 51 additions and 30 deletions

View File

@ -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":

View File

@ -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 {
t.Fatal(err)
}
defer os.Remove(src)
if err := osutil.WriteFile(src, []byte(`
void __sanitizer_cov_trace_pc() {}
int main() {}
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)
}
bin, err := osutil.TempFile("syz-cover-test-bin")
if 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)
}
defer os.Remove(bin)
flags := append(append([]string{
"-w",
"-o", bin,
"-x", "c", src,
}, target.CFlags...), test.CFlags...)
if _, err := osutil.RunCmd(time.Hour, "", target.CCompiler, kcovFlags...); err != nil {
t.Fatal(err)
}
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})
}