]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.fuzz] internal/fuzz: implement coverage and trace instrumentation
authorMatthew Dempsky <mdempsky@google.com>
Thu, 8 Apr 2021 00:11:48 +0000 (17:11 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 9 Apr 2021 17:19:43 +0000 (17:19 +0000)
This CL makes two main changes to allow internal/fuzz to support
-d=libfuzzer instrumentation:

1. It extends cmd/link to define _counters and _ecounters symbols so
internal/fuzz can find the coverage counters.

2. It adds "trace" stub functions that implement the ABI expected by
cmd/compile for comparison instrumentation.

N.B., that -tags=libfuzzer should *not* be set, so that
internal/fuzz's trace routines will be used instead of runtime's
libfuzzer trampolines.

Also, the current implementation doesn't support multi-module builds
(i.e., compiling a Go program that spans multiple .so/.dll files).
Presumably this isn't an issue, since "go test -fuzz" will need to
recompile the binary with instrumentation anyway so it can make sure
to always use a single-module build. But we can revisit this if
necessary.

Change-Id: I9b1619119ab7477bebcfd5988b4b60499a7ab0d7
Reviewed-on: https://go-review.googlesource.com/c/go/+/308289
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Katie Hockman <katie@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Katie Hockman <katie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>

src/cmd/link/internal/ld/data.go
src/internal/fuzz/coverage.go
src/internal/fuzz/trace.go [new file with mode: 0644]

index 92d38bb63e54aa04c441d18a6613273a6a91ce24..a089caa1a985b3041d2acd558fd4eaf5e55f704d 100644 (file)
@@ -1746,7 +1746,9 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
 
        // Coverage instrumentation counters for libfuzzer.
        if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
-               state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
+               sect := state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
+               ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._counters", 0), sect)
+               ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._ecounters", 0), sect)
        }
 
        if len(state.data[sym.STLSBSS]) > 0 {
@@ -2410,6 +2412,7 @@ func (ctxt *Link) address() []*sym.Segment {
        var noptr *sym.Section
        var bss *sym.Section
        var noptrbss *sym.Section
+       var fuzzCounters *sym.Section
        for i, s := range Segdata.Sections {
                if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && s.Name == ".tbss" {
                        continue
@@ -2421,17 +2424,17 @@ func (ctxt *Link) address() []*sym.Segment {
                s.Vaddr = va
                va += uint64(vlen)
                Segdata.Length = va - Segdata.Vaddr
-               if s.Name == ".data" {
+               switch s.Name {
+               case ".data":
                        data = s
-               }
-               if s.Name == ".noptrdata" {
+               case ".noptrdata":
                        noptr = s
-               }
-               if s.Name == ".bss" {
+               case ".bss":
                        bss = s
-               }
-               if s.Name == ".noptrbss" {
+               case ".noptrbss":
                        noptrbss = s
+               case "__libfuzzer_extra_counters":
+                       fuzzCounters = s
                }
        }
 
@@ -2548,6 +2551,11 @@ func (ctxt *Link) address() []*sym.Segment {
        ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
        ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
 
+       if fuzzCounters != nil {
+               ctxt.xdefine("internal/fuzz._counters", sym.SLIBFUZZER_EXTRA_COUNTER, int64(fuzzCounters.Vaddr))
+               ctxt.xdefine("internal/fuzz._ecounters", sym.SLIBFUZZER_EXTRA_COUNTER, int64(fuzzCounters.Vaddr+fuzzCounters.Length))
+       }
+
        if ctxt.IsSolaris() {
                // On Solaris, in the runtime it sets the external names of the
                // end symbols. Unset them and define separate symbols, so we
index 7624b56e0a20a3a9f557ffa28bf26c939e5b6d68..74872541c9791cbe074db5ffd63a5b98acd19643 100644 (file)
@@ -4,8 +4,29 @@
 
 package fuzz
 
+import (
+       "internal/unsafeheader"
+       "unsafe"
+)
+
 // coverage returns a []byte containing unique 8-bit counters for each edge of
 // the instrumented source code. This coverage data will only be generated if
 // `-d=libfuzzer` is set at build time. This can be used to understand the code
 // coverage of a test execution.
-func coverage() []byte { return nil }
+func coverage() []byte {
+       addr := unsafe.Pointer(&_counters)
+       size := uintptr(unsafe.Pointer(&_ecounters)) - uintptr(addr)
+
+       var res []byte
+       *(*unsafeheader.Slice)(unsafe.Pointer(&res)) = unsafeheader.Slice{
+               Data: addr,
+               Len:  int(size),
+               Cap:  int(size),
+       }
+       return res
+}
+
+// _counters and _ecounters mark the start and end, respectively, of where
+// the 8-bit coverage counters reside in memory. They're known to cmd/link,
+// which specially assigns their addresses for this purpose.
+var _counters, _ecounters [0]byte
diff --git a/src/internal/fuzz/trace.go b/src/internal/fuzz/trace.go
new file mode 100644 (file)
index 0000000..f70b1a6
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !libfuzzer
+
+package fuzz
+
+import _ "unsafe" // for go:linkname
+
+//go:linkname libfuzzerTraceCmp1 runtime.libfuzzerTraceCmp1
+//go:linkname libfuzzerTraceCmp2 runtime.libfuzzerTraceCmp2
+//go:linkname libfuzzerTraceCmp4 runtime.libfuzzerTraceCmp4
+//go:linkname libfuzzerTraceCmp8 runtime.libfuzzerTraceCmp8
+
+//go:linkname libfuzzerTraceConstCmp1 runtime.libfuzzerTraceConstCmp1
+//go:linkname libfuzzerTraceConstCmp2 runtime.libfuzzerTraceConstCmp2
+//go:linkname libfuzzerTraceConstCmp4 runtime.libfuzzerTraceConstCmp4
+//go:linkname libfuzzerTraceConstCmp8 runtime.libfuzzerTraceConstCmp8
+
+func libfuzzerTraceCmp1(arg0, arg1 uint8)  {}
+func libfuzzerTraceCmp2(arg0, arg1 uint16) {}
+func libfuzzerTraceCmp4(arg0, arg1 uint32) {}
+func libfuzzerTraceCmp8(arg0, arg1 uint64) {}
+
+func libfuzzerTraceConstCmp1(arg0, arg1 uint8)  {}
+func libfuzzerTraceConstCmp2(arg0, arg1 uint16) {}
+func libfuzzerTraceConstCmp4(arg0, arg1 uint32) {}
+func libfuzzerTraceConstCmp8(arg0, arg1 uint64) {}