*: Initial eBPF tracing support (#2625)

This commit is contained in:
Derek Parker 2021-07-31 08:16:26 -07:00 committed by GitHub
parent 89ed5a0b19
commit 10406f96d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
365 changed files with 155511 additions and 22654 deletions

3
.gitignore vendored

@ -2,7 +2,7 @@
.tags*
tags
.dbg_history
cmd/dlv/dlv
**/**/dlv
.vagrant
**/*.swp
localtests
@ -10,3 +10,4 @@ localtests
*.iml
.teamcity/target
.vscode
**/*.o

@ -26,6 +26,7 @@ clear_breakpoint(Id, Name) | Equivalent to API call [ClearBreakpoint](https://go
clear_checkpoint(ID) | Equivalent to API call [ClearCheckpoint](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.ClearCheckpoint)
raw_command(Name, ThreadID, GoroutineID, ReturnInfoLoadConfig, Expr, UnsafeCall) | Equivalent to API call [Command](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Command)
create_breakpoint(Breakpoint) | Equivalent to API call [CreateBreakpoint](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.CreateBreakpoint)
create_ebpf_tracepoint(FunctionName) | Equivalent to API call [CreateEBPFTracepoint](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.CreateEBPFTracepoint)
create_watchpoint(Scope, Expr, Type) | Equivalent to API call [CreateWatchpoint](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.CreateWatchpoint)
detach(Kill) | Equivalent to API call [Detach](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Detach)
disassemble(Scope, StartPC, EndPC, Flavour) | Equivalent to API call [Disassemble](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.Disassemble)
@ -37,6 +38,7 @@ examine_memory(Address, Length) | Equivalent to API call [ExamineMemory](https:/
find_location(Scope, Loc, IncludeNonExecutableLines, SubstitutePathRules) | Equivalent to API call [FindLocation](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.FindLocation)
function_return_locations(FnName) | Equivalent to API call [FunctionReturnLocations](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.FunctionReturnLocations)
get_breakpoint(Id, Name) | Equivalent to API call [GetBreakpoint](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.GetBreakpoint)
get_buffered_tracepoints() | Equivalent to API call [GetBufferedTracepoints](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.GetBufferedTracepoints)
get_thread(Id) | Equivalent to API call [GetThread](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.GetThread)
is_multiclient() | Equivalent to API call [IsMulticlient](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.IsMulticlient)
last_modified() | Equivalent to API call [LastModified](https://godoc.org/github.com/go-delve/delve/service/rpc2#RPCServer.LastModified)

@ -21,11 +21,12 @@ dlv trace [package] regexp [flags]
### Options
```
--ebpf Trace using eBPF (experimental).
-e, --exec string Binary file to exec and trace.
-h, --help help for trace
--output string Output path for the binary. (default "debug")
-p, --pid int Pid to attach to.
-s, --stack int Show stack trace with given depth.
-s, --stack int Show stack trace with given depth. (Ignored with -ebpf)
-t, --test Trace a test binary.
```

@ -1,12 +1,30 @@
.DEFAULT_GOAL=test
BPF_OBJ := pkg/proc/internal/ebpf/trace_probe/trace.o
BPF_SRC := $(shell find . -type f -name '*.bpf.*')
GO_SRC := $(shell find . -type f -not -path './_fixtures/*' -not -path './vendor/*' -not -path './_scripts/*' -not -path './localtests/*' -name '*.go')
check-cert:
@go run _scripts/make.go check-cert
build:
build: $(GO_SRC)
@go run _scripts/make.go build
install:
$(BPF_OBJ): $(BPF_SRC)
clang \
-I /usr/include \
-I /usr/src/kernels/$(uname -r)/tools/lib \
-I /usr/src/kernels/$(uname -r)/tools/bpf/resolve_btfids/libbpf \
-g -O2 \
-c \
-target bpf \
-o $(BPF_OBJ) \
pkg/proc/internal/ebpf/trace_probe/trace.bpf.c
build-bpf: $(BPF_OBJ) $(GO_SRC)
@env CGO_LDFLAGS="/usr/lib64/libbpf.a" go run _scripts/make.go build --tags=ebpf
install: $(GO_SRC)
@go run _scripts/make.go install
uninstall:
@ -27,4 +45,4 @@ test-integration-run:
vendor:
@go run _scripts/make.go vendor
.PHONY: vendor test-integration-run test-proc-run test check-cert install build vet
.PHONY: vendor test-integration-run test-proc-run test check-cert install build vet build-bpf uninstall

@ -111,6 +111,8 @@ func processServerMethods(serverMethods []*types.Func) []binding {
name = "set_expr"
case "command":
name = "raw_command"
case "create_e_b_p_f_tracepoint":
name = "create_ebpf_tracepoint"
default:
// remove list_ prefix, it looks better
const listPrefix = "list_"

@ -21,6 +21,7 @@ var Verbose bool
var NOTimeout bool
var TestIncludePIE bool
var TestSet, TestRegex, TestBackend, TestBuildMode string
var Tags *[]string
func NewMakeCommands() *cobra.Command {
RootCommand := &cobra.Command{
@ -34,17 +35,27 @@ func NewMakeCommands() *cobra.Command {
Run: checkCertCmd,
})
RootCommand.AddCommand(&cobra.Command{
buildCmd := &cobra.Command{
Use: "build",
Short: "Build delve",
Run: func(cmd *cobra.Command, args []string) {
tagFlag := prepareMacnative()
execute("go", "build", tagFlag, buildFlags(), DelveMainPackagePath)
if len(*Tags) > 0 {
if len(tagFlag) == 0 {
tagFlag = "-tags="
} else {
tagFlag += ","
}
tagFlag += strings.Join(*Tags, ",")
}
execute("go", "build", "-ldflags", "-extldflags -static", tagFlag, buildFlags(), DelveMainPackagePath)
if runtime.GOOS == "darwin" && os.Getenv("CERT") != "" && canMacnative() {
codesign("./dlv")
}
},
})
}
Tags = buildCmd.PersistentFlags().StringArray("tags", []string{}, "Build tags")
RootCommand.AddCommand(buildCmd)
RootCommand.AddCommand(&cobra.Command{
Use: "install",

@ -9,6 +9,7 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"reflect"
"runtime"
"strconv"
"strings"
@ -76,6 +77,7 @@ var (
traceExecFile string
traceTestBinary bool
traceStackDepth int
traceUseEBPF bool
// redirect specifications for target process
redirects []string
@ -283,7 +285,8 @@ only see the output of the trace operations you can redirect stdout.`,
traceCommand.Flags().IntVarP(&traceAttachPid, "pid", "p", 0, "Pid to attach to.")
traceCommand.Flags().StringVarP(&traceExecFile, "exec", "e", "", "Binary file to exec and trace.")
traceCommand.Flags().BoolVarP(&traceTestBinary, "test", "t", false, "Trace a test binary.")
traceCommand.Flags().IntVarP(&traceStackDepth, "stack", "s", 0, "Show stack trace with given depth.")
traceCommand.Flags().BoolVarP(&traceUseEBPF, "ebpf", "", false, "Trace using eBPF (experimental).")
traceCommand.Flags().IntVarP(&traceStackDepth, "stack", "s", 0, "Show stack trace with given depth. (Ignored with -ebpf)")
traceCommand.Flags().String("output", "debug", "Output path for the binary.")
rootCommand.AddCommand(traceCommand)
@ -522,13 +525,14 @@ func traceCmd(cmd *cobra.Command, args []string) {
dlvArgs = dlvArgs[:dlvArgsLen-1]
}
var debugname string
if traceAttachPid == 0 {
if dlvArgsLen >= 2 && traceExecFile != "" {
fmt.Fprintln(os.Stderr, "Cannot specify package when using exec.")
return 1
}
debugname := traceExecFile
debugname = traceExecFile
if traceExecFile == "" {
debugname, err = filepath.Abs(cmd.Flag("output").Value.String())
if err != nil {
@ -583,39 +587,79 @@ func traceCmd(cmd *cobra.Command, args []string) {
return 1
}
for i := range funcs {
_, err = client.CreateBreakpoint(&api.Breakpoint{
FunctionName: funcs[i],
Tracepoint: true,
Line: -1,
Stacktrace: traceStackDepth,
LoadArgs: &terminal.ShortLoadConfig,
})
if err != nil && !isBreakpointExistsErr(err) {
fmt.Fprintln(os.Stderr, err)
return 1
}
addrs, err := client.FunctionReturnLocations(funcs[i])
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
for i := range addrs {
if traceUseEBPF {
err := client.CreateEBPFTracepoint(funcs[i])
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
} else {
// Fall back to breakpoint based tracing if we get an error.
_, err = client.CreateBreakpoint(&api.Breakpoint{
Addr: addrs[i],
TraceReturn: true,
Stacktrace: traceStackDepth,
Line: -1,
LoadArgs: &terminal.ShortLoadConfig,
FunctionName: funcs[i],
Tracepoint: true,
Line: -1,
Stacktrace: traceStackDepth,
LoadArgs: &terminal.ShortLoadConfig,
})
if err != nil && !isBreakpointExistsErr(err) {
fmt.Fprintln(os.Stderr, err)
return 1
}
addrs, err := client.FunctionReturnLocations(funcs[i])
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
for i := range addrs {
_, err = client.CreateBreakpoint(&api.Breakpoint{
Addr: addrs[i],
TraceReturn: true,
Stacktrace: traceStackDepth,
Line: -1,
LoadArgs: &terminal.ShortLoadConfig,
})
if err != nil && !isBreakpointExistsErr(err) {
fmt.Fprintln(os.Stderr, err)
return 1
}
}
}
}
cmds := terminal.DebugCommands(client)
t := terminal.New(client, nil)
defer t.Close()
if traceUseEBPF {
done := make(chan struct{})
defer close(done)
go func() {
for {
select {
case <-done:
return
default:
tracepoints, err := client.GetBufferedTracepoints()
if err != nil {
panic(err)
}
for _, t := range tracepoints {
var params strings.Builder
for _, p := range t.InputParams {
if params.Len() > 0 {
params.WriteString(", ")
}
if p.Kind == reflect.String {
params.WriteString(fmt.Sprintf("%q", p.Value))
} else {
params.WriteString(p.Value)
}
}
fmt.Printf("%s:%d %s(%s)\n", t.File, t.Line, t.FunctionName, params.String())
}
}
}
}()
}
cmds.Call("continue", t)
return 0
}()

5
go.mod

@ -1,8 +1,9 @@
module github.com/go-delve/delve
go 1.11
go 1.16
require (
github.com/aquasecurity/libbpfgo v0.1.2-0.20210708203834-4928d36fafac
github.com/cosiner/argv v0.1.0
github.com/creack/pty v1.1.9
github.com/google/go-dap v0.5.0
@ -14,7 +15,7 @@ require (
github.com/spf13/cobra v1.1.3
go.starlark.net v0.0.0-20200821142938-949cc6f4b097
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015
golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f
gopkg.in/yaml.v2 v2.4.0
)

12
go.sum

@ -16,6 +16,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/aquasecurity/libbpfgo v0.1.2-0.20210708203834-4928d36fafac h1:oehMMAySC3p8eSwcwQ8lTXxeCkkPll+AwNesUNowbJ8=
github.com/aquasecurity/libbpfgo v0.1.2-0.20210708203834-4928d36fafac/go.mod h1:/+clceXE103FaXvVTIY2HAkQjxNtkra4DRWvZYr2SKw=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
@ -181,10 +183,13 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
@ -257,8 +262,9 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -317,6 +323,8 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

@ -787,6 +787,7 @@ func readType(d *dwarf.Data, name string, r *dwarf.Reader, off dwarf.Offset, typ
case reflect.String:
str := new(StringType)
t = &str.StructType
str.ReflectKind = reflect.String
typ = str
default:
typ = t

@ -145,7 +145,7 @@ func PrettyPrint(out io.Writer, instructions []byte) {
func callframecfa(opcode Opcode, ctxt *context) error {
if ctxt.CFA == 0 {
return fmt.Errorf("Could not retrieve CFA for current PC")
return errors.New("could not retrieve CFA for current PC")
}
ctxt.stack = append(ctxt.stack, int64(ctxt.CFA))
return nil

@ -1,6 +1,7 @@
package proc
import (
"debug/dwarf"
"errors"
"fmt"
"go/ast"
@ -8,6 +9,11 @@ import (
"go/parser"
"go/token"
"reflect"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/reader"
"github.com/go-delve/delve/pkg/goversion"
"github.com/go-delve/delve/pkg/proc/internal/ebpf"
)
const (
@ -384,6 +390,52 @@ func (t *Target) SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Expr)
return t.setBreakpointInternal(addr, kind, 0, cond)
}
func (t *Target) SetEBPFTracepoint(fnName string) error {
if !t.proc.SupportsBPF() {
return errors.New("eBPF is not supported")
}
var args []ebpf.UProbeArgMap
fn, ok := t.BinInfo().LookupFunc[fnName]
if !ok {
return fmt.Errorf("could not find function %s", fnName)
}
dwarfTree, err := fn.cu.image.getDwarfTree(fn.offset)
if err != nil {
return err
}
variablesFlags := reader.VariablesOnlyVisible
if t.BinInfo().Producer() != "" && goversion.ProducerAfterOrEqual(t.BinInfo().Producer(), 1, 15) {
variablesFlags |= reader.VariablesTrustDeclLine
}
_, l, _ := t.BinInfo().PCToLine(fn.Entry)
varEntries := reader.Variables(dwarfTree, fn.Entry, l, variablesFlags)
for _, entry := range varEntries {
isret, _ := entry.Val(dwarf.AttrVarParam).(bool)
if isret {
continue
}
_, dt, err := readVarEntry(entry.Tree, fn.cu.image)
if err != nil {
return err
}
offset, pieces, _, err := t.BinInfo().Location(entry, dwarf.AttrLocation, fn.Entry, op.DwarfRegisters{})
if err != nil {
return err
}
paramPieces := make([]int, 0, len(pieces))
for _, piece := range pieces {
if piece.Kind == op.RegPiece {
paramPieces = append(paramPieces, int(piece.Val))
}
}
offset += int64(t.BinInfo().Arch.PtrSize())
args = append(args, ebpf.UProbeArgMap{Offset: offset, Size: dt.Size(), Kind: dt.Common().ReflectKind, Pieces: paramPieces, InReg: len(pieces) > 0})
}
t.proc.SetUProbe(fnName, args)
return nil
}
// SetWatchpoint sets a data breakpoint at addr and stores it in the
// process wide break point table.
func (t *Target) SetWatchpoint(scope *EvalScope, expr string, wtype WatchType, cond ast.Expr) (*Breakpoint, error) {

@ -5,9 +5,10 @@ import (
"fmt"
"io"
"github.com/go-delve/delve/pkg/elfwriter"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/elfwriter"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/internal/ebpf"
)
// ErrNoThreads core file did not contain any threads.
@ -269,6 +270,14 @@ func (p *process) Checkpoints() ([]proc.Checkpoint, error) { return nil, nil }
// ClearCheckpoint clears a checkpoint, but will only return an error for core files.
func (p *process) ClearCheckpoint(int) error { return errors.New("checkpoint not found") }
func (p *process) SupportsBPF() bool {
return false
}
func (dbp *process) SetUProbe(fnName string, args []ebpf.UProbeArgMap) error {
panic("not implemented")
}
// ReadMemory will return memory from the core file at the specified location and put the
// read memory into `data`, returning the length read, and returning an error if
// the length read is shorter than the length of the `data` buffer.
@ -471,3 +480,7 @@ func (p *process) MemoryMap() ([]proc.MemoryMapEntry, error) {
func (p *process) DumpProcessNotes(notes []elfwriter.Note, threadDone func()) (threadsDone bool, out []elfwriter.Note, err error) {
return false, notes, nil
}
func (dbp *process) GetBufferedTracepoints() []ebpf.RawUProbeParams {
return nil
}

@ -81,6 +81,7 @@ import (
"github.com/go-delve/delve/pkg/elfwriter"
"github.com/go-delve/delve/pkg/logflags"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/internal/ebpf"
"github.com/go-delve/delve/pkg/proc/linutil"
"github.com/go-delve/delve/pkg/proc/macutil"
isatty "github.com/mattn/go-isatty"
@ -361,6 +362,18 @@ func (p *gdbProcess) Connect(conn net.Conn, path string, pid int, debugInfoDirs
return tgt, nil
}
func (p *gdbProcess) SupportsBPF() bool {
return false
}
func (dbp *gdbProcess) GetBufferedTracepoints() []ebpf.RawUProbeParams {
return nil
}
func (dbp *gdbProcess) SetUProbe(fnName string, args []ebpf.UProbeArgMap) error {
panic("not implemented")
}
// unusedPort returns an unused tcp port
// This is a hack and subject to a race condition with other running
// programs, but most (all?) OS will cycle through all ephemeral ports

@ -1,6 +1,9 @@
package proc
import "github.com/go-delve/delve/pkg/elfwriter"
import (
"github.com/go-delve/delve/pkg/elfwriter"
"github.com/go-delve/delve/pkg/proc/internal/ebpf"
)
// Process represents the target of the debugger. This
// target could be a system process, core file, etc.
@ -42,11 +45,16 @@ type ProcessInternal interface {
WriteBreakpoint(*Breakpoint) error
EraseBreakpoint(*Breakpoint) error
SupportsBPF() bool
SetUProbe(string, []ebpf.UProbeArgMap) error
// DumpProcessNotes returns ELF core notes describing the process and its threads.
// Implementing this method is optional.
DumpProcessNotes(notes []elfwriter.Note, threadDone func()) (bool, []elfwriter.Note, error)
// MemoryMap returns the memory map of the target process. This method must be implemented if CanDump is true.
MemoryMap() ([]MemoryMapEntry, error)
GetBufferedTracepoints() []ebpf.RawUProbeParams
}
// RecordingManipulation is an interface for manipulating process recordings.

@ -0,0 +1,31 @@
package ebpf
import (
"reflect"
"github.com/go-delve/delve/pkg/dwarf/godwarf"
"github.com/go-delve/delve/pkg/dwarf/op"
)
type UProbeArgMap struct {
Offset int64 // Offset from the stackpointer.
Size int64 // Size in bytes.
Kind reflect.Kind // Kind of variable.
Pieces []int // Pieces of the variables as stored in registers.
InReg bool // True if this param is contained in a register.
}
type RawUProbeParam struct {
Pieces []op.Piece
RealType godwarf.Type
Kind reflect.Kind
Len int64
Base uint64
Addr uint64
Data []byte
}
type RawUProbeParams struct {
FnAddr int
InputParams []*RawUProbeParam
}

@ -0,0 +1,191 @@
//go:build ebpf
// +build ebpf
package ebpf
// #include "./trace_probe/function_vals.bpf.h"
import "C"
import (
_ "embed"
"encoding/binary"
"errors"
"reflect"
"runtime"
"sync"
"unsafe"
"github.com/go-delve/delve/pkg/dwarf/godwarf"
"github.com/go-delve/delve/pkg/dwarf/op"
bpf "github.com/aquasecurity/libbpfgo"
"github.com/aquasecurity/libbpfgo/helpers"
)
//go:embed trace_probe/trace.o
var TraceProbeBytes []byte
const FakeAddressBase = 0xbeed000000000000
type EBPFContext struct {
bpfModule *bpf.Module
bpfProg *bpf.BPFProg
bpfEvents chan []byte
bpfRingBuf *bpf.RingBuffer
bpfArgMap *bpf.BPFMap
parsedBpfEvents []RawUProbeParams
m sync.Mutex
}
func (ctx *EBPFContext) Close() {
if ctx.bpfModule != nil {
ctx.bpfModule.Close()
}
}
func (ctx *EBPFContext) AttachUprobe(pid int, name string, offset uint32) error {
if ctx.bpfProg == nil {
return errors.New("no eBPF program loaded")
}
_, err := ctx.bpfProg.AttachUprobe(pid, name, offset)
return err
}
func (ctx *EBPFContext) UpdateArgMap(key uint64, args []UProbeArgMap) error {
if ctx.bpfArgMap == nil {
return errors.New("eBPF map not loaded")
}
params := createFunctionParameterList(key, args)
return ctx.bpfArgMap.Update(unsafe.Pointer(&key), unsafe.Pointer(&params))
}
func (ctx *EBPFContext) GetBufferedTracepoints() []RawUProbeParams {
ctx.m.Lock()
defer ctx.m.Unlock()
if len(ctx.parsedBpfEvents) == 0 {
return make([]RawUProbeParams, 0)
}
events := make([]RawUProbeParams, len(ctx.parsedBpfEvents))
copy(events, ctx.parsedBpfEvents)
ctx.parsedBpfEvents = ctx.parsedBpfEvents[:0]
return events
}
func SymbolToOffset(file, symbol string) (uint32, error) {
return helpers.SymbolToOffset(file, symbol)
}
func LoadEBPFTracingProgram() (*EBPFContext, error) {
var ctx EBPFContext
var err error
ctx.bpfModule, err = bpf.NewModuleFromBuffer(TraceProbeBytes, "trace.o")
if err != nil {
return nil, err
}
ctx.bpfModule.BPFLoadObject()
prog, err := ctx.bpfModule.GetProgram("uprobe__dlv_trace")
if err != nil {
return nil, err
}
ctx.bpfProg = prog
ctx.bpfEvents = make(chan []byte)
ctx.bpfRingBuf, err = ctx.bpfModule.InitRingBuf("events", ctx.bpfEvents)
if err != nil {
return nil, err
}
ctx.bpfRingBuf.Start()
ctx.bpfArgMap, err = ctx.bpfModule.GetMap("arg_map")
if err != nil {
return nil, err
}
// TODO(derekparker): This should eventually be moved to a more generalized place.
go func() {
for {
b, ok := <-ctx.bpfEvents
if !ok {
return
}
parsed := ParseFunctionParameterList(b)
ctx.m.Lock()
ctx.parsedBpfEvents = append(ctx.parsedBpfEvents, parsed)
ctx.m.Unlock()
}
}()
return &ctx, nil
}
func ParseFunctionParameterList(rawParamBytes []byte) RawUProbeParams {
params := (*C.function_parameter_list_t)(unsafe.Pointer(&rawParamBytes[0]))
defer runtime.KeepAlive(params) // Ensure the param is not garbage collected.
var rawParams RawUProbeParams
rawParams.FnAddr = int(params.fn_addr)
for i := 0; i < int(params.n_parameters); i++ {
iparam := &RawUProbeParam{}
data := make([]byte, 0x60)
ret := params.params[i]
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)
copy(data, val)
copy(data[0x30:], rawDerefValue)
iparam.Data = data
pieces := make([]op.Piece, 0, 2)
pieces = append(pieces, op.Piece{Size: 0x30, Kind: op.AddrPiece, Val: FakeAddressBase})
pieces = append(pieces, op.Piece{Size: 0x30, Kind: op.AddrPiece, Val: FakeAddressBase + 0x30})
iparam.Pieces = pieces
iparam.Addr = FakeAddressBase
switch iparam.Kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
iparam.RealType = &godwarf.IntType{BasicType: godwarf.BasicType{CommonType: godwarf.CommonType{ByteSize: 8}}}
case reflect.String:
strLen := binary.LittleEndian.Uint64(val[8:])
iparam.Base = FakeAddressBase + 0x30
iparam.Len = int64(strLen)
}
rawParams.InputParams = append(rawParams.InputParams, iparam)
}
return rawParams
}
func createFunctionParameterList(entry uint64, args []UProbeArgMap) C.function_parameter_list_t {
var params C.function_parameter_list_t
params.n_parameters = C.uint(len(args))
params.fn_addr = C.uint(entry)
for i, arg := range args {
var param C.function_parameter_t
param.size = C.uint(arg.Size)
param.offset = C.uint(arg.Offset)
param.kind = C.uint(arg.Kind)
if arg.InReg {
param.in_reg = true
param.n_pieces = C.int(len(arg.Pieces))
for i := range arg.Pieces {
if i > 5 {
break
}
param.reg_nums[i] = C.int(arg.Pieces[i])
}
}
params.params[i] = param
}
return params
}

@ -0,0 +1,39 @@
//go:build !ebpf
// +build !ebpf
package ebpf
import (
"errors"
)
type EBPFContext struct {
}
func (ctx *EBPFContext) Close() {
}
func (ctx *EBPFContext) AttachUprobe(pid int, name string, offset uint32) error {
return errors.New("eBPF is disabled")
}
func (ctx *EBPFContext) UpdateArgMap(key uint64, args []UProbeArgMap) error {
return errors.New("eBPF is disabled")
}
func (ctx *EBPFContext) GetBufferedTracepoints() []RawUProbeParams {
return nil
}
func SymbolToOffset(file, symbol string) (uint32, error) {
return 0, errors.New("eBPF disabled")
}
func LoadEBPFTracingProgram() (*EBPFContext, error) {
return nil, errors.New("eBPF disabled")
}
func ParseFunctionParameterList(rawParamBytes []byte) RawUProbeParams {
return RawUProbeParams{}
}

@ -0,0 +1,34 @@
#include <stdbool.h>
// function_parameter stores information about a single parameter to a function.
typedef struct function_parameter {
// Type of the parameter as defined by the reflect.Kind enum.
unsigned int kind;
// Size of the variable in bytes.
unsigned int size;
// Offset from stack pointer. This should only be set from the Go side.
unsigned int offset;
// If true, the parameter is passed in a register.
bool in_reg;
// The number of register pieces the parameter is passed in.
int n_pieces;
// If in_reg is true, this represents the registers that the parameter is passed in.
// This is an array because the number of registers may vary and the parameter may be
// passed in multiple registers.
int reg_nums[6];
// The following are filled in by the eBPF program.
unsigned int daddr; // Data address.
char val[0x30]; // Value of the parameter.
char deref_val[0x30]; // Dereference value of the parameter.
} function_parameter_t;
// function_parameter_list holds info about the function parameters and
// stores information on up to 8 parameters.
typedef struct function_parameter_list {
unsigned int fn_addr;
unsigned int n_parameters; // number of parameters.
function_parameter_t params[6]; // list of parameters.
} function_parameter_list_t;

@ -0,0 +1,183 @@
#include "trace.bpf.h"
#include <string.h>
#define STRING_KIND 24
// parse_string_param will parse a string parameter. The parsed value of the string
// will be put into param->deref_val. This function expects the string struct
// which contains a pointer to the string and the length of the string to have
// already been read from memory and passed in as param->val.
__always_inline
int parse_string_param(struct pt_regs *ctx, function_parameter_t *param) {
u64 str_len;
size_t str_addr;
memcpy(&str_addr, param->val, sizeof(str_addr));
memcpy(&str_len, param->val + sizeof(str_addr), sizeof(str_len));
param->daddr = str_addr;
if (str_addr != 0) {
if (str_len > 0x30) {
str_len = 0x30;
}
int ret = bpf_probe_read_user(&param->deref_val, str_len, (void *)(str_addr));
if (ret < 0) {
return 1;
}
}
return 0;
}
__always_inline
int parse_param_stack(struct pt_regs *ctx, function_parameter_t *param) {
long ret;
size_t addr = ctx->sp + param->offset;
ret = bpf_probe_read_user(&param->val, param->size, (void *)(addr));
if (ret < 0) {
return 1;
}
return 0;
}
__always_inline
void get_value_from_register(struct pt_regs *ctx, void *dest, int reg_num) {
switch (reg_num) {
case 0: // RAX
memcpy(dest, &ctx->ax, sizeof(ctx->ax));
break;
case 1: // RDX
memcpy(dest, &ctx->dx, sizeof(ctx->dx));
break;
case 2: // RCX
memcpy(dest, &ctx->cx, sizeof(ctx->cx));
break;
case 3: // RBX
memcpy(dest, &ctx->bx, sizeof(ctx->bx));
break;
case 4: // RSI
memcpy(dest, &ctx->si, sizeof(ctx->si));
break;
case 5: // RDI
memcpy(dest, &ctx->di, sizeof(ctx->di));
break;
case 6: // RBP
memcpy(dest, &ctx->bp, sizeof(ctx->bp));
break;
case 7: // RSP
memcpy(dest, &ctx->sp, sizeof(ctx->sp));
break;
case 8: // R8
memcpy(dest, &ctx->r8, sizeof(ctx->r8));
break;
case 9: // R9
memcpy(dest, &ctx->r9, sizeof(ctx->r9));
break;
case 10: // R10
memcpy(dest, &ctx->r10, sizeof(ctx->r10));
break;
case 11: // R11
memcpy(dest, &ctx->r11, sizeof(ctx->r11));
break;
case 12: // R12
memcpy(dest, &ctx->r12, sizeof(ctx->r12));
break;
case 13: // R13
memcpy(dest, &ctx->r13, sizeof(ctx->r13));
break;
case 14: // R14
memcpy(dest, &ctx->r14, sizeof(ctx->r14));
break;
case 15: // R15
memcpy(dest, &ctx->r15, sizeof(ctx->r15));
break;
}
}
__always_inline
int parse_param_registers(struct pt_regs *ctx, function_parameter_t *param) {
switch (param->n_pieces) {
case 6:
get_value_from_register(ctx, param->val+40, param->reg_nums[5]);
case 5:
get_value_from_register(ctx, param->val+32, param->reg_nums[4]);
case 4:
get_value_from_register(ctx, param->val+24, param->reg_nums[3]);
case 3:
get_value_from_register(ctx, param->val+16, param->reg_nums[2]);
case 2:
get_value_from_register(ctx, param->val+8, param->reg_nums[1]);
case 1:
get_value_from_register(ctx, param->val, param->reg_nums[0]);
}
return 0;
}
__always_inline
int parse_param(struct pt_regs *ctx, function_parameter_t *param) {
if (param->size > 0x30) {
return 0;
}
// Parse the initial value of the parameter.
// If the parameter is a basic type, we will be finished here.
// If the parameter is a more complex type such as a string or
// a slice we will need some further processing below.
int ret = 0;
if (param->in_reg) {
parse_param_registers(ctx, param);
} else {
parse_param_stack(ctx, param);
}
if (ret != 0) {
return ret;
}
switch (param->kind) {
case STRING_KIND:
return parse_string_param(ctx, param);
}
return 0;
}
SEC("uprobe/dlv_trace")
int uprobe__dlv_trace(struct pt_regs *ctx) {
function_parameter_list_t *args;
function_parameter_list_t *parsed_args;
function_parameter_t param;
uint64_t key = ctx->ip;
args = bpf_map_lookup_elem(&arg_map, &key);
if (!args) {
return 1;
}
parsed_args = bpf_ringbuf_reserve(&events, sizeof(function_parameter_list_t), 0);
if (!parsed_args) {
return 1;
}
memcpy(parsed_args, args, sizeof(function_parameter_list_t));
// Since we cannot loop in eBPF programs let's take adavantage of the
// fact that in C switch cases will pass through automatically.
switch (args->n_parameters) {
case 6:
parse_param(ctx, &parsed_args->params[5]);
case 5:
parse_param(ctx, &parsed_args->params[4]);
case 4:
parse_param(ctx, &parsed_args->params[3]);
case 3:
parse_param(ctx, &parsed_args->params[2]);
case 2:
parse_param(ctx, &parsed_args->params[1]);
case 1:
parse_param(ctx, &parsed_args->params[0]);
}
bpf_ringbuf_submit(parsed_args, 0);
return 0;
}
char _license[] SEC("license") = "GPL";

@ -0,0 +1,19 @@
#include "vmlinux.h"
#include "function_vals.bpf.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#define BPF_MAX_VAR_SIZ (1 << 29)
// Ring buffer to handle communication of variable values back to userspace.
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, BPF_MAX_VAR_SIZ);
} events SEC(".maps");
struct {
__uint(max_entries, 42);
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u64);
__type(value, function_parameter_list_t);
} arg_map SEC(".maps");

File diff suppressed because it is too large Load Diff

@ -58,6 +58,10 @@ func (m *memCache) WriteMemory(addr uint64, data []byte) (written int, err error
return m.mem.WriteMemory(addr, data)
}
func CreateLoadedCachedMemory(data []byte) MemoryReadWriter {
return &memCache{loaded: true, cacheAddr: fakeAddressUnresolv, cache: data, mem: nil}
}
func cacheMemory(mem MemoryReadWriter, addr uint64, size int) MemoryReadWriter {
if !cacheEnabled {
return mem
@ -92,6 +96,18 @@ type compositeMemory struct {
data []byte
}
// CreateCompositeMemory created a new composite memory type using the provided MemoryReadWriter as the
// underlying memory buffer.
func CreateCompositeMemory(mem MemoryReadWriter, arch *Arch, regs op.DwarfRegisters, pieces []op.Piece) (*compositeMemory, error) {
// This is basically a small wrapper to avoid having to change all callers
// of newCompositeMemory since it existed first.
cm, err := newCompositeMemory(mem, arch, regs, pieces)
if cm != nil {
cm.base = fakeAddressUnresolv
}
return cm, err
}
func newCompositeMemory(mem MemoryReadWriter, arch *Arch, regs op.DwarfRegisters, pieces []op.Piece) (*compositeMemory, error) {
cmem := &compositeMemory{realmem: mem, arch: arch, regs: regs, pieces: pieces, data: []byte{}}
for i := range pieces {

@ -1,4 +1,5 @@
//+build darwin,!macnative
//go:build darwin && !macnative
// +build darwin,!macnative
package native
@ -8,6 +9,7 @@ import (
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/internal/ebpf"
)
var ErrNativeBackendDisabled = errors.New("native backend disabled during compilation")
@ -32,6 +34,8 @@ type osSpecificDetails struct{}
// osProcessDetails holds Darwin specific information.
type osProcessDetails struct{}
func (os *osProcessDetails) Close() {}
func findExecutable(path string, pid int) string {
panic(ErrNativeBackendDisabled)
}
@ -82,6 +86,18 @@ func (dbp *nativeProcess) EntryPoint() (uint64, error) {
panic(ErrNativeBackendDisabled)
}
func (dbp *nativeProcess) SupportsBPF() bool {
panic(ErrNativeBackendDisabled)
}
func (dbp *nativeProcess) SetUProbe(fnName string, args []ebpf.UProbeArgMap) error {
panic(ErrNativeBackendDisabled)
}
func (dbp *nativeProcess) GetBufferedTracepoints() []ebpf.RawUProbeParams {
panic(ErrNativeBackendDisabled)
}
// SetPC sets the value of the PC register.
func (t *nativeThread) setPC(pc uint64) error {
panic(ErrNativeBackendDisabled)

@ -343,6 +343,7 @@ func (dbp *nativeProcess) postExit() {
if dbp.ctty != nil {
dbp.ctty.Close()
}
dbp.os.Close()
}
func (dbp *nativeProcess) writeSoftwareBreakpoint(thread *nativeThread, addr uint64) error {

@ -1,4 +1,5 @@
//+build darwin,macnative
//go:build darwin && macnative
// +build darwin,macnative
package native
@ -18,6 +19,7 @@ import (
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/internal/ebpf"
"github.com/go-delve/delve/pkg/proc/macutil"
)
@ -34,6 +36,8 @@ type osProcessDetails struct {
portSet C.mach_port_t
}
func (os *osProcessDetails) Close() {}
// Launch creates and begins debugging a new process. Uses a
// custom fork/exec process in order to take advantage of
// PT_SIGEXC on Darwin which will turn Unix signals into
@ -469,4 +473,16 @@ func (dbp *nativeProcess) EntryPoint() (uint64, error) {
return 0, nil
}
func (dbp *nativeProcess) SupportsBPF() bool {
return false
}
func (dbp *nativeProcess) SetUProbe(fnName string, args []ebpf.UProbeArgMap) error {
panic("not implemented")
}
func (dbp *nativeProcess) GetBufferedTracepoints() []ebpf.RawUProbeParams {
panic("not implemented")
}
func initialize(dbp *nativeProcess) error { return nil }

@ -0,0 +1,8 @@
//go:build ebpf
// +build ebpf
package native
func (dbp *nativeProcess) SupportsBPF() bool {
return true
}

@ -15,6 +15,7 @@ import (
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/internal/ebpf"
isatty "github.com/mattn/go-isatty"
)
@ -37,6 +38,8 @@ type osProcessDetails struct {
tid int
}
func (os *osProcessDetails) Close() {}
// Launch creates and begins debugging a new process. First entry in
// `cmd` is the program to run, and then rest are the arguments
// to be supplied to that process. `wd` is working directory of the program.
@ -374,6 +377,18 @@ func (dbp *nativeProcess) EntryPoint() (uint64, error) {
return uint64(ep), err
}
func (dbp *nativeProcess) SupportsBPF() bool {
return false
}
func (dbp *nativeProcess) SetUProbe(fnName string, args []ebpf.UProbeArgMap) error {
panic("not implemented")
}
func (dbp *nativeProcess) GetBufferedTracepoints() []ebpf.RawUProbeParams {
panic("not implemented")
}
// Usedy by Detach
func killProcess(pid int) error {
return sys.Kill(pid, sys.SIGINT)

@ -19,6 +19,7 @@ import (
sys "golang.org/x/sys/unix"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/pkg/proc/internal/ebpf"
"github.com/go-delve/delve/pkg/proc/linutil"
isatty "github.com/mattn/go-isatty"
@ -45,6 +46,14 @@ const (
// process details.
type osProcessDetails struct {
comm string
ebpf *ebpf.EBPFContext
}
func (os *osProcessDetails) Close() {
if os.ebpf != nil {
os.ebpf.Close()
}
}
// Launch creates and begins debugging a new process. First entry in
@ -183,9 +192,17 @@ func initialize(dbp *nativeProcess) error {
comm = match[1]
}
dbp.os.comm = strings.ReplaceAll(string(comm), "%", "%%")
return nil
}
func (dbp *nativeProcess) GetBufferedTracepoints() []ebpf.RawUProbeParams {
if dbp.os.ebpf == nil {
return nil
}
return dbp.os.ebpf.GetBufferedTracepoints()
}
// kill kills the target process.
func (dbp *nativeProcess) kill() error {
if dbp.exited {
@ -213,7 +230,6 @@ func (dbp *nativeProcess) kill() error {
return err
}
}
return nil
}
func (dbp *nativeProcess) requestManualStop() (err error) {
@ -689,6 +705,36 @@ func (dbp *nativeProcess) EntryPoint() (uint64, error) {
return linutil.EntryPointFromAuxv(auxvbuf, dbp.bi.Arch.PtrSize()), nil
}
func (dbp *nativeProcess) SetUProbe(fnName string, args []ebpf.UProbeArgMap) error {
// Lazily load and initialize the BPF program upon request to set a uprobe.
if dbp.os.ebpf == nil {
dbp.os.ebpf, _ = ebpf.LoadEBPFTracingProgram()
}
// We only allow up to 6 args for a BPF probe.
// Return early if we have more.
if len(args) > 6 {
return errors.New("too many arguments in traced function, max is 6")
}
debugname := dbp.bi.Images[0].Path
offset, err := ebpf.SymbolToOffset(debugname, fnName)
if err != nil {
return err
}
err = dbp.os.ebpf.AttachUprobe(dbp.Pid(), debugname, offset)
if err != nil {
return err
}
fn, ok := dbp.bi.LookupFunc[fnName]
if !ok {
return fmt.Errorf("could not find function: %s", fnName)
}
key := fn.Entry
return dbp.os.ebpf.UpdateArgMap(key, args)
}
func killProcess(pid int) error {
return sys.Kill(pid, sys.SIGINT)
}

@ -0,0 +1,8 @@
//go:build !ebpf
// +build !ebpf
package native
func (dbp *nativeProcess) SupportsBPF() bool {
return false
}

@ -20,6 +20,8 @@ type osProcessDetails struct {
running bool
}
func (os *osProcessDetails) Close() {}
// Launch creates and begins debugging a new process.
func Launch(cmd []string, wd string, flags proc.LaunchFlags, _ []string, _ string, redirects [3]string) (*proc.Target, error) {
argv0Go, err := filepath.Abs(cmd[0])
@ -485,6 +487,13 @@ func (dbp *nativeProcess) EntryPoint() (uint64, error) {
return dbp.os.entryPoint, nil
}
func (dbp *nativeProcess) SupportsBPF() bool {
return true
}
func (dbp *nativeProcess) SetUProbe(fnName string, args []proc.UProbeArgMap) {
}
func killProcess(pid int) error {
p, err := os.FindProcess(pid)
if err != nil {

@ -391,13 +391,46 @@ func (t *Target) CurrentThread() Thread {
return t.currentThread
}
type UProbeTraceResult struct {
FnAddr int
InputParams []*Variable
}
func (t *Target) GetBufferedTracepoints() []*UProbeTraceResult {
var results []*UProbeTraceResult
tracepoints := t.proc.GetBufferedTracepoints()
for _, tp := range tracepoints {
r := &UProbeTraceResult{}
r.FnAddr = tp.FnAddr
for _, ip := range tp.InputParams {
v := &Variable{}
v.RealType = ip.RealType
v.Len = ip.Len
v.Base = ip.Base
v.Addr = ip.Addr
v.Kind = ip.Kind
cachedMem := CreateLoadedCachedMemory(ip.Data)
compMem, _ := CreateCompositeMemory(cachedMem, t.BinInfo().Arch, op.DwarfRegisters{}, ip.Pieces)
v.mem = compMem
// Load the value here so that we don't have to export
// loadValue outside of proc.
v.loadValue(loadFullValue)
r.InputParams = append(r.InputParams, v)
}
results = append(results, r)
}
return results
}
// SetNextBreakpointID sets the breakpoint ID of the next breakpoint
func (t *Target) SetNextBreakpointID(id int) {
t.Breakpoints().breakpointIDCounter = id
}
const (
fakeAddressBase = 0xbeef000000000000
FakeAddressBase = 0xbeef000000000000
fakeAddressUnresolv = 0xbeed000000000000 // this address never resloves to memory
)
@ -435,7 +468,7 @@ func (t *Target) newCompositeMemory(mem MemoryReadWriter, regs op.DwarfRegisters
func (t *Target) registerFakeMemory(mem *compositeMemory) (addr uint64) {
t.fakeMemoryRegistry = append(t.fakeMemoryRegistry, mem)
addr = fakeAddressBase
addr = FakeAddressBase
if len(t.fakeMemoryRegistry) > 1 {
prevMem := t.fakeMemoryRegistry[len(t.fakeMemoryRegistry)-2]
addr = uint64(alignAddr(int64(prevMem.base+uint64(len(prevMem.data))), 0x100)) // the call to alignAddr just makes the address look nicer, it is not necessary

@ -313,6 +313,36 @@ func (env *Env) starlarkPredeclare() starlark.StringDict {
}
return env.interfaceToStarlarkValue(rpcRet), nil
})
r["create_ebpf_tracepoint"] = starlark.NewBuiltin("create_ebpf_tracepoint", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
if err := isCancelled(thread); err != nil {
return starlark.None, decorateError(thread, err)
}
var rpcArgs rpc2.CreateEBPFTracepointIn
var rpcRet rpc2.CreateEBPFTracepointOut
if len(args) > 0 && args[0] != starlark.None {
err := unmarshalStarlarkValue(args[0], &rpcArgs.FunctionName, "FunctionName")
if err != nil {
return starlark.None, decorateError(thread, err)
}
}
for _, kv := range kwargs {
var err error
switch kv[0].(starlark.String) {
case "FunctionName":
err = unmarshalStarlarkValue(kv[1], &rpcArgs.FunctionName, "FunctionName")
default:
err = fmt.Errorf("unknown argument %q", kv[0])
}
if err != nil {
return starlark.None, decorateError(thread, err)
}
}
err := env.ctx.Client().CallAPI("CreateEBPFTracepoint", &rpcArgs, &rpcRet)
if err != nil {
return starlark.None, err
}
return env.interfaceToStarlarkValue(rpcRet), nil
})
r["create_watchpoint"] = starlark.NewBuiltin("create_watchpoint", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
if err := isCancelled(thread); err != nil {
return starlark.None, decorateError(thread, err)
@ -732,6 +762,18 @@ func (env *Env) starlarkPredeclare() starlark.StringDict {
}
return env.interfaceToStarlarkValue(rpcRet), nil
})
r["get_buffered_tracepoints"] = starlark.NewBuiltin("get_buffered_tracepoints", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
if err := isCancelled(thread); err != nil {
return starlark.None, decorateError(thread, err)
}
var rpcArgs rpc2.GetBufferedTracepointsIn
var rpcRet rpc2.GetBufferedTracepointsOut
err := env.ctx.Client().CallAPI("GetBufferedTracepoints", &rpcArgs, &rpcRet)
if err != nil {
return starlark.None, err
}
return env.interfaceToStarlarkValue(rpcRet), nil
})
r["get_thread"] = starlark.NewBuiltin("get_thread", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
if err := isCancelled(thread); err != nil {
return starlark.None, decorateError(thread, err)

@ -48,6 +48,21 @@ type DebuggerState struct {
Err error `json:"-"`
}
type TracepointResult struct {
// Addr is deprecated, use Addrs.
Addr uint64 `json:"addr"`
// File is the source file for the breakpoint.
File string `json:"file"`
// Line is a line in File for the breakpoint.
Line int `json:"line"`
// FunctionName is the name of the function at the current breakpoint, and
// may not always be available.
FunctionName string `json:"functionName,omitempty"`
InputParams []Variable `json:"inputParams,omitempty"`
ReturnParams []Variable `json:"returnParams,omitempty"`
}
// Breakpoint addresses a set of locations at which process execution may be
// suspended.
type Breakpoint struct {

@ -757,6 +757,13 @@ func isBreakpointExistsErr(err error) bool {
return r
}
func (d *Debugger) CreateEBPFTracepoint(fnName string) error {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
return d.target.SetEBPFTracepoint(fnName)
}
// AmendBreakpoint will update the breakpoint with the matching ID.
// It also enables or disables the breakpoint.
func (d *Debugger) AmendBreakpoint(amend *api.Breakpoint) error {
@ -2116,6 +2123,29 @@ func (d *Debugger) Target() *proc.Target {
return d.target
}
func (d *Debugger) GetBufferedTracepoints() []api.TracepointResult {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
traces := d.target.GetBufferedTracepoints()
if traces == nil {
return nil
}
results := make([]api.TracepointResult, len(traces))
for i, trace := range traces {
f, l, fn := d.target.BinInfo().PCToLine(uint64(trace.FnAddr))
results[i].FunctionName = fn.Name
results[i].Line = l
results[i].File = f
for _, p := range trace.InputParams {
results[i].InputParams = append(results[i].InputParams, *api.ConvertVar(p))
}
}
return results
}
func go11DecodeErrorCheck(err error) error {
if _, isdecodeerr := err.(dwarf.DecodeError); !isdecodeerr {
return err

@ -214,6 +214,12 @@ func (c *RPCClient) Halt() (*api.DebuggerState, error) {
return &out.State, err
}
func (c *RPCClient) GetBufferedTracepoints() ([]api.TracepointResult, error) {
var out GetBufferedTracepointsOut
err := c.call("GetBufferedTracepoints", GetBufferedTracepointsIn{}, &out)
return out.TracepointResults, err
}
func (c *RPCClient) GetBreakpoint(id int) (*api.Breakpoint, error) {
var out GetBreakpointOut
err := c.call("GetBreakpoint", GetBreakpointIn{id, ""}, &out)
@ -236,6 +242,11 @@ func (c *RPCClient) CreateBreakpoint(breakPoint *api.Breakpoint) (*api.Breakpoin
return &out.Breakpoint, err
}
func (c *RPCClient) CreateEBPFTracepoint(fnName string) error {
var out CreateEBPFTracepointOut
return c.call("CreateEBPFTracepoint", CreateEBPFTracepointIn{FunctionName: fnName}, &out)
}
func (c *RPCClient) CreateWatchpoint(scope api.EvalScope, expr string, wtype api.WatchType) (*api.Breakpoint, error) {
var out CreateWatchpointOut
err := c.call("CreateWatchpoint", CreateWatchpointIn{scope, expr, wtype}, &out)

@ -136,6 +136,18 @@ func (s *RPCServer) Command(command api.DebuggerCommand, cb service.RPCCallback)
cb.Return(out, nil)
}
type GetBufferedTracepointsIn struct {
}
type GetBufferedTracepointsOut struct {
TracepointResults []api.TracepointResult
}
func (s *RPCServer) GetBufferedTracepoints(arg GetBufferedTracepointsIn, out *GetBufferedTracepointsOut) error {
out.TracepointResults = s.debugger.GetBufferedTracepoints()
return nil
}
type GetBreakpointIn struct {
Id int
Name string
@ -251,6 +263,18 @@ func (s *RPCServer) CreateBreakpoint(arg CreateBreakpointIn, out *CreateBreakpoi
return nil
}
type CreateEBPFTracepointIn struct {
FunctionName string
}
type CreateEBPFTracepointOut struct {
Breakpoint api.Breakpoint
}
func (s *RPCServer) CreateEBPFTracepoint(arg CreateEBPFTracepointIn, out *CreateEBPFTracepointOut) error {
return s.debugger.CreateEBPFTracepoint(arg.FunctionName)
}
type ClearBreakpointIn struct {
Id int
Name string

1
vendor/github.com/aquasecurity/libbpfgo/.gitignore generated vendored Normal file

@ -0,0 +1 @@
selftest/dist

4
vendor/github.com/aquasecurity/libbpfgo/.gitmodules generated vendored Normal file

@ -0,0 +1,4 @@
[submodule "selftest/libbpf-module"]
path = selftest/libbpf-module
url = https://github.com/libbpf/libbpf

202
vendor/github.com/aquasecurity/libbpfgo/LICENSE generated vendored Normal file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

29
vendor/github.com/aquasecurity/libbpfgo/Makefile generated vendored Normal file

@ -0,0 +1,29 @@
TARGET_BPF := test/test.bpf.o
VMLINUX_H = test/vmlinux.h
GO_SRC := $(shell find . -type f -name '*.go')
BPF_SRC := $(shell find . -type f -name '*.bpf.c')
PWD := $(shell pwd)
LIBBPF_HEADERS := /usr/include/bpf
LIBBPF := "-lbpf"
.PHONY: all
all: test
$(VMLINUX_H):
bpftool btf dump file /sys/kernel/btf/vmlinux format c > test/vmlinux.h
go_env := CC=gcc CGO_CFLAGS="-I $(LIBBPF_HEADERS)" CGO_LDFLAGS="$(LIBBPF)"
.PHONY: test
test: $(TARGET_BPF) $(GO_SRC)
$(go_env) go test -ldflags '-extldflags "-static"' .
$(TARGET_BPF): $(BPF_SRC) $(VMLINUX_H)
clang \
-g -O2 -c -target bpf \
-o $@ $<
.PHONY: clean
clean:
rm $(TARGET_BPF) $(VMLINUX_H)

61
vendor/github.com/aquasecurity/libbpfgo/Readme.md generated vendored Normal file

@ -0,0 +1,61 @@
# libbpfgo
<img src="docs/images/aqua-tux.png" width="150" height="auto">
___
libbpfgo is a Go library for working with Linux's [eBPF](https://ebpf.io/). It was created for [Tracee](https://github.com/aquasecurity/tracee), our open source Runtime Security and eBPF tracing tools written in Go. If you are interested in eBPF and it's applications, check out Tracee on Github: [https://github.com/aquasecurity/tracee](https://github.com/aquasecurity/tracee).
libbpfgo is built around libbpf - the standard library for interacting with eBPF from userspace, which is a C library maintained in Linux upstream. We have created libbpfgo as a thin Go wrapper around libbpf.
## Installing
libbpfgo is using CGO to interop with libbpf and will expect to be linked with libbpf at run or link time. Simply importing libbpfgo is not enough to get started, and you will need to fulfill the required dependency in one of the following ways:
1. Install the libbpf as a shared object in the system. Libbpf may already be packaged for you distribution, if not, you can build and install from source. More info [here](https://github.com/libbpf/libbpf).
1. Embed libbpf into your Go project as a vendored dependency. This means that the libbpf code is statically linked into the resulting binary, and there are no runtime dependencies. [Tracee](https://github.com/aquasecurity/tracee) takes this approach and you can take example from it's [Makefile](https://github.com/aquasecurity/tracee/blob/f8df7da6a27f729610992b6bd52e89d510fcf384/tracee-ebpf/Makefile#L62).
## Concepts
libbpfgo tries to make it natural for Go developers to use, by abstracting away C technicalities. For example, it will translate low level return codes into Go `error`, it will organize functionality around Go `struct`, and it will use `channel` as to let you consume events.
In a high level, this is a typical workflow for working with the library:
1. Compile your bpf program into an object file.
1. Initialize a `Module` struct - that is a unit of BPF functionality around your compiled object file.
1. Load bpf programs from the object file using the `BPFProg` struct.
1. Attach `BPFProg` to system facilities, for example to "raw tracepoints" or "kprobes" using the `BPFProg`'s associated functions.
1. Instantiate and manipulate BPF Maps via the `BPFMap` struct and it's associated methods.
1. Instantiate and manipulate Perf Buffer for communicating events from your BPF program to the driving userspace program, using the `RingBuffer` struct and it's associated objects.
## Example
```go
// initializing
import bpf "github.com/aquasecurity/libbpfgo"
...
bpfModule := bpf.NewModuleFromFile(bpfObjectPath)
bpfModule.BPFLoadObject()
// maps
mymap, _ := bpfModule.GetMap("mymap")
mymap.Update(key, value)
// ring buffer
rb, _ := bpfModule.InitRingBuffer("events", eventsChannel, buffSize)
rb.Start()
e := <-eventsChannel
```
Please check our github milestones for an idea of the project roadmap. The general goal is to fully implement/expose libbpf's API in Go as seamlessly as possible.
## Learn more
- Blost post on [how to Build eBPF Programs with libbpfgo](https://blog.aquasec.com/libbpf-ebpf-programs)
- The [selftests](./selftest) are small programs that use libbpfgo to verify functionality, they're good examples to look at for usage.
- [tracee-ebpf](https://github.com/aquasecurity/tracee/tree/main/tracee-ebpf) is a robust consumer of this package.
- Feel free to ask questions by creating a new [Discussion](https://github.com/aquasecurity/libbpfgo/discussions) and we'd love to help.

8
vendor/github.com/aquasecurity/libbpfgo/go.mod generated vendored Normal file

@ -0,0 +1,8 @@
module github.com/aquasecurity/libbpfgo
go 1.16
require (
github.com/stretchr/testify v1.7.0
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015
)

13
vendor/github.com/aquasecurity/libbpfgo/go.sum generated vendored Normal file

@ -0,0 +1,13 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

@ -0,0 +1,603 @@
package helpers
import (
"encoding/binary"
"net"
"strconv"
"strings"
)
// ParseInodeMode parses the `mode` bitmask argument of the `mknod` syscall
// http://man7.org/linux/man-pages/man7/inode.7.html
func ParseInodeMode(mode uint32) string {
var f []string
// File Type
switch {
case mode&0140000 == 0140000:
f = append(f, "S_IFSOCK")
case mode&0120000 == 0120000:
f = append(f, "S_IFLNK")
case mode&0100000 == 0100000:
f = append(f, "S_IFREG")
case mode&060000 == 060000:
f = append(f, "S_IFBLK")
case mode&040000 == 040000:
f = append(f, "S_IFDIR")
case mode&020000 == 020000:
f = append(f, "S_IFCHR")
case mode&010000 == 010000:
f = append(f, "S_IFIFO")
}
// File Mode
// Owner
if mode&00700 == 00700 {
f = append(f, "S_IRWXU")
} else {
if mode&00400 == 00400 {
f = append(f, "S_IRUSR")
}
if mode&00200 == 00200 {
f = append(f, "S_IWUSR")
}
if mode&00100 == 00100 {
f = append(f, "S_IXUSR")
}
}
// Group
if mode&00070 == 00070 {
f = append(f, "S_IRWXG")
} else {
if mode&00040 == 00040 {
f = append(f, "S_IRGRP")
}
if mode&00020 == 00020 {
f = append(f, "S_IWGRP")
}
if mode&00010 == 00010 {
f = append(f, "S_IXGRP")
}
}
// Others
if mode&00007 == 00007 {
f = append(f, "S_IRWXO")
} else {
if mode&00004 == 00004 {
f = append(f, "S_IROTH")
}
if mode&00002 == 00002 {
f = append(f, "S_IWOTH")
}
if mode&00001 == 00001 {
f = append(f, "S_IXOTH")
}
}
return strings.Join(f, "|")
}
// ParseMemProt parses the `prot` bitmask argument of the `mmap` syscall
// http://man7.org/linux/man-pages/man2/mmap.2.html
// https://elixir.bootlin.com/linux/v5.5.3/source/include/uapi/asm-generic/mman-common.h#L10
func ParseMemProt(prot uint32) string {
var f []string
if prot == 0x0 {
f = append(f, "PROT_NONE")
} else {
if prot&0x01 == 0x01 {
f = append(f, "PROT_READ")
}
if prot&0x02 == 0x02 {
f = append(f, "PROT_WRITE")
}
if prot&0x04 == 0x04 {
f = append(f, "PROT_EXEC")
}
}
return strings.Join(f, "|")
}
// ParseOpenFlags parses the `flags` bitmask argument of the `open` syscall
// http://man7.org/linux/man-pages/man2/open.2.html
// https://elixir.bootlin.com/linux/v5.5.3/source/include/uapi/asm-generic/fcntl.h
func ParseOpenFlags(flags uint32) string {
var f []string
//access mode
switch {
case flags&01 == 01:
f = append(f, "O_WRONLY")
case flags&02 == 02:
f = append(f, "O_RDWR")
default:
f = append(f, "O_RDONLY")
}
// file creation and status flags
if flags&0100 == 0100 {
f = append(f, "O_CREAT")
}
if flags&0200 == 0200 {
f = append(f, "O_EXCL")
}
if flags&0400 == 0400 {
f = append(f, "O_NOCTTY")
}
if flags&01000 == 01000 {
f = append(f, "O_TRUNC")
}
if flags&02000 == 02000 {
f = append(f, "O_APPEND")
}
if flags&04000 == 04000 {
f = append(f, "O_NONBLOCK")
}
if flags&04010000 == 04010000 {
f = append(f, "O_SYNC")
}
if flags&020000 == 020000 {
f = append(f, "O_ASYNC")
}
if flags&0100000 == 0100000 {
f = append(f, "O_LARGEFILE")
}
if flags&0200000 == 0200000 {
f = append(f, "O_DIRECTORY")
}
if flags&0400000 == 0400000 {
f = append(f, "O_NOFOLLOW")
}
if flags&02000000 == 02000000 {
f = append(f, "O_CLOEXEC")
}
if flags&040000 == 040000 {
f = append(f, "O_DIRECT")
}
if flags&01000000 == 01000000 {
f = append(f, "O_NOATIME")
}
if flags&010000000 == 010000000 {
f = append(f, "O_PATH")
}
if flags&020000000 == 020000000 {
f = append(f, "O_TMPFILE")
}
return strings.Join(f, "|")
}
// ParseAccessMode parses the mode from the `access` system call
// http://man7.org/linux/man-pages/man2/access.2.html
func ParseAccessMode(mode uint32) string {
var f []string
if mode == 0x0 {
f = append(f, "F_OK")
} else {
if mode&0x04 == 0x04 {
f = append(f, "R_OK")
}
if mode&0x02 == 0x02 {
f = append(f, "W_OK")
}
if mode&0x01 == 0x01 {
f = append(f, "X_OK")
}
}
return strings.Join(f, "|")
}
// ParseExecFlags parses the `flags` bitmask argument of the `execve` syscall
// http://man7.org/linux/man-pages/man2/axecveat.2.html
func ParseExecFlags(flags uint32) string {
var f []string
if flags&0x100 == 0x100 {
f = append(f, "AT_EMPTY_PATH")
}
if flags&0x1000 == 0x1000 {
f = append(f, "AT_SYMLINK_NOFOLLOW")
}
if len(f) == 0 {
f = append(f, "0")
}
return strings.Join(f, "|")
}
// ParseCloneFlags parses the `flags` bitmask argument of the `clone` syscall
// https://man7.org/linux/man-pages/man2/clone.2.html
func ParseCloneFlags(flags uint64) string {
var f []string
if flags&0x00000100 == 0x00000100 {
f = append(f, "CLONE_VM")
}
if flags&0x00000200 == 0x00000200 {
f = append(f, "CLONE_FS")
}
if flags&0x00000400 == 0x00000400 {
f = append(f, "CLONE_FILES")
}
if flags&0x00000800 == 0x00000800 {
f = append(f, "CLONE_SIGHAND")
}
if flags&0x00001000 == 0x00001000 {
f = append(f, "CLONE_PIDFD")
}
if flags&0x00002000 == 0x00002000 {
f = append(f, "CLONE_PTRACE")
}
if flags&0x00004000 == 0x00004000 {
f = append(f, "CLONE_VFORK")
}
if flags&0x00008000 == 0x00008000 {
f = append(f, "CLONE_PARENT")
}
if flags&0x00010000 == 0x00010000 {
f = append(f, "CLONE_THREAD")
}
if flags&0x00020000 == 0x00020000 {
f = append(f, "CLONE_NEWNS")
}
if flags&0x00040000 == 0x00040000 {
f = append(f, "CLONE_SYSVSEM")
}
if flags&0x00080000 == 0x00080000 {
f = append(f, "CLONE_SETTLS")
}
if flags&0x00100000 == 0x00100000 {
f = append(f, "CLONE_PARENT_SETTID")
}
if flags&0x00200000 == 0x00200000 {
f = append(f, "CLONE_CHILD_CLEARTID")
}
if flags&0x00400000 == 0x00400000 {
f = append(f, "CLONE_DETACHED")
}
if flags&0x00800000 == 0x00800000 {
f = append(f, "CLONE_UNTRACED")
}
if flags&0x01000000 == 0x01000000 {
f = append(f, "CLONE_CHILD_SETTID")
}
if flags&0x02000000 == 0x02000000 {
f = append(f, "CLONE_NEWCGROUP")
}
if flags&0x04000000 == 0x04000000 {
f = append(f, "CLONE_NEWUTS")
}
if flags&0x08000000 == 0x08000000 {
f = append(f, "CLONE_NEWIPC")
}
if flags&0x10000000 == 0x10000000 {
f = append(f, "CLONE_NEWUSER")
}
if flags&0x20000000 == 0x20000000 {
f = append(f, "CLONE_NEWPID")
}
if flags&0x40000000 == 0x40000000 {
f = append(f, "CLONE_NEWNET")
}
if flags&0x80000000 == 0x80000000 {
f = append(f, "CLONE_IO")
}
if len(f) == 0 {
f = append(f, "0")
}
return strings.Join(f, "|")
}
// ParseSocketType parses the `type` bitmask argument of the `socket` syscall
// http://man7.org/linux/man-pages/man2/socket.2.html
func ParseSocketType(st uint32) string {
var socketTypes = map[uint32]string{
1: "SOCK_STREAM",
2: "SOCK_DGRAM",
3: "SOCK_RAW",
4: "SOCK_RDM",
5: "SOCK_SEQPACKET",
6: "SOCK_DCCP",
10: "SOCK_PACKET",
}
var f []string
if stName, ok := socketTypes[st&0xf]; ok {
f = append(f, stName)
} else {
f = append(f, strconv.Itoa(int(st)))
}
if st&000004000 == 000004000 {
f = append(f, "SOCK_NONBLOCK")
}
if st&002000000 == 002000000 {
f = append(f, "SOCK_CLOEXEC")
}
return strings.Join(f, "|")
}
// ParseSocketDomain parses the `domain` bitmask argument of the `socket` syscall
// http://man7.org/linux/man-pages/man2/socket.2.html
func ParseSocketDomain(sd uint32) string {
var socketDomains = map[uint32]string{
0: "AF_UNSPEC",
1: "AF_UNIX",
2: "AF_INET",
3: "AF_AX25",
4: "AF_IPX",
5: "AF_APPLETALK",
6: "AF_NETROM",
7: "AF_BRIDGE",
8: "AF_ATMPVC",
9: "AF_X25",
10: "AF_INET6",
11: "AF_ROSE",
12: "AF_DECnet",
13: "AF_NETBEUI",
14: "AF_SECURITY",
15: "AF_KEY",
16: "AF_NETLINK",
17: "AF_PACKET",
18: "AF_ASH",
19: "AF_ECONET",
20: "AF_ATMSVC",
21: "AF_RDS",
22: "AF_SNA",
23: "AF_IRDA",
24: "AF_PPPOX",
25: "AF_WANPIPE",
26: "AF_LLC",
27: "AF_IB",
28: "AF_MPLS",
29: "AF_CAN",
30: "AF_TIPC",
31: "AF_BLUETOOTH",
32: "AF_IUCV",
33: "AF_RXRPC",
34: "AF_ISDN",
35: "AF_PHONET",
36: "AF_IEEE802154",
37: "AF_CAIF",
38: "AF_ALG",
39: "AF_NFC",
40: "AF_VSOCK",
41: "AF_KCM",
42: "AF_QIPCRTR",
43: "AF_SMC",
44: "AF_XDP",
}
var res string
if sdName, ok := socketDomains[sd]; ok {
res = sdName
} else {
res = strconv.Itoa(int(sd))
}
return res
}
// ParseUint32IP parses the IP address encoded as a uint32
func ParseUint32IP(in uint32) string {
ip := make(net.IP, net.IPv4len)
binary.BigEndian.PutUint32(ip, in)
return ip.String()
}
// Parse16BytesSliceIP parses the IP address encoded as 16 bytes long PrintBytesSliceIP
// It would be more correct to accept a [16]byte instead of variable lenth slice, but that would case unnecessary memory copying and type conversions
func Parse16BytesSliceIP(in []byte) string {
ip := net.IP(in)
return ip.String()
}
// ParseCapability parses the `capability` bitmask argument of the `cap_capable` function
// include/uapi/linux/capability.h
func ParseCapability(cap int32) string {
var capabilities = map[int32]string{
0: "CAP_CHOWN",
1: "CAP_DAC_OVERRIDE",
2: "CAP_DAC_READ_SEARCH",
3: "CAP_FOWNER",
4: "CAP_FSETID",
5: "CAP_KILL",
6: "CAP_SETGID",
7: "CAP_SETUID",
8: "CAP_SETPCAP",
9: "CAP_LINUX_IMMUTABLE",
10: "CAP_NET_BIND_SERVICE",
11: "CAP_NET_BROADCAST",
12: "CAP_NET_ADMIN",
13: "CAP_NET_RAW",
14: "CAP_IPC_LOCK",
15: "CAP_IPC_OWNER",
16: "CAP_SYS_MODULE",
17: "CAP_SYS_RAWIO",
18: "CAP_SYS_CHROOT",
19: "CAP_SYS_PTRACE",
20: "CAP_SYS_PACCT",
21: "CAP_SYS_ADMIN",
22: "CAP_SYS_BOOT",
23: "CAP_SYS_NICE",
24: "CAP_SYS_RESOURCE",
25: "CAP_SYS_TIME",
26: "CAP_SYS_TTY_CONFIG",
27: "CAP_MKNOD",
28: "CAP_LEASE",
29: "CAP_AUDIT_WRITE",
30: "CAP_AUDIT_CONTROL",
31: "CAP_SETFCAP",
32: "CAP_MAC_OVERRIDE",
33: "CAP_MAC_ADMIN",
34: "CAP_SYSLOG",
35: "CAP_WAKE_ALARM",
36: "CAP_BLOCK_SUSPEND",
37: "CAP_AUDIT_READ",
}
var res string
if capName, ok := capabilities[cap]; ok {
res = capName
} else {
res = strconv.Itoa(int(cap))
}
return res
}
// ParsePrctlOption parses the `option` argument of the `prctl` syscall
// http://man7.org/linux/man-pages/man2/prctl.2.html
func ParsePrctlOption(op int32) string {
var prctlOptions = map[int32]string{
1: "PR_SET_PDEATHSIG",
2: "PR_GET_PDEATHSIG",
3: "PR_GET_DUMPABLE",
4: "PR_SET_DUMPABLE",
5: "PR_GET_UNALIGN",
6: "PR_SET_UNALIGN",
7: "PR_GET_KEEPCAPS",
8: "PR_SET_KEEPCAPS",
9: "PR_GET_FPEMU",
10: "PR_SET_FPEMU",
11: "PR_GET_FPEXC",
12: "PR_SET_FPEXC",
13: "PR_GET_TIMING",
14: "PR_SET_TIMING",
15: "PR_SET_NAME",
16: "PR_GET_NAME",
19: "PR_GET_ENDIAN",
20: "PR_SET_ENDIAN",
21: "PR_GET_SECCOMP",
22: "PR_SET_SECCOMP",
23: "PR_CAPBSET_READ",
24: "PR_CAPBSET_DROP",
25: "PR_GET_TSC",
26: "PR_SET_TSC",
27: "PR_GET_SECUREBITS",
28: "PR_SET_SECUREBITS",
29: "PR_SET_TIMERSLACK",
30: "PR_GET_TIMERSLACK",
31: "PR_TASK_PERF_EVENTS_DISABLE",
32: "PR_TASK_PERF_EVENTS_ENABLE",
33: "PR_MCE_KILL",
34: "PR_MCE_KILL_GET",
35: "PR_SET_MM",
36: "PR_SET_CHILD_SUBREAPER",
37: "PR_GET_CHILD_SUBREAPER",
38: "PR_SET_NO_NEW_PRIVS",
39: "PR_GET_NO_NEW_PRIVS",
40: "PR_GET_TID_ADDRESS",
41: "PR_SET_THP_DISABLE",
42: "PR_GET_THP_DISABLE",
43: "PR_MPX_ENABLE_MANAGEMENT",
44: "PR_MPX_DISABLE_MANAGEMENT",
45: "PR_SET_FP_MODE",
46: "PR_GET_FP_MODE",
47: "PR_CAP_AMBIENT",
50: "PR_SVE_SET_VL",
51: "PR_SVE_GET_VL",
52: "PR_GET_SPECULATION_CTRL",
53: "PR_SET_SPECULATION_CTRL",
54: "PR_PAC_RESET_KEYS",
55: "PR_SET_TAGGED_ADDR_CTRL",
56: "PR_GET_TAGGED_ADDR_CTRL",
}
var res string
if opName, ok := prctlOptions[op]; ok {
res = opName
} else {
res = strconv.Itoa(int(op))
}
return res
}
// ParsePtraceRequest parses the `request` argument of the `ptrace` syscall
// http://man7.org/linux/man-pages/man2/ptrace.2.html
func ParsePtraceRequest(req int64) string {
var ptraceRequest = map[int64]string{
0: "PTRACE_TRACEME",
1: "PTRACE_PEEKTEXT",
2: "PTRACE_PEEKDATA",
3: "PTRACE_PEEKUSER",
4: "PTRACE_POKETEXT",
5: "PTRACE_POKEDATA",
6: "PTRACE_POKEUSER",
7: "PTRACE_CONT",
8: "PTRACE_KILL",
9: "PTRACE_SINGLESTEP",
12: "PTRACE_GETREGS",
13: "PTRACE_SETREGS",
14: "PTRACE_GETFPREGS",
15: "PTRACE_SETFPREGS",
16: "PTRACE_ATTACH",
17: "PTRACE_DETACH",
18: "PTRACE_GETFPXREGS",
19: "PTRACE_SETFPXREGS",
24: "PTRACE_SYSCALL",
0x4200: "PTRACE_SETOPTIONS",
0x4201: "PTRACE_GETEVENTMSG",
0x4202: "PTRACE_GETSIGINFO",
0x4203: "PTRACE_SETSIGINFO",
0x4204: "PTRACE_GETREGSET",
0x4205: "PTRACE_SETREGSET",
0x4206: "PTRACE_SEIZE",
0x4207: "PTRACE_INTERRUPT",
0x4208: "PTRACE_LISTEN",
0x4209: "PTRACE_PEEKSIGINFO",
0x420a: "PTRACE_GETSIGMASK",
0x420b: "PTRACE_SETSIGMASK",
0x420c: "PTRACE_SECCOMP_GET_FILTER",
0x420d: "PTRACE_SECCOMP_GET_METADATA",
}
var res string
if reqName, ok := ptraceRequest[req]; ok {
res = reqName
} else {
res = strconv.Itoa(int(req))
}
return res
}
// ParseBPFCmd parses the `cmd` argument of the `bpf` syscall
// https://man7.org/linux/man-pages/man2/bpf.2.html
func ParseBPFCmd(cmd int32) string {
var bpfCmd = map[int32]string{
0: "BPF_MAP_CREATE",
1: "BPF_MAP_LOOKUP_ELEM",
2: "BPF_MAP_UPDATE_ELEM",
3: "BPF_MAP_DELETE_ELEM",
4: "BPF_MAP_GET_NEXT_KEY",
5: "BPF_PROG_LOAD",
6: "BPF_OBJ_PIN",
7: "BPF_OBJ_GET",
8: "BPF_PROG_ATTACH",
9: "BPF_PROG_DETACH",
10: "BPF_PROG_TEST_RUN",
11: "BPF_PROG_GET_NEXT_ID",
12: "BPF_MAP_GET_NEXT_ID",
13: "BPF_PROG_GET_FD_BY_ID",
14: "BPF_MAP_GET_FD_BY_ID",
15: "BPF_OBJ_GET_INFO_BY_FD",
16: "BPF_PROG_QUERY",
17: "BPF_RAW_TRACEPOINT_OPEN",
18: "BPF_BTF_LOAD",
19: "BPF_BTF_GET_FD_BY_ID",
20: "BPF_TASK_FD_QUERY",
21: "BPF_MAP_LOOKUP_AND_DELETE_ELEM",
22: "BPF_MAP_FREEZE",
23: "BPF_BTF_GET_NEXT_ID",
24: "BPF_MAP_LOOKUP_BATCH",
25: "BPF_MAP_LOOKUP_AND_DELETE_BATCH",
26: "BPF_MAP_UPDATE_BATCH",
27: "BPF_MAP_DELETE_BATCH",
28: "BPF_LINK_CREATE",
29: "BPF_LINK_UPDATE",
30: "BPF_LINK_GET_FD_BY_ID",
31: "BPF_LINK_GET_NEXT_ID",
32: "BPF_ENABLE_STATS",
33: "BPF_ITER_CREATE",
34: "BPF_LINK_DETACH",
}
var res string
if cmdName, ok := bpfCmd[cmd]; ok {
res = cmdName
} else {
res = strconv.Itoa(int(cmd))
}
return res
}

52
vendor/github.com/aquasecurity/libbpfgo/helpers/elf.go generated vendored Normal file

@ -0,0 +1,52 @@
package helpers
import (
"debug/elf"
"errors"
"fmt"
)
// SymbolToOffset attempts to resolve a 'symbol' name in the binary found at
// 'path' to an offset. The offset can be used for attaching a u(ret)probe
func SymbolToOffset(path, symbol string) (uint32, error) {
f, err := elf.Open(path)
if err != nil {
return 0, fmt.Errorf("could not open elf file to resolve symbol offset: %v", err)
}
syms, err := f.Symbols()
if err != nil {
return 0, fmt.Errorf("could not open symbol section to resolve symbol offset: %v", err)
}
sectionsToSearchForSymbol := []*elf.Section{}
for i := range f.Sections {
if f.Sections[i].Flags == elf.SHF_ALLOC+elf.SHF_EXECINSTR {
sectionsToSearchForSymbol = append(sectionsToSearchForSymbol, f.Sections[i])
}
}
var executableSection *elf.Section
for i := range syms {
if syms[i].Name == symbol {
// Find what section the symbol is in by checking the executable section's
// addr space.
for m := range sectionsToSearchForSymbol {
if syms[i].Value > sectionsToSearchForSymbol[m].Addr &&
syms[i].Value < sectionsToSearchForSymbol[m].Addr+sectionsToSearchForSymbol[m].Size {
executableSection = sectionsToSearchForSymbol[m]
}
}
if executableSection == nil {
return 0, errors.New("could not find symbol in executable sections of binary")
}
return uint32(syms[i].Value - executableSection.Addr + executableSection.Offset), nil
}
}
return 0, fmt.Errorf("symbol not found")
}

@ -0,0 +1,228 @@
package helpers
import (
"bufio"
"bytes"
"compress/gzip"
"errors"
"fmt"
"io"
"os"
"strings"
"golang.org/x/sys/unix"
)
// These constants are a limited number of the total kernel config options,
// but are provided because they are most relevant for BPF
// development.
const (
CONFIG_BPF uint32 = iota + 1
CONFIG_BPF_SYSCALL
CONFIG_HAVE_EBPF_JIT
CONFIG_BPF_JIT
CONFIG_BPF_JIT_ALWAYS_ON
CONFIG_CGROUPS
CONFIG_CGROUP_BPF
CONFIG_CGROUP_NET_CLASSID
CONFIG_SOCK_CGROUP_DATA
CONFIG_BPF_EVENTS
CONFIG_KPROBE_EVENTS
CONFIG_UPROBE_EVENTS
CONFIG_TRACING
CONFIG_FTRACE_SYSCALLS
CONFIG_FUNCTION_ERROR_INJECTION
CONFIG_BPF_KPROBE_OVERRIDE
CONFIG_NET
CONFIG_XDP_SOCKETS
CONFIG_LWTUNNEL_BPF
CONFIG_NET_ACT_BPF
CONFIG_NET_CLS_BPF
CONFIG_NET_CLS_ACT
CONFIG_NET_SCH_INGRESS
CONFIG_XFRM
CONFIG_IP_ROUTE_CLASSID
CONFIG_IPV6_SEG6_BPF
CONFIG_BPF_LIRC_MODE2
CONFIG_BPF_STREAM_PARSER
CONFIG_NETFILTER_XT_MATCH_BPF
CONFIG_BPFILTER
CONFIG_BPFILTER_UMH
CONFIG_TEST_BPF
CONFIG_HZ
CONFIG_DEBUG_INFO_BTF
CONFIG_DEBUG_INFO_BTF_MODULES
CONFIG_BPF_LSM
CONFIG_BPF_PRELOAD
CONFIG_BPF_PRELOAD_UMD
)
var KernelConfigKeyStringToID map[string]uint32 = map[string]uint32{
"CONFIG_BPF": CONFIG_BPF,
"CONFIG_BPF_SYSCALL": CONFIG_BPF_SYSCALL,
"CONFIG_HAVE_EBPF_JIT": CONFIG_HAVE_EBPF_JIT,
"CONFIG_BPF_JIT": CONFIG_BPF_JIT,
"CONFIG_BPF_JIT_ALWAYS_ON": CONFIG_BPF_JIT_ALWAYS_ON,
"CONFIG_CGROUPS": CONFIG_CGROUPS,
"CONFIG_CGROUP_BPF": CONFIG_CGROUP_BPF,
"CONFIG_CGROUP_NET_CLASSID": CONFIG_CGROUP_NET_CLASSID,
"CONFIG_SOCK_CGROUP_DATA": CONFIG_SOCK_CGROUP_DATA,
"CONFIG_BPF_EVENTS": CONFIG_BPF_EVENTS,
"CONFIG_KPROBE_EVENTS": CONFIG_KPROBE_EVENTS,
"CONFIG_UPROBE_EVENTS": CONFIG_UPROBE_EVENTS,
"CONFIG_TRACING": CONFIG_TRACING,
"CONFIG_FTRACE_SYSCALLS": CONFIG_FTRACE_SYSCALLS,
"CONFIG_FUNCTION_ERROR_INJECTION": CONFIG_FUNCTION_ERROR_INJECTION,
"CONFIG_BPF_KPROBE_OVERRIDE": CONFIG_BPF_KPROBE_OVERRIDE,
"CONFIG_NET": CONFIG_NET,
"CONFIG_XDP_SOCKETS": CONFIG_XDP_SOCKETS,
"CONFIG_LWTUNNEL_BPF": CONFIG_LWTUNNEL_BPF,
"CONFIG_NET_ACT_BPF": CONFIG_NET_ACT_BPF,
"CONFIG_NET_CLS_BPF": CONFIG_NET_CLS_BPF,
"CONFIG_NET_CLS_ACT": CONFIG_NET_CLS_ACT,
"CONFIG_NET_SCH_INGRESS": CONFIG_NET_SCH_INGRESS,
"CONFIG_XFRM": CONFIG_XFRM,
"CONFIG_IP_ROUTE_CLASSID": CONFIG_IP_ROUTE_CLASSID,
"CONFIG_IPV6_SEG6_BPF": CONFIG_IPV6_SEG6_BPF,
"CONFIG_BPF_LIRC_MODE2": CONFIG_BPF_LIRC_MODE2,
"CONFIG_BPF_STREAM_PARSER": CONFIG_BPF_STREAM_PARSER,
"CONFIG_NETFILTER_XT_MATCH_BPF": CONFIG_NETFILTER_XT_MATCH_BPF,
"CONFIG_BPFILTER": CONFIG_BPFILTER,
"CONFIG_BPFILTER_UMH": CONFIG_BPFILTER_UMH,
"CONFIG_TEST_BPF": CONFIG_TEST_BPF,
"CONFIG_HZ": CONFIG_HZ,
"CONFIG_DEBUG_INFO_BTF": CONFIG_DEBUG_INFO_BTF,
"CONFIG_DEBUG_INFO_BTF_MODULES": CONFIG_DEBUG_INFO_BTF_MODULES,
"CONFIG_BPF_LSM": CONFIG_BPF_LSM,
"CONFIG_BPF_PRELOAD": CONFIG_BPF_PRELOAD,
"CONFIG_BPF_PRELOAD_UMD": CONFIG_BPF_PRELOAD_UMD,
}
var KernelConfigKeyIDToString map[uint32]string = map[uint32]string{
CONFIG_BPF: "CONFIG_BPF",
CONFIG_BPF_SYSCALL: "CONFIG_BPF_SYSCALL",
CONFIG_HAVE_EBPF_JIT: "CONFIG_HAVE_EBPF_JIT",
CONFIG_BPF_JIT: "CONFIG_BPF_JIT",
CONFIG_BPF_JIT_ALWAYS_ON: "CONFIG_BPF_JIT_ALWAYS_ON",
CONFIG_CGROUPS: "CONFIG_CGROUPS",
CONFIG_CGROUP_BPF: "CONFIG_CGROUP_BPF",
CONFIG_CGROUP_NET_CLASSID: "CONFIG_CGROUP_NET_CLASSID",
CONFIG_SOCK_CGROUP_DATA: "CONFIG_SOCK_CGROUP_DATA",
CONFIG_BPF_EVENTS: "CONFIG_BPF_EVENTS",
CONFIG_KPROBE_EVENTS: "CONFIG_KPROBE_EVENTS",
CONFIG_UPROBE_EVENTS: "CONFIG_UPROBE_EVENTS",
CONFIG_TRACING: "CONFIG_TRACING",
CONFIG_FTRACE_SYSCALLS: "CONFIG_FTRACE_SYSCALLS",
CONFIG_FUNCTION_ERROR_INJECTION: "CONFIG_FUNCTION_ERROR_INJECTION",
CONFIG_BPF_KPROBE_OVERRIDE: "CONFIG_BPF_KPROBE_OVERRIDE",
CONFIG_NET: "CONFIG_NET",
CONFIG_XDP_SOCKETS: "CONFIG_XDP_SOCKETS",
CONFIG_LWTUNNEL_BPF: "CONFIG_LWTUNNEL_BPF",
CONFIG_NET_ACT_BPF: "CONFIG_NET_ACT_BPF",
CONFIG_NET_CLS_BPF: "CONFIG_NET_CLS_BPF",
CONFIG_NET_CLS_ACT: "CONFIG_NET_CLS_ACT",
CONFIG_NET_SCH_INGRESS: "CONFIG_NET_SCH_INGRESS",
CONFIG_XFRM: "CONFIG_XFRM",
CONFIG_IP_ROUTE_CLASSID: "CONFIG_IP_ROUTE_CLASSID",
CONFIG_IPV6_SEG6_BPF: "CONFIG_IPV6_SEG6_BPF",
CONFIG_BPF_LIRC_MODE2: "CONFIG_BPF_LIRC_MODE2",
CONFIG_BPF_STREAM_PARSER: "CONFIG_BPF_STREAM_PARSER",
CONFIG_NETFILTER_XT_MATCH_BPF: "CONFIG_NETFILTER_XT_MATCH_BPF",
CONFIG_BPFILTER: "CONFIG_BPFILTER",
CONFIG_BPFILTER_UMH: "CONFIG_BPFILTER_UMH",
CONFIG_TEST_BPF: "CONFIG_TEST_BPF",
CONFIG_HZ: "CONFIG_HZ",
CONFIG_DEBUG_INFO_BTF: "CONFIG_DEBUG_INFO_BTF",
CONFIG_DEBUG_INFO_BTF_MODULES: "CONFIG_DEBUG_INFO_BTF_MODULES",
CONFIG_BPF_LSM: "CONFIG_BPF_LSM",
CONFIG_BPF_PRELOAD: "CONFIG_BPF_PRELOAD",
CONFIG_BPF_PRELOAD_UMD: "CONFIG_BPF_PRELOAD_UMD",
}
type KernelConfig map[uint32]string
// InitKernelConfig populates the passed KernelConfig
// by attempting to read the kernel config into it from:
// /proc/config-$(uname -r)
// or
// /boot/config.gz
func (k KernelConfig) InitKernelConfig() error {
x := unix.Utsname{}
err := unix.Uname(&x)
if err != nil {
return fmt.Errorf("could not determine uname release: %v", err)
}
bootConfigPath := fmt.Sprintf("/boot/config-%s", bytes.Trim(x.Release[:], "\x00"))
err = k.getBootConfigByPath(bootConfigPath)
if err == nil {
return nil
}
err2 := k.getProcGZConfigByPath("/proc/config.gz")
if err != nil {
return fmt.Errorf("%v %v", err, err2)
}
return nil
}
// GetKernelConfigValue retrieves a value from the kernel config
// If the config value does not exist an error will be returned
func (k KernelConfig) GetKernelConfigValue(key uint32) (string, error) {
v, exists := k[key]
if !exists {
return "", errors.New("kernel config value does not exist, it's possible this option is not present in your kernel version or the KernelConfig has not been initialized")
}
return v, nil
}
func (k KernelConfig) getBootConfigByPath(bootConfigPath string) error {
configFile, err := os.Open(bootConfigPath)
if err != nil {
return fmt.Errorf("could not open %s: %v", bootConfigPath, err)
}
k.readConfigFromScanner(configFile)
return nil
}
func (k KernelConfig) getProcGZConfigByPath(procConfigPath string) error {
configFile, err := os.Open(procConfigPath)
if err != nil {
return fmt.Errorf("could not open %s: %v", procConfigPath, err)
}
return k.getProcGZConfig(configFile)
}
func (k KernelConfig) getProcGZConfig(reader io.Reader) error {
zreader, err := gzip.NewReader(reader)
if err != nil {
return err
}
k.readConfigFromScanner(zreader)
return nil
}
func (k KernelConfig) readConfigFromScanner(reader io.Reader) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
kv := strings.Split(scanner.Text(), "=")
if len(kv) != 2 {
continue
}
configKeyID := KernelConfigKeyStringToID[kv[0]]
if configKeyID == 0 {
continue
}
k[configKeyID] = kv[1]
}
}

@ -0,0 +1,74 @@
package helpers
import (
"sync"
)
type slot struct {
value interface{}
used bool
}
// RWArray allows for multiple concurrent readers but
// only a single writer. The writers lock a mutex while the readers
// are lock free.
// It is implemented as an array of slots where each slot holds a
// value (of type interface{}) and a boolean marker to indicate if it's
// in use or not. The insertion (Put) performs a linear probe
// looking for an available slot as indicated by the in-use marker.
// While probing, it is not touching the value itself, as it's
// being read without a lock by the readers.
type RWArray struct {
slots []slot
mux sync.Mutex
}
func NewRWArray(capacity uint) RWArray {
return RWArray{
slots: make([]slot, capacity),
}
}
func (a *RWArray) Put(v interface{}) int {
a.mux.Lock()
defer a.mux.Unlock()
limit := len(a.slots)
for i := 0; i < limit; i++ {
if !a.slots[i].used {
a.slots[i].value = v
a.slots[i].used = true
return i
}
}
return -1
}
func (a *RWArray) Remove(index uint) {
a.mux.Lock()
defer a.mux.Unlock()
if int(index) >= len(a.slots) {
return
}
a.slots[index].value = nil
a.slots[index].used = false
}
func (a *RWArray) Get(index uint) interface{} {
if int(index) >= len(a.slots) {
return nil
}
// N.B. If slot[index].used == false, this is technically
// a race since Put() might be putting the value in there
// at the same time.
return a.slots[index].value
}
func (a *RWArray) Capacity() uint {
return uint(len(a.slots))
}

@ -0,0 +1,33 @@
package helpers
import (
"bufio"
"fmt"
"os"
)
// TracePipeListen reads data from the trace pipe that bpf_trace_printk() writes to,
// (/sys/kernel/debug/tracing/trace_pipe).
// It writes the data to stdout. The pipe is global, so this function is not
// associated with any BPF program. It is recommended to use bpf_trace_printk()
// and this function for debug purposes only.
// This is a blocking function intended to be called from a goroutine.
func TracePipeListen() error {
f, err := os.Open("/sys/kernel/debug/tracing/trace_pipe")
if err != nil {
return fmt.Errorf("failed to open trace pipe: %v", err)
}
defer f.Close()
r := bufio.NewReader(f)
b := make([]byte, 1024)
for {
len, err := r.Read(b)
if err != nil {
return fmt.Errorf("failed to read from trace pipe: %v", err)
}
s := string(b[:len])
fmt.Println(s)
}
}

30
vendor/github.com/aquasecurity/libbpfgo/libbpf_cb.go generated vendored Normal file

@ -0,0 +1,30 @@
package libbpfgo
import (
"C"
"unsafe"
)
// This callback definition needs to be in a different file from where it is declared in C
// Otherwise, multiple definition compilation error will occur
//export perfCallback
func perfCallback(ctx unsafe.Pointer, cpu C.int, data unsafe.Pointer, size C.int) {
pb := eventChannels.Get(uint(uintptr(ctx))).(*PerfBuffer)
pb.eventsChan <- C.GoBytes(data, size)
}
//export perfLostCallback
func perfLostCallback(ctx unsafe.Pointer, cpu C.int, cnt C.ulonglong) {
pb := eventChannels.Get(uint(uintptr(ctx))).(*PerfBuffer)
if pb.lostChan != nil {
pb.lostChan <- uint64(cnt)
}
}
//export ringbufferCallback
func ringbufferCallback(ctx unsafe.Pointer, data unsafe.Pointer, size C.int) C.int {
ch := eventChannels.Get(uint(uintptr(ctx))).(chan []byte)
ch <- C.GoBytes(data, size)
return C.int(0)
}

1194
vendor/github.com/aquasecurity/libbpfgo/libbpfgo.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) && go1.9
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
// +build go1.9
package unix

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
//go:build gc
// +build gc
#include "textflag.h"

@ -1,14 +1,14 @@
// Copyright 2009 The Go Authors. All rights reserved.
// 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 !gccgo
//go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h"
//
// System call support for 386, Darwin
//
// System call support for 386 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
@ -22,7 +22,7 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-40
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40

@ -1,14 +1,14 @@
// Copyright 2009 The Go Authors. All rights reserved.
// 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 !gccgo
//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc
// +build darwin dragonfly freebsd netbsd openbsd
// +build gc
#include "textflag.h"
//
// System call support for AMD64, Darwin
//
// System call support for AMD64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.

@ -1,14 +1,14 @@
// Copyright 2013 The Go Authors. All rights reserved.
// 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 !gccgo
//go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h"
//
// System call support for ARM, NetBSD
//
// System call support for ARM BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.

@ -1,14 +1,14 @@
// Copyright 2009 The Go Authors. All rights reserved.
// 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 !gccgo
//go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h"
//
// System call support for AMD64, NetBSD
//
// System call support for ARM64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.

@ -1,30 +0,0 @@
// Copyright 2015 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 !gccgo
// +build arm,darwin
#include "textflag.h"
//
// System call support for ARM, Darwin
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)

@ -1,30 +0,0 @@
// Copyright 2015 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 !gccgo
// +build arm64,darwin
#include "textflag.h"
//
// System call support for AMD64, Darwin
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
B syscall·RawSyscall6(SB)

@ -1,29 +0,0 @@
// Copyright 2009 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 !gccgo
#include "textflag.h"
//
// System call support for AMD64, DragonFly
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

@ -1,29 +0,0 @@
// Copyright 2009 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 !gccgo
#include "textflag.h"
//
// System call support for 386, FreeBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)

@ -1,29 +0,0 @@
// Copyright 2009 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 !gccgo
#include "textflag.h"
//
// System call support for AMD64, FreeBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

@ -1,29 +0,0 @@
// Copyright 2012 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 !gccgo
#include "textflag.h"
//
// System call support for ARM, FreeBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)

@ -1,29 +0,0 @@
// Copyright 2018 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 !gccgo
#include "textflag.h"
//
// System call support for ARM64, FreeBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
//go:build gc
// +build gc
#include "textflag.h"

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
//go:build gc
// +build gc
#include "textflag.h"

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
//go:build gc
// +build gc
#include "textflag.h"

@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && arm64 && gc
// +build linux
// +build arm64
// +build !gccgo
// +build gc
#include "textflag.h"

@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (mips64 || mips64le) && gc
// +build linux
// +build mips64 mips64le
// +build !gccgo
// +build gc
#include "textflag.h"

@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (mips || mipsle) && gc
// +build linux
// +build mips mipsle
// +build !gccgo
// +build gc
#include "textflag.h"

@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (ppc64 || ppc64le) && gc
// +build linux
// +build ppc64 ppc64le
// +build !gccgo
// +build gc
#include "textflag.h"

@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build riscv64,!gccgo
//go:build riscv64 && gc
// +build riscv64
// +build gc
#include "textflag.h"

@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build s390x
//go:build linux && s390x && gc
// +build linux
// +build !gccgo
// +build s390x
// +build gc
#include "textflag.h"

@ -1,29 +0,0 @@
// Copyright 2009 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 !gccgo
#include "textflag.h"
//
// System call support for 386, NetBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)

@ -1,29 +0,0 @@
// Copyright 2019 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 !gccgo
#include "textflag.h"
//
// System call support for ARM64, NetBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
B syscall·RawSyscall6(SB)

@ -1,29 +0,0 @@
// Copyright 2009 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 !gccgo
#include "textflag.h"
//
// System call support for 386, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)

@ -1,29 +0,0 @@
// Copyright 2009 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 !gccgo
#include "textflag.h"
//
// System call support for AMD64, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

@ -1,29 +0,0 @@
// Copyright 2017 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 !gccgo
#include "textflag.h"
//
// System call support for ARM, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)

@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
//go:build gc
// +build gc
#include "textflag.h"
//
// System call support for arm64, OpenBSD
// System call support for mips64, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
//go:build gc
// +build gc
#include "textflag.h"

426
vendor/golang.org/x/sys/unix/asm_zos_s390x.s generated vendored Normal file

@ -0,0 +1,426 @@
// Copyright 2020 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.
//go:build zos && s390x && gc
// +build zos
// +build s390x
// +build gc
#include "textflag.h"
#define PSALAA 1208(R0)
#define GTAB64(x) 80(x)
#define LCA64(x) 88(x)
#define CAA(x) 8(x)
#define EDCHPXV(x) 1016(x) // in the CAA
#define SAVSTACK_ASYNC(x) 336(x) // in the LCA
// SS_*, where x=SAVSTACK_ASYNC
#define SS_LE(x) 0(x)
#define SS_GO(x) 8(x)
#define SS_ERRNO(x) 16(x)
#define SS_ERRNOJR(x) 20(x)
#define LE_CALL BYTE $0x0D; BYTE $0x76; // BL R7, R6
TEXT ·clearErrno(SB),NOSPLIT,$0-0
BL addrerrno<>(SB)
MOVD $0, 0(R3)
RET
// Returns the address of errno in R3.
TEXT addrerrno<>(SB),NOSPLIT|NOFRAME,$0-0
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get __errno FuncDesc.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
ADD $(0x156*16), R9
LMG 0(R9), R5, R6
// Switch to saved LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Call __errno function.
LE_CALL
NOPH
// Switch back to Go stack.
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
RET
TEXT ·syscall_syscall(SB),NOSPLIT,$0-56
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+32(FP)
MOVD R0, r2+40(FP)
MOVD R0, err+48(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
done:
BL runtime·exitsyscall(SB)
RET
TEXT ·syscall_rawsyscall(SB),NOSPLIT,$0-56
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+32(FP)
MOVD R0, r2+40(FP)
MOVD R0, err+48(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
done:
RET
TEXT ·syscall_syscall6(SB),NOSPLIT,$0-80
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Fill in parameter list.
MOVD a4+32(FP), R12
MOVD R12, (2176+24)(R4)
MOVD a5+40(FP), R12
MOVD R12, (2176+32)(R4)
MOVD a6+48(FP), R12
MOVD R12, (2176+40)(R4)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+56(FP)
MOVD R0, r2+64(FP)
MOVD R0, err+72(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+72(FP)
done:
BL runtime·exitsyscall(SB)
RET
TEXT ·syscall_rawsyscall6(SB),NOSPLIT,$0-80
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Fill in parameter list.
MOVD a4+32(FP), R12
MOVD R12, (2176+24)(R4)
MOVD a5+40(FP), R12
MOVD R12, (2176+32)(R4)
MOVD a6+48(FP), R12
MOVD R12, (2176+40)(R4)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+56(FP)
MOVD R0, r2+64(FP)
MOVD R0, err+72(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL ·rrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+72(FP)
done:
RET
TEXT ·syscall_syscall9(SB),NOSPLIT,$0
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Fill in parameter list.
MOVD a4+32(FP), R12
MOVD R12, (2176+24)(R4)
MOVD a5+40(FP), R12
MOVD R12, (2176+32)(R4)
MOVD a6+48(FP), R12
MOVD R12, (2176+40)(R4)
MOVD a7+56(FP), R12
MOVD R12, (2176+48)(R4)
MOVD a8+64(FP), R12
MOVD R12, (2176+56)(R4)
MOVD a9+72(FP), R12
MOVD R12, (2176+64)(R4)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+80(FP)
MOVD R0, r2+88(FP)
MOVD R0, err+96(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+96(FP)
done:
BL runtime·exitsyscall(SB)
RET
TEXT ·syscall_rawsyscall9(SB),NOSPLIT,$0
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Fill in parameter list.
MOVD a4+32(FP), R12
MOVD R12, (2176+24)(R4)
MOVD a5+40(FP), R12
MOVD R12, (2176+32)(R4)
MOVD a6+48(FP), R12
MOVD R12, (2176+40)(R4)
MOVD a7+56(FP), R12
MOVD R12, (2176+48)(R4)
MOVD a8+64(FP), R12
MOVD R12, (2176+56)(R4)
MOVD a9+72(FP), R12
MOVD R12, (2176+64)(R4)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+80(FP)
MOVD R0, r2+88(FP)
MOVD R0, err+96(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+96(FP)
done:
RET
// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64)
TEXT ·svcCall(SB),NOSPLIT,$0
BL runtime·save_g(SB) // Save g and stack pointer
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD SAVSTACK_ASYNC(R8), R9
MOVD R15, 0(R9)
MOVD argv+8(FP), R1 // Move function arguments into registers
MOVD dsa+16(FP), g
MOVD fnptr+0(FP), R15
BYTE $0x0D // Branch to function
BYTE $0xEF
BL runtime·load_g(SB) // Restore g and stack pointer
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R15
RET
// func svcLoad(name *byte) unsafe.Pointer
TEXT ·svcLoad(SB),NOSPLIT,$0
MOVD R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers
MOVD $0x80000000, R1
MOVD $0, R15
BYTE $0x0A // SVC 08 LOAD
BYTE $0x08
MOVW R15, R3 // Save return code from SVC
MOVD R2, R15 // Restore go stack pointer
CMP R3, $0 // Check SVC return code
BNE error
MOVD $-2, R3 // Reset last bit of entry point to zero
AND R0, R3
MOVD R3, addr+8(FP) // Return entry point returned by SVC
CMP R0, R3 // Check if last bit of entry point was set
BNE done
MOVD R15, R2 // Save go stack pointer
MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08)
BYTE $0x0A // SVC 09 DELETE
BYTE $0x09
MOVD R2, R15 // Restore go stack pointer
error:
MOVD $0, addr+8(FP) // Return 0 on failure
done:
XOR R0, R0 // Reset r0 to 0
RET
// func svcUnload(name *byte, fnptr unsafe.Pointer) int64
TEXT ·svcUnload(SB),NOSPLIT,$0
MOVD R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers
MOVD addr+8(FP), R15
BYTE $0x0A // SVC 09
BYTE $0x09
XOR R0, R0 // Reset r0 to 0
MOVD R15, R1 // Save SVC return code
MOVD R2, R15 // Restore go stack pointer
MOVD R1, rc+0(FP) // Return SVC return code
RET
// func gettid() uint64
TEXT ·gettid(SB), NOSPLIT, $0
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get CEECAATHDID
MOVD CAA(R8), R9
MOVD 0x3D0(R9), R9
MOVD R9, ret+0(FP)
RET

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build freebsd
// +build freebsd
package unix

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
package unix

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build aix
// +build ppc
//go:build aix && ppc
// +build aix,ppc
// Functions to access/create device major and minor numbers matching the
// encoding used by AIX.

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build aix
// +build ppc64
//go:build aix && ppc64
// +build aix,ppc64
// Functions to access/create device major and minor numbers matching the
// encoding used AIX.

29
vendor/golang.org/x/sys/unix/dev_zos.go generated vendored Normal file

@ -0,0 +1,29 @@
// Copyright 2020 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.
//go:build zos && s390x
// +build zos,s390x
// Functions to access/create device major and minor numbers matching the
// encoding used by z/OS.
//
// The information below is extracted and adapted from <sys/stat.h> macros.
package unix
// Major returns the major component of a z/OS device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 16) & 0x0000FFFF)
}
// Minor returns the minor component of a z/OS device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0x0000FFFF)
}
// Mkdev returns a z/OS device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 16) | uint64(minor)
}

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package unix

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// +build ppc64 s390x mips mips64
//go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64
// +build armbe arm64be m68k mips mips64 mips64p32 ppc ppc64 s390 s390x shbe sparc sparc64
package unix

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le riscv64
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh
// +build 386 amd64 amd64p32 alpha arm arm64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh
package unix

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
// Unix environment variables.

221
vendor/golang.org/x/sys/unix/epoll_zos.go generated vendored Normal file

@ -0,0 +1,221 @@
// Copyright 2020 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.
//go:build zos && s390x
// +build zos,s390x
package unix
import (
"sync"
)
// This file simulates epoll on z/OS using poll.
// Analogous to epoll_event on Linux.
// TODO(neeilan): Pad is because the Linux kernel expects a 96-bit struct. We never pass this to the kernel; remove?
type EpollEvent struct {
Events uint32
Fd int32
Pad int32
}
const (
EPOLLERR = 0x8
EPOLLHUP = 0x10
EPOLLIN = 0x1
EPOLLMSG = 0x400
EPOLLOUT = 0x4
EPOLLPRI = 0x2
EPOLLRDBAND = 0x80
EPOLLRDNORM = 0x40
EPOLLWRBAND = 0x200
EPOLLWRNORM = 0x100
EPOLL_CTL_ADD = 0x1
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
// The following constants are part of the epoll API, but represent
// currently unsupported functionality on z/OS.
// EPOLL_CLOEXEC = 0x80000
// EPOLLET = 0x80000000
// EPOLLONESHOT = 0x40000000
// EPOLLRDHUP = 0x2000 // Typically used with edge-triggered notis
// EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode
// EPOLLWAKEUP = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability
)
// TODO(neeilan): We can eliminate these epToPoll / pToEpoll calls by using identical mask values for POLL/EPOLL
// constants where possible The lower 16 bits of epoll events (uint32) can fit any system poll event (int16).
// epToPollEvt converts epoll event field to poll equivalent.
// In epoll, Events is a 32-bit field, while poll uses 16 bits.
func epToPollEvt(events uint32) int16 {
var ep2p = map[uint32]int16{
EPOLLIN: POLLIN,
EPOLLOUT: POLLOUT,
EPOLLHUP: POLLHUP,
EPOLLPRI: POLLPRI,
EPOLLERR: POLLERR,
}
var pollEvts int16 = 0
for epEvt, pEvt := range ep2p {
if (events & epEvt) != 0 {
pollEvts |= pEvt
}
}
return pollEvts
}
// pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields.
func pToEpollEvt(revents int16) uint32 {
var p2ep = map[int16]uint32{
POLLIN: EPOLLIN,
POLLOUT: EPOLLOUT,
POLLHUP: EPOLLHUP,
POLLPRI: EPOLLPRI,
POLLERR: EPOLLERR,
}
var epollEvts uint32 = 0
for pEvt, epEvt := range p2ep {
if (revents & pEvt) != 0 {
epollEvts |= epEvt
}
}
return epollEvts
}
// Per-process epoll implementation.
type epollImpl struct {
mu sync.Mutex
epfd2ep map[int]*eventPoll
nextEpfd int
}
// eventPoll holds a set of file descriptors being watched by the process. A process can have multiple epoll instances.
// On Linux, this is an in-kernel data structure accessed through a fd.
type eventPoll struct {
mu sync.Mutex
fds map[int]*EpollEvent
}
// epoll impl for this process.
var impl epollImpl = epollImpl{
epfd2ep: make(map[int]*eventPoll),
nextEpfd: 0,
}
func (e *epollImpl) epollcreate(size int) (epfd int, err error) {
e.mu.Lock()
defer e.mu.Unlock()
epfd = e.nextEpfd
e.nextEpfd++
e.epfd2ep[epfd] = &eventPoll{
fds: make(map[int]*EpollEvent),
}
return epfd, nil
}
func (e *epollImpl) epollcreate1(flag int) (fd int, err error) {
return e.epollcreate(4)
}
func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) {
e.mu.Lock()
defer e.mu.Unlock()
ep, ok := e.epfd2ep[epfd]
if !ok {
return EBADF
}
switch op {
case EPOLL_CTL_ADD:
// TODO(neeilan): When we make epfds and fds disjoint, detect epoll
// loops here (instances watching each other) and return ELOOP.
if _, ok := ep.fds[fd]; ok {
return EEXIST
}
ep.fds[fd] = event
case EPOLL_CTL_MOD:
if _, ok := ep.fds[fd]; !ok {
return ENOENT
}
ep.fds[fd] = event
case EPOLL_CTL_DEL:
if _, ok := ep.fds[fd]; !ok {
return ENOENT
}
delete(ep.fds, fd)
}
return nil
}
// Must be called while holding ep.mu
func (ep *eventPoll) getFds() []int {
fds := make([]int, len(ep.fds))
for fd := range ep.fds {
fds = append(fds, fd)
}
return fds
}
func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) {
e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait
ep, ok := e.epfd2ep[epfd]
if !ok {
e.mu.Unlock()
return 0, EBADF
}
pollfds := make([]PollFd, 4)
for fd, epollevt := range ep.fds {
pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)})
}
e.mu.Unlock()
n, err = Poll(pollfds, msec)
if err != nil {
return n, err
}
i := 0
for _, pFd := range pollfds {
if pFd.Revents != 0 {
events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)}
i++
}
if i == n {
break
}
}
return n, nil
}
func EpollCreate(size int) (fd int, err error) {
return impl.epollcreate(size)
}
func EpollCreate1(flag int) (fd int, err error) {
return impl.epollcreate1(flag)
}
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
return impl.epollctl(epfd, op, fd, event)
}
// Because EpollWait mutates events, the caller is expected to coordinate
// concurrent access if calling with the same epfd from multiple goroutines.
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
return impl.epollwait(epfd, events, msec)
}

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build dragonfly || freebsd || linux || netbsd || openbsd
// +build dragonfly freebsd linux netbsd openbsd
package unix

@ -16,3 +16,9 @@ func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk))))
return err
}
// FcntlFstore performs a fcntl syscall for the F_PREALLOCATE command.
func FcntlFstore(fd uintptr, cmd int, fstore *Fstore_t) error {
_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(fstore))))
return err
}

@ -1,9 +1,10 @@
// +build linux,386 linux,arm linux,mips linux,mipsle
// Copyright 2014 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.
//go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) || (linux && ppc)
// +build linux,386 linux,arm linux,mips linux,mipsle linux,ppc
package unix
func init() {

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
package unix

164
vendor/golang.org/x/sys/unix/fstatfs_zos.go generated vendored Normal file

@ -0,0 +1,164 @@
// Copyright 2020 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.
//go:build zos && s390x
// +build zos,s390x
package unix
import (
"unsafe"
)
// This file simulates fstatfs on z/OS using fstatvfs and w_getmntent.
func Fstatfs(fd int, stat *Statfs_t) (err error) {
var stat_v Statvfs_t
err = Fstatvfs(fd, &stat_v)
if err == nil {
// populate stat
stat.Type = 0
stat.Bsize = stat_v.Bsize
stat.Blocks = stat_v.Blocks
stat.Bfree = stat_v.Bfree
stat.Bavail = stat_v.Bavail
stat.Files = stat_v.Files
stat.Ffree = stat_v.Ffree
stat.Fsid = stat_v.Fsid
stat.Namelen = stat_v.Namemax
stat.Frsize = stat_v.Frsize
stat.Flags = stat_v.Flag
for passn := 0; passn < 5; passn++ {
switch passn {
case 0:
err = tryGetmntent64(stat)
break
case 1:
err = tryGetmntent128(stat)
break
case 2:
err = tryGetmntent256(stat)
break
case 3:
err = tryGetmntent512(stat)
break
case 4:
err = tryGetmntent1024(stat)
break
default:
break
}
//proceed to return if: err is nil (found), err is nonnil but not ERANGE (another error occurred)
if err == nil || err != nil && err != ERANGE {
break
}
}
}
return err
}
func tryGetmntent64(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [64]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}
func tryGetmntent128(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [128]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}
func tryGetmntent256(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [256]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}
func tryGetmntent512(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [512]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}
func tryGetmntent1024(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [1024]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build gccgo
// +build !aix
//go:build gccgo && !aix
// +build gccgo,!aix
package unix
@ -12,10 +12,8 @@ import "syscall"
// We can't use the gc-syntax .s files for gccgo. On the plus side
// much of the functionality can be written directly in Go.
//extern gccgoRealSyscallNoError
func realSyscallNoError(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r uintptr)
//extern gccgoRealSyscall
func realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r, errno uintptr)
func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {

@ -21,6 +21,9 @@ struct ret {
uintptr_t err;
};
struct ret gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
__asm__(GOSYM_PREFIX GOPKGPATH ".realSyscall");
struct ret
gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
{
@ -32,6 +35,9 @@ gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintp
return r;
}
uintptr_t gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
__asm__(GOSYM_PREFIX GOPKGPATH ".realSyscallNoError");
uintptr_t
gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
{

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gccgo && linux && amd64
// +build gccgo,linux,amd64
package unix

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package unix
@ -20,6 +21,15 @@ func IoctlSetInt(fd int, req uint, value int) error {
return ioctl(fd, req, uintptr(value))
}
// IoctlSetPointerInt performs an ioctl operation which sets an
// integer value on fd, using the specified request number. The ioctl
// argument is called with a pointer to the integer value, rather than
// passing the integer value directly.
func IoctlSetPointerInt(fd int, req uint, value int) error {
v := int32(value)
return ioctl(fd, req, uintptr(unsafe.Pointer(&v)))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
//
// To change fd's window size, the req argument should be TIOCSWINSZ.

Some files were not shown because too many files have changed in this diff Show More