mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
build(deps): bump github.com/cilium/ebpf from 0.9.1 to 0.9.3
Bumps [github.com/cilium/ebpf](https://github.com/cilium/ebpf) from 0.9.1 to 0.9.3. - [Release notes](https://github.com/cilium/ebpf/releases) - [Commits](https://github.com/cilium/ebpf/compare/v0.9.1...v0.9.3) --- updated-dependencies: - dependency-name: github.com/cilium/ebpf dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
@@ -4,7 +4,7 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/checkpoint-restore/go-criu/v6 v6.2.0
|
github.com/checkpoint-restore/go-criu/v6 v6.2.0
|
||||||
github.com/cilium/ebpf v0.9.1
|
github.com/cilium/ebpf v0.9.3
|
||||||
github.com/containerd/console v1.0.3
|
github.com/containerd/console v1.0.3
|
||||||
github.com/coreos/go-systemd/v22 v22.4.0
|
github.com/coreos/go-systemd/v22 v22.4.0
|
||||||
github.com/cyphar/filepath-securejoin v0.2.3
|
github.com/cyphar/filepath-securejoin v0.2.3
|
||||||
@@ -20,7 +20,7 @@ require (
|
|||||||
github.com/urfave/cli v1.22.9
|
github.com/urfave/cli v1.22.9
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/checkpoint-restore/go-criu/v6 v6.2.0 h1:3hXH7Vbq18m6oGeSj1PZkx9z0b1c2gD/jJxAGnNdLkI=
|
github.com/checkpoint-restore/go-criu/v6 v6.2.0 h1:3hXH7Vbq18m6oGeSj1PZkx9z0b1c2gD/jJxAGnNdLkI=
|
||||||
github.com/checkpoint-restore/go-criu/v6 v6.2.0/go.mod h1:rrRTN/uSwY2X+BPRl/gkulo9gsKOSAeVp9/K2tv7xZI=
|
github.com/checkpoint-restore/go-criu/v6 v6.2.0/go.mod h1:rrRTN/uSwY2X+BPRl/gkulo9gsKOSAeVp9/K2tv7xZI=
|
||||||
github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4=
|
github.com/cilium/ebpf v0.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc=
|
||||||
github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY=
|
github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A=
|
||||||
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||||
github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU=
|
github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU=
|
||||||
@@ -66,8 +66,9 @@ golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||||
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|||||||
+1
-1
@@ -79,7 +79,7 @@ generate: export BPF_CFLAGS := $(CFLAGS)
|
|||||||
generate:
|
generate:
|
||||||
go generate ./cmd/bpf2go/test
|
go generate ./cmd/bpf2go/test
|
||||||
go generate ./internal/sys
|
go generate ./internal/sys
|
||||||
cd examples/ && go generate ./...
|
go generate ./examples/...
|
||||||
|
|
||||||
testdata/loader-%-el.elf: testdata/loader.c
|
testdata/loader-%-el.elf: testdata/loader.c
|
||||||
$* $(CFLAGS) -target bpfel -c $< -o $@
|
$* $(CFLAGS) -target bpfel -c $< -o $@
|
||||||
|
|||||||
+14
-10
@@ -4,14 +4,12 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
eBPF is a pure Go library that provides utilities for loading, compiling, and
|
ebpf-go is a pure Go library that provides utilities for loading, compiling, and
|
||||||
debugging eBPF programs. It has minimal external dependencies and is intended to
|
debugging eBPF programs. It has minimal external dependencies and is intended to
|
||||||
be used in long running processes.
|
be used in long running processes.
|
||||||
|
|
||||||
The library is maintained by [Cloudflare](https://www.cloudflare.com) and
|
See [ebpf.io](https://ebpf.io) for complementary projects from the wider eBPF
|
||||||
[Cilium](https://www.cilium.io).
|
ecosystem.
|
||||||
|
|
||||||
See [ebpf.io](https://ebpf.io) for other projects from the eBPF ecosystem.
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
@@ -23,14 +21,20 @@ eBPF and the library, and help shape the future of the project.
|
|||||||
|
|
||||||
## Getting Help
|
## Getting Help
|
||||||
|
|
||||||
Please
|
The community actively monitors our [GitHub Discussions](discussions/) page.
|
||||||
[join](https://ebpf.io/slack) the
|
Please search for existing threads before starting a new one. Refrain from
|
||||||
|
opening issues on the bug tracker if you're just starting out or if you're not
|
||||||
|
sure if something is a bug in the library code.
|
||||||
|
|
||||||
|
Alternatively, [join](https://ebpf.io/slack) the
|
||||||
[#ebpf-go](https://cilium.slack.com/messages/ebpf-go) channel on Slack if you
|
[#ebpf-go](https://cilium.slack.com/messages/ebpf-go) channel on Slack if you
|
||||||
have questions regarding the library.
|
have other questions regarding the project. Note that this channel is ephemeral
|
||||||
|
and has its history erased past a certain point, which is less helpful for
|
||||||
|
others running into the same problem later.
|
||||||
|
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
This library includes the following packages:
|
This library includes the following packages:
|
||||||
|
|
||||||
* [asm](https://pkg.go.dev/github.com/cilium/ebpf/asm) contains a basic
|
* [asm](https://pkg.go.dev/github.com/cilium/ebpf/asm) contains a basic
|
||||||
assembler, allowing you to write eBPF assembly instructions directly
|
assembler, allowing you to write eBPF assembly instructions directly
|
||||||
@@ -38,7 +42,7 @@ This library includes the following packages:
|
|||||||
* [cmd/bpf2go](https://pkg.go.dev/github.com/cilium/ebpf/cmd/bpf2go) allows
|
* [cmd/bpf2go](https://pkg.go.dev/github.com/cilium/ebpf/cmd/bpf2go) allows
|
||||||
compiling and embedding eBPF programs written in C within Go code. As well as
|
compiling and embedding eBPF programs written in C within Go code. As well as
|
||||||
compiling the C code, it auto-generates Go code for loading and manipulating
|
compiling the C code, it auto-generates Go code for loading and manipulating
|
||||||
the eBPF program and map objects.
|
the eBPF program and map objects.
|
||||||
* [link](https://pkg.go.dev/github.com/cilium/ebpf/link) allows attaching eBPF
|
* [link](https://pkg.go.dev/github.com/cilium/ebpf/link) allows attaching eBPF
|
||||||
to various hooks
|
to various hooks
|
||||||
* [perf](https://pkg.go.dev/github.com/cilium/ebpf/perf) allows reading from a
|
* [perf](https://pkg.go.dev/github.com/cilium/ebpf/perf) allows reading from a
|
||||||
|
|||||||
+8
-8
@@ -4,10 +4,10 @@ package asm
|
|||||||
|
|
||||||
// Source of ALU / ALU64 / Branch operations
|
// Source of ALU / ALU64 / Branch operations
|
||||||
//
|
//
|
||||||
// msb lsb
|
// msb lsb
|
||||||
// +----+-+---+
|
// +----+-+---+
|
||||||
// |op |S|cls|
|
// |op |S|cls|
|
||||||
// +----+-+---+
|
// +----+-+---+
|
||||||
type Source uint8
|
type Source uint8
|
||||||
|
|
||||||
const sourceMask OpCode = 0x08
|
const sourceMask OpCode = 0x08
|
||||||
@@ -39,10 +39,10 @@ const (
|
|||||||
|
|
||||||
// ALUOp are ALU / ALU64 operations
|
// ALUOp are ALU / ALU64 operations
|
||||||
//
|
//
|
||||||
// msb lsb
|
// msb lsb
|
||||||
// +----+-+---+
|
// +----+-+---+
|
||||||
// |OP |s|cls|
|
// |OP |s|cls|
|
||||||
// +----+-+---+
|
// +----+-+---+
|
||||||
type ALUOp uint8
|
type ALUOp uint8
|
||||||
|
|
||||||
const aluMask OpCode = 0xf0
|
const aluMask OpCode = 0xf0
|
||||||
|
|||||||
+9
-9
@@ -13,15 +13,15 @@ func (_ BuiltinFunc) Max() BuiltinFunc {
|
|||||||
//
|
//
|
||||||
// You can regenerate this list using the following gawk script:
|
// You can regenerate this list using the following gawk script:
|
||||||
//
|
//
|
||||||
// /FN\(.+\),/ {
|
// /FN\(.+\),/ {
|
||||||
// match($1, /\((.+)\)/, r)
|
// match($1, /\((.+)\)/, r)
|
||||||
// split(r[1], p, "_")
|
// split(r[1], p, "_")
|
||||||
// printf "Fn"
|
// printf "Fn"
|
||||||
// for (i in p) {
|
// for (i in p) {
|
||||||
// printf "%s%s", toupper(substr(p[i], 1, 1)), substr(p[i], 2)
|
// printf "%s%s", toupper(substr(p[i], 1, 1)), substr(p[i], 2)
|
||||||
// }
|
// }
|
||||||
// print ""
|
// print ""
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The script expects include/uapi/linux/bpf.h as it's input.
|
// The script expects include/uapi/linux/bpf.h as it's input.
|
||||||
const (
|
const (
|
||||||
|
|||||||
+4
-4
@@ -4,10 +4,10 @@ package asm
|
|||||||
|
|
||||||
// JumpOp affect control flow.
|
// JumpOp affect control flow.
|
||||||
//
|
//
|
||||||
// msb lsb
|
// msb lsb
|
||||||
// +----+-+---+
|
// +----+-+---+
|
||||||
// |OP |s|cls|
|
// |OP |s|cls|
|
||||||
// +----+-+---+
|
// +----+-+---+
|
||||||
type JumpOp uint8
|
type JumpOp uint8
|
||||||
|
|
||||||
const jumpMask OpCode = aluMask
|
const jumpMask OpCode = aluMask
|
||||||
|
|||||||
+8
-8
@@ -4,10 +4,10 @@ package asm
|
|||||||
|
|
||||||
// Mode for load and store operations
|
// Mode for load and store operations
|
||||||
//
|
//
|
||||||
// msb lsb
|
// msb lsb
|
||||||
// +---+--+---+
|
// +---+--+---+
|
||||||
// |MDE|sz|cls|
|
// |MDE|sz|cls|
|
||||||
// +---+--+---+
|
// +---+--+---+
|
||||||
type Mode uint8
|
type Mode uint8
|
||||||
|
|
||||||
const modeMask OpCode = 0xe0
|
const modeMask OpCode = 0xe0
|
||||||
@@ -30,10 +30,10 @@ const (
|
|||||||
|
|
||||||
// Size of load and store operations
|
// Size of load and store operations
|
||||||
//
|
//
|
||||||
// msb lsb
|
// msb lsb
|
||||||
// +---+--+---+
|
// +---+--+---+
|
||||||
// |mde|SZ|cls|
|
// |mde|SZ|cls|
|
||||||
// +---+--+---+
|
// +---+--+---+
|
||||||
type Size uint8
|
type Size uint8
|
||||||
|
|
||||||
const sizeMask OpCode = 0x18
|
const sizeMask OpCode = 0x18
|
||||||
|
|||||||
+8
-8
@@ -9,10 +9,10 @@ import (
|
|||||||
|
|
||||||
// Class of operations
|
// Class of operations
|
||||||
//
|
//
|
||||||
// msb lsb
|
// msb lsb
|
||||||
// +---+--+---+
|
// +---+--+---+
|
||||||
// | ?? |CLS|
|
// | ?? |CLS|
|
||||||
// +---+--+---+
|
// +---+--+---+
|
||||||
type Class uint8
|
type Class uint8
|
||||||
|
|
||||||
const classMask OpCode = 0x07
|
const classMask OpCode = 0x07
|
||||||
@@ -70,10 +70,10 @@ func (cls Class) isJumpOrALU() bool {
|
|||||||
//
|
//
|
||||||
// Its encoding is defined by a Class value:
|
// Its encoding is defined by a Class value:
|
||||||
//
|
//
|
||||||
// msb lsb
|
// msb lsb
|
||||||
// +----+-+---+
|
// +----+-+---+
|
||||||
// | ???? |CLS|
|
// | ???? |CLS|
|
||||||
// +----+-+---+
|
// +----+-+---+
|
||||||
type OpCode uint8
|
type OpCode uint8
|
||||||
|
|
||||||
// InvalidOpCode is returned by setters on OpCode
|
// InvalidOpCode is returned by setters on OpCode
|
||||||
|
|||||||
+3
-2
@@ -51,11 +51,12 @@ func _() {
|
|||||||
_ = x[AttachSkReuseportSelect-39]
|
_ = x[AttachSkReuseportSelect-39]
|
||||||
_ = x[AttachSkReuseportSelectOrMigrate-40]
|
_ = x[AttachSkReuseportSelectOrMigrate-40]
|
||||||
_ = x[AttachPerfEvent-41]
|
_ = x[AttachPerfEvent-41]
|
||||||
|
_ = x[AttachTraceKprobeMulti-42]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _AttachType_name = "NoneCGroupInetEgressCGroupInetSockCreateCGroupSockOpsSkSKBStreamParserSkSKBStreamVerdictCGroupDeviceSkMsgVerdictCGroupInet4BindCGroupInet6BindCGroupInet4ConnectCGroupInet6ConnectCGroupInet4PostBindCGroupInet6PostBindCGroupUDP4SendmsgCGroupUDP6SendmsgLircMode2FlowDissectorCGroupSysctlCGroupUDP4RecvmsgCGroupUDP6RecvmsgCGroupGetsockoptCGroupSetsockoptTraceRawTpTraceFEntryTraceFExitModifyReturnLSMMacTraceIterCgroupInet4GetPeernameCgroupInet6GetPeernameCgroupInet4GetSocknameCgroupInet6GetSocknameXDPDevMapCgroupInetSockReleaseXDPCPUMapSkLookupXDPSkSKBVerdictSkReuseportSelectSkReuseportSelectOrMigratePerfEvent"
|
const _AttachType_name = "NoneCGroupInetEgressCGroupInetSockCreateCGroupSockOpsSkSKBStreamParserSkSKBStreamVerdictCGroupDeviceSkMsgVerdictCGroupInet4BindCGroupInet6BindCGroupInet4ConnectCGroupInet6ConnectCGroupInet4PostBindCGroupInet6PostBindCGroupUDP4SendmsgCGroupUDP6SendmsgLircMode2FlowDissectorCGroupSysctlCGroupUDP4RecvmsgCGroupUDP6RecvmsgCGroupGetsockoptCGroupSetsockoptTraceRawTpTraceFEntryTraceFExitModifyReturnLSMMacTraceIterCgroupInet4GetPeernameCgroupInet6GetPeernameCgroupInet4GetSocknameCgroupInet6GetSocknameXDPDevMapCgroupInetSockReleaseXDPCPUMapSkLookupXDPSkSKBVerdictSkReuseportSelectSkReuseportSelectOrMigratePerfEventTraceKprobeMulti"
|
||||||
|
|
||||||
var _AttachType_index = [...]uint16{0, 4, 20, 40, 53, 70, 88, 100, 112, 127, 142, 160, 178, 197, 216, 233, 250, 259, 272, 284, 301, 318, 334, 350, 360, 371, 381, 393, 399, 408, 430, 452, 474, 496, 505, 526, 535, 543, 546, 558, 575, 601, 610}
|
var _AttachType_index = [...]uint16{0, 4, 20, 40, 53, 70, 88, 100, 112, 127, 142, 160, 178, 197, 216, 233, 250, 259, 272, 284, 301, 318, 334, 350, 360, 371, 381, 393, 399, 408, 430, 452, 474, 496, 505, 526, 535, 543, 546, 558, 575, 601, 610, 626}
|
||||||
|
|
||||||
func (i AttachType) String() string {
|
func (i AttachType) String() string {
|
||||||
if i >= AttachType(len(_AttachType_index)-1) {
|
if i >= AttachType(len(_AttachType_index)-1) {
|
||||||
|
|||||||
+28
-13
@@ -471,9 +471,10 @@ type marshalOpts struct {
|
|||||||
|
|
||||||
func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
|
func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
buf bytes.Buffer
|
buf bytes.Buffer
|
||||||
header = new(btfHeader)
|
header = new(btfHeader)
|
||||||
headerLen = binary.Size(header)
|
headerLen = binary.Size(header)
|
||||||
|
stringsLen int
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reserve space for the header. We have to write it last since
|
// Reserve space for the header. We have to write it last since
|
||||||
@@ -495,10 +496,12 @@ func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
|
|||||||
typeLen := uint32(buf.Len() - headerLen)
|
typeLen := uint32(buf.Len() - headerLen)
|
||||||
|
|
||||||
// Write string section after type section.
|
// Write string section after type section.
|
||||||
stringsLen := s.strings.Length()
|
if s.strings != nil {
|
||||||
buf.Grow(stringsLen)
|
stringsLen = s.strings.Length()
|
||||||
if err := s.strings.Marshal(&buf); err != nil {
|
buf.Grow(stringsLen)
|
||||||
return nil, err
|
if err := s.strings.Marshal(&buf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill out the header, and write it out.
|
// Fill out the header, and write it out.
|
||||||
@@ -609,6 +612,9 @@ func (s *Spec) AnyTypeByName(name string) (Type, error) {
|
|||||||
// Type exists in the Spec. If multiple candidates are found,
|
// Type exists in the Spec. If multiple candidates are found,
|
||||||
// an error is returned.
|
// an error is returned.
|
||||||
func (s *Spec) TypeByName(name string, typ interface{}) error {
|
func (s *Spec) TypeByName(name string, typ interface{}) error {
|
||||||
|
typeInterface := reflect.TypeOf((*Type)(nil)).Elem()
|
||||||
|
|
||||||
|
// typ may be **T or *Type
|
||||||
typValue := reflect.ValueOf(typ)
|
typValue := reflect.ValueOf(typ)
|
||||||
if typValue.Kind() != reflect.Ptr {
|
if typValue.Kind() != reflect.Ptr {
|
||||||
return fmt.Errorf("%T is not a pointer", typ)
|
return fmt.Errorf("%T is not a pointer", typ)
|
||||||
@@ -620,7 +626,12 @@ func (s *Spec) TypeByName(name string, typ interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wanted := typPtr.Type()
|
wanted := typPtr.Type()
|
||||||
if !wanted.AssignableTo(reflect.TypeOf((*Type)(nil)).Elem()) {
|
if wanted == typeInterface {
|
||||||
|
// This is *Type. Unwrap the value's type.
|
||||||
|
wanted = typPtr.Elem().Type()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !wanted.AssignableTo(typeInterface) {
|
||||||
return fmt.Errorf("%T does not satisfy Type interface", typ)
|
return fmt.Errorf("%T does not satisfy Type interface", typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,7 +654,7 @@ func (s *Spec) TypeByName(name string, typ interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if candidate == nil {
|
if candidate == nil {
|
||||||
return fmt.Errorf("type %s: %w", name, ErrNotFound)
|
return fmt.Errorf("%s %s: %w", wanted, name, ErrNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
typPtr.Set(reflect.ValueOf(candidate))
|
typPtr.Set(reflect.ValueOf(candidate))
|
||||||
@@ -699,7 +710,7 @@ func NewHandle(spec *Spec) (*Handle, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.byteOrder != internal.NativeEndian {
|
if spec.byteOrder != nil && spec.byteOrder != internal.NativeEndian {
|
||||||
return nil, fmt.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian)
|
return nil, fmt.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -726,9 +737,13 @@ func NewHandle(spec *Spec) (*Handle, error) {
|
|||||||
attr.BtfLogBuf = sys.NewSlicePointer(logBuf)
|
attr.BtfLogBuf = sys.NewSlicePointer(logBuf)
|
||||||
attr.BtfLogSize = uint32(len(logBuf))
|
attr.BtfLogSize = uint32(len(logBuf))
|
||||||
attr.BtfLogLevel = 1
|
attr.BtfLogLevel = 1
|
||||||
// NB: The syscall will never return ENOSPC as of 5.18-rc4.
|
|
||||||
_, _ = sys.BtfLoad(attr)
|
// Up until at least kernel 6.0, the BTF verifier does not return ENOSPC
|
||||||
return nil, internal.ErrorWithLog(err, logBuf)
|
// if there are other verification errors. ENOSPC is only returned when
|
||||||
|
// the BTF blob is correct, a log was requested, and the provided buffer
|
||||||
|
// is too small.
|
||||||
|
_, ve := sys.BtfLoad(attr)
|
||||||
|
return nil, internal.ErrorWithLog(err, logBuf, errors.Is(ve, unix.ENOSPC))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Handle{fd, attr.BtfSize}, nil
|
return &Handle{fd, attr.BtfSize}, nil
|
||||||
|
|||||||
+34
-65
@@ -6,33 +6,36 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage
|
//go:generate stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage,btfKind
|
||||||
|
|
||||||
// btfKind describes a Type.
|
// btfKind describes a Type.
|
||||||
type btfKind uint8
|
type btfKind uint8
|
||||||
|
|
||||||
// Equivalents of the BTF_KIND_* constants.
|
// Equivalents of the BTF_KIND_* constants.
|
||||||
const (
|
const (
|
||||||
kindUnknown btfKind = iota
|
kindUnknown btfKind = iota // Unknown
|
||||||
kindInt
|
kindInt // Int
|
||||||
kindPointer
|
kindPointer // Pointer
|
||||||
kindArray
|
kindArray // Array
|
||||||
kindStruct
|
kindStruct // Struct
|
||||||
kindUnion
|
kindUnion // Union
|
||||||
kindEnum
|
kindEnum // Enum
|
||||||
kindForward
|
kindForward // Forward
|
||||||
kindTypedef
|
kindTypedef // Typedef
|
||||||
kindVolatile
|
kindVolatile // Volatile
|
||||||
kindConst
|
kindConst // Const
|
||||||
kindRestrict
|
kindRestrict // Restrict
|
||||||
// Added ~4.20
|
// Added ~4.20
|
||||||
kindFunc
|
kindFunc // Func
|
||||||
kindFuncProto
|
kindFuncProto // FuncProto
|
||||||
// Added ~5.1
|
// Added ~5.1
|
||||||
kindVar
|
kindVar // Var
|
||||||
kindDatasec
|
kindDatasec // Datasec
|
||||||
// Added ~5.13
|
// Added ~5.13
|
||||||
kindFloat
|
kindFloat // Float
|
||||||
|
// Added 5.16
|
||||||
|
kindDeclTag // DeclTag
|
||||||
|
kindTypeTag // TypeTag
|
||||||
)
|
)
|
||||||
|
|
||||||
// FuncLinkage describes BTF function linkage metadata.
|
// FuncLinkage describes BTF function linkage metadata.
|
||||||
@@ -85,47 +88,6 @@ type btfType struct {
|
|||||||
SizeType uint32
|
SizeType uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k btfKind) String() string {
|
|
||||||
switch k {
|
|
||||||
case kindUnknown:
|
|
||||||
return "Unknown"
|
|
||||||
case kindInt:
|
|
||||||
return "Integer"
|
|
||||||
case kindPointer:
|
|
||||||
return "Pointer"
|
|
||||||
case kindArray:
|
|
||||||
return "Array"
|
|
||||||
case kindStruct:
|
|
||||||
return "Struct"
|
|
||||||
case kindUnion:
|
|
||||||
return "Union"
|
|
||||||
case kindEnum:
|
|
||||||
return "Enumeration"
|
|
||||||
case kindForward:
|
|
||||||
return "Forward"
|
|
||||||
case kindTypedef:
|
|
||||||
return "Typedef"
|
|
||||||
case kindVolatile:
|
|
||||||
return "Volatile"
|
|
||||||
case kindConst:
|
|
||||||
return "Const"
|
|
||||||
case kindRestrict:
|
|
||||||
return "Restrict"
|
|
||||||
case kindFunc:
|
|
||||||
return "Function"
|
|
||||||
case kindFuncProto:
|
|
||||||
return "Function Proto"
|
|
||||||
case kindVar:
|
|
||||||
return "Variable"
|
|
||||||
case kindDatasec:
|
|
||||||
return "Section"
|
|
||||||
case kindFloat:
|
|
||||||
return "Float"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("Unknown (%d)", k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mask(len uint32) uint32 {
|
func mask(len uint32) uint32 {
|
||||||
return (1 << len) - 1
|
return (1 << len) - 1
|
||||||
}
|
}
|
||||||
@@ -209,11 +171,11 @@ func (rt *rawType) Marshal(w io.Writer, bo binary.ByteOrder) error {
|
|||||||
|
|
||||||
// btfInt encodes additional data for integers.
|
// btfInt encodes additional data for integers.
|
||||||
//
|
//
|
||||||
// ? ? ? ? e e e e o o o o o o o o ? ? ? ? ? ? ? ? b b b b b b b b
|
// ? ? ? ? e e e e o o o o o o o o ? ? ? ? ? ? ? ? b b b b b b b b
|
||||||
// ? = undefined
|
// ? = undefined
|
||||||
// e = encoding
|
// e = encoding
|
||||||
// o = offset (bitfields?)
|
// o = offset (bitfields?)
|
||||||
// b = bits (bitfields)
|
// b = bits (bitfields)
|
||||||
type btfInt struct {
|
type btfInt struct {
|
||||||
Raw uint32
|
Raw uint32
|
||||||
}
|
}
|
||||||
@@ -275,7 +237,7 @@ type btfVariable struct {
|
|||||||
|
|
||||||
type btfEnum struct {
|
type btfEnum struct {
|
||||||
NameOff uint32
|
NameOff uint32
|
||||||
Val int32
|
Val uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type btfParam struct {
|
type btfParam struct {
|
||||||
@@ -283,6 +245,10 @@ type btfParam struct {
|
|||||||
Type TypeID
|
Type TypeID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type btfDeclTag struct {
|
||||||
|
ComponentIdx uint32
|
||||||
|
}
|
||||||
|
|
||||||
func readTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32) ([]rawType, error) {
|
func readTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32) ([]rawType, error) {
|
||||||
var header btfType
|
var header btfType
|
||||||
// because of the interleaving between types and struct members it is difficult to
|
// because of the interleaving between types and struct members it is difficult to
|
||||||
@@ -325,6 +291,9 @@ func readTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32) ([]rawType, err
|
|||||||
case kindDatasec:
|
case kindDatasec:
|
||||||
data = make([]btfVarSecinfo, header.Vlen())
|
data = make([]btfVarSecinfo, header.Vlen())
|
||||||
case kindFloat:
|
case kindFloat:
|
||||||
|
case kindDeclTag:
|
||||||
|
data = new(btfDeclTag)
|
||||||
|
case kindTypeTag:
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind())
|
return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind())
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-1
@@ -1,4 +1,4 @@
|
|||||||
// Code generated by "stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage"; DO NOT EDIT.
|
// Code generated by "stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage,btfKind"; DO NOT EDIT.
|
||||||
|
|
||||||
package btf
|
package btf
|
||||||
|
|
||||||
@@ -42,3 +42,38 @@ func (i VarLinkage) String() string {
|
|||||||
}
|
}
|
||||||
return _VarLinkage_name[_VarLinkage_index[i]:_VarLinkage_index[i+1]]
|
return _VarLinkage_name[_VarLinkage_index[i]:_VarLinkage_index[i+1]]
|
||||||
}
|
}
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[kindUnknown-0]
|
||||||
|
_ = x[kindInt-1]
|
||||||
|
_ = x[kindPointer-2]
|
||||||
|
_ = x[kindArray-3]
|
||||||
|
_ = x[kindStruct-4]
|
||||||
|
_ = x[kindUnion-5]
|
||||||
|
_ = x[kindEnum-6]
|
||||||
|
_ = x[kindForward-7]
|
||||||
|
_ = x[kindTypedef-8]
|
||||||
|
_ = x[kindVolatile-9]
|
||||||
|
_ = x[kindConst-10]
|
||||||
|
_ = x[kindRestrict-11]
|
||||||
|
_ = x[kindFunc-12]
|
||||||
|
_ = x[kindFuncProto-13]
|
||||||
|
_ = x[kindVar-14]
|
||||||
|
_ = x[kindDatasec-15]
|
||||||
|
_ = x[kindFloat-16]
|
||||||
|
_ = x[kindDeclTag-17]
|
||||||
|
_ = x[kindTypeTag-18]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _btfKind_name = "UnknownIntPointerArrayStructUnionEnumForwardTypedefVolatileConstRestrictFuncFuncProtoVarDatasecFloatDeclTagTypeTag"
|
||||||
|
|
||||||
|
var _btfKind_index = [...]uint8{0, 7, 10, 17, 22, 28, 33, 37, 44, 51, 59, 64, 72, 76, 85, 88, 95, 100, 107, 114}
|
||||||
|
|
||||||
|
func (i btfKind) String() string {
|
||||||
|
if i >= btfKind(len(_btfKind_index)-1) {
|
||||||
|
return "btfKind(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _btfKind_name[_btfKind_index[i]:_btfKind_index[i+1]]
|
||||||
|
}
|
||||||
|
|||||||
+31
-34
@@ -156,16 +156,17 @@ func (k coreKind) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CORERelocate calculates the difference in types between local and target.
|
// CORERelocate calculates changes needed to adjust eBPF instructions for differences
|
||||||
|
// in types.
|
||||||
//
|
//
|
||||||
// Returns a list of fixups which can be applied to instructions to make them
|
// Returns a list of fixups which can be applied to instructions to make them
|
||||||
// match the target type(s).
|
// match the target type(s).
|
||||||
//
|
//
|
||||||
// Fixups are returned in the order of relos, e.g. fixup[i] is the solution
|
// Fixups are returned in the order of relos, e.g. fixup[i] is the solution
|
||||||
// for relos[i].
|
// for relos[i].
|
||||||
func CORERelocate(local, target *Spec, relos []*CORERelocation) ([]COREFixup, error) {
|
func CORERelocate(relos []*CORERelocation, target *Spec, bo binary.ByteOrder) ([]COREFixup, error) {
|
||||||
if local.byteOrder != target.byteOrder {
|
if bo != target.byteOrder {
|
||||||
return nil, fmt.Errorf("can't relocate %s against %s", local.byteOrder, target.byteOrder)
|
return nil, fmt.Errorf("can't relocate %s against %s", bo, target.byteOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
type reloGroup struct {
|
type reloGroup struct {
|
||||||
@@ -185,15 +186,14 @@ func CORERelocate(local, target *Spec, relos []*CORERelocation) ([]COREFixup, er
|
|||||||
return nil, fmt.Errorf("%s: unexpected accessor %v", relo.kind, relo.accessor)
|
return nil, fmt.Errorf("%s: unexpected accessor %v", relo.kind, relo.accessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := local.TypeID(relo.typ)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("%s: %w", relo.kind, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
result[i] = COREFixup{
|
result[i] = COREFixup{
|
||||||
kind: relo.kind,
|
kind: relo.kind,
|
||||||
local: uint32(id),
|
local: uint32(relo.id),
|
||||||
target: uint32(id),
|
// NB: Using relo.id as the target here is incorrect, since
|
||||||
|
// it doesn't match the BTF we generate on the fly. This isn't
|
||||||
|
// too bad for now since there are no uses of the local type ID
|
||||||
|
// in the kernel, yet.
|
||||||
|
target: uint32(relo.id),
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -214,7 +214,7 @@ func CORERelocate(local, target *Spec, relos []*CORERelocation) ([]COREFixup, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
targets := target.namedTypes[newEssentialName(localTypeName)]
|
targets := target.namedTypes[newEssentialName(localTypeName)]
|
||||||
fixups, err := coreCalculateFixups(local, target, localType, targets, group.relos)
|
fixups, err := coreCalculateFixups(group.relos, target, targets, bo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("relocate %s: %w", localType, err)
|
return nil, fmt.Errorf("relocate %s: %w", localType, err)
|
||||||
}
|
}
|
||||||
@@ -230,18 +230,13 @@ func CORERelocate(local, target *Spec, relos []*CORERelocation) ([]COREFixup, er
|
|||||||
var errAmbiguousRelocation = errors.New("ambiguous relocation")
|
var errAmbiguousRelocation = errors.New("ambiguous relocation")
|
||||||
var errImpossibleRelocation = errors.New("impossible relocation")
|
var errImpossibleRelocation = errors.New("impossible relocation")
|
||||||
|
|
||||||
// coreCalculateFixups calculates the fixups for the given relocations using
|
// coreCalculateFixups finds the target type that best matches all relocations.
|
||||||
// the "best" target.
|
//
|
||||||
|
// All relos must target the same type.
|
||||||
//
|
//
|
||||||
// The best target is determined by scoring: the less poisoning we have to do
|
// The best target is determined by scoring: the less poisoning we have to do
|
||||||
// the better the target is.
|
// the better the target is.
|
||||||
func coreCalculateFixups(localSpec, targetSpec *Spec, local Type, targets []Type, relos []*CORERelocation) ([]COREFixup, error) {
|
func coreCalculateFixups(relos []*CORERelocation, targetSpec *Spec, targets []Type, bo binary.ByteOrder) ([]COREFixup, error) {
|
||||||
localID, err := localSpec.TypeID(local)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("local type ID: %w", err)
|
|
||||||
}
|
|
||||||
local = Copy(local, UnderlyingType)
|
|
||||||
|
|
||||||
bestScore := len(relos)
|
bestScore := len(relos)
|
||||||
var bestFixups []COREFixup
|
var bestFixups []COREFixup
|
||||||
for i := range targets {
|
for i := range targets {
|
||||||
@@ -254,7 +249,7 @@ func coreCalculateFixups(localSpec, targetSpec *Spec, local Type, targets []Type
|
|||||||
score := 0 // lower is better
|
score := 0 // lower is better
|
||||||
fixups := make([]COREFixup, 0, len(relos))
|
fixups := make([]COREFixup, 0, len(relos))
|
||||||
for _, relo := range relos {
|
for _, relo := range relos {
|
||||||
fixup, err := coreCalculateFixup(localSpec.byteOrder, local, localID, target, targetID, relo)
|
fixup, err := coreCalculateFixup(relo, target, targetID, bo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("target %s: %w", target, err)
|
return nil, fmt.Errorf("target %s: %w", target, err)
|
||||||
}
|
}
|
||||||
@@ -305,7 +300,7 @@ func coreCalculateFixups(localSpec, targetSpec *Spec, local Type, targets []Type
|
|||||||
|
|
||||||
// coreCalculateFixup calculates the fixup for a single local type, target type
|
// coreCalculateFixup calculates the fixup for a single local type, target type
|
||||||
// and relocation.
|
// and relocation.
|
||||||
func coreCalculateFixup(byteOrder binary.ByteOrder, local Type, localID TypeID, target Type, targetID TypeID, relo *CORERelocation) (COREFixup, error) {
|
func coreCalculateFixup(relo *CORERelocation, target Type, targetID TypeID, bo binary.ByteOrder) (COREFixup, error) {
|
||||||
fixup := func(local, target uint32) (COREFixup, error) {
|
fixup := func(local, target uint32) (COREFixup, error) {
|
||||||
return COREFixup{kind: relo.kind, local: local, target: target}, nil
|
return COREFixup{kind: relo.kind, local: local, target: target}, nil
|
||||||
}
|
}
|
||||||
@@ -320,6 +315,8 @@ func coreCalculateFixup(byteOrder binary.ByteOrder, local Type, localID TypeID,
|
|||||||
}
|
}
|
||||||
zero := COREFixup{}
|
zero := COREFixup{}
|
||||||
|
|
||||||
|
local := Copy(relo.typ, UnderlyingType)
|
||||||
|
|
||||||
switch relo.kind {
|
switch relo.kind {
|
||||||
case reloTypeIDTarget, reloTypeSize, reloTypeExists:
|
case reloTypeIDTarget, reloTypeSize, reloTypeExists:
|
||||||
if len(relo.accessor) > 1 || relo.accessor[0] != 0 {
|
if len(relo.accessor) > 1 || relo.accessor[0] != 0 {
|
||||||
@@ -339,7 +336,7 @@ func coreCalculateFixup(byteOrder binary.ByteOrder, local Type, localID TypeID,
|
|||||||
return fixup(1, 1)
|
return fixup(1, 1)
|
||||||
|
|
||||||
case reloTypeIDTarget:
|
case reloTypeIDTarget:
|
||||||
return fixup(uint32(localID), uint32(targetID))
|
return fixup(uint32(relo.id), uint32(targetID))
|
||||||
|
|
||||||
case reloTypeSize:
|
case reloTypeSize:
|
||||||
localSize, err := Sizeof(local)
|
localSize, err := Sizeof(local)
|
||||||
@@ -427,7 +424,7 @@ func coreCalculateFixup(byteOrder binary.ByteOrder, local Type, localID TypeID,
|
|||||||
|
|
||||||
case reloFieldLShiftU64:
|
case reloFieldLShiftU64:
|
||||||
var target uint32
|
var target uint32
|
||||||
if byteOrder == binary.LittleEndian {
|
if bo == binary.LittleEndian {
|
||||||
targetSize, err := targetField.sizeBits()
|
targetSize, err := targetField.sizeBits()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return zero, err
|
return zero, err
|
||||||
@@ -536,9 +533,9 @@ func (ca coreAccessor) enumValue(t Type) (*EnumValue, error) {
|
|||||||
// coreField represents the position of a "child" of a composite type from the
|
// coreField represents the position of a "child" of a composite type from the
|
||||||
// start of that type.
|
// start of that type.
|
||||||
//
|
//
|
||||||
// /- start of composite
|
// /- start of composite
|
||||||
// | offset * 8 | bitfieldOffset | bitfieldSize | ... |
|
// | offset * 8 | bitfieldOffset | bitfieldSize | ... |
|
||||||
// \- start of field end of field -/
|
// \- start of field end of field -/
|
||||||
type coreField struct {
|
type coreField struct {
|
||||||
Type Type
|
Type Type
|
||||||
|
|
||||||
@@ -858,7 +855,7 @@ func coreAreTypesCompatible(localType Type, targetType Type) error {
|
|||||||
depth = 0
|
depth = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
for ; l != nil && t != nil; l, t = localTs.shift(), targetTs.shift() {
|
for ; l != nil && t != nil; l, t = localTs.Shift(), targetTs.Shift() {
|
||||||
if depth >= maxTypeDepth {
|
if depth >= maxTypeDepth {
|
||||||
return errors.New("types are nested too deep")
|
return errors.New("types are nested too deep")
|
||||||
}
|
}
|
||||||
@@ -876,8 +873,8 @@ func coreAreTypesCompatible(localType Type, targetType Type) error {
|
|||||||
|
|
||||||
case *Pointer, *Array:
|
case *Pointer, *Array:
|
||||||
depth++
|
depth++
|
||||||
localType.walk(&localTs)
|
walkType(localType, localTs.Push)
|
||||||
targetType.walk(&targetTs)
|
walkType(targetType, targetTs.Push)
|
||||||
|
|
||||||
case *FuncProto:
|
case *FuncProto:
|
||||||
tv := targetType.(*FuncProto)
|
tv := targetType.(*FuncProto)
|
||||||
@@ -886,8 +883,8 @@ func coreAreTypesCompatible(localType Type, targetType Type) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
depth++
|
depth++
|
||||||
localType.walk(&localTs)
|
walkType(localType, localTs.Push)
|
||||||
targetType.walk(&targetTs)
|
walkType(targetType, targetTs.Push)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported type %T", localType)
|
return fmt.Errorf("unsupported type %T", localType)
|
||||||
|
|||||||
+4
@@ -605,9 +605,12 @@ type bpfCORERelo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CORERelocation struct {
|
type CORERelocation struct {
|
||||||
|
// The local type of the relocation, stripped of typedefs and qualifiers.
|
||||||
typ Type
|
typ Type
|
||||||
accessor coreAccessor
|
accessor coreAccessor
|
||||||
kind coreKind
|
kind coreKind
|
||||||
|
// The ID of the local type in the source BTF.
|
||||||
|
id TypeID
|
||||||
}
|
}
|
||||||
|
|
||||||
func CORERelocationMetadata(ins *asm.Instruction) *CORERelocation {
|
func CORERelocationMetadata(ins *asm.Instruction) *CORERelocation {
|
||||||
@@ -641,6 +644,7 @@ func newRelocationInfo(relo bpfCORERelo, ts types, strings *stringTable) (*coreR
|
|||||||
typ,
|
typ,
|
||||||
accessor,
|
accessor,
|
||||||
relo.Kind,
|
relo.Kind,
|
||||||
|
relo.TypeID,
|
||||||
},
|
},
|
||||||
asm.RawInstructionOffset(relo.InsnOff),
|
asm.RawInstructionOffset(relo.InsnOff),
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
+74
-53
@@ -56,54 +56,40 @@ func (gf *GoFormatter) enumIdentifier(name, element string) string {
|
|||||||
//
|
//
|
||||||
// It encodes https://golang.org/ref/spec#Type_declarations:
|
// It encodes https://golang.org/ref/spec#Type_declarations:
|
||||||
//
|
//
|
||||||
// type foo struct { bar uint32; }
|
// type foo struct { bar uint32; }
|
||||||
// type bar int32
|
// type bar int32
|
||||||
func (gf *GoFormatter) writeTypeDecl(name string, typ Type) error {
|
func (gf *GoFormatter) writeTypeDecl(name string, typ Type) error {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return fmt.Errorf("need a name for type %s", typ)
|
return fmt.Errorf("need a name for type %s", typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v := skipQualifiers(typ).(type) {
|
typ = skipQualifiers(typ)
|
||||||
case *Enum:
|
fmt.Fprintf(&gf.w, "type %s ", name)
|
||||||
fmt.Fprintf(&gf.w, "type %s ", name)
|
if err := gf.writeTypeLit(typ, 0); err != nil {
|
||||||
switch v.Size {
|
return err
|
||||||
case 1:
|
|
||||||
gf.w.WriteString("int8")
|
|
||||||
case 2:
|
|
||||||
gf.w.WriteString("int16")
|
|
||||||
case 4:
|
|
||||||
gf.w.WriteString("int32")
|
|
||||||
case 8:
|
|
||||||
gf.w.WriteString("int64")
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("%s: invalid enum size %d", typ, v.Size)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(v.Values) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
gf.w.WriteString("; const ( ")
|
|
||||||
for _, ev := range v.Values {
|
|
||||||
id := gf.enumIdentifier(name, ev.Name)
|
|
||||||
fmt.Fprintf(&gf.w, "%s %s = %d; ", id, name, ev.Value)
|
|
||||||
}
|
|
||||||
gf.w.WriteString(")")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
fmt.Fprintf(&gf.w, "type %s ", name)
|
|
||||||
return gf.writeTypeLit(v, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e, ok := typ.(*Enum)
|
||||||
|
if !ok || len(e.Values) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gf.w.WriteString("; const ( ")
|
||||||
|
for _, ev := range e.Values {
|
||||||
|
id := gf.enumIdentifier(name, ev.Name)
|
||||||
|
fmt.Fprintf(&gf.w, "%s %s = %d; ", id, name, ev.Value)
|
||||||
|
}
|
||||||
|
gf.w.WriteString(")")
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeType outputs the name of a named type or a literal describing the type.
|
// writeType outputs the name of a named type or a literal describing the type.
|
||||||
//
|
//
|
||||||
// It encodes https://golang.org/ref/spec#Types.
|
// It encodes https://golang.org/ref/spec#Types.
|
||||||
//
|
//
|
||||||
// foo (if foo is a named type)
|
// foo (if foo is a named type)
|
||||||
// uint32
|
// uint32
|
||||||
func (gf *GoFormatter) writeType(typ Type, depth int) error {
|
func (gf *GoFormatter) writeType(typ Type, depth int) error {
|
||||||
typ = skipQualifiers(typ)
|
typ = skipQualifiers(typ)
|
||||||
|
|
||||||
@@ -122,8 +108,8 @@ func (gf *GoFormatter) writeType(typ Type, depth int) error {
|
|||||||
//
|
//
|
||||||
// It encodes https://golang.org/ref/spec#TypeLit.
|
// It encodes https://golang.org/ref/spec#TypeLit.
|
||||||
//
|
//
|
||||||
// struct { bar uint32; }
|
// struct { bar uint32; }
|
||||||
// uint32
|
// uint32
|
||||||
func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error {
|
func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error {
|
||||||
depth++
|
depth++
|
||||||
if depth > maxTypeDepth {
|
if depth > maxTypeDepth {
|
||||||
@@ -133,10 +119,24 @@ func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error {
|
|||||||
var err error
|
var err error
|
||||||
switch v := skipQualifiers(typ).(type) {
|
switch v := skipQualifiers(typ).(type) {
|
||||||
case *Int:
|
case *Int:
|
||||||
gf.writeIntLit(v)
|
err = gf.writeIntLit(v)
|
||||||
|
|
||||||
case *Enum:
|
case *Enum:
|
||||||
gf.w.WriteString("int32")
|
if !v.Signed {
|
||||||
|
gf.w.WriteRune('u')
|
||||||
|
}
|
||||||
|
switch v.Size {
|
||||||
|
case 1:
|
||||||
|
gf.w.WriteString("int8")
|
||||||
|
case 2:
|
||||||
|
gf.w.WriteString("int16")
|
||||||
|
case 4:
|
||||||
|
gf.w.WriteString("int32")
|
||||||
|
case 8:
|
||||||
|
gf.w.WriteString("int64")
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("invalid enum size %d", v.Size)
|
||||||
|
}
|
||||||
|
|
||||||
case *Typedef:
|
case *Typedef:
|
||||||
err = gf.writeType(v.Type, depth)
|
err = gf.writeType(v.Type, depth)
|
||||||
@@ -166,19 +166,36 @@ func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gf *GoFormatter) writeIntLit(i *Int) {
|
func (gf *GoFormatter) writeIntLit(i *Int) error {
|
||||||
// NB: Encoding.IsChar is ignored.
|
|
||||||
if i.Encoding.IsBool() && i.Size == 1 {
|
|
||||||
gf.w.WriteString("bool")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bits := i.Size * 8
|
bits := i.Size * 8
|
||||||
if i.Encoding.IsSigned() {
|
switch i.Encoding {
|
||||||
fmt.Fprintf(&gf.w, "int%d", bits)
|
case Bool:
|
||||||
} else {
|
if i.Size != 1 {
|
||||||
fmt.Fprintf(&gf.w, "uint%d", bits)
|
return fmt.Errorf("bool with size %d", i.Size)
|
||||||
|
}
|
||||||
|
gf.w.WriteString("bool")
|
||||||
|
case Char:
|
||||||
|
if i.Size != 1 {
|
||||||
|
return fmt.Errorf("char with size %d", i.Size)
|
||||||
|
}
|
||||||
|
// BTF doesn't have a way to specify the signedness of a char. Assume
|
||||||
|
// we are dealing with unsigned, since this works nicely with []byte
|
||||||
|
// in Go code.
|
||||||
|
fallthrough
|
||||||
|
case Unsigned, Signed:
|
||||||
|
stem := "uint"
|
||||||
|
if i.Encoding == Signed {
|
||||||
|
stem = "int"
|
||||||
|
}
|
||||||
|
if i.Size > 8 {
|
||||||
|
fmt.Fprintf(&gf.w, "[%d]byte /* %s%d */", i.Size, stem, i.Size*8)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(&gf.w, "%s%d", stem, bits)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("can't encode %s", i.Encoding)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gf *GoFormatter) writeStructLit(size uint32, members []Member, depth int) error {
|
func (gf *GoFormatter) writeStructLit(size uint32, members []Member, depth int) error {
|
||||||
@@ -199,11 +216,15 @@ func (gf *GoFormatter) writeStructLit(size uint32, members []Member, depth int)
|
|||||||
gf.writePadding(n)
|
gf.writePadding(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
size, err := Sizeof(m.Type)
|
fieldSize, err := Sizeof(m.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field %d: %w", i, err)
|
return fmt.Errorf("field %d: %w", i, err)
|
||||||
}
|
}
|
||||||
prevOffset = offset + uint32(size)
|
|
||||||
|
prevOffset = offset + uint32(fieldSize)
|
||||||
|
if prevOffset > size {
|
||||||
|
return fmt.Errorf("field %d of size %d exceeds type size %d", i, fieldSize, size)
|
||||||
|
}
|
||||||
|
|
||||||
if err := gf.writeStructField(m, depth); err != nil {
|
if err := gf.writeStructField(m, depth); err != nil {
|
||||||
return fmt.Errorf("field %d: %w", i, err)
|
return fmt.Errorf("field %d: %w", i, err)
|
||||||
|
|||||||
+56
-18
@@ -71,51 +71,89 @@ func (i *HandleInfo) IsModule() bool {
|
|||||||
|
|
||||||
// HandleIterator allows enumerating BTF blobs loaded into the kernel.
|
// HandleIterator allows enumerating BTF blobs loaded into the kernel.
|
||||||
type HandleIterator struct {
|
type HandleIterator struct {
|
||||||
// The ID of the last retrieved handle. Only valid after a call to Next.
|
// The ID of the current handle. Only valid after a call to Next.
|
||||||
ID ID
|
ID ID
|
||||||
err error
|
// The current Handle. Only valid until a call to Next.
|
||||||
|
// See Take if you want to retain the handle.
|
||||||
|
Handle *Handle
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next retrieves a handle for the next BTF blob.
|
// Next retrieves a handle for the next BTF object.
|
||||||
//
|
//
|
||||||
// [Handle.Close] is called if *handle is non-nil to avoid leaking fds.
|
// Returns true if another BTF object was found. Call [HandleIterator.Err] after
|
||||||
//
|
|
||||||
// Returns true if another BTF blob was found. Call [HandleIterator.Err] after
|
|
||||||
// the function returns false.
|
// the function returns false.
|
||||||
func (it *HandleIterator) Next(handle **Handle) bool {
|
func (it *HandleIterator) Next() bool {
|
||||||
if *handle != nil {
|
|
||||||
(*handle).Close()
|
|
||||||
*handle = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
id := it.ID
|
id := it.ID
|
||||||
for {
|
for {
|
||||||
attr := &sys.BtfGetNextIdAttr{Id: id}
|
attr := &sys.BtfGetNextIdAttr{Id: id}
|
||||||
err := sys.BtfGetNextId(attr)
|
err := sys.BtfGetNextId(attr)
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
// There are no more BTF objects.
|
// There are no more BTF objects.
|
||||||
return false
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
it.err = fmt.Errorf("get next BTF ID: %w", err)
|
it.err = fmt.Errorf("get next BTF ID: %w", err)
|
||||||
return false
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
id = attr.NextId
|
id = attr.NextId
|
||||||
*handle, err = NewHandleFromID(id)
|
handle, err := NewHandleFromID(id)
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
// Try again with the next ID.
|
// Try again with the next ID.
|
||||||
continue
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
it.err = fmt.Errorf("retrieve handle for ID %d: %w", id, err)
|
it.err = fmt.Errorf("retrieve handle for ID %d: %w", id, err)
|
||||||
return false
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
it.ID = id
|
it.Handle.Close()
|
||||||
|
it.ID, it.Handle = id, handle
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No more handles or we encountered an error.
|
||||||
|
it.Handle.Close()
|
||||||
|
it.Handle = nil
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take the ownership of the current handle.
|
||||||
|
//
|
||||||
|
// It's the callers responsibility to close the handle.
|
||||||
|
func (it *HandleIterator) Take() *Handle {
|
||||||
|
handle := it.Handle
|
||||||
|
it.Handle = nil
|
||||||
|
return handle
|
||||||
}
|
}
|
||||||
|
|
||||||
// Err returns an error if iteration failed for some reason.
|
// Err returns an error if iteration failed for some reason.
|
||||||
func (it *HandleIterator) Err() error {
|
func (it *HandleIterator) Err() error {
|
||||||
return it.err
|
return it.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindHandle returns the first handle for which predicate returns true.
|
||||||
|
//
|
||||||
|
// Requires CAP_SYS_ADMIN.
|
||||||
|
//
|
||||||
|
// Returns an error wrapping ErrNotFound if predicate never returns true or if
|
||||||
|
// there is no BTF loaded into the kernel.
|
||||||
|
func FindHandle(predicate func(info *HandleInfo) bool) (*Handle, error) {
|
||||||
|
it := new(HandleIterator)
|
||||||
|
defer it.Handle.Close()
|
||||||
|
|
||||||
|
for it.Next() {
|
||||||
|
info, err := it.Handle.Info()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("info for ID %d: %w", it.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if predicate(info) {
|
||||||
|
return it.Take(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := it.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("iterate handles: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("find handle: %w", ErrNotFound)
|
||||||
|
}
|
||||||
|
|||||||
+4
@@ -89,6 +89,10 @@ func (st *stringTable) lookup(offset uint32) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (st *stringTable) Length() int {
|
func (st *stringTable) Length() int {
|
||||||
|
if len(st.offsets) == 0 || len(st.strings) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
last := len(st.offsets) - 1
|
last := len(st.offsets) - 1
|
||||||
return int(st.offsets[last]) + len(st.strings[last]) + 1
|
return int(st.offsets[last]) + len(st.strings[last]) + 1
|
||||||
}
|
}
|
||||||
|
|||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
package btf
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// walkType calls fn on each child of typ.
|
||||||
|
func walkType(typ Type, fn func(*Type)) {
|
||||||
|
// Explicitly type switch on the most common types to allow the inliner to
|
||||||
|
// do its work. This avoids allocating intermediate slices from walk() on
|
||||||
|
// the heap.
|
||||||
|
switch v := typ.(type) {
|
||||||
|
case *Void, *Int, *Enum, *Fwd, *Float:
|
||||||
|
// No children to traverse.
|
||||||
|
case *Pointer:
|
||||||
|
fn(&v.Target)
|
||||||
|
case *Array:
|
||||||
|
fn(&v.Index)
|
||||||
|
fn(&v.Type)
|
||||||
|
case *Struct:
|
||||||
|
for i := range v.Members {
|
||||||
|
fn(&v.Members[i].Type)
|
||||||
|
}
|
||||||
|
case *Union:
|
||||||
|
for i := range v.Members {
|
||||||
|
fn(&v.Members[i].Type)
|
||||||
|
}
|
||||||
|
case *Typedef:
|
||||||
|
fn(&v.Type)
|
||||||
|
case *Volatile:
|
||||||
|
fn(&v.Type)
|
||||||
|
case *Const:
|
||||||
|
fn(&v.Type)
|
||||||
|
case *Restrict:
|
||||||
|
fn(&v.Type)
|
||||||
|
case *Func:
|
||||||
|
fn(&v.Type)
|
||||||
|
case *FuncProto:
|
||||||
|
fn(&v.Return)
|
||||||
|
for i := range v.Params {
|
||||||
|
fn(&v.Params[i].Type)
|
||||||
|
}
|
||||||
|
case *Var:
|
||||||
|
fn(&v.Type)
|
||||||
|
case *Datasec:
|
||||||
|
for i := range v.Vars {
|
||||||
|
fn(&v.Vars[i].Type)
|
||||||
|
}
|
||||||
|
case *declTag:
|
||||||
|
fn(&v.Type)
|
||||||
|
case *typeTag:
|
||||||
|
fn(&v.Type)
|
||||||
|
case *cycle:
|
||||||
|
// cycle has children, but we ignore them deliberately.
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("don't know how to walk Type %T", v))
|
||||||
|
}
|
||||||
|
}
|
||||||
+124
-156
@@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
|
"github.com/cilium/ebpf/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxTypeDepth = 32
|
const maxTypeDepth = 32
|
||||||
@@ -35,9 +36,7 @@ type Type interface {
|
|||||||
// Make a copy of the type, without copying Type members.
|
// Make a copy of the type, without copying Type members.
|
||||||
copy() Type
|
copy() Type
|
||||||
|
|
||||||
// Enumerate all nested Types. Repeated calls must visit nested
|
// New implementations must update walkType.
|
||||||
// types in the same order.
|
|
||||||
walk(*typeDeque)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -51,6 +50,9 @@ var (
|
|||||||
_ Type = (*Var)(nil)
|
_ Type = (*Var)(nil)
|
||||||
_ Type = (*Datasec)(nil)
|
_ Type = (*Datasec)(nil)
|
||||||
_ Type = (*Float)(nil)
|
_ Type = (*Float)(nil)
|
||||||
|
_ Type = (*declTag)(nil)
|
||||||
|
_ Type = (*typeTag)(nil)
|
||||||
|
_ Type = (*cycle)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// types is a list of Type.
|
// types is a list of Type.
|
||||||
@@ -72,40 +74,32 @@ func (v *Void) Format(fs fmt.State, verb rune) { formatType(fs, verb, v) }
|
|||||||
func (v *Void) TypeName() string { return "" }
|
func (v *Void) TypeName() string { return "" }
|
||||||
func (v *Void) size() uint32 { return 0 }
|
func (v *Void) size() uint32 { return 0 }
|
||||||
func (v *Void) copy() Type { return (*Void)(nil) }
|
func (v *Void) copy() Type { return (*Void)(nil) }
|
||||||
func (v *Void) walk(*typeDeque) {}
|
|
||||||
|
|
||||||
type IntEncoding byte
|
type IntEncoding byte
|
||||||
|
|
||||||
|
// Valid IntEncodings.
|
||||||
|
//
|
||||||
|
// These may look like they are flags, but they aren't.
|
||||||
const (
|
const (
|
||||||
Signed IntEncoding = 1 << iota
|
Unsigned IntEncoding = 0
|
||||||
Char
|
Signed IntEncoding = 1
|
||||||
Bool
|
Char IntEncoding = 2
|
||||||
|
Bool IntEncoding = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ie IntEncoding) IsSigned() bool {
|
|
||||||
return ie&Signed != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ie IntEncoding) IsChar() bool {
|
|
||||||
return ie&Char != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ie IntEncoding) IsBool() bool {
|
|
||||||
return ie&Bool != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ie IntEncoding) String() string {
|
func (ie IntEncoding) String() string {
|
||||||
switch {
|
switch ie {
|
||||||
case ie.IsChar() && ie.IsSigned():
|
case Char:
|
||||||
|
// NB: There is no way to determine signedness for char.
|
||||||
return "char"
|
return "char"
|
||||||
case ie.IsChar() && !ie.IsSigned():
|
case Bool:
|
||||||
return "uchar"
|
|
||||||
case ie.IsBool():
|
|
||||||
return "bool"
|
return "bool"
|
||||||
case ie.IsSigned():
|
case Signed:
|
||||||
return "signed"
|
return "signed"
|
||||||
default:
|
case Unsigned:
|
||||||
return "unsigned"
|
return "unsigned"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("IntEncoding(%d)", byte(ie))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +120,6 @@ func (i *Int) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (i *Int) TypeName() string { return i.Name }
|
func (i *Int) TypeName() string { return i.Name }
|
||||||
func (i *Int) size() uint32 { return i.Size }
|
func (i *Int) size() uint32 { return i.Size }
|
||||||
func (i *Int) walk(*typeDeque) {}
|
|
||||||
func (i *Int) copy() Type {
|
func (i *Int) copy() Type {
|
||||||
cpy := *i
|
cpy := *i
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -141,9 +134,8 @@ func (p *Pointer) Format(fs fmt.State, verb rune) {
|
|||||||
formatType(fs, verb, p, "target=", p.Target)
|
formatType(fs, verb, p, "target=", p.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pointer) TypeName() string { return "" }
|
func (p *Pointer) TypeName() string { return "" }
|
||||||
func (p *Pointer) size() uint32 { return 8 }
|
func (p *Pointer) size() uint32 { return 8 }
|
||||||
func (p *Pointer) walk(tdq *typeDeque) { tdq.push(&p.Target) }
|
|
||||||
func (p *Pointer) copy() Type {
|
func (p *Pointer) copy() Type {
|
||||||
cpy := *p
|
cpy := *p
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -162,11 +154,6 @@ func (arr *Array) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (arr *Array) TypeName() string { return "" }
|
func (arr *Array) TypeName() string { return "" }
|
||||||
|
|
||||||
func (arr *Array) walk(tdq *typeDeque) {
|
|
||||||
tdq.push(&arr.Index)
|
|
||||||
tdq.push(&arr.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (arr *Array) copy() Type {
|
func (arr *Array) copy() Type {
|
||||||
cpy := *arr
|
cpy := *arr
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -188,12 +175,6 @@ func (s *Struct) TypeName() string { return s.Name }
|
|||||||
|
|
||||||
func (s *Struct) size() uint32 { return s.Size }
|
func (s *Struct) size() uint32 { return s.Size }
|
||||||
|
|
||||||
func (s *Struct) walk(tdq *typeDeque) {
|
|
||||||
for i := range s.Members {
|
|
||||||
tdq.push(&s.Members[i].Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Struct) copy() Type {
|
func (s *Struct) copy() Type {
|
||||||
cpy := *s
|
cpy := *s
|
||||||
cpy.Members = copyMembers(s.Members)
|
cpy.Members = copyMembers(s.Members)
|
||||||
@@ -220,12 +201,6 @@ func (u *Union) TypeName() string { return u.Name }
|
|||||||
|
|
||||||
func (u *Union) size() uint32 { return u.Size }
|
func (u *Union) size() uint32 { return u.Size }
|
||||||
|
|
||||||
func (u *Union) walk(tdq *typeDeque) {
|
|
||||||
for i := range u.Members {
|
|
||||||
tdq.push(&u.Members[i].Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *Union) copy() Type {
|
func (u *Union) copy() Type {
|
||||||
cpy := *u
|
cpy := *u
|
||||||
cpy.Members = copyMembers(u.Members)
|
cpy.Members = copyMembers(u.Members)
|
||||||
@@ -273,7 +248,9 @@ type Member struct {
|
|||||||
type Enum struct {
|
type Enum struct {
|
||||||
Name string
|
Name string
|
||||||
// Size of the enum value in bytes.
|
// Size of the enum value in bytes.
|
||||||
Size uint32
|
Size uint32
|
||||||
|
// True if the values should be interpreted as signed integers.
|
||||||
|
Signed bool
|
||||||
Values []EnumValue
|
Values []EnumValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,11 +265,10 @@ func (e *Enum) TypeName() string { return e.Name }
|
|||||||
// Is is not a valid Type
|
// Is is not a valid Type
|
||||||
type EnumValue struct {
|
type EnumValue struct {
|
||||||
Name string
|
Name string
|
||||||
Value int32
|
Value uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Enum) size() uint32 { return e.Size }
|
func (e *Enum) size() uint32 { return e.Size }
|
||||||
func (e *Enum) walk(*typeDeque) {}
|
|
||||||
func (e *Enum) copy() Type {
|
func (e *Enum) copy() Type {
|
||||||
cpy := *e
|
cpy := *e
|
||||||
cpy.Values = make([]EnumValue, len(e.Values))
|
cpy.Values = make([]EnumValue, len(e.Values))
|
||||||
@@ -332,7 +308,6 @@ func (f *Fwd) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (f *Fwd) TypeName() string { return f.Name }
|
func (f *Fwd) TypeName() string { return f.Name }
|
||||||
|
|
||||||
func (f *Fwd) walk(*typeDeque) {}
|
|
||||||
func (f *Fwd) copy() Type {
|
func (f *Fwd) copy() Type {
|
||||||
cpy := *f
|
cpy := *f
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -350,7 +325,6 @@ func (td *Typedef) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (td *Typedef) TypeName() string { return td.Name }
|
func (td *Typedef) TypeName() string { return td.Name }
|
||||||
|
|
||||||
func (td *Typedef) walk(tdq *typeDeque) { tdq.push(&td.Type) }
|
|
||||||
func (td *Typedef) copy() Type {
|
func (td *Typedef) copy() Type {
|
||||||
cpy := *td
|
cpy := *td
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -367,8 +341,7 @@ func (v *Volatile) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (v *Volatile) TypeName() string { return "" }
|
func (v *Volatile) TypeName() string { return "" }
|
||||||
|
|
||||||
func (v *Volatile) qualify() Type { return v.Type }
|
func (v *Volatile) qualify() Type { return v.Type }
|
||||||
func (v *Volatile) walk(tdq *typeDeque) { tdq.push(&v.Type) }
|
|
||||||
func (v *Volatile) copy() Type {
|
func (v *Volatile) copy() Type {
|
||||||
cpy := *v
|
cpy := *v
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -385,8 +358,7 @@ func (c *Const) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (c *Const) TypeName() string { return "" }
|
func (c *Const) TypeName() string { return "" }
|
||||||
|
|
||||||
func (c *Const) qualify() Type { return c.Type }
|
func (c *Const) qualify() Type { return c.Type }
|
||||||
func (c *Const) walk(tdq *typeDeque) { tdq.push(&c.Type) }
|
|
||||||
func (c *Const) copy() Type {
|
func (c *Const) copy() Type {
|
||||||
cpy := *c
|
cpy := *c
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -403,8 +375,7 @@ func (r *Restrict) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (r *Restrict) TypeName() string { return "" }
|
func (r *Restrict) TypeName() string { return "" }
|
||||||
|
|
||||||
func (r *Restrict) qualify() Type { return r.Type }
|
func (r *Restrict) qualify() Type { return r.Type }
|
||||||
func (r *Restrict) walk(tdq *typeDeque) { tdq.push(&r.Type) }
|
|
||||||
func (r *Restrict) copy() Type {
|
func (r *Restrict) copy() Type {
|
||||||
cpy := *r
|
cpy := *r
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -428,7 +399,6 @@ func (f *Func) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (f *Func) TypeName() string { return f.Name }
|
func (f *Func) TypeName() string { return f.Name }
|
||||||
|
|
||||||
func (f *Func) walk(tdq *typeDeque) { tdq.push(&f.Type) }
|
|
||||||
func (f *Func) copy() Type {
|
func (f *Func) copy() Type {
|
||||||
cpy := *f
|
cpy := *f
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -446,13 +416,6 @@ func (fp *FuncProto) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (fp *FuncProto) TypeName() string { return "" }
|
func (fp *FuncProto) TypeName() string { return "" }
|
||||||
|
|
||||||
func (fp *FuncProto) walk(tdq *typeDeque) {
|
|
||||||
tdq.push(&fp.Return)
|
|
||||||
for i := range fp.Params {
|
|
||||||
tdq.push(&fp.Params[i].Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fp *FuncProto) copy() Type {
|
func (fp *FuncProto) copy() Type {
|
||||||
cpy := *fp
|
cpy := *fp
|
||||||
cpy.Params = make([]FuncParam, len(fp.Params))
|
cpy.Params = make([]FuncParam, len(fp.Params))
|
||||||
@@ -478,7 +441,6 @@ func (v *Var) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (v *Var) TypeName() string { return v.Name }
|
func (v *Var) TypeName() string { return v.Name }
|
||||||
|
|
||||||
func (v *Var) walk(tdq *typeDeque) { tdq.push(&v.Type) }
|
|
||||||
func (v *Var) copy() Type {
|
func (v *Var) copy() Type {
|
||||||
cpy := *v
|
cpy := *v
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -499,12 +461,6 @@ func (ds *Datasec) TypeName() string { return ds.Name }
|
|||||||
|
|
||||||
func (ds *Datasec) size() uint32 { return ds.Size }
|
func (ds *Datasec) size() uint32 { return ds.Size }
|
||||||
|
|
||||||
func (ds *Datasec) walk(tdq *typeDeque) {
|
|
||||||
for i := range ds.Vars {
|
|
||||||
tdq.push(&ds.Vars[i].Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *Datasec) copy() Type {
|
func (ds *Datasec) copy() Type {
|
||||||
cpy := *ds
|
cpy := *ds
|
||||||
cpy.Vars = make([]VarSecinfo, len(ds.Vars))
|
cpy.Vars = make([]VarSecinfo, len(ds.Vars))
|
||||||
@@ -535,12 +491,48 @@ func (f *Float) Format(fs fmt.State, verb rune) {
|
|||||||
|
|
||||||
func (f *Float) TypeName() string { return f.Name }
|
func (f *Float) TypeName() string { return f.Name }
|
||||||
func (f *Float) size() uint32 { return f.Size }
|
func (f *Float) size() uint32 { return f.Size }
|
||||||
func (f *Float) walk(*typeDeque) {}
|
|
||||||
func (f *Float) copy() Type {
|
func (f *Float) copy() Type {
|
||||||
cpy := *f
|
cpy := *f
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// declTag associates metadata with a declaration.
|
||||||
|
type declTag struct {
|
||||||
|
Type Type
|
||||||
|
Value string
|
||||||
|
// The index this tag refers to in the target type. For composite types,
|
||||||
|
// a value of -1 indicates that the tag refers to the whole type. Otherwise
|
||||||
|
// it indicates which member or argument the tag applies to.
|
||||||
|
Index int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dt *declTag) Format(fs fmt.State, verb rune) {
|
||||||
|
formatType(fs, verb, dt, "type=", dt.Type, "value=", dt.Value, "index=", dt.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dt *declTag) TypeName() string { return "" }
|
||||||
|
func (dt *declTag) copy() Type {
|
||||||
|
cpy := *dt
|
||||||
|
return &cpy
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeTag associates metadata with a type.
|
||||||
|
type typeTag struct {
|
||||||
|
Type Type
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tt *typeTag) Format(fs fmt.State, verb rune) {
|
||||||
|
formatType(fs, verb, tt, "type=", tt.Type, "value=", tt.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tt *typeTag) TypeName() string { return "" }
|
||||||
|
func (tt *typeTag) qualify() Type { return tt.Type }
|
||||||
|
func (tt *typeTag) copy() Type {
|
||||||
|
cpy := *tt
|
||||||
|
return &cpy
|
||||||
|
}
|
||||||
|
|
||||||
// cycle is a type which had to be elided since it exceeded maxTypeDepth.
|
// cycle is a type which had to be elided since it exceeded maxTypeDepth.
|
||||||
type cycle struct {
|
type cycle struct {
|
||||||
root Type
|
root Type
|
||||||
@@ -549,7 +541,6 @@ type cycle struct {
|
|||||||
func (c *cycle) ID() TypeID { return math.MaxUint32 }
|
func (c *cycle) ID() TypeID { return math.MaxUint32 }
|
||||||
func (c *cycle) Format(fs fmt.State, verb rune) { formatType(fs, verb, c, "root=", c.root) }
|
func (c *cycle) Format(fs fmt.State, verb rune) { formatType(fs, verb, c, "root=", c.root) }
|
||||||
func (c *cycle) TypeName() string { return "" }
|
func (c *cycle) TypeName() string { return "" }
|
||||||
func (c *cycle) walk(*typeDeque) {}
|
|
||||||
func (c *cycle) copy() Type {
|
func (c *cycle) copy() Type {
|
||||||
cpy := *c
|
cpy := *c
|
||||||
return &cpy
|
return &cpy
|
||||||
@@ -576,6 +567,7 @@ var (
|
|||||||
_ qualifier = (*Const)(nil)
|
_ qualifier = (*Const)(nil)
|
||||||
_ qualifier = (*Restrict)(nil)
|
_ qualifier = (*Restrict)(nil)
|
||||||
_ qualifier = (*Volatile)(nil)
|
_ qualifier = (*Volatile)(nil)
|
||||||
|
_ qualifier = (*typeTag)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sizeof returns the size of a type in bytes.
|
// Sizeof returns the size of a type in bytes.
|
||||||
@@ -679,7 +671,7 @@ type copier map[Type]Type
|
|||||||
|
|
||||||
func (c copier) copy(typ *Type, transform Transformer) {
|
func (c copier) copy(typ *Type, transform Transformer) {
|
||||||
var work typeDeque
|
var work typeDeque
|
||||||
for t := typ; t != nil; t = work.pop() {
|
for t := typ; t != nil; t = work.Pop() {
|
||||||
// *t is the identity of the type.
|
// *t is the identity of the type.
|
||||||
if cpy := c[*t]; cpy != nil {
|
if cpy := c[*t]; cpy != nil {
|
||||||
*t = cpy
|
*t = cpy
|
||||||
@@ -697,83 +689,11 @@ func (c copier) copy(typ *Type, transform Transformer) {
|
|||||||
*t = cpy
|
*t = cpy
|
||||||
|
|
||||||
// Mark any nested types for copying.
|
// Mark any nested types for copying.
|
||||||
cpy.walk(&work)
|
walkType(cpy, work.Push)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeDeque keeps track of pointers to types which still
|
type typeDeque = internal.Deque[*Type]
|
||||||
// need to be visited.
|
|
||||||
type typeDeque struct {
|
|
||||||
types []*Type
|
|
||||||
read, write uint64
|
|
||||||
mask uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dq *typeDeque) empty() bool {
|
|
||||||
return dq.read == dq.write
|
|
||||||
}
|
|
||||||
|
|
||||||
// push adds a type to the stack.
|
|
||||||
func (dq *typeDeque) push(t *Type) {
|
|
||||||
if dq.write-dq.read < uint64(len(dq.types)) {
|
|
||||||
dq.types[dq.write&dq.mask] = t
|
|
||||||
dq.write++
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
new := len(dq.types) * 2
|
|
||||||
if new == 0 {
|
|
||||||
new = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
types := make([]*Type, new)
|
|
||||||
pivot := dq.read & dq.mask
|
|
||||||
n := copy(types, dq.types[pivot:])
|
|
||||||
n += copy(types[n:], dq.types[:pivot])
|
|
||||||
types[n] = t
|
|
||||||
|
|
||||||
dq.types = types
|
|
||||||
dq.mask = uint64(new) - 1
|
|
||||||
dq.read, dq.write = 0, uint64(n+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// shift returns the first element or null.
|
|
||||||
func (dq *typeDeque) shift() *Type {
|
|
||||||
if dq.empty() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
index := dq.read & dq.mask
|
|
||||||
t := dq.types[index]
|
|
||||||
dq.types[index] = nil
|
|
||||||
dq.read++
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// pop returns the last element or null.
|
|
||||||
func (dq *typeDeque) pop() *Type {
|
|
||||||
if dq.empty() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
dq.write--
|
|
||||||
index := dq.write & dq.mask
|
|
||||||
t := dq.types[index]
|
|
||||||
dq.types[index] = nil
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// all returns all elements.
|
|
||||||
//
|
|
||||||
// The deque is empty after calling this method.
|
|
||||||
func (dq *typeDeque) all() []*Type {
|
|
||||||
length := dq.write - dq.read
|
|
||||||
types := make([]*Type, 0, length)
|
|
||||||
for t := dq.shift(); t != nil; t = dq.shift() {
|
|
||||||
types = append(types, t)
|
|
||||||
}
|
|
||||||
return types
|
|
||||||
}
|
|
||||||
|
|
||||||
// inflateRawTypes takes a list of raw btf types linked via type IDs, and turns
|
// inflateRawTypes takes a list of raw btf types linked via type IDs, and turns
|
||||||
// it into a graph of Types connected via pointers.
|
// it into a graph of Types connected via pointers.
|
||||||
@@ -903,6 +823,7 @@ func inflateRawTypes(rawTypes []rawType, baseTypes types, rawStrings *stringTabl
|
|||||||
return members, nil
|
return members, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var declTags []*declTag
|
||||||
for i, raw := range rawTypes {
|
for i, raw := range rawTypes {
|
||||||
var (
|
var (
|
||||||
id = typeIDOffset + TypeID(i)
|
id = typeIDOffset + TypeID(i)
|
||||||
@@ -952,17 +873,20 @@ func inflateRawTypes(rawTypes []rawType, baseTypes types, rawStrings *stringTabl
|
|||||||
case kindEnum:
|
case kindEnum:
|
||||||
rawvals := raw.data.([]btfEnum)
|
rawvals := raw.data.([]btfEnum)
|
||||||
vals := make([]EnumValue, 0, len(rawvals))
|
vals := make([]EnumValue, 0, len(rawvals))
|
||||||
|
signed := raw.KindFlag()
|
||||||
for i, btfVal := range rawvals {
|
for i, btfVal := range rawvals {
|
||||||
name, err := rawStrings.Lookup(btfVal.NameOff)
|
name, err := rawStrings.Lookup(btfVal.NameOff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get name for enum value %d: %s", i, err)
|
return nil, fmt.Errorf("get name for enum value %d: %s", i, err)
|
||||||
}
|
}
|
||||||
vals = append(vals, EnumValue{
|
value := uint64(btfVal.Val)
|
||||||
Name: name,
|
if signed {
|
||||||
Value: btfVal.Val,
|
// Sign extend values to 64 bit.
|
||||||
})
|
value = uint64(int32(btfVal.Val))
|
||||||
|
}
|
||||||
|
vals = append(vals, EnumValue{name, value})
|
||||||
}
|
}
|
||||||
typ = &Enum{name, raw.Size(), vals}
|
typ = &Enum{name, raw.Size(), signed, vals}
|
||||||
|
|
||||||
case kindForward:
|
case kindForward:
|
||||||
if raw.KindFlag() {
|
if raw.KindFlag() {
|
||||||
@@ -1045,6 +969,28 @@ func inflateRawTypes(rawTypes []rawType, baseTypes types, rawStrings *stringTabl
|
|||||||
case kindFloat:
|
case kindFloat:
|
||||||
typ = &Float{name, raw.Size()}
|
typ = &Float{name, raw.Size()}
|
||||||
|
|
||||||
|
case kindDeclTag:
|
||||||
|
btfIndex := raw.data.(*btfDeclTag).ComponentIdx
|
||||||
|
if uint64(btfIndex) > math.MaxInt {
|
||||||
|
return nil, fmt.Errorf("type id %d: index exceeds int", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
index := int(btfIndex)
|
||||||
|
if btfIndex == math.MaxUint32 {
|
||||||
|
index = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
dt := &declTag{nil, name, index}
|
||||||
|
fixup(raw.Type(), &dt.Type)
|
||||||
|
typ = dt
|
||||||
|
|
||||||
|
declTags = append(declTags, dt)
|
||||||
|
|
||||||
|
case kindTypeTag:
|
||||||
|
tt := &typeTag{nil, name}
|
||||||
|
fixup(raw.Type(), &tt.Type)
|
||||||
|
typ = tt
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
|
return nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
|
||||||
}
|
}
|
||||||
@@ -1083,6 +1029,28 @@ func inflateRawTypes(rawTypes []rawType, baseTypes types, rawStrings *stringTabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, dt := range declTags {
|
||||||
|
switch t := dt.Type.(type) {
|
||||||
|
case *Var, *Typedef:
|
||||||
|
if dt.Index != -1 {
|
||||||
|
return nil, fmt.Errorf("type %s: index %d is not -1", dt, dt.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
case composite:
|
||||||
|
if dt.Index >= len(t.members()) {
|
||||||
|
return nil, fmt.Errorf("type %s: index %d exceeds members of %s", dt, dt.Index, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *Func:
|
||||||
|
if dt.Index >= len(t.Type.(*FuncProto).Params) {
|
||||||
|
return nil, fmt.Errorf("type %s: index %d exceeds params of %s", dt, dt.Index, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("type %s: decl tag for type %s is not supported", dt, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return types, nil
|
return types, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -111,8 +111,8 @@ func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error {
|
|||||||
//
|
//
|
||||||
// The constant must be defined like so in the C program:
|
// The constant must be defined like so in the C program:
|
||||||
//
|
//
|
||||||
// volatile const type foobar;
|
// volatile const type foobar;
|
||||||
// volatile const type foobar = default;
|
// volatile const type foobar = default;
|
||||||
//
|
//
|
||||||
// Replacement values must be of the same length as the C sizeof(type).
|
// Replacement values must be of the same length as the C sizeof(type).
|
||||||
// If necessary, they are marshalled according to the same rules as
|
// If necessary, they are marshalled according to the same rules as
|
||||||
@@ -198,11 +198,11 @@ func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error
|
|||||||
// The tag's value specifies the name of the program or map as
|
// The tag's value specifies the name of the program or map as
|
||||||
// found in the CollectionSpec.
|
// found in the CollectionSpec.
|
||||||
//
|
//
|
||||||
// struct {
|
// struct {
|
||||||
// Foo *ebpf.ProgramSpec `ebpf:"xdp_foo"`
|
// Foo *ebpf.ProgramSpec `ebpf:"xdp_foo"`
|
||||||
// Bar *ebpf.MapSpec `ebpf:"bar_map"`
|
// Bar *ebpf.MapSpec `ebpf:"bar_map"`
|
||||||
// Ignored int
|
// Ignored int
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Returns an error if any of the eBPF objects can't be found, or
|
// Returns an error if any of the eBPF objects can't be found, or
|
||||||
// if the same MapSpec or ProgramSpec is assigned multiple times.
|
// if the same MapSpec or ProgramSpec is assigned multiple times.
|
||||||
@@ -249,11 +249,11 @@ func (cs *CollectionSpec) Assign(to interface{}) error {
|
|||||||
// dependent resources are loaded into the kernel and populated with values if
|
// dependent resources are loaded into the kernel and populated with values if
|
||||||
// specified.
|
// specified.
|
||||||
//
|
//
|
||||||
// struct {
|
// struct {
|
||||||
// Foo *ebpf.Program `ebpf:"xdp_foo"`
|
// Foo *ebpf.Program `ebpf:"xdp_foo"`
|
||||||
// Bar *ebpf.Map `ebpf:"bar_map"`
|
// Bar *ebpf.Map `ebpf:"bar_map"`
|
||||||
// Ignored int
|
// Ignored int
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// opts may be nil.
|
// opts may be nil.
|
||||||
//
|
//
|
||||||
|
|||||||
+26
-21
@@ -261,10 +261,6 @@ func (ec *elfCode) loadRelocations(relSections map[elf.SectionIndex]*elf.Section
|
|||||||
return fmt.Errorf("section %q: reference to %q in section %s: %w", section.Name, rel.Name, rel.Section, ErrNotSupported)
|
return fmt.Errorf("section %q: reference to %q in section %s: %w", section.Name, rel.Name, rel.Section, ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
if target.Flags&elf.SHF_STRINGS > 0 {
|
|
||||||
return fmt.Errorf("section %q: string is not stack allocated: %w", section.Name, ErrNotSupported)
|
|
||||||
}
|
|
||||||
|
|
||||||
target.references++
|
target.references++
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,22 +1023,33 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := sec.Data()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if uint64(len(data)) > math.MaxUint32 {
|
|
||||||
return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
mapSpec := &MapSpec{
|
mapSpec := &MapSpec{
|
||||||
Name: SanitizeName(sec.Name, -1),
|
Name: SanitizeName(sec.Name, -1),
|
||||||
Type: Array,
|
Type: Array,
|
||||||
KeySize: 4,
|
KeySize: 4,
|
||||||
ValueSize: uint32(len(data)),
|
ValueSize: uint32(sec.Size),
|
||||||
MaxEntries: 1,
|
MaxEntries: 1,
|
||||||
Contents: []MapKV{{uint32(0), data}},
|
}
|
||||||
|
|
||||||
|
switch sec.Type {
|
||||||
|
// Only open the section if we know there's actual data to be read.
|
||||||
|
case elf.SHT_PROGBITS:
|
||||||
|
data, err := sec.Data()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint64(len(data)) > math.MaxUint32 {
|
||||||
|
return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
|
||||||
|
}
|
||||||
|
mapSpec.Contents = []MapKV{{uint32(0), data}}
|
||||||
|
|
||||||
|
case elf.SHT_NOBITS:
|
||||||
|
// NOBITS sections like .bss contain only zeroes, and since data sections
|
||||||
|
// are Arrays, the kernel already preallocates them. Skip reading zeroes
|
||||||
|
// from the ELF.
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("data section %s: unknown section type %s", sec.Name, sec.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is possible for a data section to exist without a corresponding BTF Datasec
|
// It is possible for a data section to exist without a corresponding BTF Datasec
|
||||||
@@ -1057,13 +1064,9 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n := sec.Name; {
|
if strings.HasPrefix(sec.Name, ".rodata") {
|
||||||
case strings.HasPrefix(n, ".rodata"):
|
|
||||||
mapSpec.Flags = unix.BPF_F_RDONLY_PROG
|
mapSpec.Flags = unix.BPF_F_RDONLY_PROG
|
||||||
mapSpec.Freeze = true
|
mapSpec.Freeze = true
|
||||||
case n == ".bss":
|
|
||||||
// The kernel already zero-initializes the map
|
|
||||||
mapSpec.Contents = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
maps[sec.Name] = mapSpec
|
maps[sec.Name] = mapSpec
|
||||||
@@ -1107,6 +1110,7 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
|
|||||||
{"lsm/", LSM, AttachLSMMac, 0},
|
{"lsm/", LSM, AttachLSMMac, 0},
|
||||||
{"lsm.s/", LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE},
|
{"lsm.s/", LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE},
|
||||||
{"iter/", Tracing, AttachTraceIter, 0},
|
{"iter/", Tracing, AttachTraceIter, 0},
|
||||||
|
{"iter.s/", Tracing, AttachTraceIter, unix.BPF_F_SLEEPABLE},
|
||||||
{"syscall", Syscall, AttachNone, 0},
|
{"syscall", Syscall, AttachNone, 0},
|
||||||
{"xdp_devmap/", XDP, AttachXDPDevMap, 0},
|
{"xdp_devmap/", XDP, AttachXDPDevMap, 0},
|
||||||
{"xdp_cpumap/", XDP, AttachXDPCPUMap, 0},
|
{"xdp_cpumap/", XDP, AttachXDPCPUMap, 0},
|
||||||
@@ -1149,8 +1153,9 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
|
|||||||
{"cgroup/setsockopt", CGroupSockopt, AttachCGroupSetsockopt, 0},
|
{"cgroup/setsockopt", CGroupSockopt, AttachCGroupSetsockopt, 0},
|
||||||
{"struct_ops+", StructOps, AttachNone, 0},
|
{"struct_ops+", StructOps, AttachNone, 0},
|
||||||
{"sk_lookup/", SkLookup, AttachSkLookup, 0},
|
{"sk_lookup/", SkLookup, AttachSkLookup, 0},
|
||||||
|
|
||||||
{"seccomp", SocketFilter, AttachNone, 0},
|
{"seccomp", SocketFilter, AttachNone, 0},
|
||||||
|
{"kprobe.multi", Kprobe, AttachTraceKprobeMulti, 0},
|
||||||
|
{"kretprobe.multi", Kprobe, AttachTraceKprobeMulti, 0},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range types {
|
for _, t := range types {
|
||||||
|
|||||||
+1
-1
@@ -48,7 +48,7 @@ func newMapInfoFromFd(fd *sys.FD) (*MapInfo, error) {
|
|||||||
info.KeySize,
|
info.KeySize,
|
||||||
info.ValueSize,
|
info.ValueSize,
|
||||||
info.MaxEntries,
|
info.MaxEntries,
|
||||||
info.MapFlags,
|
uint32(info.MapFlags),
|
||||||
unix.ByteSliceToString(info.Name[:]),
|
unix.ByteSliceToString(info.Name[:]),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import "math/bits"
|
||||||
|
|
||||||
|
// Deque implements a double ended queue.
|
||||||
|
type Deque[T any] struct {
|
||||||
|
elems []T
|
||||||
|
read, write uint64
|
||||||
|
mask uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dq *Deque[T]) Empty() bool {
|
||||||
|
return dq.read == dq.write
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dq *Deque[T]) remainingCap() int {
|
||||||
|
return len(dq.elems) - int(dq.write-dq.read)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push adds an element to the end.
|
||||||
|
func (dq *Deque[T]) Push(e T) {
|
||||||
|
if dq.remainingCap() >= 1 {
|
||||||
|
dq.elems[dq.write&dq.mask] = e
|
||||||
|
dq.write++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
elems := dq.linearise(1)
|
||||||
|
elems = append(elems, e)
|
||||||
|
|
||||||
|
dq.elems = elems[:cap(elems)]
|
||||||
|
dq.mask = uint64(cap(elems)) - 1
|
||||||
|
dq.read, dq.write = 0, uint64(len(elems))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift returns the first element or the zero value.
|
||||||
|
func (dq *Deque[T]) Shift() T {
|
||||||
|
var zero T
|
||||||
|
|
||||||
|
if dq.Empty() {
|
||||||
|
return zero
|
||||||
|
}
|
||||||
|
|
||||||
|
index := dq.read & dq.mask
|
||||||
|
t := dq.elems[index]
|
||||||
|
dq.elems[index] = zero
|
||||||
|
dq.read++
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop returns the last element or the zero value.
|
||||||
|
func (dq *Deque[T]) Pop() T {
|
||||||
|
var zero T
|
||||||
|
|
||||||
|
if dq.Empty() {
|
||||||
|
return zero
|
||||||
|
}
|
||||||
|
|
||||||
|
dq.write--
|
||||||
|
index := dq.write & dq.mask
|
||||||
|
t := dq.elems[index]
|
||||||
|
dq.elems[index] = zero
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// linearise the contents of the deque.
|
||||||
|
//
|
||||||
|
// The returned slice has space for at least n more elements and has power
|
||||||
|
// of two capacity.
|
||||||
|
func (dq *Deque[T]) linearise(n int) []T {
|
||||||
|
length := dq.write - dq.read
|
||||||
|
need := length + uint64(n)
|
||||||
|
if need < length {
|
||||||
|
panic("overflow")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round up to the new power of two which is at least 8.
|
||||||
|
// See https://jameshfisher.com/2018/03/30/round-up-power-2/
|
||||||
|
capacity := 1 << (64 - bits.LeadingZeros64(need-1))
|
||||||
|
if capacity < 8 {
|
||||||
|
capacity = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
types := make([]T, length, capacity)
|
||||||
|
pivot := dq.read & dq.mask
|
||||||
|
copied := copy(types, dq.elems[pivot:])
|
||||||
|
copy(types[copied:], dq.elems[:pivot])
|
||||||
|
return types
|
||||||
|
}
|
||||||
+9
-16
@@ -7,32 +7,25 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrorWithLog returns an error which includes logs from the kernel verifier.
|
// ErrorWithLog wraps err in a VerifierError that includes the parsed verifier
|
||||||
|
// log buffer.
|
||||||
//
|
//
|
||||||
// The default error output is a summary of the full log. The latter can be
|
// The default error output is a summary of the full log. The latter can be
|
||||||
// accessed via VerifierError.Log or by formatting the error, see Format.
|
// accessed via VerifierError.Log or by formatting the error, see Format.
|
||||||
//
|
func ErrorWithLog(err error, log []byte, truncated bool) *VerifierError {
|
||||||
// A set of heuristics is used to determine whether the log has been truncated.
|
|
||||||
func ErrorWithLog(err error, log []byte) *VerifierError {
|
|
||||||
const whitespace = "\t\r\v\n "
|
const whitespace = "\t\r\v\n "
|
||||||
|
|
||||||
// Convert verifier log C string by truncating it on the first 0 byte
|
// Convert verifier log C string by truncating it on the first 0 byte
|
||||||
// and trimming trailing whitespace before interpreting as a Go string.
|
// and trimming trailing whitespace before interpreting as a Go string.
|
||||||
truncated := false
|
|
||||||
if i := bytes.IndexByte(log, 0); i != -1 {
|
if i := bytes.IndexByte(log, 0); i != -1 {
|
||||||
if i == len(log)-1 && !bytes.HasSuffix(log[:i], []byte{'\n'}) {
|
|
||||||
// The null byte is at the end of the buffer and it's not preceded
|
|
||||||
// by a newline character. Most likely the buffer was too short.
|
|
||||||
truncated = true
|
|
||||||
}
|
|
||||||
|
|
||||||
log = log[:i]
|
log = log[:i]
|
||||||
} else if len(log) > 0 {
|
|
||||||
// No null byte? Dodgy!
|
|
||||||
truncated = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log = bytes.Trim(log, whitespace)
|
log = bytes.Trim(log, whitespace)
|
||||||
|
if len(log) == 0 {
|
||||||
|
return &VerifierError{err, nil, truncated}
|
||||||
|
}
|
||||||
|
|
||||||
logLines := bytes.Split(log, []byte{'\n'})
|
logLines := bytes.Split(log, []byte{'\n'})
|
||||||
lines := make([]string, 0, len(logLines))
|
lines := make([]string, 0, len(logLines))
|
||||||
for _, line := range logLines {
|
for _, line := range logLines {
|
||||||
@@ -143,8 +136,8 @@ func includePreviousLine(line string) bool {
|
|||||||
// Understood verbs are %s and %v, which are equivalent to calling Error(). %v
|
// Understood verbs are %s and %v, which are equivalent to calling Error(). %v
|
||||||
// allows outputting additional information using the following flags:
|
// allows outputting additional information using the following flags:
|
||||||
//
|
//
|
||||||
// + Output the first <width> lines, or all lines if no width is given.
|
// %+<width>v: Output the first <width> lines, or all lines if no width is given.
|
||||||
// - Output the last <width> lines, or all lines if no width is given.
|
// %-<width>v: Output the last <width> lines, or all lines if no width is given.
|
||||||
//
|
//
|
||||||
// Use width to specify how many lines to output. Use the '-' flag to output
|
// Use width to specify how many lines to output. Use the '-' flag to output
|
||||||
// lines from the end of the log instead of the beginning.
|
// lines from the end of the log instead of the beginning.
|
||||||
|
|||||||
+3
-3
@@ -42,9 +42,9 @@ type featureTest struct {
|
|||||||
//
|
//
|
||||||
// The return values have the following semantics:
|
// The return values have the following semantics:
|
||||||
//
|
//
|
||||||
// err == ErrNotSupported: the feature is not available
|
// err == ErrNotSupported: the feature is not available
|
||||||
// err == nil: the feature is available
|
// err == nil: the feature is available
|
||||||
// err != nil: the test couldn't be executed
|
// err != nil: the test couldn't be executed
|
||||||
type FeatureTestFn func() error
|
type FeatureTestFn func() error
|
||||||
|
|
||||||
// FeatureTest wraps a function so that it is run at most once.
|
// FeatureTest wraps a function so that it is run at most once.
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
// EmptyBPFContext is the smallest-possible BPF input context to be used for
|
||||||
|
// invoking `Program.{Run,Benchmark,Test}`.
|
||||||
|
//
|
||||||
|
// Programs require a context input buffer of at least 15 bytes. Looking in
|
||||||
|
// net/bpf/test_run.c, bpf_test_init() requires that the input is at least
|
||||||
|
// ETH_HLEN (14) bytes. As of Linux commit fd18942 ("bpf: Don't redirect packets
|
||||||
|
// with invalid pkt_len"), it also requires the skb to be non-empty after
|
||||||
|
// removing the Layer 2 header.
|
||||||
|
var EmptyBPFContext = make([]byte, 15)
|
||||||
+14
@@ -36,3 +36,17 @@ func NewStringPointer(str string) Pointer {
|
|||||||
|
|
||||||
return Pointer{ptr: unsafe.Pointer(p)}
|
return Pointer{ptr: unsafe.Pointer(p)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewStringSlicePointer allocates an array of Pointers to each string in the
|
||||||
|
// given slice of strings and returns a 64-bit pointer to the start of the
|
||||||
|
// resulting array.
|
||||||
|
//
|
||||||
|
// Use this function to pass arrays of strings as syscall arguments.
|
||||||
|
func NewStringSlicePointer(strings []string) Pointer {
|
||||||
|
sp := make([]Pointer, 0, len(strings))
|
||||||
|
for _, s := range strings {
|
||||||
|
sp = append(sp, NewStringPointer(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pointer{ptr: unsafe.Pointer(&sp[0])}
|
||||||
|
}
|
||||||
|
|||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var profSet unix.Sigset_t
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if err := sigsetAdd(&profSet, unix.SIGPROF); err != nil {
|
||||||
|
panic(fmt.Errorf("creating signal set: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// maskProfilerSignal locks the calling goroutine to its underlying OS thread
|
||||||
|
// and adds SIGPROF to the thread's signal mask. This prevents pprof from
|
||||||
|
// interrupting expensive syscalls like e.g. BPF_PROG_LOAD.
|
||||||
|
//
|
||||||
|
// The caller must defer sys.UnmaskProfilerSignal() to reverse the operation.
|
||||||
|
func maskProfilerSignal() {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
|
||||||
|
if err := unix.PthreadSigmask(unix.SIG_BLOCK, &profSet, nil); err != nil {
|
||||||
|
runtime.UnlockOSThread()
|
||||||
|
panic(fmt.Errorf("masking profiler signal: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmaskProfilerSignal removes SIGPROF from the underlying thread's signal
|
||||||
|
// mask, allowing it to be interrupted for profiling once again.
|
||||||
|
//
|
||||||
|
// It also unlocks the current goroutine from its underlying OS thread.
|
||||||
|
func unmaskProfilerSignal() {
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
if err := unix.PthreadSigmask(unix.SIG_UNBLOCK, &profSet, nil); err != nil {
|
||||||
|
panic(fmt.Errorf("unmasking profiler signal: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
wordBytes = int(unsafe.Sizeof(unix.Sigset_t{}.Val[0]))
|
||||||
|
wordBits = wordBytes * 8
|
||||||
|
|
||||||
|
setBytes = int(unsafe.Sizeof(unix.Sigset_t{}))
|
||||||
|
setBits = setBytes * 8
|
||||||
|
)
|
||||||
|
|
||||||
|
// sigsetAdd adds signal to set.
|
||||||
|
//
|
||||||
|
// Note: Sigset_t.Val's value type is uint32 or uint64 depending on the arch.
|
||||||
|
// This function must be able to deal with both and so must avoid any direct
|
||||||
|
// references to u32 or u64 types.
|
||||||
|
func sigsetAdd(set *unix.Sigset_t, signal unix.Signal) error {
|
||||||
|
if signal < 1 {
|
||||||
|
return fmt.Errorf("signal %d must be larger than 0", signal)
|
||||||
|
}
|
||||||
|
if int(signal) > setBits {
|
||||||
|
return fmt.Errorf("signal %d does not fit within unix.Sigset_t", signal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For amd64, runtime.sigaddset() performs the following operation:
|
||||||
|
// set[(signal-1)/32] |= 1 << ((uint32(signal) - 1) & 31)
|
||||||
|
//
|
||||||
|
// This trick depends on sigset being two u32's, causing a signal in the the
|
||||||
|
// bottom 31 bits to be written to the low word if bit 32 is low, or the high
|
||||||
|
// word if bit 32 is high.
|
||||||
|
|
||||||
|
// Signal is the nth bit in the bitfield.
|
||||||
|
bit := int(signal - 1)
|
||||||
|
// Word within the sigset the bit needs to be written to.
|
||||||
|
word := bit / wordBits
|
||||||
|
|
||||||
|
// Write the signal bit into its corresponding word at the corrected offset.
|
||||||
|
set.Val[word] |= 1 << (bit % wordBits)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+35
-4
@@ -8,10 +8,22 @@ import (
|
|||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ENOTSUPP is a Linux internal error code that has leaked into UAPI.
|
||||||
|
//
|
||||||
|
// It is not the same as ENOTSUP or EOPNOTSUPP.
|
||||||
|
var ENOTSUPP = syscall.Errno(524)
|
||||||
|
|
||||||
// BPF wraps SYS_BPF.
|
// BPF wraps SYS_BPF.
|
||||||
//
|
//
|
||||||
// Any pointers contained in attr must use the Pointer type from this package.
|
// Any pointers contained in attr must use the Pointer type from this package.
|
||||||
func BPF(cmd Cmd, attr unsafe.Pointer, size uintptr) (uintptr, error) {
|
func BPF(cmd Cmd, attr unsafe.Pointer, size uintptr) (uintptr, error) {
|
||||||
|
// Prevent the Go profiler from repeatedly interrupting the verifier,
|
||||||
|
// which could otherwise lead to a livelock due to receiving EAGAIN.
|
||||||
|
if cmd == BPF_PROG_LOAD {
|
||||||
|
maskProfilerSignal()
|
||||||
|
defer unmaskProfilerSignal()
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size)
|
r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size)
|
||||||
runtime.KeepAlive(attr)
|
runtime.KeepAlive(attr)
|
||||||
@@ -33,10 +45,10 @@ func BPF(cmd Cmd, attr unsafe.Pointer, size uintptr) (uintptr, error) {
|
|||||||
|
|
||||||
// Info is implemented by all structs that can be passed to the ObjInfo syscall.
|
// Info is implemented by all structs that can be passed to the ObjInfo syscall.
|
||||||
//
|
//
|
||||||
// MapInfo
|
// MapInfo
|
||||||
// ProgInfo
|
// ProgInfo
|
||||||
// LinkInfo
|
// LinkInfo
|
||||||
// BtfInfo
|
// BtfInfo
|
||||||
type Info interface {
|
type Info interface {
|
||||||
info() (unsafe.Pointer, uint32)
|
info() (unsafe.Pointer, uint32)
|
||||||
}
|
}
|
||||||
@@ -90,12 +102,24 @@ func NewObjName(name string) ObjName {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogLevel controls the verbosity of the kernel's eBPF program verifier.
|
||||||
|
type LogLevel uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
BPF_LOG_LEVEL1 LogLevel = 1 << iota
|
||||||
|
BPF_LOG_LEVEL2
|
||||||
|
BPF_LOG_STATS
|
||||||
|
)
|
||||||
|
|
||||||
// LinkID uniquely identifies a bpf_link.
|
// LinkID uniquely identifies a bpf_link.
|
||||||
type LinkID uint32
|
type LinkID uint32
|
||||||
|
|
||||||
// BTFID uniquely identifies a BTF blob loaded into the kernel.
|
// BTFID uniquely identifies a BTF blob loaded into the kernel.
|
||||||
type BTFID uint32
|
type BTFID uint32
|
||||||
|
|
||||||
|
// MapFlags control map behaviour.
|
||||||
|
type MapFlags uint32
|
||||||
|
|
||||||
// wrappedErrno wraps syscall.Errno to prevent direct comparisons with
|
// wrappedErrno wraps syscall.Errno to prevent direct comparisons with
|
||||||
// syscall.E* or unix.E* constants.
|
// syscall.E* or unix.E* constants.
|
||||||
//
|
//
|
||||||
@@ -108,6 +132,13 @@ func (we wrappedErrno) Unwrap() error {
|
|||||||
return we.Errno
|
return we.Errno
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (we wrappedErrno) Error() string {
|
||||||
|
if we.Errno == ENOTSUPP {
|
||||||
|
return "operation not supported"
|
||||||
|
}
|
||||||
|
return we.Errno.Error()
|
||||||
|
}
|
||||||
|
|
||||||
type syscallError struct {
|
type syscallError struct {
|
||||||
error
|
error
|
||||||
errno syscall.Errno
|
errno syscall.Errno
|
||||||
|
|||||||
+37
-17
@@ -6,14 +6,14 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AdjRoomMode int32
|
type AdjRoomMode uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_ADJ_ROOM_NET AdjRoomMode = 0
|
BPF_ADJ_ROOM_NET AdjRoomMode = 0
|
||||||
BPF_ADJ_ROOM_MAC AdjRoomMode = 1
|
BPF_ADJ_ROOM_MAC AdjRoomMode = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
type AttachType int32
|
type AttachType uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_CGROUP_INET_INGRESS AttachType = 0
|
BPF_CGROUP_INET_INGRESS AttachType = 0
|
||||||
@@ -62,7 +62,7 @@ const (
|
|||||||
__MAX_BPF_ATTACH_TYPE AttachType = 43
|
__MAX_BPF_ATTACH_TYPE AttachType = 43
|
||||||
)
|
)
|
||||||
|
|
||||||
type Cmd int32
|
type Cmd uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_MAP_CREATE Cmd = 0
|
BPF_MAP_CREATE Cmd = 0
|
||||||
@@ -104,7 +104,7 @@ const (
|
|||||||
BPF_PROG_BIND_MAP Cmd = 35
|
BPF_PROG_BIND_MAP Cmd = 35
|
||||||
)
|
)
|
||||||
|
|
||||||
type FunctionId int32
|
type FunctionId uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_FUNC_unspec FunctionId = 0
|
BPF_FUNC_unspec FunctionId = 0
|
||||||
@@ -304,14 +304,14 @@ const (
|
|||||||
__BPF_FUNC_MAX_ID FunctionId = 194
|
__BPF_FUNC_MAX_ID FunctionId = 194
|
||||||
)
|
)
|
||||||
|
|
||||||
type HdrStartOff int32
|
type HdrStartOff uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_HDR_START_MAC HdrStartOff = 0
|
BPF_HDR_START_MAC HdrStartOff = 0
|
||||||
BPF_HDR_START_NET HdrStartOff = 1
|
BPF_HDR_START_NET HdrStartOff = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
type LinkType int32
|
type LinkType uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_LINK_TYPE_UNSPEC LinkType = 0
|
BPF_LINK_TYPE_UNSPEC LinkType = 0
|
||||||
@@ -326,7 +326,7 @@ const (
|
|||||||
MAX_BPF_LINK_TYPE LinkType = 9
|
MAX_BPF_LINK_TYPE LinkType = 9
|
||||||
)
|
)
|
||||||
|
|
||||||
type MapType int32
|
type MapType uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_MAP_TYPE_UNSPEC MapType = 0
|
BPF_MAP_TYPE_UNSPEC MapType = 0
|
||||||
@@ -362,7 +362,7 @@ const (
|
|||||||
BPF_MAP_TYPE_BLOOM_FILTER MapType = 30
|
BPF_MAP_TYPE_BLOOM_FILTER MapType = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProgType int32
|
type ProgType uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_PROG_TYPE_UNSPEC ProgType = 0
|
BPF_PROG_TYPE_UNSPEC ProgType = 0
|
||||||
@@ -399,7 +399,7 @@ const (
|
|||||||
BPF_PROG_TYPE_SYSCALL ProgType = 31
|
BPF_PROG_TYPE_SYSCALL ProgType = 31
|
||||||
)
|
)
|
||||||
|
|
||||||
type RetCode int32
|
type RetCode uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_OK RetCode = 0
|
BPF_OK RetCode = 0
|
||||||
@@ -408,14 +408,14 @@ const (
|
|||||||
BPF_LWT_REROUTE RetCode = 128
|
BPF_LWT_REROUTE RetCode = 128
|
||||||
)
|
)
|
||||||
|
|
||||||
type SkAction int32
|
type SkAction uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SK_DROP SkAction = 0
|
SK_DROP SkAction = 0
|
||||||
SK_PASS SkAction = 1
|
SK_PASS SkAction = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
type StackBuildIdStatus int32
|
type StackBuildIdStatus uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_STACK_BUILD_ID_EMPTY StackBuildIdStatus = 0
|
BPF_STACK_BUILD_ID_EMPTY StackBuildIdStatus = 0
|
||||||
@@ -423,13 +423,13 @@ const (
|
|||||||
BPF_STACK_BUILD_ID_IP StackBuildIdStatus = 2
|
BPF_STACK_BUILD_ID_IP StackBuildIdStatus = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
type StatsType int32
|
type StatsType uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BPF_STATS_RUN_TIME StatsType = 0
|
BPF_STATS_RUN_TIME StatsType = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
type XdpAction int32
|
type XdpAction uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
XDP_ABORTED XdpAction = 0
|
XDP_ABORTED XdpAction = 0
|
||||||
@@ -474,7 +474,7 @@ type MapInfo struct {
|
|||||||
KeySize uint32
|
KeySize uint32
|
||||||
ValueSize uint32
|
ValueSize uint32
|
||||||
MaxEntries uint32
|
MaxEntries uint32
|
||||||
MapFlags uint32
|
MapFlags MapFlags
|
||||||
Name ObjName
|
Name ObjName
|
||||||
Ifindex uint32
|
Ifindex uint32
|
||||||
BtfVmlinuxValueTypeId uint32
|
BtfVmlinuxValueTypeId uint32
|
||||||
@@ -646,6 +646,26 @@ func LinkCreateIter(attr *LinkCreateIterAttr) (*FD, error) {
|
|||||||
return NewFD(int(fd))
|
return NewFD(int(fd))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LinkCreateKprobeMultiAttr struct {
|
||||||
|
ProgFd uint32
|
||||||
|
TargetFd uint32
|
||||||
|
AttachType AttachType
|
||||||
|
Flags uint32
|
||||||
|
KprobeMultiFlags uint32
|
||||||
|
Count uint32
|
||||||
|
Syms Pointer
|
||||||
|
Addrs Pointer
|
||||||
|
Cookies Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func LinkCreateKprobeMulti(attr *LinkCreateKprobeMultiAttr) (*FD, error) {
|
||||||
|
fd, err := BPF(BPF_LINK_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewFD(int(fd))
|
||||||
|
}
|
||||||
|
|
||||||
type LinkCreatePerfEventAttr struct {
|
type LinkCreatePerfEventAttr struct {
|
||||||
ProgFd uint32
|
ProgFd uint32
|
||||||
TargetFd uint32
|
TargetFd uint32
|
||||||
@@ -680,7 +700,7 @@ type MapCreateAttr struct {
|
|||||||
KeySize uint32
|
KeySize uint32
|
||||||
ValueSize uint32
|
ValueSize uint32
|
||||||
MaxEntries uint32
|
MaxEntries uint32
|
||||||
MapFlags uint32
|
MapFlags MapFlags
|
||||||
InnerMapFd uint32
|
InnerMapFd uint32
|
||||||
NumaNode uint32
|
NumaNode uint32
|
||||||
MapName ObjName
|
MapName ObjName
|
||||||
@@ -951,7 +971,7 @@ type ProgLoadAttr struct {
|
|||||||
InsnCnt uint32
|
InsnCnt uint32
|
||||||
Insns Pointer
|
Insns Pointer
|
||||||
License Pointer
|
License Pointer
|
||||||
LogLevel uint32
|
LogLevel LogLevel
|
||||||
LogSize uint32
|
LogSize uint32
|
||||||
LogBuf Pointer
|
LogBuf Pointer
|
||||||
KernVersion uint32
|
KernVersion uint32
|
||||||
@@ -967,7 +987,7 @@ type ProgLoadAttr struct {
|
|||||||
LineInfo Pointer
|
LineInfo Pointer
|
||||||
LineInfoCnt uint32
|
LineInfoCnt uint32
|
||||||
AttachBtfId uint32
|
AttachBtfId uint32
|
||||||
AttachProgFd uint32
|
AttachBtfObjFd uint32
|
||||||
CoreReloCnt uint32
|
CoreReloCnt uint32
|
||||||
FdArray Pointer
|
FdArray Pointer
|
||||||
CoreRelos Pointer
|
CoreRelos Pointer
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// Package unix re-exports Linux specific parts of golang.org/x/sys/unix.
|
||||||
|
//
|
||||||
|
// It avoids breaking compilation on other OS by providing stubs as follows:
|
||||||
|
// - Invoking a function always returns an error.
|
||||||
|
// - Errnos have distinct, non-zero values.
|
||||||
|
// - Constants have distinct but meaningless values.
|
||||||
|
// - Types use the same names for members, but may or may not follow the
|
||||||
|
// Linux layout.
|
||||||
|
package unix
|
||||||
|
|
||||||
|
// Note: please don't add any custom API to this package. Use internal/sys instead.
|
||||||
+61
-84
@@ -1,5 +1,4 @@
|
|||||||
//go:build linux
|
//go:build linux
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
@@ -24,175 +23,153 @@ const (
|
|||||||
E2BIG = linux.E2BIG
|
E2BIG = linux.E2BIG
|
||||||
EFAULT = linux.EFAULT
|
EFAULT = linux.EFAULT
|
||||||
EACCES = linux.EACCES
|
EACCES = linux.EACCES
|
||||||
// ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP
|
EILSEQ = linux.EILSEQ
|
||||||
ENOTSUPP = syscall.Errno(0x20c)
|
)
|
||||||
|
|
||||||
BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC
|
const (
|
||||||
BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE
|
BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC
|
||||||
BPF_F_RDONLY = linux.BPF_F_RDONLY
|
BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE
|
||||||
BPF_F_WRONLY = linux.BPF_F_WRONLY
|
BPF_F_RDONLY = linux.BPF_F_RDONLY
|
||||||
BPF_F_RDONLY_PROG = linux.BPF_F_RDONLY_PROG
|
BPF_F_WRONLY = linux.BPF_F_WRONLY
|
||||||
BPF_F_WRONLY_PROG = linux.BPF_F_WRONLY_PROG
|
BPF_F_RDONLY_PROG = linux.BPF_F_RDONLY_PROG
|
||||||
BPF_F_SLEEPABLE = linux.BPF_F_SLEEPABLE
|
BPF_F_WRONLY_PROG = linux.BPF_F_WRONLY_PROG
|
||||||
BPF_F_MMAPABLE = linux.BPF_F_MMAPABLE
|
BPF_F_SLEEPABLE = linux.BPF_F_SLEEPABLE
|
||||||
BPF_F_INNER_MAP = linux.BPF_F_INNER_MAP
|
BPF_F_MMAPABLE = linux.BPF_F_MMAPABLE
|
||||||
BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN
|
BPF_F_INNER_MAP = linux.BPF_F_INNER_MAP
|
||||||
BPF_TAG_SIZE = linux.BPF_TAG_SIZE
|
BPF_F_KPROBE_MULTI_RETURN = linux.BPF_F_KPROBE_MULTI_RETURN
|
||||||
BPF_RINGBUF_BUSY_BIT = linux.BPF_RINGBUF_BUSY_BIT
|
BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN
|
||||||
BPF_RINGBUF_DISCARD_BIT = linux.BPF_RINGBUF_DISCARD_BIT
|
BPF_TAG_SIZE = linux.BPF_TAG_SIZE
|
||||||
BPF_RINGBUF_HDR_SZ = linux.BPF_RINGBUF_HDR_SZ
|
BPF_RINGBUF_BUSY_BIT = linux.BPF_RINGBUF_BUSY_BIT
|
||||||
SYS_BPF = linux.SYS_BPF
|
BPF_RINGBUF_DISCARD_BIT = linux.BPF_RINGBUF_DISCARD_BIT
|
||||||
F_DUPFD_CLOEXEC = linux.F_DUPFD_CLOEXEC
|
BPF_RINGBUF_HDR_SZ = linux.BPF_RINGBUF_HDR_SZ
|
||||||
EPOLL_CTL_ADD = linux.EPOLL_CTL_ADD
|
SYS_BPF = linux.SYS_BPF
|
||||||
EPOLL_CLOEXEC = linux.EPOLL_CLOEXEC
|
F_DUPFD_CLOEXEC = linux.F_DUPFD_CLOEXEC
|
||||||
O_CLOEXEC = linux.O_CLOEXEC
|
EPOLL_CTL_ADD = linux.EPOLL_CTL_ADD
|
||||||
O_NONBLOCK = linux.O_NONBLOCK
|
EPOLL_CLOEXEC = linux.EPOLL_CLOEXEC
|
||||||
PROT_READ = linux.PROT_READ
|
O_CLOEXEC = linux.O_CLOEXEC
|
||||||
PROT_WRITE = linux.PROT_WRITE
|
O_NONBLOCK = linux.O_NONBLOCK
|
||||||
MAP_SHARED = linux.MAP_SHARED
|
PROT_READ = linux.PROT_READ
|
||||||
PERF_ATTR_SIZE_VER1 = linux.PERF_ATTR_SIZE_VER1
|
PROT_WRITE = linux.PROT_WRITE
|
||||||
PERF_TYPE_SOFTWARE = linux.PERF_TYPE_SOFTWARE
|
MAP_SHARED = linux.MAP_SHARED
|
||||||
PERF_TYPE_TRACEPOINT = linux.PERF_TYPE_TRACEPOINT
|
PERF_ATTR_SIZE_VER1 = linux.PERF_ATTR_SIZE_VER1
|
||||||
PERF_COUNT_SW_BPF_OUTPUT = linux.PERF_COUNT_SW_BPF_OUTPUT
|
PERF_TYPE_SOFTWARE = linux.PERF_TYPE_SOFTWARE
|
||||||
PERF_EVENT_IOC_DISABLE = linux.PERF_EVENT_IOC_DISABLE
|
PERF_TYPE_TRACEPOINT = linux.PERF_TYPE_TRACEPOINT
|
||||||
PERF_EVENT_IOC_ENABLE = linux.PERF_EVENT_IOC_ENABLE
|
PERF_COUNT_SW_BPF_OUTPUT = linux.PERF_COUNT_SW_BPF_OUTPUT
|
||||||
PERF_EVENT_IOC_SET_BPF = linux.PERF_EVENT_IOC_SET_BPF
|
PERF_EVENT_IOC_DISABLE = linux.PERF_EVENT_IOC_DISABLE
|
||||||
PerfBitWatermark = linux.PerfBitWatermark
|
PERF_EVENT_IOC_ENABLE = linux.PERF_EVENT_IOC_ENABLE
|
||||||
PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW
|
PERF_EVENT_IOC_SET_BPF = linux.PERF_EVENT_IOC_SET_BPF
|
||||||
PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC
|
PerfBitWatermark = linux.PerfBitWatermark
|
||||||
RLIM_INFINITY = linux.RLIM_INFINITY
|
PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW
|
||||||
RLIMIT_MEMLOCK = linux.RLIMIT_MEMLOCK
|
PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC
|
||||||
BPF_STATS_RUN_TIME = linux.BPF_STATS_RUN_TIME
|
RLIM_INFINITY = linux.RLIM_INFINITY
|
||||||
PERF_RECORD_LOST = linux.PERF_RECORD_LOST
|
RLIMIT_MEMLOCK = linux.RLIMIT_MEMLOCK
|
||||||
PERF_RECORD_SAMPLE = linux.PERF_RECORD_SAMPLE
|
BPF_STATS_RUN_TIME = linux.BPF_STATS_RUN_TIME
|
||||||
AT_FDCWD = linux.AT_FDCWD
|
PERF_RECORD_LOST = linux.PERF_RECORD_LOST
|
||||||
RENAME_NOREPLACE = linux.RENAME_NOREPLACE
|
PERF_RECORD_SAMPLE = linux.PERF_RECORD_SAMPLE
|
||||||
SO_ATTACH_BPF = linux.SO_ATTACH_BPF
|
AT_FDCWD = linux.AT_FDCWD
|
||||||
SO_DETACH_BPF = linux.SO_DETACH_BPF
|
RENAME_NOREPLACE = linux.RENAME_NOREPLACE
|
||||||
SOL_SOCKET = linux.SOL_SOCKET
|
SO_ATTACH_BPF = linux.SO_ATTACH_BPF
|
||||||
|
SO_DETACH_BPF = linux.SO_DETACH_BPF
|
||||||
|
SOL_SOCKET = linux.SOL_SOCKET
|
||||||
|
SIGPROF = linux.SIGPROF
|
||||||
|
SIG_BLOCK = linux.SIG_BLOCK
|
||||||
|
SIG_UNBLOCK = linux.SIG_UNBLOCK
|
||||||
)
|
)
|
||||||
|
|
||||||
// Statfs_t is a wrapper
|
|
||||||
type Statfs_t = linux.Statfs_t
|
type Statfs_t = linux.Statfs_t
|
||||||
|
|
||||||
type Stat_t = linux.Stat_t
|
type Stat_t = linux.Stat_t
|
||||||
|
|
||||||
// Rlimit is a wrapper
|
|
||||||
type Rlimit = linux.Rlimit
|
type Rlimit = linux.Rlimit
|
||||||
|
type Signal = linux.Signal
|
||||||
|
type Sigset_t = linux.Sigset_t
|
||||||
|
type PerfEventMmapPage = linux.PerfEventMmapPage
|
||||||
|
type EpollEvent = linux.EpollEvent
|
||||||
|
type PerfEventAttr = linux.PerfEventAttr
|
||||||
|
type Utsname = linux.Utsname
|
||||||
|
|
||||||
// Syscall is a wrapper
|
|
||||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||||
return linux.Syscall(trap, a1, a2, a3)
|
return linux.Syscall(trap, a1, a2, a3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FcntlInt is a wrapper
|
func PthreadSigmask(how int, set, oldset *Sigset_t) error {
|
||||||
|
return linux.PthreadSigmask(how, set, oldset)
|
||||||
|
}
|
||||||
|
|
||||||
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
||||||
return linux.FcntlInt(fd, cmd, arg)
|
return linux.FcntlInt(fd, cmd, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IoctlSetInt is a wrapper
|
|
||||||
func IoctlSetInt(fd int, req uint, value int) error {
|
func IoctlSetInt(fd int, req uint, value int) error {
|
||||||
return linux.IoctlSetInt(fd, req, value)
|
return linux.IoctlSetInt(fd, req, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statfs is a wrapper
|
|
||||||
func Statfs(path string, buf *Statfs_t) (err error) {
|
func Statfs(path string, buf *Statfs_t) (err error) {
|
||||||
return linux.Statfs(path, buf)
|
return linux.Statfs(path, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close is a wrapper
|
|
||||||
func Close(fd int) (err error) {
|
func Close(fd int) (err error) {
|
||||||
return linux.Close(fd)
|
return linux.Close(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EpollEvent is a wrapper
|
|
||||||
type EpollEvent = linux.EpollEvent
|
|
||||||
|
|
||||||
// EpollWait is a wrapper
|
|
||||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||||
return linux.EpollWait(epfd, events, msec)
|
return linux.EpollWait(epfd, events, msec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EpollCtl is a wrapper
|
|
||||||
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
|
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
|
||||||
return linux.EpollCtl(epfd, op, fd, event)
|
return linux.EpollCtl(epfd, op, fd, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eventfd is a wrapper
|
|
||||||
func Eventfd(initval uint, flags int) (fd int, err error) {
|
func Eventfd(initval uint, flags int) (fd int, err error) {
|
||||||
return linux.Eventfd(initval, flags)
|
return linux.Eventfd(initval, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write is a wrapper
|
|
||||||
func Write(fd int, p []byte) (n int, err error) {
|
func Write(fd int, p []byte) (n int, err error) {
|
||||||
return linux.Write(fd, p)
|
return linux.Write(fd, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EpollCreate1 is a wrapper
|
|
||||||
func EpollCreate1(flag int) (fd int, err error) {
|
func EpollCreate1(flag int) (fd int, err error) {
|
||||||
return linux.EpollCreate1(flag)
|
return linux.EpollCreate1(flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PerfEventMmapPage is a wrapper
|
|
||||||
type PerfEventMmapPage linux.PerfEventMmapPage
|
|
||||||
|
|
||||||
// SetNonblock is a wrapper
|
|
||||||
func SetNonblock(fd int, nonblocking bool) (err error) {
|
func SetNonblock(fd int, nonblocking bool) (err error) {
|
||||||
return linux.SetNonblock(fd, nonblocking)
|
return linux.SetNonblock(fd, nonblocking)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mmap is a wrapper
|
|
||||||
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
|
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
|
||||||
return linux.Mmap(fd, offset, length, prot, flags)
|
return linux.Mmap(fd, offset, length, prot, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Munmap is a wrapper
|
|
||||||
func Munmap(b []byte) (err error) {
|
func Munmap(b []byte) (err error) {
|
||||||
return linux.Munmap(b)
|
return linux.Munmap(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PerfEventAttr is a wrapper
|
|
||||||
type PerfEventAttr = linux.PerfEventAttr
|
|
||||||
|
|
||||||
// PerfEventOpen is a wrapper
|
|
||||||
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
||||||
return linux.PerfEventOpen(attr, pid, cpu, groupFd, flags)
|
return linux.PerfEventOpen(attr, pid, cpu, groupFd, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utsname is a wrapper
|
|
||||||
type Utsname = linux.Utsname
|
|
||||||
|
|
||||||
// Uname is a wrapper
|
|
||||||
func Uname(buf *Utsname) (err error) {
|
func Uname(buf *Utsname) (err error) {
|
||||||
return linux.Uname(buf)
|
return linux.Uname(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getpid is a wrapper
|
|
||||||
func Getpid() int {
|
func Getpid() int {
|
||||||
return linux.Getpid()
|
return linux.Getpid()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gettid is a wrapper
|
|
||||||
func Gettid() int {
|
func Gettid() int {
|
||||||
return linux.Gettid()
|
return linux.Gettid()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tgkill is a wrapper
|
|
||||||
func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
||||||
return linux.Tgkill(tgid, tid, sig)
|
return linux.Tgkill(tgid, tid, sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BytePtrFromString is a wrapper
|
|
||||||
func BytePtrFromString(s string) (*byte, error) {
|
func BytePtrFromString(s string) (*byte, error) {
|
||||||
return linux.BytePtrFromString(s)
|
return linux.BytePtrFromString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByteSliceToString is a wrapper
|
|
||||||
func ByteSliceToString(s []byte) string {
|
func ByteSliceToString(s []byte) string {
|
||||||
return linux.ByteSliceToString(s)
|
return linux.ByteSliceToString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renameat2 is a wrapper
|
|
||||||
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
|
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
|
||||||
return linux.Renameat2(olddirfd, oldpath, newdirfd, newpath, flags)
|
return linux.Renameat2(olddirfd, oldpath, newdirfd, newpath, flags)
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-90
@@ -1,5 +1,4 @@
|
|||||||
//go:build !linux
|
//go:build !linux
|
||||||
// +build !linux
|
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
@@ -11,70 +10,76 @@ import (
|
|||||||
|
|
||||||
var errNonLinux = fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH)
|
var errNonLinux = fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
|
|
||||||
|
// Errnos are distinct and non-zero.
|
||||||
const (
|
const (
|
||||||
ENOENT = syscall.ENOENT
|
ENOENT syscall.Errno = iota + 1
|
||||||
EEXIST = syscall.EEXIST
|
EEXIST
|
||||||
EAGAIN = syscall.EAGAIN
|
EAGAIN
|
||||||
ENOSPC = syscall.ENOSPC
|
ENOSPC
|
||||||
EINVAL = syscall.EINVAL
|
EINVAL
|
||||||
EINTR = syscall.EINTR
|
EINTR
|
||||||
EPERM = syscall.EPERM
|
EPERM
|
||||||
ESRCH = syscall.ESRCH
|
ESRCH
|
||||||
ENODEV = syscall.ENODEV
|
ENODEV
|
||||||
EBADF = syscall.Errno(0)
|
EBADF
|
||||||
E2BIG = syscall.Errno(0)
|
E2BIG
|
||||||
EFAULT = syscall.EFAULT
|
EFAULT
|
||||||
EACCES = syscall.Errno(0)
|
EACCES
|
||||||
// ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP
|
EILSEQ
|
||||||
ENOTSUPP = syscall.Errno(0x20c)
|
)
|
||||||
|
|
||||||
BPF_F_NO_PREALLOC = 0
|
// Constants are distinct to avoid breaking switch statements.
|
||||||
BPF_F_NUMA_NODE = 0
|
const (
|
||||||
BPF_F_RDONLY = 0
|
BPF_F_NO_PREALLOC = iota
|
||||||
BPF_F_WRONLY = 0
|
BPF_F_NUMA_NODE
|
||||||
BPF_F_RDONLY_PROG = 0
|
BPF_F_RDONLY
|
||||||
BPF_F_WRONLY_PROG = 0
|
BPF_F_WRONLY
|
||||||
BPF_F_SLEEPABLE = 0
|
BPF_F_RDONLY_PROG
|
||||||
BPF_F_MMAPABLE = 0
|
BPF_F_WRONLY_PROG
|
||||||
BPF_F_INNER_MAP = 0
|
BPF_F_SLEEPABLE
|
||||||
BPF_OBJ_NAME_LEN = 0x10
|
BPF_F_MMAPABLE
|
||||||
BPF_TAG_SIZE = 0x8
|
BPF_F_INNER_MAP
|
||||||
BPF_RINGBUF_BUSY_BIT = 0
|
BPF_F_KPROBE_MULTI_RETURN
|
||||||
BPF_RINGBUF_DISCARD_BIT = 0
|
BPF_OBJ_NAME_LEN
|
||||||
BPF_RINGBUF_HDR_SZ = 0
|
BPF_TAG_SIZE
|
||||||
SYS_BPF = 321
|
BPF_RINGBUF_BUSY_BIT
|
||||||
F_DUPFD_CLOEXEC = 0x406
|
BPF_RINGBUF_DISCARD_BIT
|
||||||
EPOLLIN = 0x1
|
BPF_RINGBUF_HDR_SZ
|
||||||
EPOLL_CTL_ADD = 0x1
|
SYS_BPF
|
||||||
EPOLL_CLOEXEC = 0x80000
|
F_DUPFD_CLOEXEC
|
||||||
O_CLOEXEC = 0x80000
|
EPOLLIN
|
||||||
O_NONBLOCK = 0x800
|
EPOLL_CTL_ADD
|
||||||
PROT_READ = 0x1
|
EPOLL_CLOEXEC
|
||||||
PROT_WRITE = 0x2
|
O_CLOEXEC
|
||||||
MAP_SHARED = 0x1
|
O_NONBLOCK
|
||||||
PERF_ATTR_SIZE_VER1 = 0
|
PROT_READ
|
||||||
PERF_TYPE_SOFTWARE = 0x1
|
PROT_WRITE
|
||||||
PERF_TYPE_TRACEPOINT = 0
|
MAP_SHARED
|
||||||
PERF_COUNT_SW_BPF_OUTPUT = 0xa
|
PERF_ATTR_SIZE_VER1
|
||||||
PERF_EVENT_IOC_DISABLE = 0
|
PERF_TYPE_SOFTWARE
|
||||||
PERF_EVENT_IOC_ENABLE = 0
|
PERF_TYPE_TRACEPOINT
|
||||||
PERF_EVENT_IOC_SET_BPF = 0
|
PERF_COUNT_SW_BPF_OUTPUT
|
||||||
PerfBitWatermark = 0x4000
|
PERF_EVENT_IOC_DISABLE
|
||||||
PERF_SAMPLE_RAW = 0x400
|
PERF_EVENT_IOC_ENABLE
|
||||||
PERF_FLAG_FD_CLOEXEC = 0x8
|
PERF_EVENT_IOC_SET_BPF
|
||||||
RLIM_INFINITY = 0x7fffffffffffffff
|
PerfBitWatermark
|
||||||
RLIMIT_MEMLOCK = 8
|
PERF_SAMPLE_RAW
|
||||||
BPF_STATS_RUN_TIME = 0
|
PERF_FLAG_FD_CLOEXEC
|
||||||
PERF_RECORD_LOST = 2
|
RLIM_INFINITY
|
||||||
PERF_RECORD_SAMPLE = 9
|
RLIMIT_MEMLOCK
|
||||||
AT_FDCWD = -0x2
|
BPF_STATS_RUN_TIME
|
||||||
RENAME_NOREPLACE = 0x1
|
PERF_RECORD_LOST
|
||||||
SO_ATTACH_BPF = 0x32
|
PERF_RECORD_SAMPLE
|
||||||
SO_DETACH_BPF = 0x1b
|
AT_FDCWD
|
||||||
SOL_SOCKET = 0x1
|
RENAME_NOREPLACE
|
||||||
|
SO_ATTACH_BPF
|
||||||
|
SO_DETACH_BPF
|
||||||
|
SOL_SOCKET
|
||||||
|
SIGPROF
|
||||||
|
SIG_BLOCK
|
||||||
|
SIG_UNBLOCK
|
||||||
)
|
)
|
||||||
|
|
||||||
// Statfs_t is a wrapper
|
|
||||||
type Statfs_t struct {
|
type Statfs_t struct {
|
||||||
Type int64
|
Type int64
|
||||||
Bsize int64
|
Bsize int64
|
||||||
@@ -92,70 +97,67 @@ type Statfs_t struct {
|
|||||||
|
|
||||||
type Stat_t struct{}
|
type Stat_t struct{}
|
||||||
|
|
||||||
// Rlimit is a wrapper
|
|
||||||
type Rlimit struct {
|
type Rlimit struct {
|
||||||
Cur uint64
|
Cur uint64
|
||||||
Max uint64
|
Max uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Syscall is a wrapper
|
type Signal int
|
||||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
|
||||||
return 0, 0, syscall.Errno(1)
|
type Sigset_t struct {
|
||||||
|
Val [4]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||||
|
return 0, 0, syscall.ENOTSUP
|
||||||
|
}
|
||||||
|
|
||||||
|
func PthreadSigmask(how int, set, oldset *Sigset_t) error {
|
||||||
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// FcntlInt is a wrapper
|
|
||||||
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
||||||
return -1, errNonLinux
|
return -1, errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// IoctlSetInt is a wrapper
|
|
||||||
func IoctlSetInt(fd int, req uint, value int) error {
|
func IoctlSetInt(fd int, req uint, value int) error {
|
||||||
return errNonLinux
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statfs is a wrapper
|
|
||||||
func Statfs(path string, buf *Statfs_t) error {
|
func Statfs(path string, buf *Statfs_t) error {
|
||||||
return errNonLinux
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close is a wrapper
|
|
||||||
func Close(fd int) (err error) {
|
func Close(fd int) (err error) {
|
||||||
return errNonLinux
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// EpollEvent is a wrapper
|
|
||||||
type EpollEvent struct {
|
type EpollEvent struct {
|
||||||
Events uint32
|
Events uint32
|
||||||
Fd int32
|
Fd int32
|
||||||
Pad int32
|
Pad int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// EpollWait is a wrapper
|
|
||||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||||
return 0, errNonLinux
|
return 0, errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// EpollCtl is a wrapper
|
|
||||||
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
|
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
|
||||||
return errNonLinux
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eventfd is a wrapper
|
|
||||||
func Eventfd(initval uint, flags int) (fd int, err error) {
|
func Eventfd(initval uint, flags int) (fd int, err error) {
|
||||||
return 0, errNonLinux
|
return 0, errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write is a wrapper
|
|
||||||
func Write(fd int, p []byte) (n int, err error) {
|
func Write(fd int, p []byte) (n int, err error) {
|
||||||
return 0, errNonLinux
|
return 0, errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// EpollCreate1 is a wrapper
|
|
||||||
func EpollCreate1(flag int) (fd int, err error) {
|
func EpollCreate1(flag int) (fd int, err error) {
|
||||||
return 0, errNonLinux
|
return 0, errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// PerfEventMmapPage is a wrapper
|
|
||||||
type PerfEventMmapPage struct {
|
type PerfEventMmapPage struct {
|
||||||
Version uint32
|
Version uint32
|
||||||
Compat_version uint32
|
Compat_version uint32
|
||||||
@@ -182,22 +184,18 @@ type PerfEventMmapPage struct {
|
|||||||
Aux_size uint64
|
Aux_size uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNonblock is a wrapper
|
|
||||||
func SetNonblock(fd int, nonblocking bool) (err error) {
|
func SetNonblock(fd int, nonblocking bool) (err error) {
|
||||||
return errNonLinux
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mmap is a wrapper
|
|
||||||
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
|
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
|
||||||
return []byte{}, errNonLinux
|
return []byte{}, errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// Munmap is a wrapper
|
|
||||||
func Munmap(b []byte) (err error) {
|
func Munmap(b []byte) (err error) {
|
||||||
return errNonLinux
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// PerfEventAttr is a wrapper
|
|
||||||
type PerfEventAttr struct {
|
type PerfEventAttr struct {
|
||||||
Type uint32
|
Type uint32
|
||||||
Size uint32
|
Size uint32
|
||||||
@@ -219,48 +217,39 @@ type PerfEventAttr struct {
|
|||||||
Sample_max_stack uint16
|
Sample_max_stack uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
// PerfEventOpen is a wrapper
|
|
||||||
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) {
|
||||||
return 0, errNonLinux
|
return 0, errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utsname is a wrapper
|
|
||||||
type Utsname struct {
|
type Utsname struct {
|
||||||
Release [65]byte
|
Release [65]byte
|
||||||
Version [65]byte
|
Version [65]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uname is a wrapper
|
|
||||||
func Uname(buf *Utsname) (err error) {
|
func Uname(buf *Utsname) (err error) {
|
||||||
return errNonLinux
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getpid is a wrapper
|
|
||||||
func Getpid() int {
|
func Getpid() int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gettid is a wrapper
|
|
||||||
func Gettid() int {
|
func Gettid() int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tgkill is a wrapper
|
|
||||||
func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
||||||
return errNonLinux
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// BytePtrFromString is a wrapper
|
|
||||||
func BytePtrFromString(s string) (*byte, error) {
|
func BytePtrFromString(s string) (*byte, error) {
|
||||||
return nil, errNonLinux
|
return nil, errNonLinux
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByteSliceToString is a wrapper
|
|
||||||
func ByteSliceToString(s []byte) string {
|
func ByteSliceToString(s []byte) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renameat2 is a wrapper
|
|
||||||
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
|
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
|
||||||
return errNonLinux
|
return errNonLinux
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -138,7 +138,7 @@ func (cg *progAttachCgroup) Pin(string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cg *progAttachCgroup) Unpin() error {
|
func (cg *progAttachCgroup) Unpin() error {
|
||||||
return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported)
|
return fmt.Errorf("can't unpin cgroup: %w", ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *progAttachCgroup) Info() (*Info, error) {
|
func (cg *progAttachCgroup) Info() (*Info, error) {
|
||||||
|
|||||||
+39
-71
@@ -1,7 +1,6 @@
|
|||||||
package link
|
package link
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -9,7 +8,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
@@ -20,12 +18,6 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
kprobeEventsPath = filepath.Join(tracefsPath, "kprobe_events")
|
kprobeEventsPath = filepath.Join(tracefsPath, "kprobe_events")
|
||||||
|
|
||||||
kprobeRetprobeBit = struct {
|
|
||||||
once sync.Once
|
|
||||||
value uint64
|
|
||||||
err error
|
|
||||||
}{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type probeType uint8
|
type probeType uint8
|
||||||
@@ -83,13 +75,6 @@ func (pt probeType) PerfEventType(ret bool) perfEventType {
|
|||||||
return uprobeEvent
|
return uprobeEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt probeType) RetprobeBit() (uint64, error) {
|
|
||||||
if pt == kprobeType {
|
|
||||||
return kretprobeBit()
|
|
||||||
}
|
|
||||||
return uretprobeBit()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kprobe attaches the given eBPF program to a perf event that fires when the
|
// Kprobe attaches the given eBPF program to a perf event that fires when the
|
||||||
// given kernel symbol starts executing. See /proc/kallsyms for available
|
// given kernel symbol starts executing. See /proc/kallsyms for available
|
||||||
// symbols. For example, printk():
|
// symbols. For example, printk():
|
||||||
@@ -123,6 +108,9 @@ func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error
|
|||||||
// Losing the reference to the resulting Link (kp) will close the Kretprobe
|
// Losing the reference to the resulting Link (kp) will close the Kretprobe
|
||||||
// and prevent further execution of prog. The Link must be Closed during
|
// and prevent further execution of prog. The Link must be Closed during
|
||||||
// program shutdown to avoid leaking system resources.
|
// program shutdown to avoid leaking system resources.
|
||||||
|
//
|
||||||
|
// On kernels 5.10 and earlier, setting a kretprobe on a nonexistent symbol
|
||||||
|
// incorrectly returns unix.EINVAL instead of os.ErrNotExist.
|
||||||
func Kretprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
|
func Kretprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
|
||||||
k, err := kprobe(symbol, prog, opts, true)
|
k, err := kprobe(symbol, prog, opts, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -194,7 +182,7 @@ func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*
|
|||||||
|
|
||||||
// Use kprobe PMU if the kernel has it available.
|
// Use kprobe PMU if the kernel has it available.
|
||||||
tp, err := pmuKprobe(args)
|
tp, err := pmuKprobe(args)
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
||||||
args.symbol = platformPrefix(symbol)
|
args.symbol = platformPrefix(symbol)
|
||||||
tp, err = pmuKprobe(args)
|
tp, err = pmuKprobe(args)
|
||||||
}
|
}
|
||||||
@@ -208,7 +196,7 @@ func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*
|
|||||||
// Use tracefs if kprobe PMU is missing.
|
// Use tracefs if kprobe PMU is missing.
|
||||||
args.symbol = symbol
|
args.symbol = symbol
|
||||||
tp, err = tracefsKprobe(args)
|
tp, err = tracefsKprobe(args)
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
||||||
args.symbol = platformPrefix(symbol)
|
args.symbol = platformPrefix(symbol)
|
||||||
tp, err = tracefsKprobe(args)
|
tp, err = tracefsKprobe(args)
|
||||||
}
|
}
|
||||||
@@ -235,14 +223,17 @@ func pmuKprobe(args probeArgs) (*perfEvent, error) {
|
|||||||
func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
|
func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
|
||||||
// Getting the PMU type will fail if the kernel doesn't support
|
// Getting the PMU type will fail if the kernel doesn't support
|
||||||
// the perf_[k,u]probe PMU.
|
// the perf_[k,u]probe PMU.
|
||||||
et, err := getPMUEventType(typ)
|
et, err := readUint64FromFileOnce("%d\n", "/sys/bus/event_source/devices", typ.String(), "type")
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
return nil, fmt.Errorf("%s: %w", typ, ErrNotSupported)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var config uint64
|
var config uint64
|
||||||
if args.ret {
|
if args.ret {
|
||||||
bit, err := typ.RetprobeBit()
|
bit, err := readUint64FromFileOnce("config:%d\n", "/sys/bus/event_source/devices", typ.String(), "/format/retprobe")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -250,8 +241,9 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
attr unix.PerfEventAttr
|
attr unix.PerfEventAttr
|
||||||
sp unsafe.Pointer
|
sp unsafe.Pointer
|
||||||
|
token string
|
||||||
)
|
)
|
||||||
switch typ {
|
switch typ {
|
||||||
case kprobeType:
|
case kprobeType:
|
||||||
@@ -261,6 +253,8 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token = kprobeToken(args)
|
||||||
|
|
||||||
attr = unix.PerfEventAttr{
|
attr = unix.PerfEventAttr{
|
||||||
// The minimum size required for PMU kprobes is PERF_ATTR_SIZE_VER1,
|
// The minimum size required for PMU kprobes is PERF_ATTR_SIZE_VER1,
|
||||||
// since it added the config2 (Ext2) field. Use Ext2 as probe_offset.
|
// since it added the config2 (Ext2) field. Use Ext2 as probe_offset.
|
||||||
@@ -280,6 +274,8 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
|
|||||||
config |= args.refCtrOffset << uprobeRefCtrOffsetShift
|
config |= args.refCtrOffset << uprobeRefCtrOffsetShift
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token = uprobeToken(args)
|
||||||
|
|
||||||
attr = unix.PerfEventAttr{
|
attr = unix.PerfEventAttr{
|
||||||
// The minimum size required for PMU uprobes is PERF_ATTR_SIZE_VER1,
|
// The minimum size required for PMU uprobes is PERF_ATTR_SIZE_VER1,
|
||||||
// since it added the config2 (Ext2) field. The Size field controls the
|
// since it added the config2 (Ext2) field. The Size field controls the
|
||||||
@@ -299,26 +295,27 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
|
|||||||
// return -EINVAL. Return ErrNotSupported to allow falling back to tracefs.
|
// return -EINVAL. Return ErrNotSupported to allow falling back to tracefs.
|
||||||
// https://github.com/torvalds/linux/blob/94710cac0ef4/kernel/trace/trace_kprobe.c#L340-L343
|
// https://github.com/torvalds/linux/blob/94710cac0ef4/kernel/trace/trace_kprobe.c#L340-L343
|
||||||
if errors.Is(err, unix.EINVAL) && strings.Contains(args.symbol, ".") {
|
if errors.Is(err, unix.EINVAL) && strings.Contains(args.symbol, ".") {
|
||||||
return nil, fmt.Errorf("symbol '%s+%#x': older kernels don't accept dots: %w", args.symbol, args.offset, ErrNotSupported)
|
return nil, fmt.Errorf("token %s: older kernels don't accept dots: %w", token, ErrNotSupported)
|
||||||
}
|
}
|
||||||
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
|
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
|
||||||
// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
|
// when trying to create a retprobe for a missing symbol.
|
||||||
// is returned to the caller.
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
return nil, fmt.Errorf("token %s: not found: %w", token, err)
|
||||||
return nil, fmt.Errorf("symbol '%s+%#x' not found: %w", args.symbol, args.offset, os.ErrNotExist)
|
|
||||||
}
|
}
|
||||||
// Since commit ab105a4fb894, -EILSEQ is returned when a kprobe sym+offset is resolved
|
// Since commit ab105a4fb894, EILSEQ is returned when a kprobe sym+offset is resolved
|
||||||
// to an invalid insn boundary.
|
// to an invalid insn boundary. The exact conditions that trigger this error are
|
||||||
if errors.Is(err, syscall.EILSEQ) {
|
// arch specific however.
|
||||||
return nil, fmt.Errorf("symbol '%s+%#x' not found (bad insn boundary): %w", args.symbol, args.offset, os.ErrNotExist)
|
if errors.Is(err, unix.EILSEQ) {
|
||||||
|
return nil, fmt.Errorf("token %s: bad insn boundary: %w", token, os.ErrNotExist)
|
||||||
}
|
}
|
||||||
// Since at least commit cb9a19fe4aa51, ENOTSUPP is returned
|
// Since at least commit cb9a19fe4aa51, ENOTSUPP is returned
|
||||||
// when attempting to set a uprobe on a trap instruction.
|
// when attempting to set a uprobe on a trap instruction.
|
||||||
if errors.Is(err, unix.ENOTSUPP) {
|
if errors.Is(err, sys.ENOTSUPP) {
|
||||||
return nil, fmt.Errorf("failed setting uprobe on offset %#x (possible trap insn): %w", args.offset, err)
|
return nil, fmt.Errorf("token %s: failed setting uprobe on offset %#x (possible trap insn): %w", token, args.offset, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("opening perf event: %w", err)
|
return nil, fmt.Errorf("token %s: opening perf event: %w", token, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the string pointer is not collected before PerfEventOpen returns.
|
// Ensure the string pointer is not collected before PerfEventOpen returns.
|
||||||
@@ -454,16 +451,15 @@ func createTraceFSProbeEvent(typ probeType, args probeArgs) error {
|
|||||||
pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(args.ret), args.group, args.symbol, token)
|
pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(args.ret), args.group, args.symbol, token)
|
||||||
}
|
}
|
||||||
_, err = f.WriteString(pe)
|
_, err = f.WriteString(pe)
|
||||||
|
|
||||||
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
|
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
|
||||||
// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
|
// when trying to create a retprobe for a missing symbol.
|
||||||
// is returned to the caller.
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
// EINVAL is also returned on pre-5.2 kernels when the `SYM[+offs]` token
|
return fmt.Errorf("token %s: not found: %w", token, err)
|
||||||
// is resolved to an invalid insn boundary.
|
|
||||||
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
|
||||||
return fmt.Errorf("token %s: %w", token, os.ErrNotExist)
|
|
||||||
}
|
}
|
||||||
// Since commit ab105a4fb894, -EILSEQ is returned when a kprobe sym+offset is resolved
|
// Since commit ab105a4fb894, EILSEQ is returned when a kprobe sym+offset is resolved
|
||||||
// to an invalid insn boundary.
|
// to an invalid insn boundary. The exact conditions that trigger this error are
|
||||||
|
// arch specific however.
|
||||||
if errors.Is(err, syscall.EILSEQ) {
|
if errors.Is(err, syscall.EILSEQ) {
|
||||||
return fmt.Errorf("token %s: bad insn boundary: %w", token, os.ErrNotExist)
|
return fmt.Errorf("token %s: bad insn boundary: %w", token, os.ErrNotExist)
|
||||||
}
|
}
|
||||||
@@ -472,8 +468,9 @@ func createTraceFSProbeEvent(typ probeType, args probeArgs) error {
|
|||||||
if errors.Is(err, syscall.ERANGE) {
|
if errors.Is(err, syscall.ERANGE) {
|
||||||
return fmt.Errorf("token %s: offset too big: %w", token, os.ErrNotExist)
|
return fmt.Errorf("token %s: offset too big: %w", token, os.ErrNotExist)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err)
|
return fmt.Errorf("token %s: writing '%s': %w", token, pe, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -527,35 +524,6 @@ func probePrefix(ret bool) string {
|
|||||||
return "p"
|
return "p"
|
||||||
}
|
}
|
||||||
|
|
||||||
// determineRetprobeBit reads a Performance Monitoring Unit's retprobe bit
|
|
||||||
// from /sys/bus/event_source/devices/<pmu>/format/retprobe.
|
|
||||||
func determineRetprobeBit(typ probeType) (uint64, error) {
|
|
||||||
p := filepath.Join("/sys/bus/event_source/devices/", typ.String(), "/format/retprobe")
|
|
||||||
|
|
||||||
data, err := os.ReadFile(p)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var rp uint64
|
|
||||||
n, err := fmt.Sscanf(string(bytes.TrimSpace(data)), "config:%d", &rp)
|
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("parse retprobe bit: %w", err)
|
|
||||||
}
|
|
||||||
if n != 1 {
|
|
||||||
return 0, fmt.Errorf("parse retprobe bit: expected 1 item, got %d", n)
|
|
||||||
}
|
|
||||||
|
|
||||||
return rp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func kretprobeBit() (uint64, error) {
|
|
||||||
kprobeRetprobeBit.once.Do(func() {
|
|
||||||
kprobeRetprobeBit.value, kprobeRetprobeBit.err = determineRetprobeBit(kprobeType)
|
|
||||||
})
|
|
||||||
return kprobeRetprobeBit.value, kprobeRetprobeBit.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// kprobeToken creates the SYM[+offs] token for the tracefs api.
|
// kprobeToken creates the SYM[+offs] token for the tracefs api.
|
||||||
func kprobeToken(args probeArgs) string {
|
func kprobeToken(args probeArgs) string {
|
||||||
po := args.symbol
|
po := args.symbol
|
||||||
|
|||||||
+176
@@ -0,0 +1,176 @@
|
|||||||
|
package link
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/cilium/ebpf"
|
||||||
|
"github.com/cilium/ebpf/asm"
|
||||||
|
"github.com/cilium/ebpf/internal"
|
||||||
|
"github.com/cilium/ebpf/internal/sys"
|
||||||
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KprobeMultiOptions defines additional parameters that will be used
|
||||||
|
// when opening a KprobeMulti Link.
|
||||||
|
type KprobeMultiOptions struct {
|
||||||
|
// Symbols takes a list of kernel symbol names to attach an ebpf program to.
|
||||||
|
//
|
||||||
|
// Mutually exclusive with Addresses.
|
||||||
|
Symbols []string
|
||||||
|
|
||||||
|
// Addresses takes a list of kernel symbol addresses in case they can not
|
||||||
|
// be referred to by name.
|
||||||
|
//
|
||||||
|
// Note that only start addresses can be specified, since the fprobe API
|
||||||
|
// limits the attach point to the function entry or return.
|
||||||
|
//
|
||||||
|
// Mutually exclusive with Symbols.
|
||||||
|
Addresses []uint64
|
||||||
|
|
||||||
|
// Cookies specifies arbitrary values that can be fetched from an eBPF
|
||||||
|
// program via `bpf_get_attach_cookie()`.
|
||||||
|
//
|
||||||
|
// If set, its length should be equal to the length of Symbols or Addresses.
|
||||||
|
// Each Cookie is assigned to the Symbol or Address specified at the
|
||||||
|
// corresponding slice index.
|
||||||
|
Cookies []uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// KprobeMulti attaches the given eBPF program to the entry point of a given set
|
||||||
|
// of kernel symbols.
|
||||||
|
//
|
||||||
|
// The difference with Kprobe() is that multi-kprobe accomplishes this in a
|
||||||
|
// single system call, making it significantly faster than attaching many
|
||||||
|
// probes one at a time.
|
||||||
|
//
|
||||||
|
// Requires at least Linux 5.18.
|
||||||
|
func KprobeMulti(prog *ebpf.Program, opts KprobeMultiOptions) (Link, error) {
|
||||||
|
return kprobeMulti(prog, opts, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// KretprobeMulti attaches the given eBPF program to the return point of a given
|
||||||
|
// set of kernel symbols.
|
||||||
|
//
|
||||||
|
// The difference with Kretprobe() is that multi-kprobe accomplishes this in a
|
||||||
|
// single system call, making it significantly faster than attaching many
|
||||||
|
// probes one at a time.
|
||||||
|
//
|
||||||
|
// Requires at least Linux 5.18.
|
||||||
|
func KretprobeMulti(prog *ebpf.Program, opts KprobeMultiOptions) (Link, error) {
|
||||||
|
return kprobeMulti(prog, opts, unix.BPF_F_KPROBE_MULTI_RETURN)
|
||||||
|
}
|
||||||
|
|
||||||
|
func kprobeMulti(prog *ebpf.Program, opts KprobeMultiOptions, flags uint32) (Link, error) {
|
||||||
|
if prog == nil {
|
||||||
|
return nil, errors.New("cannot attach a nil program")
|
||||||
|
}
|
||||||
|
|
||||||
|
syms := uint32(len(opts.Symbols))
|
||||||
|
addrs := uint32(len(opts.Addresses))
|
||||||
|
cookies := uint32(len(opts.Cookies))
|
||||||
|
|
||||||
|
if syms == 0 && addrs == 0 {
|
||||||
|
return nil, fmt.Errorf("one of Symbols or Addresses is required: %w", errInvalidInput)
|
||||||
|
}
|
||||||
|
if syms != 0 && addrs != 0 {
|
||||||
|
return nil, fmt.Errorf("Symbols and Addresses are mutually exclusive: %w", errInvalidInput)
|
||||||
|
}
|
||||||
|
if cookies > 0 && cookies != syms && cookies != addrs {
|
||||||
|
return nil, fmt.Errorf("Cookies must be exactly Symbols or Addresses in length: %w", errInvalidInput)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := haveBPFLinkKprobeMulti(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
attr := &sys.LinkCreateKprobeMultiAttr{
|
||||||
|
ProgFd: uint32(prog.FD()),
|
||||||
|
AttachType: sys.BPF_TRACE_KPROBE_MULTI,
|
||||||
|
KprobeMultiFlags: flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case syms != 0:
|
||||||
|
attr.Count = syms
|
||||||
|
attr.Syms = sys.NewStringSlicePointer(opts.Symbols)
|
||||||
|
|
||||||
|
case addrs != 0:
|
||||||
|
attr.Count = addrs
|
||||||
|
attr.Addrs = sys.NewPointer(unsafe.Pointer(&opts.Addresses[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if cookies != 0 {
|
||||||
|
attr.Cookies = sys.NewPointer(unsafe.Pointer(&opts.Cookies[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := sys.LinkCreateKprobeMulti(attr)
|
||||||
|
if errors.Is(err, unix.ESRCH) {
|
||||||
|
return nil, fmt.Errorf("couldn't find one or more symbols: %w", os.ErrNotExist)
|
||||||
|
}
|
||||||
|
if errors.Is(err, unix.EINVAL) {
|
||||||
|
return nil, fmt.Errorf("%w (missing kernel symbol or prog's AttachType not AttachTraceKprobeMulti?)", err)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &kprobeMultiLink{RawLink{fd, ""}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type kprobeMultiLink struct {
|
||||||
|
RawLink
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Link = (*kprobeMultiLink)(nil)
|
||||||
|
|
||||||
|
func (kml *kprobeMultiLink) Update(prog *ebpf.Program) error {
|
||||||
|
return fmt.Errorf("update kprobe_multi: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kml *kprobeMultiLink) Pin(string) error {
|
||||||
|
return fmt.Errorf("pin kprobe_multi: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kml *kprobeMultiLink) Unpin() error {
|
||||||
|
return fmt.Errorf("unpin kprobe_multi: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
var haveBPFLinkKprobeMulti = internal.FeatureTest("bpf_link_kprobe_multi", "5.18", func() error {
|
||||||
|
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
||||||
|
Name: "probe_kpm_link",
|
||||||
|
Type: ebpf.Kprobe,
|
||||||
|
Instructions: asm.Instructions{
|
||||||
|
asm.Mov.Imm(asm.R0, 0),
|
||||||
|
asm.Return(),
|
||||||
|
},
|
||||||
|
AttachType: ebpf.AttachTraceKprobeMulti,
|
||||||
|
License: "MIT",
|
||||||
|
})
|
||||||
|
if errors.Is(err, unix.E2BIG) {
|
||||||
|
// Kernel doesn't support AttachType field.
|
||||||
|
return internal.ErrNotSupported
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer prog.Close()
|
||||||
|
|
||||||
|
fd, err := sys.LinkCreateKprobeMulti(&sys.LinkCreateKprobeMultiAttr{
|
||||||
|
ProgFd: uint32(prog.FD()),
|
||||||
|
AttachType: sys.BPF_TRACE_KPROBE_MULTI,
|
||||||
|
Count: 1,
|
||||||
|
Syms: sys.NewStringSlicePointer([]string{"vprintk"}),
|
||||||
|
})
|
||||||
|
if errors.Is(err, unix.EINVAL) {
|
||||||
|
return internal.ErrNotSupported
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fd.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
+6
-9
@@ -177,7 +177,7 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
|
|||||||
}
|
}
|
||||||
fd, err := sys.LinkCreate(&attr)
|
fd, err := sys.LinkCreate(&attr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't create link: %s", err)
|
return nil, fmt.Errorf("create link: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &RawLink{fd, ""}, nil
|
return &RawLink{fd, ""}, nil
|
||||||
@@ -280,27 +280,24 @@ func (l *RawLink) Info() (*Info, error) {
|
|||||||
switch info.Type {
|
switch info.Type {
|
||||||
case CgroupType:
|
case CgroupType:
|
||||||
extra = &CgroupInfo{}
|
extra = &CgroupInfo{}
|
||||||
case IterType:
|
|
||||||
// not supported
|
|
||||||
case NetNsType:
|
case NetNsType:
|
||||||
extra = &NetNsInfo{}
|
extra = &NetNsInfo{}
|
||||||
case RawTracepointType:
|
|
||||||
// not supported
|
|
||||||
case TracingType:
|
case TracingType:
|
||||||
extra = &TracingInfo{}
|
extra = &TracingInfo{}
|
||||||
case XDPType:
|
case XDPType:
|
||||||
extra = &XDPInfo{}
|
extra = &XDPInfo{}
|
||||||
case PerfEventType:
|
case RawTracepointType, IterType,
|
||||||
// no extra
|
PerfEventType, KprobeMultiType:
|
||||||
|
// Extra metadata not supported.
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown link info type: %d", info.Type)
|
return nil, fmt.Errorf("unknown link info type: %d", info.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.Type != RawTracepointType && info.Type != IterType && info.Type != PerfEventType {
|
if extra != nil {
|
||||||
buf := bytes.NewReader(info.Extra[:])
|
buf := bytes.NewReader(info.Extra[:])
|
||||||
err := binary.Read(buf, internal.NativeEndian, extra)
|
err := binary.Read(buf, internal.NativeEndian, extra)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can not read extra link info: %w", err)
|
return nil, fmt.Errorf("cannot read extra link info: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+67
-27
@@ -7,8 +7,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/cilium/ebpf"
|
"github.com/cilium/ebpf"
|
||||||
@@ -270,7 +270,11 @@ func unsafeStringPtr(str string) (unsafe.Pointer, error) {
|
|||||||
// can pass a raw symbol name, e.g. a kernel symbol containing dots.
|
// can pass a raw symbol name, e.g. a kernel symbol containing dots.
|
||||||
func getTraceEventID(group, name string) (uint64, error) {
|
func getTraceEventID(group, name string) (uint64, error) {
|
||||||
name = sanitizeSymbol(name)
|
name = sanitizeSymbol(name)
|
||||||
tid, err := uint64FromFile(tracefsPath, "events", group, name, "id")
|
path, err := sanitizePath(tracefsPath, "events", group, name, "id")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
tid, err := readUint64FromFile("%d\n", path)
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return 0, fmt.Errorf("trace event %s/%s: %w", group, name, os.ErrNotExist)
|
return 0, fmt.Errorf("trace event %s/%s: %w", group, name, os.ErrNotExist)
|
||||||
}
|
}
|
||||||
@@ -281,22 +285,6 @@ func getTraceEventID(group, name string) (uint64, error) {
|
|||||||
return tid, nil
|
return tid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPMUEventType reads a Performance Monitoring Unit's type (numeric identifier)
|
|
||||||
// from /sys/bus/event_source/devices/<pmu>/type.
|
|
||||||
//
|
|
||||||
// Returns ErrNotSupported if the pmu type is not supported.
|
|
||||||
func getPMUEventType(typ probeType) (uint64, error) {
|
|
||||||
et, err := uint64FromFile("/sys/bus/event_source/devices", typ.String(), "type")
|
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
|
||||||
return 0, fmt.Errorf("pmu type %s: %w", typ, ErrNotSupported)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("reading pmu type %s: %w", typ, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return et, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// openTracepointPerfEvent opens a tracepoint-type perf event. System-wide
|
// openTracepointPerfEvent opens a tracepoint-type perf event. System-wide
|
||||||
// [k,u]probes created by writing to <tracefs>/[k,u]probe_events are tracepoints
|
// [k,u]probes created by writing to <tracefs>/[k,u]probe_events are tracepoints
|
||||||
// behind the scenes, and can be attached to using these perf events.
|
// behind the scenes, and can be attached to using these perf events.
|
||||||
@@ -317,23 +305,75 @@ func openTracepointPerfEvent(tid uint64, pid int) (*sys.FD, error) {
|
|||||||
return sys.NewFD(fd)
|
return sys.NewFD(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint64FromFile reads a uint64 from a file. All elements of path are sanitized
|
func sanitizePath(base string, path ...string) (string, error) {
|
||||||
// and joined onto base. Returns error if base no longer prefixes the path after
|
|
||||||
// joining all components.
|
|
||||||
func uint64FromFile(base string, path ...string) (uint64, error) {
|
|
||||||
l := filepath.Join(path...)
|
l := filepath.Join(path...)
|
||||||
p := filepath.Join(base, l)
|
p := filepath.Join(base, l)
|
||||||
if !strings.HasPrefix(p, base) {
|
if !strings.HasPrefix(p, base) {
|
||||||
return 0, fmt.Errorf("path '%s' attempts to escape base path '%s': %w", l, base, errInvalidInput)
|
return "", fmt.Errorf("path '%s' attempts to escape base path '%s': %w", l, base, errInvalidInput)
|
||||||
}
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
data, err := os.ReadFile(p)
|
// readUint64FromFile reads a uint64 from a file.
|
||||||
|
//
|
||||||
|
// format specifies the contents of the file in fmt.Scanf syntax.
|
||||||
|
func readUint64FromFile(format string, path ...string) (uint64, error) {
|
||||||
|
filename := filepath.Join(path...)
|
||||||
|
data, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("reading file %s: %w", p, err)
|
return 0, fmt.Errorf("reading file %q: %w", filename, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
et := bytes.TrimSpace(data)
|
var value uint64
|
||||||
return strconv.ParseUint(string(et), 10, 64)
|
n, err := fmt.Fscanf(bytes.NewReader(data), format, &value)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("parsing file %q: %w", filename, err)
|
||||||
|
}
|
||||||
|
if n != 1 {
|
||||||
|
return 0, fmt.Errorf("parsing file %q: expected 1 item, got %d", filename, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type uint64FromFileKey struct {
|
||||||
|
format, path string
|
||||||
|
}
|
||||||
|
|
||||||
|
var uint64FromFileCache = struct {
|
||||||
|
sync.RWMutex
|
||||||
|
values map[uint64FromFileKey]uint64
|
||||||
|
}{
|
||||||
|
values: map[uint64FromFileKey]uint64{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// readUint64FromFileOnce is like readUint64FromFile but memoizes the result.
|
||||||
|
func readUint64FromFileOnce(format string, path ...string) (uint64, error) {
|
||||||
|
filename := filepath.Join(path...)
|
||||||
|
key := uint64FromFileKey{format, filename}
|
||||||
|
|
||||||
|
uint64FromFileCache.RLock()
|
||||||
|
if value, ok := uint64FromFileCache.values[key]; ok {
|
||||||
|
uint64FromFileCache.RUnlock()
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
uint64FromFileCache.RUnlock()
|
||||||
|
|
||||||
|
value, err := readUint64FromFile(format, filename)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64FromFileCache.Lock()
|
||||||
|
defer uint64FromFileCache.Unlock()
|
||||||
|
|
||||||
|
if value, ok := uint64FromFileCache.values[key]; ok {
|
||||||
|
// Someone else got here before us, use what is cached.
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64FromFileCache.values[key] = value
|
||||||
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Probe BPF perf link.
|
// Probe BPF perf link.
|
||||||
|
|||||||
+1
@@ -23,6 +23,7 @@ const (
|
|||||||
NetNsType = sys.BPF_LINK_TYPE_NETNS
|
NetNsType = sys.BPF_LINK_TYPE_NETNS
|
||||||
XDPType = sys.BPF_LINK_TYPE_XDP
|
XDPType = sys.BPF_LINK_TYPE_XDP
|
||||||
PerfEventType = sys.BPF_LINK_TYPE_PERF_EVENT
|
PerfEventType = sys.BPF_LINK_TYPE_PERF_EVENT
|
||||||
|
KprobeMultiType = sys.BPF_LINK_TYPE_KPROBE_MULTI
|
||||||
)
|
)
|
||||||
|
|
||||||
var haveProgAttach = internal.FeatureTest("BPF_PROG_ATTACH", "4.10", func() error {
|
var haveProgAttach = internal.FeatureTest("BPF_PROG_ATTACH", "4.10", func() error {
|
||||||
|
|||||||
+10
-1
@@ -1,6 +1,7 @@
|
|||||||
package link
|
package link
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/cilium/ebpf"
|
"github.com/cilium/ebpf"
|
||||||
@@ -70,6 +71,10 @@ func AttachFreplace(targetProg *ebpf.Program, name string, prog *ebpf.Program) (
|
|||||||
Attach: ebpf.AttachNone,
|
Attach: ebpf.AttachNone,
|
||||||
BTF: typeID,
|
BTF: typeID,
|
||||||
})
|
})
|
||||||
|
if errors.Is(err, sys.ENOTSUPP) {
|
||||||
|
// This may be returned by bpf_tracing_prog_attach via bpf_arch_text_poke.
|
||||||
|
return nil, fmt.Errorf("create raw tracepoint: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -99,8 +104,12 @@ func attachBTFID(program *ebpf.Program) (Link, error) {
|
|||||||
fd, err := sys.RawTracepointOpen(&sys.RawTracepointOpenAttr{
|
fd, err := sys.RawTracepointOpen(&sys.RawTracepointOpenAttr{
|
||||||
ProgFd: uint32(program.FD()),
|
ProgFd: uint32(program.FD()),
|
||||||
})
|
})
|
||||||
|
if errors.Is(err, sys.ENOTSUPP) {
|
||||||
|
// This may be returned by bpf_tracing_prog_attach via bpf_arch_text_poke.
|
||||||
|
return nil, fmt.Errorf("create raw tracepoint: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("create raw tracepoint: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
raw := RawLink{fd: fd}
|
raw := RawLink{fd: fd}
|
||||||
|
|||||||
+7
-21
@@ -7,7 +7,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/cilium/ebpf"
|
"github.com/cilium/ebpf"
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
@@ -16,12 +15,6 @@ import (
|
|||||||
var (
|
var (
|
||||||
uprobeEventsPath = filepath.Join(tracefsPath, "uprobe_events")
|
uprobeEventsPath = filepath.Join(tracefsPath, "uprobe_events")
|
||||||
|
|
||||||
uprobeRetprobeBit = struct {
|
|
||||||
once sync.Once
|
|
||||||
value uint64
|
|
||||||
err error
|
|
||||||
}{}
|
|
||||||
|
|
||||||
uprobeRefCtrOffsetPMUPath = "/sys/bus/event_source/devices/uprobe/format/ref_ctr_offset"
|
uprobeRefCtrOffsetPMUPath = "/sys/bus/event_source/devices/uprobe/format/ref_ctr_offset"
|
||||||
// elixir.bootlin.com/linux/v5.15-rc7/source/kernel/events/core.c#L9799
|
// elixir.bootlin.com/linux/v5.15-rc7/source/kernel/events/core.c#L9799
|
||||||
uprobeRefCtrOffsetShift = 32
|
uprobeRefCtrOffsetShift = 32
|
||||||
@@ -81,7 +74,7 @@ type UprobeOptions struct {
|
|||||||
|
|
||||||
// To open a new Executable, use:
|
// To open a new Executable, use:
|
||||||
//
|
//
|
||||||
// OpenExecutable("/bin/bash")
|
// OpenExecutable("/bin/bash")
|
||||||
//
|
//
|
||||||
// The returned value can then be used to open Uprobe(s).
|
// The returned value can then be used to open Uprobe(s).
|
||||||
func OpenExecutable(path string) (*Executable, error) {
|
func OpenExecutable(path string) (*Executable, error) {
|
||||||
@@ -194,13 +187,13 @@ func (ex *Executable) address(symbol string, opts *UprobeOptions) (uint64, error
|
|||||||
// given symbol starts executing in the given Executable.
|
// given symbol starts executing in the given Executable.
|
||||||
// For example, /bin/bash::main():
|
// For example, /bin/bash::main():
|
||||||
//
|
//
|
||||||
// ex, _ = OpenExecutable("/bin/bash")
|
// ex, _ = OpenExecutable("/bin/bash")
|
||||||
// ex.Uprobe("main", prog, nil)
|
// ex.Uprobe("main", prog, nil)
|
||||||
//
|
//
|
||||||
// When using symbols which belongs to shared libraries,
|
// When using symbols which belongs to shared libraries,
|
||||||
// an offset must be provided via options:
|
// an offset must be provided via options:
|
||||||
//
|
//
|
||||||
// up, err := ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
// up, err := ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||||
//
|
//
|
||||||
// Note: Setting the Offset field in the options supersedes the symbol's offset.
|
// Note: Setting the Offset field in the options supersedes the symbol's offset.
|
||||||
//
|
//
|
||||||
@@ -228,13 +221,13 @@ func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
|||||||
// Uretprobe attaches the given eBPF program to a perf event that fires right
|
// Uretprobe attaches the given eBPF program to a perf event that fires right
|
||||||
// before the given symbol exits. For example, /bin/bash::main():
|
// before the given symbol exits. For example, /bin/bash::main():
|
||||||
//
|
//
|
||||||
// ex, _ = OpenExecutable("/bin/bash")
|
// ex, _ = OpenExecutable("/bin/bash")
|
||||||
// ex.Uretprobe("main", prog, nil)
|
// ex.Uretprobe("main", prog, nil)
|
||||||
//
|
//
|
||||||
// When using symbols which belongs to shared libraries,
|
// When using symbols which belongs to shared libraries,
|
||||||
// an offset must be provided via options:
|
// an offset must be provided via options:
|
||||||
//
|
//
|
||||||
// up, err := ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
// up, err := ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||||
//
|
//
|
||||||
// Note: Setting the Offset field in the options supersedes the symbol's offset.
|
// Note: Setting the Offset field in the options supersedes the symbol's offset.
|
||||||
//
|
//
|
||||||
@@ -364,10 +357,3 @@ func uprobeToken(args probeArgs) string {
|
|||||||
|
|
||||||
return po
|
return po
|
||||||
}
|
}
|
||||||
|
|
||||||
func uretprobeBit() (uint64, error) {
|
|
||||||
uprobeRetprobeBit.once.Do(func() {
|
|
||||||
uprobeRetprobeBit.value, uprobeRetprobeBit.err = determineRetprobeBit(uprobeType)
|
|
||||||
})
|
|
||||||
return uprobeRetprobeBit.value, uprobeRetprobeBit.err
|
|
||||||
}
|
|
||||||
|
|||||||
+8
-2
@@ -1,12 +1,14 @@
|
|||||||
package ebpf
|
package ebpf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
"github.com/cilium/ebpf/btf"
|
"github.com/cilium/ebpf/btf"
|
||||||
|
"github.com/cilium/ebpf/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// splitSymbols splits insns into subsections delimited by Symbol Instructions.
|
// splitSymbols splits insns into subsections delimited by Symbol Instructions.
|
||||||
@@ -67,7 +69,7 @@ func hasFunctionReferences(insns asm.Instructions) bool {
|
|||||||
//
|
//
|
||||||
// Passing a nil target will relocate against the running kernel. insns are
|
// Passing a nil target will relocate against the running kernel. insns are
|
||||||
// modified in place.
|
// modified in place.
|
||||||
func applyRelocations(insns asm.Instructions, local, target *btf.Spec) error {
|
func applyRelocations(insns asm.Instructions, target *btf.Spec, bo binary.ByteOrder) error {
|
||||||
var relos []*btf.CORERelocation
|
var relos []*btf.CORERelocation
|
||||||
var reloInsns []*asm.Instruction
|
var reloInsns []*asm.Instruction
|
||||||
iter := insns.Iterate()
|
iter := insns.Iterate()
|
||||||
@@ -82,12 +84,16 @@ func applyRelocations(insns asm.Instructions, local, target *btf.Spec) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if bo == nil {
|
||||||
|
bo = internal.NativeEndian
|
||||||
|
}
|
||||||
|
|
||||||
target, err := maybeLoadKernelBTF(target)
|
target, err := maybeLoadKernelBTF(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fixups, err := btf.CORERelocate(local, target, relos)
|
fixups, err := btf.CORERelocate(relos, target, bo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -413,7 +413,7 @@ func (spec *MapSpec) createMap(inner *sys.FD, opts MapOptions, handles *handleCa
|
|||||||
KeySize: spec.KeySize,
|
KeySize: spec.KeySize,
|
||||||
ValueSize: spec.ValueSize,
|
ValueSize: spec.ValueSize,
|
||||||
MaxEntries: spec.MaxEntries,
|
MaxEntries: spec.MaxEntries,
|
||||||
MapFlags: spec.Flags,
|
MapFlags: sys.MapFlags(spec.Flags),
|
||||||
NumaNode: spec.NumaNode,
|
NumaNode: spec.NumaNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+156
-59
@@ -35,16 +35,44 @@ const (
|
|||||||
// verifier log.
|
// verifier log.
|
||||||
const DefaultVerifierLogSize = 64 * 1024
|
const DefaultVerifierLogSize = 64 * 1024
|
||||||
|
|
||||||
|
// maxVerifierLogSize is the maximum size of verifier log buffer the kernel
|
||||||
|
// will accept before returning EINVAL.
|
||||||
|
const maxVerifierLogSize = math.MaxUint32 >> 2
|
||||||
|
|
||||||
// ProgramOptions control loading a program into the kernel.
|
// ProgramOptions control loading a program into the kernel.
|
||||||
type ProgramOptions struct {
|
type ProgramOptions struct {
|
||||||
// Controls the detail emitted by the kernel verifier. Set to non-zero
|
// Bitmap controlling the detail emitted by the kernel's eBPF verifier log.
|
||||||
// to enable logging.
|
// LogLevel-type values can be ORed together to request specific kinds of
|
||||||
LogLevel uint32
|
// verifier output. See the documentation on [ebpf.LogLevel] for details.
|
||||||
// Controls the output buffer size for the verifier. Defaults to
|
//
|
||||||
// DefaultVerifierLogSize.
|
// opts.LogLevel = (ebpf.LogLevelBranch | ebpf.LogLevelStats)
|
||||||
|
//
|
||||||
|
// If left to its default value, the program will first be loaded without
|
||||||
|
// verifier output enabled. Upon error, the program load will be repeated
|
||||||
|
// with LogLevelBranch and the given (or default) LogSize value.
|
||||||
|
//
|
||||||
|
// Setting this to a non-zero value will unconditionally enable the verifier
|
||||||
|
// log, populating the [ebpf.Program.VerifierLog] field on successful loads
|
||||||
|
// and including detailed verifier errors if the program is rejected. This
|
||||||
|
// will always allocate an output buffer, but will result in only a single
|
||||||
|
// attempt at loading the program.
|
||||||
|
LogLevel LogLevel
|
||||||
|
|
||||||
|
// Controls the output buffer size for the verifier log, in bytes. See the
|
||||||
|
// documentation on ProgramOptions.LogLevel for details about how this value
|
||||||
|
// is used.
|
||||||
|
//
|
||||||
|
// If this value is set too low to fit the verifier log, the resulting
|
||||||
|
// [ebpf.VerifierError]'s Truncated flag will be true, and the error string
|
||||||
|
// will also contain a hint to that effect.
|
||||||
|
//
|
||||||
|
// Defaults to DefaultVerifierLogSize.
|
||||||
LogSize int
|
LogSize int
|
||||||
// Type information used for CO-RE relocations and when attaching to
|
|
||||||
// kernel functions.
|
// Disables the verifier log completely, regardless of other options.
|
||||||
|
LogDisabled bool
|
||||||
|
|
||||||
|
// Type information used for CO-RE relocations.
|
||||||
//
|
//
|
||||||
// This is useful in environments where the kernel BTF is not available
|
// This is useful in environments where the kernel BTF is not available
|
||||||
// (containers) or where it is in a non-standard location. Defaults to
|
// (containers) or where it is in a non-standard location. Defaults to
|
||||||
@@ -74,7 +102,7 @@ type ProgramSpec struct {
|
|||||||
// The program to attach to. Must be provided manually.
|
// The program to attach to. Must be provided manually.
|
||||||
AttachTarget *Program
|
AttachTarget *Program
|
||||||
|
|
||||||
// The name of the ELF section this program orininated from.
|
// The name of the ELF section this program originated from.
|
||||||
SectionName string
|
SectionName string
|
||||||
|
|
||||||
Instructions asm.Instructions
|
Instructions asm.Instructions
|
||||||
@@ -181,6 +209,10 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
|||||||
return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
|
return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.LogSize < 0 {
|
||||||
|
return nil, errors.New("ProgramOptions.LogSize must be a positive value; disable verifier logs using ProgramOptions.LogDisabled")
|
||||||
|
}
|
||||||
|
|
||||||
// Kernels before 5.0 (6c4fc209fcf9 "bpf: remove useless version check for prog load")
|
// Kernels before 5.0 (6c4fc209fcf9 "bpf: remove useless version check for prog load")
|
||||||
// require the version field to be set to the value of the KERNEL_VERSION
|
// require the version field to be set to the value of the KERNEL_VERSION
|
||||||
// macro for kprobe-type programs.
|
// macro for kprobe-type programs.
|
||||||
@@ -206,17 +238,11 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
|||||||
attr.ProgName = sys.NewObjName(spec.Name)
|
attr.ProgName = sys.NewObjName(spec.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
kernelTypes := opts.KernelTypes
|
|
||||||
|
|
||||||
insns := make(asm.Instructions, len(spec.Instructions))
|
insns := make(asm.Instructions, len(spec.Instructions))
|
||||||
copy(insns, spec.Instructions)
|
copy(insns, spec.Instructions)
|
||||||
|
|
||||||
var btfDisabled bool
|
var btfDisabled bool
|
||||||
if spec.BTF != nil {
|
if spec.BTF != nil {
|
||||||
if err := applyRelocations(insns, spec.BTF, kernelTypes); err != nil {
|
|
||||||
return nil, fmt.Errorf("apply CO-RE relocations: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
handle, err := handles.btfHandle(spec.BTF)
|
handle, err := handles.btfHandle(spec.BTF)
|
||||||
btfDisabled = errors.Is(err, btf.ErrNotSupported)
|
btfDisabled = errors.Is(err, btf.ErrNotSupported)
|
||||||
if err != nil && !btfDisabled {
|
if err != nil && !btfDisabled {
|
||||||
@@ -241,6 +267,10 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := applyRelocations(insns, opts.KernelTypes, spec.ByteOrder); err != nil {
|
||||||
|
return nil, fmt.Errorf("apply CO-RE relocations: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := fixupAndValidate(insns); err != nil {
|
if err := fixupAndValidate(insns); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -262,10 +292,10 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
|||||||
}
|
}
|
||||||
|
|
||||||
attr.AttachBtfId = uint32(targetID)
|
attr.AttachBtfId = uint32(targetID)
|
||||||
attr.AttachProgFd = uint32(spec.AttachTarget.FD())
|
attr.AttachBtfObjFd = uint32(spec.AttachTarget.FD())
|
||||||
defer runtime.KeepAlive(spec.AttachTarget)
|
defer runtime.KeepAlive(spec.AttachTarget)
|
||||||
} else if spec.AttachTo != "" {
|
} else if spec.AttachTo != "" {
|
||||||
targetID, err := findTargetInKernel(kernelTypes, spec.AttachTo, spec.Type, spec.AttachType)
|
module, targetID, err := findTargetInKernel(spec.AttachTo, spec.Type, spec.AttachType)
|
||||||
if err != nil && !errors.Is(err, errUnrecognizedAttachType) {
|
if err != nil && !errors.Is(err, errUnrecognizedAttachType) {
|
||||||
// We ignore errUnrecognizedAttachType since AttachTo may be non-empty
|
// We ignore errUnrecognizedAttachType since AttachTo may be non-empty
|
||||||
// for programs that don't attach anywhere.
|
// for programs that don't attach anywhere.
|
||||||
@@ -273,16 +303,22 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
|||||||
}
|
}
|
||||||
|
|
||||||
attr.AttachBtfId = uint32(targetID)
|
attr.AttachBtfId = uint32(targetID)
|
||||||
|
if module != nil {
|
||||||
|
attr.AttachBtfObjFd = uint32(module.FD())
|
||||||
|
defer module.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logSize := DefaultVerifierLogSize
|
if opts.LogSize == 0 {
|
||||||
if opts.LogSize > 0 {
|
opts.LogSize = DefaultVerifierLogSize
|
||||||
logSize = opts.LogSize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The caller provided a specific verifier log level. Immediately load
|
||||||
|
// the program with the given log level and buffer size, and skip retrying
|
||||||
|
// with a different level / size later.
|
||||||
var logBuf []byte
|
var logBuf []byte
|
||||||
if opts.LogLevel > 0 {
|
if !opts.LogDisabled && opts.LogLevel != 0 {
|
||||||
logBuf = make([]byte, logSize)
|
logBuf = make([]byte, opts.LogSize)
|
||||||
attr.LogLevel = opts.LogLevel
|
attr.LogLevel = opts.LogLevel
|
||||||
attr.LogSize = uint32(len(logBuf))
|
attr.LogSize = uint32(len(logBuf))
|
||||||
attr.LogBuf = sys.NewSlicePointer(logBuf)
|
attr.LogBuf = sys.NewSlicePointer(logBuf)
|
||||||
@@ -293,13 +329,17 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
|||||||
return &Program{unix.ByteSliceToString(logBuf), fd, spec.Name, "", spec.Type}, nil
|
return &Program{unix.ByteSliceToString(logBuf), fd, spec.Name, "", spec.Type}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.LogLevel == 0 && opts.LogSize >= 0 {
|
// A verifier error occurred, but the caller did not specify a log level.
|
||||||
// Re-run with the verifier enabled to get better error messages.
|
// Re-run with branch-level verifier logs enabled to obtain more info.
|
||||||
logBuf = make([]byte, logSize)
|
var truncated bool
|
||||||
attr.LogLevel = 1
|
if !opts.LogDisabled && opts.LogLevel == 0 {
|
||||||
|
logBuf = make([]byte, opts.LogSize)
|
||||||
|
attr.LogLevel = LogLevelBranch
|
||||||
attr.LogSize = uint32(len(logBuf))
|
attr.LogSize = uint32(len(logBuf))
|
||||||
attr.LogBuf = sys.NewSlicePointer(logBuf)
|
attr.LogBuf = sys.NewSlicePointer(logBuf)
|
||||||
_, _ = sys.ProgLoad(attr)
|
|
||||||
|
_, ve := sys.ProgLoad(attr)
|
||||||
|
truncated = errors.Is(ve, unix.ENOSPC)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@@ -318,11 +358,15 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
|||||||
return nil, fmt.Errorf("load program: %w", err)
|
return nil, fmt.Errorf("load program: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.LogSize > maxVerifierLogSize {
|
||||||
|
return nil, fmt.Errorf("load program: %w (ProgramOptions.LogSize exceeds maximum value of %d)", err, maxVerifierLogSize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = internal.ErrorWithLog(err, logBuf)
|
err = internal.ErrorWithLog(err, logBuf, truncated)
|
||||||
if btfDisabled {
|
if btfDisabled {
|
||||||
return nil, fmt.Errorf("load program: %w (BTF disabled)", err)
|
return nil, fmt.Errorf("load program: %w (kernel without BTF support)", err)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("load program: %w", err)
|
return nil, fmt.Errorf("load program: %w", err)
|
||||||
}
|
}
|
||||||
@@ -542,7 +586,7 @@ func (p *Program) Run(opts *RunOptions) (uint32, error) {
|
|||||||
// run or an error. reset is called whenever the benchmark syscall is
|
// run or an error. reset is called whenever the benchmark syscall is
|
||||||
// interrupted, and should be set to testing.B.ResetTimer or similar.
|
// interrupted, and should be set to testing.B.ResetTimer or similar.
|
||||||
//
|
//
|
||||||
// Note: profiling a call to this function will skew it's results, see
|
// Note: profiling a call to this function will skew its results, see
|
||||||
// https://github.com/cilium/ebpf/issues/24
|
// https://github.com/cilium/ebpf/issues/24
|
||||||
//
|
//
|
||||||
// This function requires at least Linux 4.12.
|
// This function requires at least Linux 4.12.
|
||||||
@@ -580,8 +624,7 @@ var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() e
|
|||||||
}
|
}
|
||||||
defer prog.Close()
|
defer prog.Close()
|
||||||
|
|
||||||
// Programs require at least 14 bytes input
|
in := internal.EmptyBPFContext
|
||||||
in := make([]byte, 14)
|
|
||||||
attr := sys.ProgRunAttr{
|
attr := sys.ProgRunAttr{
|
||||||
ProgFd: uint32(prog.FD()),
|
ProgFd: uint32(prog.FD()),
|
||||||
DataSizeIn: uint32(len(in)),
|
DataSizeIn: uint32(len(in)),
|
||||||
@@ -599,7 +642,7 @@ var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() e
|
|||||||
// We know that PROG_TEST_RUN is supported if we get EINTR.
|
// We know that PROG_TEST_RUN is supported if we get EINTR.
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case errors.Is(err, unix.ENOTSUPP):
|
case errors.Is(err, sys.ENOTSUPP):
|
||||||
// The first PROG_TEST_RUN patches shipped in 4.12 didn't include
|
// The first PROG_TEST_RUN patches shipped in 4.12 didn't include
|
||||||
// a test runner for SocketFilter. ENOTSUPP means PROG_TEST_RUN is
|
// a test runner for SocketFilter. ENOTSUPP means PROG_TEST_RUN is
|
||||||
// supported, but not for the program type used in the probe.
|
// supported, but not for the program type used in the probe.
|
||||||
@@ -660,7 +703,7 @@ func (p *Program) testRun(opts *RunOptions) (uint32, time.Duration, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, unix.ENOTSUPP) {
|
if errors.Is(err, sys.ENOTSUPP) {
|
||||||
return 0, 0, fmt.Errorf("kernel doesn't support testing program type %s: %w", p.Type(), ErrNotSupported)
|
return 0, 0, fmt.Errorf("kernel doesn't support testing program type %s: %w", p.Type(), ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,11 +813,15 @@ var errUnrecognizedAttachType = errors.New("unrecognized attach type")
|
|||||||
|
|
||||||
// find an attach target type in the kernel.
|
// find an attach target type in the kernel.
|
||||||
//
|
//
|
||||||
// spec may be nil and defaults to the canonical kernel BTF. name together with
|
// name, progType and attachType determine which type we need to attach to.
|
||||||
// progType and attachType determine which type we need to attach to.
|
|
||||||
//
|
//
|
||||||
// Returns errUnrecognizedAttachType.
|
// The attach target may be in a loaded kernel module.
|
||||||
func findTargetInKernel(spec *btf.Spec, name string, progType ProgramType, attachType AttachType) (btf.TypeID, error) {
|
// In that case the returned handle will be non-nil.
|
||||||
|
// The caller is responsible for closing the handle.
|
||||||
|
//
|
||||||
|
// Returns errUnrecognizedAttachType if the combination of progType and attachType
|
||||||
|
// is not recognised.
|
||||||
|
func findTargetInKernel(name string, progType ProgramType, attachType AttachType) (*btf.Handle, btf.TypeID, error) {
|
||||||
type match struct {
|
type match struct {
|
||||||
p ProgramType
|
p ProgramType
|
||||||
a AttachType
|
a AttachType
|
||||||
@@ -782,59 +829,109 @@ func findTargetInKernel(spec *btf.Spec, name string, progType ProgramType, attac
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
typeName, featureName string
|
typeName, featureName string
|
||||||
isBTFTypeFunc = true
|
target btf.Type
|
||||||
)
|
)
|
||||||
|
|
||||||
switch (match{progType, attachType}) {
|
switch (match{progType, attachType}) {
|
||||||
case match{LSM, AttachLSMMac}:
|
case match{LSM, AttachLSMMac}:
|
||||||
typeName = "bpf_lsm_" + name
|
typeName = "bpf_lsm_" + name
|
||||||
featureName = name + " LSM hook"
|
featureName = name + " LSM hook"
|
||||||
|
target = (*btf.Func)(nil)
|
||||||
case match{Tracing, AttachTraceIter}:
|
case match{Tracing, AttachTraceIter}:
|
||||||
typeName = "bpf_iter_" + name
|
typeName = "bpf_iter_" + name
|
||||||
featureName = name + " iterator"
|
featureName = name + " iterator"
|
||||||
|
target = (*btf.Func)(nil)
|
||||||
case match{Tracing, AttachTraceFEntry}:
|
case match{Tracing, AttachTraceFEntry}:
|
||||||
typeName = name
|
typeName = name
|
||||||
featureName = fmt.Sprintf("fentry %s", name)
|
featureName = fmt.Sprintf("fentry %s", name)
|
||||||
|
target = (*btf.Func)(nil)
|
||||||
case match{Tracing, AttachTraceFExit}:
|
case match{Tracing, AttachTraceFExit}:
|
||||||
typeName = name
|
typeName = name
|
||||||
featureName = fmt.Sprintf("fexit %s", name)
|
featureName = fmt.Sprintf("fexit %s", name)
|
||||||
|
target = (*btf.Func)(nil)
|
||||||
case match{Tracing, AttachModifyReturn}:
|
case match{Tracing, AttachModifyReturn}:
|
||||||
typeName = name
|
typeName = name
|
||||||
featureName = fmt.Sprintf("fmod_ret %s", name)
|
featureName = fmt.Sprintf("fmod_ret %s", name)
|
||||||
|
target = (*btf.Func)(nil)
|
||||||
case match{Tracing, AttachTraceRawTp}:
|
case match{Tracing, AttachTraceRawTp}:
|
||||||
typeName = fmt.Sprintf("btf_trace_%s", name)
|
typeName = fmt.Sprintf("btf_trace_%s", name)
|
||||||
featureName = fmt.Sprintf("raw_tp %s", name)
|
featureName = fmt.Sprintf("raw_tp %s", name)
|
||||||
isBTFTypeFunc = false
|
target = (*btf.Typedef)(nil)
|
||||||
default:
|
default:
|
||||||
return 0, errUnrecognizedAttachType
|
return nil, 0, errUnrecognizedAttachType
|
||||||
}
|
}
|
||||||
|
|
||||||
spec, err := maybeLoadKernelBTF(spec)
|
// maybeLoadKernelBTF may return external BTF if /sys/... is not available.
|
||||||
|
// Ideally we shouldn't use external BTF here, since we might try to use
|
||||||
|
// it for parsing kmod split BTF later on. That seems unlikely to work.
|
||||||
|
spec, err := maybeLoadKernelBTF(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("load kernel spec: %w", err)
|
return nil, 0, fmt.Errorf("load kernel spec: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var target btf.Type
|
err = spec.TypeByName(typeName, &target)
|
||||||
if isBTFTypeFunc {
|
if errors.Is(err, btf.ErrNotFound) {
|
||||||
var targetFunc *btf.Func
|
module, id, err := findTargetInModule(spec, typeName, target)
|
||||||
err = spec.TypeByName(typeName, &targetFunc)
|
|
||||||
target = targetFunc
|
|
||||||
} else {
|
|
||||||
var targetTypedef *btf.Typedef
|
|
||||||
err = spec.TypeByName(typeName, &targetTypedef)
|
|
||||||
target = targetTypedef
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, btf.ErrNotFound) {
|
if errors.Is(err, btf.ErrNotFound) {
|
||||||
return 0, &internal.UnsupportedFeatureError{
|
return nil, 0, &internal.UnsupportedFeatureError{Name: featureName}
|
||||||
Name: featureName,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("find target for %s: %w", featureName, err)
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("find target for %s in modules: %w", featureName, err)
|
||||||
|
}
|
||||||
|
return module, id, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("find target for %s in vmlinux: %w", featureName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return spec.TypeID(target)
|
id, err := spec.TypeID(target)
|
||||||
|
return nil, id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// find an attach target type in a kernel module.
|
||||||
|
//
|
||||||
|
// vmlinux must contain the kernel's types and is used to parse kmod BTF.
|
||||||
|
//
|
||||||
|
// Returns btf.ErrNotFound if the target can't be found in any module.
|
||||||
|
func findTargetInModule(vmlinux *btf.Spec, typeName string, target btf.Type) (*btf.Handle, btf.TypeID, error) {
|
||||||
|
it := new(btf.HandleIterator)
|
||||||
|
defer it.Handle.Close()
|
||||||
|
|
||||||
|
for it.Next() {
|
||||||
|
info, err := it.Handle.Info()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("get info for BTF ID %d: %w", it.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !info.IsModule() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := it.Handle.Spec(vmlinux)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("parse types for module %s: %w", info.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = spec.TypeByName(typeName, &target)
|
||||||
|
if errors.Is(err, btf.ErrNotFound) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("lookup type in module %s: %w", info.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := spec.TypeID(target)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("lookup type id in module %s: %w", info.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return it.Take(), id, nil
|
||||||
|
}
|
||||||
|
if err := it.Err(); err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("iterate modules: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, 0, btf.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// find an attach target type in a program.
|
// find an attach target type in a program.
|
||||||
|
|||||||
+1
-1
@@ -111,7 +111,7 @@ readonly branch="${BRANCH:-master}"
|
|||||||
fetch() {
|
fetch() {
|
||||||
echo Fetching "${1}"
|
echo Fetching "${1}"
|
||||||
pushd "${tmp_dir}" > /dev/null
|
pushd "${tmp_dir}" > /dev/null
|
||||||
curl -s -L -O --fail --etag-compare "${1}.etag" --etag-save "${1}.etag" "https://github.com/cilium/ci-kernels/raw/${branch}/${1}"
|
curl --no-progress-meter -L -O --fail --etag-compare "${1}.etag" --etag-save "${1}.etag" "https://github.com/cilium/ci-kernels/raw/${branch}/${1}"
|
||||||
local ret=$?
|
local ret=$?
|
||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
return $ret
|
return $ret
|
||||||
|
|||||||
+2
-2
@@ -143,8 +143,8 @@ func wrapMapError(err error) error {
|
|||||||
return sys.Error(ErrKeyExist, unix.EEXIST)
|
return sys.Error(ErrKeyExist, unix.EEXIST)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, unix.ENOTSUPP) {
|
if errors.Is(err, sys.ENOTSUPP) {
|
||||||
return sys.Error(ErrNotSupported, unix.ENOTSUPP)
|
return sys.Error(ErrNotSupported, sys.ENOTSUPP)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, unix.E2BIG) {
|
if errors.Is(err, unix.E2BIG) {
|
||||||
|
|||||||
+19
@@ -1,6 +1,7 @@
|
|||||||
package ebpf
|
package ebpf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/cilium/ebpf/internal/sys"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -229,6 +230,7 @@ const (
|
|||||||
AttachSkReuseportSelect
|
AttachSkReuseportSelect
|
||||||
AttachSkReuseportSelectOrMigrate
|
AttachSkReuseportSelectOrMigrate
|
||||||
AttachPerfEvent
|
AttachPerfEvent
|
||||||
|
AttachTraceKprobeMulti
|
||||||
)
|
)
|
||||||
|
|
||||||
// AttachFlags of the eBPF program used in BPF_PROG_ATTACH command
|
// AttachFlags of the eBPF program used in BPF_PROG_ATTACH command
|
||||||
@@ -282,3 +284,20 @@ type BatchOptions struct {
|
|||||||
ElemFlags uint64
|
ElemFlags uint64
|
||||||
Flags uint64
|
Flags uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogLevel controls the verbosity of the kernel's eBPF program verifier.
|
||||||
|
// These constants can be used for the ProgramOptions.LogLevel field.
|
||||||
|
type LogLevel = sys.LogLevel
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Print verifier state at branch points.
|
||||||
|
LogLevelBranch = sys.BPF_LOG_LEVEL1
|
||||||
|
|
||||||
|
// Print verifier state for every instruction.
|
||||||
|
// Available since Linux v5.2.
|
||||||
|
LogLevelInstruction = sys.BPF_LOG_LEVEL2
|
||||||
|
|
||||||
|
// Print verifier errors and stats at the end of the verification process.
|
||||||
|
// Available since Linux v5.2.
|
||||||
|
LogLevelStats = sys.BPF_LOG_STATS
|
||||||
|
)
|
||||||
|
|||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
# This source code refers to The Go Authors for copyright purposes.
|
|
||||||
# The master list of authors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/AUTHORS.
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
# This source code was written by the Go contributors.
|
|
||||||
# The master list of contributors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
|
||||||
+17
-3
@@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
import (
|
import "unsafe"
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IoctlRetInt performs an ioctl operation specified by req on a device
|
// IoctlRetInt performs an ioctl operation specified by req on a device
|
||||||
// associated with opened file descriptor fd, and returns a non-negative
|
// associated with opened file descriptor fd, and returns a non-negative
|
||||||
@@ -217,3 +215,19 @@ func IoctlKCMAttach(fd int, info KCMAttach) error {
|
|||||||
func IoctlKCMUnattach(fd int, info KCMUnattach) error {
|
func IoctlKCMUnattach(fd int, info KCMUnattach) error {
|
||||||
return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info))
|
return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IoctlLoopGetStatus64 gets the status of the loop device associated with the
|
||||||
|
// file descriptor fd using the LOOP_GET_STATUS64 operation.
|
||||||
|
func IoctlLoopGetStatus64(fd int) (*LoopInfo64, error) {
|
||||||
|
var value LoopInfo64
|
||||||
|
if err := ioctlPtr(fd, LOOP_GET_STATUS64, unsafe.Pointer(&value)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IoctlLoopSetStatus64 sets the status of the loop device associated with the
|
||||||
|
// file descriptor fd using the LOOP_SET_STATUS64 operation.
|
||||||
|
func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
|
||||||
|
return ioctlPtr(fd, LOOP_SET_STATUS64, unsafe.Pointer(value))
|
||||||
|
}
|
||||||
|
|||||||
+11
-16
@@ -73,12 +73,12 @@ aix_ppc64)
|
|||||||
darwin_amd64)
|
darwin_amd64)
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
mkasm="go run mkasm_darwin.go"
|
mkasm="go run mkasm.go"
|
||||||
;;
|
;;
|
||||||
darwin_arm64)
|
darwin_arm64)
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
mkasm="go run mkasm_darwin.go"
|
mkasm="go run mkasm.go"
|
||||||
;;
|
;;
|
||||||
dragonfly_amd64)
|
dragonfly_amd64)
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
@@ -142,33 +142,33 @@ netbsd_arm64)
|
|||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
;;
|
;;
|
||||||
openbsd_386)
|
openbsd_386)
|
||||||
|
mkasm="go run mkasm.go"
|
||||||
mkerrors="$mkerrors -m32"
|
mkerrors="$mkerrors -m32"
|
||||||
mksyscall="go run mksyscall.go -l32 -openbsd"
|
mksyscall="go run mksyscall.go -l32 -openbsd -libc"
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
mksysctl="go run mksysctl_openbsd.go"
|
||||||
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
|
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
;;
|
;;
|
||||||
openbsd_amd64)
|
openbsd_amd64)
|
||||||
|
mkasm="go run mkasm.go"
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mksyscall="go run mksyscall.go -openbsd"
|
mksyscall="go run mksyscall.go -openbsd -libc"
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
mksysctl="go run mksysctl_openbsd.go"
|
||||||
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
|
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||||
;;
|
;;
|
||||||
openbsd_arm)
|
openbsd_arm)
|
||||||
|
mkasm="go run mkasm.go"
|
||||||
mkerrors="$mkerrors"
|
mkerrors="$mkerrors"
|
||||||
mksyscall="go run mksyscall.go -l32 -openbsd -arm"
|
mksyscall="go run mksyscall.go -l32 -openbsd -arm -libc"
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
mksysctl="go run mksysctl_openbsd.go"
|
||||||
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
|
|
||||||
# Let the type of C char be signed for making the bare syscall
|
# Let the type of C char be signed for making the bare syscall
|
||||||
# API consistent across platforms.
|
# API consistent across platforms.
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||||
;;
|
;;
|
||||||
openbsd_arm64)
|
openbsd_arm64)
|
||||||
|
mkasm="go run mkasm.go"
|
||||||
mkerrors="$mkerrors -m64"
|
mkerrors="$mkerrors -m64"
|
||||||
mksyscall="go run mksyscall.go -openbsd"
|
mksyscall="go run mksyscall.go -openbsd -libc"
|
||||||
mksysctl="go run mksysctl_openbsd.go"
|
mksysctl="go run mksysctl_openbsd.go"
|
||||||
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
|
|
||||||
# Let the type of C char be signed for making the bare syscall
|
# Let the type of C char be signed for making the bare syscall
|
||||||
# API consistent across platforms.
|
# API consistent across platforms.
|
||||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||||
@@ -214,11 +214,6 @@ esac
|
|||||||
if [ "$GOOSARCH" == "aix_ppc64" ]; then
|
if [ "$GOOSARCH" == "aix_ppc64" ]; then
|
||||||
# aix/ppc64 script generates files instead of writing to stdin.
|
# aix/ppc64 script generates files instead of writing to stdin.
|
||||||
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
|
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
|
||||||
elif [ "$GOOS" == "darwin" ]; then
|
|
||||||
# 1.12 and later, syscalls via libSystem
|
|
||||||
echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
|
|
||||||
# 1.13 and later, syscalls via libSystem (including syscallPtr)
|
|
||||||
echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go";
|
|
||||||
elif [ "$GOOS" == "illumos" ]; then
|
elif [ "$GOOS" == "illumos" ]; then
|
||||||
# illumos code generation requires a --illumos switch
|
# illumos code generation requires a --illumos switch
|
||||||
echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
|
echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
|
||||||
@@ -232,5 +227,5 @@ esac
|
|||||||
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
||||||
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
||||||
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
|
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
|
||||||
if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi
|
if [ -n "$mkasm" ]; then echo "$mkasm $GOOS $GOARCH"; fi
|
||||||
) | $run
|
) | $run
|
||||||
|
|||||||
+4
@@ -297,6 +297,10 @@ struct ltchars {
|
|||||||
#define SOL_NETLINK 270
|
#define SOL_NETLINK 270
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SOL_SMC
|
||||||
|
#define SOL_SMC 286
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SOL_BLUETOOTH
|
#ifdef SOL_BLUETOOTH
|
||||||
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
|
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
|
||||||
// but it is already in bluetooth_linux.go
|
// but it is already in bluetooth_linux.go
|
||||||
|
|||||||
-27
@@ -1,27 +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.
|
|
||||||
|
|
||||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
|
||||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
|
||||||
|
|
||||||
package unix
|
|
||||||
|
|
||||||
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
|
||||||
if val < 0 {
|
|
||||||
return "-" + uitoa(uint(-val))
|
|
||||||
}
|
|
||||||
return uitoa(uint(val))
|
|
||||||
}
|
|
||||||
|
|
||||||
func uitoa(val uint) string {
|
|
||||||
var buf [32]byte // big enough for int64
|
|
||||||
i := len(buf) - 1
|
|
||||||
for val >= 10 {
|
|
||||||
buf[i] = byte(val%10 + '0')
|
|
||||||
i--
|
|
||||||
val /= 10
|
|
||||||
}
|
|
||||||
buf[i] = byte(val + '0')
|
|
||||||
return string(buf[i:])
|
|
||||||
}
|
|
||||||
+1
-9
@@ -29,8 +29,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/internal/unsafeheader"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||||
@@ -82,13 +80,7 @@ func BytePtrToString(p *byte) string {
|
|||||||
ptr = unsafe.Pointer(uintptr(ptr) + 1)
|
ptr = unsafe.Pointer(uintptr(ptr) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var s []byte
|
return string(unsafe.Slice(p, n))
|
||||||
h := (*unsafeheader.Slice)(unsafe.Pointer(&s))
|
|
||||||
h.Data = unsafe.Pointer(p)
|
|
||||||
h.Len = n
|
|
||||||
h.Cap = n
|
|
||||||
|
|
||||||
return string(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||||
|
|||||||
+53
-4
@@ -218,13 +218,62 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func recvmsgRaw(fd int, iov []Iovec, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
|
func recvmsgRaw(fd int, iov []Iovec, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
|
||||||
// Recvmsg not implemented on AIX
|
var msg Msghdr
|
||||||
return -1, -1, -1, ENOSYS
|
msg.Name = (*byte)(unsafe.Pointer(rsa))
|
||||||
|
msg.Namelen = uint32(SizeofSockaddrAny)
|
||||||
|
var dummy byte
|
||||||
|
if len(oob) > 0 {
|
||||||
|
// receive at least one normal byte
|
||||||
|
if emptyIovecs(iov) {
|
||||||
|
var iova [1]Iovec
|
||||||
|
iova[0].Base = &dummy
|
||||||
|
iova[0].SetLen(1)
|
||||||
|
iov = iova[:]
|
||||||
|
}
|
||||||
|
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
|
||||||
|
msg.SetControllen(len(oob))
|
||||||
|
}
|
||||||
|
if len(iov) > 0 {
|
||||||
|
msg.Iov = &iov[0]
|
||||||
|
msg.SetIovlen(len(iov))
|
||||||
|
}
|
||||||
|
if n, err = recvmsg(fd, &msg, flags); n == -1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oobn = int(msg.Controllen)
|
||||||
|
recvflags = int(msg.Flags)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
|
func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
|
||||||
// SendmsgN not implemented on AIX
|
var msg Msghdr
|
||||||
return -1, ENOSYS
|
msg.Name = (*byte)(unsafe.Pointer(ptr))
|
||||||
|
msg.Namelen = uint32(salen)
|
||||||
|
var dummy byte
|
||||||
|
var empty bool
|
||||||
|
if len(oob) > 0 {
|
||||||
|
// send at least one normal byte
|
||||||
|
empty = emptyIovecs(iov)
|
||||||
|
if empty {
|
||||||
|
var iova [1]Iovec
|
||||||
|
iova[0].Base = &dummy
|
||||||
|
iova[0].SetLen(1)
|
||||||
|
iov = iova[:]
|
||||||
|
}
|
||||||
|
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
|
||||||
|
msg.SetControllen(len(oob))
|
||||||
|
}
|
||||||
|
if len(iov) > 0 {
|
||||||
|
msg.Iov = &iov[0]
|
||||||
|
msg.SetIovlen(len(iov))
|
||||||
|
}
|
||||||
|
if n, err = sendmsg(fd, &msg, flags); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if len(oob) > 0 && empty {
|
||||||
|
n = 0
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
||||||
|
|||||||
+1
-1
@@ -363,7 +363,7 @@ func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Sockle
|
|||||||
var empty bool
|
var empty bool
|
||||||
if len(oob) > 0 {
|
if len(oob) > 0 {
|
||||||
// send at least one normal byte
|
// send at least one normal byte
|
||||||
empty := emptyIovecs(iov)
|
empty = emptyIovecs(iov)
|
||||||
if empty {
|
if empty {
|
||||||
var iova [1]Iovec
|
var iova [1]Iovec
|
||||||
iova[0].Base = &dummy
|
iova[0].Base = &dummy
|
||||||
|
|||||||
-32
@@ -1,32 +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.
|
|
||||||
|
|
||||||
//go:build darwin && go1.12 && !go1.13
|
|
||||||
// +build darwin,go1.12,!go1.13
|
|
||||||
|
|
||||||
package unix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const _SYS_GETDIRENTRIES64 = 344
|
|
||||||
|
|
||||||
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
|
||||||
// To implement this using libSystem we'd need syscall_syscallPtr for
|
|
||||||
// fdopendir. However, syscallPtr was only added in Go 1.13, so we fall
|
|
||||||
// back to raw syscalls for this func on Go 1.12.
|
|
||||||
var p unsafe.Pointer
|
|
||||||
if len(buf) > 0 {
|
|
||||||
p = unsafe.Pointer(&buf[0])
|
|
||||||
} else {
|
|
||||||
p = unsafe.Pointer(&_zero)
|
|
||||||
}
|
|
||||||
r0, _, e1 := Syscall6(_SYS_GETDIRENTRIES64, uintptr(fd), uintptr(p), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
|
|
||||||
n = int(r0)
|
|
||||||
if e1 != 0 {
|
|
||||||
return n, errnoErr(e1)
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
-108
@@ -1,108 +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.
|
|
||||||
|
|
||||||
//go:build darwin && go1.13
|
|
||||||
// +build darwin,go1.13
|
|
||||||
|
|
||||||
package unix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/internal/unsafeheader"
|
|
||||||
)
|
|
||||||
|
|
||||||
//sys closedir(dir uintptr) (err error)
|
|
||||||
//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
|
|
||||||
|
|
||||||
func fdopendir(fd int) (dir uintptr, err error) {
|
|
||||||
r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0)
|
|
||||||
dir = uintptr(r0)
|
|
||||||
if e1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var libc_fdopendir_trampoline_addr uintptr
|
|
||||||
|
|
||||||
//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"
|
|
||||||
|
|
||||||
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
|
||||||
// Simulate Getdirentries using fdopendir/readdir_r/closedir.
|
|
||||||
// We store the number of entries to skip in the seek
|
|
||||||
// offset of fd. See issue #31368.
|
|
||||||
// It's not the full required semantics, but should handle the case
|
|
||||||
// of calling Getdirentries or ReadDirent repeatedly.
|
|
||||||
// It won't handle assigning the results of lseek to *basep, or handle
|
|
||||||
// the directory being edited underfoot.
|
|
||||||
skip, err := Seek(fd, 0, 1 /* SEEK_CUR */)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to duplicate the incoming file descriptor
|
|
||||||
// because the caller expects to retain control of it, but
|
|
||||||
// fdopendir expects to take control of its argument.
|
|
||||||
// Just Dup'ing the file descriptor is not enough, as the
|
|
||||||
// result shares underlying state. Use Openat to make a really
|
|
||||||
// new file descriptor referring to the same directory.
|
|
||||||
fd2, err := Openat(fd, ".", O_RDONLY, 0)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
d, err := fdopendir(fd2)
|
|
||||||
if err != nil {
|
|
||||||
Close(fd2)
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer closedir(d)
|
|
||||||
|
|
||||||
var cnt int64
|
|
||||||
for {
|
|
||||||
var entry Dirent
|
|
||||||
var entryp *Dirent
|
|
||||||
e := readdir_r(d, &entry, &entryp)
|
|
||||||
if e != 0 {
|
|
||||||
return n, errnoErr(e)
|
|
||||||
}
|
|
||||||
if entryp == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if skip > 0 {
|
|
||||||
skip--
|
|
||||||
cnt++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
reclen := int(entry.Reclen)
|
|
||||||
if reclen > len(buf) {
|
|
||||||
// Not enough room. Return for now.
|
|
||||||
// The counter will let us know where we should start up again.
|
|
||||||
// Note: this strategy for suspending in the middle and
|
|
||||||
// restarting is O(n^2) in the length of the directory. Oh well.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy entry into return buffer.
|
|
||||||
var s []byte
|
|
||||||
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&s))
|
|
||||||
hdr.Data = unsafe.Pointer(&entry)
|
|
||||||
hdr.Cap = reclen
|
|
||||||
hdr.Len = reclen
|
|
||||||
copy(buf, s)
|
|
||||||
|
|
||||||
buf = buf[reclen:]
|
|
||||||
n += reclen
|
|
||||||
cnt++
|
|
||||||
}
|
|
||||||
// Set the seek offset of the input fd to record
|
|
||||||
// how many files we've already returned.
|
|
||||||
_, err = Seek(fd, cnt, 0 /* SEEK_SET */)
|
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
+90
@@ -19,6 +19,96 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//sys closedir(dir uintptr) (err error)
|
||||||
|
//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
|
||||||
|
|
||||||
|
func fdopendir(fd int) (dir uintptr, err error) {
|
||||||
|
r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0)
|
||||||
|
dir = uintptr(r0)
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var libc_fdopendir_trampoline_addr uintptr
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"
|
||||||
|
|
||||||
|
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||||
|
// Simulate Getdirentries using fdopendir/readdir_r/closedir.
|
||||||
|
// We store the number of entries to skip in the seek
|
||||||
|
// offset of fd. See issue #31368.
|
||||||
|
// It's not the full required semantics, but should handle the case
|
||||||
|
// of calling Getdirentries or ReadDirent repeatedly.
|
||||||
|
// It won't handle assigning the results of lseek to *basep, or handle
|
||||||
|
// the directory being edited underfoot.
|
||||||
|
skip, err := Seek(fd, 0, 1 /* SEEK_CUR */)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to duplicate the incoming file descriptor
|
||||||
|
// because the caller expects to retain control of it, but
|
||||||
|
// fdopendir expects to take control of its argument.
|
||||||
|
// Just Dup'ing the file descriptor is not enough, as the
|
||||||
|
// result shares underlying state. Use Openat to make a really
|
||||||
|
// new file descriptor referring to the same directory.
|
||||||
|
fd2, err := Openat(fd, ".", O_RDONLY, 0)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
d, err := fdopendir(fd2)
|
||||||
|
if err != nil {
|
||||||
|
Close(fd2)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer closedir(d)
|
||||||
|
|
||||||
|
var cnt int64
|
||||||
|
for {
|
||||||
|
var entry Dirent
|
||||||
|
var entryp *Dirent
|
||||||
|
e := readdir_r(d, &entry, &entryp)
|
||||||
|
if e != 0 {
|
||||||
|
return n, errnoErr(e)
|
||||||
|
}
|
||||||
|
if entryp == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if skip > 0 {
|
||||||
|
skip--
|
||||||
|
cnt++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
reclen := int(entry.Reclen)
|
||||||
|
if reclen > len(buf) {
|
||||||
|
// Not enough room. Return for now.
|
||||||
|
// The counter will let us know where we should start up again.
|
||||||
|
// Note: this strategy for suspending in the middle and
|
||||||
|
// restarting is O(n^2) in the length of the directory. Oh well.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy entry into return buffer.
|
||||||
|
s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen)
|
||||||
|
copy(buf, s)
|
||||||
|
|
||||||
|
buf = buf[reclen:]
|
||||||
|
n += reclen
|
||||||
|
cnt++
|
||||||
|
}
|
||||||
|
// Set the seek offset of the input fd to record
|
||||||
|
// how many files we've already returned.
|
||||||
|
_, err = Seek(fd, cnt, 0 /* SEEK_SET */)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
|
// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
|
||||||
type SockaddrDatalink struct {
|
type SockaddrDatalink struct {
|
||||||
Len uint8
|
Len uint8
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint32(countin)}
|
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint32(countin)}
|
||||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||||
return int(ioDesc.Len), err
|
return int(ioDesc.Len), err
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint64(countin)}
|
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint64(countin)}
|
||||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||||
return int(ioDesc.Len), err
|
return int(ioDesc.Len), err
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||||
|
|
||||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint32(countin)}
|
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint32(countin)}
|
||||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||||
return int(ioDesc.Len), err
|
return int(ioDesc.Len), err
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||||
|
|
||||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint64(countin)}
|
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint64(countin)}
|
||||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||||
return int(ioDesc.Len), err
|
return int(ioDesc.Len), err
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||||
|
|
||||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint64(countin)}
|
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint64(countin)}
|
||||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||||
return int(ioDesc.Len), err
|
return int(ioDesc.Len), err
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-12
@@ -13,6 +13,7 @@ package unix
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@@ -233,7 +234,7 @@ func Futimesat(dirfd int, path string, tv []Timeval) error {
|
|||||||
func Futimes(fd int, tv []Timeval) (err error) {
|
func Futimes(fd int, tv []Timeval) (err error) {
|
||||||
// Believe it or not, this is the best we can do on Linux
|
// Believe it or not, this is the best we can do on Linux
|
||||||
// (and is what glibc does).
|
// (and is what glibc does).
|
||||||
return Utimes("/proc/self/fd/"+itoa(fd), tv)
|
return Utimes("/proc/self/fd/"+strconv.Itoa(fd), tv)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImplementsGetwd = true
|
const ImplementsGetwd = true
|
||||||
@@ -1541,7 +1542,7 @@ func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Sockle
|
|||||||
var dummy byte
|
var dummy byte
|
||||||
var empty bool
|
var empty bool
|
||||||
if len(oob) > 0 {
|
if len(oob) > 0 {
|
||||||
empty := emptyIovecs(iov)
|
empty = emptyIovecs(iov)
|
||||||
if empty {
|
if empty {
|
||||||
var sockType int
|
var sockType int
|
||||||
sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE)
|
sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE)
|
||||||
@@ -1891,17 +1892,28 @@ func PrctlRetInt(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uint
|
|||||||
return int(ret), nil
|
return int(ret), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// issue 1435.
|
|
||||||
// On linux Setuid and Setgid only affects the current thread, not the process.
|
|
||||||
// This does not match what most callers expect so we must return an error
|
|
||||||
// here rather than letting the caller think that the call succeeded.
|
|
||||||
|
|
||||||
func Setuid(uid int) (err error) {
|
func Setuid(uid int) (err error) {
|
||||||
return EOPNOTSUPP
|
return syscall.Setuid(uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Setgid(uid int) (err error) {
|
func Setgid(gid int) (err error) {
|
||||||
return EOPNOTSUPP
|
return syscall.Setgid(gid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setreuid(ruid, euid int) (err error) {
|
||||||
|
return syscall.Setreuid(ruid, euid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setregid(rgid, egid int) (err error) {
|
||||||
|
return syscall.Setregid(rgid, egid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setresuid(ruid, euid, suid int) (err error) {
|
||||||
|
return syscall.Setresuid(ruid, euid, suid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setresgid(rgid, egid, sgid int) (err error) {
|
||||||
|
return syscall.Setresgid(rgid, egid, sgid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetfsgidRetGid sets fsgid for current thread and returns previous fsgid set.
|
// SetfsgidRetGid sets fsgid for current thread and returns previous fsgid set.
|
||||||
@@ -2240,7 +2252,7 @@ func (fh *FileHandle) Bytes() []byte {
|
|||||||
if n == 0 {
|
if n == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return (*[1 << 30]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&fh.fileHandle.Type)) + 4))[:n:n]
|
return unsafe.Slice((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&fh.fileHandle.Type))+4)), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameToHandleAt wraps the name_to_handle_at system call; it obtains
|
// NameToHandleAt wraps the name_to_handle_at system call; it obtains
|
||||||
@@ -2356,6 +2368,16 @@ func Setitimer(which ItimerWhich, it Itimerval) (Itimerval, error) {
|
|||||||
return prev, nil
|
return prev, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sysnb rtSigprocmask(how int, set *Sigset_t, oldset *Sigset_t, sigsetsize uintptr) (err error) = SYS_RT_SIGPROCMASK
|
||||||
|
|
||||||
|
func PthreadSigmask(how int, set, oldset *Sigset_t) error {
|
||||||
|
if oldset != nil {
|
||||||
|
// Explicitly clear in case Sigset_t is larger than _C__NSIG.
|
||||||
|
*oldset = Sigset_t{}
|
||||||
|
}
|
||||||
|
return rtSigprocmask(how, set, oldset, _C__NSIG/8)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unimplemented
|
* Unimplemented
|
||||||
*/
|
*/
|
||||||
@@ -2414,7 +2436,6 @@ func Setitimer(which ItimerWhich, it Itimerval) (Itimerval, error) {
|
|||||||
// RestartSyscall
|
// RestartSyscall
|
||||||
// RtSigaction
|
// RtSigaction
|
||||||
// RtSigpending
|
// RtSigpending
|
||||||
// RtSigprocmask
|
|
||||||
// RtSigqueueinfo
|
// RtSigqueueinfo
|
||||||
// RtSigreturn
|
// RtSigreturn
|
||||||
// RtSigsuspend
|
// RtSigsuspend
|
||||||
|
|||||||
-4
@@ -41,10 +41,6 @@ func setTimeval(sec, usec int64) Timeval {
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
|
||||||
//sys setfsgid(gid int) (prev int, err error) = SYS_SETFSGID32
|
//sys setfsgid(gid int) (prev int, err error) = SYS_SETFSGID32
|
||||||
//sys setfsuid(uid int) (prev int, err error) = SYS_SETFSUID32
|
//sys setfsuid(uid int) (prev int, err error) = SYS_SETFSUID32
|
||||||
//sysnb Setregid(rgid int, egid int) (err error) = SYS_SETREGID32
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error) = SYS_SETRESGID32
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error) = SYS_SETRESUID32
|
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error) = SYS_SETREUID32
|
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
||||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||||
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
|
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
|
||||||
|
|||||||
-4
@@ -46,11 +46,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||||
|
|
||||||
|
|||||||
-4
@@ -62,10 +62,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
|
|||||||
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
|
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
|
||||||
//sys setfsgid(gid int) (prev int, err error) = SYS_SETFSGID32
|
//sys setfsgid(gid int) (prev int, err error) = SYS_SETFSGID32
|
||||||
//sys setfsuid(uid int) (prev int, err error) = SYS_SETFSUID32
|
//sys setfsuid(uid int) (prev int, err error) = SYS_SETFSUID32
|
||||||
//sysnb Setregid(rgid int, egid int) (err error) = SYS_SETREGID32
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error) = SYS_SETRESGID32
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error) = SYS_SETRESUID32
|
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error) = SYS_SETREUID32
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
||||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||||
|
|||||||
-4
@@ -39,11 +39,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb setrlimit(resource int, rlim *Rlimit) (err error)
|
//sysnb setrlimit(resource int, rlim *Rlimit) (err error)
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||||
|
|
||||||
|
|||||||
-4
@@ -34,10 +34,6 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||||
|
|
||||||
|
|||||||
-4
@@ -37,11 +37,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||||
//sys Statfs(path string, buf *Statfs_t) (err error)
|
//sys Statfs(path string, buf *Statfs_t) (err error)
|
||||||
|
|||||||
-4
@@ -32,10 +32,6 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
||||||
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
|
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
|
||||||
|
|||||||
-4
@@ -34,10 +34,6 @@ import (
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
||||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||||
|
|||||||
-4
@@ -34,11 +34,7 @@ package unix
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||||
//sys Stat(path string, stat *Stat_t) (err error)
|
//sys Stat(path string, stat *Stat_t) (err error)
|
||||||
|
|||||||
-4
@@ -38,11 +38,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||||
|
|
||||||
|
|||||||
-4
@@ -34,11 +34,7 @@ import (
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||||
//sys Stat(path string, stat *Stat_t) (err error)
|
//sys Stat(path string, stat *Stat_t) (err error)
|
||||||
//sys Statfs(path string, buf *Statfs_t) (err error)
|
//sys Statfs(path string, buf *Statfs_t) (err error)
|
||||||
|
|||||||
-4
@@ -31,11 +31,7 @@ package unix
|
|||||||
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
|
||||||
//sys setfsgid(gid int) (prev int, err error)
|
//sys setfsgid(gid int) (prev int, err error)
|
||||||
//sys setfsuid(uid int) (prev int, err error)
|
//sys setfsuid(uid int) (prev int, err error)
|
||||||
//sysnb Setregid(rgid int, egid int) (err error)
|
|
||||||
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
|
|
||||||
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
|
|
||||||
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
||||||
//sysnb Setreuid(ruid int, euid int) (err error)
|
|
||||||
//sys Shutdown(fd int, how int) (err error)
|
//sys Shutdown(fd int, how int) (err error)
|
||||||
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
|
||||||
//sys Stat(path string, stat *Stat_t) (err error)
|
//sys Stat(path string, stat *Stat_t) (err error)
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2022 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 (openbsd && 386) || (openbsd && amd64) || (openbsd && arm) || (openbsd && arm64)
|
||||||
|
// +build openbsd,386 openbsd,amd64 openbsd,arm openbsd,arm64
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
// Implemented in the runtime package (runtime/sys_openbsd3.go)
|
||||||
|
func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
|
||||||
|
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
||||||
|
func syscall_syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1, r2 uintptr, err Errno)
|
||||||
|
func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
|
||||||
|
func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
||||||
|
|
||||||
|
//go:linkname syscall_syscall syscall.syscall
|
||||||
|
//go:linkname syscall_syscall6 syscall.syscall6
|
||||||
|
//go:linkname syscall_syscall10 syscall.syscall10
|
||||||
|
//go:linkname syscall_rawSyscall syscall.rawSyscall
|
||||||
|
//go:linkname syscall_rawSyscall6 syscall.rawSyscall6
|
||||||
|
|
||||||
|
func syscall_syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) {
|
||||||
|
return syscall_syscall10(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, 0)
|
||||||
|
}
|
||||||
+67
-44
@@ -750,8 +750,8 @@ type EventPort struct {
|
|||||||
// we should handle things gracefully. To do so, we need to keep an extra
|
// we should handle things gracefully. To do so, we need to keep an extra
|
||||||
// reference to the cookie around until the event is processed
|
// reference to the cookie around until the event is processed
|
||||||
// thus the otherwise seemingly extraneous "cookies" map
|
// thus the otherwise seemingly extraneous "cookies" map
|
||||||
// The key of this map is a pointer to the corresponding &fCookie.cookie
|
// The key of this map is a pointer to the corresponding fCookie
|
||||||
cookies map[*interface{}]*fileObjCookie
|
cookies map[*fileObjCookie]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PortEvent is an abstraction of the port_event C struct.
|
// PortEvent is an abstraction of the port_event C struct.
|
||||||
@@ -778,7 +778,7 @@ func NewEventPort() (*EventPort, error) {
|
|||||||
port: port,
|
port: port,
|
||||||
fds: make(map[uintptr]*fileObjCookie),
|
fds: make(map[uintptr]*fileObjCookie),
|
||||||
paths: make(map[string]*fileObjCookie),
|
paths: make(map[string]*fileObjCookie),
|
||||||
cookies: make(map[*interface{}]*fileObjCookie),
|
cookies: make(map[*fileObjCookie]struct{}),
|
||||||
}
|
}
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
@@ -799,6 +799,7 @@ func (e *EventPort) Close() error {
|
|||||||
}
|
}
|
||||||
e.fds = nil
|
e.fds = nil
|
||||||
e.paths = nil
|
e.paths = nil
|
||||||
|
e.cookies = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,17 +827,16 @@ func (e *EventPort) AssociatePath(path string, stat os.FileInfo, events int, coo
|
|||||||
if _, found := e.paths[path]; found {
|
if _, found := e.paths[path]; found {
|
||||||
return fmt.Errorf("%v is already associated with this Event Port", path)
|
return fmt.Errorf("%v is already associated with this Event Port", path)
|
||||||
}
|
}
|
||||||
fobj, err := createFileObj(path, stat)
|
fCookie, err := createFileObjCookie(path, stat, cookie)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fCookie := &fileObjCookie{fobj, cookie}
|
_, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fCookie.fobj)), events, (*byte)(unsafe.Pointer(fCookie)))
|
||||||
_, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fobj)), events, (*byte)(unsafe.Pointer(&fCookie.cookie)))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
e.paths[path] = fCookie
|
e.paths[path] = fCookie
|
||||||
e.cookies[&fCookie.cookie] = fCookie
|
e.cookies[fCookie] = struct{}{}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -858,7 +858,7 @@ func (e *EventPort) DissociatePath(path string) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
// dissociate was successful, safe to delete the cookie
|
// dissociate was successful, safe to delete the cookie
|
||||||
fCookie := e.paths[path]
|
fCookie := e.paths[path]
|
||||||
delete(e.cookies, &fCookie.cookie)
|
delete(e.cookies, fCookie)
|
||||||
}
|
}
|
||||||
delete(e.paths, path)
|
delete(e.paths, path)
|
||||||
return err
|
return err
|
||||||
@@ -871,13 +871,16 @@ func (e *EventPort) AssociateFd(fd uintptr, events int, cookie interface{}) erro
|
|||||||
if _, found := e.fds[fd]; found {
|
if _, found := e.fds[fd]; found {
|
||||||
return fmt.Errorf("%v is already associated with this Event Port", fd)
|
return fmt.Errorf("%v is already associated with this Event Port", fd)
|
||||||
}
|
}
|
||||||
fCookie := &fileObjCookie{nil, cookie}
|
fCookie, err := createFileObjCookie("", nil, cookie)
|
||||||
_, err := port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(&fCookie.cookie)))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(fCookie)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
e.fds[fd] = fCookie
|
e.fds[fd] = fCookie
|
||||||
e.cookies[&fCookie.cookie] = fCookie
|
e.cookies[fCookie] = struct{}{}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -896,27 +899,31 @@ func (e *EventPort) DissociateFd(fd uintptr) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
// dissociate was successful, safe to delete the cookie
|
// dissociate was successful, safe to delete the cookie
|
||||||
fCookie := e.fds[fd]
|
fCookie := e.fds[fd]
|
||||||
delete(e.cookies, &fCookie.cookie)
|
delete(e.cookies, fCookie)
|
||||||
}
|
}
|
||||||
delete(e.fds, fd)
|
delete(e.fds, fd)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFileObj(name string, stat os.FileInfo) (*fileObj, error) {
|
func createFileObjCookie(name string, stat os.FileInfo, cookie interface{}) (*fileObjCookie, error) {
|
||||||
fobj := new(fileObj)
|
fCookie := new(fileObjCookie)
|
||||||
bs, err := ByteSliceFromString(name)
|
fCookie.cookie = cookie
|
||||||
if err != nil {
|
if name != "" && stat != nil {
|
||||||
return nil, err
|
fCookie.fobj = new(fileObj)
|
||||||
|
bs, err := ByteSliceFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fCookie.fobj.Name = (*int8)(unsafe.Pointer(&bs[0]))
|
||||||
|
s := stat.Sys().(*syscall.Stat_t)
|
||||||
|
fCookie.fobj.Atim.Sec = s.Atim.Sec
|
||||||
|
fCookie.fobj.Atim.Nsec = s.Atim.Nsec
|
||||||
|
fCookie.fobj.Mtim.Sec = s.Mtim.Sec
|
||||||
|
fCookie.fobj.Mtim.Nsec = s.Mtim.Nsec
|
||||||
|
fCookie.fobj.Ctim.Sec = s.Ctim.Sec
|
||||||
|
fCookie.fobj.Ctim.Nsec = s.Ctim.Nsec
|
||||||
}
|
}
|
||||||
fobj.Name = (*int8)(unsafe.Pointer(&bs[0]))
|
return fCookie, nil
|
||||||
s := stat.Sys().(*syscall.Stat_t)
|
|
||||||
fobj.Atim.Sec = s.Atim.Sec
|
|
||||||
fobj.Atim.Nsec = s.Atim.Nsec
|
|
||||||
fobj.Mtim.Sec = s.Mtim.Sec
|
|
||||||
fobj.Mtim.Nsec = s.Mtim.Nsec
|
|
||||||
fobj.Ctim.Sec = s.Ctim.Sec
|
|
||||||
fobj.Ctim.Nsec = s.Ctim.Nsec
|
|
||||||
return fobj, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOne wraps port_get(3c) and returns a single PortEvent.
|
// GetOne wraps port_get(3c) and returns a single PortEvent.
|
||||||
@@ -929,44 +936,50 @@ func (e *EventPort) GetOne(t *Timespec) (*PortEvent, error) {
|
|||||||
p := new(PortEvent)
|
p := new(PortEvent)
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
defer e.mu.Unlock()
|
defer e.mu.Unlock()
|
||||||
e.peIntToExt(pe, p)
|
err = e.peIntToExt(pe, p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// peIntToExt converts a cgo portEvent struct into the friendlier PortEvent
|
// peIntToExt converts a cgo portEvent struct into the friendlier PortEvent
|
||||||
// NOTE: Always call this function while holding the e.mu mutex
|
// NOTE: Always call this function while holding the e.mu mutex
|
||||||
func (e *EventPort) peIntToExt(peInt *portEvent, peExt *PortEvent) {
|
func (e *EventPort) peIntToExt(peInt *portEvent, peExt *PortEvent) error {
|
||||||
|
if e.cookies == nil {
|
||||||
|
return fmt.Errorf("this EventPort is already closed")
|
||||||
|
}
|
||||||
peExt.Events = peInt.Events
|
peExt.Events = peInt.Events
|
||||||
peExt.Source = peInt.Source
|
peExt.Source = peInt.Source
|
||||||
cookie := (*interface{})(unsafe.Pointer(peInt.User))
|
fCookie := (*fileObjCookie)(unsafe.Pointer(peInt.User))
|
||||||
peExt.Cookie = *cookie
|
_, found := e.cookies[fCookie]
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
panic("unexpected event port address; may be due to kernel bug; see https://go.dev/issue/54254")
|
||||||
|
}
|
||||||
|
peExt.Cookie = fCookie.cookie
|
||||||
|
delete(e.cookies, fCookie)
|
||||||
|
|
||||||
switch peInt.Source {
|
switch peInt.Source {
|
||||||
case PORT_SOURCE_FD:
|
case PORT_SOURCE_FD:
|
||||||
delete(e.cookies, cookie)
|
|
||||||
peExt.Fd = uintptr(peInt.Object)
|
peExt.Fd = uintptr(peInt.Object)
|
||||||
// Only remove the fds entry if it exists and this cookie matches
|
// Only remove the fds entry if it exists and this cookie matches
|
||||||
if fobj, ok := e.fds[peExt.Fd]; ok {
|
if fobj, ok := e.fds[peExt.Fd]; ok {
|
||||||
if &fobj.cookie == cookie {
|
if fobj == fCookie {
|
||||||
delete(e.fds, peExt.Fd)
|
delete(e.fds, peExt.Fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case PORT_SOURCE_FILE:
|
case PORT_SOURCE_FILE:
|
||||||
if fCookie, ok := e.cookies[cookie]; ok && uintptr(unsafe.Pointer(fCookie.fobj)) == uintptr(peInt.Object) {
|
peExt.fobj = fCookie.fobj
|
||||||
// Use our stashed reference rather than using unsafe on what we got back
|
|
||||||
// the unsafe version would be (*fileObj)(unsafe.Pointer(uintptr(peInt.Object)))
|
|
||||||
peExt.fobj = fCookie.fobj
|
|
||||||
} else {
|
|
||||||
panic("mismanaged memory")
|
|
||||||
}
|
|
||||||
delete(e.cookies, cookie)
|
|
||||||
peExt.Path = BytePtrToString((*byte)(unsafe.Pointer(peExt.fobj.Name)))
|
peExt.Path = BytePtrToString((*byte)(unsafe.Pointer(peExt.fobj.Name)))
|
||||||
// Only remove the paths entry if it exists and this cookie matches
|
// Only remove the paths entry if it exists and this cookie matches
|
||||||
if fobj, ok := e.paths[peExt.Path]; ok {
|
if fobj, ok := e.paths[peExt.Path]; ok {
|
||||||
if &fobj.cookie == cookie {
|
if fobj == fCookie {
|
||||||
delete(e.paths, peExt.Path)
|
delete(e.paths, peExt.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pending wraps port_getn(3c) and returns how many events are pending.
|
// Pending wraps port_getn(3c) and returns how many events are pending.
|
||||||
@@ -990,7 +1003,7 @@ func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error)
|
|||||||
got := uint32(min)
|
got := uint32(min)
|
||||||
max := uint32(len(s))
|
max := uint32(len(s))
|
||||||
var err error
|
var err error
|
||||||
ps := make([]portEvent, max, max)
|
ps := make([]portEvent, max)
|
||||||
_, err = port_getn(e.port, &ps[0], max, &got, timeout)
|
_, err = port_getn(e.port, &ps[0], max, &got, timeout)
|
||||||
// got will be trustworthy with ETIME, but not any other error.
|
// got will be trustworthy with ETIME, but not any other error.
|
||||||
if err != nil && err != ETIME {
|
if err != nil && err != ETIME {
|
||||||
@@ -998,8 +1011,18 @@ func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error)
|
|||||||
}
|
}
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
defer e.mu.Unlock()
|
defer e.mu.Unlock()
|
||||||
|
valid := 0
|
||||||
for i := 0; i < int(got); i++ {
|
for i := 0; i < int(got); i++ {
|
||||||
e.peIntToExt(&ps[i], &s[i])
|
err2 := e.peIntToExt(&ps[i], &s[i])
|
||||||
|
if err2 != nil {
|
||||||
|
if valid == 0 && err == nil {
|
||||||
|
// If err2 is the only error and there are no valid events
|
||||||
|
// to return, return it to the caller.
|
||||||
|
err = err2
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
valid = i + 1
|
||||||
}
|
}
|
||||||
return int(got), err
|
return valid, err
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-11
@@ -13,8 +13,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/internal/unsafeheader"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -117,11 +115,7 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use unsafe to convert addr into a []byte.
|
// Use unsafe to convert addr into a []byte.
|
||||||
var b []byte
|
b := unsafe.Slice((*byte)(unsafe.Pointer(addr)), length)
|
||||||
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b))
|
|
||||||
hdr.Data = unsafe.Pointer(addr)
|
|
||||||
hdr.Cap = length
|
|
||||||
hdr.Len = length
|
|
||||||
|
|
||||||
// Register mapping in m and return it.
|
// Register mapping in m and return it.
|
||||||
p := &b[cap(b)-1]
|
p := &b[cap(b)-1]
|
||||||
@@ -429,11 +423,15 @@ func Send(s int, buf []byte, flags int) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
|
func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
|
||||||
ptr, n, err := to.sockaddr()
|
var ptr unsafe.Pointer
|
||||||
if err != nil {
|
var salen _Socklen
|
||||||
return err
|
if to != nil {
|
||||||
|
ptr, salen, err = to.sockaddr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sendto(fd, p, flags, ptr, n)
|
return sendto(fd, p, flags, ptr, salen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetsockoptByte(fd, level, opt int, value byte) (err error) {
|
func SetsockoptByte(fd, level, opt int, value byte) (err error) {
|
||||||
|
|||||||
+2
-11
@@ -7,11 +7,7 @@
|
|||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
import (
|
import "unsafe"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/internal/unsafeheader"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SysvShmAttach attaches the Sysv shared memory segment associated with the
|
// SysvShmAttach attaches the Sysv shared memory segment associated with the
|
||||||
// shared memory identifier id.
|
// shared memory identifier id.
|
||||||
@@ -34,12 +30,7 @@ func SysvShmAttach(id int, addr uintptr, flag int) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use unsafe to convert addr into a []byte.
|
// Use unsafe to convert addr into a []byte.
|
||||||
// TODO: convert to unsafe.Slice once we can assume Go 1.17
|
b := unsafe.Slice((*byte)(unsafe.Pointer(addr)), int(info.Segsz))
|
||||||
var b []byte
|
|
||||||
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b))
|
|
||||||
hdr.Data = unsafe.Pointer(addr)
|
|
||||||
hdr.Cap = int(info.Segsz)
|
|
||||||
hdr.Len = int(info.Segsz)
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+65
-30
@@ -160,13 +160,12 @@ func Lremovexattr(link string, attr string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Listxattr(file string, dest []byte) (sz int, err error) {
|
func Listxattr(file string, dest []byte) (sz int, err error) {
|
||||||
d := initxattrdest(dest, 0)
|
|
||||||
destsiz := len(dest)
|
destsiz := len(dest)
|
||||||
|
|
||||||
// FreeBSD won't allow you to list xattrs from multiple namespaces
|
// FreeBSD won't allow you to list xattrs from multiple namespaces
|
||||||
s := 0
|
s, pos := 0, 0
|
||||||
for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
||||||
stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
|
stmp, e := ListxattrNS(file, nsid, dest[pos:])
|
||||||
|
|
||||||
/* Errors accessing system attrs are ignored so that
|
/* Errors accessing system attrs are ignored so that
|
||||||
* we can implement the Linux-like behavior of omitting errors that
|
* we can implement the Linux-like behavior of omitting errors that
|
||||||
@@ -175,66 +174,102 @@ func Listxattr(file string, dest []byte) (sz int, err error) {
|
|||||||
* Linux will still error if we ask for user attributes on a file that
|
* Linux will still error if we ask for user attributes on a file that
|
||||||
* we don't have read permissions on, so don't ignore those errors
|
* we don't have read permissions on, so don't ignore those errors
|
||||||
*/
|
*/
|
||||||
if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
if e != nil {
|
||||||
continue
|
if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
||||||
} else if e != nil {
|
continue
|
||||||
|
}
|
||||||
return s, e
|
return s, e
|
||||||
}
|
}
|
||||||
|
|
||||||
s += stmp
|
s += stmp
|
||||||
destsiz -= s
|
pos = s
|
||||||
if destsiz < 0 {
|
if pos > destsiz {
|
||||||
destsiz = 0
|
pos = destsiz
|
||||||
}
|
}
|
||||||
d = initxattrdest(dest, s)
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListxattrNS(file string, nsid int, dest []byte) (sz int, err error) {
|
||||||
|
d := initxattrdest(dest, 0)
|
||||||
|
destsiz := len(dest)
|
||||||
|
|
||||||
|
s, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
|
||||||
|
if e != nil {
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Flistxattr(fd int, dest []byte) (sz int, err error) {
|
func Flistxattr(fd int, dest []byte) (sz int, err error) {
|
||||||
d := initxattrdest(dest, 0)
|
|
||||||
destsiz := len(dest)
|
destsiz := len(dest)
|
||||||
|
|
||||||
s := 0
|
s, pos := 0, 0
|
||||||
for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
||||||
stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
|
stmp, e := FlistxattrNS(fd, nsid, dest[pos:])
|
||||||
if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
|
||||||
continue
|
if e != nil {
|
||||||
} else if e != nil {
|
if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
||||||
|
continue
|
||||||
|
}
|
||||||
return s, e
|
return s, e
|
||||||
}
|
}
|
||||||
|
|
||||||
s += stmp
|
s += stmp
|
||||||
destsiz -= s
|
pos = s
|
||||||
if destsiz < 0 {
|
if pos > destsiz {
|
||||||
destsiz = 0
|
pos = destsiz
|
||||||
}
|
}
|
||||||
d = initxattrdest(dest, s)
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FlistxattrNS(fd int, nsid int, dest []byte) (sz int, err error) {
|
||||||
|
d := initxattrdest(dest, 0)
|
||||||
|
destsiz := len(dest)
|
||||||
|
|
||||||
|
s, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
|
||||||
|
if e != nil {
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Llistxattr(link string, dest []byte) (sz int, err error) {
|
func Llistxattr(link string, dest []byte) (sz int, err error) {
|
||||||
d := initxattrdest(dest, 0)
|
|
||||||
destsiz := len(dest)
|
destsiz := len(dest)
|
||||||
|
|
||||||
s := 0
|
s, pos := 0, 0
|
||||||
for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
||||||
stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
|
stmp, e := LlistxattrNS(link, nsid, dest[pos:])
|
||||||
if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
|
||||||
continue
|
if e != nil {
|
||||||
} else if e != nil {
|
if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
||||||
|
continue
|
||||||
|
}
|
||||||
return s, e
|
return s, e
|
||||||
}
|
}
|
||||||
|
|
||||||
s += stmp
|
s += stmp
|
||||||
destsiz -= s
|
pos = s
|
||||||
if destsiz < 0 {
|
if pos > destsiz {
|
||||||
destsiz = 0
|
pos = destsiz
|
||||||
}
|
}
|
||||||
d = initxattrdest(dest, s)
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LlistxattrNS(link string, nsid int, dest []byte) (sz int, err error) {
|
||||||
|
d := initxattrdest(dest, 0)
|
||||||
|
destsiz := len(dest)
|
||||||
|
|
||||||
|
s, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
|
||||||
|
if e != nil {
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
|
|||||||
+1
@@ -2940,6 +2940,7 @@ const (
|
|||||||
SOL_RAW = 0xff
|
SOL_RAW = 0xff
|
||||||
SOL_RDS = 0x114
|
SOL_RDS = 0x114
|
||||||
SOL_RXRPC = 0x110
|
SOL_RXRPC = 0x110
|
||||||
|
SOL_SMC = 0x11e
|
||||||
SOL_TCP = 0x6
|
SOL_TCP = 0x6
|
||||||
SOL_TIPC = 0x10f
|
SOL_TIPC = 0x10f
|
||||||
SOL_TLS = 0x11a
|
SOL_TLS = 0x11a
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include -m32
|
// mkerrors.sh -Wall -Werror -static -I/tmp/386/include -m32
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build 386 && linux
|
//go:build 386 && linux
|
||||||
// +build 386,linux
|
// +build 386,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/386/include -m32 _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include -m64
|
// mkerrors.sh -Wall -Werror -static -I/tmp/amd64/include -m64
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build amd64 && linux
|
//go:build amd64 && linux
|
||||||
// +build amd64,linux
|
// +build amd64,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/amd64/include -m64 _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/arm/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build arm && linux
|
//go:build arm && linux
|
||||||
// +build arm,linux
|
// +build arm,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/arm/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include -fsigned-char
|
// mkerrors.sh -Wall -Werror -static -I/tmp/arm64/include -fsigned-char
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build arm64 && linux
|
//go:build arm64 && linux
|
||||||
// +build arm64,linux
|
// +build arm64,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/arm64/include -fsigned-char _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/loong64/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build loong64 && linux
|
//go:build loong64 && linux
|
||||||
// +build loong64,linux
|
// +build loong64,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/loong64/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/mips/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build mips && linux
|
//go:build mips && linux
|
||||||
// +build mips,linux
|
// +build mips,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/mips/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/mips64/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build mips64 && linux
|
//go:build mips64 && linux
|
||||||
// +build mips64,linux
|
// +build mips64,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/mips64/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/mips64le/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build mips64le && linux
|
//go:build mips64le && linux
|
||||||
// +build mips64le,linux
|
// +build mips64le,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/mips64le/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/mipsle/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build mipsle && linux
|
//go:build mipsle && linux
|
||||||
// +build mipsle,linux
|
// +build mipsle,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/mipsle/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/ppc/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build ppc && linux
|
//go:build ppc && linux
|
||||||
// +build ppc,linux
|
// +build ppc,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/ppc/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/ppc64/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build ppc64 && linux
|
//go:build ppc64 && linux
|
||||||
// +build ppc64,linux
|
// +build ppc64,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/ppc64/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/ppc64le/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build ppc64le && linux
|
//go:build ppc64le && linux
|
||||||
// +build ppc64le,linux
|
// +build ppc64le,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/ppc64le/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/riscv64/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build riscv64 && linux
|
//go:build riscv64 && linux
|
||||||
// +build riscv64,linux
|
// +build riscv64,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/riscv64/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include -fsigned-char
|
// mkerrors.sh -Wall -Werror -static -I/tmp/s390x/include -fsigned-char
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build s390x && linux
|
//go:build s390x && linux
|
||||||
// +build s390x,linux
|
// +build s390x,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/s390x/include -fsigned-char _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
// mkerrors.sh -Wall -Werror -static -I/tmp/include
|
// mkerrors.sh -Wall -Werror -static -I/tmp/sparc64/include
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build sparc64 && linux
|
//go:build sparc64 && linux
|
||||||
// +build sparc64,linux
|
// +build sparc64,linux
|
||||||
|
|
||||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
// cgo -godefs -- -Wall -Werror -static -I/tmp/sparc64/include _const.go
|
||||||
|
|
||||||
package unix
|
package unix
|
||||||
|
|
||||||
|
|||||||
-40
@@ -1,40 +0,0 @@
|
|||||||
// go run mksyscall.go -tags darwin,amd64,go1.13 syscall_darwin.1_13.go
|
|
||||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
|
||||||
|
|
||||||
//go:build darwin && amd64 && go1.13
|
|
||||||
// +build darwin,amd64,go1.13
|
|
||||||
|
|
||||||
package unix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ syscall.Errno
|
|
||||||
|
|
||||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
|
||||||
|
|
||||||
func closedir(dir uintptr) (err error) {
|
|
||||||
_, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0)
|
|
||||||
if e1 != 0 {
|
|
||||||
err = errnoErr(e1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var libc_closedir_trampoline_addr uintptr
|
|
||||||
|
|
||||||
//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib"
|
|
||||||
|
|
||||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
|
||||||
|
|
||||||
func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) {
|
|
||||||
r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result)))
|
|
||||||
res = Errno(r0)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var libc_readdir_r_trampoline_addr uintptr
|
|
||||||
|
|
||||||
//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib"
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user