mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.fuzz] internal/fuzz: implement coverage and trace instrumentation
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>
This commit is contained in:
parent
2f3bc725fe
commit
74f49f3366
3 changed files with 67 additions and 9 deletions
|
|
@ -1746,7 +1746,9 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
|
||||||
|
|
||||||
// Coverage instrumentation counters for libfuzzer.
|
// Coverage instrumentation counters for libfuzzer.
|
||||||
if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
|
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 {
|
if len(state.data[sym.STLSBSS]) > 0 {
|
||||||
|
|
@ -2410,6 +2412,7 @@ func (ctxt *Link) address() []*sym.Segment {
|
||||||
var noptr *sym.Section
|
var noptr *sym.Section
|
||||||
var bss *sym.Section
|
var bss *sym.Section
|
||||||
var noptrbss *sym.Section
|
var noptrbss *sym.Section
|
||||||
|
var fuzzCounters *sym.Section
|
||||||
for i, s := range Segdata.Sections {
|
for i, s := range Segdata.Sections {
|
||||||
if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && s.Name == ".tbss" {
|
if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && s.Name == ".tbss" {
|
||||||
continue
|
continue
|
||||||
|
|
@ -2421,17 +2424,17 @@ func (ctxt *Link) address() []*sym.Segment {
|
||||||
s.Vaddr = va
|
s.Vaddr = va
|
||||||
va += uint64(vlen)
|
va += uint64(vlen)
|
||||||
Segdata.Length = va - Segdata.Vaddr
|
Segdata.Length = va - Segdata.Vaddr
|
||||||
if s.Name == ".data" {
|
switch s.Name {
|
||||||
|
case ".data":
|
||||||
data = s
|
data = s
|
||||||
}
|
case ".noptrdata":
|
||||||
if s.Name == ".noptrdata" {
|
|
||||||
noptr = s
|
noptr = s
|
||||||
}
|
case ".bss":
|
||||||
if s.Name == ".bss" {
|
|
||||||
bss = s
|
bss = s
|
||||||
}
|
case ".noptrbss":
|
||||||
if s.Name == ".noptrbss" {
|
|
||||||
noptrbss = s
|
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.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
|
||||||
ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.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() {
|
if ctxt.IsSolaris() {
|
||||||
// On Solaris, in the runtime it sets the external names of the
|
// On Solaris, in the runtime it sets the external names of the
|
||||||
// end symbols. Unset them and define separate symbols, so we
|
// end symbols. Unset them and define separate symbols, so we
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,29 @@
|
||||||
|
|
||||||
package fuzz
|
package fuzz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"internal/unsafeheader"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// coverage returns a []byte containing unique 8-bit counters for each edge of
|
// 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
|
// 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
|
// `-d=libfuzzer` is set at build time. This can be used to understand the code
|
||||||
// coverage of a test execution.
|
// 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
|
||||||
|
|
|
||||||
29
src/internal/fuzz/trace.go
Normal file
29
src/internal/fuzz/trace.go
Normal file
|
|
@ -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) {}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue