Repository: cilium/ebpf
Pull request #355 (2021-07-25 15:29:57)

features: add HaveProgType API
With this commit we add `HaveProgType(pt ebpf.ProgramType) error`,
which allows to probe for available BPF program types. As with the
HaveMapType API, results are cached and probes run at most once.

Signed-off-by: Robin Gögge <r.goegge@outlook.com>

rgo3: Keeping it as a draft for now, as I still have to investigate some of the failing probes.

Patch:
diff --git a/collection.go b/collection.go
index d495b66..129b31a 100644
--- a/collection.go
+++ b/collection.go
@@ -208,20 +208,20 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)
 		opts = &CollectionOptions{}
 	}
 
-	loadMap, loadProgram, populateMaps, done, cleanup := lazyLoadCollection(cs, opts)
-	defer cleanup()
+	loader := newCollectionLoader(cs, opts)
+	defer loader.close()
 
 	valueOf := func(typ reflect.Type, name string) (reflect.Value, error) {
 		switch typ {
 		case reflect.TypeOf((*Program)(nil)):
-			p, err := loadProgram(name)
+			p, err := loader.loadProgram(name)
 			if err != nil {
 				return reflect.Value{}, err
 			}
 			return reflect.ValueOf(p), nil
 
 		case reflect.TypeOf((*Map)(nil)):
-			m, err := loadMap(name)
+			m, err := loader.loadMap(name)
 			if err != nil {
 				return reflect.Value{}, err
 			}
@@ -237,12 +237,13 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)
 		return err
 	}
 
-	// Finally, autopopulate the requested maps.
-	if err := populateMaps(); err != nil {
+	// Finally, populate the requested maps.
+	if err := loader.populateMaps(); err != nil {
 		return err
 	}
 
-	done()
+	loader.finalize()
+
 	return nil
 }
 
@@ -260,29 +261,32 @@ func NewCollection(spec *CollectionSpec) (*Collection, error) {
 
 // NewCollectionWithOptions creates a Collection from a specification.
 func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Collection, error) {
-	loadMap, loadProgram, populateMaps, done, cleanup := lazyLoadCollection(spec, &opts)
-	defer cleanup()
+	loader := newCollectionLoader(spec, &opts)
+	defer loader.close()
 
 	// Create maps first, as their fds need to be linked into programs.
 	for mapName := range spec.Maps {
-		if _, err := loadMap(mapName); err != nil {
+		if _, err := loader.loadMap(mapName); err != nil {
 			return nil, err
 		}
 	}
 
 	for progName := range spec.Programs {
-		if _, err := loadProgram(progName); err != nil {
+		if _, err := loader.loadProgram(progName); err != nil {
 			return nil, err
 		}
 	}
 
-	// Maps can contain pointers to Programs, so populate them after
+	// Maps can contain Program and Map stubs, so populate them after
 	// all Maps and Programs have been successfully loaded.
-	if err := populateMaps(); err != nil {
+	if err := loader.populateMaps(); err != nil {
 		return nil, err
 	}
 
-	maps, progs := done()
+	maps, progs := loader.maps, loader.programs
+
+	loader.finalize()
+
 	return &Collection{
 		progs,
 		maps,
@@ -335,149 +339,145 @@ func (hc handleCache) close() {
 	}
 }
 
-func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) (
-	loadMap func(string) (*Map, error),
-	loadProgram func(string) (*Program, error),
-	populateMaps func() error,
-	done func() (map[string]*Map, map[string]*Program),
-	cleanup func(),
-) {
-	var (
-		maps             = make(map[string]*Map)
-		progs            = make(map[string]*Program)
-		handles          = newHandleCache()
-		skipMapsAndProgs = false
-	)
-
-	cleanup = func() {
-		handles.close()
+type collectionLoader struct {
+	coll     *CollectionSpec
+	opts     *CollectionOptions
+	maps     map[string]*Map
+	programs map[string]*Program
+	handles  *handleCache
+}
 
-		if skipMapsAndProgs {
-			return
-		}
+func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) *collectionLoader {
+	return &collectionLoader{
+		coll,
+		opts,
+		make(map[string]*Map),
+		make(map[string]*Program),
+		newHandleCache(),
+	}
+}
 
-		for _, m := range maps {
-			m.Close()
-		}
+// finalize should be called when all the collectionLoader's resources
+// have been successfully loaded into the kernel and populated with values.
+func (cl *collectionLoader) finalize() {
+	cl.maps, cl.programs = nil, nil
+}
 
-		for _, p := range progs {
-			p.Close()
-		}
+func (cl *collectionLoader) close() {
+	cl.handles.close()
+	for _, m := range cl.maps {
+		m.Close()
 	}
-
-	done = func() (map[string]*Map, map[string]*Program) {
-		skipMapsAndProgs = true
-		return maps, progs
+	for _, p := range cl.programs {
+		p.Close()
 	}
+}
 
-	loadMap = func(mapName string) (*Map, error) {
-		if m := maps[mapName]; m != nil {
-			return m, nil
-		}
-
-		mapSpec := coll.Maps[mapName]
-		if mapSpec == nil {
-			return nil, fmt.Errorf("missing map %s", mapName)
-		}
-
-		m, err := newMapWithOptions(mapSpec, opts.Maps, handles)
-		if err != nil {
-			return nil, fmt.Errorf("map %s: %w", mapName, err)
-		}
-
-		maps[mapName] = m
+func (cl *collectionLoader) loadMap(mapName string) (*Map, error) {
+	if m := cl.maps[mapName]; m != nil {
 		return m, nil
 	}
 
-	loadProgram = func(progName string) (*Program, error) {
-		if prog := progs[progName]; prog != nil {
-			return prog, nil
-		}
+	mapSpec := cl.coll.Maps[mapName]
+	if mapSpec == nil {
+		return nil, fmt.Errorf("missing map %s", mapName)
+	}
 
-		progSpec := coll.Programs[progName]
-		if progSpec == nil {
-			return nil, fmt.Errorf("unknown program %s", progName)
-		}
+	m, err := newMapWithOptions(mapSpec, cl.opts.Maps, cl.handles)
+	if err != nil {
+		return nil, fmt.Errorf("map %s: %w", mapName, err)
+	}
 
-		progSpec = progSpec.Copy()
+	cl.maps[mapName] = m
+	return m, nil
+}
 
-		// Rewrite any reference to a valid map.
-		for i := range progSpec.Instructions {
-			ins := &progSpec.Instructions[i]
+func (cl *collectionLoader) loadProgram(progName string) (*Program, error) {
+	if prog := cl.programs[progName]; prog != nil {
+		return prog, nil
+	}
 
-			if !ins.IsLoadFromMap() || ins.Reference == "" {
-				continue
-			}
+	progSpec := cl.coll.Programs[progName]
+	if progSpec == nil {
+		return nil, fmt.Errorf("unknown program %s", progName)
+	}
 
-			if uint32(ins.Constant) != math.MaxUint32 {
-				// Don't overwrite maps already rewritten, users can
-				// rewrite programs in the spec themselves
-				continue
-			}
+	progSpec = progSpec.Copy()
 
-			m, err := loadMap(ins.Reference)
-			if err != nil {
-				return nil, fmt.Errorf("program %s: %w", progName, err)
-			}
+	// Rewrite any reference to a valid map.
+	for i := range progSpec.Instructions {
+		ins := &progSpec.Instructions[i]
 
-			fd := m.FD()
-			if fd < 0 {
-				return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd)
-			}
-			if err := ins.RewriteMapPtr(m.FD()); err != nil {
-				return nil, fmt.Errorf("progam %s: map %s: %w", progName, ins.Reference, err)
-			}
+		if !ins.IsLoadFromMap() || ins.Reference == "" {
+			continue
+		}
+
+		if uint32(ins.Constant) != math.MaxUint32 {
+			// Don't overwrite maps already rewritten, users can
+			// rewrite programs in the spec themselves
+			continue
 		}
 
-		prog, err := newProgramWithOptions(progSpec, opts.Programs, handles)
+		m, err := cl.loadMap(ins.Reference)
 		if err != nil {
 			return nil, fmt.Errorf("program %s: %w", progName, err)
 		}
 
-		progs[progName] = prog
-		return prog, nil
+		fd := m.FD()
+		if fd < 0 {
+			return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd)
+		}
+		if err := ins.RewriteMapPtr(m.FD()); err != nil {
+			return nil, fmt.Errorf("progam %s: map %s: %w", progName, ins.Reference, err)
+		}
 	}
 
-	populateMaps = func() error {
-		for mapName, m := range maps {
-			mapSpec, ok := coll.Maps[mapName]
-			if !ok {
-				return fmt.Errorf("missing map spec %s", mapName)
-			}
+	prog, err := newProgramWithOptions(progSpec, cl.opts.Programs, cl.handles)
+	if err != nil {
+		return nil, fmt.Errorf("program %s: %w", progName, err)
+	}
+
+	cl.programs[progName] = prog
+	return prog, nil
+}
+
+func (cl *collectionLoader) populateMaps() error {
+	for mapName, m := range cl.maps {
+		mapSpec, ok := cl.coll.Maps[mapName]
+		if !ok {
+			return fmt.Errorf("missing map spec %s", mapName)
+		}
+
+		mapSpec = mapSpec.Copy()
 
-			mapSpec = mapSpec.Copy()
-
-			// Replace any object stubs with loaded objects.
-			for i, kv := range mapSpec.Contents {
-				switch v := kv.Value.(type) {
-				case programStub:
-					// loadProgram is idempotent and could return an existing Program.
-					prog, err := loadProgram(string(v))
-					if err != nil {
-						return fmt.Errorf("loading program %s, for map %s: %w", v, mapName, err)
-					}
-					mapSpec.Contents[i] = MapKV{kv.Key, prog}
-
-				case mapStub:
-					// loadMap is idempotent and could return an existing Map.
-					innerMap, err := loadMap(string(v))
-					if err != nil {
-						return fmt.Errorf("loading inner map %s, for map %s: %w", v, mapName, err)
-					}
-					mapSpec.Contents[i] = MapKV{kv.Key, innerMap}
+		// Replace any object stubs with loaded objects.
+		for i, kv := range mapSpec.Contents {
+			switch v := kv.Value.(type) {
+			case programStub:
+				// loadProgram is idempotent and could return an existing Program.
+				prog, err := cl.loadProgram(string(v))
+				if err != nil {
+					return fmt.Errorf("loading program %s, for map %s: %w", v, mapName, err)
 				}
-			}
+				mapSpec.Contents[i] = MapKV{kv.Key, prog}
 
-			// Populate and freeze the map if specified.
-			if err := m.finalize(mapSpec); err != nil {
-				return fmt.Errorf("populating map %s: %w", mapName, err)
+			case mapStub:
+				// loadMap is idempotent and could return an existing Map.
+				innerMap, err := cl.loadMap(string(v))
+				if err != nil {
+					return fmt.Errorf("loading inner map %s, for map %s: %w", v, mapName, err)
+				}
+				mapSpec.Contents[i] = MapKV{kv.Key, innerMap}
 			}
 		}
 
-		return nil
+		// Populate and freeze the map if specified.
+		if err := m.finalize(mapSpec); err != nil {
+			return fmt.Errorf("populating map %s: %w", mapName, err)
+		}
 	}
 
-	return
+	return nil
 }
 
 // LoadCollection parses an object file and converts it to a collection.
diff --git a/examples/README.md b/examples/README.md
index 1765e3c..7364705 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,6 +1,7 @@
 # eBPF Examples
 
 - [kprobe](kprobe/) - Attach a program to the entry or exit of an arbitrary kernel symbol (function).
+- [kprobepin](kprobepin/) - Reuse a pinned map for the kprobe example. It assumes the BPF FS is mounted at `/sys/fs/bpf`.
 - [uretprobe](uretprobe/) - Like a kprobe, but for symbols in userspace binaries (e.g. `bash`).
 - [tracepoint](tracepoint/) - Attach a program to predetermined kernel tracepoints.
 - Add your use case(s) here!
diff --git a/examples/kprobepin/bpf/kprobe_pin_example.c b/examples/kprobepin/bpf/kprobe_pin_example.c
new file mode 100644
index 0000000..279bacf
--- /dev/null
+++ b/examples/kprobepin/bpf/kprobe_pin_example.c
@@ -0,0 +1,27 @@
+#include "common.h"
+#include "bpf_helpers.h"
+
+char __license[] SEC("license") = "Dual MIT/GPL";
+
+struct {
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	__type(key, u32);
+	__type(value, u64);
+	__uint(max_entries, 1);
+	__uint(pinning, LIBBPF_PIN_BY_NAME);
+} kprobe_map SEC(".maps");
+
+SEC("kprobe/sys_execve")
+int kprobe_execve() {
+	u32 key     = 0;
+	u64 initval = 1, *valp;
+
+	valp = bpf_map_lookup_elem(&kprobe_map, &key);
+	if (!valp) {
+		bpf_map_update_elem(&kprobe_map, &key, &initval, BPF_ANY);
+		return 0;
+	}
+	__sync_fetch_and_add(valp, 1);
+
+	return 0;
+}
diff --git a/examples/kprobepin/kprobepinexample_bpfeb.go b/examples/kprobepin/kprobepinexample_bpfeb.go
new file mode 100644
index 0000000..1ea8820
--- /dev/null
+++ b/examples/kprobepin/kprobepinexample_bpfeb.go
@@ -0,0 +1,116 @@
+// Code generated by bpf2go; DO NOT EDIT.
+// +build armbe arm64be mips mips64 mips64p32 ppc64 s390 s390x sparc sparc64
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+
+	"github.com/cilium/ebpf"
+)
+
+// LoadKProbePinExample returns the embedded CollectionSpec for KProbePinExample.
+func LoadKProbePinExample() (*ebpf.CollectionSpec, error) {
+	reader := bytes.NewReader(_KProbePinExampleBytes)
+	spec, err := ebpf.LoadCollectionSpecFromReader(reader)
+	if err != nil {
+		return nil, fmt.Errorf("can't load KProbePinExample: %w", err)
+	}
+
+	return spec, err
+}
+
+// LoadKProbePinExampleObjects loads KProbePinExample and converts it into a struct.
+//
+// The following types are suitable as obj argument:
+//
+//     *KProbePinExampleObjects
+//     *KProbePinExamplePrograms
+//     *KProbePinExampleMaps
+//
+// See ebpf.CollectionSpec.LoadAndAssign documentation for details.
+func LoadKProbePinExampleObjects(obj interface{}, opts *ebpf.CollectionOptions) error {
+	spec, err := LoadKProbePinExample()
+	if err != nil {
+		return err
+	}
+
+	return spec.LoadAndAssign(obj, opts)
+}
+
+// KProbePinExampleSpecs contains maps and programs before they are loaded into the kernel.
+//
+// It can be passed ebpf.CollectionSpec.Assign.
+type KProbePinExampleSpecs struct {
+	KProbePinExampleProgramSpecs
+	KProbePinExampleMapSpecs
+}
+
+// KProbePinExampleSpecs contains programs before they are loaded into the kernel.
+//
+// It can be passed ebpf.CollectionSpec.Assign.
+type KProbePinExampleProgramSpecs struct {
+	KprobeExecve *ebpf.ProgramSpec `ebpf:"kprobe_execve"`
+}
+
+// KProbePinExampleMapSpecs contains maps before they are loaded into the kernel.
+//
+// It can be passed ebpf.CollectionSpec.Assign.
+type KProbePinExampleMapSpecs struct {
+	KprobeMap *ebpf.MapSpec `ebpf:"kprobe_map"`
+}
+
+// KProbePinExampleObjects contains all objects after they have been loaded into the kernel.
+//
+// It can be passed to LoadKProbePinExampleObjects or ebpf.CollectionSpec.LoadAndAssign.
+type KProbePinExampleObjects struct {
+	KProbePinExamplePrograms
+	KProbePinExampleMaps
+}
+
+func (o *KProbePinExampleObjects) Close() error {
+	return _KProbePinExampleClose(
+		&o.KProbePinExamplePrograms,
+		&o.KProbePinExampleMaps,
+	)
+}
+
+// KProbePinExampleMaps contains all maps after they have been loaded into the kernel.
+//
+// It can be passed to LoadKProbePinExampleObjects or ebpf.CollectionSpec.LoadAndAssign.
+type KProbePinExampleMaps struct {
+	KprobeMap *ebpf.Map `ebpf:"kprobe_map"`
+}
+
+func (m *KProbePinExampleMaps) Close() error {
+	return _KProbePinExampleClose(
+		m.KprobeMap,
+	)
+}
+
+// KProbePinExamplePrograms contains all programs after they have been loaded into the kernel.
+//
+// It can be passed to LoadKProbePinExampleObjects or ebpf.CollectionSpec.LoadAndAssign.
+type KProbePinExamplePrograms struct {
+	KprobeExecve *ebpf.Program `ebpf:"kprobe_execve"`
+}
+
+func (p *KProbePinExamplePrograms) Close() error {
+	return _KProbePinExampleClose(
+		p.KprobeExecve,
+	)
+}
+
+func _KProbePinExampleClose(closers ...io.Closer) error {
+	for _, closer := range closers {
+		if err := closer.Close(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// Do not access this directly.
+var _KProbePinExampleBytes = []byte("\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\xf7\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x40\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x40\x00\x16\x00\x01\xb7\x10\x00\x00\x00\x00\x00\x00\x63\xa1\xff\xfc\x00\x00\x00\x00\xb7\x60\x00\x00\x00\x00\x00\x01\x7b\xa6\xff\xf0\x00\x00\x00\x00\xbf\x2a\x00\x00\x00\x00\x00\x00\x07\x20\x00\x00\xff\xff\xff\xfc\x18\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\x00\x00\x00\x00\x00\x00\x01\x55\x00\x00\x09\x00\x00\x00\x00\xbf\x2a\x00\x00\x00\x00\x00\x00\x07\x20\x00\x00\xff\xff\xff\xfc\xbf\x3a\x00\x00\x00\x00\x00\x00\x07\x30\x00\x00\xff\xff\xff\xf0\x18\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\x40\x00\x00\x00\x00\x00\x00\x85\x00\x00\x00\x00\x00\x00\x02\x05\x00\x00\x01\x00\x00\x00\x00\xdb\x06\x00\x00\x00\x00\x00\x00\xb7\x00\x00\x00\x00\x00\x00\x00\x95\x00\x00\x00\x00\x00\x00\x00\x44\x75\x61\x6c\x20\x4d\x49\x54\x2f\x47\x50\x4c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x20\x00\x02\x30\x9f\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x02\x7a\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x50\x00\x02\x31\x9f\x00\x00\x00\x00\x00\x00\x00\x50\x00\x00\x00\x00\x00\x00\x00\x98\x00\x02\x7a\x00\x00\x00\x00\x00\x00\x00\x00\x98\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x02\x31\x9f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x48\x00\x00\x00\x00\x00\x00\x00\x90\x00\x01\x50\x00\x00\x00\x00\x00\x00\x00\x98\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x01\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x11\x01\x25\x0e\x13\x05\x03\x0e\x10\x17\x1b\x0e\x11\x01\x12\x06\x00\x00\x02\x34\x00\x03\x0e\x49\x13\x3f\x19\x3a\x0b\x3b\x0b\x02\x18\x00\x00\x03\x01\x01\x49\x13\x00\x00\x04\x21\x00\x49\x13\x37\x0b\x00\x00\x05\x24\x00\x03\x0e\x3e\x0b\x0b\x0b\x00\x00\x06\x24\x00\x03\x0e\x0b\x0b\x3e\x0b\x00\x00\x07\x13\x01\x0b\x0b\x3a\x0b\x3b\x0b\x00\x00\x08\x0d\x00\x03\x0e\x49\x13\x3a\x0b\x3b\x0b\x38\x0b\x00\x00\x09\x0f\x00\x49\x13\x00\x00\x0a\x16\x00\x49\x13\x03\x0e\x3a\x0b\x3b\x0b\x00\x00\x0b\x34\x00\x03\x0e\x49\x13\x3a\x0b\x3b\x0b\x00\x00\x0c\x15\x01\x49\x13\x27\x19\x00\x00\x0d\x05\x00\x49\x13\x00\x00\x0e\x0f\x00\x00\x00\x0f\x26\x00\x00\x00\x10\x04\x01\x49\x13\x0b\x0b\x3a\x0b\x3b\x0b\x00\x00\x11\x28\x00\x03\x0e\x1c\x0f\x00\x00\x12\x2e\x01\x11\x01\x12\x06\x40\x18\x97\x42\x19\x03\x0e\x3a\x0b\x3b\x0b\x49\x13\x3f\x19\x00\x00\x13\x34\x00\x02\x17\x03\x0e\x3a\x0b\x3b\x0b\x49\x13\x00\x00\x00\x00\x00\x01\xd9\x00\x04\x00\x00\x00\x00\x08\x01\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x02\x00\x00\x00\x00\x00\x00\x00\x3f\x01\x04\x09\x03\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x4b\x04\x00\x00\x00\x52\x0d\x00\x05\x00\x00\x00\x00\x06\x01\x06\x00\x00\x00\x00\x08\x07\x02\x00\x00\x00\x00\x00\x00\x00\x6e\x01\x0c\x09\x03\x00\x00\x00\x00\x00\x00\x00\x00\x07\x28\x01\x06\x08\x00\x00\x00\x00\x00\x00\x00\xaf\x01\x07\x00\x08\x00\x00\x00\x00\x00\x00\x00\xc7\x01\x08\x08\x08\x00\x00\x00\x00\x00\x00\x00\xe9\x01\x09\x10\x08\x00\x00\x00\x00\x00\x00\x01\x0b\x01\x0a\x18\x08\x00\x00\x00\x00\x00\x00\x01\x0b\x01\x0b\x20\x00\x09\x00\x00\x00\xb4\x03\x00\x00\x00\xc0\x04\x00\x00\x00\x52\x02\x00\x05\x00\x00\x00\x00\x05\x04\x09\x00\x00\x00\xcc\x0a\x00\x00\x00\xd7\x00\x00\x00\x00\x02\x11\x0a\x00\x00\x00\xe2\x00\x00\x00\x00\x02\x0a\x05\x00\x00\x00\x00\x07\x04\x09\x00\x00\x00\xee\x0a\x00\x00\x00\xf9\x00\x00\x00\x00\x02\x13\x0a\x00\x00\x01\x04\x00\x00\x00\x00\x02\x0c\x05\x00\x00\x00\x00\x07\x08\x09\x00\x00\x01\x10\x03\x00\x00\x00\xc0\x04\x00\x00\x00\x52\x01\x00\x0b\x00\x00\x00\x00\x00\x00\x01\x27\x03\x2a\x09\x00\x00\x01\x2c\x0c\x00\x00\x01\x3c\x0d\x00\x00\x01\x3c\x0d\x00\x00\x01\x3d\x00\x0e\x09\x00\x00\x01\x42\x0f\x0b\x00\x00\x00\x00\x00\x00\x01\x4e\x03\x40\x09\x00\x00\x01\x53\x0c\x00\x00\x01\x6d\x0d\x00\x00\x01\x3c\x0d\x00\x00\x01\x3d\x0d\x00\x00\x01\x3d\x0d\x00\x00\x00\xf9\x00\x05\x00\x00\x00\x00\x05\x08\x10\x00\x00\x00\xe2\x04\x02\x3a\x11\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x01\x11\x00\x00\x00\x00\x02\x11\x00\x00\x00\x00\x04\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x01\x5a\x00\x00\x00\x00\x01\x0f\x00\x00\x00\xc0\x13\x00\x00\x00\x00\x00\x00\x00\x00\x01\x10\x00\x00\x00\xcc\x13\x00\x00\x00\x38\x00\x00\x00\x00\x01\x11\x00\x00\x00\xee\x13\x00\x00\x00\x84\x00\x00\x00\x00\x01\x11\x00\x00\x00\xe9\x00\x00\x00\x62\x70\x66\x2f\x6b\x70\x72\x6f\x62\x65\x5f\x70\x69\x6e\x5f\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x00\x2e\x00\x5f\x5f\x6c\x69\x63\x65\x6e\x73\x65\x00\x63\x68\x61\x72\x00\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\x00\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x00\x74\x79\x70\x65\x00\x69\x6e\x74\x00\x6b\x65\x79\x00\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\x00\x5f\x5f\x75\x33\x32\x00\x75\x33\x32\x00\x76\x61\x6c\x75\x65\x00\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\x20\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\x00\x5f\x5f\x75\x36\x34\x00\x75\x36\x34\x00\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\x00\x70\x69\x6e\x6e\x69\x6e\x67\x00\x62\x70\x66\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\x70\x5f\x65\x6c\x65\x6d\x00\x62\x70\x66\x5f\x6d\x61\x70\x5f\x75\x70\x64\x61\x74\x65\x5f\x65\x6c\x65\x6d\x00\x6c\x6f\x6e\x67\x20\x69\x6e\x74\x00\x42\x50\x46\x5f\x41\x4e\x59\x00\x42\x50\x46\x5f\x4e\x4f\x45\x58\x49\x53\x54\x00\x42\x50\x46\x5f\x45\x58\x49\x53\x54\x00\x42\x50\x46\x5f\x46\x5f\x4c\x4f\x43\x4b\x00\x6b\x70\x72\x6f\x62\x65\x5f\x65\x78\x65\x63\x76\x65\x00\x69\x6e\x69\x74\x76\x61\x6c\x00\x76\x61\x6c\x70\x00\xeb\x9f\x01\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x01\xa8\x00\x00\x01\xa8\x00\x00\x01\xb5\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x20\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x05\x01\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x20\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x19\x08\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x1d\x08\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x23\x01\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x20\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x30\x08\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x34\x08\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x3a\x01\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x40\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00\x04\x00\x00\x05\x00\x00\x00\x28\x00\x00\x00\x51\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x56\x00\x00\x00\x05\x00\x00\x00\x40\x00\x00\x00\x5a\x00\x00\x00\x09\x00\x00\x00\x80\x00\x00\x00\x60\x00\x00\x00\x0d\x00\x00\x00\xc0\x00\x00\x00\x6c\x00\x00\x00\x0d\x00\x00\x01\x00\x00\x00\x00\x74\x0e\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x01\x00\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x7f\x0c\x00\x00\x01\x00\x00\x00\x11\x00\x00\x01\x98\x01\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x08\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x04\x00\x00\x00\x0d\x00\x00\x01\x9d\x0e\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x01\x00\x00\x01\xa7\x0f\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x01\xad\x0f\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x69\x6e\x74\x00\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\x00\x75\x33\x32\x00\x5f\x5f\x75\x33\x32\x00\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\x00\x75\x36\x34\x00\x5f\x5f\x75\x36\x34\x00\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\x20\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\x00\x74\x79\x70\x65\x00\x6b\x65\x79\x00\x76\x61\x6c\x75\x65\x00\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\x00\x70\x69\x6e\x6e\x69\x6e\x67\x00\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x00\x6b\x70\x72\x6f\x62\x65\x5f\x65\x78\x65\x63\x76\x65\x00\x6b\x70\x72\x6f\x62\x65\x2f\x73\x79\x73\x5f\x65\x78\x65\x63\x76\x65\x00\x2e\x2f\x62\x70\x66\x2f\x6b\x70\x72\x6f\x62\x65\x5f\x70\x69\x6e\x5f\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x00\x69\x6e\x74\x20\x6b\x70\x72\x6f\x62\x65\x5f\x65\x78\x65\x63\x76\x65\x28\x29\x20\x7b\x00\x09\x75\x33\x32\x20\x6b\x65\x79\x20\x20\x20\x20\x20\x3d\x20\x30\x3b\x00\x09\x75\x36\x34\x20\x69\x6e\x69\x74\x76\x61\x6c\x20\x3d\x20\x31\x2c\x20\x2a\x76\x61\x6c\x70\x3b\x00\x09\x76\x61\x6c\x70\x20\x3d\x20\x62\x70\x66\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\x70\x5f\x65\x6c\x65\x6d\x28\x26\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x2c\x20\x26\x6b\x65\x79\x29\x3b\x00\x09\x69\x66\x20\x28\x21\x76\x61\x6c\x70\x29\x20\x7b\x00\x09\x09\x62\x70\x66\x5f\x6d\x61\x70\x5f\x75\x70\x64\x61\x74\x65\x5f\x65\x6c\x65\x6d\x28\x26\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x2c\x20\x26\x6b\x65\x79\x2c\x20\x26\x69\x6e\x69\x74\x76\x61\x6c\x2c\x20\x42\x50\x46\x5f\x41\x4e\x59\x29\x3b\x00\x09\x5f\x5f\x73\x79\x6e\x63\x5f\x66\x65\x74\x63\x68\x5f\x61\x6e\x64\x5f\x61\x64\x64\x28\x76\x61\x6c\x70\x2c\x20\x31\x29\x3b\x00\x7d\x00\x63\x68\x61\x72\x00\x5f\x5f\x6c\x69\x63\x65\x6e\x73\x65\x00\x2e\x6d\x61\x70\x73\x00\x6c\x69\x63\x65\x6e\x73\x65\x00\xeb\x9f\x01\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x14\x00\x00\x00\xac\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x8d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x10\x00\x00\x00\x8d\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x9f\x00\x00\x00\xba\x00\x00\x3c\x00\x00\x00\x00\x08\x00\x00\x00\x9f\x00\x00\x00\xd0\x00\x00\x40\x06\x00\x00\x00\x18\x00\x00\x00\x9f\x00\x00\x00\xe2\x00\x00\x44\x06\x00\x00\x00\x28\x00\x00\x00\x9f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x9f\x00\x00\x00\xfb\x00\x00\x4c\x09\x00\x00\x00\x48\x00\x00\x00\x9f\x00\x00\x01\x2b\x00\x00\x50\x06\x00\x00\x00\x58\x00\x00\x00\x9f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x00\x00\x00\x9f\x00\x00\x01\x39\x00\x00\x54\x03\x00\x00\x00\x98\x00\x00\x00\x9f\x00\x00\x01\x76\x00\x00\x60\x02\x00\x00\x00\xa0\x00\x00\x00\x9f\x00\x00\x01\x96\x00\x00\x6c\x01\x00\x00\x00\x00\x0c\xff\xff\xff\xff\x04\x00\x08\x00\x08\x7c\x0b\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x9e\x00\x04\x00\x00\x00\x5c\x08\x01\x01\xfb\x0e\x0d\x00\x01\x01\x01\x01\x00\x00\x00\x01\x00\x00\x01\x62\x70\x66\x00\x2e\x2e\x2f\x68\x65\x61\x64\x65\x72\x73\x00\x00\x6b\x70\x72\x6f\x62\x65\x5f\x70\x69\x6e\x5f\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x00\x01\x00\x00\x63\x6f\x6d\x6d\x6f\x6e\x2e\x68\x00\x02\x00\x00\x62\x70\x66\x5f\x68\x65\x6c\x70\x65\x72\x5f\x64\x65\x66\x73\x2e\x68\x00\x02\x00\x00\x00\x00\x09\x02\x00\x00\x00\x00\x00\x00\x00\x00\x03\x0e\x01\x05\x06\x0a\x21\x2f\x06\x03\x6f\x20\x05\x09\x06\x03\x13\x2e\x05\x06\x3d\x06\x03\x6c\x20\x05\x03\x06\x03\x15\x4a\x06\x03\x6b\x4a\x05\x02\x06\x03\x18\x20\x05\x01\x23\x02\x02\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x04\x00\xff\xf1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x26\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x2b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x53\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x6e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x95\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\xa1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x4f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x6a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x91\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x8b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\xbd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\xd1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\xda\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\xe2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\xee\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x01\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeb\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x98\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x11\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x72\x12\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x33\x11\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x28\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x70\x00\x00\x00\x28\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x23\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x02\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x03\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x25\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x04\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x2b\x00\x00\x00\x05\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x37\x00\x00\x00\x26\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x4c\x00\x00\x00\x06\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x53\x00\x00\x00\x07\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x5a\x00\x00\x00\x08\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x66\x00\x00\x00\x28\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x73\x00\x00\x00\x09\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x7f\x00\x00\x00\x0a\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x8b\x00\x00\x00\x0b\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x97\x00\x00\x00\x0c\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\xa3\x00\x00\x00\x0d\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\xc1\x00\x00\x00\x0e\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\xd1\x00\x00\x00\x0f\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\xdc\x00\x00\x00\x10\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\xe3\x00\x00\x00\x11\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\xf3\x00\x00\x00\x12\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\xfe\x00\x00\x00\x13\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\x05\x00\x00\x00\x14\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\x1d\x00\x00\x00\x15\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\x44\x00\x00\x00\x16\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\x6e\x00\x00\x00\x17\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\x7d\x00\x00\x00\x18\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\x83\x00\x00\x00\x19\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\x89\x00\x00\x00\x1a\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\x8f\x00\x00\x00\x1b\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\x96\x00\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\xa4\x00\x00\x00\x1c\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\xaf\x00\x00\x00\x22\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\xb3\x00\x00\x00\x0a\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\xbe\x00\x00\x00\x22\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\xc2\x00\x00\x00\x1d\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\xcd\x00\x00\x00\x22\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\xd1\x00\x00\x00\x1e\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x01\xa0\x00\x00\x00\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xb8\x00\x00\x00\x26\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2c\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x50\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x24\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x69\x00\x00\x00\x21\x00\x00\x00\x01\x27\x26\x28\x00\x2e\x64\x65\x62\x75\x67\x5f\x61\x62\x62\x72\x65\x76\x00\x2e\x74\x65\x78\x74\x00\x2e\x72\x65\x6c\x2e\x42\x54\x46\x2e\x65\x78\x74\x00\x2e\x6d\x61\x70\x73\x00\x2e\x64\x65\x62\x75\x67\x5f\x73\x74\x72\x00\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x00\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x69\x6e\x66\x6f\x00\x2e\x6c\x6c\x76\x6d\x5f\x61\x64\x64\x72\x73\x69\x67\x00\x2e\x72\x65\x6c\x6b\x70\x72\x6f\x62\x65\x2f\x73\x79\x73\x5f\x65\x78\x65\x63\x76\x65\x00\x6b\x70\x72\x6f\x62\x65\x5f\x65\x78\x65\x63\x76\x65\x00\x5f\x5f\x6c\x69\x63\x65\x6e\x73\x65\x00\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x6c\x69\x6e\x65\x00\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x66\x72\x61\x6d\x65\x00\x2e\x64\x65\x62\x75\x67\x5f\x6c\x6f\x63\x00\x6b\x70\x72\x6f\x62\x65\x5f\x70\x69\x6e\x5f\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x00\x2e\x73\x74\x72\x74\x61\x62\x00\x2e\x73\x79\x6d\x74\x61\x62\x00\x2e\x72\x65\x6c\x2e\x42\x54\x46\x00\x4c\x42\x42\x30\x5f\x33\x00\x4c\x42\x42\x30\x5f\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcb\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x4b\x00\x00\x00\x00\x00\x00\x00\xf2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\xb8\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x15\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x82\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x28\x00\x00\x00\x00\x00\x00\x00\xba\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xe2\x00\x00\x00\x00\x00\x00\x00\xdd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x42\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xbf\x00\x00\x00\x00\x00\x00\x01\xdd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3e\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\xd8\x00\x00\x00\x00\x00\x00\x02\x70\x00\x00\x00\x15\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x28\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x9c\x00\x00\x00\x00\x00\x00\x01\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\xdf\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\xba\x00\x00\x00\x00\x00\x00\x03\x75\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x48\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x15\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x19\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x2f\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x68\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x15\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x9e\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x10\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x18\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x15\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x8e\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x38\x00\x00\x00\x00\x00\x00\x00\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x38\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x15\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x4e\x6f\xff\x4c\x03\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x48\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd3\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\xe0\x00\x00\x00\x00\x00\x00\x03\xd8\x00\x00\x00\x01\x00\x00\x00\x26\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x18")
diff --git a/examples/kprobepin/kprobepinexample_bpfel.go b/examples/kprobepin/kprobepinexample_bpfel.go
new file mode 100644
index 0000000..72363a2
--- /dev/null
+++ b/examples/kprobepin/kprobepinexample_bpfel.go
@@ -0,0 +1,116 @@
+// Code generated by bpf2go; DO NOT EDIT.
+// +build 386 amd64 amd64p32 arm arm64 mipsle mips64le mips64p32le ppc64le riscv64
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+
+	"github.com/cilium/ebpf"
+)
+
+// LoadKProbePinExample returns the embedded CollectionSpec for KProbePinExample.
+func LoadKProbePinExample() (*ebpf.CollectionSpec, error) {
+	reader := bytes.NewReader(_KProbePinExampleBytes)
+	spec, err := ebpf.LoadCollectionSpecFromReader(reader)
+	if err != nil {
+		return nil, fmt.Errorf("can't load KProbePinExample: %w", err)
+	}
+
+	return spec, err
+}
+
+// LoadKProbePinExampleObjects loads KProbePinExample and converts it into a struct.
+//
+// The following types are suitable as obj argument:
+//
+//     *KProbePinExampleObjects
+//     *KProbePinExamplePrograms
+//     *KProbePinExampleMaps
+//
+// See ebpf.CollectionSpec.LoadAndAssign documentation for details.
+func LoadKProbePinExampleObjects(obj interface{}, opts *ebpf.CollectionOptions) error {
+	spec, err := LoadKProbePinExample()
+	if err != nil {
+		return err
+	}
+
+	return spec.LoadAndAssign(obj, opts)
+}
+
+// KProbePinExampleSpecs contains maps and programs before they are loaded into the kernel.
+//
+// It can be passed ebpf.CollectionSpec.Assign.
+type KProbePinExampleSpecs struct {
+	KProbePinExampleProgramSpecs
+	KProbePinExampleMapSpecs
+}
+
+// KProbePinExampleSpecs contains programs before they are loaded into the kernel.
+//
+// It can be passed ebpf.CollectionSpec.Assign.
+type KProbePinExampleProgramSpecs struct {
+	KprobeExecve *ebpf.ProgramSpec `ebpf:"kprobe_execve"`
+}
+
+// KProbePinExampleMapSpecs contains maps before they are loaded into the kernel.
+//
+// It can be passed ebpf.CollectionSpec.Assign.
+type KProbePinExampleMapSpecs struct {
+	KprobeMap *ebpf.MapSpec `ebpf:"kprobe_map"`
+}
+
+// KProbePinExampleObjects contains all objects after they have been loaded into the kernel.
+//
+// It can be passed to LoadKProbePinExampleObjects or ebpf.CollectionSpec.LoadAndAssign.
+type KProbePinExampleObjects struct {
+	KProbePinExamplePrograms
+	KProbePinExampleMaps
+}
+
+func (o *KProbePinExampleObjects) Close() error {
+	return _KProbePinExampleClose(
+		&o.KProbePinExamplePrograms,
+		&o.KProbePinExampleMaps,
+	)
+}
+
+// KProbePinExampleMaps contains all maps after they have been loaded into the kernel.
+//
+// It can be passed to LoadKProbePinExampleObjects or ebpf.CollectionSpec.LoadAndAssign.
+type KProbePinExampleMaps struct {
+	KprobeMap *ebpf.Map `ebpf:"kprobe_map"`
+}
+
+func (m *KProbePinExampleMaps) Close() error {
+	return _KProbePinExampleClose(
+		m.KprobeMap,
+	)
+}
+
+// KProbePinExamplePrograms contains all programs after they have been loaded into the kernel.
+//
+// It can be passed to LoadKProbePinExampleObjects or ebpf.CollectionSpec.LoadAndAssign.
+type KProbePinExamplePrograms struct {
+	KprobeExecve *ebpf.Program `ebpf:"kprobe_execve"`
+}
+
+func (p *KProbePinExamplePrograms) Close() error {
+	return _KProbePinExampleClose(
+		p.KprobeExecve,
+	)
+}
+
+func _KProbePinExampleClose(closers ...io.Closer) error {
+	for _, closer := range closers {
+		if err := closer.Close(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// Do not access this directly.
+var _KProbePinExampleBytes = []byte("\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\xf7\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x40\x00\x16\x00\x01\x00\xb7\x01\x00\x00\x00\x00\x00\x00\x63\x1a\xfc\xff\x00\x00\x00\x00\xb7\x06\x00\x00\x01\x00\x00\x00\x7b\x6a\xf0\xff\x00\x00\x00\x00\xbf\xa2\x00\x00\x00\x00\x00\x00\x07\x02\x00\x00\xfc\xff\xff\xff\x18\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\x00\x00\x00\x01\x00\x00\x00\x55\x00\x09\x00\x00\x00\x00\x00\xbf\xa2\x00\x00\x00\x00\x00\x00\x07\x02\x00\x00\xfc\xff\xff\xff\xbf\xa3\x00\x00\x00\x00\x00\x00\x07\x03\x00\x00\xf0\xff\xff\xff\x18\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\x04\x00\x00\x00\x00\x00\x00\x85\x00\x00\x00\x02\x00\x00\x00\x05\x00\x01\x00\x00\x00\x00\x00\xdb\x60\x00\x00\x00\x00\x00\x00\xb7\x00\x00\x00\x00\x00\x00\x00\x95\x00\x00\x00\x00\x00\x00\x00\x44\x75\x61\x6c\x20\x4d\x49\x54\x2f\x47\x50\x4c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x02\x00\x30\x9f\x20\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00\x00\x02\x00\x7a\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x50\x00\x00\x00\x00\x00\x00\x00\x02\x00\x31\x9f\x50\x00\x00\x00\x00\x00\x00\x00\x98\x00\x00\x00\x00\x00\x00\x00\x02\x00\x7a\x00\x98\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x02\x00\x31\x9f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x48\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x01\x00\x50\x98\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x01\x00\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x11\x01\x25\x0e\x13\x05\x03\x0e\x10\x17\x1b\x0e\x11\x01\x12\x06\x00\x00\x02\x34\x00\x03\x0e\x49\x13\x3f\x19\x3a\x0b\x3b\x0b\x02\x18\x00\x00\x03\x01\x01\x49\x13\x00\x00\x04\x21\x00\x49\x13\x37\x0b\x00\x00\x05\x24\x00\x03\x0e\x3e\x0b\x0b\x0b\x00\x00\x06\x24\x00\x03\x0e\x0b\x0b\x3e\x0b\x00\x00\x07\x13\x01\x0b\x0b\x3a\x0b\x3b\x0b\x00\x00\x08\x0d\x00\x03\x0e\x49\x13\x3a\x0b\x3b\x0b\x38\x0b\x00\x00\x09\x0f\x00\x49\x13\x00\x00\x0a\x16\x00\x49\x13\x03\x0e\x3a\x0b\x3b\x0b\x00\x00\x0b\x34\x00\x03\x0e\x49\x13\x3a\x0b\x3b\x0b\x00\x00\x0c\x15\x01\x49\x13\x27\x19\x00\x00\x0d\x05\x00\x49\x13\x00\x00\x0e\x0f\x00\x00\x00\x0f\x26\x00\x00\x00\x10\x04\x01\x49\x13\x0b\x0b\x3a\x0b\x3b\x0b\x00\x00\x11\x28\x00\x03\x0e\x1c\x0f\x00\x00\x12\x2e\x01\x11\x01\x12\x06\x40\x18\x97\x42\x19\x03\x0e\x3a\x0b\x3b\x0b\x49\x13\x3f\x19\x00\x00\x13\x34\x00\x02\x17\x03\x0e\x3a\x0b\x3b\x0b\x49\x13\x00\x00\x00\xd9\x01\x00\x00\x04\x00\x00\x00\x00\x00\x08\x01\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x02\x00\x00\x00\x00\x3f\x00\x00\x00\x01\x04\x09\x03\x00\x00\x00\x00\x00\x00\x00\x00\x03\x4b\x00\x00\x00\x04\x52\x00\x00\x00\x0d\x00\x05\x00\x00\x00\x00\x06\x01\x06\x00\x00\x00\x00\x08\x07\x02\x00\x00\x00\x00\x6e\x00\x00\x00\x01\x0c\x09\x03\x00\x00\x00\x00\x00\x00\x00\x00\x07\x28\x01\x06\x08\x00\x00\x00\x00\xaf\x00\x00\x00\x01\x07\x00\x08\x00\x00\x00\x00\xc7\x00\x00\x00\x01\x08\x08\x08\x00\x00\x00\x00\xe9\x00\x00\x00\x01\x09\x10\x08\x00\x00\x00\x00\x0b\x01\x00\x00\x01\x0a\x18\x08\x00\x00\x00\x00\x0b\x01\x00\x00\x01\x0b\x20\x00\x09\xb4\x00\x00\x00\x03\xc0\x00\x00\x00\x04\x52\x00\x00\x00\x02\x00\x05\x00\x00\x00\x00\x05\x04\x09\xcc\x00\x00\x00\x0a\xd7\x00\x00\x00\x00\x00\x00\x00\x02\x11\x0a\xe2\x00\x00\x00\x00\x00\x00\x00\x02\x0a\x05\x00\x00\x00\x00\x07\x04\x09\xee\x00\x00\x00\x0a\xf9\x00\x00\x00\x00\x00\x00\x00\x02\x13\x0a\x04\x01\x00\x00\x00\x00\x00\x00\x02\x0c\x05\x00\x00\x00\x00\x07\x08\x09\x10\x01\x00\x00\x03\xc0\x00\x00\x00\x04\x52\x00\x00\x00\x01\x00\x0b\x00\x00\x00\x00\x27\x01\x00\x00\x03\x2a\x09\x2c\x01\x00\x00\x0c\x3c\x01\x00\x00\x0d\x3c\x01\x00\x00\x0d\x3d\x01\x00\x00\x00\x0e\x09\x42\x01\x00\x00\x0f\x0b\x00\x00\x00\x00\x4e\x01\x00\x00\x03\x40\x09\x53\x01\x00\x00\x0c\x6d\x01\x00\x00\x0d\x3c\x01\x00\x00\x0d\x3d\x01\x00\x00\x0d\x3d\x01\x00\x00\x0d\xf9\x00\x00\x00\x00\x05\x00\x00\x00\x00\x05\x08\x10\xe2\x00\x00\x00\x04\x02\x3a\x11\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x01\x11\x00\x00\x00\x00\x02\x11\x00\x00\x00\x00\x04\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x01\x5a\x00\x00\x00\x00\x01\x0f\xc0\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x01\x10\xcc\x00\x00\x00\x13\x38\x00\x00\x00\x00\x00\x00\x00\x01\x11\xee\x00\x00\x00\x13\x84\x00\x00\x00\x00\x00\x00\x00\x01\x11\xe9\x00\x00\x00\x00\x00\x00\x62\x70\x66\x2f\x6b\x70\x72\x6f\x62\x65\x5f\x70\x69\x6e\x5f\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x00\x2e\x00\x5f\x5f\x6c\x69\x63\x65\x6e\x73\x65\x00\x63\x68\x61\x72\x00\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\x00\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x00\x74\x79\x70\x65\x00\x69\x6e\x74\x00\x6b\x65\x79\x00\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\x00\x5f\x5f\x75\x33\x32\x00\x75\x33\x32\x00\x76\x61\x6c\x75\x65\x00\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\x20\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\x00\x5f\x5f\x75\x36\x34\x00\x75\x36\x34\x00\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\x00\x70\x69\x6e\x6e\x69\x6e\x67\x00\x62\x70\x66\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\x70\x5f\x65\x6c\x65\x6d\x00\x62\x70\x66\x5f\x6d\x61\x70\x5f\x75\x70\x64\x61\x74\x65\x5f\x65\x6c\x65\x6d\x00\x6c\x6f\x6e\x67\x20\x69\x6e\x74\x00\x42\x50\x46\x5f\x41\x4e\x59\x00\x42\x50\x46\x5f\x4e\x4f\x45\x58\x49\x53\x54\x00\x42\x50\x46\x5f\x45\x58\x49\x53\x54\x00\x42\x50\x46\x5f\x46\x5f\x4c\x4f\x43\x4b\x00\x6b\x70\x72\x6f\x62\x65\x5f\x65\x78\x65\x63\x76\x65\x00\x69\x6e\x69\x74\x76\x61\x6c\x00\x76\x61\x6c\x70\x00\x9f\xeb\x01\x00\x18\x00\x00\x00\x00\x00\x00\x00\xa8\x01\x00\x00\xa8\x01\x00\x00\xb5\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x03\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\x04\x00\x00\x00\x20\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x01\x04\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x06\x00\x00\x00\x19\x00\x00\x00\x00\x00\x00\x08\x07\x00\x00\x00\x1d\x00\x00\x00\x00\x00\x00\x08\x08\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x01\x04\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x0a\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x08\x0b\x00\x00\x00\x34\x00\x00\x00\x00\x00\x00\x08\x0c\x00\x00\x00\x3a\x00\x00\x00\x00\x00\x00\x01\x08\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x04\x28\x00\x00\x00\x51\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x56\x00\x00\x00\x05\x00\x00\x00\x40\x00\x00\x00\x5a\x00\x00\x00\x09\x00\x00\x00\x80\x00\x00\x00\x60\x00\x00\x00\x0d\x00\x00\x00\xc0\x00\x00\x00\x6c\x00\x00\x00\x0d\x00\x00\x00\x00\x01\x00\x00\x74\x00\x00\x00\x00\x00\x00\x0e\x0f\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x02\x00\x00\x00\x7f\x00\x00\x00\x01\x00\x00\x0c\x11\x00\x00\x00\x98\x01\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x08\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x13\x00\x00\x00\x04\x00\x00\x00\x0d\x00\x00\x00\x9d\x01\x00\x00\x00\x00\x00\x0e\x14\x00\x00\x00\x01\x00\x00\x00\xa7\x01\x00\x00\x01\x00\x00\x0f\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\xad\x01\x00\x00\x01\x00\x00\x0f\x00\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x00\x69\x6e\x74\x00\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\x00\x75\x33\x32\x00\x5f\x5f\x75\x33\x32\x00\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\x00\x75\x36\x34\x00\x5f\x5f\x75\x36\x34\x00\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\x20\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\x00\x74\x79\x70\x65\x00\x6b\x65\x79\x00\x76\x61\x6c\x75\x65\x00\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\x00\x70\x69\x6e\x6e\x69\x6e\x67\x00\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x00\x6b\x70\x72\x6f\x62\x65\x5f\x65\x78\x65\x63\x76\x65\x00\x6b\x70\x72\x6f\x62\x65\x2f\x73\x79\x73\x5f\x65\x78\x65\x63\x76\x65\x00\x2e\x2f\x62\x70\x66\x2f\x6b\x70\x72\x6f\x62\x65\x5f\x70\x69\x6e\x5f\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x00\x69\x6e\x74\x20\x6b\x70\x72\x6f\x62\x65\x5f\x65\x78\x65\x63\x76\x65\x28\x29\x20\x7b\x00\x09\x75\x33\x32\x20\x6b\x65\x79\x20\x20\x20\x20\x20\x3d\x20\x30\x3b\x00\x09\x75\x36\x34\x20\x69\x6e\x69\x74\x76\x61\x6c\x20\x3d\x20\x31\x2c\x20\x2a\x76\x61\x6c\x70\x3b\x00\x09\x76\x61\x6c\x70\x20\x3d\x20\x62\x70\x66\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\x70\x5f\x65\x6c\x65\x6d\x28\x26\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x2c\x20\x26\x6b\x65\x79\x29\x3b\x00\x09\x69\x66\x20\x28\x21\x76\x61\x6c\x70\x29\x20\x7b\x00\x09\x09\x62\x70\x66\x5f\x6d\x61\x70\x5f\x75\x70\x64\x61\x74\x65\x5f\x65\x6c\x65\x6d\x28\x26\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x2c\x20\x26\x6b\x65\x79\x2c\x20\x26\x69\x6e\x69\x74\x76\x61\x6c\x2c\x20\x42\x50\x46\x5f\x41\x4e\x59\x29\x3b\x00\x09\x5f\x5f\x73\x79\x6e\x63\x5f\x66\x65\x74\x63\x68\x5f\x61\x6e\x64\x5f\x61\x64\x64\x28\x76\x61\x6c\x70\x2c\x20\x31\x29\x3b\x00\x7d\x00\x63\x68\x61\x72\x00\x5f\x5f\x6c\x69\x63\x65\x6e\x73\x65\x00\x2e\x6d\x61\x70\x73\x00\x6c\x69\x63\x65\x6e\x73\x65\x00\x9f\xeb\x01\x00\x20\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x14\x00\x00\x00\xac\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x8d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x10\x00\x00\x00\x8d\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x9f\x00\x00\x00\xba\x00\x00\x00\x00\x3c\x00\x00\x08\x00\x00\x00\x9f\x00\x00\x00\xd0\x00\x00\x00\x06\x40\x00\x00\x18\x00\x00\x00\x9f\x00\x00\x00\xe2\x00\x00\x00\x06\x44\x00\x00\x28\x00\x00\x00\x9f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x9f\x00\x00\x00\xfb\x00\x00\x00\x09\x4c\x00\x00\x48\x00\x00\x00\x9f\x00\x00\x00\x2b\x01\x00\x00\x06\x50\x00\x00\x58\x00\x00\x00\x9f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x00\x00\x00\x9f\x00\x00\x00\x39\x01\x00\x00\x03\x54\x00\x00\x98\x00\x00\x00\x9f\x00\x00\x00\x76\x01\x00\x00\x02\x60\x00\x00\xa0\x00\x00\x00\x9f\x00\x00\x00\x96\x01\x00\x00\x01\x6c\x00\x00\x00\x0c\x00\x00\x00\xff\xff\xff\xff\x04\x00\x08\x00\x08\x7c\x0b\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00\x00\x9e\x00\x00\x00\x04\x00\x5c\x00\x00\x00\x08\x01\x01\xfb\x0e\x0d\x00\x01\x01\x01\x01\x00\x00\x00\x01\x00\x00\x01\x62\x70\x66\x00\x2e\x2e\x2f\x68\x65\x61\x64\x65\x72\x73\x00\x00\x6b\x70\x72\x6f\x62\x65\x5f\x70\x69\x6e\x5f\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x00\x01\x00\x00\x63\x6f\x6d\x6d\x6f\x6e\x2e\x68\x00\x02\x00\x00\x62\x70\x66\x5f\x68\x65\x6c\x70\x65\x72\x5f\x64\x65\x66\x73\x2e\x68\x00\x02\x00\x00\x00\x00\x09\x02\x00\x00\x00\x00\x00\x00\x00\x00\x03\x0e\x01\x05\x06\x0a\x21\x2f\x06\x03\x6f\x20\x05\x09\x06\x03\x13\x2e\x05\x06\x3d\x06\x03\x6c\x20\x05\x03\x06\x03\x15\x4a\x06\x03\x6b\x4a\x05\x02\x06\x03\x18\x20\x05\x01\x23\x02\x02\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6\x00\x00\x00\x04\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x26\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x2b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x53\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x6e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x95\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xa1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x4f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x6a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x91\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x8b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xa9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xbd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xd1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xda\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xe2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xee\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x03\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x19\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeb\x00\x00\x00\x00\x00\x03\x00\x98\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x00\x00\x00\x00\x00\x03\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x11\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x72\x00\x00\x00\x12\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00\x00\x33\x00\x00\x00\x11\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x28\x00\x00\x00\x70\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x28\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x23\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x02\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x03\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x25\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x04\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x21\x00\x00\x00\x2b\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x05\x00\x00\x00\x37\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x26\x00\x00\x00\x4c\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x06\x00\x00\x00\x53\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x07\x00\x00\x00\x5a\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x08\x00\x00\x00\x66\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x28\x00\x00\x00\x73\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x09\x00\x00\x00\x7f\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0a\x00\x00\x00\x8b\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0b\x00\x00\x00\x97\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0c\x00\x00\x00\xa3\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0d\x00\x00\x00\xc1\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0e\x00\x00\x00\xd1\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0f\x00\x00\x00\xdc\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x10\x00\x00\x00\xe3\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x11\x00\x00\x00\xf3\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x12\x00\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x13\x00\x00\x00\x05\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x14\x00\x00\x00\x1d\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x15\x00\x00\x00\x44\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x16\x00\x00\x00\x6e\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x17\x00\x00\x00\x7d\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x18\x00\x00\x00\x83\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x19\x00\x00\x00\x89\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x1a\x00\x00\x00\x8f\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x1b\x00\x00\x00\x96\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x21\x00\x00\x00\xa4\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x1c\x00\x00\x00\xaf\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x22\x00\x00\x00\xb3\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0a\x00\x00\x00\xbe\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x22\x00\x00\x00\xc2\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x1d\x00\x00\x00\xcd\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x22\x00\x00\x00\xd1\x01\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x1e\x00\x00\x00\xa0\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\xb8\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x26\x00\x00\x00\x2c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x24\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x21\x00\x00\x00\x69\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x21\x00\x00\x00\x27\x26\x28\x00\x2e\x64\x65\x62\x75\x67\x5f\x61\x62\x62\x72\x65\x76\x00\x2e\x74\x65\x78\x74\x00\x2e\x72\x65\x6c\x2e\x42\x54\x46\x2e\x65\x78\x74\x00\x2e\x6d\x61\x70\x73\x00\x2e\x64\x65\x62\x75\x67\x5f\x73\x74\x72\x00\x6b\x70\x72\x6f\x62\x65\x5f\x6d\x61\x70\x00\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x69\x6e\x66\x6f\x00\x2e\x6c\x6c\x76\x6d\x5f\x61\x64\x64\x72\x73\x69\x67\x00\x2e\x72\x65\x6c\x6b\x70\x72\x6f\x62\x65\x2f\x73\x79\x73\x5f\x65\x78\x65\x63\x76\x65\x00\x6b\x70\x72\x6f\x62\x65\x5f\x65\x78\x65\x63\x76\x65\x00\x5f\x5f\x6c\x69\x63\x65\x6e\x73\x65\x00\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x6c\x69\x6e\x65\x00\x2e\x72\x65\x6c\x2e\x64\x65\x62\x75\x67\x5f\x66\x72\x61\x6d\x65\x00\x2e\x64\x65\x62\x75\x67\x5f\x6c\x6f\x63\x00\x6b\x70\x72\x6f\x62\x65\x5f\x70\x69\x6e\x5f\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x00\x2e\x73\x74\x72\x74\x61\x62\x00\x2e\x73\x79\x6d\x74\x61\x62\x00\x2e\x72\x65\x6c\x2e\x42\x54\x46\x00\x4c\x42\x42\x30\x5f\x33\x00\x4c\x42\x42\x30\x5f\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcb\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4b\x12\x00\x00\x00\x00\x00\x00\xf2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8\x0e\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x03\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x82\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x01\x00\x00\x00\x00\x00\x00\xba\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe2\x01\x00\x00\x00\x00\x00\x00\xdd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x42\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x02\x00\x00\x00\x00\x00\x00\xdd\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3e\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8\x0e\x00\x00\x00\x00\x00\x00\x70\x02\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x09\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\x01\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9c\x04\x00\x00\x00\x00\x00\x00\x1e\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xdf\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xba\x05\x00\x00\x00\x00\x00\x00\x75\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x48\x11\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x0c\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2f\x09\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x68\x11\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x0e\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x9e\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x0a\x00\x00\x00\x00\x00\x00\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x12\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x10\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x8e\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\x0a\x00\x00\x00\x00\x00\x00\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\x12\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x12\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x4e\x00\x00\x00\x03\x4c\xff\x6f\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x48\x12\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd3\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0a\x00\x00\x00\x00\x00\x00\xd8\x03\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x26\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00")
diff --git a/examples/kprobepin/main.go b/examples/kprobepin/main.go
new file mode 100644
index 0000000..dd4f55f
--- /dev/null
+++ b/examples/kprobepin/main.go
@@ -0,0 +1,94 @@
+// +build linux
+
+// This program demonstrates attaching an eBPF program to a kernel symbol.
+// The eBPF program will be attached to the start of the sys_execve
+// kernel function and prints out the number of times it has been called
+// every second.
+package main
+
+import (
+	"log"
+	"os"
+	"os/signal"
+	"path"
+	"syscall"
+	"time"
+
+	"github.com/cilium/ebpf"
+	"github.com/cilium/ebpf/link"
+	"golang.org/x/sys/unix"
+)
+
+//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-11 KProbePinExample ./bpf/kprobe_pin_example.c -- -I../headers
+
+const (
+	mapKey    uint32 = 0
+	bpfFSPath        = "/sys/fs/bpf"
+)
+
+func main() {
+
+	// Name of the kernel function to trace.
+	fn := "sys_execve"
+
+	// Subscribe to signals for terminating the program.
+	stopper := make(chan os.Signal, 1)
+	signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)
+
+	// Increase the rlimit of the current process to provide sufficient space
+	// for locking memory for the eBPF map.
+	if err := unix.Setrlimit(unix.RLIMIT_MEMLOCK, &unix.Rlimit{
+		Cur: unix.RLIM_INFINITY,
+		Max: unix.RLIM_INFINITY,
+	}); err != nil {
+		log.Fatalf("failed to set temporary rlimit: %v", err)
+	}
+
+	pinPath := path.Join(bpfFSPath, fn)
+	if err := os.MkdirAll(pinPath, os.ModePerm); err != nil {
+		log.Fatalf("failed to create bpf fs subpath: %+v", err)
+	}
+
+	var kProbeObj KProbePinExampleObjects
+	if err := LoadKProbePinExampleObjects(&kProbeObj, &ebpf.CollectionOptions{
+		Maps: ebpf.MapOptions{
+			// Pin the map to the BPF filesystem and configure the
+			// library to automatically re-write it in the BPF
+			// program so it can be re-used if it already exists or
+			// create it if not
+			PinPath: pinPath,
+		},
+	}); err != nil {
+		log.Fatalf("loading objects: %v", err)
+	}
+	defer kProbeObj.Close()
+
+	// Open a Kprobe at the entry point of the kernel function and attach the
+	// pre-compiled program. Each time the kernel function enters, the program
+	// will increment the execution counter by 1. The read loop below polls this
+	// map value once per second.
+	kp, err := link.Kprobe(fn, kProbeObj.KprobeExecve)
+	if err != nil {
+		log.Fatalf("opening kprobe: %s", err)
+	}
+	defer kp.Close()
+
+	// Read loop reporting the total amount of times the kernel
+	// function was entered, once per second.
+	ticker := time.NewTicker(1 * time.Second)
+
+	log.Println("Waiting for events..")
+
+	for {
+		select {
+		case <-ticker.C:
+			var value uint64
+			if err := kProbeObj.KprobeMap.Lookup(mapKey, &value); err != nil {
+				log.Fatalf("reading map: %v", err)
+			}
+			log.Printf("%s called %d times\n", fn, value)
+		case <-stopper:
+			return
+		}
+	}
+}
diff --git a/features/prog.go b/features/prog.go
new file mode 100644
index 0000000..f5e2b9a
--- /dev/null
+++ b/features/prog.go
@@ -0,0 +1,156 @@
+package features
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"os"
+	"sync"
+
+	"github.com/cilium/ebpf"
+	"github.com/cilium/ebpf/asm"
+	"github.com/cilium/ebpf/internal"
+	"github.com/cilium/ebpf/internal/unix"
+)
+
+func init() {
+	pc.progTypes = make(map[ebpf.ProgramType]error)
+}
+
+var (
+	pc progCache
+)
+
+type progCache struct {
+	sync.Mutex
+	progTypes map[ebpf.ProgramType]error
+}
+
+func createProgLoadAttr(pt ebpf.ProgramType) (*internal.BPFProgLoadAttr, error) {
+	var expectedAttachType ebpf.AttachType
+
+	insns := asm.Instructions{
+		asm.LoadImm(asm.R0, 0, asm.DWord),
+		asm.Return(),
+	}
+
+	buf := bytes.NewBuffer(make([]byte, 0, len(insns)*asm.InstructionSize))
+	if err := insns.Marshal(buf, internal.NativeEndian); err != nil {
+		return nil, err
+	}
+
+	bytecode := buf.Bytes()
+	instructions := internal.NewSlicePointer(bytecode)
+
+	// Some programs have expected attach types which are checked during the
+	// BPD_PROG_LOAD syscall.
+	switch pt {
+	case ebpf.CGroupSockAddr:
+		expectedAttachType = ebpf.AttachCGroupInet4Connect
+	case ebpf.CGroupSockopt:
+		expectedAttachType = ebpf.AttachCGroupGetsockopt
+	case ebpf.SkLookup:
+		expectedAttachType = ebpf.AttachSkLookup
+	default:
+		expectedAttachType = ebpf.AttachNone
+	}
+
+	// Kernels before 5.0 (6c4fc209fcf9 "bpf: remove useless version check for prog load")
+	// require the version field to be set to the value of the KERNEL_VERSION
+	// macro for kprobe-type programs.
+	v, err := internal.KernelVersion()
+	if err != nil {
+		return nil, fmt.Errorf("detecting kernel version: %w", err)
+	}
+	kv := v.Kernel()
+
+	return &internal.BPFProgLoadAttr{
+		ProgType:           uint32(pt),
+		Instructions:       instructions,
+		InsCount:           uint32(len(bytecode) / asm.InstructionSize),
+		ExpectedAttachType: uint32(expectedAttachType),
+		License:            internal.NewStringPointer("GPL"),
+		KernelVersion:      kv,
+	}, nil
+}
+
+// HaveProgType probes the running kernel for the availability of the specified program type.
+// Return values have the following semantics:
+//
+//   err == nil: The feature is available.
+//   errors.Is(err, ebpf.ErrNotSupported): The feature is not available.
+//   err != nil: Any errors encountered during probe execution, wrapped.
+//
+// Note that the latter case may include false negatives, and that program creation may
+// succeed despite an error being returned. Some program types cannot reliably be probed and
+// will also return error. Only `nil` and `ebpf.ErrNotSupported` are conclusive.
+//
+// Probe results are cached and persist throughout any process capability changes.
+func HaveProgType(pt ebpf.ProgramType) error {
+	if err := validateProgType(pt); err != nil {
+		return err
+	}
+
+	return haveProgType(pt)
+
+}
+
+func validateProgType(pt ebpf.ProgramType) error {
+	if pt > pt.Max() {
+		return os.ErrInvalid
+	}
+
+	if progLoadProbeNotImplemented(pt) {
+		// A probe for a these prog types has BTF requirements we currently cannot meet
+		// Once we figure out how to add a working probe in this package, we can remove
+		// this check
+		return fmt.Errorf("a probe for ProgType %s isn't implemented", pt.String())
+	}
+
+	return nil
+}
+
+func haveProgType(pt ebpf.ProgramType) error {
+	pc.Lock()
+	defer pc.Unlock()
+	err, ok := pc.progTypes[pt]
+	if ok {
+		return err
+	}
+
+	attr, err := createProgLoadAttr(pt)
+	if err != nil {
+		return fmt.Errorf("couldn't create the program load attribute: %w", err)
+	}
+
+	_, err = internal.BPFProgLoad(attr)
+
+	switch {
+	// EINVAL occurs when attempting to create a program with an unknown type.
+	// E2BIG occurs when BPFProgLoadAttr contains non-zero bytes past the end
+	// of the struct known by the running kernel, meaning the kernel is too old
+	// to support the given map type.
+	case errors.Is(err, unix.EINVAL), errors.Is(err, unix.E2BIG):
+		err = ebpf.ErrNotSupported
+
+	// EPERM is kept as-is and is not converted or wrapped.
+	case errors.Is(err, unix.EPERM):
+		break
+
+	// Wrap unexpected errors.
+	case err != nil:
+		err = fmt.Errorf("unexpected error during feature probe: %w", err)
+	}
+
+	pc.progTypes[pt] = err
+
+	return err
+}
+
+func progLoadProbeNotImplemented(pt ebpf.ProgramType) bool {
+	switch pt {
+	case ebpf.Tracing, ebpf.StructOps, ebpf.Extension, ebpf.LSM:
+		return true
+	}
+	return false
+}
diff --git a/internal/syscall.go b/internal/syscall.go
index 5755ba9..b75037b 100644
--- a/internal/syscall.go
+++ b/internal/syscall.go
@@ -1,6 +1,7 @@
 package internal
 
 import (
+	"errors"
 	"fmt"
 	"path/filepath"
 	"runtime"
@@ -68,6 +69,48 @@ func BPF(cmd BPFCmd, attr unsafe.Pointer, size uintptr) (uintptr, error) {
 	return r1, err
 }
 
+type BPFProgLoadAttr struct {
+	ProgType           uint32
+	InsCount           uint32
+	Instructions       Pointer
+	License            Pointer
+	LogLevel           uint32
+	LogSize            uint32
+	LogBuf             Pointer
+	KernelVersion      uint32     // since 4.1  2541517c32be
+	ProgFlags          uint32     // since 4.11 e07b98d9bffe
+	ProgName           BPFObjName // since 4.15 067cae47771c
+	ProgIfIndex        uint32     // since 4.15 1f6f4cb7ba21
+	ExpectedAttachType uint32     // since 4.17 5e43f899b03a
+	ProgBTFFd          uint32
+	FuncInfoRecSize    uint32
+	FuncInfo           Pointer
+	FuncInfoCnt        uint32
+	LineInfoRecSize    uint32
+	LineInfo           Pointer
+	LineInfoCnt        uint32
+	AttachBTFID        uint32
+	AttachProgFd       uint32
+}
+
+// BPFProgLoad wraps BPF_PROG_LOAD.
+func BPFProgLoad(attr *BPFProgLoadAttr) (*FD, error) {
+	for {
+		fd, err := BPF(BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
+		// As of ~4.20 the verifier can be interrupted by a signal,
+		// and returns EAGAIN in that case.
+		if errors.Is(err, unix.EAGAIN) {
+			continue
+		}
+
+		if err != nil {
+			return nil, err
+		}
+
+		return NewFD(uint32(fd)), nil
+	}
+}
+
 type BPFProgAttachAttr struct {
 	TargetFd     uint32
 	AttachBpfFd  uint32
diff --git a/prog.go b/prog.go
index a6cbed3..ce2a27f 100644
--- a/prog.go
+++ b/prog.go
@@ -171,16 +171,16 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
 		kv = v.Kernel()
 	}
 
-	attr := &bpfProgLoadAttr{
-		progType:           spec.Type,
-		progFlags:          spec.Flags,
-		expectedAttachType: spec.AttachType,
-		license:            internal.NewStringPointer(spec.License),
-		kernelVersion:      kv,
+	attr := &internal.BPFProgLoadAttr{
+		ProgType:           uint32(spec.Type),
+		ProgFlags:          spec.Flags,
+		ExpectedAttachType: uint32(spec.AttachType),
+		License:            internal.NewStringPointer(spec.License),
+		KernelVersion:      kv,
 	}
 
 	if haveObjName() == nil {
-		attr.progName = internal.NewBPFObjName(spec.Name)
+		attr.ProgName = internal.NewBPFObjName(spec.Name)
 	}
 
 	var err error
@@ -207,23 +207,23 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
 		}
 
 		if handle != nil {
-			attr.progBTFFd = uint32(handle.FD())
+			attr.ProgBTFFd = uint32(handle.FD())
 
 			recSize, bytes, err := btf.ProgramLineInfos(spec.BTF)
 			if err != nil {
 				return nil, fmt.Errorf("get BTF line infos: %w", err)
 			}
-			attr.lineInfoRecSize = recSize
-			attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
-			attr.lineInfo = internal.NewSlicePointer(bytes)
+			attr.LineInfoRecSize = recSize
+			attr.LineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
+			attr.LineInfo = internal.NewSlicePointer(bytes)
 
 			recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF)
 			if err != nil {
 				return nil, fmt.Errorf("get BTF function infos: %w", err)
 			}
-			attr.funcInfoRecSize = recSize
-			attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
-			attr.funcInfo = internal.NewSlicePointer(bytes)
+			attr.FuncInfoRecSize = recSize
+			attr.FuncInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
+			attr.FuncInfo = internal.NewSlicePointer(bytes)
 		}
 	}
 
@@ -243,8 +243,8 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
 	}
 
 	bytecode := buf.Bytes()
-	attr.instructions = internal.NewSlicePointer(bytecode)
-	attr.insCount = uint32(len(bytecode) / asm.InstructionSize)
+	attr.Instructions = internal.NewSlicePointer(bytecode)
+	attr.InsCount = uint32(len(bytecode) / asm.InstructionSize)
 
 	if spec.AttachTo != "" {
 		if spec.AttachTarget != nil {
@@ -273,10 +273,10 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
 			return nil, err
 		}
 		if target != nil {
-			attr.attachBTFID = target.ID()
+			attr.AttachBTFID = uint32(target.ID())
 		}
 		if spec.AttachTarget != nil {
-			attr.attachProgFd = uint32(spec.AttachTarget.FD())
+			attr.AttachProgFd = uint32(spec.AttachTarget.FD())
 		}
 	}
 
@@ -288,12 +288,12 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
 	var logBuf []byte
 	if opts.LogLevel > 0 {
 		logBuf = make([]byte, logSize)
-		attr.logLevel = opts.LogLevel
-		attr.logSize = uint32(len(logBuf))
-		attr.logBuf = internal.NewSlicePointer(logBuf)
+		attr.LogLevel = opts.LogLevel
+		attr.LogSize = uint32(len(logBuf))
+		attr.LogBuf = internal.NewSlicePointer(logBuf)
 	}
 
-	fd, err := bpfProgLoad(attr)
+	fd, err := internal.BPFProgLoad(attr)
 	if err == nil {
 		return &Program{internal.CString(logBuf), fd, spec.Name, "", spec.Type}, nil
 	}
@@ -302,11 +302,11 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
 	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
-		attr.logSize = uint32(len(logBuf))
-		attr.logBuf = internal.NewSlicePointer(logBuf)
+		attr.LogLevel = 1
+		attr.LogSize = uint32(len(logBuf))
+		attr.LogBuf = internal.NewSlicePointer(logBuf)
 
-		_, logErr = bpfProgLoad(attr)
+		_, logErr = internal.BPFProgLoad(attr)
 	}
 
 	if errors.Is(logErr, unix.EPERM) && logBuf[0] == 0 {
diff --git a/syscalls.go b/syscalls.go
index 62d85ed..dd25b8d 100644
--- a/syscalls.go
+++ b/syscalls.go
@@ -7,7 +7,6 @@ import (
 	"unsafe"
 
 	"github.com/cilium/ebpf/internal"
-	"github.com/cilium/ebpf/internal/btf"
 	"github.com/cilium/ebpf/internal/unix"
 )
 
@@ -73,30 +72,6 @@ type bpfMapInfo struct {
 	btf_value_type_id         uint32
 }
 
-type bpfProgLoadAttr struct {
-	progType           ProgramType
-	insCount           uint32
-	instructions       internal.Pointer
-	license            internal.Pointer
-	logLevel           uint32
-	logSize            uint32
-	logBuf             internal.Pointer
-	kernelVersion      uint32              // since 4.1  2541517c32be
-	progFlags          uint32              // since 4.11 e07b98d9bffe
-	progName           internal.BPFObjName // since 4.15 067cae47771c
-	progIfIndex        uint32              // since 4.15 1f6f4cb7ba21
-	expectedAttachType AttachType          // since 4.17 5e43f899b03a
-	progBTFFd          uint32
-	funcInfoRecSize    uint32
-	funcInfo           internal.Pointer
-	funcInfoCnt        uint32
-	lineInfoRecSize    uint32
-	lineInfo           internal.Pointer
-	lineInfoCnt        uint32
-	attachBTFID        btf.TypeID
-	attachProgFd       uint32
-}
-
 type bpfProgInfo struct {
 	prog_type                uint32
 	id                       uint32
@@ -155,23 +130,6 @@ type bpfObjGetNextIDAttr struct {
 	openFlags uint32
 }
 
-func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) {
-	for {
-		fd, err := internal.BPF(internal.BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
-		// As of ~4.20 the verifier can be interrupted by a signal,
-		// and returns EAGAIN in that case.
-		if errors.Is(err, unix.EAGAIN) {
-			continue
-		}
-
-		if err != nil {
-			return nil, err
-		}
-
-		return internal.NewFD(uint32(fd)), nil
-	}
-}
-
 func bpfProgTestRun(attr *bpfProgTestRunAttr) error {
 	_, err := internal.BPF(internal.BPF_PROG_TEST_RUN, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 	return err
diff --git a/types.go b/types.go
index c91d806..e0bd3ef 100644
--- a/types.go
+++ b/types.go
@@ -123,6 +123,11 @@ func (mt MapType) canStoreProgram() bool {
 // ProgramType of the eBPF program
 type ProgramType uint32
 
+// Max return the latest supported ProgramType.
+func (_ ProgramType) Max() ProgramType {
+	return maxProgramType - 1
+}
+
 // eBPF program types
 const (
 	UnspecifiedProgram ProgramType = iota
@@ -156,6 +161,7 @@ const (
 	Extension
 	LSM
 	SkLookup
+	maxProgramType
 )
 
 // AttachType of the eBPF program, needed to differentiate allowed context accesses in


Test patch:
diff --git a/features/prog_test.go b/features/prog_test.go
new file mode 100644
index 0000000..76c90e6
--- /dev/null
+++ b/features/prog_test.go
@@ -0,0 +1,92 @@
+package features
+
+import (
+	"fmt"
+	"math"
+	"os"
+	"testing"
+
+	"github.com/cilium/ebpf"
+	"github.com/cilium/ebpf/internal/testutils"
+)
+
+var progTypeMinVersion = map[ebpf.ProgramType]string{
+	ebpf.SocketFilter:          "3.19",
+	ebpf.Kprobe:                "4.1",
+	ebpf.SchedCLS:              "4.1",
+	ebpf.SchedACT:              "4.1",
+	ebpf.TracePoint:            "4.7",
+	ebpf.XDP:                   "4.8",
+	ebpf.PerfEvent:             "4.9",
+	ebpf.CGroupSKB:             "4.10",
+	ebpf.CGroupSock:            "4.10",
+	ebpf.LWTIn:                 "4.10",
+	ebpf.LWTOut:                "4.10",
+	ebpf.LWTXmit:               "4.10",
+	ebpf.SockOps:               "4.13",
+	ebpf.SkSKB:                 "4.14",
+	ebpf.CGroupDevice:          "4.15",
+	ebpf.SkMsg:                 "4.17",
+	ebpf.RawTracepoint:         "4.17",
+	ebpf.CGroupSockAddr:        "4.17",
+	ebpf.LWTSeg6Local:          "4.18",
+	ebpf.LircMode2:             "4.18",
+	ebpf.SkReuseport:           "4.19",
+	ebpf.FlowDissector:         "4.20",
+	ebpf.CGroupSysctl:          "5.2",
+	ebpf.RawTracepointWritable: "5.2",
+	ebpf.CGroupSockopt:         "5.3",
+	ebpf.Tracing:               "5.5",
+	ebpf.StructOps:             "5.6",
+	ebpf.Extension:             "5.6",
+	ebpf.LSM:                   "5.7",
+	ebpf.SkLookup:              "5.9",
+}
+
+func TestHaveProgType(t *testing.T) {
+	for progType := ebpf.UnspecifiedProgram + 1; progType <= progType.Max(); progType++ {
+		// Need inner loop copy to make use of t.Parallel()
+		pt := progType
+
+		minVersion, ok := progTypeMinVersion[pt]
+		if !ok {
+			// In cases where a new prog type wasn't added to progTypeMinVersion
+			// we should make sure the test runs anyway and fails on old kernels
+			minVersion = "0.0"
+		}
+
+		feature := fmt.Sprintf("program type %s", pt.String())
+
+		t.Run(pt.String(), func(t *testing.T) {
+			t.Parallel()
+
+			if progLoadProbeNotImplemented(pt) {
+				t.Skipf("Test for prog type %s requires working probe", pt.String())
+			}
+			testutils.SkipOnOldKernel(t, minVersion, feature)
+
+			if err := HaveProgType(pt); err != nil {
+				if pt == ebpf.LircMode2 {
+					// The probe for LircMode2 technically works but needs to be skipped if unsuccessful
+					// because the current testing kernels don't support it.
+					testutils.SkipIfNotSupported(t, err)
+				}
+
+				t.Fatalf("Program type %s isn't supported even though kernel is at least %s: %v", pt.String(), minVersion, err)
+			}
+		})
+
+	}
+}
+
+func TestHaveProgTypeUnsupported(t *testing.T) {
+	if err := haveProgType(ebpf.ProgramType(math.MaxUint32)); err != ebpf.ErrNotSupported {
+		t.Fatalf("Expected ebpf.ErrNotSupported but was: %v", err)
+	}
+}
+
+func TestHaveProgTypeInvalid(t *testing.T) {
+	if err := HaveProgType(ebpf.ProgramType(math.MaxUint32)); err != os.ErrInvalid {
+		t.Fatalf("Expected os.ErrInvalid but was: %v", err)
+	}
+}