Repository: cilium/ebpf
Pull request #116 (2020-07-02 10:10:48)

Drop support for go 1.12, and remove golang.org/x/xerrors
Now that Go1.12 reached EOL, it should be possible to drop support for it, and to remove the transitional golang.org/x/xerrors
dependency.

This also fixes a minor bug, detected by Go 1.13+;

    # github.com/cilium/ebpf
    ./elf_reader.go:211: Errorf call needs 2 args but has 3 args
    FAIL    github.com/cilium/ebpf [build failed]

relates to https://github.com/cilium/ebpf/issues/37
relates to https://github.com/cilium/ebpf/issues/38


thaJeztah: @lmb PTAL

Patch:
diff --git a/abi.go b/abi.go
index fd6139c..d432eb4 100644
--- a/abi.go
+++ b/abi.go
@@ -3,14 +3,13 @@ package ebpf
 import (
 	"bufio"
 	"bytes"
+	"errors"
 	"fmt"
 	"io"
 	"os"
 	"syscall"
 
 	"github.com/cilium/ebpf/internal"
-
-	"golang.org/x/xerrors"
 )
 
 // MapABI are the attributes of a Map which are available across all supported kernels.
@@ -35,7 +34,7 @@ func newMapABIFromSpec(spec *MapSpec) *MapABI {
 func newMapABIFromFd(fd *internal.FD) (string, *MapABI, error) {
 	info, err := bpfGetMapInfoByFD(fd)
 	if err != nil {
-		if xerrors.Is(err, syscall.EINVAL) {
+		if errors.Is(err, syscall.EINVAL) {
 			abi, err := newMapABIFromProc(fd)
 			return "", abi, err
 		}
@@ -98,7 +97,7 @@ func newProgramABIFromSpec(spec *ProgramSpec) *ProgramABI {
 func newProgramABIFromFd(fd *internal.FD) (string, *ProgramABI, error) {
 	info, err := bpfGetProgInfoByFD(fd)
 	if err != nil {
-		if xerrors.Is(err, syscall.EINVAL) {
+		if errors.Is(err, syscall.EINVAL) {
 			return newProgramABIFromProc(fd)
 		}
 
@@ -127,7 +126,7 @@ func newProgramABIFromProc(fd *internal.FD) (string, *ProgramABI, error) {
 		"prog_type": &abi.Type,
 		"prog_tag":  &name,
 	})
-	if xerrors.Is(err, errMissingFields) {
+	if errors.Is(err, errMissingFields) {
 		return "", nil, &internal.UnsupportedFeatureError{
 			Name:           "reading ABI from /proc/self/fdinfo",
 			MinimumVersion: internal.Version{4, 11, 0},
@@ -153,12 +152,12 @@ func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error {
 	defer fh.Close()
 
 	if err := scanFdInfoReader(fh, fields); err != nil {
-		return xerrors.Errorf("%s: %w", fh.Name(), err)
+		return fmt.Errorf("%s: %w", fh.Name(), err)
 	}
 	return nil
 }
 
-var errMissingFields = xerrors.New("missing fields")
+var errMissingFields = errors.New("missing fields")
 
 func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
 	var (
@@ -179,7 +178,7 @@ func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
 		}
 
 		if n, err := fmt.Fscanln(bytes.NewReader(parts[1]), field); err != nil || n != 1 {
-			return xerrors.Errorf("can't parse field %s: %v", name, err)
+			return fmt.Errorf("can't parse field %s: %v", name, err)
 		}
 
 		scanned++
diff --git a/asm/instruction.go b/asm/instruction.go
index 02ed6c6..8fbcf56 100644
--- a/asm/instruction.go
+++ b/asm/instruction.go
@@ -2,12 +2,11 @@ package asm
 
 import (
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io"
 	"math"
 	"strings"
-
-	"golang.org/x/xerrors"
 )
 
 // InstructionSize is the size of a BPF instruction in bytes
@@ -43,7 +42,7 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err
 	ins.Constant = int64(bi.Constant)
 	ins.Dst, ins.Src, err = bi.Registers.Unmarshal(bo)
 	if err != nil {
-		return 0, xerrors.Errorf("can't unmarshal registers: %s", err)
+		return 0, fmt.Errorf("can't unmarshal registers: %s", err)
 	}
 
 	if !bi.OpCode.isDWordLoad() {
@@ -53,10 +52,10 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err
 	var bi2 bpfInstruction
 	if err := binary.Read(r, bo, &bi2); err != nil {
 		// No Wrap, to avoid io.EOF clash
-		return 0, xerrors.New("64bit immediate is missing second half")
+		return 0, errors.New("64bit immediate is missing second half")
 	}
 	if bi2.OpCode != 0 || bi2.Offset != 0 || bi2.Registers != 0 {
-		return 0, xerrors.New("64bit immediate has non-zero fields")
+		return 0, errors.New("64bit immediate has non-zero fields")
 	}
 	ins.Constant = int64(uint64(uint32(bi2.Constant))<<32 | uint64(uint32(bi.Constant)))
 
@@ -66,7 +65,7 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err
 // Marshal encodes a BPF instruction.
 func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error) {
 	if ins.OpCode == InvalidOpCode {
-		return 0, xerrors.New("invalid opcode")
+		return 0, errors.New("invalid opcode")
 	}
 
 	isDWordLoad := ins.OpCode.isDWordLoad()
@@ -79,7 +78,7 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error)
 
 	regs, err := newBPFRegisters(ins.Dst, ins.Src, bo)
 	if err != nil {
-		return 0, xerrors.Errorf("can't marshal registers: %s", err)
+		return 0, fmt.Errorf("can't marshal registers: %s", err)
 	}
 
 	bpfi := bpfInstruction{
@@ -113,11 +112,11 @@ 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() {
-		return xerrors.Errorf("%s is not a 64 bit load", ins.OpCode)
+		return fmt.Errorf("%s is not a 64 bit load", ins.OpCode)
 	}
 
 	if ins.Src != PseudoMapFD && ins.Src != PseudoMapValue {
-		return xerrors.New("not a load from a map")
+		return errors.New("not a load from a map")
 	}
 
 	// Preserve the offset value for direct map loads.
@@ -136,11 +135,11 @@ func (ins *Instruction) mapPtr() uint32 {
 // Returns an error if the instruction is not a direct load.
 func (ins *Instruction) RewriteMapOffset(offset uint32) error {
 	if !ins.OpCode.isDWordLoad() {
-		return xerrors.Errorf("%s is not a 64 bit load", ins.OpCode)
+		return fmt.Errorf("%s is not a 64 bit load", ins.OpCode)
 	}
 
 	if ins.Src != PseudoMapValue {
-		return xerrors.New("not a direct load from a map")
+		return errors.New("not a direct load from a map")
 	}
 
 	fd := uint64(ins.Constant) & math.MaxUint32
@@ -251,7 +250,7 @@ func (insns Instructions) String() string {
 // Returns an error if the symbol isn't used, see IsUnreferencedSymbol.
 func (insns Instructions) RewriteMapPtr(symbol string, fd int) error {
 	if symbol == "" {
-		return xerrors.New("empty symbol")
+		return errors.New("empty symbol")
 	}
 
 	found := false
@@ -286,7 +285,7 @@ func (insns Instructions) SymbolOffsets() (map[string]int, error) {
 		}
 
 		if _, ok := offsets[ins.Symbol]; ok {
-			return nil, xerrors.Errorf("duplicate symbol %s", ins.Symbol)
+			return nil, fmt.Errorf("duplicate symbol %s", ins.Symbol)
 		}
 
 		offsets[ins.Symbol] = i
@@ -324,7 +323,7 @@ func (insns Instructions) marshalledOffsets() (map[string]int, error) {
 		}
 
 		if _, ok := symbols[ins.Symbol]; ok {
-			return nil, xerrors.Errorf("duplicate symbol %s", ins.Symbol)
+			return nil, fmt.Errorf("duplicate symbol %s", ins.Symbol)
 		}
 
 		symbols[ins.Symbol] = currentPos
@@ -405,7 +404,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
 			// Rewrite bpf to bpf call
 			offset, ok := absoluteOffsets[ins.Reference]
 			if !ok {
-				return xerrors.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
+				return fmt.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
 			}
 
 			ins.Constant = int64(offset - num - 1)
@@ -414,7 +413,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
 			// Rewrite jump to label
 			offset, ok := absoluteOffsets[ins.Reference]
 			if !ok {
-				return xerrors.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
+				return fmt.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
 			}
 
 			ins.Offset = int16(offset - num - 1)
@@ -422,7 +421,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
 
 		n, err := ins.Marshal(w, bo)
 		if err != nil {
-			return xerrors.Errorf("instruction %d: %w", i, err)
+			return fmt.Errorf("instruction %d: %w", i, err)
 		}
 
 		num += int(n / InstructionSize)
@@ -446,7 +445,7 @@ func newBPFRegisters(dst, src Register, bo binary.ByteOrder) (bpfRegisters, erro
 	case binary.BigEndian:
 		return bpfRegisters((dst << 4) | (src & 0xF)), nil
 	default:
-		return 0, xerrors.Errorf("unrecognized ByteOrder %T", bo)
+		return 0, fmt.Errorf("unrecognized ByteOrder %T", bo)
 	}
 }
 
@@ -457,7 +456,7 @@ func (r bpfRegisters) Unmarshal(bo binary.ByteOrder) (dst, src Register, err err
 	case binary.BigEndian:
 		return Register(r >> 4), Register(r & 0xf), nil
 	default:
-		return 0, 0, xerrors.Errorf("unrecognized ByteOrder %T", bo)
+		return 0, 0, fmt.Errorf("unrecognized ByteOrder %T", bo)
 	}
 }
 
diff --git a/collection.go b/collection.go
index 5b3ed58..0c8b65d 100644
--- a/collection.go
+++ b/collection.go
@@ -1,12 +1,13 @@
 package ebpf
 
 import (
+	"errors"
+	"fmt"
 	"math"
 
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/btf"
-	"golang.org/x/xerrors"
 )
 
 // CollectionOptions control loading a collection into the kernel.
@@ -64,12 +65,12 @@ func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error {
 				// Not all programs need to use the map
 
 			default:
-				return xerrors.Errorf("program %s: %w", progName, err)
+				return fmt.Errorf("program %s: %w", progName, err)
 			}
 		}
 
 		if !seen {
-			return xerrors.Errorf("map %s not referenced by any programs", symbol)
+			return fmt.Errorf("map %s not referenced by any programs", symbol)
 		}
 
 		// Prevent NewCollection from creating rewritten maps
@@ -96,21 +97,21 @@ func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error {
 func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error {
 	rodata := cs.Maps[".rodata"]
 	if rodata == nil {
-		return xerrors.New("missing .rodata section")
+		return errors.New("missing .rodata section")
 	}
 
 	if rodata.BTF == nil {
-		return xerrors.New(".rodata section has no BTF")
+		return errors.New(".rodata section has no BTF")
 	}
 
 	if n := len(rodata.Contents); n != 1 {
-		return xerrors.Errorf("expected one key in .rodata, found %d", n)
+		return fmt.Errorf("expected one key in .rodata, found %d", n)
 	}
 
 	kv := rodata.Contents[0]
 	value, ok := kv.Value.([]byte)
 	if !ok {
-		return xerrors.Errorf("first value in .rodata is %T not []byte", kv.Value)
+		return fmt.Errorf("first value in .rodata is %T not []byte", kv.Value)
 	}
 
 	buf := make([]byte, len(value))
@@ -185,14 +186,14 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (col
 		var handle *btf.Handle
 		if mapSpec.BTF != nil {
 			handle, err = loadBTF(btf.MapSpec(mapSpec.BTF))
-			if err != nil && !xerrors.Is(err, btf.ErrNotSupported) {
+			if err != nil && !errors.Is(err, btf.ErrNotSupported) {
 				return nil, err
 			}
 		}
 
 		m, err := newMapWithBTF(mapSpec, handle)
 		if err != nil {
-			return nil, xerrors.Errorf("map %s: %w", mapName, err)
+			return nil, fmt.Errorf("map %s: %w", mapName, err)
 		}
 		maps[mapName] = m
 	}
@@ -216,29 +217,29 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (col
 
 			m := maps[ins.Reference]
 			if m == nil {
-				return nil, xerrors.Errorf("program %s: missing map %s", progName, ins.Reference)
+				return nil, fmt.Errorf("program %s: missing map %s", progName, ins.Reference)
 			}
 
 			fd := m.FD()
 			if fd < 0 {
-				return nil, xerrors.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd)
+				return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd)
 			}
 			if err := ins.RewriteMapPtr(m.FD()); err != nil {
-				return nil, xerrors.Errorf("progam %s: map %s: %w", progName, ins.Reference, err)
+				return nil, fmt.Errorf("progam %s: map %s: %w", progName, ins.Reference, err)
 			}
 		}
 
 		var handle *btf.Handle
 		if progSpec.BTF != nil {
 			handle, err = loadBTF(btf.ProgramSpec(progSpec.BTF))
-			if err != nil && !xerrors.Is(err, btf.ErrNotSupported) {
+			if err != nil && !errors.Is(err, btf.ErrNotSupported) {
 				return nil, err
 			}
 		}
 
 		prog, err := newProgramWithBTF(progSpec, handle, opts.Programs)
 		if err != nil {
-			return nil, xerrors.Errorf("program %s: %w", progName, err)
+			return nil, fmt.Errorf("program %s: %w", progName, err)
 		}
 		progs[progName] = prog
 	}
diff --git a/elf_reader.go b/elf_reader.go
index b55957c..77acaed 100644
--- a/elf_reader.go
+++ b/elf_reader.go
@@ -4,6 +4,8 @@ import (
 	"bytes"
 	"debug/elf"
 	"encoding/binary"
+	"errors"
+	"fmt"
 	"io"
 	"math"
 	"os"
@@ -13,8 +15,6 @@ import (
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/btf"
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
 type elfCode struct {
@@ -35,7 +35,7 @@ func LoadCollectionSpec(file string) (*CollectionSpec, error) {
 
 	spec, err := LoadCollectionSpecFromReader(f)
 	if err != nil {
-		return nil, xerrors.Errorf("file %s: %w", file, err)
+		return nil, fmt.Errorf("file %s: %w", file, err)
 	}
 	return spec, nil
 }
@@ -50,7 +50,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 
 	symbols, err := f.Symbols()
 	if err != nil {
-		return nil, xerrors.Errorf("load symbols: %v", err)
+		return nil, fmt.Errorf("load symbols: %v", err)
 	}
 
 	ec := &elfCode{f, symbols, symbolsPerSection(symbols), "", 0}
@@ -79,13 +79,13 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 			dataSections[elf.SectionIndex(i)] = sec
 		case sec.Type == elf.SHT_REL:
 			if int(sec.Info) >= len(ec.Sections) {
-				return nil, xerrors.Errorf("found relocation section %v for missing section %v", i, sec.Info)
+				return nil, fmt.Errorf("found relocation section %v for missing section %v", i, sec.Info)
 			}
 
 			// Store relocations under the section index of the target
 			idx := elf.SectionIndex(sec.Info)
 			if relSections[idx] != nil {
-				return nil, xerrors.Errorf("section %d has multiple relocation sections", sec.Info)
+				return nil, fmt.Errorf("section %d has multiple relocation sections", sec.Info)
 			}
 			relSections[idx] = sec
 		case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0:
@@ -95,32 +95,32 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 
 	ec.license, err = loadLicense(licenseSection)
 	if err != nil {
-		return nil, xerrors.Errorf("load license: %w", err)
+		return nil, fmt.Errorf("load license: %w", err)
 	}
 
 	ec.version, err = loadVersion(versionSection, ec.ByteOrder)
 	if err != nil {
-		return nil, xerrors.Errorf("load version: %w", err)
+		return nil, fmt.Errorf("load version: %w", err)
 	}
 
 	btfSpec, err := btf.LoadSpecFromReader(rd)
 	if err != nil {
-		return nil, xerrors.Errorf("load BTF: %w", err)
+		return nil, fmt.Errorf("load BTF: %w", err)
 	}
 
 	relocations, referencedSections, err := ec.loadRelocations(relSections)
 	if err != nil {
-		return nil, xerrors.Errorf("load relocations: %w", err)
+		return nil, fmt.Errorf("load relocations: %w", err)
 	}
 
 	maps := make(map[string]*MapSpec)
 	if err := ec.loadMaps(maps, mapSections); err != nil {
-		return nil, xerrors.Errorf("load maps: %w", err)
+		return nil, fmt.Errorf("load maps: %w", err)
 	}
 
 	if len(btfMaps) > 0 {
 		if err := ec.loadBTFMaps(maps, btfMaps, btfSpec); err != nil {
-			return nil, xerrors.Errorf("load BTF maps: %w", err)
+			return nil, fmt.Errorf("load BTF maps: %w", err)
 		}
 	}
 
@@ -134,13 +134,13 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 		}
 
 		if err := ec.loadDataSections(maps, dataSections, btfSpec); err != nil {
-			return nil, xerrors.Errorf("load data sections: %w", err)
+			return nil, fmt.Errorf("load data sections: %w", err)
 		}
 	}
 
 	progs, err := ec.loadPrograms(progSections, relocations, btfSpec)
 	if err != nil {
-		return nil, xerrors.Errorf("load programs: %w", err)
+		return nil, fmt.Errorf("load programs: %w", err)
 	}
 
 	return &CollectionSpec{maps, progs}, nil
@@ -153,7 +153,7 @@ func loadLicense(sec *elf.Section) (string, error) {
 
 	data, err := sec.Data()
 	if err != nil {
-		return "", xerrors.Errorf("section %s: %v", sec.Name, err)
+		return "", fmt.Errorf("section %s: %v", sec.Name, err)
 	}
 	return string(bytes.TrimRight(data, "\000")), nil
 }
@@ -165,7 +165,7 @@ func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
 
 	var version uint32
 	if err := binary.Read(sec.Open(), bo, &version); err != nil {
-		return 0, xerrors.Errorf("section %s: %v", sec.Name, err)
+		return 0, fmt.Errorf("section %s: %v", sec.Name, err)
 	}
 	return version, nil
 }
@@ -179,17 +179,17 @@ func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section,
 	for idx, sec := range progSections {
 		syms := ec.symbolsPerSection[idx]
 		if len(syms) == 0 {
-			return nil, xerrors.Errorf("section %v: missing symbols", sec.Name)
+			return nil, fmt.Errorf("section %v: missing symbols", sec.Name)
 		}
 
 		funcSym, ok := syms[0]
 		if !ok {
-			return nil, xerrors.Errorf("section %v: no label at start", sec.Name)
+			return nil, fmt.Errorf("section %v: no label at start", sec.Name)
 		}
 
 		insns, length, err := ec.loadInstructions(sec, syms, relocations[idx])
 		if err != nil {
-			return nil, xerrors.Errorf("program %s: can't unmarshal instructions: %w", funcSym.Name, err)
+			return nil, fmt.Errorf("program %s: can't unmarshal instructions: %w", funcSym.Name, err)
 		}
 
 		progType, attachType, attachTo := getProgType(sec.Name)
@@ -207,8 +207,8 @@ func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section,
 
 		if btfSpec != nil {
 			spec.BTF, err = btfSpec.Program(sec.Name, length)
-			if err != nil && !xerrors.Is(err, btf.ErrNoExtendedInfo) {
-				return nil, xerrors.Errorf("program %s: %w", sec.Name, funcSym.Name, err)
+			if err != nil && !errors.Is(err, btf.ErrNoExtendedInfo) {
+				return nil, fmt.Errorf("program %s: %w", funcSym.Name, err)
 			}
 		}
 
@@ -226,7 +226,7 @@ func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section,
 	for _, prog := range progs {
 		err := link(prog, libs)
 		if err != nil {
-			return nil, xerrors.Errorf("program %s: %w", prog.Name, err)
+			return nil, fmt.Errorf("program %s: %w", prog.Name, err)
 		}
 		res[prog.Name] = prog
 	}
@@ -247,14 +247,14 @@ func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations m
 			return insns, offset, nil
 		}
 		if err != nil {
-			return nil, 0, xerrors.Errorf("offset %d: %w", offset, err)
+			return nil, 0, fmt.Errorf("offset %d: %w", offset, err)
 		}
 
 		ins.Symbol = symbols[offset].Name
 
 		if rel, ok := relocations[offset]; ok {
 			if err = ec.relocateInstruction(&ins, rel); err != nil {
-				return nil, 0, xerrors.Errorf("offset %d: can't relocate instruction: %w", offset, err)
+				return nil, 0, fmt.Errorf("offset %d: can't relocate instruction: %w", offset, err)
 			}
 		}
 
@@ -275,7 +275,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
 		// from the section itself.
 		idx := int(rel.Section)
 		if idx > len(ec.Sections) {
-			return xerrors.New("out-of-bounds section index")
+			return errors.New("out-of-bounds section index")
 		}
 
 		name = ec.Sections[idx].Name
@@ -295,7 +295,7 @@ outer:
 			// section. Weirdly, the offset of the real symbol in the
 			// section is encoded in the instruction stream.
 			if bind != elf.STB_LOCAL {
-				return xerrors.Errorf("direct load: %s: unsupported relocation %s", name, bind)
+				return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind)
 			}
 
 			// For some reason, clang encodes the offset of the symbol its
@@ -317,13 +317,13 @@ outer:
 
 		case elf.STT_OBJECT:
 			if bind != elf.STB_GLOBAL {
-				return xerrors.Errorf("load: %s: unsupported binding: %s", name, bind)
+				return fmt.Errorf("load: %s: unsupported binding: %s", name, bind)
 			}
 
 			ins.Src = asm.PseudoMapFD
 
 		default:
-			return xerrors.Errorf("load: %s: unsupported relocation: %s", name, typ)
+			return fmt.Errorf("load: %s: unsupported relocation: %s", name, typ)
 		}
 
 		// Mark the instruction as needing an update when creating the
@@ -334,18 +334,18 @@ outer:
 
 	case ins.OpCode.JumpOp() == asm.Call:
 		if ins.Src != asm.PseudoCall {
-			return xerrors.Errorf("call: %s: incorrect source register", name)
+			return fmt.Errorf("call: %s: incorrect source register", name)
 		}
 
 		switch typ {
 		case elf.STT_NOTYPE, elf.STT_FUNC:
 			if bind != elf.STB_GLOBAL {
-				return xerrors.Errorf("call: %s: unsupported binding: %s", name, bind)
+				return fmt.Errorf("call: %s: unsupported binding: %s", name, bind)
 			}
 
 		case elf.STT_SECTION:
 			if bind != elf.STB_LOCAL {
-				return xerrors.Errorf("call: %s: unsupported binding: %s", name, bind)
+				return fmt.Errorf("call: %s: unsupported binding: %s", name, bind)
 			}
 
 			// The function we want to call is in the indicated section,
@@ -354,23 +354,23 @@ outer:
 			// A value of -1 references the first instruction in the section.
 			offset := int64(int32(ins.Constant)+1) * asm.InstructionSize
 			if offset < 0 {
-				return xerrors.Errorf("call: %s: invalid offset %d", name, offset)
+				return fmt.Errorf("call: %s: invalid offset %d", name, offset)
 			}
 
 			sym, ok := ec.symbolsPerSection[rel.Section][uint64(offset)]
 			if !ok {
-				return xerrors.Errorf("call: %s: no symbol at offset %d", name, offset)
+				return fmt.Errorf("call: %s: no symbol at offset %d", name, offset)
 			}
 
 			ins.Constant = -1
 			name = sym.Name
 
 		default:
-			return xerrors.Errorf("call: %s: invalid symbol type %s", name, typ)
+			return fmt.Errorf("call: %s: invalid symbol type %s", name, typ)
 		}
 
 	default:
-		return xerrors.Errorf("relocation for unsupported instruction: %s", ins.OpCode)
+		return fmt.Errorf("relocation for unsupported instruction: %s", ins.OpCode)
 	}
 
 	ins.Reference = name
@@ -381,11 +381,11 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
 	for idx, sec := range mapSections {
 		syms := ec.symbolsPerSection[idx]
 		if len(syms) == 0 {
-			return xerrors.Errorf("section %v: no symbols", sec.Name)
+			return fmt.Errorf("section %v: no symbols", sec.Name)
 		}
 
 		if sec.Size%uint64(len(syms)) != 0 {
-			return xerrors.Errorf("section %v: map descriptors are not of equal size", sec.Name)
+			return fmt.Errorf("section %v: map descriptors are not of equal size", sec.Name)
 		}
 
 		var (
@@ -395,11 +395,11 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
 		for i, offset := 0, uint64(0); i < len(syms); i, offset = i+1, offset+size {
 			mapSym, ok := syms[offset]
 			if !ok {
-				return xerrors.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
+				return fmt.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
 			}
 
 			if maps[mapSym.Name] != nil {
-				return xerrors.Errorf("section %v: map %v already exists", sec.Name, mapSym)
+				return fmt.Errorf("section %v: map %v already exists", sec.Name, mapSym)
 			}
 
 			lr := io.LimitReader(r, int64(size))
@@ -409,19 +409,19 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
 			}
 			switch {
 			case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil:
-				return xerrors.Errorf("map %v: missing type", mapSym)
+				return fmt.Errorf("map %v: missing type", mapSym)
 			case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil:
-				return xerrors.Errorf("map %v: missing key size", mapSym)
+				return fmt.Errorf("map %v: missing key size", mapSym)
 			case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil:
-				return xerrors.Errorf("map %v: missing value size", mapSym)
+				return fmt.Errorf("map %v: missing value size", mapSym)
 			case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil:
-				return xerrors.Errorf("map %v: missing max entries", mapSym)
+				return fmt.Errorf("map %v: missing max entries", mapSym)
 			case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil:
-				return xerrors.Errorf("map %v: missing flags", mapSym)
+				return fmt.Errorf("map %v: missing flags", mapSym)
 			}
 
 			if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil {
-				return xerrors.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
+				return fmt.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
 			}
 
 			maps[mapSym.Name] = &spec
@@ -433,24 +433,24 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
 
 func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec, mapSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error {
 	if spec == nil {
-		return xerrors.Errorf("missing BTF")
+		return fmt.Errorf("missing BTF")
 	}
 
 	for idx, sec := range mapSections {
 		syms := ec.symbolsPerSection[idx]
 		if len(syms) == 0 {
-			return xerrors.Errorf("section %v: no symbols", sec.Name)
+			return fmt.Errorf("section %v: no symbols", sec.Name)
 		}
 
 		for _, sym := range syms {
 			name := sym.Name
 			if maps[name] != nil {
-				return xerrors.Errorf("section %v: map %v already exists", sec.Name, sym)
+				return fmt.Errorf("section %v: map %v already exists", sec.Name, sym)
 			}
 
 			mapSpec, err := mapSpecFromBTF(spec, name)
 			if err != nil {
-				return xerrors.Errorf("map %v: %w", name, err)
+				return fmt.Errorf("map %v: %w", name, err)
 			}
 
 			maps[name] = mapSpec
@@ -463,20 +463,20 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec, mapSections map[elf.Sec
 func mapSpecFromBTF(spec *btf.Spec, name string) (*MapSpec, error) {
 	btfMap, btfMapMembers, err := spec.Map(name)
 	if err != nil {
-		return nil, xerrors.Errorf("can't get BTF: %w", err)
+		return nil, fmt.Errorf("can't get BTF: %w", err)
 	}
 
 	keyType := btf.MapKey(btfMap)
 	size, err := btf.Sizeof(keyType)
 	if err != nil {
-		return nil, xerrors.Errorf("can't get size of BTF key: %w", err)
+		return nil, fmt.Errorf("can't get size of BTF key: %w", err)
 	}
 	keySize := uint32(size)
 
 	valueType := btf.MapValue(btfMap)
 	size, err = btf.Sizeof(valueType)
 	if err != nil {
-		return nil, xerrors.Errorf("can't get size of BTF value: %w", err)
+		return nil, fmt.Errorf("can't get size of BTF value: %w", err)
 	}
 	valueSize := uint32(size)
 
@@ -488,54 +488,54 @@ func mapSpecFromBTF(spec *btf.Spec, name string) (*MapSpec, error) {
 		case "type":
 			mapType, err = uintFromBTF(member.Type)
 			if err != nil {
-				return nil, xerrors.Errorf("can't get type: %w", err)
+				return nil, fmt.Errorf("can't get type: %w", err)
 			}
 
 		case "map_flags":
 			flags, err = uintFromBTF(member.Type)
 			if err != nil {
-				return nil, xerrors.Errorf("can't get BTF map flags: %w", err)
+				return nil, fmt.Errorf("can't get BTF map flags: %w", err)
 			}
 
 		case "max_entries":
 			maxEntries, err = uintFromBTF(member.Type)
 			if err != nil {
-				return nil, xerrors.Errorf("can't get BTF map max entries: %w", err)
+				return nil, fmt.Errorf("can't get BTF map max entries: %w", err)
 			}
 
 		case "key_size":
 			if _, isVoid := keyType.(*btf.Void); !isVoid {
-				return nil, xerrors.New("both key and key_size given")
+				return nil, errors.New("both key and key_size given")
 			}
 
 			keySize, err = uintFromBTF(member.Type)
 			if err != nil {
-				return nil, xerrors.Errorf("can't get BTF key size: %w", err)
+				return nil, fmt.Errorf("can't get BTF key size: %w", err)
 			}
 
 		case "value_size":
 			if _, isVoid := valueType.(*btf.Void); !isVoid {
-				return nil, xerrors.New("both value and value_size given")
+				return nil, errors.New("both value and value_size given")
 			}
 
 			valueSize, err = uintFromBTF(member.Type)
 			if err != nil {
-				return nil, xerrors.Errorf("can't get BTF value size: %w", err)
+				return nil, fmt.Errorf("can't get BTF value size: %w", err)
 			}
 
 		case "pinning":
 			pinning, err := uintFromBTF(member.Type)
 			if err != nil {
-				return nil, xerrors.Errorf("can't get pinning: %w", err)
+				return nil, fmt.Errorf("can't get pinning: %w", err)
 			}
 
 			if pinning != 0 {
-				return nil, xerrors.Errorf("'pinning' attribute not supported: %w", ErrNotSupported)
+				return nil, fmt.Errorf("'pinning' attribute not supported: %w", ErrNotSupported)
 			}
 
 		case "key", "value":
 		default:
-			return nil, xerrors.Errorf("unrecognized field %s in BTF map definition", member.Name)
+			return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name)
 		}
 	}
 
@@ -554,12 +554,12 @@ func mapSpecFromBTF(spec *btf.Spec, name string) (*MapSpec, error) {
 func uintFromBTF(typ btf.Type) (uint32, error) {
 	ptr, ok := typ.(*btf.Pointer)
 	if !ok {
-		return 0, xerrors.Errorf("not a pointer: %v", typ)
+		return 0, fmt.Errorf("not a pointer: %v", typ)
 	}
 
 	arr, ok := ptr.Target.(*btf.Array)
 	if !ok {
-		return 0, xerrors.Errorf("not a pointer to array: %v", typ)
+		return 0, fmt.Errorf("not a pointer to array: %v", typ)
 	}
 
 	return arr.Nelems, nil
@@ -567,7 +567,7 @@ func uintFromBTF(typ btf.Type) (uint32, error) {
 
 func (ec *elfCode) loadDataSections(maps map[string]*MapSpec, dataSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error {
 	if spec == nil {
-		return xerrors.New("data sections require BTF, make sure all consts are marked as static")
+		return errors.New("data sections require BTF, make sure all consts are marked as static")
 	}
 
 	for _, sec := range dataSections {
@@ -578,11 +578,11 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec, dataSections map[e
 
 		data, err := sec.Data()
 		if err != nil {
-			return xerrors.Errorf("data section %s: can't get contents: %w", sec.Name, err)
+			return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
 		}
 
 		if uint64(len(data)) > math.MaxUint32 {
-			return xerrors.Errorf("data section %s: contents exceed maximum size", sec.Name)
+			return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
 		}
 
 		mapSpec := &MapSpec{
@@ -681,7 +681,7 @@ func (ec *elfCode) loadRelocations(sections map[elf.SectionIndex]*elf.Section) (
 		rels := make(map[uint64]elf.Symbol)
 
 		if sec.Entsize < 16 {
-			return nil, nil, xerrors.Errorf("section %s: relocations are less than 16 bytes", sec.Name)
+			return nil, nil, fmt.Errorf("section %s: relocations are less than 16 bytes", sec.Name)
 		}
 
 		r := sec.Open()
@@ -690,12 +690,12 @@ func (ec *elfCode) loadRelocations(sections map[elf.SectionIndex]*elf.Section) (
 
 			var rel elf.Rel64
 			if binary.Read(ent, ec.ByteOrder, &rel) != nil {
-				return nil, nil, xerrors.Errorf("can't parse relocation at offset %v", off)
+				return nil, nil, fmt.Errorf("can't parse relocation at offset %v", off)
 			}
 
 			symNo := int(elf.R_SYM64(rel.Info) - 1)
 			if symNo >= len(ec.symbols) {
-				return nil, nil, xerrors.Errorf("relocation at offset %d: symbol %v doesnt exist", off, symNo)
+				return nil, nil, fmt.Errorf("relocation at offset %d: symbol %v doesnt exist", off, symNo)
 			}
 
 			symbol := ec.symbols[symNo]
diff --git a/go.mod b/go.mod
index 1d3420b..a05cf85 100644
--- a/go.mod
+++ b/go.mod
@@ -1,8 +1,5 @@
 module github.com/cilium/ebpf
 
-go 1.12
+go 1.13
 
-require (
-	golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9
-	golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
-)
+require golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9
diff --git a/go.sum b/go.sum
index c4e24f5..e8b6241 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,2 @@
-golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU=
-golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/internal/btf/btf.go b/internal/btf/btf.go
index 64174e1..3dd000a 100644
--- a/internal/btf/btf.go
+++ b/internal/btf/btf.go
@@ -4,6 +4,8 @@ import (
 	"bytes"
 	"debug/elf"
 	"encoding/binary"
+	"errors"
+	"fmt"
 	"io"
 	"io/ioutil"
 	"math"
@@ -14,8 +16,6 @@ import (
 
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
 const btfMagic = 0xeB9F
@@ -23,8 +23,8 @@ const btfMagic = 0xeB9F
 // Errors returned by BTF functions.
 var (
 	ErrNotSupported   = internal.ErrNotSupported
-	ErrNotFound       = xerrors.New("not found")
-	ErrNoExtendedInfo = xerrors.New("no extended info")
+	ErrNotFound       = errors.New("not found")
+	ErrNoExtendedInfo = errors.New("no extended info")
 )
 
 // Spec represents decoded BTF.
@@ -77,7 +77,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
 			}
 
 			if sec.Size > math.MaxUint32 {
-				return nil, xerrors.Errorf("section %s exceeds maximum size", sec.Name)
+				return nil, fmt.Errorf("section %s exceeds maximum size", sec.Name)
 			}
 
 			sectionSizes[sec.Name] = uint32(sec.Size)
@@ -90,7 +90,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
 
 	symbols, err := file.Symbols()
 	if err != nil {
-		return nil, xerrors.Errorf("can't read symbols: %v", err)
+		return nil, fmt.Errorf("can't read symbols: %v", err)
 	}
 
 	variableOffsets := make(map[variable]uint32)
@@ -106,7 +106,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
 		}
 
 		if symbol.Value > math.MaxUint32 {
-			return nil, xerrors.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name)
+			return nil, fmt.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name)
 		}
 
 		variableOffsets[variable{secName, symbol.Name}] = uint32(symbol.Value)
@@ -123,7 +123,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
 
 	spec.funcInfos, spec.lineInfos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings)
 	if err != nil {
-		return nil, xerrors.Errorf("can't read ext info: %w", err)
+		return nil, fmt.Errorf("can't read ext info: %w", err)
 	}
 
 	return spec, nil
@@ -178,10 +178,10 @@ func LoadKernelSpec() (*Spec, error) {
 func loadKernelSpec() (*Spec, error) {
 	fh, err := os.Open("/sys/kernel/btf/vmlinux")
 	if os.IsNotExist(err) {
-		return nil, xerrors.Errorf("can't open kernel BTF at /sys/kernel/btf/vmlinux: %w", ErrNotFound)
+		return nil, fmt.Errorf("can't open kernel BTF at /sys/kernel/btf/vmlinux: %w", ErrNotFound)
 	}
 	if err != nil {
-		return nil, xerrors.Errorf("can't read kernel BTF: %s", err)
+		return nil, fmt.Errorf("can't read kernel BTF: %s", err)
 	}
 	defer fh.Close()
 
@@ -191,53 +191,53 @@ func loadKernelSpec() (*Spec, error) {
 func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) ([]rawType, stringTable, error) {
 	rawBTF, err := ioutil.ReadAll(btf)
 	if err != nil {
-		return nil, nil, xerrors.Errorf("can't read BTF: %v", err)
+		return nil, nil, fmt.Errorf("can't read BTF: %v", err)
 	}
 
 	rd := bytes.NewReader(rawBTF)
 
 	var header btfHeader
 	if err := binary.Read(rd, bo, &header); err != nil {
-		return nil, nil, xerrors.Errorf("can't read header: %v", err)
+		return nil, nil, fmt.Errorf("can't read header: %v", err)
 	}
 
 	if header.Magic != btfMagic {
-		return nil, nil, xerrors.Errorf("incorrect magic value %v", header.Magic)
+		return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic)
 	}
 
 	if header.Version != 1 {
-		return nil, nil, xerrors.Errorf("unexpected version %v", header.Version)
+		return nil, nil, fmt.Errorf("unexpected version %v", header.Version)
 	}
 
 	if header.Flags != 0 {
-		return nil, nil, xerrors.Errorf("unsupported flags %v", header.Flags)
+		return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags)
 	}
 
 	remainder := int64(header.HdrLen) - int64(binary.Size(&header))
 	if remainder < 0 {
-		return nil, nil, xerrors.New("header is too short")
+		return nil, nil, errors.New("header is too short")
 	}
 
 	if _, err := io.CopyN(internal.DiscardZeroes{}, rd, remainder); err != nil {
-		return nil, nil, xerrors.Errorf("header padding: %v", err)
+		return nil, nil, fmt.Errorf("header padding: %v", err)
 	}
 
 	if _, err := rd.Seek(int64(header.HdrLen+header.StringOff), io.SeekStart); err != nil {
-		return nil, nil, xerrors.Errorf("can't seek to start of string section: %v", err)
+		return nil, nil, fmt.Errorf("can't seek to start of string section: %v", err)
 	}
 
 	rawStrings, err := readStringTable(io.LimitReader(rd, int64(header.StringLen)))
 	if err != nil {
-		return nil, nil, xerrors.Errorf("can't read type names: %w", err)
+		return nil, nil, fmt.Errorf("can't read type names: %w", err)
 	}
 
 	if _, err := rd.Seek(int64(header.HdrLen+header.TypeOff), io.SeekStart); err != nil {
-		return nil, nil, xerrors.Errorf("can't seek to start of type section: %v", err)
+		return nil, nil, fmt.Errorf("can't seek to start of type section: %v", err)
 	}
 
 	rawTypes, err := readTypes(io.LimitReader(rd, int64(header.TypeLen)), bo)
 	if err != nil {
-		return nil, nil, xerrors.Errorf("can't read types: %w", err)
+		return nil, nil, fmt.Errorf("can't read types: %w", err)
 	}
 
 	return rawTypes, rawStrings, nil
@@ -260,12 +260,12 @@ func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[s
 		}
 
 		if name == ".kconfig" || name == ".ksym" {
-			return xerrors.Errorf("reference to %s: %w", name, ErrNotSupported)
+			return fmt.Errorf("reference to %s: %w", name, ErrNotSupported)
 		}
 
 		size, ok := sectionSizes[name]
 		if !ok {
-			return xerrors.Errorf("data section %s: missing size", name)
+			return fmt.Errorf("data section %s: missing size", name)
 		}
 
 		rawTypes[i].SizeType = size
@@ -274,17 +274,17 @@ func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[s
 		for j, secInfo := range secinfos {
 			id := int(secInfo.Type - 1)
 			if id >= len(rawTypes) {
-				return xerrors.Errorf("data section %s: invalid type id %d for variable %d", name, id, j)
+				return fmt.Errorf("data section %s: invalid type id %d for variable %d", name, id, j)
 			}
 
 			varName, err := rawStrings.Lookup(rawTypes[id].NameOff)
 			if err != nil {
-				return xerrors.Errorf("data section %s: can't get name for type %d: %w", name, id, err)
+				return fmt.Errorf("data section %s: can't get name for type %d: %w", name, id, err)
 			}
 
 			offset, ok := variableOffsets[variable{name, varName}]
 			if !ok {
-				return xerrors.Errorf("data section %s: missing offset for variable %s", name, varName)
+				return fmt.Errorf("data section %s: missing offset for variable %s", name, varName)
 			}
 
 			secinfos[j].Offset = offset
@@ -318,7 +318,7 @@ func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
 		}
 
 		if err := raw.Marshal(&buf, opts.ByteOrder); err != nil {
-			return nil, xerrors.Errorf("can't marshal BTF: %w", err)
+			return nil, fmt.Errorf("can't marshal BTF: %w", err)
 		}
 	}
 
@@ -342,7 +342,7 @@ func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
 	raw := buf.Bytes()
 	err := binary.Write(sliceWriter(raw[:headerLen]), opts.ByteOrder, header)
 	if err != nil {
-		return nil, xerrors.Errorf("can't write header: %v", err)
+		return nil, fmt.Errorf("can't write header: %v", err)
 	}
 
 	return raw, nil
@@ -352,7 +352,7 @@ type sliceWriter []byte
 
 func (sw sliceWriter) Write(p []byte) (int, error) {
 	if len(p) != len(sw) {
-		return 0, xerrors.New("size doesn't match")
+		return 0, errors.New("size doesn't match")
 	}
 
 	return copy(sw, p), nil
@@ -366,18 +366,18 @@ func (sw sliceWriter) Write(p []byte) (int, error) {
 // contain extended BTF info.
 func (s *Spec) Program(name string, length uint64) (*Program, error) {
 	if length == 0 {
-		return nil, xerrors.New("length musn't be zero")
+		return nil, errors.New("length musn't be zero")
 	}
 
 	if s.funcInfos == nil && s.lineInfos == nil {
-		return nil, xerrors.Errorf("BTF for section %s: %w", name, ErrNoExtendedInfo)
+		return nil, fmt.Errorf("BTF for section %s: %w", name, ErrNoExtendedInfo)
 	}
 
 	funcInfos, funcOK := s.funcInfos[name]
 	lineInfos, lineOK := s.lineInfos[name]
 
 	if !funcOK && !lineOK {
-		return nil, xerrors.Errorf("no extended BTF info for section %s", name)
+		return nil, fmt.Errorf("no extended BTF info for section %s", name)
 	}
 
 	return &Program{s, length, funcInfos, lineInfos}, nil
@@ -394,7 +394,7 @@ func (s *Spec) Map(name string) (*Map, []Member, error) {
 
 	mapStruct, ok := mapVar.Type.(*Struct)
 	if !ok {
-		return nil, nil, xerrors.Errorf("expected struct, have %s", mapVar.Type)
+		return nil, nil, fmt.Errorf("expected struct, have %s", mapVar.Type)
 	}
 
 	var key, value Type
@@ -423,7 +423,7 @@ func (s *Spec) Map(name string) (*Map, []Member, error) {
 func (s *Spec) Datasec(name string) (*Map, error) {
 	var datasec Datasec
 	if err := s.FindType(name, &datasec); err != nil {
-		return nil, xerrors.Errorf("data section %s: can't get BTF: %w", name, err)
+		return nil, fmt.Errorf("data section %s: can't get BTF: %w", name, err)
 	}
 
 	return &Map{s, &Void{}, &datasec}, nil
@@ -447,14 +447,14 @@ func (s *Spec) FindType(name string, typ Type) error {
 		}
 
 		if candidate != nil {
-			return xerrors.Errorf("type %s: multiple candidates for %T", name, typ)
+			return fmt.Errorf("type %s: multiple candidates for %T", name, typ)
 		}
 
 		candidate = typ
 	}
 
 	if candidate == nil {
-		return xerrors.Errorf("type %s: %w", name, ErrNotFound)
+		return fmt.Errorf("type %s: %w", name, ErrNotFound)
 	}
 
 	value := reflect.Indirect(reflect.ValueOf(copyType(candidate)))
@@ -476,7 +476,7 @@ func NewHandle(spec *Spec) (*Handle, error) {
 	}
 
 	if spec.byteOrder != internal.NativeEndian {
-		return nil, xerrors.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian)
+		return nil, fmt.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian)
 	}
 
 	btf, err := spec.marshal(marshalOpts{
@@ -484,11 +484,11 @@ func NewHandle(spec *Spec) (*Handle, error) {
 		StripFuncLinkage: haveFuncLinkage() != nil,
 	})
 	if err != nil {
-		return nil, xerrors.Errorf("can't marshal BTF: %w", err)
+		return nil, fmt.Errorf("can't marshal BTF: %w", err)
 	}
 
 	if uint64(len(btf)) > math.MaxUint32 {
-		return nil, xerrors.New("BTF exceeds the maximum size")
+		return nil, errors.New("BTF exceeds the maximum size")
 	}
 
 	attr := &bpfLoadBTFAttr{
@@ -572,12 +572,12 @@ func ProgramSpec(s *Program) *Spec {
 func ProgramAppend(s, other *Program) error {
 	funcInfos, err := s.funcInfos.append(other.funcInfos, s.length)
 	if err != nil {
-		return xerrors.Errorf("func infos: %w", err)
+		return fmt.Errorf("func infos: %w", err)
 	}
 
 	lineInfos, err := s.lineInfos.append(other.lineInfos, s.length)
 	if err != nil {
-		return xerrors.Errorf("line infos: %w", err)
+		return fmt.Errorf("line infos: %w", err)
 	}
 
 	s.length += other.length
@@ -682,7 +682,7 @@ var haveBTF = internal.FeatureTest("BTF", "5.1", func() (bool, error) {
 	}
 	// Check for EINVAL specifically, rather than err != nil since we
 	// otherwise misdetect due to insufficient permissions.
-	return !xerrors.Is(err, unix.EINVAL), nil
+	return !errors.Is(err, unix.EINVAL), nil
 })
 
 var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() (bool, error) {
@@ -712,5 +712,5 @@ var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() (bo
 
 	// Check for EINVAL specifically, rather than err != nil since we
 	// otherwise misdetect due to insufficient permissions.
-	return !xerrors.Is(err, unix.EINVAL), nil
+	return !errors.Is(err, unix.EINVAL), nil
 })
diff --git a/internal/btf/btf_types.go b/internal/btf/btf_types.go
index ace2187..e34a87e 100644
--- a/internal/btf/btf_types.go
+++ b/internal/btf/btf_types.go
@@ -4,8 +4,6 @@ import (
 	"encoding/binary"
 	"fmt"
 	"io"
-
-	"golang.org/x/xerrors"
 )
 
 // btfKind describes a Type.
@@ -215,7 +213,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
 		if err := binary.Read(r, bo, &header); err == io.EOF {
 			return types, nil
 		} else if err != nil {
-			return nil, xerrors.Errorf("can't read type info for id %v: %v", id, err)
+			return nil, fmt.Errorf("can't read type info for id %v: %v", id, err)
 		}
 
 		var data interface{}
@@ -244,7 +242,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
 		case kindDatasec:
 			data = make([]btfVarSecinfo, header.Vlen())
 		default:
-			return nil, xerrors.Errorf("type id %v: unknown kind: %v", id, header.Kind())
+			return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind())
 		}
 
 		if data == nil {
@@ -253,7 +251,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
 		}
 
 		if err := binary.Read(r, bo, data); err != nil {
-			return nil, xerrors.Errorf("type id %d: kind %v: can't read %T: %v", id, header.Kind(), data, err)
+			return nil, fmt.Errorf("type id %d: kind %v: can't read %T: %v", id, header.Kind(), data, err)
 		}
 
 		types = append(types, rawType{header, data})
diff --git a/internal/btf/ext_info.go b/internal/btf/ext_info.go
index 1b1e33c..28918ae 100644
--- a/internal/btf/ext_info.go
+++ b/internal/btf/ext_info.go
@@ -3,13 +3,13 @@ package btf
 import (
 	"bytes"
 	"encoding/binary"
+	"errors"
+	"fmt"
 	"io"
 	"io/ioutil"
 
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/internal"
-
-	"golang.org/x/xerrors"
 )
 
 type btfExtHeader struct {
@@ -27,49 +27,49 @@ type btfExtHeader struct {
 func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, err error) {
 	var header btfExtHeader
 	if err := binary.Read(r, bo, &header); err != nil {
-		return nil, nil, xerrors.Errorf("can't read header: %v", err)
+		return nil, nil, fmt.Errorf("can't read header: %v", err)
 	}
 
 	if header.Magic != btfMagic {
-		return nil, nil, xerrors.Errorf("incorrect magic value %v", header.Magic)
+		return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic)
 	}
 
 	if header.Version != 1 {
-		return nil, nil, xerrors.Errorf("unexpected version %v", header.Version)
+		return nil, nil, fmt.Errorf("unexpected version %v", header.Version)
 	}
 
 	if header.Flags != 0 {
-		return nil, nil, xerrors.Errorf("unsupported flags %v", header.Flags)
+		return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags)
 	}
 
 	remainder := int64(header.HdrLen) - int64(binary.Size(&header))
 	if remainder < 0 {
-		return nil, nil, xerrors.New("header is too short")
+		return nil, nil, errors.New("header is too short")
 	}
 
 	// Of course, the .BTF.ext header has different semantics than the
 	// .BTF ext header. We need to ignore non-null values.
 	_, err = io.CopyN(ioutil.Discard, r, remainder)
 	if err != nil {
-		return nil, nil, xerrors.Errorf("header padding: %v", err)
+		return nil, nil, fmt.Errorf("header padding: %v", err)
 	}
 
 	if _, err := r.Seek(int64(header.HdrLen+header.FuncInfoOff), io.SeekStart); err != nil {
-		return nil, nil, xerrors.Errorf("can't seek to function info section: %v", err)
+		return nil, nil, fmt.Errorf("can't seek to function info section: %v", err)
 	}
 
 	funcInfo, err = parseExtInfo(io.LimitReader(r, int64(header.FuncInfoLen)), bo, strings)
 	if err != nil {
-		return nil, nil, xerrors.Errorf("function info: %w", err)
+		return nil, nil, fmt.Errorf("function info: %w", err)
 	}
 
 	if _, err := r.Seek(int64(header.HdrLen+header.LineInfoOff), io.SeekStart); err != nil {
-		return nil, nil, xerrors.Errorf("can't seek to line info section: %v", err)
+		return nil, nil, fmt.Errorf("can't seek to line info section: %v", err)
 	}
 
 	lineInfo, err = parseExtInfo(io.LimitReader(r, int64(header.LineInfoLen)), bo, strings)
 	if err != nil {
-		return nil, nil, xerrors.Errorf("line info: %w", err)
+		return nil, nil, fmt.Errorf("line info: %w", err)
 	}
 
 	return funcInfo, lineInfo, nil
@@ -92,7 +92,7 @@ type extInfo struct {
 
 func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) {
 	if other.recordSize != ei.recordSize {
-		return extInfo{}, xerrors.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize)
+		return extInfo{}, fmt.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize)
 	}
 
 	records := make([]extInfoRecord, 0, len(ei.records)+len(other.records))
@@ -117,7 +117,7 @@ func (ei extInfo) MarshalBinary() ([]byte, error) {
 		// while the ELF tracks it in bytes.
 		insnOff := uint32(info.InsnOff / asm.InstructionSize)
 		if err := binary.Write(buf, internal.NativeEndian, insnOff); err != nil {
-			return nil, xerrors.Errorf("can't write instruction offset: %v", err)
+			return nil, fmt.Errorf("can't write instruction offset: %v", err)
 		}
 
 		buf.Write(info.Opaque)
@@ -129,12 +129,12 @@ func (ei extInfo) MarshalBinary() ([]byte, error) {
 func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]extInfo, error) {
 	var recordSize uint32
 	if err := binary.Read(r, bo, &recordSize); err != nil {
-		return nil, xerrors.Errorf("can't read record size: %v", err)
+		return nil, fmt.Errorf("can't read record size: %v", err)
 	}
 
 	if recordSize < 4 {
 		// Need at least insnOff
-		return nil, xerrors.New("record size too short")
+		return nil, errors.New("record size too short")
 	}
 
 	result := make(map[string]extInfo)
@@ -143,32 +143,32 @@ func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[st
 		if err := binary.Read(r, bo, &infoHeader); err == io.EOF {
 			return result, nil
 		} else if err != nil {
-			return nil, xerrors.Errorf("can't read ext info header: %v", err)
+			return nil, fmt.Errorf("can't read ext info header: %v", err)
 		}
 
 		secName, err := strings.Lookup(infoHeader.SecNameOff)
 		if err != nil {
-			return nil, xerrors.Errorf("can't get section name: %w", err)
+			return nil, fmt.Errorf("can't get section name: %w", err)
 		}
 
 		if infoHeader.NumInfo == 0 {
-			return nil, xerrors.Errorf("section %s has invalid number of records", secName)
+			return nil, fmt.Errorf("section %s has invalid number of records", secName)
 		}
 
 		var records []extInfoRecord
 		for i := uint32(0); i < infoHeader.NumInfo; i++ {
 			var byteOff uint32
 			if err := binary.Read(r, bo, &byteOff); err != nil {
-				return nil, xerrors.Errorf("section %v: can't read extended info offset: %v", secName, err)
+				return nil, fmt.Errorf("section %v: can't read extended info offset: %v", secName, err)
 			}
 
 			buf := make([]byte, int(recordSize-4))
 			if _, err := io.ReadFull(r, buf); err != nil {
-				return nil, xerrors.Errorf("section %v: can't read record: %v", secName, err)
+				return nil, fmt.Errorf("section %v: can't read record: %v", secName, err)
 			}
 
 			if byteOff%asm.InstructionSize != 0 {
-				return nil, xerrors.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff)
+				return nil, fmt.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff)
 			}
 
 			records = append(records, extInfoRecord{uint64(byteOff), buf})
diff --git a/internal/btf/strings.go b/internal/btf/strings.go
index a5f905f..8782643 100644
--- a/internal/btf/strings.go
+++ b/internal/btf/strings.go
@@ -2,10 +2,10 @@ package btf
 
 import (
 	"bytes"
+	"errors"
+	"fmt"
 	"io"
 	"io/ioutil"
-
-	"golang.org/x/xerrors"
 )
 
 type stringTable []byte
@@ -13,19 +13,19 @@ type stringTable []byte
 func readStringTable(r io.Reader) (stringTable, error) {
 	contents, err := ioutil.ReadAll(r)
 	if err != nil {
-		return nil, xerrors.Errorf("can't read string table: %v", err)
+		return nil, fmt.Errorf("can't read string table: %v", err)
 	}
 
 	if len(contents) < 1 {
-		return nil, xerrors.New("string table is empty")
+		return nil, errors.New("string table is empty")
 	}
 
 	if contents[0] != '\x00' {
-		return nil, xerrors.New("first item in string table is non-empty")
+		return nil, errors.New("first item in string table is non-empty")
 	}
 
 	if contents[len(contents)-1] != '\x00' {
-		return nil, xerrors.New("string table isn't null terminated")
+		return nil, errors.New("string table isn't null terminated")
 	}
 
 	return stringTable(contents), nil
@@ -33,22 +33,22 @@ func readStringTable(r io.Reader) (stringTable, error) {
 
 func (st stringTable) Lookup(offset uint32) (string, error) {
 	if int64(offset) > int64(^uint(0)>>1) {
-		return "", xerrors.Errorf("offset %d overflows int", offset)
+		return "", fmt.Errorf("offset %d overflows int", offset)
 	}
 
 	pos := int(offset)
 	if pos >= len(st) {
-		return "", xerrors.Errorf("offset %d is out of bounds", offset)
+		return "", fmt.Errorf("offset %d is out of bounds", offset)
 	}
 
 	if pos > 0 && st[pos-1] != '\x00' {
-		return "", xerrors.Errorf("offset %d isn't start of a string", offset)
+		return "", fmt.Errorf("offset %d isn't start of a string", offset)
 	}
 
 	str := st[pos:]
 	end := bytes.IndexByte(str, '\x00')
 	if end == -1 {
-		return "", xerrors.Errorf("offset %d isn't null terminated", offset)
+		return "", fmt.Errorf("offset %d isn't null terminated", offset)
 	}
 
 	return string(str[:end]), nil
diff --git a/internal/btf/types.go b/internal/btf/types.go
index 18048f7..264142a 100644
--- a/internal/btf/types.go
+++ b/internal/btf/types.go
@@ -1,9 +1,9 @@
 package btf
 
 import (
+	"errors"
+	"fmt"
 	"math"
-
-	"golang.org/x/xerrors"
 )
 
 const maxTypeDepth = 32
@@ -311,7 +311,7 @@ func Sizeof(typ Type) (int, error) {
 		switch v := typ.(type) {
 		case *Array:
 			if n > 0 && int64(v.Nelems) > math.MaxInt64/n {
-				return 0, xerrors.New("overflow")
+				return 0, errors.New("overflow")
 			}
 
 			// Arrays may be of zero length, which allows
@@ -337,22 +337,22 @@ func Sizeof(typ Type) (int, error) {
 			continue
 
 		default:
-			return 0, xerrors.Errorf("unrecognized type %T", typ)
+			return 0, fmt.Errorf("unrecognized type %T", typ)
 		}
 
 		if n > 0 && elem > math.MaxInt64/n {
-			return 0, xerrors.New("overflow")
+			return 0, errors.New("overflow")
 		}
 
 		size := n * elem
 		if int64(int(size)) != size {
-			return 0, xerrors.New("overflow")
+			return 0, errors.New("overflow")
 		}
 
 		return int(size), nil
 	}
 
-	return 0, xerrors.New("exceeded type depth")
+	return 0, errors.New("exceeded type depth")
 }
 
 // copy a Type recursively.
@@ -434,7 +434,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
 		for i, btfMember := range raw {
 			name, err := rawStrings.LookupName(btfMember.NameOff)
 			if err != nil {
-				return nil, xerrors.Errorf("can't get name for member %d: %w", i, err)
+				return nil, fmt.Errorf("can't get name for member %d: %w", i, err)
 			}
 			members = append(members, Member{
 				Name:   name,
@@ -461,7 +461,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
 
 		name, err := rawStrings.LookupName(raw.NameOff)
 		if err != nil {
-			return nil, xerrors.Errorf("can't get name for type id %d: %w", id, err)
+			return nil, fmt.Errorf("can't get name for type id %d: %w", id, err)
 		}
 
 		switch raw.Kind() {
@@ -485,14 +485,14 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
 		case kindStruct:
 			members, err := convertMembers(raw.data.([]btfMember))
 			if err != nil {
-				return nil, xerrors.Errorf("struct %s (id %d): %w", name, id, err)
+				return nil, fmt.Errorf("struct %s (id %d): %w", name, id, err)
 			}
 			typ = &Struct{id, name, raw.Size(), members}
 
 		case kindUnion:
 			members, err := convertMembers(raw.data.([]btfMember))
 			if err != nil {
-				return nil, xerrors.Errorf("union %s (id %d): %w", name, id, err)
+				return nil, fmt.Errorf("union %s (id %d): %w", name, id, err)
 			}
 			typ = &Union{id, name, raw.Size(), members}
 
@@ -552,7 +552,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
 			typ = &Datasec{id, name, raw.SizeType, vars}
 
 		default:
-			return nil, xerrors.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
+			return nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
 		}
 
 		types = append(types, typ)
@@ -567,7 +567,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
 	for _, fixup := range fixups {
 		i := int(fixup.id)
 		if i >= len(types) {
-			return nil, xerrors.Errorf("reference to invalid type id: %d", fixup.id)
+			return nil, fmt.Errorf("reference to invalid type id: %d", fixup.id)
 		}
 
 		// Default void (id 0) to unknown
@@ -577,7 +577,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
 		}
 
 		if expected := fixup.expectedKind; expected != kindUnknown && rawKind != expected {
-			return nil, xerrors.Errorf("expected type id %d to have kind %s, found %s", fixup.id, expected, rawKind)
+			return nil, fmt.Errorf("expected type id %d to have kind %s, found %s", fixup.id, expected, rawKind)
 		}
 
 		*fixup.typ = types[i]
diff --git a/internal/errors.go b/internal/errors.go
index 72dedb4..b6aee81 100644
--- a/internal/errors.go
+++ b/internal/errors.go
@@ -2,11 +2,11 @@ package internal
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
 	"strings"
 
 	"github.com/cilium/ebpf/internal/unix"
-	"golang.org/x/xerrors"
 )
 
 // ErrorWithLog returns an error that includes logs from the
@@ -16,7 +16,7 @@ import (
 // the log. It is used to check for truncation of the output.
 func ErrorWithLog(err error, log []byte, logErr error) error {
 	logStr := strings.Trim(CString(log), "\t\r\n ")
-	if xerrors.Is(logErr, unix.ENOSPC) {
+	if errors.Is(logErr, unix.ENOSPC) {
 		logStr += " (truncated...)"
 	}
 
diff --git a/internal/fd.go b/internal/fd.go
index 499f1ec..af04955 100644
--- a/internal/fd.go
+++ b/internal/fd.go
@@ -1,16 +1,16 @@
 package internal
 
 import (
+	"errors"
+	"fmt"
 	"os"
 	"runtime"
 	"strconv"
 
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
-var ErrClosedFd = xerrors.New("use of closed file descriptor")
+var ErrClosedFd = errors.New("use of closed file descriptor")
 
 type FD struct {
 	raw int64
@@ -57,7 +57,7 @@ func (fd *FD) Dup() (*FD, error) {
 
 	dup, err := unix.FcntlInt(uintptr(fd.raw), unix.F_DUPFD_CLOEXEC, 0)
 	if err != nil {
-		return nil, xerrors.Errorf("can't dup fd: %v", err)
+		return nil, fmt.Errorf("can't dup fd: %v", err)
 	}
 
 	return NewFD(uint32(dup)), nil
diff --git a/internal/feature.go b/internal/feature.go
index 671a6a0..7375b21 100644
--- a/internal/feature.go
+++ b/internal/feature.go
@@ -1,14 +1,13 @@
 package internal
 
 import (
+	"errors"
 	"fmt"
 	"sync"
-
-	"golang.org/x/xerrors"
 )
 
 // ErrNotSupported indicates that a feature is not supported by the current kernel.
-var ErrNotSupported = xerrors.New("not supported")
+var ErrNotSupported = errors.New("not supported")
 
 // UnsupportedFeatureError is returned by FeatureTest() functions.
 type UnsupportedFeatureError struct {
@@ -67,7 +66,7 @@ func FeatureTest(name, version string, fn FeatureTestFn) func() error {
 		}
 
 		available, err := fn()
-		if xerrors.Is(err, ErrNotSupported) {
+		if errors.Is(err, ErrNotSupported) {
 			// The feature test aborted because a dependent feature
 			// is missing, which we should cache.
 			available = false
@@ -75,7 +74,7 @@ func FeatureTest(name, version string, fn FeatureTestFn) func() error {
 			// We couldn't execute the feature test to a point
 			// where it could make a determination.
 			// Don't cache the result, just return it.
-			return xerrors.Errorf("can't detect support for %s: %w", name, err)
+			return fmt.Errorf("can't detect support for %s: %w", name, err)
 		}
 
 		ft.successful = true
@@ -99,7 +98,7 @@ func NewVersion(ver string) (Version, error) {
 	var major, minor, patch uint16
 	n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch)
 	if n < 2 {
-		return Version{}, xerrors.Errorf("invalid version: %s", ver)
+		return Version{}, fmt.Errorf("invalid version: %s", ver)
 	}
 	return Version{major, minor, patch}, nil
 }
diff --git a/internal/io.go b/internal/io.go
index f364f21..fa74027 100644
--- a/internal/io.go
+++ b/internal/io.go
@@ -1,6 +1,6 @@
 package internal
 
-import "golang.org/x/xerrors"
+import "errors"
 
 // DiscardZeroes makes sure that all written bytes are zero
 // before discarding them.
@@ -9,7 +9,7 @@ type DiscardZeroes struct{}
 func (DiscardZeroes) Write(p []byte) (int, error) {
 	for _, b := range p {
 		if b != 0 {
-			return 0, xerrors.New("encountered non-zero byte")
+			return 0, errors.New("encountered non-zero byte")
 		}
 	}
 	return len(p), nil
diff --git a/internal/syscall.go b/internal/syscall.go
index b9de045..efbf403 100644
--- a/internal/syscall.go
+++ b/internal/syscall.go
@@ -1,12 +1,12 @@
 package internal
 
 import (
+	"fmt"
 	"path/filepath"
 	"runtime"
 	"unsafe"
 
 	"github.com/cilium/ebpf/internal/unix"
-	"golang.org/x/xerrors"
 )
 
 //go:generate stringer -output syscall_string.go -type=BPFCmd
@@ -107,7 +107,7 @@ func BPFObjPin(fileName string, fd *FD) error {
 		return err
 	}
 	if uint64(statfs.Type) != bpfFSType {
-		return xerrors.Errorf("%s is not on a bpf filesystem", fileName)
+		return fmt.Errorf("%s is not on a bpf filesystem", fileName)
 	}
 
 	value, err := fd.Value()
@@ -121,7 +121,7 @@ func BPFObjPin(fileName string, fd *FD) error {
 	}
 	_, err = BPF(BPF_OBJ_PIN, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 	if err != nil {
-		return xerrors.Errorf("pin object %s: %w", fileName, err)
+		return fmt.Errorf("pin object %s: %w", fileName, err)
 	}
 	return nil
 }
@@ -133,7 +133,7 @@ func BPFObjGet(fileName string) (*FD, error) {
 	}
 	ptr, err := BPF(BPF_OBJ_GET, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 	if err != nil {
-		return nil, xerrors.Errorf("get object %s: %w", fileName, err)
+		return nil, fmt.Errorf("get object %s: %w", fileName, err)
 	}
 	return NewFD(uint32(ptr)), nil
 }
diff --git a/link/cgroup.go b/link/cgroup.go
index 96a5cec..16a9439 100644
--- a/link/cgroup.go
+++ b/link/cgroup.go
@@ -1,11 +1,11 @@
 package link
 
 import (
+	"errors"
+	"fmt"
 	"os"
 
 	"github.com/cilium/ebpf"
-
-	"golang.org/x/xerrors"
 )
 
 type cgroupAttachFlags uint32
@@ -30,7 +30,7 @@ type CgroupOptions struct {
 func AttachCgroup(opts CgroupOptions) (Link, error) {
 	cgroup, err := os.Open(opts.Path)
 	if err != nil {
-		return nil, xerrors.Errorf("can't open cgroup: %s", err)
+		return nil, fmt.Errorf("can't open cgroup: %s", err)
 	}
 
 	clone, err := opts.Program.Clone()
@@ -41,10 +41,10 @@ func AttachCgroup(opts CgroupOptions) (Link, error) {
 
 	var cg Link
 	cg, err = newLinkCgroup(cgroup, opts.Attach, clone)
-	if xerrors.Is(err, ErrNotSupported) {
+	if errors.Is(err, ErrNotSupported) {
 		cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowMulti)
 	}
-	if xerrors.Is(err, ErrNotSupported) {
+	if errors.Is(err, ErrNotSupported) {
 		cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowOverride)
 	}
 	if err != nil {
@@ -80,7 +80,7 @@ func (cg *progAttachCgroup) isLink() {}
 func newProgAttachCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program, flags cgroupAttachFlags) (*progAttachCgroup, error) {
 	if flags&flagAllowMulti > 0 {
 		if err := haveProgAttachReplace(); err != nil {
-			return nil, xerrors.Errorf("can't support multiple programs: %w", err)
+			return nil, fmt.Errorf("can't support multiple programs: %w", err)
 		}
 	}
 
@@ -91,7 +91,7 @@ func newProgAttachCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Pro
 		Attach:  attach,
 	})
 	if err != nil {
-		return nil, xerrors.Errorf("cgroup: %w", err)
+		return nil, fmt.Errorf("cgroup: %w", err)
 	}
 
 	return &progAttachCgroup{cgroup, prog, attach, flags}, nil
@@ -107,7 +107,7 @@ func (cg *progAttachCgroup) Close() error {
 		Attach:  cg.attachType,
 	})
 	if err != nil {
-		return xerrors.Errorf("close cgroup: %s", err)
+		return fmt.Errorf("close cgroup: %s", err)
 	}
 	return nil
 }
@@ -135,7 +135,7 @@ func (cg *progAttachCgroup) Update(prog *ebpf.Program) error {
 
 	if err := RawAttachProgram(args); err != nil {
 		new.Close()
-		return xerrors.Errorf("can't update cgroup: %s", err)
+		return fmt.Errorf("can't update cgroup: %s", err)
 	}
 
 	cg.current.Close()
@@ -144,7 +144,7 @@ func (cg *progAttachCgroup) Update(prog *ebpf.Program) error {
 }
 
 func (cg *progAttachCgroup) Pin(string) error {
-	return xerrors.Errorf("can't pin cgroup: %w", ErrNotSupported)
+	return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported)
 }
 
 type linkCgroup struct {
diff --git a/link/iter.go b/link/iter.go
index 2aa6af1..f464114 100644
--- a/link/iter.go
+++ b/link/iter.go
@@ -1,10 +1,10 @@
 package link
 
 import (
+	"fmt"
 	"io"
 
 	"github.com/cilium/ebpf"
-	"golang.org/x/xerrors"
 )
 
 type IterOptions struct {
@@ -24,7 +24,7 @@ func AttachIter(opts IterOptions) (*Iter, error) {
 		Attach:  ebpf.AttachTraceIter,
 	})
 	if err != nil {
-		return nil, xerrors.Errorf("can't link iterator: %w", err)
+		return nil, fmt.Errorf("can't link iterator: %w", err)
 	}
 
 	return &Iter{link}, err
@@ -79,7 +79,7 @@ func (it *Iter) Open() (io.ReadCloser, error) {
 
 	fd, err := bpfIterCreate(attr)
 	if err != nil {
-		return nil, xerrors.Errorf("can't create iterator: %w", err)
+		return nil, fmt.Errorf("can't create iterator: %w", err)
 	}
 
 	return fd.File("bpf_iter"), nil
diff --git a/link/link.go b/link/link.go
index 911ec83..19f385f 100644
--- a/link/link.go
+++ b/link/link.go
@@ -1,10 +1,10 @@
 package link
 
 import (
+	"fmt"
+
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/internal"
-
-	"golang.org/x/xerrors"
 )
 
 var ErrNotSupported = internal.ErrNotSupported
@@ -57,12 +57,12 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
 	}
 
 	if opts.Target < 0 {
-		return nil, xerrors.Errorf("invalid target: %s", internal.ErrClosedFd)
+		return nil, fmt.Errorf("invalid target: %s", internal.ErrClosedFd)
 	}
 
 	progFd := opts.Program.FD()
 	if progFd < 0 {
-		return nil, xerrors.Errorf("invalid program: %s", internal.ErrClosedFd)
+		return nil, fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
 	}
 
 	attr := bpfLinkCreateAttr{
@@ -72,7 +72,7 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
 	}
 	fd, err := bpfLinkCreate(&attr)
 	if err != nil {
-		return nil, xerrors.Errorf("can't create link: %s", err)
+		return nil, fmt.Errorf("can't create link: %s", err)
 	}
 
 	return &RawLink{fd}, nil
@@ -82,7 +82,7 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
 func LoadPinnedRawLink(fileName string) (*RawLink, error) {
 	fd, err := internal.BPFObjGet(fileName)
 	if err != nil {
-		return nil, xerrors.Errorf("can't load pinned link: %s", err)
+		return nil, fmt.Errorf("can't load pinned link: %s", err)
 	}
 
 	return &RawLink{fd}, nil
@@ -103,7 +103,7 @@ func (l *RawLink) Close() error {
 // until the pin is removed.
 func (l *RawLink) Pin(fileName string) error {
 	if err := internal.BPFObjPin(fileName, l.fd); err != nil {
-		return xerrors.Errorf("can't pin link: %s", err)
+		return fmt.Errorf("can't pin link: %s", err)
 	}
 	return nil
 }
@@ -126,20 +126,20 @@ type RawLinkUpdateOptions struct {
 func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error {
 	newFd := opts.New.FD()
 	if newFd < 0 {
-		return xerrors.Errorf("invalid program: %s", internal.ErrClosedFd)
+		return fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
 	}
 
 	var oldFd int
 	if opts.Old != nil {
 		oldFd = opts.Old.FD()
 		if oldFd < 0 {
-			return xerrors.Errorf("invalid replacement program: %s", internal.ErrClosedFd)
+			return fmt.Errorf("invalid replacement program: %s", internal.ErrClosedFd)
 		}
 	}
 
 	linkFd, err := l.fd.Value()
 	if err != nil {
-		return xerrors.Errorf("can't update link: %s", err)
+		return fmt.Errorf("can't update link: %s", err)
 	}
 
 	attr := bpfLinkUpdateAttr{
diff --git a/link/program.go b/link/program.go
index 7c7d347..0fe9d37 100644
--- a/link/program.go
+++ b/link/program.go
@@ -1,10 +1,10 @@
 package link
 
 import (
+	"fmt"
+
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/internal"
-
-	"golang.org/x/xerrors"
 )
 
 type RawAttachProgramOptions struct {
@@ -43,7 +43,7 @@ func RawAttachProgram(opts RawAttachProgramOptions) error {
 	}
 
 	if err := internal.BPFProgAttach(&attr); err != nil {
-		return xerrors.Errorf("can't attach program: %s", err)
+		return fmt.Errorf("can't attach program: %s", err)
 	}
 	return nil
 }
@@ -69,7 +69,7 @@ func RawDetachProgram(opts RawDetachProgramOptions) error {
 		AttachType:  uint32(opts.Attach),
 	}
 	if err := internal.BPFProgDetach(&attr); err != nil {
-		return xerrors.Errorf("can't detach program: %s", err)
+		return fmt.Errorf("can't detach program: %s", err)
 	}
 
 	return nil
diff --git a/link/syscalls.go b/link/syscalls.go
index ac14839..e6c0bd4 100644
--- a/link/syscalls.go
+++ b/link/syscalls.go
@@ -1,14 +1,13 @@
 package link
 
 import (
+	"errors"
 	"unsafe"
 
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
 var haveProgAttach = internal.FeatureTest("BPF_PROG_ATTACH", "4.10", func() (bool, error) {
@@ -63,12 +62,12 @@ var haveProgAttachReplace = internal.FeatureTest("BPF_PROG_ATTACH atomic replace
 	}
 
 	err = internal.BPFProgAttach(&attr)
-	if xerrors.Is(err, unix.EPERM) {
+	if errors.Is(err, unix.EPERM) {
 		// We don't have enough permissions, so we never get to the point
 		// where flags are checked.
 		return false, err
 	}
-	return !xerrors.Is(err, unix.EINVAL), nil
+	return !errors.Is(err, unix.EINVAL), nil
 })
 
 type bpfLinkCreateAttr struct {
@@ -120,7 +119,7 @@ var haveBPFLink = internal.FeatureTest("bpf_link", "5.7", func() (bool, error) {
 		attachType: ebpf.AttachCGroupInetIngress,
 	}
 	_, err = bpfLinkCreate(&attr)
-	return !xerrors.Is(err, unix.EINVAL), nil
+	return !errors.Is(err, unix.EINVAL), nil
 })
 
 type bpfIterCreateAttr struct {
diff --git a/linker.go b/linker.go
index b9a54da..1bb8f61 100644
--- a/linker.go
+++ b/linker.go
@@ -1,10 +1,10 @@
 package ebpf
 
 import (
+	"fmt"
+
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/internal/btf"
-
-	"golang.org/x/xerrors"
 )
 
 // link resolves bpf-to-bpf calls.
@@ -28,7 +28,7 @@ func link(prog *ProgramSpec, libs []*ProgramSpec) error {
 
 			needed, err := needSection(insns, lib.Instructions)
 			if err != nil {
-				return xerrors.Errorf("linking %s: %w", lib.Name, err)
+				return fmt.Errorf("linking %s: %w", lib.Name, err)
 			}
 
 			if !needed {
@@ -41,7 +41,7 @@ func link(prog *ProgramSpec, libs []*ProgramSpec) error {
 
 			if prog.BTF != nil && lib.BTF != nil {
 				if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil {
-					return xerrors.Errorf("linking BTF of %s: %w", lib.Name, err)
+					return fmt.Errorf("linking BTF of %s: %w", lib.Name, err)
 				}
 			}
 		}
diff --git a/map.go b/map.go
index 31abc17..461b995 100644
--- a/map.go
+++ b/map.go
@@ -1,21 +1,20 @@
 package ebpf
 
 import (
+	"errors"
 	"fmt"
 	"strings"
 
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/btf"
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
 // Errors returned by Map and MapIterator methods.
 var (
-	ErrKeyNotExist      = xerrors.New("key does not exist")
-	ErrKeyExist         = xerrors.New("key already exists")
-	ErrIterationAborted = xerrors.New("iteration aborted")
+	ErrKeyNotExist      = errors.New("key does not exist")
+	ErrKeyExist         = errors.New("key already exists")
+	ErrIterationAborted = errors.New("iteration aborted")
 )
 
 // MapID represents the unique ID of an eBPF map
@@ -92,7 +91,7 @@ type Map struct {
 // You should not use fd after calling this function.
 func NewMapFromFD(fd int) (*Map, error) {
 	if fd < 0 {
-		return nil, xerrors.New("invalid fd")
+		return nil, errors.New("invalid fd")
 	}
 	bpfFd := internal.NewFD(uint32(fd))
 
@@ -118,8 +117,8 @@ func NewMap(spec *MapSpec) (*Map, error) {
 	}
 
 	handle, err := btf.NewHandle(btf.MapSpec(spec.BTF))
-	if err != nil && !xerrors.Is(err, btf.ErrNotSupported) {
-		return nil, xerrors.Errorf("can't load BTF: %w", err)
+	if err != nil && !errors.Is(err, btf.ErrNotSupported) {
+		return nil, fmt.Errorf("can't load BTF: %w", err)
 	}
 
 	return newMapWithBTF(spec, handle)
@@ -131,7 +130,7 @@ func newMapWithBTF(spec *MapSpec, handle *btf.Handle) (*Map, error) {
 	}
 
 	if spec.InnerMap == nil {
-		return nil, xerrors.Errorf("%s requires InnerMap", spec.Type)
+		return nil, fmt.Errorf("%s requires InnerMap", spec.Type)
 	}
 
 	template, err := createMap(spec.InnerMap, nil, handle)
@@ -155,25 +154,25 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
 		}
 
 		if abi.ValueSize != 0 && abi.ValueSize != 4 {
-			return nil, xerrors.New("ValueSize must be zero or four for map of map")
+			return nil, errors.New("ValueSize must be zero or four for map of map")
 		}
 		abi.ValueSize = 4
 
 	case PerfEventArray:
 		if abi.KeySize != 0 && abi.KeySize != 4 {
-			return nil, xerrors.New("KeySize must be zero or four for perf event array")
+			return nil, errors.New("KeySize must be zero or four for perf event array")
 		}
 		abi.KeySize = 4
 
 		if abi.ValueSize != 0 && abi.ValueSize != 4 {
-			return nil, xerrors.New("ValueSize must be zero or four for perf event array")
+			return nil, errors.New("ValueSize must be zero or four for perf event array")
 		}
 		abi.ValueSize = 4
 
 		if abi.MaxEntries == 0 {
 			n, err := internal.PossibleCPUs()
 			if err != nil {
-				return nil, xerrors.Errorf("perf event array: %w", err)
+				return nil, fmt.Errorf("perf event array: %w", err)
 			}
 			abi.MaxEntries = uint32(n)
 		}
@@ -181,7 +180,7 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
 
 	if abi.Flags&(unix.BPF_F_RDONLY_PROG|unix.BPF_F_WRONLY_PROG) > 0 || spec.Freeze {
 		if err := haveMapMutabilityModifiers(); err != nil {
-			return nil, xerrors.Errorf("map create: %w", err)
+			return nil, fmt.Errorf("map create: %w", err)
 		}
 	}
 
@@ -197,7 +196,7 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
 		var err error
 		attr.innerMapFd, err = inner.Value()
 		if err != nil {
-			return nil, xerrors.Errorf("map create: %w", err)
+			return nil, fmt.Errorf("map create: %w", err)
 		}
 	}
 
@@ -213,7 +212,7 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
 
 	fd, err := bpfMapCreate(&attr)
 	if err != nil {
-		return nil, xerrors.Errorf("map create: %w", err)
+		return nil, fmt.Errorf("map create: %w", err)
 	}
 
 	m, err := newMap(fd, spec.Name, abi)
@@ -223,13 +222,13 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
 
 	if err := m.populate(spec.Contents); err != nil {
 		m.Close()
-		return nil, xerrors.Errorf("map create: can't set initial contents: %w", err)
+		return nil, fmt.Errorf("map create: can't set initial contents: %w", err)
 	}
 
 	if spec.Freeze {
 		if err := m.Freeze(); err != nil {
 			m.Close()
-			return nil, xerrors.Errorf("can't freeze map: %w", err)
+			return nil, fmt.Errorf("can't freeze map: %w", err)
 		}
 	}
 
@@ -301,9 +300,9 @@ func (m *Map) Lookup(key, valueOut interface{}) error {
 		*value = m
 		return nil
 	case *Map:
-		return xerrors.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
+		return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
 	case Map:
-		return xerrors.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
+		return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
 
 	case **Program:
 		p, err := unmarshalProgram(valueBytes)
@@ -315,9 +314,9 @@ func (m *Map) Lookup(key, valueOut interface{}) error {
 		*value = p
 		return nil
 	case *Program:
-		return xerrors.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
+		return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
 	case Program:
-		return xerrors.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
+		return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
 
 	default:
 		return unmarshalBytes(valueOut, valueBytes)
@@ -332,11 +331,11 @@ func (m *Map) LookupAndDelete(key, valueOut interface{}) error {
 
 	keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
 	if err != nil {
-		return xerrors.Errorf("can't marshal key: %w", err)
+		return fmt.Errorf("can't marshal key: %w", err)
 	}
 
 	if err := bpfMapLookupAndDelete(m.fd, keyPtr, valuePtr); err != nil {
-		return xerrors.Errorf("lookup and delete failed: %w", err)
+		return fmt.Errorf("lookup and delete failed: %w", err)
 	}
 
 	return unmarshalBytes(valueOut, valueBytes)
@@ -350,7 +349,7 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) {
 	valuePtr := internal.NewSlicePointer(valueBytes)
 
 	err := m.lookup(key, valuePtr)
-	if xerrors.Is(err, ErrKeyNotExist) {
+	if errors.Is(err, ErrKeyNotExist) {
 		return nil, nil
 	}
 
@@ -360,11 +359,11 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) {
 func (m *Map) lookup(key interface{}, valueOut internal.Pointer) error {
 	keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
 	if err != nil {
-		return xerrors.Errorf("can't marshal key: %w", err)
+		return fmt.Errorf("can't marshal key: %w", err)
 	}
 
 	if err = bpfMapLookupElem(m.fd, keyPtr, valueOut); err != nil {
-		return xerrors.Errorf("lookup failed: %w", err)
+		return fmt.Errorf("lookup failed: %w", err)
 	}
 	return nil
 }
@@ -394,7 +393,7 @@ func (m *Map) Put(key, value interface{}) error {
 func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
 	keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
 	if err != nil {
-		return xerrors.Errorf("can't marshal key: %w", err)
+		return fmt.Errorf("can't marshal key: %w", err)
 	}
 
 	var valuePtr internal.Pointer
@@ -404,11 +403,11 @@ func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
 		valuePtr, err = marshalPtr(value, int(m.abi.ValueSize))
 	}
 	if err != nil {
-		return xerrors.Errorf("can't marshal value: %w", err)
+		return fmt.Errorf("can't marshal value: %w", err)
 	}
 
 	if err = bpfMapUpdateElem(m.fd, keyPtr, valuePtr, uint64(flags)); err != nil {
-		return xerrors.Errorf("update failed: %w", err)
+		return fmt.Errorf("update failed: %w", err)
 	}
 
 	return nil
@@ -420,11 +419,11 @@ func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
 func (m *Map) Delete(key interface{}) error {
 	keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
 	if err != nil {
-		return xerrors.Errorf("can't marshal key: %w", err)
+		return fmt.Errorf("can't marshal key: %w", err)
 	}
 
 	if err = bpfMapDeleteElem(m.fd, keyPtr); err != nil {
-		return xerrors.Errorf("delete failed: %w", err)
+		return fmt.Errorf("delete failed: %w", err)
 	}
 	return nil
 }
@@ -446,7 +445,7 @@ func (m *Map) NextKey(key, nextKeyOut interface{}) error {
 	}
 
 	if err := unmarshalBytes(nextKeyOut, nextKeyBytes); err != nil {
-		return xerrors.Errorf("can't unmarshal next key: %w", err)
+		return fmt.Errorf("can't unmarshal next key: %w", err)
 	}
 	return nil
 }
@@ -463,7 +462,7 @@ func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) {
 	nextKeyPtr := internal.NewSlicePointer(nextKey)
 
 	err := m.nextKey(key, nextKeyPtr)
-	if xerrors.Is(err, ErrKeyNotExist) {
+	if errors.Is(err, ErrKeyNotExist) {
 		return nil, nil
 	}
 
@@ -479,12 +478,12 @@ func (m *Map) nextKey(key interface{}, nextKeyOut internal.Pointer) error {
 	if key != nil {
 		keyPtr, err = marshalPtr(key, int(m.abi.KeySize))
 		if err != nil {
-			return xerrors.Errorf("can't marshal key: %w", err)
+			return fmt.Errorf("can't marshal key: %w", err)
 		}
 	}
 
 	if err = bpfMapGetNextKey(m.fd, keyPtr, nextKeyOut); err != nil {
-		return xerrors.Errorf("next key failed: %w", err)
+		return fmt.Errorf("next key failed: %w", err)
 	}
 	return nil
 }
@@ -537,7 +536,7 @@ func (m *Map) Clone() (*Map, error) {
 
 	dup, err := m.fd.Dup()
 	if err != nil {
-		return nil, xerrors.Errorf("can't clone map: %w", err)
+		return nil, fmt.Errorf("can't clone map: %w", err)
 	}
 
 	return newMap(dup, m.name, &m.abi)
@@ -555,11 +554,11 @@ func (m *Map) Pin(fileName string) error {
 // It makes no changes to kernel-side restrictions.
 func (m *Map) Freeze() error {
 	if err := haveMapMutabilityModifiers(); err != nil {
-		return xerrors.Errorf("can't freeze map: %w", err)
+		return fmt.Errorf("can't freeze map: %w", err)
 	}
 
 	if err := bpfMapFreeze(m.fd); err != nil {
-		return xerrors.Errorf("can't freeze map: %w", err)
+		return fmt.Errorf("can't freeze map: %w", err)
 	}
 	return nil
 }
@@ -567,7 +566,7 @@ func (m *Map) Freeze() error {
 func (m *Map) populate(contents []MapKV) error {
 	for _, kv := range contents {
 		if err := m.Put(kv.Key, kv.Value); err != nil {
-			return xerrors.Errorf("key %v: %w", kv.Key, err)
+			return fmt.Errorf("key %v: %w", kv.Key, err)
 		}
 	}
 	return nil
@@ -601,7 +600,7 @@ func LoadPinnedMapExplicit(fileName string, abi *MapABI) (*Map, error) {
 
 func unmarshalMap(buf []byte) (*Map, error) {
 	if len(buf) != 4 {
-		return nil, xerrors.New("map id requires 4 byte value")
+		return nil, errors.New("map id requires 4 byte value")
 	}
 
 	// Looking up an entry in a nested map or prog array returns an id,
@@ -626,12 +625,12 @@ func patchValue(value []byte, typ btf.Type, replacements map[string]interface{})
 	replaced := make(map[string]bool)
 	replace := func(name string, offset, size int, replacement interface{}) error {
 		if offset+size > len(value) {
-			return xerrors.Errorf("%s: offset %d(+%d) is out of bounds", name, offset, size)
+			return fmt.Errorf("%s: offset %d(+%d) is out of bounds", name, offset, size)
 		}
 
 		buf, err := marshalBytes(replacement, size)
 		if err != nil {
-			return xerrors.Errorf("marshal %s: %w", name, err)
+			return fmt.Errorf("marshal %s: %w", name, err)
 		}
 
 		copy(value[offset:offset+size], buf)
@@ -655,7 +654,7 @@ func patchValue(value []byte, typ btf.Type, replacements map[string]interface{})
 		}
 
 	default:
-		return xerrors.Errorf("patching %T is not supported", typ)
+		return fmt.Errorf("patching %T is not supported", typ)
 	}
 
 	if len(replaced) == len(replacements) {
@@ -670,10 +669,10 @@ func patchValue(value []byte, typ btf.Type, replacements map[string]interface{})
 	}
 
 	if len(missing) == 1 {
-		return xerrors.Errorf("unknown field: %s", missing[0])
+		return fmt.Errorf("unknown field: %s", missing[0])
 	}
 
-	return xerrors.Errorf("unknown fields: %s", strings.Join(missing, ","))
+	return fmt.Errorf("unknown fields: %s", strings.Join(missing, ","))
 }
 
 // MapIterator iterates a Map.
@@ -731,7 +730,7 @@ func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool {
 		mi.prevKey = mi.prevBytes
 
 		mi.err = mi.target.Lookup(nextBytes, valueOut)
-		if xerrors.Is(mi.err, ErrKeyNotExist) {
+		if errors.Is(mi.err, ErrKeyNotExist) {
 			// Even though the key should be valid, we couldn't look up
 			// its value. If we're iterating a hash map this is probably
 			// because a concurrent delete removed the value before we
@@ -750,7 +749,7 @@ func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool {
 		return mi.err == nil
 	}
 
-	mi.err = xerrors.Errorf("%w", ErrIterationAborted)
+	mi.err = fmt.Errorf("%w", ErrIterationAborted)
 	return false
 }
 
diff --git a/marshalers.go b/marshalers.go
index 89fdc86..c0db2f6 100644
--- a/marshalers.go
+++ b/marshalers.go
@@ -4,13 +4,13 @@ import (
 	"bytes"
 	"encoding"
 	"encoding/binary"
+	"errors"
+	"fmt"
 	"reflect"
 	"runtime"
 	"unsafe"
 
 	"github.com/cilium/ebpf/internal"
-
-	"golang.org/x/xerrors"
 )
 
 func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
@@ -18,7 +18,7 @@ func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
 		if length == 0 {
 			return internal.NewPointer(nil), nil
 		}
-		return internal.Pointer{}, xerrors.New("can't use nil as key of map")
+		return internal.Pointer{}, errors.New("can't use nil as key of map")
 	}
 
 	if ptr, ok := data.(unsafe.Pointer); ok {
@@ -42,12 +42,12 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) {
 	case []byte:
 		buf = value
 	case unsafe.Pointer:
-		err = xerrors.New("can't marshal from unsafe.Pointer")
+		err = errors.New("can't marshal from unsafe.Pointer")
 	default:
 		var wr bytes.Buffer
 		err = binary.Write(&wr, internal.NativeEndian, value)
 		if err != nil {
-			err = xerrors.Errorf("encoding %T: %v", value, err)
+			err = fmt.Errorf("encoding %T: %v", value, err)
 		}
 		buf = wr.Bytes()
 	}
@@ -56,7 +56,7 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) {
 	}
 
 	if len(buf) != length {
-		return nil, xerrors.Errorf("%T doesn't marshal to %d bytes", data, length)
+		return nil, fmt.Errorf("%T doesn't marshal to %d bytes", data, length)
 	}
 	return buf, nil
 }
@@ -92,13 +92,13 @@ func unmarshalBytes(data interface{}, buf []byte) error {
 		*value = buf
 		return nil
 	case string:
-		return xerrors.New("require pointer to string")
+		return errors.New("require pointer to string")
 	case []byte:
-		return xerrors.New("require pointer to []byte")
+		return errors.New("require pointer to []byte")
 	default:
 		rd := bytes.NewReader(buf)
 		if err := binary.Read(rd, internal.NativeEndian, value); err != nil {
-			return xerrors.Errorf("decoding %T: %v", value, err)
+			return fmt.Errorf("decoding %T: %v", value, err)
 		}
 		return nil
 	}
@@ -113,7 +113,7 @@ func unmarshalBytes(data interface{}, buf []byte) error {
 func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, error) {
 	sliceType := reflect.TypeOf(slice)
 	if sliceType.Kind() != reflect.Slice {
-		return internal.Pointer{}, xerrors.New("per-CPU value requires slice")
+		return internal.Pointer{}, errors.New("per-CPU value requires slice")
 	}
 
 	possibleCPUs, err := internal.PossibleCPUs()
@@ -124,7 +124,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er
 	sliceValue := reflect.ValueOf(slice)
 	sliceLen := sliceValue.Len()
 	if sliceLen > possibleCPUs {
-		return internal.Pointer{}, xerrors.Errorf("per-CPU value exceeds number of CPUs")
+		return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs")
 	}
 
 	alignedElemLength := align(elemLength, 8)
@@ -151,7 +151,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er
 func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) error {
 	slicePtrType := reflect.TypeOf(slicePtr)
 	if slicePtrType.Kind() != reflect.Ptr || slicePtrType.Elem().Kind() != reflect.Slice {
-		return xerrors.Errorf("per-cpu value requires pointer to slice")
+		return fmt.Errorf("per-cpu value requires pointer to slice")
 	}
 
 	possibleCPUs, err := internal.PossibleCPUs()
@@ -170,7 +170,7 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro
 
 	step := len(buf) / possibleCPUs
 	if step < elemLength {
-		return xerrors.Errorf("per-cpu element length is larger than available data")
+		return fmt.Errorf("per-cpu element length is larger than available data")
 	}
 	for i := 0; i < possibleCPUs; i++ {
 		var elem interface{}
@@ -188,7 +188,7 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro
 
 		err := unmarshalBytes(elem, elemBytes)
 		if err != nil {
-			return xerrors.Errorf("cpu %d: %w", i, err)
+			return fmt.Errorf("cpu %d: %w", i, err)
 		}
 
 		buf = buf[step:]
diff --git a/perf/reader.go b/perf/reader.go
index 151cc4a..9e469a9 100644
--- a/perf/reader.go
+++ b/perf/reader.go
@@ -2,6 +2,7 @@ package perf
 
 import (
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io"
 	"math"
@@ -11,13 +12,11 @@ import (
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
 var (
-	errClosed = xerrors.New("perf reader was closed")
-	errEOR    = xerrors.New("end of ring")
+	errClosed = errors.New("perf reader was closed")
+	errEOR    = errors.New("end of ring")
 )
 
 // perfEventHeader must match 'struct perf_event_header` in <linux/perf_event.h>.
@@ -29,7 +28,7 @@ type perfEventHeader struct {
 
 func addToEpoll(epollfd, fd int, cpu int) error {
 	if int64(cpu) > math.MaxInt32 {
-		return xerrors.Errorf("unsupported CPU number: %d", cpu)
+		return fmt.Errorf("unsupported CPU number: %d", cpu)
 	}
 
 	// The representation of EpollEvent isn't entirely accurate.
@@ -43,7 +42,7 @@ func addToEpoll(epollfd, fd int, cpu int) error {
 	}
 
 	if err := unix.EpollCtl(epollfd, unix.EPOLL_CTL_ADD, fd, &event); err != nil {
-		return xerrors.Errorf("can't add fd to epoll: %v", err)
+		return fmt.Errorf("can't add fd to epoll: %v", err)
 	}
 	return nil
 }
@@ -87,7 +86,7 @@ func readRecord(rd io.Reader, cpu int) (Record, error) {
 	}
 
 	if err != nil {
-		return Record{}, xerrors.Errorf("can't read event header: %v", err)
+		return Record{}, fmt.Errorf("can't read event header: %v", err)
 	}
 
 	switch header.Type {
@@ -113,7 +112,7 @@ func readLostRecords(rd io.Reader) (uint64, error) {
 
 	err := binary.Read(rd, internal.NativeEndian, &lostHeader)
 	if err != nil {
-		return 0, xerrors.Errorf("can't read lost records header: %v", err)
+		return 0, fmt.Errorf("can't read lost records header: %v", err)
 	}
 
 	return lostHeader.Lost, nil
@@ -123,12 +122,12 @@ func readRawSample(rd io.Reader) ([]byte, error) {
 	// This must match 'struct perf_event_sample in kernel sources.
 	var size uint32
 	if err := binary.Read(rd, internal.NativeEndian, &size); err != nil {
-		return nil, xerrors.Errorf("can't read sample size: %v", err)
+		return nil, fmt.Errorf("can't read sample size: %v", err)
 	}
 
 	data := make([]byte, int(size))
 	if _, err := io.ReadFull(rd, data); err != nil {
-		return nil, xerrors.Errorf("can't read sample: %v", err)
+		return nil, fmt.Errorf("can't read sample: %v", err)
 	}
 	return data, nil
 }
@@ -182,12 +181,12 @@ func NewReader(array *ebpf.Map, perCPUBuffer int) (*Reader, error) {
 // NewReaderWithOptions creates a new reader with the given options.
 func NewReaderWithOptions(array *ebpf.Map, perCPUBuffer int, opts ReaderOptions) (pr *Reader, err error) {
 	if perCPUBuffer < 1 {
-		return nil, xerrors.New("perCPUBuffer must be larger than 0")
+		return nil, errors.New("perCPUBuffer must be larger than 0")
 	}
 
 	epollFd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
 	if err != nil {
-		return nil, xerrors.Errorf("can't create epoll fd: %v", err)
+		return nil, fmt.Errorf("can't create epoll fd: %v", err)
 	}
 
 	var (
@@ -215,7 +214,7 @@ func NewReaderWithOptions(array *ebpf.Map, perCPUBuffer int, opts ReaderOptions)
 	// Hence we have to create a ring for each CPU.
 	for i := 0; i < nCPU; i++ {
 		ring, err := newPerfEventRing(i, perCPUBuffer, opts.Watermark)
-		if xerrors.Is(err, unix.ENODEV) {
+		if errors.Is(err, unix.ENODEV) {
 			// The requested CPU is currently offline, skip it.
 			rings = append(rings, nil)
 			pauseFds = append(pauseFds, -1)
@@ -223,7 +222,7 @@ func NewReaderWithOptions(array *ebpf.Map, perCPUBuffer int, opts ReaderOptions)
 		}
 
 		if err != nil {
-			return nil, xerrors.Errorf("failed to create perf ring for CPU %d: %v", i, err)
+			return nil, fmt.Errorf("failed to create perf ring for CPU %d: %v", i, err)
 		}
 		rings = append(rings, ring)
 		pauseFds = append(pauseFds, ring.fd)
@@ -281,7 +280,7 @@ func (pr *Reader) Close() error {
 		internal.NativeEndian.PutUint64(value[:], 1)
 		_, err = unix.Write(pr.closeFd, value[:])
 		if err != nil {
-			err = xerrors.Errorf("can't write event fd: %v", err)
+			err = fmt.Errorf("can't write event fd: %v", err)
 			return
 		}
 
@@ -308,7 +307,7 @@ func (pr *Reader) Close() error {
 		pr.array.Close()
 	})
 	if err != nil {
-		return xerrors.Errorf("close PerfReader: %w", err)
+		return fmt.Errorf("close PerfReader: %w", err)
 	}
 	return nil
 }
@@ -388,8 +387,8 @@ func (pr *Reader) Pause() error {
 	}
 
 	for i := range pr.pauseFds {
-		if err := pr.array.Delete(uint32(i)); err != nil && !xerrors.Is(err, ebpf.ErrKeyNotExist) {
-			return xerrors.Errorf("could't delete event fd for CPU %d: %w", i, err)
+		if err := pr.array.Delete(uint32(i)); err != nil && !errors.Is(err, ebpf.ErrKeyNotExist) {
+			return fmt.Errorf("could't delete event fd for CPU %d: %w", i, err)
 		}
 	}
 
@@ -413,7 +412,7 @@ func (pr *Reader) Resume() error {
 		}
 
 		if err := pr.array.Put(uint32(i), uint32(fd)); err != nil {
-			return xerrors.Errorf("couldn't put event fd %d for CPU %d: %w", fd, i, err)
+			return fmt.Errorf("couldn't put event fd %d for CPU %d: %w", fd, i, err)
 		}
 	}
 
@@ -427,7 +426,7 @@ type temporaryError interface {
 // IsClosed returns true if the error occurred because
 // a Reader was closed.
 func IsClosed(err error) bool {
-	return xerrors.Is(err, errClosed)
+	return errors.Is(err, errClosed)
 }
 
 type unknownEventError struct {
@@ -442,5 +441,5 @@ func (uev *unknownEventError) Error() string {
 // because an unknown event was submitted to the perf event ring.
 func IsUnknownEvent(err error) bool {
 	var uee *unknownEventError
-	return xerrors.As(err, &uee)
+	return errors.As(err, &uee)
 }
diff --git a/perf/ring.go b/perf/ring.go
index a353a5f..2d0404f 100644
--- a/perf/ring.go
+++ b/perf/ring.go
@@ -1,6 +1,8 @@
 package perf
 
 import (
+	"errors"
+	"fmt"
 	"io"
 	"math"
 	"os"
@@ -9,8 +11,6 @@ import (
 	"unsafe"
 
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
 // perfEventRing is a page of metadata followed by
@@ -24,7 +24,7 @@ type perfEventRing struct {
 
 func newPerfEventRing(cpu, perCPUBuffer, watermark int) (*perfEventRing, error) {
 	if watermark >= perCPUBuffer {
-		return nil, xerrors.New("watermark must be smaller than perCPUBuffer")
+		return nil, errors.New("watermark must be smaller than perCPUBuffer")
 	}
 
 	fd, err := createPerfEvent(cpu, watermark)
@@ -40,7 +40,7 @@ func newPerfEventRing(cpu, perCPUBuffer, watermark int) (*perfEventRing, error)
 	mmap, err := unix.Mmap(fd, 0, perfBufferSize(perCPUBuffer), unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
 	if err != nil {
 		unix.Close(fd)
-		return nil, xerrors.Errorf("can't mmap: %v", err)
+		return nil, fmt.Errorf("can't mmap: %v", err)
 	}
 
 	// This relies on the fact that we allocate an extra metadata page,
@@ -101,7 +101,7 @@ func createPerfEvent(cpu, watermark int) (int, error) {
 	attr.Size = uint32(unsafe.Sizeof(attr))
 	fd, err := unix.PerfEventOpen(&attr, -1, cpu, -1, unix.PERF_FLAG_FD_CLOEXEC)
 	if err != nil {
-		return -1, xerrors.Errorf("can't create perf event: %w", err)
+		return -1, fmt.Errorf("can't create perf event: %w", err)
 	}
 	return fd, nil
 }
diff --git a/prog.go b/prog.go
index fd4430b..429203f 100644
--- a/prog.go
+++ b/prog.go
@@ -3,6 +3,7 @@ package ebpf
 import (
 	"bytes"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"math"
 	"strings"
@@ -12,8 +13,6 @@ import (
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/btf"
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
 // ErrNotSupported is returned whenever the kernel doesn't support a feature.
@@ -120,8 +119,8 @@ func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
 	}
 
 	handle, err := btf.NewHandle(btf.ProgramSpec(spec.BTF))
-	if err != nil && !xerrors.Is(err, btf.ErrNotSupported) {
-		return nil, xerrors.Errorf("can't load BTF: %w", err)
+	if err != nil && !errors.Is(err, btf.ErrNotSupported) {
+		return nil, fmt.Errorf("can't load BTF: %w", err)
 	}
 
 	return newProgramWithBTF(spec, handle, opts)
@@ -165,7 +164,7 @@ func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions)
 	}
 
 	err = internal.ErrorWithLog(err, logBuf, logErr)
-	return nil, xerrors.Errorf("can't load program: %w", err)
+	return nil, fmt.Errorf("can't load program: %w", err)
 }
 
 // NewProgramFromFD creates a program from a raw fd.
@@ -175,7 +174,7 @@ func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions)
 // Requires at least Linux 4.11.
 func NewProgramFromFD(fd int) (*Program, error) {
 	if fd < 0 {
-		return nil, xerrors.New("invalid fd")
+		return nil, errors.New("invalid fd")
 	}
 	bpfFd := internal.NewFD(uint32(fd))
 
@@ -198,15 +197,15 @@ func newProgram(fd *internal.FD, name string, abi *ProgramABI) *Program {
 
 func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr, error) {
 	if len(spec.Instructions) == 0 {
-		return nil, xerrors.New("Instructions cannot be empty")
+		return nil, errors.New("Instructions cannot be empty")
 	}
 
 	if len(spec.License) == 0 {
-		return nil, xerrors.New("License cannot be empty")
+		return nil, errors.New("License cannot be empty")
 	}
 
 	if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian {
-		return nil, xerrors.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
+		return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
 	}
 
 	buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize))
@@ -235,7 +234,7 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
 
 		recSize, bytes, err := btf.ProgramLineInfos(spec.BTF)
 		if err != nil {
-			return nil, xerrors.Errorf("can't get BTF line infos: %w", err)
+			return nil, fmt.Errorf("can't get BTF line infos: %w", err)
 		}
 		attr.lineInfoRecSize = recSize
 		attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
@@ -243,7 +242,7 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
 
 		recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF)
 		if err != nil {
-			return nil, xerrors.Errorf("can't get BTF function infos: %w", err)
+			return nil, fmt.Errorf("can't get BTF function infos: %w", err)
 		}
 		attr.funcInfoRecSize = recSize
 		attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
@@ -301,7 +300,7 @@ func (p *Program) Clone() (*Program, error) {
 
 	dup, err := p.fd.Dup()
 	if err != nil {
-		return nil, xerrors.Errorf("can't clone program: %w", err)
+		return nil, fmt.Errorf("can't clone program: %w", err)
 	}
 
 	return newProgram(dup, p.name, &p.abi), nil
@@ -312,7 +311,7 @@ func (p *Program) Clone() (*Program, error) {
 // This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional
 func (p *Program) Pin(fileName string) error {
 	if err := internal.BPFObjPin(fileName, p.fd); err != nil {
-		return xerrors.Errorf("can't pin program: %w", err)
+		return fmt.Errorf("can't pin program: %w", err)
 	}
 	return nil
 }
@@ -336,7 +335,7 @@ func (p *Program) Close() error {
 func (p *Program) Test(in []byte) (uint32, []byte, error) {
 	ret, out, _, err := p.testRun(in, 1, nil)
 	if err != nil {
-		return ret, nil, xerrors.Errorf("can't test program: %w", err)
+		return ret, nil, fmt.Errorf("can't test program: %w", err)
 	}
 	return ret, out, nil
 }
@@ -355,7 +354,7 @@ func (p *Program) Test(in []byte) (uint32, []byte, error) {
 func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.Duration, error) {
 	ret, _, total, err := p.testRun(in, repeat, reset)
 	if err != nil {
-		return ret, total, xerrors.Errorf("can't benchmark program: %w", err)
+		return ret, total, fmt.Errorf("can't benchmark program: %w", err)
 	}
 	return ret, total, nil
 }
@@ -387,7 +386,7 @@ var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() (
 
 	// Check for EINVAL specifically, rather than err != nil since we
 	// otherwise misdetect due to insufficient permissions.
-	return !xerrors.Is(err, unix.EINVAL), nil
+	return !errors.Is(err, unix.EINVAL), nil
 })
 
 func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte, time.Duration, error) {
@@ -434,14 +433,14 @@ func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte,
 			break
 		}
 
-		if xerrors.Is(err, unix.EINTR) {
+		if errors.Is(err, unix.EINTR) {
 			if reset != nil {
 				reset()
 			}
 			continue
 		}
 
-		return 0, nil, 0, xerrors.Errorf("can't run test: %w", err)
+		return 0, nil, 0, fmt.Errorf("can't run test: %w", err)
 	}
 
 	if int(attr.dataSizeOut) > cap(out) {
@@ -457,7 +456,7 @@ func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte,
 
 func unmarshalProgram(buf []byte) (*Program, error) {
 	if len(buf) != 4 {
-		return nil, xerrors.New("program id requires 4 byte value")
+		return nil, errors.New("program id requires 4 byte value")
 	}
 
 	// Looking up an entry in a nested map or prog array returns an id,
@@ -483,7 +482,7 @@ func (p *Program) MarshalBinary() ([]byte, error) {
 // Deprecated: use link.RawAttachProgram instead.
 func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error {
 	if fd < 0 {
-		return xerrors.New("invalid fd")
+		return errors.New("invalid fd")
 	}
 
 	pfd, err := p.fd.Value()
@@ -506,11 +505,11 @@ func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error {
 // Deprecated: use link.RawDetachProgram instead.
 func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error {
 	if fd < 0 {
-		return xerrors.New("invalid fd")
+		return errors.New("invalid fd")
 	}
 
 	if flags != 0 {
-		return xerrors.New("flags must be zero")
+		return errors.New("flags must be zero")
 	}
 
 	pfd, err := p.fd.Value()
@@ -539,7 +538,7 @@ func LoadPinnedProgram(fileName string) (*Program, error) {
 	name, abi, err := newProgramABIFromFd(fd)
 	if err != nil {
 		_ = fd.Close()
-		return nil, xerrors.Errorf("can't get ABI for %s: %w", fileName, err)
+		return nil, fmt.Errorf("can't get ABI for %s: %w", fileName, err)
 	}
 
 	return newProgram(fd, name, abi), nil
@@ -599,7 +598,7 @@ func (p *Program) ID() (ProgramID, error) {
 func resolveBTFType(name string, progType ProgramType, attachType AttachType) (btf.Type, error) {
 	kernel, err := btf.LoadKernelSpec()
 	if err != nil {
-		return nil, xerrors.Errorf("can't resolve BTF type %s: %w", name, err)
+		return nil, fmt.Errorf("can't resolve BTF type %s: %w", name, err)
 	}
 
 	type match struct {
@@ -612,7 +611,7 @@ func resolveBTFType(name string, progType ProgramType, attachType AttachType) (b
 	case match{Tracing, AttachTraceIter}:
 		var target btf.Func
 		if err := kernel.FindType("bpf_iter_"+name, &target); err != nil {
-			return nil, xerrors.Errorf("can't resolve BTF for iterator %s: %w", name, err)
+			return nil, fmt.Errorf("can't resolve BTF for iterator %s: %w", name, err)
 		}
 
 		return &target, nil
diff --git a/syscalls.go b/syscalls.go
index ff98cc4..2b713d0 100644
--- a/syscalls.go
+++ b/syscalls.go
@@ -1,19 +1,19 @@
 package ebpf
 
 import (
+	"errors"
+	"fmt"
 	"os"
 	"unsafe"
 
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/btf"
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
 // Generic errors returned by BPF syscalls.
 var (
-	ErrNotExist = xerrors.New("requested object does not exist")
+	ErrNotExist = errors.New("requested object does not exist")
 )
 
 // bpfObjName is a null-terminated string made up of
@@ -174,8 +174,8 @@ func bpfProgTestRun(attr *bpfProgTestRunAttr) error {
 
 func bpfMapCreate(attr *bpfMapCreateAttr) (*internal.FD, error) {
 	fd, err := internal.BPF(internal.BPF_MAP_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
-	if xerrors.Is(err, os.ErrPermission) {
-		return nil, xerrors.New("permission denied or insufficient rlimit to lock memory for map")
+	if errors.Is(err, os.ErrPermission) {
+		return nil, errors.New("permission denied or insufficient rlimit to lock memory for map")
 	}
 
 	if err != nil {
@@ -317,11 +317,11 @@ func wrapObjError(err error) error {
 	if err == nil {
 		return nil
 	}
-	if xerrors.Is(err, unix.ENOENT) {
-		return xerrors.Errorf("%w", ErrNotExist)
+	if errors.Is(err, unix.ENOENT) {
+		return fmt.Errorf("%w", ErrNotExist)
 	}
 
-	return xerrors.New(err.Error())
+	return errors.New(err.Error())
 }
 
 func wrapMapError(err error) error {
@@ -329,15 +329,15 @@ func wrapMapError(err error) error {
 		return nil
 	}
 
-	if xerrors.Is(err, unix.ENOENT) {
+	if errors.Is(err, unix.ENOENT) {
 		return ErrKeyNotExist
 	}
 
-	if xerrors.Is(err, unix.EEXIST) {
+	if errors.Is(err, unix.EEXIST) {
 		return ErrKeyExist
 	}
 
-	return xerrors.New(err.Error())
+	return errors.New(err.Error())
 }
 
 func bpfMapFreeze(m *internal.FD) error {
@@ -367,7 +367,7 @@ func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) er
 	}
 	_, err = internal.BPF(internal.BPF_OBJ_GET_INFO_BY_FD, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 	if err != nil {
-		return xerrors.Errorf("fd %d: %w", fd, err)
+		return fmt.Errorf("fd %d: %w", fd, err)
 	}
 	return nil
 }
@@ -375,7 +375,7 @@ func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) er
 func bpfGetProgInfoByFD(fd *internal.FD) (*bpfProgInfo, error) {
 	var info bpfProgInfo
 	if err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil {
-		return nil, xerrors.Errorf("can't get program info: %w", err)
+		return nil, fmt.Errorf("can't get program info: %w", err)
 	}
 	return &info, nil
 }
@@ -384,7 +384,7 @@ func bpfGetMapInfoByFD(fd *internal.FD) (*bpfMapInfo, error) {
 	var info bpfMapInfo
 	err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
 	if err != nil {
-		return nil, xerrors.Errorf("can't get map info: %w", err)
+		return nil, fmt.Errorf("can't get map info: %w", err)
 	}
 	return &info, nil
 }


Test patch:
diff --git a/example_program_test.go b/example_program_test.go
index a9a1d0e..debac07 100644
--- a/example_program_test.go
+++ b/example_program_test.go
@@ -8,8 +8,8 @@ import (
 	"io/ioutil"
 	"os"
 	"strconv"
+	"strings"
 	"time"
-      "strings"
 
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/asm"
@@ -24,8 +24,8 @@ func getTracepointID() (uint64, error) {
 	if err != nil {
 		return 0, fmt.Errorf("failed to read tracepoint ID for 'sys_enter_open': %v", err)
 	}
-      tid := strings.TrimSuffix(string(data), "\n")
-      return strconv.ParseUint(tid, 10, 64)
+	tid := strings.TrimSuffix(string(data), "\n")
+	return strconv.ParseUint(tid, 10, 64)
 }
 
 // Example_program demonstrates how to attach an eBPF program to a tracepoint.
diff --git a/internal/btf/btf_test.go b/internal/btf/btf_test.go
index bf6d43f..1dc2eda 100644
--- a/internal/btf/btf_test.go
+++ b/internal/btf/btf_test.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"compress/gzip"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -11,7 +12,6 @@ import (
 
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/testutils"
-	"golang.org/x/xerrors"
 )
 
 func TestParseVmlinux(t *testing.T) {
@@ -39,7 +39,7 @@ func TestParseVmlinux(t *testing.T) {
 
 func TestParseCurrentKernelBTF(t *testing.T) {
 	spec, err := loadKernelSpec()
-	if xerrors.Is(err, ErrNotFound) {
+	if errors.Is(err, ErrNotFound) {
 		t.Skip("BTF is not available:", err)
 	}
 	if err != nil {
@@ -86,7 +86,7 @@ func TestLoadSpecFromElf(t *testing.T) {
 		}
 
 		var tmp Void
-		if err := spec.FindType("totally_bogus_type", &tmp); !xerrors.Is(err, ErrNotFound) {
+		if err := spec.FindType("totally_bogus_type", &tmp); !errors.Is(err, ErrNotFound) {
 			t.Error("FindType doesn't return ErrNotFound:", err)
 		}
 
diff --git a/internal/feature_test.go b/internal/feature_test.go
index 163e6d8..895a391 100644
--- a/internal/feature_test.go
+++ b/internal/feature_test.go
@@ -1,10 +1,10 @@
 package internal
 
 import (
+	"errors"
+	"fmt"
 	"strings"
 	"testing"
-
-	"golang.org/x/xerrors"
 )
 
 func TestFeatureTest(t *testing.T) {
@@ -46,12 +46,12 @@ func TestFeatureTest(t *testing.T) {
 		t.Error("UnsupportedFeatureError.Error doesn't contain version")
 	}
 
-	if !xerrors.Is(err, ErrNotSupported) {
+	if !errors.Is(err, ErrNotSupported) {
 		t.Error("UnsupportedFeatureError is not ErrNotSupported")
 	}
 
 	fn = FeatureTest("bar", "2.1.1", func() (bool, error) {
-		return false, xerrors.New("foo")
+		return false, errors.New("foo")
 	})
 
 	err1, err2 := fn(), fn()
@@ -60,7 +60,7 @@ func TestFeatureTest(t *testing.T) {
 	}
 
 	fn = FeatureTest("bar", "2.1.1", func() (bool, error) {
-		return false, xerrors.Errorf("bar: %w", ErrNotSupported)
+		return false, fmt.Errorf("bar: %w", ErrNotSupported)
 	})
 
 	err1, err2 = fn(), fn()
diff --git a/internal/testutils/feature.go b/internal/testutils/feature.go
index b02b680..7ab8541 100644
--- a/internal/testutils/feature.go
+++ b/internal/testutils/feature.go
@@ -2,12 +2,12 @@ package testutils
 
 import (
 	"bytes"
+	"errors"
 	"sync"
 	"testing"
 
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/unix"
-	"golang.org/x/xerrors"
 )
 
 var (
@@ -44,7 +44,7 @@ func CheckFeatureTest(t *testing.T, fn func() error) {
 	}
 
 	var ufe *internal.UnsupportedFeatureError
-	if xerrors.As(err, &ufe) {
+	if errors.As(err, &ufe) {
 		checkKernelVersion(t, ufe)
 	} else {
 		t.Error("Feature test failed:", err)
@@ -53,11 +53,11 @@ func CheckFeatureTest(t *testing.T, fn func() error) {
 
 func SkipIfNotSupported(tb testing.TB, err error) {
 	var ufe *internal.UnsupportedFeatureError
-	if xerrors.As(err, &ufe) {
+	if errors.As(err, &ufe) {
 		checkKernelVersion(tb, ufe)
 		tb.Skip(ufe.Error())
 	}
-	if xerrors.Is(err, internal.ErrNotSupported) {
+	if errors.Is(err, internal.ErrNotSupported) {
 		tb.Skip(err.Error())
 	}
 }
diff --git a/link/iter_test.go b/link/iter_test.go
index 5e1bac0..3db91e3 100644
--- a/link/iter_test.go
+++ b/link/iter_test.go
@@ -1,14 +1,13 @@
 package link
 
 import (
+	"errors"
 	"io/ioutil"
 	"testing"
 
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/internal/btf"
-
-	"golang.org/x/xerrors"
 )
 
 func TestIter(t *testing.T) {
@@ -22,7 +21,7 @@ func TestIter(t *testing.T) {
 		},
 		License: "MIT",
 	})
-	if xerrors.Is(err, btf.ErrNotFound) {
+	if errors.Is(err, btf.ErrNotFound) {
 		t.Skip("Kernel doesn't support iter:", err)
 	}
 	if err != nil {
diff --git a/link/link_test.go b/link/link_test.go
index b53acef..cc0a587 100644
--- a/link/link_test.go
+++ b/link/link_test.go
@@ -1,6 +1,7 @@
 package link
 
 import (
+	"errors"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -10,8 +11,6 @@ import (
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/internal/testutils"
-
-	"golang.org/x/xerrors"
 )
 
 func TestRawLink(t *testing.T) {
@@ -101,7 +100,7 @@ func testLink(t *testing.T, link Link, opts testLinkOptions) {
 	}
 
 	if opts.loadPinned == nil {
-		if !xerrors.Is(err, ErrNotSupported) {
+		if !errors.Is(err, ErrNotSupported) {
 			t.Errorf("%T.Pin doesn't return ErrNotSupported: %s", link, err)
 		}
 	} else {
diff --git a/map_test.go b/map_test.go
index 7dbc8cf..e4d7237 100644
--- a/map_test.go
+++ b/map_test.go
@@ -1,6 +1,7 @@
 package ebpf
 
 import (
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"math"
@@ -14,8 +15,6 @@ import (
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/testutils"
 	"github.com/cilium/ebpf/internal/unix"
-
-	"golang.org/x/xerrors"
 )
 
 func TestMain(m *testing.M) {
@@ -75,11 +74,11 @@ func TestMapClose(t *testing.T) {
 		t.Fatal("Can't close map:", err)
 	}
 
-	if err := m.Put(uint32(0), uint32(42)); !xerrors.Is(err, internal.ErrClosedFd) {
+	if err := m.Put(uint32(0), uint32(42)); !errors.Is(err, internal.ErrClosedFd) {
 		t.Fatal("Put doesn't check for closed fd", err)
 	}
 
-	if _, err := m.LookupBytes(uint32(0)); !xerrors.Is(err, internal.ErrClosedFd) {
+	if _, err := m.LookupBytes(uint32(0)); !errors.Is(err, internal.ErrClosedFd) {
 		t.Fatal("Get doesn't check for closed fd", err)
 	}
 }
@@ -201,7 +200,7 @@ func TestMapQueue(t *testing.T) {
 		t.Error("Want value 4242, got", v)
 	}
 
-	if err := m.LookupAndDelete(nil, &v); !xerrors.Is(err, ErrKeyNotExist) {
+	if err := m.LookupAndDelete(nil, &v); !errors.Is(err, ErrKeyNotExist) {
 		t.Fatal("Lookup and delete on empty Queue:", err)
 	}
 }
@@ -435,7 +434,7 @@ func TestNotExist(t *testing.T) {
 
 	var tmp uint32
 	err := hash.Lookup("hello", &tmp)
-	if !xerrors.Is(err, ErrKeyNotExist) {
+	if !errors.Is(err, ErrKeyNotExist) {
 		t.Error("Lookup doesn't return ErrKeyNotExist")
 	}
 
@@ -447,11 +446,11 @@ func TestNotExist(t *testing.T) {
 		t.Error("LookupBytes returns non-nil buffer for non-existent key")
 	}
 
-	if err := hash.Delete("hello"); !xerrors.Is(err, ErrKeyNotExist) {
+	if err := hash.Delete("hello"); !errors.Is(err, ErrKeyNotExist) {
 		t.Error("Deleting unknown key doesn't return ErrKeyNotExist")
 	}
 
-	if err := hash.NextKey(nil, &tmp); !xerrors.Is(err, ErrKeyNotExist) {
+	if err := hash.NextKey(nil, &tmp); !errors.Is(err, ErrKeyNotExist) {
 		t.Error("Looking up next key in empty map doesn't return a non-existing error")
 	}
 }
@@ -464,7 +463,7 @@ func TestExist(t *testing.T) {
 		t.Errorf("Failed to put key/value pair into hash: %v", err)
 	}
 
-	if err := hash.Update("hello", uint32(42), UpdateNoExist); !xerrors.Is(err, ErrKeyExist) {
+	if err := hash.Update("hello", uint32(42), UpdateNoExist); !errors.Is(err, ErrKeyExist) {
 		t.Error("Updating existing key doesn't return ErrKeyExist")
 	}
 }
@@ -731,7 +730,7 @@ func TestMapGetNextID(t *testing.T) {
 	for {
 		last := next
 		if next, err = MapGetNextID(last); err != nil {
-			if !xerrors.Is(err, ErrNotExist) {
+			if !errors.Is(err, ErrNotExist) {
 				t.Fatal("Expected ErrNotExist, got:", err)
 			}
 			break
@@ -761,7 +760,7 @@ func TestNewMapFromID(t *testing.T) {
 
 	// As there can be multiple maps, we use max(uint32) as MapID to trigger an expected error.
 	_, err = NewMapFromID(MapID(math.MaxUint32))
-	if !xerrors.Is(err, ErrNotExist) {
+	if !errors.Is(err, ErrNotExist) {
 		t.Fatal("Expected ErrNotExist, got:", err)
 	}
 }
@@ -920,7 +919,7 @@ func BenchmarkMap(b *testing.B) {
 
 		for i := 0; i < b.N; i++ {
 			err := m.Delete(unsafe.Pointer(&key))
-			if err != nil && !xerrors.Is(err, ErrKeyNotExist) {
+			if err != nil && !errors.Is(err, ErrKeyNotExist) {
 				b.Fatal(err)
 			}
 		}
diff --git a/prog_test.go b/prog_test.go
index f896cc6..1e2da96 100644
--- a/prog_test.go
+++ b/prog_test.go
@@ -3,6 +3,7 @@ package ebpf
 import (
 	"bytes"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"math"
@@ -18,7 +19,6 @@ import (
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/testutils"
 	"github.com/cilium/ebpf/internal/unix"
-	"golang.org/x/xerrors"
 )
 
 func TestProgramRun(t *testing.T) {
@@ -271,7 +271,7 @@ func TestProgramVerifierOutput(t *testing.T) {
 	}
 
 	var ve *internal.VerifierError
-	if !xerrors.As(err, &ve) {
+	if !errors.As(err, &ve) {
 		t.Error("Error is not a VerifierError")
 	}
 }
@@ -421,7 +421,7 @@ func TestProgramGetNextID(t *testing.T) {
 	for {
 		last := next
 		if next, err = ProgramGetNextID(last); err != nil {
-			if !xerrors.Is(err, ErrNotExist) {
+			if !errors.Is(err, ErrNotExist) {
 				t.Fatal("Expected ErrNotExist, got:", err)
 			}
 			break
@@ -460,7 +460,7 @@ func TestNewProgramFromID(t *testing.T) {
 
 	// As there can be multiple programs, we use max(uint32) as ProgramID to trigger an expected error.
 	_, err = NewProgramFromID(ProgramID(math.MaxUint32))
-	if !xerrors.Is(err, ErrNotExist) {
+	if !errors.Is(err, ErrNotExist) {
 		t.Fatal("Expected ErrNotExist, got:", err)
 	}
 }