tools/syz-execprog: use more precise addresses when collecting coverage

Make two improvements to addresses obtained from kcov:
 - call backend.PreviousInstructionPC() so that they point to the
   __sanitizer_cov_trace_pc calls;
 - read the top 32 bits of the kernel addresses from /proc/kallsyms
   instead of using the hardcoded 0xffffffff value
diff --git a/tools/syz-execprog/execprog.go b/tools/syz-execprog/execprog.go
index 70d0eee..4d5e3d0 100644
--- a/tools/syz-execprog/execprog.go
+++ b/tools/syz-execprog/execprog.go
@@ -11,10 +11,12 @@
 	"fmt"
 	"os"
 	"runtime"
+	"strconv"
 	"sync"
 	"time"
 
 	"github.com/google/syzkaller/pkg/cover"
+	"github.com/google/syzkaller/pkg/cover/backend"
 	"github.com/google/syzkaller/pkg/csource"
 	"github.com/google/syzkaller/pkg/db"
 	"github.com/google/syzkaller/pkg/host"
@@ -25,6 +27,7 @@
 	"github.com/google/syzkaller/pkg/tool"
 	"github.com/google/syzkaller/prog"
 	_ "github.com/google/syzkaller/sys"
+	"github.com/google/syzkaller/sys/targets"
 )
 
 var (
@@ -72,6 +75,7 @@
 	if err != nil {
 		log.Fatalf("%v", err)
 	}
+
 	progs := loadPrograms(target, flag.Args())
 	if len(progs) == 0 {
 		return
@@ -102,13 +106,17 @@
 			}
 		}
 	}
+	sysTarget := targets.Get(*flagOS, *flagArch)
+	upperBase := getKernelUpperBase(sysTarget)
 	ctx := &Context{
-		progs:    progs,
-		config:   config,
-		execOpts: execOpts,
-		gate:     ipc.NewGate(2**flagProcs, gateCallback),
-		shutdown: make(chan struct{}),
-		repeat:   *flagRepeat,
+		progs:     progs,
+		config:    config,
+		execOpts:  execOpts,
+		gate:      ipc.NewGate(2**flagProcs, gateCallback),
+		shutdown:  make(chan struct{}),
+		repeat:    *flagRepeat,
+		target:    sysTarget,
+		upperBase: upperBase,
 	}
 	var wg sync.WaitGroup
 	wg.Add(*flagProcs)
@@ -134,6 +142,8 @@
 	repeat    int
 	pos       int
 	lastPrint time.Time
+	target    *targets.Target
+	upperBase uint32
 }
 
 func (ctx *Context) run(pid int) {
@@ -251,13 +261,39 @@
 	log.Logf(0, "ncomps=%v ncandidates=%v", ncomps, ncandidates)
 }
 
+func getKernelUpperBase(target *targets.Target) uint32 {
+	defaultRet := uint32(0xffffffff)
+	if target.OS == targets.Linux {
+		// Read the first 8 bytes from /proc/kallsyms.
+		f, err := os.Open("/proc/kallsyms")
+		if err != nil {
+			log.Logf(1, "could not get kernel fixup address: %v", err)
+			return defaultRet
+		}
+		defer f.Close()
+		data := make([]byte, 8)
+		_, err = f.ReadAt(data, 0)
+		if err != nil {
+			log.Logf(1, "could not get kernel fixup address: %v", err)
+			return defaultRet
+		}
+		value, err := strconv.ParseUint(string(data), 16, 32)
+		if err != nil {
+			log.Logf(1, "could not get kernel fixup address: %v", err)
+			return defaultRet
+		}
+		return uint32(value)
+	}
+	return defaultRet
+}
+
 func (ctx *Context) dumpCallCoverage(coverFile string, info *ipc.CallInfo) {
 	if len(info.Cover) == 0 {
 		return
 	}
 	buf := new(bytes.Buffer)
 	for _, pc := range info.Cover {
-		fmt.Fprintf(buf, "0x%x\n", cover.RestorePC(pc, 0xffffffff))
+		fmt.Fprintf(buf, "0x%x\n", backend.PreviousInstructionPC(ctx.target, cover.RestorePC(pc, ctx.upperBase)))
 	}
 	err := osutil.WriteFile(coverFile, buf.Bytes())
 	if err != nil {