diff --git a/_scripts/test_linux.sh b/_scripts/test_linux.sh index 56297de2..33b063c0 100755 --- a/_scripts/test_linux.sh +++ b/_scripts/test_linux.sh @@ -41,7 +41,7 @@ GOPATH=$(pwd)/go export GOPATH export PATH=$PATH:$GOROOT/bin:$GOPATH/bin go version -go install honnef.co/go/tools/cmd/staticcheck@2021.1.1 || true +go install honnef.co/go/tools/cmd/staticcheck@2022.1.2 || true uname -a echo "$PATH" diff --git a/cmd/dlv/dlv_test.go b/cmd/dlv/dlv_test.go index 6f337d8f..2bb3a44e 100644 --- a/cmd/dlv/dlv_test.go +++ b/cmd/dlv/dlv_test.go @@ -1182,10 +1182,6 @@ func TestVersion(t *testing.T) { } func TestStaticcheck(t *testing.T) { - if goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) { - //TODO(aarzilli): remove this before version 1.8.0 is released - t.Skip("staticcheck does not currently support Go 1.18") - } _, err := exec.LookPath("staticcheck") if err != nil { t.Skip("staticcheck not installed") diff --git a/pkg/proc/disasm.go b/pkg/proc/disasm.go index 161f81b7..92c5b3b6 100644 --- a/pkg/proc/disasm.go +++ b/pkg/proc/disasm.go @@ -150,9 +150,7 @@ func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *Breakpoint for len(mem) > 0 { bp, atbp := breakpoints.M[pc] if atbp { - for i := range bp.OriginalData { - mem[i] = bp.OriginalData[i] - } + copy(mem, bp.OriginalData) } file, line, fn := bi.PCToLine(pc) diff --git a/pkg/proc/internal/ebpf/helpers.go b/pkg/proc/internal/ebpf/helpers.go index faf37179..5e0fc355 100644 --- a/pkg/proc/internal/ebpf/helpers.go +++ b/pkg/proc/internal/ebpf/helpers.go @@ -1,10 +1,8 @@ -//go:build linux && amd64 && cgo && go1.16 -// +build linux,amd64,cgo,go1.16 +//go:build linux && amd64 && go1.16 +// +build linux,amd64,go1.16 package ebpf -// #include "./bpf/include/function_vals.bpf.h" -import "C" import ( "debug/elf" "encoding/binary" @@ -22,6 +20,36 @@ import ( "github.com/cilium/ebpf/ringbuf" ) +//lint:file-ignore U1000 some fields are used by the C program + +// function_parameter_t tracks function_parameter_t from function_vals.bpf.h +type function_parameter_t struct { + kind uint32 + size uint32 + offset int32 + in_reg bool + n_pieces int32 + reg_nums [6]int32 + daddr uint64 + val [0x30]byte + deref_val [0x30]byte +} + +// function_parameter_list_t tracks function_parameter_list_t from function_vals.bpf.h +type function_parameter_list_t struct { + goid_offset uint32 + g_addr_offset uint64 + goroutine_id uint32 + fn_addr uint32 + is_ret bool + + n_parameters uint32 + params [6]function_parameter_t + + n_ret_parameters uint32 + ret_params [6]function_parameter_t +} + //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -tags "go1.16" -target amd64 trace bpf/trace.bpf.c -- -I./bpf/include const FakeAddressBase = 0xbeed000000000000 @@ -56,7 +84,7 @@ func (ctx *EBPFContext) UpdateArgMap(key uint64, goidOffset int64, args []UProbe return errors.New("eBPF map not loaded") } params := createFunctionParameterList(key, goidOffset, args, isret) - params.g_addr_offset = C.longlong(gAddrOffset) + params.g_addr_offset = gAddrOffset return ctx.bpfArgMap.Update(unsafe.Pointer(&key), unsafe.Pointer(¶ms), ebpf.UpdateAny) } @@ -118,7 +146,7 @@ func LoadEBPFTracingProgram(path string) (*EBPFContext, error) { } func parseFunctionParameterList(rawParamBytes []byte) RawUProbeParams { - params := (*C.function_parameter_list_t)(unsafe.Pointer(&rawParamBytes[0])) + params := (*function_parameter_list_t)(unsafe.Pointer(&rawParamBytes[0])) defer runtime.KeepAlive(params) // Ensure the param is not garbage collected. @@ -126,14 +154,14 @@ func parseFunctionParameterList(rawParamBytes []byte) RawUProbeParams { rawParams.FnAddr = int(params.fn_addr) rawParams.GoroutineID = int(params.goroutine_id) - parseParam := func(param C.function_parameter_t) *RawUProbeParam { + parseParam := func(param function_parameter_t) *RawUProbeParam { iparam := &RawUProbeParam{} data := make([]byte, 0x60) ret := param iparam.Kind = reflect.Kind(ret.kind) - val := C.GoBytes(unsafe.Pointer(&ret.val), C.int(ret.size)) - rawDerefValue := C.GoBytes(unsafe.Pointer(&ret.deref_val[0]), 0x30) + val := ret.val[:ret.size] + rawDerefValue := ret.deref_val[:0x30] copy(data, val) copy(data[0x30:], rawDerefValue) iparam.Data = data @@ -166,26 +194,26 @@ func parseFunctionParameterList(rawParamBytes []byte) RawUProbeParams { return rawParams } -func createFunctionParameterList(entry uint64, goidOffset int64, args []UProbeArgMap, isret bool) C.function_parameter_list_t { - var params C.function_parameter_list_t - params.goid_offset = C.uint(goidOffset) - params.fn_addr = C.uint(entry) - params.is_ret = C.bool(isret) - params.n_parameters = C.uint(0) - params.n_ret_parameters = C.uint(0) +func createFunctionParameterList(entry uint64, goidOffset int64, args []UProbeArgMap, isret bool) function_parameter_list_t { + var params function_parameter_list_t + params.goid_offset = uint32(goidOffset) + params.fn_addr = uint32(entry) + params.is_ret = isret + params.n_parameters = 0 + params.n_ret_parameters = 0 for _, arg := range args { - var param C.function_parameter_t - param.size = C.uint(arg.Size) - param.offset = C.int(arg.Offset) - param.kind = C.uint(arg.Kind) + var param function_parameter_t + param.size = uint32(arg.Size) + param.offset = int32(arg.Offset) + param.kind = uint32(arg.Kind) if arg.InReg { param.in_reg = true - param.n_pieces = C.int(len(arg.Pieces)) + param.n_pieces = int32(len(arg.Pieces)) for i := range arg.Pieces { if i > 5 { break } - param.reg_nums[i] = C.int(arg.Pieces[i]) + param.reg_nums[i] = int32(arg.Pieces[i]) } } if !arg.Ret { diff --git a/pkg/proc/internal/ebpf/helpers_disabled.go b/pkg/proc/internal/ebpf/helpers_disabled.go index daf7f091..66d18c52 100644 --- a/pkg/proc/internal/ebpf/helpers_disabled.go +++ b/pkg/proc/internal/ebpf/helpers_disabled.go @@ -1,5 +1,5 @@ -//go:build !linux || !amd64 || !go1.16 || !cgo -// +build !linux !amd64 !go1.16 !cgo +//go:build !linux || !amd64 || !go1.16 +// +build !linux !amd64 !go1.16 package ebpf diff --git a/pkg/proc/internal/ebpf/helpers_test.go b/pkg/proc/internal/ebpf/helpers_test.go new file mode 100644 index 00000000..8843ecb3 --- /dev/null +++ b/pkg/proc/internal/ebpf/helpers_test.go @@ -0,0 +1,43 @@ +//go:build linux && amd64 && cgo && go1.16 +// +build linux,amd64,cgo,go1.16 + +package ebpf + +import ( + "reflect" + "testing" + + "github.com/go-delve/delve/pkg/proc/internal/ebpf/testhelper" +) + +func compareStructTypes(t *testing.T, gostructVal, cstructVal interface{}) { + gostruct := reflect.ValueOf(gostructVal).Type() + cstruct := reflect.ValueOf(cstructVal).Type() + if gostruct.NumField() != cstruct.NumField() { + t.Errorf("mismatched field number %d %d", gostruct.NumField(), cstruct.NumField()) + return + } + for i := 0; i < cstruct.NumField(); i++ { + gofield := gostruct.Field(i) + cfield := cstruct.Field(i) + t.Logf("%d %s %s\n", i, gofield.Name, cfield.Name) + if gofield.Name != cfield.Name { + t.Errorf("mismatched name for field %s %s", gofield.Name, cfield.Name) + } + if gofield.Offset != cfield.Offset { + t.Errorf("mismatched offset for field %s %s (%d %d)", gofield.Name, cfield.Name, gofield.Offset, cfield.Offset) + } + if gofield.Type.Size() != cfield.Type.Size() { + t.Errorf("mismatched size for field %s %s (%d %d)", gofield.Name, cfield.Name, gofield.Type.Size(), cfield.Type.Size()) + } + } +} + +func TestStructConsistency(t *testing.T) { + t.Run("function_parameter_t", func(t *testing.T) { + compareStructTypes(t, function_parameter_t{}, testhelper.Function_parameter_t{}) + }) + t.Run("function_parameter_list_t", func(t *testing.T) { + compareStructTypes(t, function_parameter_list_t{}, testhelper.Function_parameter_list_t{}) + }) +} diff --git a/pkg/proc/internal/ebpf/testhelper/testhelper.go b/pkg/proc/internal/ebpf/testhelper/testhelper.go new file mode 100644 index 00000000..2441990d --- /dev/null +++ b/pkg/proc/internal/ebpf/testhelper/testhelper.go @@ -0,0 +1,13 @@ +//go:build linux && amd64 && cgo && go1.16 +// +build linux,amd64,cgo,go1.16 + +package testhelper + +// #include "../bpf/include/function_vals.bpf.h" +import "C" + +// Function_parameter_t exports function_parameter_t from function_vals.bpf.h +type Function_parameter_t C.function_parameter_t + +// Function_parameter_list_t exports function_parameter_list_t from function_vals.bpf.h +type Function_parameter_list_t C.function_parameter_list_t