go.mod: runc v1.0.0
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
		 Akihiro Suda
					Akihiro Suda
				
			
				
					committed by
					
						 Davanum Srinivas
						Davanum Srinivas
					
				
			
			
				
	
			
			
			 Davanum Srinivas
						Davanum Srinivas
					
				
			
						parent
						
							28bb59c080
						
					
				
				
					commit
					f913a42755
				
			
							
								
								
									
										21
									
								
								vendor/github.com/cilium/ebpf/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/cilium/ebpf/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -18,6 +18,23 @@ reason about the proposed changes. | ||||
| ## Running the tests | ||||
|  | ||||
| Many of the tests require privileges to set resource limits and load eBPF code. | ||||
| The easiest way to obtain these is to run the tests with `sudo`: | ||||
| The easiest way to obtain these is to run the tests with `sudo`. | ||||
|  | ||||
| To test the current package with your local kernel you can simply run: | ||||
| ``` | ||||
| go test -exec sudo  ./... | ||||
| ``` | ||||
|  | ||||
| To test the current package with a different kernel version you can use the [run-tests.sh](run-tests.sh) script. | ||||
| It requires [virtme](https://github.com/amluto/virtme) and qemu to be installed. | ||||
|  | ||||
| Examples: | ||||
|  | ||||
| ```bash | ||||
| # Run all tests on a 5.4 kernel | ||||
| ./run-tests.sh 5.4 | ||||
|  | ||||
| # Run a subset of tests: | ||||
| ./run-tests.sh 5.4 go test ./link | ||||
| ``` | ||||
|  | ||||
|     sudo go test ./... | ||||
							
								
								
									
										7
									
								
								vendor/github.com/cilium/ebpf/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/cilium/ebpf/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| # The development version of clang is distributed as the 'clang' binary, | ||||
| # while stable/released versions have a version number attached. | ||||
| # Pin the default clang to a stable version. | ||||
| CLANG ?= clang-11 | ||||
| CLANG ?= clang-12 | ||||
| CFLAGS := -target bpf -O2 -g -Wall -Werror $(CFLAGS) | ||||
|  | ||||
| # Obtain an absolute path to the directory of the Makefile. | ||||
| @@ -17,7 +17,7 @@ VERSION := $(shell cat ${REPODIR}/testdata/docker/VERSION) | ||||
| TARGETS := \ | ||||
| 	testdata/loader-clang-7 \ | ||||
| 	testdata/loader-clang-9 \ | ||||
| 	testdata/loader-clang-11 \ | ||||
| 	testdata/loader-$(CLANG) \ | ||||
| 	testdata/invalid_map \ | ||||
| 	testdata/raw_tracepoint \ | ||||
| 	testdata/invalid_map_static \ | ||||
| @@ -33,6 +33,7 @@ TARGETS := \ | ||||
| docker-all: | ||||
| 	docker run --rm --user "${UIDGID}" \ | ||||
| 		-v "${REPODIR}":/ebpf -w /ebpf --env MAKEFLAGS \ | ||||
| 		--env CFLAGS="-fdebug-prefix-map=/ebpf=." \ | ||||
| 		"${IMAGE}:${VERSION}" \ | ||||
| 		make all | ||||
|  | ||||
| @@ -47,6 +48,8 @@ clean: | ||||
| 	-$(RM) internal/btf/testdata/*.elf | ||||
|  | ||||
| all: $(addsuffix -el.elf,$(TARGETS)) $(addsuffix -eb.elf,$(TARGETS)) | ||||
| 	ln -srf testdata/loader-$(CLANG)-el.elf testdata/loader-el.elf | ||||
| 	ln -srf testdata/loader-$(CLANG)-eb.elf testdata/loader-eb.elf | ||||
|  | ||||
| testdata/loader-%-el.elf: testdata/loader.c | ||||
| 	$* $(CFLAGS) -mlittle-endian -c $< -o $@ | ||||
|   | ||||
							
								
								
									
										32
									
								
								vendor/github.com/cilium/ebpf/asm/instruction.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								vendor/github.com/cilium/ebpf/asm/instruction.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -57,7 +57,7 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err | ||||
| 		return 0, fmt.Errorf("can't unmarshal registers: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	if !bi.OpCode.isDWordLoad() { | ||||
| 	if !bi.OpCode.IsDWordLoad() { | ||||
| 		return InstructionSize, nil | ||||
| 	} | ||||
|  | ||||
| @@ -80,7 +80,7 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error) | ||||
| 		return 0, errors.New("invalid opcode") | ||||
| 	} | ||||
|  | ||||
| 	isDWordLoad := ins.OpCode.isDWordLoad() | ||||
| 	isDWordLoad := ins.OpCode.IsDWordLoad() | ||||
|  | ||||
| 	cons := int32(ins.Constant) | ||||
| 	if isDWordLoad { | ||||
| @@ -123,7 +123,7 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error) | ||||
| // | ||||
| // Returns an error if the instruction doesn't load a map. | ||||
| func (ins *Instruction) RewriteMapPtr(fd int) error { | ||||
| 	if !ins.OpCode.isDWordLoad() { | ||||
| 	if !ins.OpCode.IsDWordLoad() { | ||||
| 		return fmt.Errorf("%s is not a 64 bit load", ins.OpCode) | ||||
| 	} | ||||
|  | ||||
| @@ -138,15 +138,19 @@ func (ins *Instruction) RewriteMapPtr(fd int) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (ins *Instruction) mapPtr() uint32 { | ||||
| 	return uint32(uint64(ins.Constant) & math.MaxUint32) | ||||
| // MapPtr returns the map fd for this instruction. | ||||
| // | ||||
| // The result is undefined if the instruction is not a load from a map, | ||||
| // see IsLoadFromMap. | ||||
| func (ins *Instruction) MapPtr() int { | ||||
| 	return int(int32(uint64(ins.Constant) & math.MaxUint32)) | ||||
| } | ||||
|  | ||||
| // RewriteMapOffset changes the offset of a direct load from a map. | ||||
| // | ||||
| // Returns an error if the instruction is not a direct load. | ||||
| func (ins *Instruction) RewriteMapOffset(offset uint32) error { | ||||
| 	if !ins.OpCode.isDWordLoad() { | ||||
| 	if !ins.OpCode.IsDWordLoad() { | ||||
| 		return fmt.Errorf("%s is not a 64 bit load", ins.OpCode) | ||||
| 	} | ||||
|  | ||||
| @@ -163,10 +167,10 @@ func (ins *Instruction) mapOffset() uint32 { | ||||
| 	return uint32(uint64(ins.Constant) >> 32) | ||||
| } | ||||
|  | ||||
| // isLoadFromMap returns true if the instruction loads from a map. | ||||
| // IsLoadFromMap returns true if the instruction loads from a map. | ||||
| // | ||||
| // This covers both loading the map pointer and direct map value loads. | ||||
| func (ins *Instruction) isLoadFromMap() bool { | ||||
| func (ins *Instruction) IsLoadFromMap() bool { | ||||
| 	return ins.OpCode == LoadImmOp(DWord) && (ins.Src == PseudoMapFD || ins.Src == PseudoMapValue) | ||||
| } | ||||
|  | ||||
| @@ -177,6 +181,12 @@ func (ins *Instruction) IsFunctionCall() bool { | ||||
| 	return ins.OpCode.JumpOp() == Call && ins.Src == PseudoCall | ||||
| } | ||||
|  | ||||
| // IsConstantLoad returns true if the instruction loads a constant of the | ||||
| // given size. | ||||
| func (ins *Instruction) IsConstantLoad(size Size) bool { | ||||
| 	return ins.OpCode == LoadImmOp(size) && ins.Src == R0 && ins.Offset == 0 | ||||
| } | ||||
|  | ||||
| // Format implements fmt.Formatter. | ||||
| func (ins Instruction) Format(f fmt.State, c rune) { | ||||
| 	if c != 'v' { | ||||
| @@ -197,8 +207,8 @@ func (ins Instruction) Format(f fmt.State, c rune) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if ins.isLoadFromMap() { | ||||
| 		fd := int32(ins.mapPtr()) | ||||
| 	if ins.IsLoadFromMap() { | ||||
| 		fd := ins.MapPtr() | ||||
| 		switch ins.Src { | ||||
| 		case PseudoMapFD: | ||||
| 			fmt.Fprintf(f, "LoadMapPtr dst: %s fd: %d", ins.Dst, fd) | ||||
| @@ -403,7 +413,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error { | ||||
| func (insns Instructions) Tag(bo binary.ByteOrder) (string, error) { | ||||
| 	h := sha1.New() | ||||
| 	for i, ins := range insns { | ||||
| 		if ins.isLoadFromMap() { | ||||
| 		if ins.IsLoadFromMap() { | ||||
| 			ins.Constant = 0 | ||||
| 		} | ||||
| 		_, err := ins.Marshal(h, bo) | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/cilium/ebpf/asm/load_store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/cilium/ebpf/asm/load_store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -111,7 +111,7 @@ func LoadMapPtr(dst Register, fd int) Instruction { | ||||
| 		OpCode:   LoadImmOp(DWord), | ||||
| 		Dst:      dst, | ||||
| 		Src:      PseudoMapFD, | ||||
| 		Constant: int64(fd), | ||||
| 		Constant: int64(uint32(fd)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/cilium/ebpf/asm/opcode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/cilium/ebpf/asm/opcode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -69,13 +69,13 @@ const InvalidOpCode OpCode = 0xff | ||||
| // rawInstructions returns the number of BPF instructions required | ||||
| // to encode this opcode. | ||||
| func (op OpCode) rawInstructions() int { | ||||
| 	if op.isDWordLoad() { | ||||
| 	if op.IsDWordLoad() { | ||||
| 		return 2 | ||||
| 	} | ||||
| 	return 1 | ||||
| } | ||||
|  | ||||
| func (op OpCode) isDWordLoad() bool { | ||||
| func (op OpCode) IsDWordLoad() bool { | ||||
| 	return op == LoadImmOp(DWord) | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										59
									
								
								vendor/github.com/cilium/ebpf/collection.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/cilium/ebpf/collection.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,6 +3,7 @@ package ebpf | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| @@ -89,8 +90,8 @@ func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error { | ||||
| // | ||||
| // The constant must be defined like so in the C program: | ||||
| // | ||||
| //    static volatile const type foobar; | ||||
| //    static volatile const type foobar = default; | ||||
| //    volatile const type foobar; | ||||
| //    volatile const type foobar = default; | ||||
| // | ||||
| // Replacement values must be of the same length as the C sizeof(type). | ||||
| // If necessary, they are marshalled according to the same rules as | ||||
| @@ -269,11 +270,21 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Co | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| type btfHandleCache map[*btf.Spec]*btf.Handle | ||||
| type handleCache struct { | ||||
| 	btfHandles map[*btf.Spec]*btf.Handle | ||||
| 	btfSpecs   map[io.ReaderAt]*btf.Spec | ||||
| } | ||||
|  | ||||
| func (btfs btfHandleCache) load(spec *btf.Spec) (*btf.Handle, error) { | ||||
| 	if btfs[spec] != nil { | ||||
| 		return btfs[spec], nil | ||||
| func newHandleCache() *handleCache { | ||||
| 	return &handleCache{ | ||||
| 		btfHandles: make(map[*btf.Spec]*btf.Handle), | ||||
| 		btfSpecs:   make(map[io.ReaderAt]*btf.Spec), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (hc handleCache) btfHandle(spec *btf.Spec) (*btf.Handle, error) { | ||||
| 	if hc.btfHandles[spec] != nil { | ||||
| 		return hc.btfHandles[spec], nil | ||||
| 	} | ||||
|  | ||||
| 	handle, err := btf.NewHandle(spec) | ||||
| @@ -281,14 +292,30 @@ func (btfs btfHandleCache) load(spec *btf.Spec) (*btf.Handle, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	btfs[spec] = handle | ||||
| 	hc.btfHandles[spec] = handle | ||||
| 	return handle, nil | ||||
| } | ||||
|  | ||||
| func (btfs btfHandleCache) close() { | ||||
| 	for _, handle := range btfs { | ||||
| func (hc handleCache) btfSpec(rd io.ReaderAt) (*btf.Spec, error) { | ||||
| 	if hc.btfSpecs[rd] != nil { | ||||
| 		return hc.btfSpecs[rd], nil | ||||
| 	} | ||||
|  | ||||
| 	spec, err := btf.LoadSpecFromReader(rd) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	hc.btfSpecs[rd] = spec | ||||
| 	return spec, nil | ||||
| } | ||||
|  | ||||
| func (hc handleCache) close() { | ||||
| 	for _, handle := range hc.btfHandles { | ||||
| 		handle.Close() | ||||
| 	} | ||||
| 	hc.btfHandles = nil | ||||
| 	hc.btfSpecs = nil | ||||
| } | ||||
|  | ||||
| func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) ( | ||||
| @@ -300,12 +327,12 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) ( | ||||
| 	var ( | ||||
| 		maps             = make(map[string]*Map) | ||||
| 		progs            = make(map[string]*Program) | ||||
| 		btfs             = make(btfHandleCache) | ||||
| 		handles          = newHandleCache() | ||||
| 		skipMapsAndProgs = false | ||||
| 	) | ||||
|  | ||||
| 	cleanup = func() { | ||||
| 		btfs.close() | ||||
| 		handles.close() | ||||
|  | ||||
| 		if skipMapsAndProgs { | ||||
| 			return | ||||
| @@ -335,7 +362,7 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) ( | ||||
| 			return nil, fmt.Errorf("missing map %s", mapName) | ||||
| 		} | ||||
|  | ||||
| 		m, err := newMapWithOptions(mapSpec, opts.Maps, btfs) | ||||
| 		m, err := newMapWithOptions(mapSpec, opts.Maps, handles) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("map %s: %w", mapName, err) | ||||
| 		} | ||||
| @@ -360,7 +387,7 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) ( | ||||
| 		for i := range progSpec.Instructions { | ||||
| 			ins := &progSpec.Instructions[i] | ||||
|  | ||||
| 			if ins.OpCode != asm.LoadImmOp(asm.DWord) || ins.Reference == "" { | ||||
| 			if !ins.IsLoadFromMap() || ins.Reference == "" { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| @@ -372,7 +399,7 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) ( | ||||
|  | ||||
| 			m, err := loadMap(ins.Reference) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("program %s: %s", progName, err) | ||||
| 				return nil, fmt.Errorf("program %s: %w", progName, err) | ||||
| 			} | ||||
|  | ||||
| 			fd := m.FD() | ||||
| @@ -384,7 +411,7 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) ( | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		prog, err := newProgramWithOptions(progSpec, opts.Programs, btfs) | ||||
| 		prog, err := newProgramWithOptions(progSpec, opts.Programs, handles) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("program %s: %w", progName, err) | ||||
| 		} | ||||
| @@ -534,7 +561,7 @@ func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Va | ||||
| 			} | ||||
|  | ||||
| 			if err != nil { | ||||
| 				return fmt.Errorf("field %s: %s", field.Name, err) | ||||
| 				return fmt.Errorf("field %s: %w", field.Name, err) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|   | ||||
							
								
								
									
										47
									
								
								vendor/github.com/cilium/ebpf/elf_reader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								vendor/github.com/cilium/ebpf/elf_reader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -96,7 +96,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { | ||||
| 	} | ||||
|  | ||||
| 	btfSpec, err := btf.LoadSpecFromReader(rd) | ||||
| 	if err != nil { | ||||
| 	if err != nil && !errors.Is(err, btf.ErrNotFound) { | ||||
| 		return nil, fmt.Errorf("load BTF: %w", err) | ||||
| 	} | ||||
|  | ||||
| @@ -159,7 +159,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { | ||||
| 			} | ||||
|  | ||||
| 			if target.Flags&elf.SHF_STRINGS > 0 { | ||||
| 				return nil, fmt.Errorf("section %q: string %q is not stack allocated: %w", section.Name, rel.Name, ErrNotSupported) | ||||
| 				return nil, fmt.Errorf("section %q: string is not stack allocated: %w", section.Name, ErrNotSupported) | ||||
| 			} | ||||
|  | ||||
| 			target.references++ | ||||
| @@ -374,17 +374,25 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err | ||||
| 		} | ||||
|  | ||||
| 	case dataSection: | ||||
| 		var offset uint32 | ||||
| 		switch typ { | ||||
| 		case elf.STT_SECTION: | ||||
| 			if bind != elf.STB_LOCAL { | ||||
| 				return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind) | ||||
| 			} | ||||
|  | ||||
| 			// This is really a reference to a static symbol, which clang doesn't | ||||
| 			// emit a symbol table entry for. Instead it encodes the offset in | ||||
| 			// the instruction itself. | ||||
| 			offset = uint32(uint64(ins.Constant)) | ||||
|  | ||||
| 		case elf.STT_OBJECT: | ||||
| 			if bind != elf.STB_GLOBAL { | ||||
| 				return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind) | ||||
| 			} | ||||
|  | ||||
| 			offset = uint32(rel.Value) | ||||
|  | ||||
| 		default: | ||||
| 			return fmt.Errorf("incorrect relocation type %v for direct map load", typ) | ||||
| 		} | ||||
| @@ -394,10 +402,8 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err | ||||
| 		// it's not clear how to encode that into Instruction. | ||||
| 		name = target.Name | ||||
|  | ||||
| 		// For some reason, clang encodes the offset of the symbol its | ||||
| 		// section in the first basic BPF instruction, while the kernel | ||||
| 		// expects it in the second one. | ||||
| 		ins.Constant <<= 32 | ||||
| 		// The kernel expects the offset in the second basic BPF instruction. | ||||
| 		ins.Constant = int64(uint64(offset) << 32) | ||||
| 		ins.Src = asm.PseudoMapValue | ||||
|  | ||||
| 		// Mark the instruction as needing an update when creating the | ||||
| @@ -491,33 +497,38 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error { | ||||
| 				return fmt.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset) | ||||
| 			} | ||||
|  | ||||
| 			if maps[mapSym.Name] != nil { | ||||
| 			mapName := mapSym.Name | ||||
| 			if maps[mapName] != nil { | ||||
| 				return fmt.Errorf("section %v: map %v already exists", sec.Name, mapSym) | ||||
| 			} | ||||
|  | ||||
| 			lr := io.LimitReader(r, int64(size)) | ||||
|  | ||||
| 			spec := MapSpec{ | ||||
| 				Name: SanitizeName(mapSym.Name, -1), | ||||
| 				Name: SanitizeName(mapName, -1), | ||||
| 			} | ||||
| 			switch { | ||||
| 			case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil: | ||||
| 				return fmt.Errorf("map %v: missing type", mapSym) | ||||
| 				return fmt.Errorf("map %s: missing type", mapName) | ||||
| 			case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil: | ||||
| 				return fmt.Errorf("map %v: missing key size", mapSym) | ||||
| 				return fmt.Errorf("map %s: missing key size", mapName) | ||||
| 			case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil: | ||||
| 				return fmt.Errorf("map %v: missing value size", mapSym) | ||||
| 				return fmt.Errorf("map %s: missing value size", mapName) | ||||
| 			case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil: | ||||
| 				return fmt.Errorf("map %v: missing max entries", mapSym) | ||||
| 				return fmt.Errorf("map %s: missing max entries", mapName) | ||||
| 			case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil: | ||||
| 				return fmt.Errorf("map %v: missing flags", mapSym) | ||||
| 				return fmt.Errorf("map %s: missing flags", mapName) | ||||
| 			} | ||||
|  | ||||
| 			if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil { | ||||
| 				return fmt.Errorf("map %v: unknown and non-zero fields in definition", mapSym) | ||||
| 				return fmt.Errorf("map %s: unknown and non-zero fields in definition", mapName) | ||||
| 			} | ||||
|  | ||||
| 			maps[mapSym.Name] = &spec | ||||
| 			if err := spec.clampPerfEventArraySize(); err != nil { | ||||
| 				return fmt.Errorf("map %s: %w", mapName, err) | ||||
| 			} | ||||
|  | ||||
| 			maps[mapName] = &spec | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -565,6 +576,10 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error { | ||||
| 				return fmt.Errorf("map %v: %w", name, err) | ||||
| 			} | ||||
|  | ||||
| 			if err := mapSpec.clampPerfEventArraySize(); err != nil { | ||||
| 				return fmt.Errorf("map %v: %w", name, err) | ||||
| 			} | ||||
|  | ||||
| 			maps[name] = mapSpec | ||||
| 		} | ||||
| 	} | ||||
| @@ -847,6 +862,8 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) { | ||||
| 		"uretprobe/":            {Kprobe, AttachNone, 0}, | ||||
| 		"tracepoint/":           {TracePoint, AttachNone, 0}, | ||||
| 		"raw_tracepoint/":       {RawTracepoint, AttachNone, 0}, | ||||
| 		"raw_tp/":               {RawTracepoint, AttachNone, 0}, | ||||
| 		"tp_btf/":               {Tracing, AttachTraceRawTp, 0}, | ||||
| 		"xdp":                   {XDP, AttachNone, 0}, | ||||
| 		"perf_event":            {PerfEvent, AttachNone, 0}, | ||||
| 		"lwt_in":                {LWTIn, AttachNone, 0}, | ||||
|   | ||||
							
								
								
									
										28
									
								
								vendor/github.com/cilium/ebpf/internal/btf/btf.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/cilium/ebpf/internal/btf/btf.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -35,7 +35,7 @@ type Spec struct { | ||||
| 	namedTypes map[string][]namedType | ||||
| 	funcInfos  map[string]extInfo | ||||
| 	lineInfos  map[string]extInfo | ||||
| 	coreRelos  map[string]bpfCoreRelos | ||||
| 	coreRelos  map[string]coreRelos | ||||
| 	byteOrder  binary.ByteOrder | ||||
| } | ||||
|  | ||||
| @@ -53,7 +53,7 @@ type btfHeader struct { | ||||
|  | ||||
| // LoadSpecFromReader reads BTF sections from an ELF. | ||||
| // | ||||
| // Returns a nil Spec and no error if no BTF was present. | ||||
| // Returns ErrNotFound if the reader contains no BTF. | ||||
| func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { | ||||
| 	file, err := internal.NewSafeELFFile(rd) | ||||
| 	if err != nil { | ||||
| @@ -67,7 +67,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { | ||||
| 	} | ||||
|  | ||||
| 	if btfSection == nil { | ||||
| 		return nil, nil | ||||
| 		return nil, fmt.Errorf("btf: %w", ErrNotFound) | ||||
| 	} | ||||
|  | ||||
| 	symbols, err := file.Symbols() | ||||
| @@ -438,13 +438,13 @@ func (s *Spec) Program(name string, length uint64) (*Program, error) { | ||||
|  | ||||
| 	funcInfos, funcOK := s.funcInfos[name] | ||||
| 	lineInfos, lineOK := s.lineInfos[name] | ||||
| 	coreRelos, coreOK := s.coreRelos[name] | ||||
| 	relos, coreOK := s.coreRelos[name] | ||||
|  | ||||
| 	if !funcOK && !lineOK && !coreOK { | ||||
| 		return nil, fmt.Errorf("no extended BTF info for section %s", name) | ||||
| 	} | ||||
|  | ||||
| 	return &Program{s, length, funcInfos, lineInfos, coreRelos}, nil | ||||
| 	return &Program{s, length, funcInfos, lineInfos, relos}, nil | ||||
| } | ||||
|  | ||||
| // Datasec returns the BTF required to create maps which represent data sections. | ||||
| @@ -491,7 +491,8 @@ func (s *Spec) FindType(name string, typ Type) error { | ||||
| 		return fmt.Errorf("type %s: %w", name, ErrNotFound) | ||||
| 	} | ||||
|  | ||||
| 	value := reflect.Indirect(reflect.ValueOf(copyType(candidate))) | ||||
| 	cpy, _ := copyType(candidate, nil) | ||||
| 	value := reflect.Indirect(reflect.ValueOf(cpy)) | ||||
| 	reflect.Indirect(reflect.ValueOf(typ)).Set(value) | ||||
| 	return nil | ||||
| } | ||||
| @@ -606,7 +607,7 @@ type Program struct { | ||||
| 	spec                 *Spec | ||||
| 	length               uint64 | ||||
| 	funcInfos, lineInfos extInfo | ||||
| 	coreRelos            bpfCoreRelos | ||||
| 	coreRelos            coreRelos | ||||
| } | ||||
|  | ||||
| // ProgramSpec returns the Spec needed for loading function and line infos into the kernel. | ||||
| @@ -665,16 +666,23 @@ func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) { | ||||
| 	return s.lineInfos.recordSize, bytes, nil | ||||
| } | ||||
|  | ||||
| // ProgramRelocations returns the CO-RE relocations required to adjust the | ||||
| // program to the target. | ||||
| // ProgramFixups returns the changes required to adjust the program to the target. | ||||
| // | ||||
| // This is a free function instead of a method to hide it from users | ||||
| // of package ebpf. | ||||
| func ProgramRelocations(s *Program, target *Spec) (map[uint64]Relocation, error) { | ||||
| func ProgramFixups(s *Program, target *Spec) (COREFixups, error) { | ||||
| 	if len(s.coreRelos) == 0 { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	if target == nil { | ||||
| 		var err error | ||||
| 		target, err = LoadKernelSpec() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return coreRelocate(s.spec, target, s.coreRelos) | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										795
									
								
								vendor/github.com/cilium/ebpf/internal/btf/core.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										795
									
								
								vendor/github.com/cilium/ebpf/internal/btf/core.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,43 +3,160 @@ package btf | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/cilium/ebpf/asm" | ||||
| ) | ||||
|  | ||||
| // Code in this file is derived from libbpf, which is available under a BSD | ||||
| // 2-Clause license. | ||||
|  | ||||
| // Relocation describes a CO-RE relocation. | ||||
| type Relocation struct { | ||||
| 	Current uint32 | ||||
| 	New     uint32 | ||||
| // COREFixup is the result of computing a CO-RE relocation for a target. | ||||
| type COREFixup struct { | ||||
| 	Kind   COREKind | ||||
| 	Local  uint32 | ||||
| 	Target uint32 | ||||
| 	Poison bool | ||||
| } | ||||
|  | ||||
| func (r Relocation) equal(other Relocation) bool { | ||||
| 	return r.Current == other.Current && r.New == other.New | ||||
| func (f COREFixup) equal(other COREFixup) bool { | ||||
| 	return f.Local == other.Local && f.Target == other.Target | ||||
| } | ||||
|  | ||||
| // coreReloKind is the type of CO-RE relocation | ||||
| type coreReloKind uint32 | ||||
| func (f COREFixup) String() string { | ||||
| 	if f.Poison { | ||||
| 		return fmt.Sprintf("%s=poison", f.Kind) | ||||
| 	} | ||||
| 	return fmt.Sprintf("%s=%d->%d", f.Kind, f.Local, f.Target) | ||||
| } | ||||
|  | ||||
| func (f COREFixup) apply(ins *asm.Instruction) error { | ||||
| 	if f.Poison { | ||||
| 		return errors.New("can't poison individual instruction") | ||||
| 	} | ||||
|  | ||||
| 	switch class := ins.OpCode.Class(); class { | ||||
| 	case asm.LdXClass, asm.StClass, asm.StXClass: | ||||
| 		if want := int16(f.Local); want != ins.Offset { | ||||
| 			return fmt.Errorf("invalid offset %d, expected %d", ins.Offset, want) | ||||
| 		} | ||||
|  | ||||
| 		if f.Target > math.MaxInt16 { | ||||
| 			return fmt.Errorf("offset %d exceeds MaxInt16", f.Target) | ||||
| 		} | ||||
|  | ||||
| 		ins.Offset = int16(f.Target) | ||||
|  | ||||
| 	case asm.LdClass: | ||||
| 		if !ins.IsConstantLoad(asm.DWord) { | ||||
| 			return fmt.Errorf("not a dword-sized immediate load") | ||||
| 		} | ||||
|  | ||||
| 		if want := int64(f.Local); want != ins.Constant { | ||||
| 			return fmt.Errorf("invalid immediate %d, expected %d", ins.Constant, want) | ||||
| 		} | ||||
|  | ||||
| 		ins.Constant = int64(f.Target) | ||||
|  | ||||
| 	case asm.ALUClass: | ||||
| 		if ins.OpCode.ALUOp() == asm.Swap { | ||||
| 			return fmt.Errorf("relocation against swap") | ||||
| 		} | ||||
|  | ||||
| 		fallthrough | ||||
|  | ||||
| 	case asm.ALU64Class: | ||||
| 		if src := ins.OpCode.Source(); src != asm.ImmSource { | ||||
| 			return fmt.Errorf("invalid source %s", src) | ||||
| 		} | ||||
|  | ||||
| 		if want := int64(f.Local); want != ins.Constant { | ||||
| 			return fmt.Errorf("invalid immediate %d, expected %d", ins.Constant, want) | ||||
| 		} | ||||
|  | ||||
| 		if f.Target > math.MaxInt32 { | ||||
| 			return fmt.Errorf("immediate %d exceeds MaxInt32", f.Target) | ||||
| 		} | ||||
|  | ||||
| 		ins.Constant = int64(f.Target) | ||||
|  | ||||
| 	default: | ||||
| 		return fmt.Errorf("invalid class %s", class) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (f COREFixup) isNonExistant() bool { | ||||
| 	return f.Kind.checksForExistence() && f.Target == 0 | ||||
| } | ||||
|  | ||||
| type COREFixups map[uint64]COREFixup | ||||
|  | ||||
| // Apply a set of CO-RE relocations to a BPF program. | ||||
| func (fs COREFixups) Apply(insns asm.Instructions) (asm.Instructions, error) { | ||||
| 	if len(fs) == 0 { | ||||
| 		cpy := make(asm.Instructions, len(insns)) | ||||
| 		copy(cpy, insns) | ||||
| 		return insns, nil | ||||
| 	} | ||||
|  | ||||
| 	cpy := make(asm.Instructions, 0, len(insns)) | ||||
| 	iter := insns.Iterate() | ||||
| 	for iter.Next() { | ||||
| 		fixup, ok := fs[iter.Offset.Bytes()] | ||||
| 		if !ok { | ||||
| 			cpy = append(cpy, *iter.Ins) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		ins := *iter.Ins | ||||
| 		if fixup.Poison { | ||||
| 			const badRelo = asm.BuiltinFunc(0xbad2310) | ||||
|  | ||||
| 			cpy = append(cpy, badRelo.Call()) | ||||
| 			if ins.OpCode.IsDWordLoad() { | ||||
| 				// 64 bit constant loads occupy two raw bpf instructions, so | ||||
| 				// we need to add another instruction as padding. | ||||
| 				cpy = append(cpy, badRelo.Call()) | ||||
| 			} | ||||
|  | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if err := fixup.apply(&ins); err != nil { | ||||
| 			return nil, fmt.Errorf("instruction %d, offset %d: %s: %w", iter.Index, iter.Offset.Bytes(), fixup.Kind, err) | ||||
| 		} | ||||
|  | ||||
| 		cpy = append(cpy, ins) | ||||
| 	} | ||||
|  | ||||
| 	return cpy, nil | ||||
| } | ||||
|  | ||||
| // COREKind is the type of CO-RE relocation | ||||
| type COREKind uint32 | ||||
|  | ||||
| const ( | ||||
| 	reloFieldByteOffset coreReloKind = iota /* field byte offset */ | ||||
| 	reloFieldByteSize                       /* field size in bytes */ | ||||
| 	reloFieldExists                         /* field existence in target kernel */ | ||||
| 	reloFieldSigned                         /* field signedness (0 - unsigned, 1 - signed) */ | ||||
| 	reloFieldLShiftU64                      /* bitfield-specific left bitshift */ | ||||
| 	reloFieldRShiftU64                      /* bitfield-specific right bitshift */ | ||||
| 	reloTypeIDLocal                         /* type ID in local BPF object */ | ||||
| 	reloTypeIDTarget                        /* type ID in target kernel */ | ||||
| 	reloTypeExists                          /* type existence in target kernel */ | ||||
| 	reloTypeSize                            /* type size in bytes */ | ||||
| 	reloEnumvalExists                       /* enum value existence in target kernel */ | ||||
| 	reloEnumvalValue                        /* enum value integer value */ | ||||
| 	reloFieldByteOffset COREKind = iota /* field byte offset */ | ||||
| 	reloFieldByteSize                   /* field size in bytes */ | ||||
| 	reloFieldExists                     /* field existence in target kernel */ | ||||
| 	reloFieldSigned                     /* field signedness (0 - unsigned, 1 - signed) */ | ||||
| 	reloFieldLShiftU64                  /* bitfield-specific left bitshift */ | ||||
| 	reloFieldRShiftU64                  /* bitfield-specific right bitshift */ | ||||
| 	reloTypeIDLocal                     /* type ID in local BPF object */ | ||||
| 	reloTypeIDTarget                    /* type ID in target kernel */ | ||||
| 	reloTypeExists                      /* type existence in target kernel */ | ||||
| 	reloTypeSize                        /* type size in bytes */ | ||||
| 	reloEnumvalExists                   /* enum value existence in target kernel */ | ||||
| 	reloEnumvalValue                    /* enum value integer value */ | ||||
| ) | ||||
|  | ||||
| func (k coreReloKind) String() string { | ||||
| func (k COREKind) String() string { | ||||
| 	switch k { | ||||
| 	case reloFieldByteOffset: | ||||
| 		return "byte_off" | ||||
| @@ -70,103 +187,249 @@ func (k coreReloKind) String() string { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func coreRelocate(local, target *Spec, coreRelos bpfCoreRelos) (map[uint64]Relocation, error) { | ||||
| 	if target == nil { | ||||
| 		var err error | ||||
| 		target, err = loadKernelSpec() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| func (k COREKind) checksForExistence() bool { | ||||
| 	return k == reloEnumvalExists || k == reloTypeExists || k == reloFieldExists | ||||
| } | ||||
|  | ||||
| func coreRelocate(local, target *Spec, relos coreRelos) (COREFixups, error) { | ||||
| 	if local.byteOrder != target.byteOrder { | ||||
| 		return nil, fmt.Errorf("can't relocate %s against %s", local.byteOrder, target.byteOrder) | ||||
| 	} | ||||
|  | ||||
| 	relocations := make(map[uint64]Relocation, len(coreRelos)) | ||||
| 	for _, relo := range coreRelos { | ||||
| 		accessorStr, err := local.strings.Lookup(relo.AccessStrOff) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	var ids []TypeID | ||||
| 	relosByID := make(map[TypeID]coreRelos) | ||||
| 	result := make(COREFixups, len(relos)) | ||||
| 	for _, relo := range relos { | ||||
| 		if relo.kind == reloTypeIDLocal { | ||||
| 			// Filtering out reloTypeIDLocal here makes our lives a lot easier | ||||
| 			// down the line, since it doesn't have a target at all. | ||||
| 			if len(relo.accessor) > 1 || relo.accessor[0] != 0 { | ||||
| 				return nil, fmt.Errorf("%s: unexpected accessor %v", relo.kind, relo.accessor) | ||||
| 			} | ||||
|  | ||||
| 		accessor, err := parseCoreAccessor(accessorStr) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("accessor %q: %s", accessorStr, err) | ||||
| 		} | ||||
|  | ||||
| 		if int(relo.TypeID) >= len(local.types) { | ||||
| 			return nil, fmt.Errorf("invalid type id %d", relo.TypeID) | ||||
| 		} | ||||
|  | ||||
| 		typ := local.types[relo.TypeID] | ||||
|  | ||||
| 		if relo.ReloKind == reloTypeIDLocal { | ||||
| 			relocations[uint64(relo.InsnOff)] = Relocation{ | ||||
| 				uint32(typ.ID()), | ||||
| 				uint32(typ.ID()), | ||||
| 			result[uint64(relo.insnOff)] = COREFixup{ | ||||
| 				relo.kind, | ||||
| 				uint32(relo.typeID), | ||||
| 				uint32(relo.typeID), | ||||
| 				false, | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		named, ok := typ.(namedType) | ||||
| 		if !ok || named.name() == "" { | ||||
| 			return nil, fmt.Errorf("relocate anonymous type %s: %w", typ.String(), ErrNotSupported) | ||||
| 		relos, ok := relosByID[relo.typeID] | ||||
| 		if !ok { | ||||
| 			ids = append(ids, relo.typeID) | ||||
| 		} | ||||
|  | ||||
| 		name := essentialName(named.name()) | ||||
| 		res, err := coreCalculateRelocation(typ, target.namedTypes[name], relo.ReloKind, accessor) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("relocate %s: %w", name, err) | ||||
| 		} | ||||
|  | ||||
| 		relocations[uint64(relo.InsnOff)] = res | ||||
| 		relosByID[relo.typeID] = append(relos, relo) | ||||
| 	} | ||||
|  | ||||
| 	return relocations, nil | ||||
| 	// Ensure we work on relocations in a deterministic order. | ||||
| 	sort.Slice(ids, func(i, j int) bool { | ||||
| 		return ids[i] < ids[j] | ||||
| 	}) | ||||
|  | ||||
| 	for _, id := range ids { | ||||
| 		if int(id) >= len(local.types) { | ||||
| 			return nil, fmt.Errorf("invalid type id %d", id) | ||||
| 		} | ||||
|  | ||||
| 		localType := local.types[id] | ||||
| 		named, ok := localType.(namedType) | ||||
| 		if !ok || named.name() == "" { | ||||
| 			return nil, fmt.Errorf("relocate unnamed or anonymous type %s: %w", localType, ErrNotSupported) | ||||
| 		} | ||||
|  | ||||
| 		relos := relosByID[id] | ||||
| 		targets := target.namedTypes[named.essentialName()] | ||||
| 		fixups, err := coreCalculateFixups(localType, targets, relos) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("relocate %s: %w", localType, err) | ||||
| 		} | ||||
|  | ||||
| 		for i, relo := range relos { | ||||
| 			result[uint64(relo.insnOff)] = fixups[i] | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| var errAmbiguousRelocation = errors.New("ambiguous relocation") | ||||
| var errImpossibleRelocation = errors.New("impossible relocation") | ||||
|  | ||||
| // coreCalculateFixups calculates the fixups for the given relocations using | ||||
| // the "best" target. | ||||
| // | ||||
| // The best target is determined by scoring: the less poisoning we have to do | ||||
| // the better the target is. | ||||
| func coreCalculateFixups(local Type, targets []namedType, relos coreRelos) ([]COREFixup, error) { | ||||
| 	localID := local.ID() | ||||
| 	local, err := copyType(local, skipQualifierAndTypedef) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	bestScore := len(relos) | ||||
| 	var bestFixups []COREFixup | ||||
| 	for i := range targets { | ||||
| 		targetID := targets[i].ID() | ||||
| 		target, err := copyType(targets[i], skipQualifierAndTypedef) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		score := 0 // lower is better | ||||
| 		fixups := make([]COREFixup, 0, len(relos)) | ||||
| 		for _, relo := range relos { | ||||
| 			fixup, err := coreCalculateFixup(local, localID, target, targetID, relo) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("target %s: %w", target, err) | ||||
| 			} | ||||
| 			if fixup.Poison || fixup.isNonExistant() { | ||||
| 				score++ | ||||
| 			} | ||||
| 			fixups = append(fixups, fixup) | ||||
| 		} | ||||
|  | ||||
| 		if score > bestScore { | ||||
| 			// We have a better target already, ignore this one. | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if score < bestScore { | ||||
| 			// This is the best target yet, use it. | ||||
| 			bestScore = score | ||||
| 			bestFixups = fixups | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Some other target has the same score as the current one. Make sure | ||||
| 		// the fixups agree with each other. | ||||
| 		for i, fixup := range bestFixups { | ||||
| 			if !fixup.equal(fixups[i]) { | ||||
| 				return nil, fmt.Errorf("%s: multiple types match: %w", fixup.Kind, errAmbiguousRelocation) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if bestFixups == nil { | ||||
| 		// Nothing at all matched, probably because there are no suitable | ||||
| 		// targets at all. Poison everything! | ||||
| 		bestFixups = make([]COREFixup, len(relos)) | ||||
| 		for i, relo := range relos { | ||||
| 			bestFixups[i] = COREFixup{Kind: relo.kind, Poison: true} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return bestFixups, nil | ||||
| } | ||||
|  | ||||
| // coreCalculateFixup calculates the fixup for a single local type, target type | ||||
| // and relocation. | ||||
| func coreCalculateFixup(local Type, localID TypeID, target Type, targetID TypeID, relo coreRelo) (COREFixup, error) { | ||||
| 	fixup := func(local, target uint32) (COREFixup, error) { | ||||
| 		return COREFixup{relo.kind, local, target, false}, nil | ||||
| 	} | ||||
| 	poison := func() (COREFixup, error) { | ||||
| 		if relo.kind.checksForExistence() { | ||||
| 			return fixup(1, 0) | ||||
| 		} | ||||
| 		return COREFixup{relo.kind, 0, 0, true}, nil | ||||
| 	} | ||||
| 	zero := COREFixup{} | ||||
|  | ||||
| 	switch relo.kind { | ||||
| 	case reloTypeIDTarget, reloTypeSize, reloTypeExists: | ||||
| 		if len(relo.accessor) > 1 || relo.accessor[0] != 0 { | ||||
| 			return zero, fmt.Errorf("%s: unexpected accessor %v", relo.kind, relo.accessor) | ||||
| 		} | ||||
|  | ||||
| 		err := coreAreTypesCompatible(local, target) | ||||
| 		if errors.Is(err, errImpossibleRelocation) { | ||||
| 			return poison() | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return zero, fmt.Errorf("relocation %s: %w", relo.kind, err) | ||||
| 		} | ||||
|  | ||||
| 		switch relo.kind { | ||||
| 		case reloTypeExists: | ||||
| 			return fixup(1, 1) | ||||
|  | ||||
| func coreCalculateRelocation(local Type, targets []namedType, kind coreReloKind, localAccessor coreAccessor) (Relocation, error) { | ||||
| 	var relos []Relocation | ||||
| 	var matches []Type | ||||
| 	for _, target := range targets { | ||||
| 		switch kind { | ||||
| 		case reloTypeIDTarget: | ||||
| 			if localAccessor[0] != 0 { | ||||
| 				return Relocation{}, fmt.Errorf("%s: unexpected non-zero accessor", kind) | ||||
| 			return fixup(uint32(localID), uint32(targetID)) | ||||
|  | ||||
| 		case reloTypeSize: | ||||
| 			localSize, err := Sizeof(local) | ||||
| 			if err != nil { | ||||
| 				return zero, err | ||||
| 			} | ||||
|  | ||||
| 			if compat, err := coreAreTypesCompatible(local, target); err != nil { | ||||
| 				return Relocation{}, fmt.Errorf("%s: %s", kind, err) | ||||
| 			} else if !compat { | ||||
| 				continue | ||||
| 			targetSize, err := Sizeof(target) | ||||
| 			if err != nil { | ||||
| 				return zero, err | ||||
| 			} | ||||
|  | ||||
| 			relos = append(relos, Relocation{uint32(target.ID()), uint32(target.ID())}) | ||||
|  | ||||
| 		default: | ||||
| 			return Relocation{}, fmt.Errorf("relocation %s: %w", kind, ErrNotSupported) | ||||
| 			return fixup(uint32(localSize), uint32(targetSize)) | ||||
| 		} | ||||
| 		matches = append(matches, target) | ||||
| 	} | ||||
|  | ||||
| 	if len(relos) == 0 { | ||||
| 		// TODO: Add switch for existence checks like reloEnumvalExists here. | ||||
| 	case reloEnumvalValue, reloEnumvalExists: | ||||
| 		localValue, targetValue, err := coreFindEnumValue(local, relo.accessor, target) | ||||
| 		if errors.Is(err, errImpossibleRelocation) { | ||||
| 			return poison() | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return zero, fmt.Errorf("relocation %s: %w", relo.kind, err) | ||||
| 		} | ||||
|  | ||||
| 		// TODO: This might have to be poisoned. | ||||
| 		return Relocation{}, fmt.Errorf("no relocation found, tried %v", targets) | ||||
| 	} | ||||
| 		switch relo.kind { | ||||
| 		case reloEnumvalExists: | ||||
| 			return fixup(1, 1) | ||||
|  | ||||
| 		case reloEnumvalValue: | ||||
| 			return fixup(uint32(localValue.Value), uint32(targetValue.Value)) | ||||
| 		} | ||||
|  | ||||
| 	case reloFieldByteOffset, reloFieldByteSize, reloFieldExists: | ||||
| 		if _, ok := target.(*Fwd); ok { | ||||
| 			// We can't relocate fields using a forward declaration, so | ||||
| 			// skip it. If a non-forward declaration is present in the BTF | ||||
| 			// we'll find it in one of the other iterations. | ||||
| 			return poison() | ||||
| 		} | ||||
|  | ||||
| 		localField, targetField, err := coreFindField(local, relo.accessor, target) | ||||
| 		if errors.Is(err, errImpossibleRelocation) { | ||||
| 			return poison() | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return zero, fmt.Errorf("target %s: %w", target, err) | ||||
| 		} | ||||
|  | ||||
| 		switch relo.kind { | ||||
| 		case reloFieldExists: | ||||
| 			return fixup(1, 1) | ||||
|  | ||||
| 		case reloFieldByteOffset: | ||||
| 			return fixup(localField.offset/8, targetField.offset/8) | ||||
|  | ||||
| 		case reloFieldByteSize: | ||||
| 			localSize, err := Sizeof(localField.Type) | ||||
| 			if err != nil { | ||||
| 				return zero, err | ||||
| 			} | ||||
|  | ||||
| 			targetSize, err := Sizeof(targetField.Type) | ||||
| 			if err != nil { | ||||
| 				return zero, err | ||||
| 			} | ||||
|  | ||||
| 			return fixup(uint32(localSize), uint32(targetSize)) | ||||
|  | ||||
| 	relo := relos[0] | ||||
| 	for _, altRelo := range relos[1:] { | ||||
| 		if !altRelo.equal(relo) { | ||||
| 			return Relocation{}, fmt.Errorf("multiple types %v match: %w", matches, errAmbiguousRelocation) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return relo, nil | ||||
| 	return zero, fmt.Errorf("relocation %s: %w", relo.kind, ErrNotSupported) | ||||
| } | ||||
|  | ||||
| /* coreAccessor contains a path through a struct. It contains at least one index. | ||||
| @@ -219,6 +482,240 @@ func parseCoreAccessor(accessor string) (coreAccessor, error) { | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| func (ca coreAccessor) String() string { | ||||
| 	strs := make([]string, 0, len(ca)) | ||||
| 	for _, i := range ca { | ||||
| 		strs = append(strs, strconv.Itoa(i)) | ||||
| 	} | ||||
| 	return strings.Join(strs, ":") | ||||
| } | ||||
|  | ||||
| func (ca coreAccessor) enumValue(t Type) (*EnumValue, error) { | ||||
| 	e, ok := t.(*Enum) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("not an enum: %s", t) | ||||
| 	} | ||||
|  | ||||
| 	if len(ca) > 1 { | ||||
| 		return nil, fmt.Errorf("invalid accessor %s for enum", ca) | ||||
| 	} | ||||
|  | ||||
| 	i := ca[0] | ||||
| 	if i >= len(e.Values) { | ||||
| 		return nil, fmt.Errorf("invalid index %d for %s", i, e) | ||||
| 	} | ||||
|  | ||||
| 	return &e.Values[i], nil | ||||
| } | ||||
|  | ||||
| type coreField struct { | ||||
| 	Type   Type | ||||
| 	offset uint32 | ||||
| } | ||||
|  | ||||
| func adjustOffset(base uint32, t Type, n int) (uint32, error) { | ||||
| 	size, err := Sizeof(t) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	return base + (uint32(n) * uint32(size) * 8), nil | ||||
| } | ||||
|  | ||||
| // coreFindField descends into the local type using the accessor and tries to | ||||
| // find an equivalent field in target at each step. | ||||
| // | ||||
| // Returns the field and the offset of the field from the start of | ||||
| // target in bits. | ||||
| func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreField, _ error) { | ||||
| 	// The first index is used to offset a pointer of the base type like | ||||
| 	// when accessing an array. | ||||
| 	localOffset, err := adjustOffset(0, local, localAcc[0]) | ||||
| 	if err != nil { | ||||
| 		return coreField{}, coreField{}, err | ||||
| 	} | ||||
|  | ||||
| 	targetOffset, err := adjustOffset(0, target, localAcc[0]) | ||||
| 	if err != nil { | ||||
| 		return coreField{}, coreField{}, err | ||||
| 	} | ||||
|  | ||||
| 	if err := coreAreMembersCompatible(local, target); err != nil { | ||||
| 		return coreField{}, coreField{}, fmt.Errorf("fields: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	var localMaybeFlex, targetMaybeFlex bool | ||||
| 	for _, acc := range localAcc[1:] { | ||||
| 		switch localType := local.(type) { | ||||
| 		case composite: | ||||
| 			// For composite types acc is used to find the field in the local type, | ||||
| 			// and then we try to find a field in target with the same name. | ||||
| 			localMembers := localType.members() | ||||
| 			if acc >= len(localMembers) { | ||||
| 				return coreField{}, coreField{}, fmt.Errorf("invalid accessor %d for %s", acc, local) | ||||
| 			} | ||||
|  | ||||
| 			localMember := localMembers[acc] | ||||
| 			if localMember.Name == "" { | ||||
| 				_, ok := localMember.Type.(composite) | ||||
| 				if !ok { | ||||
| 					return coreField{}, coreField{}, fmt.Errorf("unnamed field with type %s: %s", localMember.Type, ErrNotSupported) | ||||
| 				} | ||||
|  | ||||
| 				// This is an anonymous struct or union, ignore it. | ||||
| 				local = localMember.Type | ||||
| 				localOffset += localMember.Offset | ||||
| 				localMaybeFlex = false | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			targetType, ok := target.(composite) | ||||
| 			if !ok { | ||||
| 				return coreField{}, coreField{}, fmt.Errorf("target not composite: %w", errImpossibleRelocation) | ||||
| 			} | ||||
|  | ||||
| 			targetMember, last, err := coreFindMember(targetType, localMember.Name) | ||||
| 			if err != nil { | ||||
| 				return coreField{}, coreField{}, err | ||||
| 			} | ||||
|  | ||||
| 			if targetMember.BitfieldSize > 0 { | ||||
| 				return coreField{}, coreField{}, fmt.Errorf("field %q is a bitfield: %w", targetMember.Name, ErrNotSupported) | ||||
| 			} | ||||
|  | ||||
| 			local = localMember.Type | ||||
| 			localMaybeFlex = acc == len(localMembers)-1 | ||||
| 			localOffset += localMember.Offset | ||||
| 			target = targetMember.Type | ||||
| 			targetMaybeFlex = last | ||||
| 			targetOffset += targetMember.Offset | ||||
|  | ||||
| 		case *Array: | ||||
| 			// For arrays, acc is the index in the target. | ||||
| 			targetType, ok := target.(*Array) | ||||
| 			if !ok { | ||||
| 				return coreField{}, coreField{}, fmt.Errorf("target not array: %w", errImpossibleRelocation) | ||||
| 			} | ||||
|  | ||||
| 			if localType.Nelems == 0 && !localMaybeFlex { | ||||
| 				return coreField{}, coreField{}, fmt.Errorf("local type has invalid flexible array") | ||||
| 			} | ||||
| 			if targetType.Nelems == 0 && !targetMaybeFlex { | ||||
| 				return coreField{}, coreField{}, fmt.Errorf("target type has invalid flexible array") | ||||
| 			} | ||||
|  | ||||
| 			if localType.Nelems > 0 && acc >= int(localType.Nelems) { | ||||
| 				return coreField{}, coreField{}, fmt.Errorf("invalid access of %s at index %d", localType, acc) | ||||
| 			} | ||||
| 			if targetType.Nelems > 0 && acc >= int(targetType.Nelems) { | ||||
| 				return coreField{}, coreField{}, fmt.Errorf("out of bounds access of target: %w", errImpossibleRelocation) | ||||
| 			} | ||||
|  | ||||
| 			local = localType.Type | ||||
| 			localMaybeFlex = false | ||||
| 			localOffset, err = adjustOffset(localOffset, local, acc) | ||||
| 			if err != nil { | ||||
| 				return coreField{}, coreField{}, err | ||||
| 			} | ||||
|  | ||||
| 			target = targetType.Type | ||||
| 			targetMaybeFlex = false | ||||
| 			targetOffset, err = adjustOffset(targetOffset, target, acc) | ||||
| 			if err != nil { | ||||
| 				return coreField{}, coreField{}, err | ||||
| 			} | ||||
|  | ||||
| 		default: | ||||
| 			return coreField{}, coreField{}, fmt.Errorf("relocate field of %T: %w", localType, ErrNotSupported) | ||||
| 		} | ||||
|  | ||||
| 		if err := coreAreMembersCompatible(local, target); err != nil { | ||||
| 			return coreField{}, coreField{}, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return coreField{local, localOffset}, coreField{target, targetOffset}, nil | ||||
| } | ||||
|  | ||||
| // coreFindMember finds a member in a composite type while handling anonymous | ||||
| // structs and unions. | ||||
| func coreFindMember(typ composite, name Name) (Member, bool, error) { | ||||
| 	if name == "" { | ||||
| 		return Member{}, false, errors.New("can't search for anonymous member") | ||||
| 	} | ||||
|  | ||||
| 	type offsetTarget struct { | ||||
| 		composite | ||||
| 		offset uint32 | ||||
| 	} | ||||
|  | ||||
| 	targets := []offsetTarget{{typ, 0}} | ||||
| 	visited := make(map[composite]bool) | ||||
|  | ||||
| 	for i := 0; i < len(targets); i++ { | ||||
| 		target := targets[i] | ||||
|  | ||||
| 		// Only visit targets once to prevent infinite recursion. | ||||
| 		if visited[target] { | ||||
| 			continue | ||||
| 		} | ||||
| 		if len(visited) >= maxTypeDepth { | ||||
| 			// This check is different than libbpf, which restricts the entire | ||||
| 			// path to BPF_CORE_SPEC_MAX_LEN items. | ||||
| 			return Member{}, false, fmt.Errorf("type is nested too deep") | ||||
| 		} | ||||
| 		visited[target] = true | ||||
|  | ||||
| 		members := target.members() | ||||
| 		for j, member := range members { | ||||
| 			if member.Name == name { | ||||
| 				// NB: This is safe because member is a copy. | ||||
| 				member.Offset += target.offset | ||||
| 				return member, j == len(members)-1, nil | ||||
| 			} | ||||
|  | ||||
| 			// The names don't match, but this member could be an anonymous struct | ||||
| 			// or union. | ||||
| 			if member.Name != "" { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			comp, ok := member.Type.(composite) | ||||
| 			if !ok { | ||||
| 				return Member{}, false, fmt.Errorf("anonymous non-composite type %T not allowed", member.Type) | ||||
| 			} | ||||
|  | ||||
| 			targets = append(targets, offsetTarget{comp, target.offset + member.Offset}) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return Member{}, false, fmt.Errorf("no matching member: %w", errImpossibleRelocation) | ||||
| } | ||||
|  | ||||
| // coreFindEnumValue follows localAcc to find the equivalent enum value in target. | ||||
| func coreFindEnumValue(local Type, localAcc coreAccessor, target Type) (localValue, targetValue *EnumValue, _ error) { | ||||
| 	localValue, err := localAcc.enumValue(local) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	targetEnum, ok := target.(*Enum) | ||||
| 	if !ok { | ||||
| 		return nil, nil, errImpossibleRelocation | ||||
| 	} | ||||
|  | ||||
| 	localName := localValue.Name.essentialName() | ||||
| 	for i, targetValue := range targetEnum.Values { | ||||
| 		if targetValue.Name.essentialName() != localName { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		return localValue, &targetEnum.Values[i], nil | ||||
| 	} | ||||
|  | ||||
| 	return nil, nil, errImpossibleRelocation | ||||
| } | ||||
|  | ||||
| /* The comment below is from bpf_core_types_are_compat in libbpf.c: | ||||
|  * | ||||
|  * Check local and target types for compatibility. This check is used for | ||||
| @@ -239,8 +736,10 @@ func parseCoreAccessor(accessor string) (coreAccessor, error) { | ||||
|  *     number of input args and compatible return and argument types. | ||||
|  * These rules are not set in stone and probably will be adjusted as we get | ||||
|  * more experience with using BPF CO-RE relocations. | ||||
|  * | ||||
|  * Returns errImpossibleRelocation if types are not compatible. | ||||
|  */ | ||||
| func coreAreTypesCompatible(localType Type, targetType Type) (bool, error) { | ||||
| func coreAreTypesCompatible(localType Type, targetType Type) error { | ||||
| 	var ( | ||||
| 		localTs, targetTs typeDeque | ||||
| 		l, t              = &localType, &targetType | ||||
| @@ -249,14 +748,14 @@ func coreAreTypesCompatible(localType Type, targetType Type) (bool, error) { | ||||
|  | ||||
| 	for ; l != nil && t != nil; l, t = localTs.shift(), targetTs.shift() { | ||||
| 		if depth >= maxTypeDepth { | ||||
| 			return false, errors.New("types are nested too deep") | ||||
| 			return errors.New("types are nested too deep") | ||||
| 		} | ||||
|  | ||||
| 		localType = skipQualifierAndTypedef(*l) | ||||
| 		targetType = skipQualifierAndTypedef(*t) | ||||
| 		localType = *l | ||||
| 		targetType = *t | ||||
|  | ||||
| 		if reflect.TypeOf(localType) != reflect.TypeOf(targetType) { | ||||
| 			return false, nil | ||||
| 			return fmt.Errorf("type mismatch: %w", errImpossibleRelocation) | ||||
| 		} | ||||
|  | ||||
| 		switch lv := (localType).(type) { | ||||
| @@ -266,7 +765,7 @@ func coreAreTypesCompatible(localType Type, targetType Type) (bool, error) { | ||||
| 		case *Int: | ||||
| 			tv := targetType.(*Int) | ||||
| 			if lv.isBitfield() || tv.isBitfield() { | ||||
| 				return false, nil | ||||
| 				return fmt.Errorf("bitfield: %w", errImpossibleRelocation) | ||||
| 			} | ||||
|  | ||||
| 		case *Pointer, *Array: | ||||
| @@ -277,7 +776,7 @@ func coreAreTypesCompatible(localType Type, targetType Type) (bool, error) { | ||||
| 		case *FuncProto: | ||||
| 			tv := targetType.(*FuncProto) | ||||
| 			if len(lv.Params) != len(tv.Params) { | ||||
| 				return false, nil | ||||
| 				return fmt.Errorf("function param mismatch: %w", errImpossibleRelocation) | ||||
| 			} | ||||
|  | ||||
| 			depth++ | ||||
| @@ -285,22 +784,24 @@ func coreAreTypesCompatible(localType Type, targetType Type) (bool, error) { | ||||
| 			targetType.walk(&targetTs) | ||||
|  | ||||
| 		default: | ||||
| 			return false, fmt.Errorf("unsupported type %T", localType) | ||||
| 			return fmt.Errorf("unsupported type %T", localType) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if l != nil { | ||||
| 		return false, fmt.Errorf("dangling local type %T", *l) | ||||
| 		return fmt.Errorf("dangling local type %T", *l) | ||||
| 	} | ||||
|  | ||||
| 	if t != nil { | ||||
| 		return false, fmt.Errorf("dangling target type %T", *t) | ||||
| 		return fmt.Errorf("dangling target type %T", *t) | ||||
| 	} | ||||
|  | ||||
| 	return true, nil | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| /* The comment below is from bpf_core_fields_are_compat in libbpf.c: | ||||
| /* coreAreMembersCompatible checks two types for field-based relocation compatibility. | ||||
|  * | ||||
|  * The comment below is from bpf_core_fields_are_compat in libbpf.c: | ||||
|  * | ||||
|  * Check two types for compatibility for the purpose of field access | ||||
|  * relocation. const/volatile/restrict and typedefs are skipped to ensure we | ||||
| @@ -314,65 +815,63 @@ func coreAreTypesCompatible(localType Type, targetType Type) (bool, error) { | ||||
|  *   - for INT, size and signedness are ignored; | ||||
|  *   - for ARRAY, dimensionality is ignored, element types are checked for | ||||
|  *     compatibility recursively; | ||||
|  *     [ NB: coreAreMembersCompatible doesn't recurse, this check is done | ||||
|  *       by coreFindField. ] | ||||
|  *   - everything else shouldn't be ever a target of relocation. | ||||
|  * These rules are not set in stone and probably will be adjusted as we get | ||||
|  * more experience with using BPF CO-RE relocations. | ||||
|  * | ||||
|  * Returns errImpossibleRelocation if the members are not compatible. | ||||
|  */ | ||||
| func coreAreMembersCompatible(localType Type, targetType Type) (bool, error) { | ||||
| 	doNamesMatch := func(a, b string) bool { | ||||
| func coreAreMembersCompatible(localType Type, targetType Type) error { | ||||
| 	doNamesMatch := func(a, b string) error { | ||||
| 		if a == "" || b == "" { | ||||
| 			// allow anonymous and named type to match | ||||
| 			return true | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		return essentialName(a) == essentialName(b) | ||||
| 		if essentialName(a) == essentialName(b) { | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		return fmt.Errorf("names don't match: %w", errImpossibleRelocation) | ||||
| 	} | ||||
|  | ||||
| 	for depth := 0; depth <= maxTypeDepth; depth++ { | ||||
| 		localType = skipQualifierAndTypedef(localType) | ||||
| 		targetType = skipQualifierAndTypedef(targetType) | ||||
|  | ||||
| 		_, lok := localType.(composite) | ||||
| 		_, tok := targetType.(composite) | ||||
| 		if lok && tok { | ||||
| 			return true, nil | ||||
| 		} | ||||
|  | ||||
| 		if reflect.TypeOf(localType) != reflect.TypeOf(targetType) { | ||||
| 			return false, nil | ||||
| 		} | ||||
|  | ||||
| 		switch lv := localType.(type) { | ||||
| 		case *Pointer: | ||||
| 			return true, nil | ||||
|  | ||||
| 		case *Enum: | ||||
| 			tv := targetType.(*Enum) | ||||
| 			return doNamesMatch(lv.name(), tv.name()), nil | ||||
|  | ||||
| 		case *Fwd: | ||||
| 			tv := targetType.(*Fwd) | ||||
| 			return doNamesMatch(lv.name(), tv.name()), nil | ||||
|  | ||||
| 		case *Int: | ||||
| 			tv := targetType.(*Int) | ||||
| 			return !lv.isBitfield() && !tv.isBitfield(), nil | ||||
|  | ||||
| 		case *Array: | ||||
| 			tv := targetType.(*Array) | ||||
|  | ||||
| 			localType = lv.Type | ||||
| 			targetType = tv.Type | ||||
|  | ||||
| 		default: | ||||
| 			return false, fmt.Errorf("unsupported type %T", localType) | ||||
| 		} | ||||
| 	_, lok := localType.(composite) | ||||
| 	_, tok := targetType.(composite) | ||||
| 	if lok && tok { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return false, errors.New("types are nested too deep") | ||||
| 	if reflect.TypeOf(localType) != reflect.TypeOf(targetType) { | ||||
| 		return fmt.Errorf("type mismatch: %w", errImpossibleRelocation) | ||||
| 	} | ||||
|  | ||||
| 	switch lv := localType.(type) { | ||||
| 	case *Array, *Pointer: | ||||
| 		return nil | ||||
|  | ||||
| 	case *Enum: | ||||
| 		tv := targetType.(*Enum) | ||||
| 		return doNamesMatch(lv.name(), tv.name()) | ||||
|  | ||||
| 	case *Fwd: | ||||
| 		tv := targetType.(*Fwd) | ||||
| 		return doNamesMatch(lv.name(), tv.name()) | ||||
|  | ||||
| 	case *Int: | ||||
| 		tv := targetType.(*Int) | ||||
| 		if lv.isBitfield() || tv.isBitfield() { | ||||
| 			return fmt.Errorf("bitfield: %w", errImpossibleRelocation) | ||||
| 		} | ||||
| 		return nil | ||||
|  | ||||
| 	default: | ||||
| 		return fmt.Errorf("type %s: %w", localType, ErrNotSupported) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func skipQualifierAndTypedef(typ Type) Type { | ||||
| func skipQualifierAndTypedef(typ Type) (Type, error) { | ||||
| 	result := typ | ||||
| 	for depth := 0; depth <= maxTypeDepth; depth++ { | ||||
| 		switch v := (result).(type) { | ||||
| @@ -381,8 +880,8 @@ func skipQualifierAndTypedef(typ Type) Type { | ||||
| 		case *Typedef: | ||||
| 			result = v.Type | ||||
| 		default: | ||||
| 			return result | ||||
| 			return result, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return typ | ||||
| 	return nil, errors.New("exceeded type depth") | ||||
| } | ||||
|   | ||||
							
								
								
									
										46
									
								
								vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -30,7 +30,7 @@ type btfExtCoreHeader struct { | ||||
| 	CoreReloLen uint32 | ||||
| } | ||||
|  | ||||
| func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, coreRelos map[string]bpfCoreRelos, err error) { | ||||
| func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, relos map[string]coreRelos, err error) { | ||||
| 	var header btfExtHeader | ||||
| 	var coreHeader btfExtCoreHeader | ||||
| 	if err := binary.Read(r, bo, &header); err != nil { | ||||
| @@ -94,13 +94,13 @@ func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (f | ||||
| 			return nil, nil, nil, fmt.Errorf("can't seek to CO-RE relocation section: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		coreRelos, err = parseExtInfoRelos(io.LimitReader(r, int64(coreHeader.CoreReloLen)), bo, strings) | ||||
| 		relos, err = parseExtInfoRelos(io.LimitReader(r, int64(coreHeader.CoreReloLen)), bo, strings) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, nil, fmt.Errorf("CO-RE relocation info: %w", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return funcInfo, lineInfo, coreRelos, nil | ||||
| 	return funcInfo, lineInfo, relos, nil | ||||
| } | ||||
|  | ||||
| type btfExtInfoSec struct { | ||||
| @@ -208,18 +208,25 @@ type bpfCoreRelo struct { | ||||
| 	InsnOff      uint32 | ||||
| 	TypeID       TypeID | ||||
| 	AccessStrOff uint32 | ||||
| 	ReloKind     coreReloKind | ||||
| 	Kind         COREKind | ||||
| } | ||||
|  | ||||
| type bpfCoreRelos []bpfCoreRelo | ||||
| type coreRelo struct { | ||||
| 	insnOff  uint32 | ||||
| 	typeID   TypeID | ||||
| 	accessor coreAccessor | ||||
| 	kind     COREKind | ||||
| } | ||||
|  | ||||
| type coreRelos []coreRelo | ||||
|  | ||||
| // append two slices of extInfoRelo to each other. The InsnOff of b are adjusted | ||||
| // by offset. | ||||
| func (r bpfCoreRelos) append(other bpfCoreRelos, offset uint64) bpfCoreRelos { | ||||
| 	result := make([]bpfCoreRelo, 0, len(r)+len(other)) | ||||
| func (r coreRelos) append(other coreRelos, offset uint64) coreRelos { | ||||
| 	result := make([]coreRelo, 0, len(r)+len(other)) | ||||
| 	result = append(result, r...) | ||||
| 	for _, relo := range other { | ||||
| 		relo.InsnOff += uint32(offset) | ||||
| 		relo.insnOff += uint32(offset) | ||||
| 		result = append(result, relo) | ||||
| 	} | ||||
| 	return result | ||||
| @@ -227,7 +234,7 @@ func (r bpfCoreRelos) append(other bpfCoreRelos, offset uint64) bpfCoreRelos { | ||||
|  | ||||
| var extInfoReloSize = binary.Size(bpfCoreRelo{}) | ||||
|  | ||||
| func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]bpfCoreRelos, error) { | ||||
| func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]coreRelos, error) { | ||||
| 	var recordSize uint32 | ||||
| 	if err := binary.Read(r, bo, &recordSize); err != nil { | ||||
| 		return nil, fmt.Errorf("read record size: %v", err) | ||||
| @@ -237,14 +244,14 @@ func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (m | ||||
| 		return nil, fmt.Errorf("expected record size %d, got %d", extInfoReloSize, recordSize) | ||||
| 	} | ||||
|  | ||||
| 	result := make(map[string]bpfCoreRelos) | ||||
| 	result := make(map[string]coreRelos) | ||||
| 	for { | ||||
| 		secName, infoHeader, err := parseExtInfoHeader(r, bo, strings) | ||||
| 		if errors.Is(err, io.EOF) { | ||||
| 			return result, nil | ||||
| 		} | ||||
|  | ||||
| 		var relos []bpfCoreRelo | ||||
| 		var relos coreRelos | ||||
| 		for i := uint32(0); i < infoHeader.NumInfo; i++ { | ||||
| 			var relo bpfCoreRelo | ||||
| 			if err := binary.Read(r, bo, &relo); err != nil { | ||||
| @@ -255,7 +262,22 @@ func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (m | ||||
| 				return nil, fmt.Errorf("section %v: offset %v is not aligned with instruction size", secName, relo.InsnOff) | ||||
| 			} | ||||
|  | ||||
| 			relos = append(relos, relo) | ||||
| 			accessorStr, err := strings.Lookup(relo.AccessStrOff) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			accessor, err := parseCoreAccessor(accessorStr) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("accessor %q: %s", accessorStr, err) | ||||
| 			} | ||||
|  | ||||
| 			relos = append(relos, coreRelo{ | ||||
| 				relo.InsnOff, | ||||
| 				relo.TypeID, | ||||
| 				accessor, | ||||
| 				relo.Kind, | ||||
| 			}) | ||||
| 		} | ||||
|  | ||||
| 		result[secName] = relos | ||||
|   | ||||
							
								
								
									
										46
									
								
								vendor/github.com/cilium/ebpf/internal/btf/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								vendor/github.com/cilium/ebpf/internal/btf/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,7 +1,6 @@ | ||||
| package btf | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"strings" | ||||
| @@ -37,6 +36,7 @@ type Type interface { | ||||
| type namedType interface { | ||||
| 	Type | ||||
| 	name() string | ||||
| 	essentialName() string | ||||
| } | ||||
|  | ||||
| // Name identifies a type. | ||||
| @@ -48,6 +48,10 @@ func (n Name) name() string { | ||||
| 	return string(n) | ||||
| } | ||||
|  | ||||
| func (n Name) essentialName() string { | ||||
| 	return essentialName(string(n)) | ||||
| } | ||||
|  | ||||
| // Void is the unit type of BTF. | ||||
| type Void struct{} | ||||
|  | ||||
| @@ -174,8 +178,7 @@ func (s *Struct) walk(tdq *typeDeque) { | ||||
|  | ||||
| func (s *Struct) copy() Type { | ||||
| 	cpy := *s | ||||
| 	cpy.Members = make([]Member, len(s.Members)) | ||||
| 	copy(cpy.Members, s.Members) | ||||
| 	cpy.Members = copyMembers(s.Members) | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| @@ -206,8 +209,7 @@ func (u *Union) walk(tdq *typeDeque) { | ||||
|  | ||||
| func (u *Union) copy() Type { | ||||
| 	cpy := *u | ||||
| 	cpy.Members = make([]Member, len(u.Members)) | ||||
| 	copy(cpy.Members, u.Members) | ||||
| 	cpy.Members = copyMembers(u.Members) | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| @@ -215,6 +217,12 @@ func (u *Union) members() []Member { | ||||
| 	return u.Members | ||||
| } | ||||
|  | ||||
| func copyMembers(orig []Member) []Member { | ||||
| 	cpy := make([]Member, len(orig)) | ||||
| 	copy(cpy, orig) | ||||
| 	return cpy | ||||
| } | ||||
|  | ||||
| type composite interface { | ||||
| 	members() []Member | ||||
| } | ||||
| @@ -511,7 +519,7 @@ func Sizeof(typ Type) (int, error) { | ||||
| 		switch v := typ.(type) { | ||||
| 		case *Array: | ||||
| 			if n > 0 && int64(v.Nelems) > math.MaxInt64/n { | ||||
| 				return 0, errors.New("overflow") | ||||
| 				return 0, fmt.Errorf("type %s: overflow", typ) | ||||
| 			} | ||||
|  | ||||
| 			// Arrays may be of zero length, which allows | ||||
| @@ -532,28 +540,30 @@ func Sizeof(typ Type) (int, error) { | ||||
| 			continue | ||||
|  | ||||
| 		default: | ||||
| 			return 0, fmt.Errorf("unrecognized type %T", typ) | ||||
| 			return 0, fmt.Errorf("unsized type %T", typ) | ||||
| 		} | ||||
|  | ||||
| 		if n > 0 && elem > math.MaxInt64/n { | ||||
| 			return 0, errors.New("overflow") | ||||
| 			return 0, fmt.Errorf("type %s: overflow", typ) | ||||
| 		} | ||||
|  | ||||
| 		size := n * elem | ||||
| 		if int64(int(size)) != size { | ||||
| 			return 0, errors.New("overflow") | ||||
| 			return 0, fmt.Errorf("type %s: overflow", typ) | ||||
| 		} | ||||
|  | ||||
| 		return int(size), nil | ||||
| 	} | ||||
|  | ||||
| 	return 0, errors.New("exceeded type depth") | ||||
| 	return 0, fmt.Errorf("type %s: exceeded type depth", typ) | ||||
| } | ||||
|  | ||||
| // copy a Type recursively. | ||||
| // | ||||
| // typ may form a cycle. | ||||
| func copyType(typ Type) Type { | ||||
| // | ||||
| // Returns any errors from transform verbatim. | ||||
| func copyType(typ Type, transform func(Type) (Type, error)) (Type, error) { | ||||
| 	var ( | ||||
| 		copies = make(map[Type]Type) | ||||
| 		work   typeDeque | ||||
| @@ -566,7 +576,17 @@ func copyType(typ Type) Type { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		cpy := (*t).copy() | ||||
| 		var cpy Type | ||||
| 		if transform != nil { | ||||
| 			tf, err := transform(*t) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("copy %s: %w", typ, err) | ||||
| 			} | ||||
| 			cpy = tf.copy() | ||||
| 		} else { | ||||
| 			cpy = (*t).copy() | ||||
| 		} | ||||
|  | ||||
| 		copies[*t] = cpy | ||||
| 		*t = cpy | ||||
|  | ||||
| @@ -574,7 +594,7 @@ func copyType(typ Type) Type { | ||||
| 		cpy.walk(&work) | ||||
| 	} | ||||
|  | ||||
| 	return typ | ||||
| 	return typ, nil | ||||
| } | ||||
|  | ||||
| // typeDeque keeps track of pointers to types which still | ||||
|   | ||||
							
								
								
									
										16
									
								
								vendor/github.com/cilium/ebpf/internal/elf.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/cilium/ebpf/internal/elf.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -50,3 +50,19 @@ func (se *SafeELFFile) Symbols() (syms []elf.Symbol, err error) { | ||||
| 	syms, err = se.File.Symbols() | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // DynamicSymbols is the safe version of elf.File.DynamicSymbols. | ||||
| func (se *SafeELFFile) DynamicSymbols() (syms []elf.Symbol, err error) { | ||||
| 	defer func() { | ||||
| 		r := recover() | ||||
| 		if r == nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		syms = nil | ||||
| 		err = fmt.Errorf("reading ELF dynamic symbols panicked: %s", r) | ||||
| 	}() | ||||
|  | ||||
| 	syms, err = se.File.DynamicSymbols() | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/github.com/cilium/ebpf/internal/endian.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/cilium/ebpf/internal/endian.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -9,11 +9,16 @@ import ( | ||||
| // depending on the host's endianness. | ||||
| var NativeEndian binary.ByteOrder | ||||
|  | ||||
| // Clang is set to either "el" or "eb" depending on the host's endianness. | ||||
| var ClangEndian string | ||||
|  | ||||
| func init() { | ||||
| 	if isBigEndian() { | ||||
| 		NativeEndian = binary.BigEndian | ||||
| 		ClangEndian = "eb" | ||||
| 	} else { | ||||
| 		NativeEndian = binary.LittleEndian | ||||
| 		ClangEndian = "el" | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/cilium/ebpf/internal/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/cilium/ebpf/internal/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -29,6 +29,10 @@ type VerifierError struct { | ||||
| 	log   string | ||||
| } | ||||
|  | ||||
| func (le *VerifierError) Unwrap() error { | ||||
| 	return le.cause | ||||
| } | ||||
|  | ||||
| func (le *VerifierError) Error() string { | ||||
| 	if le.log == "" { | ||||
| 		return le.cause.Error() | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/cilium/ebpf/internal/ptr.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/cilium/ebpf/internal/ptr.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -22,10 +22,6 @@ func NewSlicePointer(buf []byte) Pointer { | ||||
|  | ||||
| // NewStringPointer creates a 64-bit pointer from a string. | ||||
| func NewStringPointer(str string) Pointer { | ||||
| 	if str == "" { | ||||
| 		return Pointer{} | ||||
| 	} | ||||
|  | ||||
| 	p, err := unix.BytePtrFromString(str) | ||||
| 	if err != nil { | ||||
| 		return Pointer{} | ||||
|   | ||||
							
								
								
									
										1
									
								
								vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -42,6 +42,7 @@ const ( | ||||
| 	PROT_READ                = linux.PROT_READ | ||||
| 	PROT_WRITE               = linux.PROT_WRITE | ||||
| 	MAP_SHARED               = linux.MAP_SHARED | ||||
| 	PERF_ATTR_SIZE_VER1      = linux.PERF_ATTR_SIZE_VER1 | ||||
| 	PERF_TYPE_SOFTWARE       = linux.PERF_TYPE_SOFTWARE | ||||
| 	PERF_TYPE_TRACEPOINT     = linux.PERF_TYPE_TRACEPOINT | ||||
| 	PERF_COUNT_SW_BPF_OUTPUT = linux.PERF_COUNT_SW_BPF_OUTPUT | ||||
|   | ||||
							
								
								
									
										1
									
								
								vendor/github.com/cilium/ebpf/internal/unix/types_other.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/cilium/ebpf/internal/unix/types_other.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -43,6 +43,7 @@ const ( | ||||
| 	PROT_READ                = 0x1 | ||||
| 	PROT_WRITE               = 0x2 | ||||
| 	MAP_SHARED               = 0x1 | ||||
| 	PERF_ATTR_SIZE_VER1      = 0 | ||||
| 	PERF_TYPE_SOFTWARE       = 0x1 | ||||
| 	PERF_TYPE_TRACEPOINT     = 0 | ||||
| 	PERF_COUNT_SW_BPF_OUTPUT = 0xa | ||||
|   | ||||
							
								
								
									
										284
									
								
								vendor/github.com/cilium/ebpf/link/kprobe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										284
									
								
								vendor/github.com/cilium/ebpf/link/kprobe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,12 +1,16 @@ | ||||
| package link | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/rand" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"sync" | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/cilium/ebpf" | ||||
| 	"github.com/cilium/ebpf/internal" | ||||
| @@ -15,13 +19,60 @@ import ( | ||||
|  | ||||
| var ( | ||||
| 	kprobeEventsPath = filepath.Join(tracefsPath, "kprobe_events") | ||||
|  | ||||
| 	kprobeRetprobeBit = struct { | ||||
| 		once  sync.Once | ||||
| 		value uint64 | ||||
| 		err   error | ||||
| 	}{} | ||||
| ) | ||||
|  | ||||
| type probeType uint8 | ||||
|  | ||||
| const ( | ||||
| 	kprobeType probeType = iota | ||||
| 	uprobeType | ||||
| ) | ||||
|  | ||||
| func (pt probeType) String() string { | ||||
| 	if pt == kprobeType { | ||||
| 		return "kprobe" | ||||
| 	} | ||||
| 	return "uprobe" | ||||
| } | ||||
|  | ||||
| func (pt probeType) EventsPath() string { | ||||
| 	if pt == kprobeType { | ||||
| 		return kprobeEventsPath | ||||
| 	} | ||||
| 	return uprobeEventsPath | ||||
| } | ||||
|  | ||||
| func (pt probeType) PerfEventType(ret bool) perfEventType { | ||||
| 	if pt == kprobeType { | ||||
| 		if ret { | ||||
| 			return kretprobeEvent | ||||
| 		} | ||||
| 		return kprobeEvent | ||||
| 	} | ||||
| 	if ret { | ||||
| 		return uretprobeEvent | ||||
| 	} | ||||
| 	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 | ||||
| // given kernel symbol starts executing. See /proc/kallsyms for available | ||||
| // symbols. For example, printk(): | ||||
| // | ||||
| //	Kprobe("printk") | ||||
| //	Kprobe("printk", prog) | ||||
| // | ||||
| // The resulting Link must be Closed during program shutdown to avoid leaking | ||||
| // system resources. | ||||
| @@ -44,7 +95,7 @@ func Kprobe(symbol string, prog *ebpf.Program) (Link, error) { | ||||
| // before the given kernel symbol exits, with the function stack left intact. | ||||
| // See /proc/kallsyms for available symbols. For example, printk(): | ||||
| // | ||||
| //	Kretprobe("printk") | ||||
| //	Kretprobe("printk", prog) | ||||
| // | ||||
| // The resulting Link must be Closed during program shutdown to avoid leaking | ||||
| // system resources. | ||||
| @@ -80,7 +131,10 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) { | ||||
| 	} | ||||
|  | ||||
| 	// Use kprobe PMU if the kernel has it available. | ||||
| 	tp, err := pmuKprobe(symbol, ret) | ||||
| 	tp, err := pmuKprobe(platformPrefix(symbol), ret) | ||||
| 	if errors.Is(err, os.ErrNotExist) { | ||||
| 		tp, err = pmuKprobe(symbol, ret) | ||||
| 	} | ||||
| 	if err == nil { | ||||
| 		return tp, nil | ||||
| 	} | ||||
| @@ -89,7 +143,10 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) { | ||||
| 	} | ||||
|  | ||||
| 	// Use tracefs if kprobe PMU is missing. | ||||
| 	tp, err = tracefsKprobe(symbol, ret) | ||||
| 	tp, err = tracefsKprobe(platformPrefix(symbol), ret) | ||||
| 	if errors.Is(err, os.ErrNotExist) { | ||||
| 		tp, err = tracefsKprobe(symbol, ret) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("creating trace event '%s' in tracefs: %w", symbol, err) | ||||
| 	} | ||||
| @@ -97,36 +154,70 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) { | ||||
| 	return tp, nil | ||||
| } | ||||
|  | ||||
| // pmuKprobe opens a perf event based on a Performance Monitoring Unit. | ||||
| // Requires at least 4.17 (e12f03d7031a "perf/core: Implement the | ||||
| // 'perf_kprobe' PMU"). | ||||
| // Returns ErrNotSupported if the kernel doesn't support perf_kprobe PMU, | ||||
| // or os.ErrNotExist if the given symbol does not exist in the kernel. | ||||
| // pmuKprobe opens a perf event based on the kprobe PMU. | ||||
| // Returns os.ErrNotExist if the given symbol does not exist in the kernel. | ||||
| func pmuKprobe(symbol string, ret bool) (*perfEvent, error) { | ||||
| 	return pmuProbe(kprobeType, symbol, "", 0, ret) | ||||
| } | ||||
|  | ||||
| // pmuProbe opens a perf event based on a Performance Monitoring Unit. | ||||
| // | ||||
| // Requires at least a 4.17 kernel. | ||||
| // e12f03d7031a "perf/core: Implement the 'perf_kprobe' PMU" | ||||
| // 33ea4b24277b "perf/core: Implement the 'perf_uprobe' PMU" | ||||
| // | ||||
| // Returns ErrNotSupported if the kernel doesn't support perf_[k,u]probe PMU | ||||
| func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) { | ||||
| 	// Getting the PMU type will fail if the kernel doesn't support | ||||
| 	// the perf_kprobe PMU. | ||||
| 	et, err := getPMUEventType("kprobe") | ||||
| 	// the perf_[k,u]probe PMU. | ||||
| 	et, err := getPMUEventType(typ) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// Create a pointer to a NUL-terminated string for the kernel. | ||||
| 	sp, err := unsafeStringPtr(symbol) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// TODO: Parse the position of the bit from /sys/bus/event_source/devices/%s/format/retprobe. | ||||
| 	config := 0 | ||||
| 	var config uint64 | ||||
| 	if ret { | ||||
| 		config = 1 | ||||
| 		bit, err := typ.RetprobeBit() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		config |= 1 << bit | ||||
| 	} | ||||
|  | ||||
| 	attr := unix.PerfEventAttr{ | ||||
| 		Type:   uint32(et),          // PMU event type read from sysfs | ||||
| 		Ext1:   uint64(uintptr(sp)), // Kernel symbol to trace | ||||
| 		Config: uint64(config),      // perf_kprobe PMU treats config as flags | ||||
| 	var ( | ||||
| 		attr unix.PerfEventAttr | ||||
| 		sp   unsafe.Pointer | ||||
| 	) | ||||
| 	switch typ { | ||||
| 	case kprobeType: | ||||
| 		// Create a pointer to a NUL-terminated string for the kernel. | ||||
| 		sp, err := unsafeStringPtr(symbol) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		attr = unix.PerfEventAttr{ | ||||
| 			Type:   uint32(et),          // PMU event type read from sysfs | ||||
| 			Ext1:   uint64(uintptr(sp)), // Kernel symbol to trace | ||||
| 			Config: config,              // Retprobe flag | ||||
| 		} | ||||
| 	case uprobeType: | ||||
| 		sp, err := unsafeStringPtr(path) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		attr = unix.PerfEventAttr{ | ||||
| 			// The minimum size required for PMU uprobes is PERF_ATTR_SIZE_VER1, | ||||
| 			// since it added the config2 (Ext2) field. The Size field controls the | ||||
| 			// size of the internal buffer the kernel allocates for reading the | ||||
| 			// perf_event_attr argument from userspace. | ||||
| 			Size:   unix.PERF_ATTR_SIZE_VER1, | ||||
| 			Type:   uint32(et),          // PMU event type read from sysfs | ||||
| 			Ext1:   uint64(uintptr(sp)), // Uprobe path | ||||
| 			Ext2:   offset,              // Uprobe offset | ||||
| 			Config: config,              // Retprobe flag | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) | ||||
| @@ -144,22 +235,27 @@ func pmuKprobe(symbol string, ret bool) (*perfEvent, error) { | ||||
| 	// Ensure the string pointer is not collected before PerfEventOpen returns. | ||||
| 	runtime.KeepAlive(sp) | ||||
|  | ||||
| 	// Kernel has perf_kprobe PMU available, initialize perf event. | ||||
| 	// Kernel has perf_[k,u]probe PMU available, initialize perf event. | ||||
| 	return &perfEvent{ | ||||
| 		fd:       internal.NewFD(uint32(fd)), | ||||
| 		pmuID:    et, | ||||
| 		name:     symbol, | ||||
| 		ret:      ret, | ||||
| 		progType: ebpf.Kprobe, | ||||
| 		fd:    internal.NewFD(uint32(fd)), | ||||
| 		pmuID: et, | ||||
| 		name:  symbol, | ||||
| 		typ:   typ.PerfEventType(ret), | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // tracefsKprobe creates a trace event by writing an entry to <tracefs>/kprobe_events. | ||||
| // A new trace event group name is generated on every call to support creating | ||||
| // multiple trace events for the same kernel symbol. A perf event is then opened | ||||
| // on the newly-created trace event and returned to the caller. | ||||
| // tracefsKprobe creates a Kprobe tracefs entry. | ||||
| func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) { | ||||
| 	return tracefsProbe(kprobeType, symbol, "", 0, ret) | ||||
| } | ||||
|  | ||||
| // tracefsProbe creates a trace event by writing an entry to <tracefs>/[k,u]probe_events. | ||||
| // A new trace event group name is generated on every call to support creating | ||||
| // multiple trace events for the same kernel or userspace symbol. | ||||
| // Path and offset are only set in the case of uprobe(s) and are used to set | ||||
| // the executable/library path on the filesystem and the offset where the probe is inserted. | ||||
| // A perf event is then opened on the newly-created trace event and returned to the caller. | ||||
| func tracefsProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) { | ||||
| 	// Generate a random string for each trace event we attempt to create. | ||||
| 	// This value is used as the 'group' token in tracefs to allow creating | ||||
| 	// multiple kprobe trace events with the same name. | ||||
| @@ -176,14 +272,13 @@ func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) { | ||||
| 	if err == nil { | ||||
| 		return nil, fmt.Errorf("trace event already exists: %s/%s", group, symbol) | ||||
| 	} | ||||
| 	// The read is expected to fail with ErrNotSupported due to a non-existing event. | ||||
| 	if err != nil && !errors.Is(err, ErrNotSupported) { | ||||
| 	if err != nil && !errors.Is(err, os.ErrNotExist) { | ||||
| 		return nil, fmt.Errorf("checking trace event %s/%s: %w", group, symbol, err) | ||||
| 	} | ||||
|  | ||||
| 	// Create the kprobe trace event using tracefs. | ||||
| 	if err := createTraceFSKprobeEvent(group, symbol, ret); err != nil { | ||||
| 		return nil, fmt.Errorf("creating kprobe event on tracefs: %w", err) | ||||
| 	// Create the [k,u]probe trace event using tracefs. | ||||
| 	if err := createTraceFSProbeEvent(typ, group, symbol, path, offset, ret); err != nil { | ||||
| 		return nil, fmt.Errorf("creating probe entry on tracefs: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	// Get the newly-created trace event's id. | ||||
| @@ -202,65 +297,83 @@ func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) { | ||||
| 		fd:        fd, | ||||
| 		group:     group, | ||||
| 		name:      symbol, | ||||
| 		ret:       ret, | ||||
| 		tracefsID: tid, | ||||
| 		progType:  ebpf.Kprobe, // kernel only allows attaching kprobe programs to kprobe events | ||||
| 		typ:       typ.PerfEventType(ret), | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // createTraceFSKprobeEvent creates a new ephemeral trace event by writing to | ||||
| // <tracefs>/kprobe_events. Returns ErrNotSupported if symbol is not a valid | ||||
| // kernel symbol, or if it is not traceable with kprobes. | ||||
| func createTraceFSKprobeEvent(group, symbol string, ret bool) error { | ||||
| // createTraceFSProbeEvent creates a new ephemeral trace event by writing to | ||||
| // <tracefs>/[k,u]probe_events. Returns os.ErrNotExist if symbol is not a valid | ||||
| // kernel symbol, or if it is not traceable with kprobes. Returns os.ErrExist | ||||
| // if a probe with the same group and symbol already exists. | ||||
| func createTraceFSProbeEvent(typ probeType, group, symbol, path string, offset uint64, ret bool) error { | ||||
| 	// Open the kprobe_events file in tracefs. | ||||
| 	f, err := os.OpenFile(kprobeEventsPath, os.O_APPEND|os.O_WRONLY, 0666) | ||||
| 	f, err := os.OpenFile(typ.EventsPath(), os.O_APPEND|os.O_WRONLY, 0666) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("error opening kprobe_events: %w", err) | ||||
| 		return fmt.Errorf("error opening '%s': %w", typ.EventsPath(), err) | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	// The kprobe_events syntax is as follows (see Documentation/trace/kprobetrace.txt): | ||||
| 	// p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe | ||||
| 	// r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe | ||||
| 	// -:[GRP/]EVENT                                        : Clear a probe | ||||
| 	// | ||||
| 	// Some examples: | ||||
| 	// r:ebpf_1234/r_my_kretprobe nf_conntrack_destroy | ||||
| 	// p:ebpf_5678/p_my_kprobe __x64_sys_execve | ||||
| 	// | ||||
| 	// Leaving the kretprobe's MAXACTIVE set to 0 (or absent) will make the | ||||
| 	// kernel default to NR_CPUS. This is desired in most eBPF cases since | ||||
| 	// subsampling or rate limiting logic can be more accurately implemented in | ||||
| 	// the eBPF program itself. See Documentation/kprobes.txt for more details. | ||||
| 	pe := fmt.Sprintf("%s:%s/%s %s", kprobePrefix(ret), group, symbol, symbol) | ||||
| 	var pe string | ||||
| 	switch typ { | ||||
| 	case kprobeType: | ||||
| 		// The kprobe_events syntax is as follows (see Documentation/trace/kprobetrace.txt): | ||||
| 		// p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe | ||||
| 		// r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe | ||||
| 		// -:[GRP/]EVENT                                        : Clear a probe | ||||
| 		// | ||||
| 		// Some examples: | ||||
| 		// r:ebpf_1234/r_my_kretprobe nf_conntrack_destroy | ||||
| 		// p:ebpf_5678/p_my_kprobe __x64_sys_execve | ||||
| 		// | ||||
| 		// Leaving the kretprobe's MAXACTIVE set to 0 (or absent) will make the | ||||
| 		// kernel default to NR_CPUS. This is desired in most eBPF cases since | ||||
| 		// subsampling or rate limiting logic can be more accurately implemented in | ||||
| 		// the eBPF program itself. | ||||
| 		// See Documentation/kprobes.txt for more details. | ||||
| 		pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(ret), group, symbol, symbol) | ||||
| 	case uprobeType: | ||||
| 		// The uprobe_events syntax is as follows: | ||||
| 		// p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a probe | ||||
| 		// r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return probe | ||||
| 		// -:[GRP/]EVENT                           : Clear a probe | ||||
| 		// | ||||
| 		// Some examples: | ||||
| 		// r:ebpf_1234/readline /bin/bash:0x12345 | ||||
| 		// p:ebpf_5678/main_mySymbol /bin/mybin:0x12345 | ||||
| 		// | ||||
| 		// See Documentation/trace/uprobetracer.txt for more details. | ||||
| 		pathOffset := uprobePathOffset(path, offset) | ||||
| 		pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(ret), group, symbol, pathOffset) | ||||
| 	} | ||||
| 	_, err = f.WriteString(pe) | ||||
| 	// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL | ||||
| 	// when trying to create a kretprobe for a missing symbol. Make sure ENOENT | ||||
| 	// is returned to the caller. | ||||
| 	if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) { | ||||
| 		return fmt.Errorf("kernel symbol %s not found: %w", symbol, os.ErrNotExist) | ||||
| 		return fmt.Errorf("symbol %s not found: %w", symbol, os.ErrNotExist) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("writing '%s' to kprobe_events: %w", pe, err) | ||||
| 		return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // closeTraceFSKprobeEvent removes the kprobe with the given group, symbol and kind | ||||
| // from <tracefs>/kprobe_events. | ||||
| func closeTraceFSKprobeEvent(group, symbol string) error { | ||||
| 	f, err := os.OpenFile(kprobeEventsPath, os.O_APPEND|os.O_WRONLY, 0666) | ||||
| // closeTraceFSProbeEvent removes the [k,u]probe with the given type, group and symbol | ||||
| // from <tracefs>/[k,u]probe_events. | ||||
| func closeTraceFSProbeEvent(typ probeType, group, symbol string) error { | ||||
| 	f, err := os.OpenFile(typ.EventsPath(), os.O_APPEND|os.O_WRONLY, 0666) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("error opening kprobe_events: %w", err) | ||||
| 		return fmt.Errorf("error opening %s: %w", typ.EventsPath(), err) | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	// See kprobe_events syntax above. Kprobe type does not need to be specified | ||||
| 	// See [k,u]probe_events syntax above. The probe type does not need to be specified | ||||
| 	// for removals. | ||||
| 	pe := fmt.Sprintf("-:%s/%s", group, symbol) | ||||
| 	if _, err = f.WriteString(pe); err != nil { | ||||
| 		return fmt.Errorf("writing '%s' to kprobe_events: %w", pe, err) | ||||
| 		return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| @@ -288,9 +401,38 @@ func randomGroup(prefix string) (string, error) { | ||||
| 	return group, nil | ||||
| } | ||||
|  | ||||
| func kprobePrefix(ret bool) string { | ||||
| func probePrefix(ret bool) string { | ||||
| 	if ret { | ||||
| 		return "r" | ||||
| 	} | ||||
| 	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 := ioutil.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 | ||||
| } | ||||
|   | ||||
							
								
								
									
										78
									
								
								vendor/github.com/cilium/ebpf/link/perf_event.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										78
									
								
								vendor/github.com/cilium/ebpf/link/perf_event.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -31,6 +31,10 @@ import ( | ||||
| //   exported kernel symbols. kprobe-based (tracefs) trace events can be | ||||
| //   created system-wide by writing to the <tracefs>/kprobe_events file, or | ||||
| //   they can be scoped to the current process by creating PMU perf events. | ||||
| // - u(ret)probe: Ephemeral trace events based on user provides ELF binaries | ||||
| //   and offsets. uprobe-based (tracefs) trace events can be | ||||
| //   created system-wide by writing to the <tracefs>/uprobe_events file, or | ||||
| //   they can be scoped to the current process by creating PMU perf events. | ||||
| // - perf event: An object instantiated based on an existing trace event or | ||||
| //   kernel symbol. Referred to by fd in userspace. | ||||
| //   Exactly one eBPF program can be attached to a perf event. Multiple perf | ||||
| @@ -52,6 +56,16 @@ const ( | ||||
| 	perfAllThreads = -1 | ||||
| ) | ||||
|  | ||||
| type perfEventType uint8 | ||||
|  | ||||
| const ( | ||||
| 	tracepointEvent perfEventType = iota | ||||
| 	kprobeEvent | ||||
| 	kretprobeEvent | ||||
| 	uprobeEvent | ||||
| 	uretprobeEvent | ||||
| ) | ||||
|  | ||||
| // A perfEvent represents a perf event kernel object. Exactly one eBPF program | ||||
| // can be attached to it. It is created based on a tracefs trace event or a | ||||
| // Performance Monitoring Unit (PMU). | ||||
| @@ -66,11 +80,10 @@ type perfEvent struct { | ||||
| 	// ID of the trace event read from tracefs. Valid IDs are non-zero. | ||||
| 	tracefsID uint64 | ||||
|  | ||||
| 	// True for kretprobes/uretprobes. | ||||
| 	ret bool | ||||
| 	// The event type determines the types of programs that can be attached. | ||||
| 	typ perfEventType | ||||
|  | ||||
| 	fd       *internal.FD | ||||
| 	progType ebpf.ProgramType | ||||
| 	fd *internal.FD | ||||
| } | ||||
|  | ||||
| func (pe *perfEvent) isLink() {} | ||||
| @@ -117,13 +130,18 @@ func (pe *perfEvent) Close() error { | ||||
| 		return fmt.Errorf("closing perf event fd: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	switch t := pe.progType; t { | ||||
| 	case ebpf.Kprobe: | ||||
| 		// For kprobes created using tracefs, clean up the <tracefs>/kprobe_events entry. | ||||
| 	switch pe.typ { | ||||
| 	case kprobeEvent, kretprobeEvent: | ||||
| 		// Clean up kprobe tracefs entry. | ||||
| 		if pe.tracefsID != 0 { | ||||
| 			return closeTraceFSKprobeEvent(pe.group, pe.name) | ||||
| 			return closeTraceFSProbeEvent(kprobeType, pe.group, pe.name) | ||||
| 		} | ||||
| 	case ebpf.TracePoint: | ||||
| 	case uprobeEvent, uretprobeEvent: | ||||
| 		// Clean up uprobe tracefs entry. | ||||
| 		if pe.tracefsID != 0 { | ||||
| 			return closeTraceFSProbeEvent(uprobeType, pe.group, pe.name) | ||||
| 		} | ||||
| 	case tracepointEvent: | ||||
| 		// Tracepoint trace events don't hold any extra resources. | ||||
| 		return nil | ||||
| 	} | ||||
| @@ -141,12 +159,21 @@ func (pe *perfEvent) attach(prog *ebpf.Program) error { | ||||
| 	if pe.fd == nil { | ||||
| 		return errors.New("cannot attach to nil perf event") | ||||
| 	} | ||||
| 	if t := prog.Type(); t != pe.progType { | ||||
| 		return fmt.Errorf("invalid program type (expected %s): %s", pe.progType, t) | ||||
| 	} | ||||
| 	if prog.FD() < 0 { | ||||
| 		return fmt.Errorf("invalid program: %w", internal.ErrClosedFd) | ||||
| 	} | ||||
| 	switch pe.typ { | ||||
| 	case kprobeEvent, kretprobeEvent, uprobeEvent, uretprobeEvent: | ||||
| 		if t := prog.Type(); t != ebpf.Kprobe { | ||||
| 			return fmt.Errorf("invalid program type (expected %s): %s", ebpf.Kprobe, t) | ||||
| 		} | ||||
| 	case tracepointEvent: | ||||
| 		if t := prog.Type(); t != ebpf.TracePoint { | ||||
| 			return fmt.Errorf("invalid program type (expected %s): %s", ebpf.TracePoint, t) | ||||
| 		} | ||||
| 	default: | ||||
| 		return fmt.Errorf("unknown perf event type: %d", pe.typ) | ||||
| 	} | ||||
|  | ||||
| 	// The ioctl below will fail when the fd is invalid. | ||||
| 	kfd, _ := pe.fd.Value() | ||||
| @@ -180,8 +207,8 @@ func unsafeStringPtr(str string) (unsafe.Pointer, error) { | ||||
| // group and name must be alphanumeric or underscore, as required by the kernel. | ||||
| func getTraceEventID(group, name string) (uint64, error) { | ||||
| 	tid, err := uint64FromFile(tracefsPath, "events", group, name, "id") | ||||
| 	if errors.Is(err, ErrNotSupported) { | ||||
| 		return 0, fmt.Errorf("trace event %s/%s: %w", group, name, ErrNotSupported) | ||||
| 	if errors.Is(err, os.ErrNotExist) { | ||||
| 		return 0, fmt.Errorf("trace event %s/%s: %w", group, name, os.ErrNotExist) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return 0, fmt.Errorf("reading trace event ID of %s/%s: %w", group, name, err) | ||||
| @@ -192,20 +219,22 @@ func getTraceEventID(group, name string) (uint64, error) { | ||||
|  | ||||
| // getPMUEventType reads a Performance Monitoring Unit's type (numeric identifier) | ||||
| // from /sys/bus/event_source/devices/<pmu>/type. | ||||
| func getPMUEventType(pmu string) (uint64, error) { | ||||
| 	et, err := uint64FromFile("/sys/bus/event_source/devices", pmu, "type") | ||||
| 	if errors.Is(err, ErrNotSupported) { | ||||
| 		return 0, fmt.Errorf("pmu type %s: %w", pmu, ErrNotSupported) | ||||
| // | ||||
| // 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", pmu, err) | ||||
| 		return 0, fmt.Errorf("reading pmu type %s: %w", typ, err) | ||||
| 	} | ||||
|  | ||||
| 	return et, nil | ||||
| } | ||||
|  | ||||
| // openTracepointPerfEvent opens a tracepoint-type perf event. System-wide | ||||
| // kprobes created by writing to <tracefs>/kprobe_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. | ||||
| func openTracepointPerfEvent(tid uint64) (*internal.FD, error) { | ||||
| 	attr := unix.PerfEventAttr{ | ||||
| @@ -228,22 +257,13 @@ func openTracepointPerfEvent(tid uint64) (*internal.FD, 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) { | ||||
|  | ||||
| 	// Resolve leaf path separately for error feedback. Makes the join onto | ||||
| 	// base more readable (can't mix with variadic args). | ||||
| 	l := filepath.Join(path...) | ||||
|  | ||||
| 	p := filepath.Join(base, l) | ||||
| 	if !strings.HasPrefix(p, base) { | ||||
| 		return 0, fmt.Errorf("path '%s' attempts to escape base path '%s': %w", l, base, errInvalidInput) | ||||
| 	} | ||||
|  | ||||
| 	data, err := ioutil.ReadFile(p) | ||||
| 	if os.IsNotExist(err) { | ||||
| 		// Only echo leaf path, the base path can be prepended at the call site | ||||
| 		// if more verbosity is required. | ||||
| 		return 0, fmt.Errorf("symbol %s: %w", l, ErrNotSupported) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return 0, fmt.Errorf("reading file %s: %w", p, err) | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										25
									
								
								vendor/github.com/cilium/ebpf/link/platform.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/cilium/ebpf/link/platform.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| package link | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"runtime" | ||||
| ) | ||||
|  | ||||
| func platformPrefix(symbol string) string { | ||||
|  | ||||
| 	prefix := runtime.GOARCH | ||||
|  | ||||
| 	// per https://github.com/golang/go/blob/master/src/go/build/syslist.go | ||||
| 	switch prefix { | ||||
| 	case "386": | ||||
| 		prefix = "ia32" | ||||
| 	case "amd64", "amd64p32": | ||||
| 		prefix = "x64" | ||||
| 	case "arm64", "arm64be": | ||||
| 		prefix = "arm64" | ||||
| 	default: | ||||
| 		return symbol | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Sprintf("__%s_%s", prefix, symbol) | ||||
| } | ||||
							
								
								
									
										4
									
								
								vendor/github.com/cilium/ebpf/link/program.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/cilium/ebpf/link/program.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -43,7 +43,7 @@ func RawAttachProgram(opts RawAttachProgramOptions) error { | ||||
| 	} | ||||
|  | ||||
| 	if err := internal.BPFProgAttach(&attr); err != nil { | ||||
| 		return fmt.Errorf("can't attach program: %s", err) | ||||
| 		return fmt.Errorf("can't attach program: %w", err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -69,7 +69,7 @@ func RawDetachProgram(opts RawDetachProgramOptions) error { | ||||
| 		AttachType:  uint32(opts.Attach), | ||||
| 	} | ||||
| 	if err := internal.BPFProgDetach(&attr); err != nil { | ||||
| 		return fmt.Errorf("can't detach program: %s", err) | ||||
| 		return fmt.Errorf("can't detach program: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/cilium/ebpf/link/tracepoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/cilium/ebpf/link/tracepoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,7 +11,7 @@ import ( | ||||
| // tracepoints. The top-level directory is the group, the event's subdirectory | ||||
| // is the name. Example: | ||||
| // | ||||
| //	Tracepoint("syscalls", "sys_enter_fork") | ||||
| //	Tracepoint("syscalls", "sys_enter_fork", prog) | ||||
| // | ||||
| // Note that attaching eBPF programs to syscalls (sys_enter_*/sys_exit_*) is | ||||
| // only possible as of kernel 4.14 (commit cf5f5ce). | ||||
| @@ -44,7 +44,7 @@ func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) { | ||||
| 		tracefsID: tid, | ||||
| 		group:     group, | ||||
| 		name:      name, | ||||
| 		progType:  ebpf.TracePoint, | ||||
| 		typ:       tracepointEvent, | ||||
| 	} | ||||
|  | ||||
| 	if err := pe.attach(prog); err != nil { | ||||
|   | ||||
							
								
								
									
										207
									
								
								vendor/github.com/cilium/ebpf/link/uprobe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								vendor/github.com/cilium/ebpf/link/uprobe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | ||||
| package link | ||||
|  | ||||
| import ( | ||||
| 	"debug/elf" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/cilium/ebpf" | ||||
| 	"github.com/cilium/ebpf/internal" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	uprobeEventsPath = filepath.Join(tracefsPath, "uprobe_events") | ||||
|  | ||||
| 	// rgxUprobeSymbol is used to strip invalid characters from the uprobe symbol | ||||
| 	// as they are not allowed to be used as the EVENT token in tracefs. | ||||
| 	rgxUprobeSymbol = regexp.MustCompile("[^a-zA-Z0-9]+") | ||||
|  | ||||
| 	uprobeRetprobeBit = struct { | ||||
| 		once  sync.Once | ||||
| 		value uint64 | ||||
| 		err   error | ||||
| 	}{} | ||||
| ) | ||||
|  | ||||
| // Executable defines an executable program on the filesystem. | ||||
| type Executable struct { | ||||
| 	// Path of the executable on the filesystem. | ||||
| 	path string | ||||
| 	// Parsed ELF symbols and dynamic symbols. | ||||
| 	symbols map[string]elf.Symbol | ||||
| } | ||||
|  | ||||
| // To open a new Executable, use: | ||||
| // | ||||
| //	OpenExecutable("/bin/bash") | ||||
| // | ||||
| // The returned value can then be used to open Uprobe(s). | ||||
| func OpenExecutable(path string) (*Executable, error) { | ||||
| 	if path == "" { | ||||
| 		return nil, fmt.Errorf("path cannot be empty") | ||||
| 	} | ||||
|  | ||||
| 	f, err := os.Open(path) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("open file '%s': %w", path, err) | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	se, err := internal.NewSafeELFFile(f) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("parse ELF file: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	var ex = Executable{ | ||||
| 		path:    path, | ||||
| 		symbols: make(map[string]elf.Symbol), | ||||
| 	} | ||||
| 	if err := ex.addSymbols(se.Symbols); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if err := ex.addSymbols(se.DynamicSymbols); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &ex, nil | ||||
| } | ||||
|  | ||||
| func (ex *Executable) addSymbols(f func() ([]elf.Symbol, error)) error { | ||||
| 	// elf.Symbols and elf.DynamicSymbols return ErrNoSymbols if the section is not found. | ||||
| 	syms, err := f() | ||||
| 	if err != nil && !errors.Is(err, elf.ErrNoSymbols) { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, s := range syms { | ||||
| 		ex.symbols[s.Name] = s | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) { | ||||
| 	if s, ok := ex.symbols[symbol]; ok { | ||||
| 		return &s, nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("symbol %s not found", symbol) | ||||
| } | ||||
|  | ||||
| // Uprobe attaches the given eBPF program to a perf event that fires when the | ||||
| // given symbol starts executing in the given Executable. | ||||
| // For example, /bin/bash::main(): | ||||
| // | ||||
| //  ex, _ = OpenExecutable("/bin/bash") | ||||
| //  ex.Uprobe("main", prog) | ||||
| // | ||||
| // The resulting Link must be Closed during program shutdown to avoid leaking | ||||
| // system resources. Functions provided by shared libraries can currently not | ||||
| // be traced and will result in an ErrNotSupported. | ||||
| func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program) (Link, error) { | ||||
| 	u, err := ex.uprobe(symbol, prog, false) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	err = u.attach(prog) | ||||
| 	if err != nil { | ||||
| 		u.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return u, nil | ||||
| } | ||||
|  | ||||
| // Uretprobe attaches the given eBPF program to a perf event that fires right | ||||
| // before the given symbol exits. For example, /bin/bash::main(): | ||||
| // | ||||
| //  ex, _ = OpenExecutable("/bin/bash") | ||||
| //  ex.Uretprobe("main", prog) | ||||
| // | ||||
| // The resulting Link must be Closed during program shutdown to avoid leaking | ||||
| // system resources. Functions provided by shared libraries can currently not | ||||
| // be traced and will result in an ErrNotSupported. | ||||
| func (ex *Executable) Uretprobe(symbol string, prog *ebpf.Program) (Link, error) { | ||||
| 	u, err := ex.uprobe(symbol, prog, true) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	err = u.attach(prog) | ||||
| 	if err != nil { | ||||
| 		u.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return u, nil | ||||
| } | ||||
|  | ||||
| // uprobe opens a perf event for the given binary/symbol and attaches prog to it. | ||||
| // If ret is true, create a uretprobe. | ||||
| func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) { | ||||
| 	if prog == nil { | ||||
| 		return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput) | ||||
| 	} | ||||
| 	if prog.Type() != ebpf.Kprobe { | ||||
| 		return nil, fmt.Errorf("eBPF program type %s is not Kprobe: %w", prog.Type(), errInvalidInput) | ||||
| 	} | ||||
|  | ||||
| 	sym, err := ex.symbol(symbol) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("symbol '%s' not found in '%s': %w", symbol, ex.path, err) | ||||
| 	} | ||||
|  | ||||
| 	// Symbols with location 0 from section undef are shared library calls and | ||||
| 	// are relocated before the binary is executed. Dynamic linking is not | ||||
| 	// implemented by the library, so mark this as unsupported for now. | ||||
| 	if sym.Section == elf.SHN_UNDEF && sym.Value == 0 { | ||||
| 		return nil, fmt.Errorf("cannot resolve %s library call '%s': %w", ex.path, symbol, ErrNotSupported) | ||||
| 	} | ||||
|  | ||||
| 	// Use uprobe PMU if the kernel has it available. | ||||
| 	tp, err := pmuUprobe(sym.Name, ex.path, sym.Value, ret) | ||||
| 	if err == nil { | ||||
| 		return tp, nil | ||||
| 	} | ||||
| 	if err != nil && !errors.Is(err, ErrNotSupported) { | ||||
| 		return nil, fmt.Errorf("creating perf_uprobe PMU: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	// Use tracefs if uprobe PMU is missing. | ||||
| 	tp, err = tracefsUprobe(uprobeSanitizedSymbol(sym.Name), ex.path, sym.Value, ret) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("creating trace event '%s:%s' in tracefs: %w", ex.path, symbol, err) | ||||
| 	} | ||||
|  | ||||
| 	return tp, nil | ||||
| } | ||||
|  | ||||
| // pmuUprobe opens a perf event based on the uprobe PMU. | ||||
| func pmuUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) { | ||||
| 	return pmuProbe(uprobeType, symbol, path, offset, ret) | ||||
| } | ||||
|  | ||||
| // tracefsUprobe creates a Uprobe tracefs entry. | ||||
| func tracefsUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) { | ||||
| 	return tracefsProbe(uprobeType, symbol, path, offset, ret) | ||||
| } | ||||
|  | ||||
| // uprobeSanitizedSymbol replaces every invalid characted for the tracefs api with an underscore. | ||||
| func uprobeSanitizedSymbol(symbol string) string { | ||||
| 	return rgxUprobeSymbol.ReplaceAllString(symbol, "_") | ||||
| } | ||||
|  | ||||
| // uprobePathOffset creates the PATH:OFFSET token for the tracefs api. | ||||
| func uprobePathOffset(path string, offset uint64) string { | ||||
| 	return fmt.Sprintf("%s:%#x", path, offset) | ||||
| } | ||||
|  | ||||
| func uretprobeBit() (uint64, error) { | ||||
| 	uprobeRetprobeBit.once.Do(func() { | ||||
| 		uprobeRetprobeBit.value, uprobeRetprobeBit.err = determineRetprobeBit(uprobeType) | ||||
| 	}) | ||||
| 	return uprobeRetprobeBit.value, uprobeRetprobeBit.err | ||||
| } | ||||
							
								
								
									
										11
									
								
								vendor/github.com/cilium/ebpf/linker.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/cilium/ebpf/linker.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -108,12 +108,16 @@ func fixupJumpsAndCalls(insns asm.Instructions) error { | ||||
| 		offset := iter.Offset | ||||
| 		ins := iter.Ins | ||||
|  | ||||
| 		if ins.Reference == "" { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		switch { | ||||
| 		case ins.IsFunctionCall() && ins.Constant == -1: | ||||
| 			// Rewrite bpf to bpf call | ||||
| 			callOffset, ok := symbolOffsets[ins.Reference] | ||||
| 			if !ok { | ||||
| 				return fmt.Errorf("instruction %d: reference to missing symbol %q", i, ins.Reference) | ||||
| 				return fmt.Errorf("call at %d: reference to missing symbol %q", i, ins.Reference) | ||||
| 			} | ||||
|  | ||||
| 			ins.Constant = int64(callOffset - offset - 1) | ||||
| @@ -122,10 +126,13 @@ func fixupJumpsAndCalls(insns asm.Instructions) error { | ||||
| 			// Rewrite jump to label | ||||
| 			jumpOffset, ok := symbolOffsets[ins.Reference] | ||||
| 			if !ok { | ||||
| 				return fmt.Errorf("instruction %d: reference to missing symbol %q", i, ins.Reference) | ||||
| 				return fmt.Errorf("jump at %d: reference to missing symbol %q", i, ins.Reference) | ||||
| 			} | ||||
|  | ||||
| 			ins.Offset = int16(jumpOffset - offset - 1) | ||||
|  | ||||
| 		case ins.IsLoadFromMap() && ins.MapPtr() == -1: | ||||
| 			return fmt.Errorf("map %s: %w", ins.Reference, errUnsatisfiedReference) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										50
									
								
								vendor/github.com/cilium/ebpf/map.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										50
									
								
								vendor/github.com/cilium/ebpf/map.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -18,6 +18,7 @@ var ( | ||||
| 	ErrKeyNotExist      = errors.New("key does not exist") | ||||
| 	ErrKeyExist         = errors.New("key already exists") | ||||
| 	ErrIterationAborted = errors.New("iteration aborted") | ||||
| 	ErrMapIncompatible  = errors.New("map's spec is incompatible with pinned map") | ||||
| ) | ||||
|  | ||||
| // MapOptions control loading a map into the kernel. | ||||
| @@ -87,6 +88,23 @@ func (ms *MapSpec) Copy() *MapSpec { | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| func (ms *MapSpec) clampPerfEventArraySize() error { | ||||
| 	if ms.Type != PerfEventArray { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	n, err := internal.PossibleCPUs() | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("perf event array: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	if n := uint32(n); ms.MaxEntries > n { | ||||
| 		ms.MaxEntries = n | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // MapKV is used to initialize the contents of a Map. | ||||
| type MapKV struct { | ||||
| 	Key   interface{} | ||||
| @@ -96,19 +114,19 @@ type MapKV struct { | ||||
| func (ms *MapSpec) checkCompatibility(m *Map) error { | ||||
| 	switch { | ||||
| 	case m.typ != ms.Type: | ||||
| 		return fmt.Errorf("expected type %v, got %v", ms.Type, m.typ) | ||||
| 		return fmt.Errorf("expected type %v, got %v: %w", ms.Type, m.typ, ErrMapIncompatible) | ||||
|  | ||||
| 	case m.keySize != ms.KeySize: | ||||
| 		return fmt.Errorf("expected key size %v, got %v", ms.KeySize, m.keySize) | ||||
| 		return fmt.Errorf("expected key size %v, got %v: %w", ms.KeySize, m.keySize, ErrMapIncompatible) | ||||
|  | ||||
| 	case m.valueSize != ms.ValueSize: | ||||
| 		return fmt.Errorf("expected value size %v, got %v", ms.ValueSize, m.valueSize) | ||||
| 		return fmt.Errorf("expected value size %v, got %v: %w", ms.ValueSize, m.valueSize, ErrMapIncompatible) | ||||
|  | ||||
| 	case m.maxEntries != ms.MaxEntries: | ||||
| 		return fmt.Errorf("expected max entries %v, got %v", ms.MaxEntries, m.maxEntries) | ||||
| 		return fmt.Errorf("expected max entries %v, got %v: %w", ms.MaxEntries, m.maxEntries, ErrMapIncompatible) | ||||
|  | ||||
| 	case m.flags != ms.Flags: | ||||
| 		return fmt.Errorf("expected flags %v, got %v", ms.Flags, m.flags) | ||||
| 		return fmt.Errorf("expected flags %v, got %v: %w", ms.Flags, m.flags, ErrMapIncompatible) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -171,14 +189,16 @@ func NewMap(spec *MapSpec) (*Map, error) { | ||||
| // The caller is responsible for ensuring the process' rlimit is set | ||||
| // sufficiently high for locking memory during map creation. This can be done | ||||
| // by calling unix.Setrlimit with unix.RLIMIT_MEMLOCK prior to calling NewMapWithOptions. | ||||
| // | ||||
| // May return an error wrapping ErrMapIncompatible. | ||||
| func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) { | ||||
| 	btfs := make(btfHandleCache) | ||||
| 	defer btfs.close() | ||||
| 	handles := newHandleCache() | ||||
| 	defer handles.close() | ||||
|  | ||||
| 	return newMapWithOptions(spec, opts, btfs) | ||||
| 	return newMapWithOptions(spec, opts, handles) | ||||
| } | ||||
|  | ||||
| func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (_ *Map, err error) { | ||||
| func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ *Map, err error) { | ||||
| 	closeOnError := func(c io.Closer) { | ||||
| 		if err != nil { | ||||
| 			c.Close() | ||||
| @@ -202,7 +222,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (_ * | ||||
| 		defer closeOnError(m) | ||||
|  | ||||
| 		if err := spec.checkCompatibility(m); err != nil { | ||||
| 			return nil, fmt.Errorf("use pinned map %s: %s", spec.Name, err) | ||||
| 			return nil, fmt.Errorf("use pinned map %s: %w", spec.Name, err) | ||||
| 		} | ||||
|  | ||||
| 		return m, nil | ||||
| @@ -211,7 +231,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (_ * | ||||
| 		// Nothing to do here | ||||
|  | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unsupported pin type %d", int(spec.Pinning)) | ||||
| 		return nil, fmt.Errorf("pin type %d: %w", int(spec.Pinning), ErrNotSupported) | ||||
| 	} | ||||
|  | ||||
| 	var innerFd *internal.FD | ||||
| @@ -224,7 +244,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (_ * | ||||
| 			return nil, errors.New("inner maps cannot be pinned") | ||||
| 		} | ||||
|  | ||||
| 		template, err := createMap(spec.InnerMap, nil, opts, btfs) | ||||
| 		template, err := createMap(spec.InnerMap, nil, opts, handles) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -233,7 +253,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (_ * | ||||
| 		innerFd = template.fd | ||||
| 	} | ||||
|  | ||||
| 	m, err := createMap(spec, innerFd, opts, btfs) | ||||
| 	m, err := createMap(spec, innerFd, opts, handles) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -249,7 +269,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (_ * | ||||
| 	return m, nil | ||||
| } | ||||
|  | ||||
| func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, btfs btfHandleCache) (_ *Map, err error) { | ||||
| func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *handleCache) (_ *Map, err error) { | ||||
| 	closeOnError := func(closer io.Closer) { | ||||
| 		if err != nil { | ||||
| 			closer.Close() | ||||
| @@ -320,7 +340,7 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, btfs btfHandl | ||||
|  | ||||
| 	var btfDisabled bool | ||||
| 	if spec.BTF != nil { | ||||
| 		handle, err := btfs.load(btf.MapSpec(spec.BTF)) | ||||
| 		handle, err := handles.btfHandle(btf.MapSpec(spec.BTF)) | ||||
| 		btfDisabled = errors.Is(err, btf.ErrNotSupported) | ||||
| 		if err != nil && !btfDisabled { | ||||
| 			return nil, fmt.Errorf("load BTF: %w", err) | ||||
|   | ||||
							
								
								
									
										149
									
								
								vendor/github.com/cilium/ebpf/prog.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										149
									
								
								vendor/github.com/cilium/ebpf/prog.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -5,6 +5,7 @@ import ( | ||||
| 	"encoding/binary" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| @@ -19,6 +20,8 @@ import ( | ||||
| // ErrNotSupported is returned whenever the kernel doesn't support a feature. | ||||
| var ErrNotSupported = internal.ErrNotSupported | ||||
|  | ||||
| var errUnsatisfiedReference = errors.New("unsatisfied reference") | ||||
|  | ||||
| // ProgramID represents the unique ID of an eBPF program. | ||||
| type ProgramID uint32 | ||||
|  | ||||
| @@ -41,6 +44,12 @@ type ProgramOptions struct { | ||||
| 	// Controls the output buffer size for the verifier. Defaults to | ||||
| 	// DefaultVerifierLogSize. | ||||
| 	LogSize int | ||||
| 	// An ELF containing the target BTF for this program. It is used both to | ||||
| 	// find the correct function to trace and to apply CO-RE relocations. | ||||
| 	// This is useful in environments where the kernel BTF is not available | ||||
| 	// (containers) or where it is in a non-standard location. Defaults to | ||||
| 	// use the kernel BTF from a well-known location. | ||||
| 	TargetBTF io.ReaderAt | ||||
| } | ||||
|  | ||||
| // ProgramSpec defines a Program. | ||||
| @@ -125,21 +134,21 @@ func NewProgram(spec *ProgramSpec) (*Program, error) { | ||||
| // Loading a program for the first time will perform | ||||
| // feature detection by loading small, temporary programs. | ||||
| func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error) { | ||||
| 	btfs := make(btfHandleCache) | ||||
| 	defer btfs.close() | ||||
| 	handles := newHandleCache() | ||||
| 	defer handles.close() | ||||
|  | ||||
| 	return newProgramWithOptions(spec, opts, btfs) | ||||
| 	prog, err := newProgramWithOptions(spec, opts, handles) | ||||
| 	if errors.Is(err, errUnsatisfiedReference) { | ||||
| 		return nil, fmt.Errorf("cannot load program without loading its whole collection: %w", err) | ||||
| 	} | ||||
| 	return prog, err | ||||
| } | ||||
|  | ||||
| func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, btfs btfHandleCache) (*Program, error) { | ||||
| func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *handleCache) (*Program, error) { | ||||
| 	if len(spec.Instructions) == 0 { | ||||
| 		return nil, errors.New("Instructions cannot be empty") | ||||
| 	} | ||||
|  | ||||
| 	if len(spec.License) == 0 { | ||||
| 		return nil, errors.New("License cannot be empty") | ||||
| 	} | ||||
|  | ||||
| 	if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian { | ||||
| 		return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian) | ||||
| 	} | ||||
| @@ -157,27 +166,10 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, btfs btfHandl | ||||
| 		kv = v.Kernel() | ||||
| 	} | ||||
|  | ||||
| 	insns := make(asm.Instructions, len(spec.Instructions)) | ||||
| 	copy(insns, spec.Instructions) | ||||
|  | ||||
| 	if err := fixupJumpsAndCalls(insns); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize)) | ||||
| 	err := insns.Marshal(buf, internal.NativeEndian) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	bytecode := buf.Bytes() | ||||
| 	insCount := uint32(len(bytecode) / asm.InstructionSize) | ||||
| 	attr := &bpfProgLoadAttr{ | ||||
| 		progType:           spec.Type, | ||||
| 		progFlags:          spec.Flags, | ||||
| 		expectedAttachType: spec.AttachType, | ||||
| 		insCount:           insCount, | ||||
| 		instructions:       internal.NewSlicePointer(bytecode), | ||||
| 		license:            internal.NewStringPointer(spec.License), | ||||
| 		kernelVersion:      kv, | ||||
| 	} | ||||
| @@ -186,15 +178,24 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, btfs btfHandl | ||||
| 		attr.progName = newBPFObjName(spec.Name) | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var targetBTF *btf.Spec | ||||
| 	if opts.TargetBTF != nil { | ||||
| 		targetBTF, err = handles.btfSpec(opts.TargetBTF) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("load target BTF: %w", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var btfDisabled bool | ||||
| 	var core btf.COREFixups | ||||
| 	if spec.BTF != nil { | ||||
| 		if relos, err := btf.ProgramRelocations(spec.BTF, nil); err != nil { | ||||
| 			return nil, fmt.Errorf("CO-RE relocations: %s", err) | ||||
| 		} else if len(relos) > 0 { | ||||
| 			return nil, fmt.Errorf("applying CO-RE relocations: %w", ErrNotSupported) | ||||
| 		core, err = btf.ProgramFixups(spec.BTF, targetBTF) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("CO-RE relocations: %w", err) | ||||
| 		} | ||||
|  | ||||
| 		handle, err := btfs.load(btf.ProgramSpec(spec.BTF)) | ||||
| 		handle, err := handles.btfHandle(btf.ProgramSpec(spec.BTF)) | ||||
| 		btfDisabled = errors.Is(err, btf.ErrNotSupported) | ||||
| 		if err != nil && !btfDisabled { | ||||
| 			return nil, fmt.Errorf("load BTF: %w", err) | ||||
| @@ -221,8 +222,27 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, btfs btfHandl | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	insns, err := core.Apply(spec.Instructions) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("CO-RE fixup: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := fixupJumpsAndCalls(insns); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize)) | ||||
| 	err = insns.Marshal(buf, internal.NativeEndian) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	bytecode := buf.Bytes() | ||||
| 	attr.instructions = internal.NewSlicePointer(bytecode) | ||||
| 	attr.insCount = uint32(len(bytecode) / asm.InstructionSize) | ||||
|  | ||||
| 	if spec.AttachTo != "" { | ||||
| 		target, err := resolveBTFType(spec.AttachTo, spec.Type, spec.AttachType) | ||||
| 		target, err := resolveBTFType(targetBTF, spec.AttachTo, spec.Type, spec.AttachType) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -250,7 +270,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, btfs btfHandl | ||||
| 	} | ||||
|  | ||||
| 	logErr := err | ||||
| 	if opts.LogLevel == 0 { | ||||
| 	if opts.LogLevel == 0 && opts.LogSize >= 0 { | ||||
| 		// Re-run with the verifier enabled to get better error messages. | ||||
| 		logBuf = make([]byte, logSize) | ||||
| 		attr.logLevel = 1 | ||||
| @@ -664,52 +684,45 @@ func (p *Program) ID() (ProgramID, error) { | ||||
| 	return ProgramID(info.id), nil | ||||
| } | ||||
|  | ||||
| func findKernelType(name string, typ btf.Type) error { | ||||
| 	kernel, err := btf.LoadKernelSpec() | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("can't load kernel spec: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	return kernel.FindType(name, typ) | ||||
| } | ||||
|  | ||||
| func resolveBTFType(name string, progType ProgramType, attachType AttachType) (btf.Type, error) { | ||||
| func resolveBTFType(kernel *btf.Spec, name string, progType ProgramType, attachType AttachType) (btf.Type, error) { | ||||
| 	type match struct { | ||||
| 		p ProgramType | ||||
| 		a AttachType | ||||
| 	} | ||||
|  | ||||
| 	target := match{progType, attachType} | ||||
| 	switch target { | ||||
| 	var target btf.Type | ||||
| 	var typeName, featureName string | ||||
| 	switch (match{progType, attachType}) { | ||||
| 	case match{LSM, AttachLSMMac}: | ||||
| 		var target btf.Func | ||||
| 		err := findKernelType("bpf_lsm_"+name, &target) | ||||
| 		if errors.Is(err, btf.ErrNotFound) { | ||||
| 			return nil, &internal.UnsupportedFeatureError{ | ||||
| 				Name: name + " LSM hook", | ||||
| 			} | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("resolve BTF for LSM hook %s: %w", name, err) | ||||
| 		} | ||||
|  | ||||
| 		return &target, nil | ||||
| 		target = new(btf.Func) | ||||
| 		typeName = "bpf_lsm_" + name | ||||
| 		featureName = name + " LSM hook" | ||||
|  | ||||
| 	case match{Tracing, AttachTraceIter}: | ||||
| 		var target btf.Func | ||||
| 		err := findKernelType("bpf_iter_"+name, &target) | ||||
| 		if errors.Is(err, btf.ErrNotFound) { | ||||
| 			return nil, &internal.UnsupportedFeatureError{ | ||||
| 				Name: name + " iterator", | ||||
| 			} | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("resolve BTF for iterator %s: %w", name, err) | ||||
| 		} | ||||
|  | ||||
| 		return &target, nil | ||||
| 		target = new(btf.Func) | ||||
| 		typeName = "bpf_iter_" + name | ||||
| 		featureName = name + " iterator" | ||||
|  | ||||
| 	default: | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	if kernel == nil { | ||||
| 		var err error | ||||
| 		kernel, err = btf.LoadKernelSpec() | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("load kernel spec: %w", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	err := kernel.FindType(typeName, target) | ||||
| 	if errors.Is(err, btf.ErrNotFound) { | ||||
| 		return nil, &internal.UnsupportedFeatureError{ | ||||
| 			Name: featureName, | ||||
| 		} | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("resolve BTF for %s: %w", featureName, err) | ||||
| 	} | ||||
| 	return target, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										125
									
								
								vendor/github.com/cilium/ebpf/run-tests.sh
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										125
									
								
								vendor/github.com/cilium/ebpf/run-tests.sh
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,56 +1,95 @@ | ||||
| #!/bin/bash | ||||
| # Test the current package under a different kernel. | ||||
| # Requires virtme and qemu to be installed. | ||||
| # Examples: | ||||
| #     Run all tests on a 5.4 kernel | ||||
| #     $ ./run-tests.sh 5.4 | ||||
| #     Run a subset of tests: | ||||
| #     $ ./run-tests.sh 5.4 go test ./link | ||||
|  | ||||
| set -eu | ||||
| set -o pipefail | ||||
| set -euo pipefail | ||||
|  | ||||
| if [[ "${1:-}" = "--in-vm" ]]; then | ||||
| script="$(realpath "$0")" | ||||
| readonly script | ||||
|  | ||||
| # This script is a bit like a Matryoshka doll since it keeps re-executing itself | ||||
| # in various different contexts: | ||||
| # | ||||
| #   1. invoked by the user like run-tests.sh 5.4 | ||||
| #   2. invoked by go test like run-tests.sh --exec-vm | ||||
| #   3. invoked by init in the vm like run-tests.sh --exec-test | ||||
| # | ||||
| # This allows us to use all available CPU on the host machine to compile our | ||||
| # code, and then only use the VM to execute the test. This is because the VM | ||||
| # is usually slower at compiling than the host. | ||||
| if [[ "${1:-}" = "--exec-vm" ]]; then | ||||
|   shift | ||||
|  | ||||
|   input="$1" | ||||
|   shift | ||||
|  | ||||
|   # Use sudo if /dev/kvm isn't accessible by the current user. | ||||
|   sudo="" | ||||
|   if [[ ! -r /dev/kvm || ! -w /dev/kvm ]]; then | ||||
|     sudo="sudo" | ||||
|   fi | ||||
|   readonly sudo | ||||
|  | ||||
|   testdir="$(dirname "$1")" | ||||
|   output="$(mktemp -d)" | ||||
|   printf -v cmd "%q " "$@" | ||||
|  | ||||
|   if [[ "$(stat -c '%t:%T' -L /proc/$$/fd/0)" == "1:3" ]]; then | ||||
|     # stdin is /dev/null, which doesn't play well with qemu. Use a fifo as a | ||||
|     # blocking substitute. | ||||
|     mkfifo "${output}/fake-stdin" | ||||
|     # Open for reading and writing to avoid blocking. | ||||
|     exec 0<> "${output}/fake-stdin" | ||||
|     rm "${output}/fake-stdin" | ||||
|   fi | ||||
|  | ||||
|   $sudo virtme-run --kimg "${input}/bzImage" --memory 768M --pwd \ | ||||
|   --rwdir="${testdir}=${testdir}" \ | ||||
|   --rodir=/run/input="${input}" \ | ||||
|   --rwdir=/run/output="${output}" \ | ||||
|   --script-sh "PATH=\"$PATH\" \"$script\" --exec-test $cmd" \ | ||||
|   --qemu-opts -smp 2 # need at least two CPUs for some tests | ||||
|  | ||||
|   if [[ ! -e "${output}/success" ]]; then | ||||
|     exit 1 | ||||
|   fi | ||||
|  | ||||
|   $sudo rm -r "$output" | ||||
|   exit 0 | ||||
| elif [[ "${1:-}" = "--exec-test" ]]; then | ||||
|   shift | ||||
|  | ||||
|   mount -t bpf bpf /sys/fs/bpf | ||||
|   mount -t tracefs tracefs /sys/kernel/debug/tracing | ||||
|   export CGO_ENABLED=0 | ||||
|   export GOFLAGS=-mod=readonly | ||||
|   export GOPATH=/run/go-path | ||||
|   export GOPROXY=file:///run/go-path/pkg/mod/cache/download | ||||
|   export GOSUMDB=off | ||||
|   export GOCACHE=/run/go-cache | ||||
|  | ||||
|   if [[ -d "/run/input/bpf" ]]; then | ||||
|     export KERNEL_SELFTESTS="/run/input/bpf" | ||||
|   fi | ||||
|  | ||||
|   readonly output="${1}" | ||||
|   shift | ||||
|  | ||||
|   echo Running tests... | ||||
|   go test -v -coverpkg=./... -coverprofile="$output/coverage.txt" -count 1 ./... | ||||
|   touch "$output/success" | ||||
|   dmesg -C | ||||
|   if ! "$@"; then | ||||
|     dmesg | ||||
|     exit 1 | ||||
|   fi | ||||
|   touch "/run/output/success" | ||||
|   exit 0 | ||||
| fi | ||||
|  | ||||
| # Pull all dependencies, so that we can run tests without the | ||||
| # vm having network access. | ||||
| go mod download | ||||
|  | ||||
| # Use sudo if /dev/kvm isn't accessible by the current user. | ||||
| sudo="" | ||||
| if [[ ! -r /dev/kvm || ! -w /dev/kvm ]]; then | ||||
|   sudo="sudo" | ||||
| fi | ||||
| readonly sudo | ||||
|  | ||||
| readonly kernel_version="${1:-}" | ||||
| if [[ -z "${kernel_version}" ]]; then | ||||
|   echo "Expecting kernel version as first argument" | ||||
|   exit 1 | ||||
| fi | ||||
| shift | ||||
|  | ||||
| readonly kernel="linux-${kernel_version}.bz" | ||||
| readonly selftests="linux-${kernel_version}-selftests-bpf.bz" | ||||
| readonly input="$(mktemp -d)" | ||||
| readonly output="$(mktemp -d)" | ||||
| readonly tmp_dir="${TMPDIR:-/tmp}" | ||||
| readonly branch="${BRANCH:-master}" | ||||
|  | ||||
| @@ -60,6 +99,7 @@ fetch() { | ||||
| } | ||||
|  | ||||
| fetch "${kernel}" | ||||
| cp "${tmp_dir}/${kernel}" "${input}/bzImage" | ||||
|  | ||||
| if fetch "${selftests}"; then | ||||
|   mkdir "${input}/bpf" | ||||
| @@ -68,25 +108,16 @@ else | ||||
|   echo "No selftests found, disabling" | ||||
| fi | ||||
|  | ||||
| echo Testing on "${kernel_version}" | ||||
| $sudo virtme-run --kimg "${tmp_dir}/${kernel}" --memory 512M --pwd \ | ||||
|   --rw \ | ||||
|   --rwdir=/run/input="${input}" \ | ||||
|   --rwdir=/run/output="${output}" \ | ||||
|   --rodir=/run/go-path="$(go env GOPATH)" \ | ||||
|   --rwdir=/run/go-cache="$(go env GOCACHE)" \ | ||||
|   --script-sh "PATH=\"$PATH\" $(realpath "$0") --in-vm /run/output" \ | ||||
|   --qemu-opts -smp 2 # need at least two CPUs for some tests | ||||
|  | ||||
| if [[ ! -e "${output}/success" ]]; then | ||||
|   echo "Test failed on ${kernel_version}" | ||||
|   exit 1 | ||||
| else | ||||
|   echo "Test successful on ${kernel_version}" | ||||
|   if [[ -v COVERALLS_TOKEN ]]; then | ||||
|     goveralls -coverprofile="${output}/coverage.txt" -service=semaphore -repotoken "$COVERALLS_TOKEN" | ||||
|   fi | ||||
| args=(-v -short -coverpkg=./... -coverprofile=coverage.out -count 1 ./...) | ||||
| if (( $# > 0 )); then | ||||
|   args=("$@") | ||||
| fi | ||||
|  | ||||
| $sudo rm -r "${input}" | ||||
| $sudo rm -r "${output}" | ||||
| export GOFLAGS=-mod=readonly | ||||
| export CGO_ENABLED=0 | ||||
|  | ||||
| echo Testing on "${kernel_version}" | ||||
| go test -exec "$script --exec-vm $input" "${args[@]}" | ||||
| echo "Test successful on ${kernel_version}" | ||||
|  | ||||
| rm -r "${input}" | ||||
|   | ||||
							
								
								
									
										36
									
								
								vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -111,14 +111,13 @@ type Conn struct { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // New establishes a connection to any available bus and authenticates. | ||||
| // Callers should call Close() when done with the connection. | ||||
| // Deprecated: use NewWithContext instead | ||||
| // Deprecated: use NewWithContext instead. | ||||
| func New() (*Conn, error) { | ||||
| 	return NewWithContext(context.Background()) | ||||
| } | ||||
|  | ||||
| // NewWithContext same as New with context | ||||
| // NewWithContext establishes a connection to any available bus and authenticates. | ||||
| // Callers should call Close() when done with the connection. | ||||
| func NewWithContext(ctx context.Context) (*Conn, error) { | ||||
| 	conn, err := NewSystemConnectionContext(ctx) | ||||
| 	if err != nil && os.Geteuid() == 0 { | ||||
| @@ -127,44 +126,41 @@ func NewWithContext(ctx context.Context) (*Conn, error) { | ||||
| 	return conn, err | ||||
| } | ||||
|  | ||||
| // NewSystemConnection establishes a connection to the system bus and authenticates. | ||||
| // Callers should call Close() when done with the connection | ||||
| // Deprecated: use NewSystemConnectionContext instead | ||||
| // Deprecated: use NewSystemConnectionContext instead. | ||||
| func NewSystemConnection() (*Conn, error) { | ||||
| 	return NewSystemConnectionContext(context.Background()) | ||||
| } | ||||
|  | ||||
| // NewSystemConnectionContext same as NewSystemConnection with context | ||||
| // NewSystemConnectionContext establishes a connection to the system bus and authenticates. | ||||
| // Callers should call Close() when done with the connection. | ||||
| func NewSystemConnectionContext(ctx context.Context) (*Conn, error) { | ||||
| 	return NewConnection(func() (*dbus.Conn, error) { | ||||
| 		return dbusAuthHelloConnection(ctx, dbus.SystemBusPrivate) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // NewUserConnection establishes a connection to the session bus and | ||||
| // authenticates. This can be used to connect to systemd user instances. | ||||
| // Callers should call Close() when done with the connection. | ||||
| // Deprecated: use NewUserConnectionContext instead | ||||
| // Deprecated: use NewUserConnectionContext instead. | ||||
| func NewUserConnection() (*Conn, error) { | ||||
| 	return NewUserConnectionContext(context.Background()) | ||||
| } | ||||
|  | ||||
| // NewUserConnectionContext same as NewUserConnection with context | ||||
| // NewUserConnectionContext establishes a connection to the session bus and | ||||
| // authenticates. This can be used to connect to systemd user instances. | ||||
| // Callers should call Close() when done with the connection. | ||||
| func NewUserConnectionContext(ctx context.Context) (*Conn, error) { | ||||
| 	return NewConnection(func() (*dbus.Conn, error) { | ||||
| 		return dbusAuthHelloConnection(ctx, dbus.SessionBusPrivate) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // NewSystemdConnection establishes a private, direct connection to systemd. | ||||
| // This can be used for communicating with systemd without a dbus daemon. | ||||
| // Callers should call Close() when done with the connection. | ||||
| // Deprecated: use NewSystemdConnectionContext instead | ||||
| // Deprecated: use NewSystemdConnectionContext instead. | ||||
| func NewSystemdConnection() (*Conn, error) { | ||||
| 	return NewSystemdConnectionContext(context.Background()) | ||||
| } | ||||
|  | ||||
| // NewSystemdConnectionContext same as NewSystemdConnection with context | ||||
| // NewSystemdConnectionContext establishes a private, direct connection to systemd. | ||||
| // This can be used for communicating with systemd without a dbus daemon. | ||||
| // Callers should call Close() when done with the connection. | ||||
| func NewSystemdConnectionContext(ctx context.Context) (*Conn, error) { | ||||
| 	return NewConnection(func() (*dbus.Conn, error) { | ||||
| 		// We skip Hello when talking directly to systemd. | ||||
| @@ -174,7 +170,7 @@ func NewSystemdConnectionContext(ctx context.Context) (*Conn, error) { | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Close closes an established connection | ||||
| // Close closes an established connection. | ||||
| func (c *Conn) Close() { | ||||
| 	c.sysconn.Close() | ||||
| 	c.sigconn.Close() | ||||
| @@ -217,7 +213,7 @@ func NewConnection(dialBus func() (*dbus.Conn, error)) (*Conn, error) { | ||||
|  | ||||
| // GetManagerProperty returns the value of a property on the org.freedesktop.systemd1.Manager | ||||
| // interface. The value is returned in its string representation, as defined at | ||||
| // https://developer.gnome.org/glib/unstable/gvariant-text.html | ||||
| // https://developer.gnome.org/glib/unstable/gvariant-text.html. | ||||
| func (c *Conn) GetManagerProperty(prop string) (string, error) { | ||||
| 	variant, err := c.sysobj.GetProperty("org.freedesktop.systemd1.Manager." + prop) | ||||
| 	if err != nil { | ||||
|   | ||||
							
								
								
									
										303
									
								
								vendor/github.com/coreos/go-systemd/v22/dbus/methods.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										303
									
								
								vendor/github.com/coreos/go-systemd/v22/dbus/methods.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -73,7 +73,12 @@ func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args | ||||
| 	return jobID, nil | ||||
| } | ||||
|  | ||||
| // StartUnit enqueues a start job and depending jobs, if any (unless otherwise | ||||
| // Deprecated: use StartUnitContext instead. | ||||
| func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.StartUnitContext(context.Background(), name, mode, ch) | ||||
| } | ||||
|  | ||||
| // StartUnitContext enqueues a start job and depending jobs, if any (unless otherwise | ||||
| // specified by the mode string). | ||||
| // | ||||
| // Takes the unit to activate, plus a mode string. The mode needs to be one of | ||||
| @@ -103,137 +108,124 @@ func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args | ||||
| // should not be considered authoritative. | ||||
| // | ||||
| // If an error does occur, it will be returned to the user alongside a job ID of 0. | ||||
| // Deprecated: use StartUnitContext instead | ||||
| func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.StartUnitContext(context.Background(), name, mode, ch) | ||||
| } | ||||
|  | ||||
| // StartUnitContext same as StartUnit with context | ||||
| func (c *Conn) StartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) | ||||
| } | ||||
|  | ||||
| // StopUnit is similar to StartUnit but stops the specified unit rather | ||||
| // than starting it. | ||||
| // Deprecated: use StopUnitContext instead | ||||
| // Deprecated: use StopUnitContext instead. | ||||
| func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.StopUnitContext(context.Background(), name, mode, ch) | ||||
| } | ||||
|  | ||||
| // StopUnitContext same as StopUnit with context | ||||
| // StopUnitContext is similar to StartUnitContext, but stops the specified unit | ||||
| // rather than starting it. | ||||
| func (c *Conn) StopUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) | ||||
| } | ||||
|  | ||||
| // ReloadUnit reloads a unit.  Reloading is done only if the unit is already running and fails otherwise. | ||||
| // Deprecated: use ReloadUnitContext instead | ||||
| // Deprecated: use ReloadUnitContext instead. | ||||
| func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.ReloadUnitContext(context.Background(), name, mode, ch) | ||||
| } | ||||
|  | ||||
| // ReloadUnitContext same as ReloadUnit with context | ||||
| // ReloadUnitContext reloads a unit. Reloading is done only if the unit | ||||
| // is already running, and fails otherwise. | ||||
| func (c *Conn) ReloadUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) | ||||
| } | ||||
|  | ||||
| // RestartUnit restarts a service.  If a service is restarted that isn't | ||||
| // running it will be started. | ||||
| // Deprecated: use RestartUnitContext instead | ||||
| // Deprecated: use RestartUnitContext instead. | ||||
| func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.RestartUnitContext(context.Background(), name, mode, ch) | ||||
| } | ||||
|  | ||||
| // RestartUnitContext same as RestartUnit with context | ||||
| // RestartUnitContext restarts a service. If a service is restarted that isn't | ||||
| // running it will be started. | ||||
| func (c *Conn) RestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) | ||||
| } | ||||
|  | ||||
| // TryRestartUnit is like RestartUnit, except that a service that isn't running | ||||
| // is not affected by the restart. | ||||
| // Deprecated: use TryRestartUnitContext instead | ||||
| // Deprecated: use TryRestartUnitContext instead. | ||||
| func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.TryRestartUnitContext(context.Background(), name, mode, ch) | ||||
| } | ||||
|  | ||||
| // TryRestartUnitContext same as TryRestartUnit with context | ||||
| // TryRestartUnitContext is like RestartUnitContext, except that a service that | ||||
| // isn't running is not affected by the restart. | ||||
| func (c *Conn) TryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) | ||||
| } | ||||
|  | ||||
| // ReloadOrRestartUnit attempts a reload if the unit supports it and use a restart | ||||
| // otherwise. | ||||
| // Deprecated: use ReloadOrRestartUnitContext instead | ||||
| // Deprecated: use ReloadOrRestartUnitContext instead. | ||||
| func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.ReloadOrRestartUnitContext(context.Background(), name, mode, ch) | ||||
| } | ||||
|  | ||||
| // ReloadOrRestartUnitContext same as ReloadOrRestartUnit with context | ||||
| // ReloadOrRestartUnitContext attempts a reload if the unit supports it and use | ||||
| // a restart otherwise. | ||||
| func (c *Conn) ReloadOrRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) | ||||
| } | ||||
|  | ||||
| // ReloadOrTryRestartUnit attempts a reload if the unit supports it and use a "Try" | ||||
| // flavored restart otherwise. | ||||
| // Deprecated: use ReloadOrTryRestartUnitContext instead | ||||
| // Deprecated: use ReloadOrTryRestartUnitContext instead. | ||||
| func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.ReloadOrTryRestartUnitContext(context.Background(), name, mode, ch) | ||||
| } | ||||
|  | ||||
| // ReloadOrTryRestartUnitContext same as ReloadOrTryRestartUnit with context | ||||
| // ReloadOrTryRestartUnitContext attempts a reload if the unit supports it, | ||||
| // and use a "Try" flavored restart otherwise. | ||||
| func (c *Conn) ReloadOrTryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { | ||||
| 	return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) | ||||
| } | ||||
|  | ||||
| // StartTransientUnit() may be used to create and start a transient unit, which | ||||
| // will be released as soon as it is not running or referenced anymore or the | ||||
| // system is rebooted. name is the unit name including suffix, and must be | ||||
| // unique. mode is the same as in StartUnit(), properties contains properties | ||||
| // of the unit. | ||||
| // Deprecated: use StartTransientUnitContext instead | ||||
| // Deprecated: use StartTransientUnitContext instead. | ||||
| func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) { | ||||
| 	return c.StartTransientUnitContext(context.Background(), name, mode, properties, ch) | ||||
| } | ||||
|  | ||||
| // StartTransientUnitContext same as StartTransientUnit with context | ||||
| // StartTransientUnitContext may be used to create and start a transient unit, which | ||||
| // will be released as soon as it is not running or referenced anymore or the | ||||
| // system is rebooted. name is the unit name including suffix, and must be | ||||
| // unique. mode is the same as in StartUnitContext, properties contains properties | ||||
| // of the unit. | ||||
| func (c *Conn) StartTransientUnitContext(ctx context.Context, name string, mode string, properties []Property, ch chan<- string) (int, error) { | ||||
| 	return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) | ||||
| } | ||||
|  | ||||
| // KillUnit takes the unit name and a UNIX signal number to send.  All of the unit's | ||||
| // processes are killed. | ||||
| // Deprecated: use KillUnitContext instead | ||||
| // Deprecated: use KillUnitContext instead. | ||||
| func (c *Conn) KillUnit(name string, signal int32) { | ||||
| 	c.KillUnitContext(context.Background(), name, signal) | ||||
| } | ||||
|  | ||||
| // KillUnitContext same as KillUnit with context | ||||
| // KillUnitContext takes the unit name and a UNIX signal number to send. | ||||
| // All of the unit's processes are killed. | ||||
| func (c *Conn) KillUnitContext(ctx context.Context, name string, signal int32) { | ||||
| 	c.KillUnitWithTarget(ctx, name, All, signal) | ||||
| } | ||||
|  | ||||
| // KillUnitWithTarget is like KillUnitContext, but allows you to specify which process in the unit to send the signal to | ||||
| // KillUnitWithTarget is like KillUnitContext, but allows you to specify which | ||||
| // process in the unit to send the signal to. | ||||
| func (c *Conn) KillUnitWithTarget(ctx context.Context, name string, target Who, signal int32) error { | ||||
| 	return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.KillUnit", 0, name, string(target), signal).Store() | ||||
| } | ||||
|  | ||||
| // ResetFailedUnit resets the "failed" state of a specific unit. | ||||
| // Deprecated: use ResetFailedUnitContext instead | ||||
| // Deprecated: use ResetFailedUnitContext instead. | ||||
| func (c *Conn) ResetFailedUnit(name string) error { | ||||
| 	return c.ResetFailedUnitContext(context.Background(), name) | ||||
| } | ||||
|  | ||||
| // ResetFailedUnitContext same as ResetFailedUnit with context | ||||
| // ResetFailedUnitContext resets the "failed" state of a specific unit. | ||||
| func (c *Conn) ResetFailedUnitContext(ctx context.Context, name string) error { | ||||
| 	return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() | ||||
| } | ||||
|  | ||||
| // SystemState returns the systemd state. Equivalent to `systemctl is-system-running`. | ||||
| // Deprecated: use SystemStateContext instead | ||||
| // Deprecated: use SystemStateContext instead. | ||||
| func (c *Conn) SystemState() (*Property, error) { | ||||
| 	return c.SystemStateContext(context.Background()) | ||||
| } | ||||
|  | ||||
| // SystemStateContext same as SystemState with context | ||||
| // SystemStateContext returns the systemd state. Equivalent to | ||||
| // systemctl is-system-running. | ||||
| func (c *Conn) SystemStateContext(ctx context.Context) (*Property, error) { | ||||
| 	var err error | ||||
| 	var prop dbus.Variant | ||||
| @@ -247,7 +239,7 @@ func (c *Conn) SystemStateContext(ctx context.Context) (*Property, error) { | ||||
| 	return &Property{Name: "SystemState", Value: prop}, nil | ||||
| } | ||||
|  | ||||
| // getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface | ||||
| // getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface. | ||||
| func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) { | ||||
| 	var err error | ||||
| 	var props map[string]dbus.Variant | ||||
| @@ -270,36 +262,36 @@ func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInte | ||||
| 	return out, nil | ||||
| } | ||||
|  | ||||
| // GetUnitProperties takes the (unescaped) unit name and returns all of its dbus object properties. | ||||
| // Deprecated: use GetUnitPropertiesContext instead | ||||
| // Deprecated: use GetUnitPropertiesContext instead. | ||||
| func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { | ||||
| 	return c.GetUnitPropertiesContext(context.Background(), unit) | ||||
| } | ||||
|  | ||||
| // GetUnitPropertiesContext same as GetUnitPropertiesContext with context | ||||
| // GetUnitPropertiesContext takes the (unescaped) unit name and returns all of | ||||
| // its dbus object properties. | ||||
| func (c *Conn) GetUnitPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { | ||||
| 	path := unitPath(unit) | ||||
| 	return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") | ||||
| } | ||||
|  | ||||
| // GetUnitPathProperties takes the (escaped) unit path and returns all of its dbus object properties. | ||||
| // Deprecated: use GetUnitPathPropertiesContext instead | ||||
| // Deprecated: use GetUnitPathPropertiesContext instead. | ||||
| func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) { | ||||
| 	return c.GetUnitPathPropertiesContext(context.Background(), path) | ||||
| } | ||||
|  | ||||
| // GetUnitPathPropertiesContext same as GetUnitPathProperties with context | ||||
| // GetUnitPathPropertiesContext takes the (escaped) unit path and returns all | ||||
| // of its dbus object properties. | ||||
| func (c *Conn) GetUnitPathPropertiesContext(ctx context.Context, path dbus.ObjectPath) (map[string]interface{}, error) { | ||||
| 	return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") | ||||
| } | ||||
|  | ||||
| // GetAllProperties takes the (unescaped) unit name and returns all of its dbus object properties. | ||||
| // Deprecated: use GetAllPropertiesContext instead | ||||
| // Deprecated: use GetAllPropertiesContext instead. | ||||
| func (c *Conn) GetAllProperties(unit string) (map[string]interface{}, error) { | ||||
| 	return c.GetAllPropertiesContext(context.Background(), unit) | ||||
| } | ||||
|  | ||||
| // GetAllPropertiesContext same as GetAllProperties with context | ||||
| // GetAllPropertiesContext takes the (unescaped) unit name and returns all of | ||||
| // its dbus object properties. | ||||
| func (c *Conn) GetAllPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { | ||||
| 	path := unitPath(unit) | ||||
| 	return c.getProperties(ctx, path, "") | ||||
| @@ -323,64 +315,63 @@ func (c *Conn) getProperty(ctx context.Context, unit string, dbusInterface strin | ||||
| 	return &Property{Name: propertyName, Value: prop}, nil | ||||
| } | ||||
|  | ||||
| // Deprecated: use GetUnitPropertyContext instead | ||||
| // Deprecated: use GetUnitPropertyContext instead. | ||||
| func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) { | ||||
| 	return c.GetUnitPropertyContext(context.Background(), unit, propertyName) | ||||
| } | ||||
|  | ||||
| // GetUnitPropertyContext same as GetUnitProperty with context | ||||
| // GetUnitPropertyContext takes an (unescaped) unit name, and a property name, | ||||
| // and returns the property value. | ||||
| func (c *Conn) GetUnitPropertyContext(ctx context.Context, unit string, propertyName string) (*Property, error) { | ||||
| 	return c.getProperty(ctx, unit, "org.freedesktop.systemd1.Unit", propertyName) | ||||
| } | ||||
|  | ||||
| // GetServiceProperty returns property for given service name and property name | ||||
| // Deprecated: use GetServicePropertyContext instead | ||||
| // Deprecated: use GetServicePropertyContext instead. | ||||
| func (c *Conn) GetServiceProperty(service string, propertyName string) (*Property, error) { | ||||
| 	return c.GetServicePropertyContext(context.Background(), service, propertyName) | ||||
| } | ||||
|  | ||||
| // GetServicePropertyContext same as GetServiceProperty with context | ||||
| // GetServiceProperty returns property for given service name and property name. | ||||
| func (c *Conn) GetServicePropertyContext(ctx context.Context, service string, propertyName string) (*Property, error) { | ||||
| 	return c.getProperty(ctx, service, "org.freedesktop.systemd1.Service", propertyName) | ||||
| } | ||||
|  | ||||
| // GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type. | ||||
| // Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope | ||||
| // return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit | ||||
| // Deprecated: use GetUnitTypePropertiesContext instead | ||||
| // Deprecated: use GetUnitTypePropertiesContext instead. | ||||
| func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) { | ||||
| 	return c.GetUnitTypePropertiesContext(context.Background(), unit, unitType) | ||||
| } | ||||
|  | ||||
| // GetUnitTypePropertiesContext same as GetUnitTypeProperties with context | ||||
| // GetUnitTypePropertiesContext returns the extra properties for a unit, specific to the unit type. | ||||
| // Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope. | ||||
| // Returns "dbus.Error: Unknown interface" error if the unitType is not the correct type of the unit. | ||||
| func (c *Conn) GetUnitTypePropertiesContext(ctx context.Context, unit string, unitType string) (map[string]interface{}, error) { | ||||
| 	path := unitPath(unit) | ||||
| 	return c.getProperties(ctx, path, "org.freedesktop.systemd1."+unitType) | ||||
| } | ||||
|  | ||||
| // SetUnitProperties() may be used to modify certain unit properties at runtime. | ||||
| // Deprecated: use SetUnitPropertiesContext instead. | ||||
| func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error { | ||||
| 	return c.SetUnitPropertiesContext(context.Background(), name, runtime, properties...) | ||||
| } | ||||
|  | ||||
| // SetUnitPropertiesContext may be used to modify certain unit properties at runtime. | ||||
| // Not all properties may be changed at runtime, but many resource management | ||||
| // settings (primarily those in systemd.cgroup(5)) may. The changes are applied | ||||
| // instantly, and stored on disk for future boots, unless runtime is true, in which | ||||
| // case the settings only apply until the next reboot. name is the name of the unit | ||||
| // to modify. properties are the settings to set, encoded as an array of property | ||||
| // name and value pairs. | ||||
| // Deprecated: use SetUnitPropertiesContext instead | ||||
| func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error { | ||||
| 	return c.SetUnitPropertiesContext(context.Background(), name, runtime, properties...) | ||||
| } | ||||
|  | ||||
| // SetUnitPropertiesContext same as SetUnitProperties with context | ||||
| func (c *Conn) SetUnitPropertiesContext(ctx context.Context, name string, runtime bool, properties ...Property) error { | ||||
| 	return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store() | ||||
| } | ||||
|  | ||||
| // Deprecated: use GetUnitTypePropertyContext instead | ||||
| // Deprecated: use GetUnitTypePropertyContext instead. | ||||
| func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) { | ||||
| 	return c.GetUnitTypePropertyContext(context.Background(), unit, unitType, propertyName) | ||||
| } | ||||
|  | ||||
| // GetUnitTypePropertyContext same as GetUnitTypeProperty with context | ||||
| // GetUnitTypePropertyContext takes a property name, a unit name, and a unit type, | ||||
| // and returns a property value. For valid values of unitType, see GetUnitTypePropertiesContext. | ||||
| func (c *Conn) GetUnitTypePropertyContext(ctx context.Context, unit string, unitType string, propertyName string) (*Property, error) { | ||||
| 	return c.getProperty(ctx, unit, "org.freedesktop.systemd1."+unitType, propertyName) | ||||
| } | ||||
| @@ -426,58 +417,55 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { | ||||
| 	return status, nil | ||||
| } | ||||
|  | ||||
| // ListUnits returns an array with all currently loaded units. Note that | ||||
| // units may be known by multiple names at the same time, and hence there might | ||||
| // be more unit names loaded than actual units behind them. | ||||
| // Also note that a unit is only loaded if it is active and/or enabled. | ||||
| // Units that are both disabled and inactive will thus not be returned. | ||||
| // Deprecated: use ListUnitsContext instead | ||||
| // Deprecated: use ListUnitsContext instead. | ||||
| func (c *Conn) ListUnits() ([]UnitStatus, error) { | ||||
| 	return c.ListUnitsContext(context.Background()) | ||||
| } | ||||
|  | ||||
| // ListUnitsContext same as ListUnits with context | ||||
| // ListUnitsContext returns an array with all currently loaded units. Note that | ||||
| // units may be known by multiple names at the same time, and hence there might | ||||
| // be more unit names loaded than actual units behind them. | ||||
| // Also note that a unit is only loaded if it is active and/or enabled. | ||||
| // Units that are both disabled and inactive will thus not be returned. | ||||
| func (c *Conn) ListUnitsContext(ctx context.Context) ([]UnitStatus, error) { | ||||
| 	return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnits", 0).Store) | ||||
| } | ||||
|  | ||||
| // ListUnitsFiltered returns an array with units filtered by state. | ||||
| // It takes a list of units' statuses to filter. | ||||
| // Deprecated: use ListUnitsFilteredContext instead | ||||
| // Deprecated: use ListUnitsFilteredContext instead. | ||||
| func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) { | ||||
| 	return c.ListUnitsFilteredContext(context.Background(), states) | ||||
| } | ||||
|  | ||||
| // ListUnitsFilteredContext same as ListUnitsFiltered with context | ||||
| // ListUnitsFilteredContext returns an array with units filtered by state. | ||||
| // It takes a list of units' statuses to filter. | ||||
| func (c *Conn) ListUnitsFilteredContext(ctx context.Context, states []string) ([]UnitStatus, error) { | ||||
| 	return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) | ||||
| } | ||||
|  | ||||
| // ListUnitsByPatterns returns an array with units. | ||||
| // It takes a list of units' statuses and names to filter. | ||||
| // Note that units may be known by multiple names at the same time, | ||||
| // and hence there might be more unit names loaded than actual units behind them. | ||||
| // Deprecated: use ListUnitsByPatternsContext instead | ||||
| // Deprecated: use ListUnitsByPatternsContext instead. | ||||
| func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) { | ||||
| 	return c.ListUnitsByPatternsContext(context.Background(), states, patterns) | ||||
| } | ||||
|  | ||||
| // ListUnitsByPatternsContext same as ListUnitsByPatterns with context | ||||
| // ListUnitsByPatternsContext returns an array with units. | ||||
| // It takes a list of units' statuses and names to filter. | ||||
| // Note that units may be known by multiple names at the same time, | ||||
| // and hence there might be more unit names loaded than actual units behind them. | ||||
| func (c *Conn) ListUnitsByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitStatus, error) { | ||||
| 	return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) | ||||
| } | ||||
|  | ||||
| // ListUnitsByNames returns an array with units. It takes a list of units' | ||||
| // names and returns an UnitStatus array. Comparing to ListUnitsByPatterns | ||||
| // method, this method returns statuses even for inactive or non-existing | ||||
| // units. Input array should contain exact unit names, but not patterns. | ||||
| // Note: Requires systemd v230 or higher | ||||
| // Deprecated: use ListUnitsByNamesContext instead | ||||
| // Deprecated: use ListUnitsByNamesContext instead. | ||||
| func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { | ||||
| 	return c.ListUnitsByNamesContext(context.Background(), units) | ||||
| } | ||||
|  | ||||
| // ListUnitsByNamesContext same as ListUnitsByNames with context | ||||
| // ListUnitsByNamesContext returns an array with units. It takes a list of units' | ||||
| // names and returns an UnitStatus array. Comparing to ListUnitsByPatternsContext | ||||
| // method, this method returns statuses even for inactive or non-existing | ||||
| // units. Input array should contain exact unit names, but not patterns. | ||||
| // | ||||
| // Requires systemd v230 or higher. | ||||
| func (c *Conn) ListUnitsByNamesContext(ctx context.Context, units []string) ([]UnitStatus, error) { | ||||
| 	return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) | ||||
| } | ||||
| @@ -513,37 +501,43 @@ func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) { | ||||
| 	return files, nil | ||||
| } | ||||
|  | ||||
| // ListUnitFiles returns an array of all available units on disk. | ||||
| // Deprecated: use ListUnitFilesContext instead | ||||
| // Deprecated: use ListUnitFilesContext instead. | ||||
| func (c *Conn) ListUnitFiles() ([]UnitFile, error) { | ||||
| 	return c.ListUnitFilesContext(context.Background()) | ||||
| } | ||||
|  | ||||
| // ListUnitFilesContext same as ListUnitFiles with context | ||||
| // ListUnitFiles returns an array of all available units on disk. | ||||
| func (c *Conn) ListUnitFilesContext(ctx context.Context) ([]UnitFile, error) { | ||||
| 	return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) | ||||
| } | ||||
|  | ||||
| // ListUnitFilesByPatterns returns an array of all available units on disk matched the patterns. | ||||
| // Deprecated: use ListUnitFilesByPatternsContext instead | ||||
| // Deprecated: use ListUnitFilesByPatternsContext instead. | ||||
| func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) { | ||||
| 	return c.ListUnitFilesByPatternsContext(context.Background(), states, patterns) | ||||
| } | ||||
|  | ||||
| // ListUnitFilesByPatternsContext same as ListUnitFilesByPatterns with context | ||||
| // ListUnitFilesByPatternsContext returns an array of all available units on disk matched the patterns. | ||||
| func (c *Conn) ListUnitFilesByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitFile, error) { | ||||
| 	return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) | ||||
| } | ||||
|  | ||||
| type LinkUnitFileChange EnableUnitFileChange | ||||
|  | ||||
| // LinkUnitFiles() links unit files (that are located outside of the | ||||
| // Deprecated: use LinkUnitFilesContext instead. | ||||
| func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { | ||||
| 	return c.LinkUnitFilesContext(context.Background(), files, runtime, force) | ||||
| } | ||||
|  | ||||
| // LinkUnitFilesContext links unit files (that are located outside of the | ||||
| // usual unit search paths) into the unit search path. | ||||
| // | ||||
| // It takes a list of absolute paths to unit files to link and two | ||||
| // booleans. The first boolean controls whether the unit shall be | ||||
| // booleans. | ||||
| // | ||||
| // The first boolean controls whether the unit shall be | ||||
| // enabled for runtime only (true, /run), or persistently (false, | ||||
| // /etc). | ||||
| // | ||||
| // The second controls whether symlinks pointing to other units shall | ||||
| // be replaced if necessary. | ||||
| // | ||||
| @@ -551,12 +545,6 @@ type LinkUnitFileChange EnableUnitFileChange | ||||
| // structures with three strings: the type of the change (one of symlink | ||||
| // or unlink), the file name of the symlink and the destination of the | ||||
| // symlink. | ||||
| // Deprecated: use LinkUnitFilesContext instead | ||||
| func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { | ||||
| 	return c.LinkUnitFilesContext(context.Background(), files, runtime, force) | ||||
| } | ||||
|  | ||||
| // LinkUnitFilesContext same as LinkUnitFiles with context | ||||
| func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { | ||||
| 	result := make([][]interface{}, 0) | ||||
| 	err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) | ||||
| @@ -583,8 +571,13 @@ func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime | ||||
| 	return changes, nil | ||||
| } | ||||
|  | ||||
| // EnableUnitFiles() may be used to enable one or more units in the system (by | ||||
| // creating symlinks to them in /etc or /run). | ||||
| // Deprecated: use EnableUnitFilesContext instead. | ||||
| func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { | ||||
| 	return c.EnableUnitFilesContext(context.Background(), files, runtime, force) | ||||
| } | ||||
|  | ||||
| // EnableUnitFilesContext may be used to enable one or more units in the system | ||||
| // (by creating symlinks to them in /etc or /run). | ||||
| // | ||||
| // It takes a list of unit files to enable (either just file names or full | ||||
| // absolute paths if the unit files are residing outside the usual unit | ||||
| @@ -599,12 +592,6 @@ func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime | ||||
| // structures with three strings: the type of the change (one of symlink | ||||
| // or unlink), the file name of the symlink and the destination of the | ||||
| // symlink. | ||||
| // Deprecated: use EnableUnitFilesContext instead | ||||
| func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { | ||||
| 	return c.EnableUnitFilesContext(context.Background(), files, runtime, force) | ||||
| } | ||||
|  | ||||
| // EnableUnitFilesContext same as EnableUnitFiles with context | ||||
| func (c *Conn) EnableUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { | ||||
| 	var carries_install_info bool | ||||
|  | ||||
| @@ -639,8 +626,13 @@ type EnableUnitFileChange struct { | ||||
| 	Destination string // Destination of the symlink | ||||
| } | ||||
|  | ||||
| // DisableUnitFiles() may be used to disable one or more units in the system (by | ||||
| // removing symlinks to them from /etc or /run). | ||||
| // Deprecated: use DisableUnitFilesContext instead. | ||||
| func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) { | ||||
| 	return c.DisableUnitFilesContext(context.Background(), files, runtime) | ||||
| } | ||||
|  | ||||
| // DisableUnitFilesContext may be used to disable one or more units in the | ||||
| // system (by removing symlinks to them from /etc or /run). | ||||
| // | ||||
| // It takes a list of unit files to disable (either just file names or full | ||||
| // absolute paths if the unit files are residing outside the usual unit | ||||
| @@ -651,12 +643,6 @@ type EnableUnitFileChange struct { | ||||
| // consists of structures with three strings: the type of the change (one of | ||||
| // symlink or unlink), the file name of the symlink and the destination of the | ||||
| // symlink. | ||||
| // Deprecated: use DisableUnitFilesContext instead | ||||
| func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) { | ||||
| 	return c.DisableUnitFilesContext(context.Background(), files, runtime) | ||||
| } | ||||
|  | ||||
| // DisableUnitFilesContext same as DisableUnitFiles with context | ||||
| func (c *Conn) DisableUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]DisableUnitFileChange, error) { | ||||
| 	result := make([][]interface{}, 0) | ||||
| 	err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) | ||||
| @@ -689,21 +675,20 @@ type DisableUnitFileChange struct { | ||||
| 	Destination string // Destination of the symlink | ||||
| } | ||||
|  | ||||
| // MaskUnitFiles masks one or more units in the system | ||||
| // | ||||
| // It takes three arguments: | ||||
| //   * list of units to mask (either just file names or full | ||||
| //     absolute paths if the unit files are residing outside | ||||
| //     the usual unit search paths) | ||||
| //   * runtime to specify whether the unit was enabled for runtime | ||||
| //     only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) | ||||
| //   * force flag | ||||
| // Deprecated: use MaskUnitFilesContext instead | ||||
| // Deprecated: use MaskUnitFilesContext instead. | ||||
| func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { | ||||
| 	return c.MaskUnitFilesContext(context.Background(), files, runtime, force) | ||||
| } | ||||
|  | ||||
| // MaskUnitFilesContext same as MaskUnitFiles with context | ||||
| // MaskUnitFilesContext masks one or more units in the system. | ||||
| // | ||||
| // The files argument contains a  list of units to mask (either just file names | ||||
| // or full absolute paths if the unit files are residing outside the usual unit | ||||
| // search paths). | ||||
| // | ||||
| // The runtime argument is used to specify whether the unit was enabled for | ||||
| // runtime only (true, /run/systemd/..), or persistently (false, | ||||
| // /etc/systemd/..). | ||||
| func (c *Conn) MaskUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { | ||||
| 	result := make([][]interface{}, 0) | ||||
| 	err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) | ||||
| @@ -736,20 +721,18 @@ type MaskUnitFileChange struct { | ||||
| 	Destination string // Destination of the symlink | ||||
| } | ||||
|  | ||||
| // UnmaskUnitFiles unmasks one or more units in the system | ||||
| // | ||||
| // It takes two arguments: | ||||
| //   * list of unit files to mask (either just file names or full | ||||
| //     absolute paths if the unit files are residing outside | ||||
| //     the usual unit search paths) | ||||
| //   * runtime to specify whether the unit was enabled for runtime | ||||
| //     only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) | ||||
| // Deprecated: use UnmaskUnitFilesContext instead | ||||
| // Deprecated: use UnmaskUnitFilesContext instead. | ||||
| func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileChange, error) { | ||||
| 	return c.UnmaskUnitFilesContext(context.Background(), files, runtime) | ||||
| } | ||||
|  | ||||
| // UnmaskUnitFilesContext same as UnmaskUnitFiles with context | ||||
| // UnmaskUnitFilesContext unmasks one or more units in the system. | ||||
| // | ||||
| // It takes the list of unit files to mask (either just file names or full | ||||
| // absolute paths if the unit files are residing outside the usual unit search | ||||
| // paths), and a boolean runtime flag to specify whether the unit was enabled | ||||
| // for runtime only (true, /run/systemd/..), or persistently (false, | ||||
| // /etc/systemd/..). | ||||
| func (c *Conn) UnmaskUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]UnmaskUnitFileChange, error) { | ||||
| 	result := make([][]interface{}, 0) | ||||
| 	err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) | ||||
| @@ -782,14 +765,13 @@ type UnmaskUnitFileChange struct { | ||||
| 	Destination string // Destination of the symlink | ||||
| } | ||||
|  | ||||
| // Reload instructs systemd to scan for and reload unit files. This is | ||||
| // equivalent to a 'systemctl daemon-reload'. | ||||
| // Deprecated: use ReloadContext instead | ||||
| // Deprecated: use ReloadContext instead. | ||||
| func (c *Conn) Reload() error { | ||||
| 	return c.ReloadContext(context.Background()) | ||||
| } | ||||
|  | ||||
| // ReloadContext same as Reload with context | ||||
| // ReloadContext instructs systemd to scan for and reload unit files. This is | ||||
| // an equivalent to systemctl daemon-reload. | ||||
| func (c *Conn) ReloadContext(ctx context.Context) error { | ||||
| 	return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.Reload", 0).Store() | ||||
| } | ||||
| @@ -798,12 +780,12 @@ func unitPath(name string) dbus.ObjectPath { | ||||
| 	return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name)) | ||||
| } | ||||
|  | ||||
| // unitName returns the unescaped base element of the supplied escaped path | ||||
| // unitName returns the unescaped base element of the supplied escaped path. | ||||
| func unitName(dpath dbus.ObjectPath) string { | ||||
| 	return pathBusUnescape(path.Base(string(dpath))) | ||||
| } | ||||
|  | ||||
| // Currently queued job definition | ||||
| // JobStatus holds a currently queued job definition. | ||||
| type JobStatus struct { | ||||
| 	Id       uint32          // The numeric job id | ||||
| 	Unit     string          // The primary unit name for this job | ||||
| @@ -813,13 +795,12 @@ type JobStatus struct { | ||||
| 	UnitPath dbus.ObjectPath // The unit object path | ||||
| } | ||||
|  | ||||
| // ListJobs returns an array with all currently queued jobs | ||||
| // Deprecated: use ListJobsContext instead | ||||
| // Deprecated: use ListJobsContext instead. | ||||
| func (c *Conn) ListJobs() ([]JobStatus, error) { | ||||
| 	return c.ListJobsContext(context.Background()) | ||||
| } | ||||
|  | ||||
| // ListJobsContext same as ListJobs with context | ||||
| // ListJobsContext returns an array with all currently queued jobs. | ||||
| func (c *Conn) ListJobsContext(ctx context.Context) ([]JobStatus, error) { | ||||
| 	return c.listJobsInternal(ctx) | ||||
| } | ||||
|   | ||||
							
								
								
									
										10
									
								
								vendor/github.com/golang/protobuf/proto/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/golang/protobuf/proto/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -13,6 +13,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"google.golang.org/protobuf/reflect/protodesc" | ||||
| 	"google.golang.org/protobuf/reflect/protoreflect" | ||||
| 	"google.golang.org/protobuf/reflect/protoregistry" | ||||
| 	"google.golang.org/protobuf/runtime/protoimpl" | ||||
| @@ -62,14 +63,7 @@ func FileDescriptor(s filePath) fileDescGZIP { | ||||
| 	// Find the descriptor in the v2 registry. | ||||
| 	var b []byte | ||||
| 	if fd, _ := protoregistry.GlobalFiles.FindFileByPath(s); fd != nil { | ||||
| 		if fd, ok := fd.(interface{ ProtoLegacyRawDesc() []byte }); ok { | ||||
| 			b = fd.ProtoLegacyRawDesc() | ||||
| 		} else { | ||||
| 			// TODO: Use protodesc.ToFileDescriptorProto to construct | ||||
| 			// a descriptorpb.FileDescriptorProto and marshal it. | ||||
| 			// However, doing so causes the proto package to have a dependency | ||||
| 			// on descriptorpb, leading to cyclic dependency issues. | ||||
| 		} | ||||
| 		b, _ = Marshal(protodesc.ToFileDescriptorProto(fd)) | ||||
| 	} | ||||
|  | ||||
| 	// Locally cache the raw descriptor form for the file. | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/github.com/golang/protobuf/ptypes/any.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/golang/protobuf/ptypes/any.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -19,6 +19,8 @@ const urlPrefix = "type.googleapis.com/" | ||||
|  | ||||
| // AnyMessageName returns the message name contained in an anypb.Any message. | ||||
| // Most type assertions should use the Is function instead. | ||||
| // | ||||
| // Deprecated: Call the any.MessageName method instead. | ||||
| func AnyMessageName(any *anypb.Any) (string, error) { | ||||
| 	name, err := anyMessageName(any) | ||||
| 	return string(name), err | ||||
| @@ -38,6 +40,8 @@ func anyMessageName(any *anypb.Any) (protoreflect.FullName, error) { | ||||
| } | ||||
|  | ||||
| // MarshalAny marshals the given message m into an anypb.Any message. | ||||
| // | ||||
| // Deprecated: Call the anypb.New function instead. | ||||
| func MarshalAny(m proto.Message) (*anypb.Any, error) { | ||||
| 	switch dm := m.(type) { | ||||
| 	case DynamicAny: | ||||
| @@ -58,6 +62,9 @@ func MarshalAny(m proto.Message) (*anypb.Any, error) { | ||||
| // Empty returns a new message of the type specified in an anypb.Any message. | ||||
| // It returns protoregistry.NotFound if the corresponding message type could not | ||||
| // be resolved in the global registry. | ||||
| // | ||||
| // Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead | ||||
| // to resolve the message name and create a new instance of it. | ||||
| func Empty(any *anypb.Any) (proto.Message, error) { | ||||
| 	name, err := anyMessageName(any) | ||||
| 	if err != nil { | ||||
| @@ -76,6 +83,8 @@ func Empty(any *anypb.Any) (proto.Message, error) { | ||||
| // | ||||
| // The target message m may be a *DynamicAny message. If the underlying message | ||||
| // type could not be resolved, then this returns protoregistry.NotFound. | ||||
| // | ||||
| // Deprecated: Call the any.UnmarshalTo method instead. | ||||
| func UnmarshalAny(any *anypb.Any, m proto.Message) error { | ||||
| 	if dm, ok := m.(*DynamicAny); ok { | ||||
| 		if dm.Message == nil { | ||||
| @@ -100,6 +109,8 @@ func UnmarshalAny(any *anypb.Any, m proto.Message) error { | ||||
| } | ||||
|  | ||||
| // Is reports whether the Any message contains a message of the specified type. | ||||
| // | ||||
| // Deprecated: Call the any.MessageIs method instead. | ||||
| func Is(any *anypb.Any, m proto.Message) bool { | ||||
| 	if any == nil || m == nil { | ||||
| 		return false | ||||
| @@ -119,6 +130,9 @@ func Is(any *anypb.Any, m proto.Message) bool { | ||||
| //   var x ptypes.DynamicAny | ||||
| //   if err := ptypes.UnmarshalAny(a, &x); err != nil { ... } | ||||
| //   fmt.Printf("unmarshaled message: %v", x.Message) | ||||
| // | ||||
| // Deprecated: Use the any.UnmarshalNew method instead to unmarshal | ||||
| // the any message contents into a new instance of the underlying message. | ||||
| type DynamicAny struct{ proto.Message } | ||||
|  | ||||
| func (m DynamicAny) String() string { | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/golang/protobuf/ptypes/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/golang/protobuf/ptypes/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,4 +3,8 @@ | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Package ptypes provides functionality for interacting with well-known types. | ||||
| // | ||||
| // Deprecated: Well-known types have specialized functionality directly | ||||
| // injected into the generated packages for each message type. | ||||
| // See the deprecation notice for each function for the suggested alternative. | ||||
| package ptypes | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/golang/protobuf/ptypes/duration.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/golang/protobuf/ptypes/duration.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -21,6 +21,8 @@ const ( | ||||
|  | ||||
| // Duration converts a durationpb.Duration to a time.Duration. | ||||
| // Duration returns an error if dur is invalid or overflows a time.Duration. | ||||
| // | ||||
| // Deprecated: Call the dur.AsDuration and dur.CheckValid methods instead. | ||||
| func Duration(dur *durationpb.Duration) (time.Duration, error) { | ||||
| 	if err := validateDuration(dur); err != nil { | ||||
| 		return 0, err | ||||
| @@ -39,6 +41,8 @@ func Duration(dur *durationpb.Duration) (time.Duration, error) { | ||||
| } | ||||
|  | ||||
| // DurationProto converts a time.Duration to a durationpb.Duration. | ||||
| // | ||||
| // Deprecated: Call the durationpb.New function instead. | ||||
| func DurationProto(d time.Duration) *durationpb.Duration { | ||||
| 	nanos := d.Nanoseconds() | ||||
| 	secs := nanos / 1e9 | ||||
|   | ||||
							
								
								
									
										9
									
								
								vendor/github.com/golang/protobuf/ptypes/timestamp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/golang/protobuf/ptypes/timestamp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -33,6 +33,8 @@ const ( | ||||
| // | ||||
| // A nil Timestamp returns an error. The first return value in that case is | ||||
| // undefined. | ||||
| // | ||||
| // Deprecated: Call the ts.AsTime and ts.CheckValid methods instead. | ||||
| func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) { | ||||
| 	// Don't return the zero value on error, because corresponds to a valid | ||||
| 	// timestamp. Instead return whatever time.Unix gives us. | ||||
| @@ -46,6 +48,8 @@ func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) { | ||||
| } | ||||
|  | ||||
| // TimestampNow returns a google.protobuf.Timestamp for the current time. | ||||
| // | ||||
| // Deprecated: Call the timestamppb.Now function instead. | ||||
| func TimestampNow() *timestamppb.Timestamp { | ||||
| 	ts, err := TimestampProto(time.Now()) | ||||
| 	if err != nil { | ||||
| @@ -56,6 +60,8 @@ func TimestampNow() *timestamppb.Timestamp { | ||||
|  | ||||
| // TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. | ||||
| // It returns an error if the resulting Timestamp is invalid. | ||||
| // | ||||
| // Deprecated: Call the timestamppb.New function instead. | ||||
| func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) { | ||||
| 	ts := ×tamppb.Timestamp{ | ||||
| 		Seconds: t.Unix(), | ||||
| @@ -69,6 +75,9 @@ func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) { | ||||
|  | ||||
| // TimestampString returns the RFC 3339 string for valid Timestamps. | ||||
| // For invalid Timestamps, it returns an error message in parentheses. | ||||
| // | ||||
| // Deprecated: Call the ts.AsTime method instead, | ||||
| // followed by a call to the Format method on the time.Time value. | ||||
| func TimestampString(ts *timestamppb.Timestamp) string { | ||||
| 	t, err := Timestamp(ts) | ||||
| 	if err != nil { | ||||
|   | ||||
							
								
								
									
										8
									
								
								vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,7 +11,6 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/google/go-cmp/cmp" | ||||
| 	"golang.org/x/xerrors" | ||||
| ) | ||||
|  | ||||
| func equateAlways(_, _ interface{}) bool { return true } | ||||
| @@ -147,10 +146,3 @@ func areConcreteErrors(x, y interface{}) bool { | ||||
| 	_, ok2 := y.(error) | ||||
| 	return ok1 && ok2 | ||||
| } | ||||
|  | ||||
| func compareErrors(x, y interface{}) bool { | ||||
| 	xe := x.(error) | ||||
| 	ye := y.(error) | ||||
| 	// TODO(≥go1.13): Use standard definition of errors.Is. | ||||
| 	return xerrors.Is(xe, ye) || xerrors.Is(ye, xe) | ||||
| } | ||||
|   | ||||
							
								
								
									
										15
									
								
								vendor/github.com/google/go-cmp/cmp/cmpopts/errors_go113.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/google/go-cmp/cmp/cmpopts/errors_go113.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| // Copyright 2021, The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build go1.13 | ||||
|  | ||||
| package cmpopts | ||||
|  | ||||
| import "errors" | ||||
|  | ||||
| func compareErrors(x, y interface{}) bool { | ||||
| 	xe := x.(error) | ||||
| 	ye := y.(error) | ||||
| 	return errors.Is(xe, ye) || errors.Is(ye, xe) | ||||
| } | ||||
							
								
								
									
										18
									
								
								vendor/github.com/google/go-cmp/cmp/cmpopts/errors_xerrors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/google/go-cmp/cmp/cmpopts/errors_xerrors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| // Copyright 2021, The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build !go1.13 | ||||
|  | ||||
| // TODO(≥go1.13): For support on <go1.13, we use the xerrors package. | ||||
| // Drop this file when we no longer support older Go versions. | ||||
|  | ||||
| package cmpopts | ||||
|  | ||||
| import "golang.org/x/xerrors" | ||||
|  | ||||
| func compareErrors(x, y interface{}) bool { | ||||
| 	xe := x.(error) | ||||
| 	ye := y.(error) | ||||
| 	return xerrors.Is(xe, ye) || xerrors.Is(ye, xe) | ||||
| } | ||||
							
								
								
									
										4
									
								
								vendor/github.com/google/go-cmp/cmp/report_compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/google/go-cmp/cmp/report_compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -79,7 +79,7 @@ func (opts formatOptions) verbosity() uint { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const maxVerbosityPreset = 3 | ||||
| const maxVerbosityPreset = 6 | ||||
|  | ||||
| // verbosityPreset modifies the verbosity settings given an index | ||||
| // between 0 and maxVerbosityPreset, inclusive. | ||||
| @@ -100,7 +100,7 @@ func verbosityPreset(opts formatOptions, i int) formatOptions { | ||||
| func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) { | ||||
| 	if opts.DiffMode == diffIdentical { | ||||
| 		opts = opts.WithVerbosity(1) | ||||
| 	} else { | ||||
| 	} else if opts.verbosity() < 3 { | ||||
| 		opts = opts.WithVerbosity(3) | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										25
									
								
								vendor/github.com/google/go-cmp/cmp/report_slices.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/google/go-cmp/cmp/report_slices.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -26,8 +26,6 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { | ||||
| 		return false // No differences detected | ||||
| 	case !v.ValueX.IsValid() || !v.ValueY.IsValid(): | ||||
| 		return false // Both values must be valid | ||||
| 	case v.Type.Kind() == reflect.Slice && (v.ValueX.Len() == 0 || v.ValueY.Len() == 0): | ||||
| 		return false // Both slice values have to be non-empty | ||||
| 	case v.NumIgnored > 0: | ||||
| 		return false // Some ignore option was used | ||||
| 	case v.NumTransformed > 0: | ||||
| @@ -45,7 +43,16 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	switch t := v.Type; t.Kind() { | ||||
| 	// Check whether this is an interface with the same concrete types. | ||||
| 	t := v.Type | ||||
| 	vx, vy := v.ValueX, v.ValueY | ||||
| 	if t.Kind() == reflect.Interface && !vx.IsNil() && !vy.IsNil() && vx.Elem().Type() == vy.Elem().Type() { | ||||
| 		vx, vy = vx.Elem(), vy.Elem() | ||||
| 		t = vx.Type() | ||||
| 	} | ||||
|  | ||||
| 	// Check whether we provide specialized diffing for this type. | ||||
| 	switch t.Kind() { | ||||
| 	case reflect.String: | ||||
| 	case reflect.Array, reflect.Slice: | ||||
| 		// Only slices of primitive types have specialized handling. | ||||
| @@ -57,6 +64,11 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		// Both slice values have to be non-empty. | ||||
| 		if t.Kind() == reflect.Slice && (vx.Len() == 0 || vy.Len() == 0) { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		// If a sufficient number of elements already differ, | ||||
| 		// use specialized formatting even if length requirement is not met. | ||||
| 		if v.NumDiff > v.NumSame { | ||||
| @@ -68,7 +80,7 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { | ||||
|  | ||||
| 	// Use specialized string diffing for longer slices or strings. | ||||
| 	const minLength = 64 | ||||
| 	return v.ValueX.Len() >= minLength && v.ValueY.Len() >= minLength | ||||
| 	return vx.Len() >= minLength && vy.Len() >= minLength | ||||
| } | ||||
|  | ||||
| // FormatDiffSlice prints a diff for the slices (or strings) represented by v. | ||||
| @@ -77,6 +89,11 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { | ||||
| func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { | ||||
| 	assert(opts.DiffMode == diffUnknown) | ||||
| 	t, vx, vy := v.Type, v.ValueX, v.ValueY | ||||
| 	if t.Kind() == reflect.Interface { | ||||
| 		vx, vy = vx.Elem(), vy.Elem() | ||||
| 		t = vx.Type() | ||||
| 		opts = opts.WithTypeMode(emitType) | ||||
| 	} | ||||
|  | ||||
| 	// Auto-detect the type of the data. | ||||
| 	var isLinedText, isText, isBinary bool | ||||
|   | ||||
							
								
								
									
										24
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/opencontainers/runc/libcontainer/user/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,19 +11,17 @@ import ( | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	minId = 0 | ||||
| 	maxId = 1<<31 - 1 //for 32-bit systems compatibility | ||||
| 	minID = 0 | ||||
| 	maxID = 1<<31 - 1 // for 32-bit systems compatibility | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// The current operating system does not provide the required data for user lookups. | ||||
| 	ErrUnsupported = errors.New("user lookup: operating system does not provide passwd-formatted data") | ||||
|  | ||||
| 	// No matching entries found in file. | ||||
| 	// ErrNoPasswdEntries is returned if no matching entries were found in /etc/group. | ||||
| 	ErrNoPasswdEntries = errors.New("no matching entries in passwd file") | ||||
| 	ErrNoGroupEntries  = errors.New("no matching entries in group file") | ||||
|  | ||||
| 	ErrRange = fmt.Errorf("uids and gids must be in range %d-%d", minId, maxId) | ||||
| 	// ErrNoGroupEntries is returned if no matching entries were found in /etc/passwd. | ||||
| 	ErrNoGroupEntries = errors.New("no matching entries in group file") | ||||
| 	// ErrRange is returned if a UID or GID is outside of the valid range. | ||||
| 	ErrRange = fmt.Errorf("uids and gids must be in range %d-%d", minID, maxID) | ||||
| ) | ||||
|  | ||||
| type User struct { | ||||
| @@ -328,7 +326,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( | ||||
| 		user.Uid = uidArg | ||||
|  | ||||
| 		// Must be inside valid uid range. | ||||
| 		if user.Uid < minId || user.Uid > maxId { | ||||
| 		if user.Uid < minID || user.Uid > maxID { | ||||
| 			return nil, ErrRange | ||||
| 		} | ||||
|  | ||||
| @@ -377,7 +375,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( | ||||
| 				user.Gid = gidArg | ||||
|  | ||||
| 				// Must be inside valid gid range. | ||||
| 				if user.Gid < minId || user.Gid > maxId { | ||||
| 				if user.Gid < minID || user.Gid > maxID { | ||||
| 					return nil, ErrRange | ||||
| 				} | ||||
|  | ||||
| @@ -401,7 +399,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( | ||||
| // or the given group data is nil, the id will be returned as-is | ||||
| // provided it is in the legal range. | ||||
| func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, error) { | ||||
| 	var groups = []Group{} | ||||
| 	groups := []Group{} | ||||
| 	if group != nil { | ||||
| 		var err error | ||||
| 		groups, err = ParseGroupFilter(group, func(g Group) bool { | ||||
| @@ -439,7 +437,7 @@ func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, err | ||||
| 				return nil, fmt.Errorf("Unable to find group %s", ag) | ||||
| 			} | ||||
| 			// Ensure gid is inside gid range. | ||||
| 			if gid < minId || gid > maxId { | ||||
| 			if gid < minID || gid > maxID { | ||||
| 				return nil, ErrRange | ||||
| 			} | ||||
| 			gidMap[int(gid)] = struct{}{} | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/github.com/sirupsen/logrus/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/sirupsen/logrus/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,14 +4,12 @@ git: | ||||
|   depth: 1 | ||||
| env: | ||||
|   - GO111MODULE=on | ||||
| go: [1.13.x, 1.14.x] | ||||
| os: [linux, osx] | ||||
| go: 1.15.x | ||||
| os: linux | ||||
| install: | ||||
|   - ./travis/install.sh | ||||
| script: | ||||
|   - ./travis/cross_build.sh | ||||
|   - ./travis/lint.sh | ||||
|   - export GOMAXPROCS=4 | ||||
|   - export GORACE=halt_on_error=1 | ||||
|   - go test -race -v ./... | ||||
|   - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then go test -race -v -tags appengine ./... ; fi | ||||
|   - cd ci | ||||
|   - go run mage.go -v -w ../ crossBuild | ||||
|   - go run mage.go -v -w ../ lint | ||||
|   - go run mage.go -v -w ../ test | ||||
|   | ||||
							
								
								
									
										36
									
								
								vendor/github.com/sirupsen/logrus/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								vendor/github.com/sirupsen/logrus/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,3 +1,39 @@ | ||||
| # 1.8.1 | ||||
| Code quality: | ||||
|   * move magefile in its own subdir/submodule to remove magefile dependency on logrus consumer | ||||
|   * improve timestamp format documentation | ||||
|  | ||||
| Fixes: | ||||
|   * fix race condition on logger hooks | ||||
|  | ||||
|  | ||||
| # 1.8.0 | ||||
|  | ||||
| Correct versioning number replacing v1.7.1. | ||||
|  | ||||
| # 1.7.1 | ||||
|  | ||||
| Beware this release has introduced a new public API and its semver is therefore incorrect. | ||||
|  | ||||
| Code quality: | ||||
|   * use go 1.15 in travis | ||||
|   * use magefile as task runner | ||||
|  | ||||
| Fixes: | ||||
|   * small fixes about new go 1.13 error formatting system | ||||
|   * Fix for long time race condiction with mutating data hooks | ||||
|  | ||||
| Features: | ||||
|   * build support for zos | ||||
|  | ||||
| # 1.7.0 | ||||
| Fixes: | ||||
|   * the dependency toward a windows terminal library has been removed | ||||
|  | ||||
| Features: | ||||
|   * a new buffer pool management API has been added | ||||
|   * a set of `<LogLevel>Fn()` functions have been added | ||||
|  | ||||
| # 1.6.0 | ||||
| Fixes: | ||||
|   * end of line cleanup | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/sirupsen/logrus/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/sirupsen/logrus/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -402,7 +402,7 @@ func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { | ||||
|   // source of the official loggers. | ||||
|   serialized, err := json.Marshal(entry.Data) | ||||
|     if err != nil { | ||||
|       return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) | ||||
|       return nil, fmt.Errorf("Failed to marshal fields to JSON, %w", err) | ||||
|     } | ||||
|   return append(serialized, '\n'), nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										75
									
								
								vendor/github.com/sirupsen/logrus/entry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										75
									
								
								vendor/github.com/sirupsen/logrus/entry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -78,6 +78,14 @@ func NewEntry(logger *Logger) *Entry { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) Dup() *Entry { | ||||
| 	data := make(Fields, len(entry.Data)) | ||||
| 	for k, v := range entry.Data { | ||||
| 		data[k] = v | ||||
| 	} | ||||
| 	return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, Context: entry.Context, err: entry.err} | ||||
| } | ||||
|  | ||||
| // Returns the bytes representation of this entry from the formatter. | ||||
| func (entry *Entry) Bytes() ([]byte, error) { | ||||
| 	return entry.Logger.Formatter.Format(entry) | ||||
| @@ -123,11 +131,9 @@ func (entry *Entry) WithFields(fields Fields) *Entry { | ||||
| 	for k, v := range fields { | ||||
| 		isErrField := false | ||||
| 		if t := reflect.TypeOf(v); t != nil { | ||||
| 			switch t.Kind() { | ||||
| 			case reflect.Func: | ||||
| 			switch { | ||||
| 			case t.Kind() == reflect.Func, t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Func: | ||||
| 				isErrField = true | ||||
| 			case reflect.Ptr: | ||||
| 				isErrField = t.Elem().Kind() == reflect.Func | ||||
| 			} | ||||
| 		} | ||||
| 		if isErrField { | ||||
| @@ -212,68 +218,72 @@ func (entry Entry) HasCaller() (has bool) { | ||||
| 		entry.Caller != nil | ||||
| } | ||||
|  | ||||
| // This function is not declared with a pointer value because otherwise | ||||
| // race conditions will occur when using multiple goroutines | ||||
| func (entry Entry) log(level Level, msg string) { | ||||
| func (entry *Entry) log(level Level, msg string) { | ||||
| 	var buffer *bytes.Buffer | ||||
|  | ||||
| 	// Default to now, but allow users to override if they want. | ||||
| 	// | ||||
| 	// We don't have to worry about polluting future calls to Entry#log() | ||||
| 	// with this assignment because this function is declared with a | ||||
| 	// non-pointer receiver. | ||||
| 	if entry.Time.IsZero() { | ||||
| 		entry.Time = time.Now() | ||||
| 	newEntry := entry.Dup() | ||||
|  | ||||
| 	if newEntry.Time.IsZero() { | ||||
| 		newEntry.Time = time.Now() | ||||
| 	} | ||||
|  | ||||
| 	entry.Level = level | ||||
| 	entry.Message = msg | ||||
| 	entry.Logger.mu.Lock() | ||||
| 	if entry.Logger.ReportCaller { | ||||
| 		entry.Caller = getCaller() | ||||
| 	} | ||||
| 	entry.Logger.mu.Unlock() | ||||
| 	newEntry.Level = level | ||||
| 	newEntry.Message = msg | ||||
|  | ||||
| 	entry.fireHooks() | ||||
| 	newEntry.Logger.mu.Lock() | ||||
| 	reportCaller := newEntry.Logger.ReportCaller | ||||
| 	newEntry.Logger.mu.Unlock() | ||||
|  | ||||
| 	if reportCaller { | ||||
| 		newEntry.Caller = getCaller() | ||||
| 	} | ||||
|  | ||||
| 	newEntry.fireHooks() | ||||
|  | ||||
| 	buffer = getBuffer() | ||||
| 	defer func() { | ||||
| 		entry.Buffer = nil | ||||
| 		newEntry.Buffer = nil | ||||
| 		putBuffer(buffer) | ||||
| 	}() | ||||
| 	buffer.Reset() | ||||
| 	entry.Buffer = buffer | ||||
| 	newEntry.Buffer = buffer | ||||
|  | ||||
| 	entry.write() | ||||
| 	newEntry.write() | ||||
|  | ||||
| 	entry.Buffer = nil | ||||
| 	newEntry.Buffer = nil | ||||
|  | ||||
| 	// To avoid Entry#log() returning a value that only would make sense for | ||||
| 	// panic() to use in Entry#Panic(), we avoid the allocation by checking | ||||
| 	// directly here. | ||||
| 	if level <= PanicLevel { | ||||
| 		panic(&entry) | ||||
| 		panic(newEntry) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) fireHooks() { | ||||
| 	var tmpHooks LevelHooks | ||||
| 	entry.Logger.mu.Lock() | ||||
| 	defer entry.Logger.mu.Unlock() | ||||
| 	err := entry.Logger.Hooks.Fire(entry.Level, entry) | ||||
| 	tmpHooks = make(LevelHooks, len(entry.Logger.Hooks)) | ||||
| 	for k, v := range entry.Logger.Hooks { | ||||
| 		tmpHooks[k] = v | ||||
| 	} | ||||
| 	entry.Logger.mu.Unlock() | ||||
|  | ||||
| 	err := tmpHooks.Fire(entry.Level, entry) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (entry *Entry) write() { | ||||
| 	entry.Logger.mu.Lock() | ||||
| 	defer entry.Logger.mu.Unlock() | ||||
| 	serialized, err := entry.Logger.Formatter.Format(entry) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) | ||||
| 		return | ||||
| 	} | ||||
| 	if _, err = entry.Logger.Out.Write(serialized); err != nil { | ||||
| 	entry.Logger.mu.Lock() | ||||
| 	defer entry.Logger.mu.Unlock() | ||||
| 	if _, err := entry.Logger.Out.Write(serialized); err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) | ||||
| 	} | ||||
| } | ||||
| @@ -319,7 +329,6 @@ func (entry *Entry) Fatal(args ...interface{}) { | ||||
|  | ||||
| func (entry *Entry) Panic(args ...interface{}) { | ||||
| 	entry.Log(PanicLevel, args...) | ||||
| 	panic(fmt.Sprint(args...)) | ||||
| } | ||||
|  | ||||
| // Entry Printf family functions | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/sirupsen/logrus/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/sirupsen/logrus/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,7 +4,5 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | ||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||
| golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= | ||||
| golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= | ||||
| golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/github.com/sirupsen/logrus/json_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/sirupsen/logrus/json_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -23,6 +23,9 @@ func (f FieldMap) resolve(key fieldKey) string { | ||||
| // JSONFormatter formats logs into parsable json | ||||
| type JSONFormatter struct { | ||||
| 	// TimestampFormat sets the format used for marshaling timestamps. | ||||
| 	// The format to use is the same than for time.Format or time.Parse from the standard | ||||
| 	// library. | ||||
| 	// The standard Library already provides a set of predefined format. | ||||
| 	TimestampFormat string | ||||
|  | ||||
| 	// DisableTimestamp allows disabling automatic timestamps in output | ||||
| @@ -118,7 +121,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { | ||||
| 		encoder.SetIndent("", "  ") | ||||
| 	} | ||||
| 	if err := encoder.Encode(data); err != nil { | ||||
| 		return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err) | ||||
| 		return nil, fmt.Errorf("failed to marshal fields to JSON, %w", err) | ||||
| 	} | ||||
|  | ||||
| 	return b.Bytes(), nil | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/sirupsen/logrus/logger.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/sirupsen/logrus/logger.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -12,7 +12,7 @@ import ( | ||||
| // LogFunction For big messages, it can be more efficient to pass a function | ||||
| // and only call it if the log level is actually enables rather than | ||||
| // generating the log message and then checking if the level is enabled | ||||
| type LogFunction func()[]interface{} | ||||
| type LogFunction func() []interface{} | ||||
|  | ||||
| type Logger struct { | ||||
| 	// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/sirupsen/logrus/terminal_check_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/sirupsen/logrus/terminal_check_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // +build linux aix | ||||
| // +build linux aix zos | ||||
| // +build !js | ||||
|  | ||||
| package logrus | ||||
|   | ||||
							
								
								
									
										7
									
								
								vendor/github.com/sirupsen/logrus/text_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/sirupsen/logrus/text_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -53,7 +53,10 @@ type TextFormatter struct { | ||||
| 	// the time passed since beginning of execution. | ||||
| 	FullTimestamp bool | ||||
|  | ||||
| 	// TimestampFormat to use for display when a full timestamp is printed | ||||
| 	// TimestampFormat to use for display when a full timestamp is printed. | ||||
| 	// The format to use is the same than for time.Format or time.Parse from the standard | ||||
| 	// library. | ||||
| 	// The standard Library already provides a set of predefined format. | ||||
| 	TimestampFormat string | ||||
|  | ||||
| 	// The fields are sorted by default for a consistent output. For applications | ||||
| @@ -235,6 +238,8 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin | ||||
| 		levelColor = yellow | ||||
| 	case ErrorLevel, FatalLevel, PanicLevel: | ||||
| 		levelColor = red | ||||
| 	case InfoLevel: | ||||
| 		levelColor = blue | ||||
| 	default: | ||||
| 		levelColor = blue | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user