From a00bb51c0fcffce4ad9e20cf19e74d25281fc80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iago=20L=C3=B3pez=20Galeiras?= Date: Mon, 9 Jan 2017 14:26:13 +0100 Subject: [PATCH] Add iovisor/gobpf dependency --- .../iovisor/gobpf/elf/COPYRIGHT.txt | 14 + .../github.com/iovisor/gobpf/elf/LICENSE.txt | 201 +++++++ vendor/github.com/iovisor/gobpf/elf/elf.go | 546 ++++++++++++++++++ .../iovisor/gobpf/elf/elf_unsupported.go | 33 ++ .../iovisor/gobpf/elf/kernel_version.go | 107 ++++ vendor/github.com/iovisor/gobpf/elf/module.go | 157 +++++ .../iovisor/gobpf/elf/module_unsupported.go | 24 + vendor/github.com/iovisor/gobpf/elf/perf.go | 291 ++++++++++ .../iovisor/gobpf/elf/perf_unsupported.go | 15 + vendor/github.com/iovisor/gobpf/elf/table.go | 108 ++++ .../iovisor/gobpf/elf/utsname_int8.go | 14 + .../iovisor/gobpf/elf/utsname_uint8.go | 14 + vendor/manifest | 11 +- 13 files changed, 1534 insertions(+), 1 deletion(-) create mode 100644 vendor/github.com/iovisor/gobpf/elf/COPYRIGHT.txt create mode 100644 vendor/github.com/iovisor/gobpf/elf/LICENSE.txt create mode 100644 vendor/github.com/iovisor/gobpf/elf/elf.go create mode 100644 vendor/github.com/iovisor/gobpf/elf/elf_unsupported.go create mode 100644 vendor/github.com/iovisor/gobpf/elf/kernel_version.go create mode 100644 vendor/github.com/iovisor/gobpf/elf/module.go create mode 100644 vendor/github.com/iovisor/gobpf/elf/module_unsupported.go create mode 100644 vendor/github.com/iovisor/gobpf/elf/perf.go create mode 100644 vendor/github.com/iovisor/gobpf/elf/perf_unsupported.go create mode 100644 vendor/github.com/iovisor/gobpf/elf/table.go create mode 100644 vendor/github.com/iovisor/gobpf/elf/utsname_int8.go create mode 100644 vendor/github.com/iovisor/gobpf/elf/utsname_uint8.go diff --git a/vendor/github.com/iovisor/gobpf/elf/COPYRIGHT.txt b/vendor/github.com/iovisor/gobpf/elf/COPYRIGHT.txt new file mode 100644 index 0000000000..1eae73fb26 --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/COPYRIGHT.txt @@ -0,0 +1,14 @@ +Copyright 2016 PLUMgrid +Copyright 2016 Kinvolk + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/iovisor/gobpf/elf/LICENSE.txt b/vendor/github.com/iovisor/gobpf/elf/LICENSE.txt new file mode 100644 index 0000000000..8dada3edaf --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/iovisor/gobpf/elf/elf.go b/vendor/github.com/iovisor/gobpf/elf/elf.go new file mode 100644 index 0000000000..eb133ec61b --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/elf.go @@ -0,0 +1,546 @@ +// +build linux + +// Copyright 2016 Cilium Project +// Copyright 2016 Sylvain Afchain +// Copyright 2016 Kinvolk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package elf + +import ( + "bytes" + "debug/elf" + "encoding/binary" + "errors" + "fmt" + "io" + "os" + "strings" + "syscall" + "unsafe" +) + +/* +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// from https://github.com/safchain/goebpf +// Apache License, Version 2.0 + +typedef struct bpf_map_def { + unsigned int type; + unsigned int key_size; + unsigned int value_size; + unsigned int max_entries; +} bpf_map_def; + +typedef struct bpf_map { + int fd; + bpf_map_def def; +} bpf_map; + +__u64 ptr_to_u64(void *ptr) +{ + return (__u64) (unsigned long) ptr; +} + +static void bpf_apply_relocation(int fd, struct bpf_insn *insn) +{ + insn->src_reg = BPF_PSEUDO_MAP_FD; + insn->imm = fd; +} + +static int bpf_create_map(enum bpf_map_type map_type, int key_size, + int value_size, int max_entries) +{ + int ret; + union bpf_attr attr; + memset(&attr, 0, sizeof(attr)); + + attr.map_type = map_type; + attr.key_size = key_size; + attr.value_size = value_size; + attr.max_entries = max_entries; + + ret = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); + if (ret < 0 && errno == EPERM) { + // When EPERM is returned, two reasons are possible: + // 1. user has no permissions for bpf() + // 2. user has insufficent rlimit for locked memory + // Unfortunately, there is no api to inspect the current usage of locked + // mem for the user, so an accurate calculation of how much memory to lock + // for this new program is difficult to calculate. As a hack, bump the limit + // to unlimited. If program load fails again, return the error. + + struct rlimit rl = {}; + if (getrlimit(RLIMIT_MEMLOCK, &rl) == 0) { + rl.rlim_max = RLIM_INFINITY; + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_MEMLOCK, &rl) == 0) { + ret = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); + } + else { + printf("setrlimit() failed with errno=%d\n", errno); + return -1; + } + } + } + + return ret; +} + +static bpf_map *bpf_load_map(bpf_map_def *map_def) +{ + bpf_map *map; + + map = calloc(1, sizeof(bpf_map)); + if (map == NULL) + return NULL; + + memcpy(&map->def, map_def, sizeof(bpf_map_def)); + + map->fd = bpf_create_map(map_def->type, + map_def->key_size, + map_def->value_size, + map_def->max_entries + ); + + if (map->fd < 0) + return 0; + + return map; +} + +static int bpf_prog_load(enum bpf_prog_type prog_type, + const struct bpf_insn *insns, int prog_len, + const char *license, int kern_version, + char *log_buf, int log_size) +{ + int ret; + union bpf_attr attr; + memset(&attr, 0, sizeof(attr)); + + attr.prog_type = prog_type; + attr.insn_cnt = prog_len / sizeof(struct bpf_insn); + attr.insns = ptr_to_u64((void *) insns); + attr.license = ptr_to_u64((void *) license); + attr.log_buf = ptr_to_u64(log_buf); + attr.log_size = log_size; + attr.log_level = 1; + attr.kern_version = kern_version; + + ret = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); + if (ret < 0 && errno == EPERM) { + // When EPERM is returned, two reasons are possible: + // 1. user has no permissions for bpf() + // 2. user has insufficent rlimit for locked memory + // Unfortunately, there is no api to inspect the current usage of locked + // mem for the user, so an accurate calculation of how much memory to lock + // for this new program is difficult to calculate. As a hack, bump the limit + // to unlimited. If program load fails again, return the error. + + struct rlimit rl = {}; + if (getrlimit(RLIMIT_MEMLOCK, &rl) == 0) { + rl.rlim_max = RLIM_INFINITY; + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_MEMLOCK, &rl) == 0) { + ret = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); + } + else { + printf("setrlimit() failed with errno=%d\n", errno); + return -1; + } + } + } + + return ret; +} + +static int bpf_update_element(int fd, void *key, void *value, unsigned long long flags) +{ + union bpf_attr attr = { + .map_fd = fd, + .key = ptr_to_u64(key), + .value = ptr_to_u64(value), + .flags = flags, + }; + + return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); +} + + +static int perf_event_open_map(int pid, int cpu, int group_fd, unsigned long flags) +{ + struct perf_event_attr attr = {0,}; + attr.type = PERF_TYPE_SOFTWARE; + attr.sample_type = PERF_SAMPLE_RAW; + attr.wakeup_events = 1; + + attr.size = sizeof(struct perf_event_attr); + attr.config = 10; // PERF_COUNT_SW_BPF_OUTPUT + + return syscall(__NR_perf_event_open, &attr, pid, cpu, + group_fd, flags); +} +*/ +import "C" + +const useCurrentKernelVersion = 0xFFFFFFFE + +// Based on https://github.com/safchain/goebpf +// Apache License + +func elfReadLicense(file *elf.File) (string, error) { + if lsec := file.Section("license"); lsec != nil { + data, err := lsec.Data() + if err != nil { + return "", err + } + return string(data), nil + } + return "", nil +} + +func elfReadVersion(file *elf.File) (uint32, error) { + if vsec := file.Section("version"); vsec != nil { + data, err := vsec.Data() + if err != nil { + return 0, err + } + if len(data) != 4 { + return 0, errors.New("version is not a __u32") + } + version := *(*C.uint32_t)(unsafe.Pointer(&data[0])) + if err != nil { + return 0, err + } + return uint32(version), nil + } + return 0, nil +} + +func elfReadMaps(file *elf.File) (map[string]*Map, error) { + maps := make(map[string]*Map) + for sectionIdx, section := range file.Sections { + if strings.HasPrefix(section.Name, "maps/") { + data, err := section.Data() + if err != nil { + return nil, err + } + + name := strings.TrimPrefix(section.Name, "maps/") + + mapCount := len(data) / C.sizeof_struct_bpf_map_def + for i := 0; i < mapCount; i++ { + pos := i * C.sizeof_struct_bpf_map_def + cm := C.bpf_load_map((*C.bpf_map_def)(unsafe.Pointer(&data[pos]))) + if cm == nil { + return nil, fmt.Errorf("error while loading map %s", section.Name) + } + + m := &Map{ + Name: name, + SectionIdx: sectionIdx, + Idx: i, + m: cm, + } + + if oldMap, ok := maps[name]; ok { + return nil, fmt.Errorf("duplicate map: %q (section %q) and %q (section %q)", + oldMap.Name, file.Sections[oldMap.SectionIdx].Name, + name, section.Name) + } + maps[name] = m + } + } + } + return maps, nil +} + +func (b *Module) relocate(data []byte, rdata []byte) error { + var symbol elf.Symbol + var offset uint64 + + symbols, err := b.file.Symbols() + if err != nil { + return err + } + + br := bytes.NewReader(data) + + for { + switch b.file.Class { + case elf.ELFCLASS64: + var rel elf.Rel64 + err := binary.Read(br, b.file.ByteOrder, &rel) + if err != nil { + if err == io.EOF { + return nil + } + return err + } + + symNo := rel.Info >> 32 + symbol = symbols[symNo-1] + + offset = rel.Off + case elf.ELFCLASS32: + var rel elf.Rel32 + err := binary.Read(br, b.file.ByteOrder, &rel) + if err != nil { + if err == io.EOF { + return nil + } + return err + } + + symNo := rel.Info >> 8 + symbol = symbols[symNo-1] + + offset = uint64(rel.Off) + default: + return errors.New("architecture not supported") + } + + rinsn := (*C.struct_bpf_insn)(unsafe.Pointer(&rdata[offset])) + if rinsn.code != (C.BPF_LD | C.BPF_IMM | C.BPF_DW) { + return errors.New("invalid relocation") + } + + symbolSec := b.file.Sections[symbol.Section] + if !strings.HasPrefix(symbolSec.Name, "maps/") { + return fmt.Errorf("map location not supported: map %q is in section %q instead of \"maps/%s\"", + symbol.Name, symbolSec.Name, symbol.Name) + } + name := strings.TrimPrefix(symbolSec.Name, "maps/") + + m := b.Map(name) + if m == nil { + return fmt.Errorf("relocation error, symbol %q not found in section %q", + symbol.Name, symbolSec.Name) + } + + C.bpf_apply_relocation(m.m.fd, rinsn) + } +} + +func (b *Module) Load() error { + fileReader, err := os.Open(b.fileName) + if err != nil { + return err + } + + b.file, err = elf.NewFile(fileReader) + if err != nil { + return err + } + defer fileReader.Close() + + license, err := elfReadLicense(b.file) + if err != nil { + return err + } + + lp := unsafe.Pointer(C.CString(license)) + defer C.free(lp) + + version, err := elfReadVersion(b.file) + if err != nil { + return err + } + if version == useCurrentKernelVersion { + version, err = currentVersion() + if err != nil { + return err + } + } + + maps, err := elfReadMaps(b.file) + if err != nil { + return err + } + b.maps = maps + + processed := make([]bool, len(b.file.Sections)) + for i, section := range b.file.Sections { + if processed[i] { + continue + } + + data, err := section.Data() + if err != nil { + return err + } + + if len(data) == 0 { + continue + } + + if section.Type == elf.SHT_REL { + rsection := b.file.Sections[section.Info] + + processed[i] = true + processed[section.Info] = true + + secName := rsection.Name + isKprobe := strings.HasPrefix(secName, "kprobe/") + isKretprobe := strings.HasPrefix(secName, "kretprobe/") + + if isKprobe || isKretprobe { + rdata, err := rsection.Data() + if err != nil { + return err + } + + if len(rdata) == 0 { + continue + } + + err = b.relocate(data, rdata) + if err != nil { + return err + } + + insns := (*C.struct_bpf_insn)(unsafe.Pointer(&rdata[0])) + + progFd := C.bpf_prog_load(C.BPF_PROG_TYPE_KPROBE, + insns, C.int(rsection.Size), + (*C.char)(lp), C.int(version), + (*C.char)(unsafe.Pointer(&b.log[0])), C.int(len(b.log))) + if progFd < 0 { + return fmt.Errorf("error while loading %q:\n%s", secName, b.log) + } + b.probes[secName] = &Kprobe{ + Name: secName, + insns: insns, + fd: int(progFd), + } + } + } + } + + for i, section := range b.file.Sections { + if processed[i] { + continue + } + + if strings.HasPrefix(section.Name, "kprobe/") || strings.HasPrefix(section.Name, "kretprobe/") { + data, err := section.Data() + if err != nil { + return err + } + + if len(data) == 0 { + continue + } + + insns := (*C.struct_bpf_insn)(unsafe.Pointer(&data[0])) + + fd := C.bpf_prog_load(C.BPF_PROG_TYPE_KPROBE, + insns, C.int(section.Size), + (*C.char)(lp), C.int(version), + (*C.char)(unsafe.Pointer(&b.log[0])), C.int(len(b.log))) + if fd < 0 { + return fmt.Errorf("error while loading %q:\n%s", section.Name, b.log) + } + b.probes[section.Name] = &Kprobe{ + Name: section.Name, + fd: int(fd), + } + } + } + + for name, _ := range b.maps { + var cpu C.int = 0 + + for { + pmuFD := C.perf_event_open_map(-1 /* pid */, cpu /* cpu */, -1 /* group_fd */, C.PERF_FLAG_FD_CLOEXEC) + if pmuFD < 0 { + if cpu == 0 { + return fmt.Errorf("perf_event_open for map error: %v", err) + } + break + } + + // mmap + pageSize := os.Getpagesize() + pageCount := 8 + mmapSize := pageSize * (pageCount + 1) + + base, err := syscall.Mmap(int(pmuFD), 0, mmapSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED) + if err != nil { + return fmt.Errorf("mmap error: %v", err) + } + + // enable + _, _, err2 := syscall.Syscall(syscall.SYS_IOCTL, uintptr(pmuFD), C.PERF_EVENT_IOC_ENABLE, 0) + if err2 != 0 { + return fmt.Errorf("error enabling perf event: %v", err2) + } + + // assign perf fd tp map + ret, err := C.bpf_update_element(C.int(b.maps[name].m.fd), unsafe.Pointer(&cpu), unsafe.Pointer(&pmuFD), C.BPF_ANY) + if ret != 0 { + return fmt.Errorf("cannot assign perf fd to map %q: %s (cpu %d)", name, err, cpu) + } + + b.maps[name].pmuFDs = append(b.maps[name].pmuFDs, pmuFD) + b.maps[name].headers = append(b.maps[name].headers, (*C.struct_perf_event_mmap_page)(unsafe.Pointer(&base[0]))) + + cpu++ + } + } + return nil +} + +// Map represents a eBPF map. An eBPF map has to be declared in the +// C file. +type Map struct { + Name string + SectionIdx int + Idx int + m *C.bpf_map + + // only for perf maps + pmuFDs []C.int + headers []*C.struct_perf_event_mmap_page +} + +func (b *Module) IterMaps() <-chan *Map { + ch := make(chan *Map) + go func() { + for name := range b.maps { + ch <- b.maps[name] + } + close(ch) + }() + return ch +} + +func (b *Module) Map(name string) *Map { + return b.maps[name] +} diff --git a/vendor/github.com/iovisor/gobpf/elf/elf_unsupported.go b/vendor/github.com/iovisor/gobpf/elf/elf_unsupported.go new file mode 100644 index 0000000000..4c408e3fb8 --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/elf_unsupported.go @@ -0,0 +1,33 @@ +// +build !linux + +package elf + +import ( + "fmt" +) + +func (b *Module) Load() error { + return fmt.Errorf("not supported") +} + +// not supported; dummy struct +type BPFKProbePerf struct{} + +func NewBpfPerfEvent(fileName string) *BPFKProbePerf { + // not supported + return nil +} + +func (b *BPFKProbePerf) Load() error { + return fmt.Errorf("not supported") +} + +func (b *BPFKProbePerf) PollStart(mapName string, receiverChan chan []byte) { + // not supported + return +} + +func (b *BPFKProbePerf) PollStop(mapName string) { + // not supported + return +} diff --git a/vendor/github.com/iovisor/gobpf/elf/kernel_version.go b/vendor/github.com/iovisor/gobpf/elf/kernel_version.go new file mode 100644 index 0000000000..83ea52e718 --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/kernel_version.go @@ -0,0 +1,107 @@ +// +build linux + +// Copyright 2016-2017 Kinvolk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package elf + +import ( + "fmt" + "io/ioutil" + "regexp" + "strconv" + "strings" + "syscall" +) + +var versionRegex = regexp.MustCompile(`^(\d+)\.(\d+).(\d+).*$`) + +func kernelVersionFromReleaseString(releaseString string) (uint32, error) { + versionParts := versionRegex.FindStringSubmatch(releaseString) + if len(versionParts) != 4 { + return 0, fmt.Errorf("got invalid release version %q (expected format '4.3.2-1')", releaseString) + } + major, err := strconv.Atoi(versionParts[1]) + if err != nil { + return 0, err + } + + minor, err := strconv.Atoi(versionParts[2]) + if err != nil { + return 0, err + } + + patch, err := strconv.Atoi(versionParts[3]) + if err != nil { + return 0, err + } + out := major*256*256 + minor*256 + patch + return uint32(out), nil +} + +func currentVersionUname() (uint32, error) { + var buf syscall.Utsname + if err := syscall.Uname(&buf); err != nil { + return 0, err + } + releaseString := strings.Trim(utsnameStr(buf.Release[:]), "\x00") + return kernelVersionFromReleaseString(releaseString) +} + +func currentVersionUbuntu() (uint32, error) { + procVersion, err := ioutil.ReadFile("/proc/version_signature") + if err != nil { + return 0, err + } + var u1, u2, releaseString string + _, err = fmt.Sscanf(string(procVersion), "%s %s %s", &u1, &u2, &releaseString) + if err != nil { + return 0, err + } + return kernelVersionFromReleaseString(releaseString) +} + +var debianVersionRegex = regexp.MustCompile(`.* SMP Debian (\d+\.\d+.\d+-\d+) .*`) + +func currentVersionDebian() (uint32, error) { + procVersion, err := ioutil.ReadFile("/proc/version") + if err != nil { + return 0, err + } + match := debianVersionRegex.FindStringSubmatch(string(procVersion)) + if len(match) != 2 { + return 0, fmt.Errorf("failed to get kernel version from /proc/version: %s", procVersion) + } + return kernelVersionFromReleaseString(match[1]) +} + +func currentVersion() (uint32, error) { + // We need extra checks for Debian and Ubuntu as they modify + // the kernel version patch number for compatibilty with + // out-of-tree modules. Linux perf tools do the same for Ubuntu + // systems: https://github.com/torvalds/linux/commit/d18acd15c + // + // See also: + // https://kernel-handbook.alioth.debian.org/ch-versions.html + // https://wiki.ubuntu.com/Kernel/FAQ + version, err := currentVersionUbuntu() + if err == nil { + return version, nil + } + version, err = currentVersionDebian() + if err == nil { + return version, nil + } + return currentVersionUname() +} diff --git a/vendor/github.com/iovisor/gobpf/elf/module.go b/vendor/github.com/iovisor/gobpf/elf/module.go new file mode 100644 index 0000000000..bb1dd85b26 --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/module.go @@ -0,0 +1,157 @@ +// +build linux + +// Copyright 2016 Cilium Project +// Copyright 2016 Sylvain Afchain +// Copyright 2016 Kinvolk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package elf + +import ( + "debug/elf" + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" + "syscall" +) + +/* +#include +#include +#include +#include + +static int perf_event_open_tracepoint(int tracepoint_id, int pid, int cpu, + int group_fd, unsigned long flags) +{ + struct perf_event_attr attr = {0,}; + attr.type = PERF_TYPE_TRACEPOINT; + attr.sample_type = PERF_SAMPLE_RAW; + attr.sample_period = 1; + attr.wakeup_events = 1; + attr.config = tracepoint_id; + + return syscall(__NR_perf_event_open, &attr, pid, cpu, + group_fd, flags); +} +*/ +import "C" + +type Module struct { + fileName string + file *elf.File + + log []byte + maps map[string]*Map + probes map[string]*Kprobe +} + +// Kprobe represents a kprobe or kretprobe and has to be declared +// in the C file, +type Kprobe struct { + Name string + insns *C.struct_bpf_insn + fd int + efd int +} + +func NewModule(fileName string) *Module { + return &Module{ + fileName: fileName, + probes: make(map[string]*Kprobe), + log: make([]byte, 65536), + } +} + +func (b *Module) EnableKprobe(secName string) error { + var probeType, funcName string + isKretprobe := strings.HasPrefix(secName, "kretprobe/") + probe, ok := b.probes[secName] + if !ok { + return fmt.Errorf("no such kprobe %q", secName) + } + progFd := probe.fd + if isKretprobe { + probeType = "r" + funcName = strings.TrimPrefix(secName, "kretprobe/") + } else { + probeType = "p" + funcName = strings.TrimPrefix(secName, "kprobe/") + } + eventName := probeType + funcName + + kprobeEventsFileName := "/sys/kernel/debug/tracing/kprobe_events" + f, err := os.OpenFile(kprobeEventsFileName, os.O_APPEND|os.O_WRONLY, 0666) + if err != nil { + return fmt.Errorf("cannot open kprobe_events: %v\n", err) + } + defer f.Close() + + cmd := fmt.Sprintf("%s:%s %s\n", probeType, eventName, funcName) + _, err = f.WriteString(cmd) + if err != nil { + return fmt.Errorf("cannot write %q to kprobe_events: %v\n", cmd, err) + } + + kprobeIdFile := fmt.Sprintf("/sys/kernel/debug/tracing/events/kprobes/%s/id", eventName) + kprobeIdBytes, err := ioutil.ReadFile(kprobeIdFile) + if err != nil { + return fmt.Errorf("cannot read kprobe id: %v\n", err) + } + kprobeId, err := strconv.Atoi(strings.TrimSpace(string(kprobeIdBytes))) + if err != nil { + return fmt.Errorf("invalid kprobe id): %v\n", err) + } + + efd := C.perf_event_open_tracepoint(C.int(kprobeId), -1 /* pid */, 0 /* cpu */, -1 /* group_fd */, C.PERF_FLAG_FD_CLOEXEC) + if efd < 0 { + return fmt.Errorf("perf_event_open for kprobe error") + } + + _, _, err2 := syscall.Syscall(syscall.SYS_IOCTL, uintptr(efd), C.PERF_EVENT_IOC_ENABLE, 0) + if err2 != 0 { + return fmt.Errorf("error enabling perf event: %v", err2) + } + + _, _, err2 = syscall.Syscall(syscall.SYS_IOCTL, uintptr(efd), C.PERF_EVENT_IOC_SET_BPF, uintptr(progFd)) + if err2 != 0 { + return fmt.Errorf("error enabling perf event: %v", err2) + } + probe.efd = int(efd) + return nil +} + +func (b *Module) IterKprobes() <-chan *Kprobe { + ch := make(chan *Kprobe) + go func() { + for name := range b.probes { + ch <- b.probes[name] + } + close(ch) + }() + return ch +} + +func (b *Module) EnableKprobes() error { + var err error + for _, kprobe := range b.probes { + err = b.EnableKprobe(kprobe.Name) + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/iovisor/gobpf/elf/module_unsupported.go b/vendor/github.com/iovisor/gobpf/elf/module_unsupported.go new file mode 100644 index 0000000000..82a16b9d78 --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/module_unsupported.go @@ -0,0 +1,24 @@ +// +build !linux + +package elf + +import "fmt" + +type Module struct{} +type Kprobe struct{} + +func NewModule(fileName string) *Module { + return nil +} + +func (b *Module) EnableKprobe(secName string) error { + return fmt.Errorf("not supported") +} + +func (b *Module) IterKprobes() <-chan *Kprobe { + return nil +} + +func (b *Module) EnableKprobes() error { + return fmt.Errorf("not supported") +} diff --git a/vendor/github.com/iovisor/gobpf/elf/perf.go b/vendor/github.com/iovisor/gobpf/elf/perf.go new file mode 100644 index 0000000000..2a9d467bb4 --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/perf.go @@ -0,0 +1,291 @@ +// +build linux + +// Copyright 2016 Cilium Project +// Copyright 2016 Sylvain Afchain +// Copyright 2016 Kinvolk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package elf + +import ( + "fmt" + "os" + "sort" + "syscall" + "unsafe" +) + +/* +#include +#include +#include +#include +#include +#include + +// from https://github.com/cilium/cilium/blob/master/pkg/bpf/perf.go + +struct event_sample { + struct perf_event_header header; + uint32_t size; + uint8_t data[]; +}; + +struct read_state { + void *buf; + int buf_len; +}; + +static int perf_event_read(int page_count, int page_size, void *_state, + void *_header, void *_sample_ptr, void *_lost_ptr) +{ + volatile struct perf_event_mmap_page *header = _header; + uint64_t data_head = *((volatile uint64_t *) &header->data_head); + uint64_t data_tail = header->data_tail; + uint64_t raw_size = (uint64_t)page_count * page_size; + void *base = ((uint8_t *)header) + page_size; + struct read_state *state = _state; + struct event_sample *e; + void *begin, *end; + void **sample_ptr = (void **) _sample_ptr; + void **lost_ptr = (void **) _lost_ptr; + + // No data to read on this ring + __sync_synchronize(); + if (data_head == data_tail) + return 0; + + begin = base + data_tail % raw_size; + e = begin; + end = base + (data_tail + e->header.size) % raw_size; + + if (state->buf_len < e->header.size || !state->buf) { + state->buf = realloc(state->buf, e->header.size); + state->buf_len = e->header.size; + } + + if (end < begin) { + uint64_t len = base + raw_size - begin; + + memcpy(state->buf, begin, len); + memcpy((char *) state->buf + len, base, e->header.size - len); + + e = state->buf; + } else { + memcpy(state->buf, begin, e->header.size); + } + + switch (e->header.type) { + case PERF_RECORD_SAMPLE: + *sample_ptr = state->buf; + break; + case PERF_RECORD_LOST: + *lost_ptr = state->buf; + break; + } + + __sync_synchronize(); + header->data_tail += e->header.size; + + return e->header.type; +} +*/ +import "C" + +type PerfMap struct { + name string + program *Module + receiverChan chan []byte + pollStop chan bool + timestamp func(*[]byte) uint64 +} + +// Matching 'struct perf_event_sample in kernel sources +type PerfEventSample struct { + PerfEventHeader + Size uint32 + data byte // Size bytes of data +} + +func InitPerfMap(b *Module, mapName string, receiverChan chan []byte) (*PerfMap, error) { + _, ok := b.maps[mapName] + if !ok { + return nil, fmt.Errorf("no map with name %s", mapName) + } + // Maps are initialized in b.Load(), nothing to do here + return &PerfMap{ + name: mapName, + program: b, + receiverChan: receiverChan, + pollStop: make(chan bool), + }, nil +} + +// SetTimestampFunc registers a timestamp callback that will be used to +// reorder the perf events chronologically. +// +// If not set, the order of events sent through receiverChan is not guaranteed. +// +// Typically, the ebpf program will use bpf_ktime_get_ns() to get a timestamp +// and store it in the perf event. The perf event struct is opaque to this +// package, hence the need for a callback. +func (pm *PerfMap) SetTimestampFunc(timestamp func(*[]byte) uint64) { + pm.timestamp = timestamp +} + +func (pm *PerfMap) PollStart() { + incoming := OrderedBytesArray{timestamp: pm.timestamp} + + m, ok := pm.program.maps[pm.name] + if !ok { + // should not happen or only when pm.program is + // suddenly changed + panic(fmt.Sprintf("cannot find map %q", pm.name)) + } + + go func() { + cpuCount := len(m.pmuFDs) + pageSize := os.Getpagesize() + pageCount := 8 + state := C.struct_read_state{} + + for { + select { + case <-pm.pollStop: + break + default: + perfEventPoll(m.pmuFDs) + } + + for { + var harvestCount C.int + beforeHarvest := nowNanoseconds() + for cpu := 0; cpu < cpuCount; cpu++ { + for { + var sample *PerfEventSample + var lost *PerfEventLost + + ok := C.perf_event_read(C.int(pageCount), C.int(pageSize), + unsafe.Pointer(&state), unsafe.Pointer(m.headers[cpu]), + unsafe.Pointer(&sample), unsafe.Pointer(&lost)) + + switch ok { + case 0: + break // nothing to read + case C.PERF_RECORD_SAMPLE: + size := sample.Size - 4 + b := C.GoBytes(unsafe.Pointer(&sample.data), C.int(size)) + incoming.bytesArray = append(incoming.bytesArray, b) + harvestCount++ + if pm.timestamp == nil { + continue + } + if incoming.timestamp(&b) > beforeHarvest { + // see comment below + break + } else { + continue + } + case C.PERF_RECORD_LOST: + default: + // TODO: handle lost/unknown events? + } + break + } + } + + if incoming.timestamp != nil { + sort.Sort(incoming) + } + for i := 0; i < incoming.Len(); i++ { + if incoming.timestamp != nil && incoming.timestamp(&incoming.bytesArray[0]) > beforeHarvest { + // This record has been sent after the beginning of the harvest. Stop + // processing here to keep the order. "incoming" is sorted, so the next + // elements also must not be processed now. + break + } + pm.receiverChan <- incoming.bytesArray[0] + // remove first element + incoming.bytesArray = incoming.bytesArray[1:] + } + if harvestCount == 0 && len(incoming.bytesArray) == 0 { + break + } + } + } + }() +} + +func (pm *PerfMap) PollStop() { + pm.pollStop <- true +} + +func perfEventPoll(fds []C.int) error { + var pfds []C.struct_pollfd + + for i, _ := range fds { + var pfd C.struct_pollfd + + pfd.fd = fds[i] + pfd.events = C.POLLIN + + pfds = append(pfds, pfd) + } + _, err := C.poll(&pfds[0], C.nfds_t(len(fds)), 500) + if err != nil { + return fmt.Errorf("error polling: %v", err.(syscall.Errno)) + } + + return nil +} + +// Assume the timestamp is at the beginning of the user struct +type OrderedBytesArray struct { + bytesArray [][]byte + timestamp func(*[]byte) uint64 +} + +func (a OrderedBytesArray) Len() int { + return len(a.bytesArray) +} + +func (a OrderedBytesArray) Swap(i, j int) { + a.bytesArray[i], a.bytesArray[j] = a.bytesArray[j], a.bytesArray[i] +} + +func (a OrderedBytesArray) Less(i, j int) bool { + return *(*C.uint64_t)(unsafe.Pointer(&a.bytesArray[i][0])) < *(*C.uint64_t)(unsafe.Pointer(&a.bytesArray[j][0])) +} + +// Matching 'struct perf_event_header in +type PerfEventHeader struct { + Type uint32 + Misc uint16 + TotalSize uint16 +} + +// Matching 'struct perf_event_lost in kernel sources +type PerfEventLost struct { + PerfEventHeader + Id uint64 + Lost uint64 +} + +// nowNanoseconds returns a time that can be compared to bpf_ktime_get_ns() +func nowNanoseconds() uint64 { + var ts syscall.Timespec + syscall.Syscall(syscall.SYS_CLOCK_GETTIME, 1 /* CLOCK_MONOTONIC */, uintptr(unsafe.Pointer(&ts)), 0) + sec, nsec := ts.Unix() + return 1000*1000*1000*uint64(sec) + uint64(nsec) +} diff --git a/vendor/github.com/iovisor/gobpf/elf/perf_unsupported.go b/vendor/github.com/iovisor/gobpf/elf/perf_unsupported.go new file mode 100644 index 0000000000..686e3673ac --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/perf_unsupported.go @@ -0,0 +1,15 @@ +// +build !linux + +package elf + +import "fmt" + +type PerfMap struct{} + +func InitPerfMap(b *Module, mapName string, receiverChan chan []byte) (*PerfMap, error) { + return nil, fmt.Errorf("not supported") +} + +func (pm *PerfMap) PollStart() {} + +func (pm *PerfMap) PollStop() {} diff --git a/vendor/github.com/iovisor/gobpf/elf/table.go b/vendor/github.com/iovisor/gobpf/elf/table.go new file mode 100644 index 0000000000..e4a2e5ee17 --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/table.go @@ -0,0 +1,108 @@ +// +build linux + +// Copyright 2016 Cilium Project +// Copyright 2016 Sylvain Afchain +// Copyright 2016 Kinvolk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package elf + +import ( + "fmt" + "syscall" + "unsafe" +) + +/* +#include +#include + +extern __u64 ptr_to_u64(void *); + +// from https://github.com/cilium/cilium/blob/master/pkg/bpf/bpf.go +// Apache License, Version 2.0 + +static void create_bpf_update_elem(int fd, void *key, void *value, + unsigned long long flags, void *attr) +{ + union bpf_attr* ptr_bpf_attr; + ptr_bpf_attr = (union bpf_attr*)attr; + ptr_bpf_attr->map_fd = fd; + ptr_bpf_attr->key = ptr_to_u64(key); + ptr_bpf_attr->value = ptr_to_u64(value); + ptr_bpf_attr->flags = flags; +} + +static void create_bpf_lookup_elem(int fd, void *key, void *value, void *attr) +{ + union bpf_attr* ptr_bpf_attr; + ptr_bpf_attr = (union bpf_attr*)attr; + ptr_bpf_attr->map_fd = fd; + ptr_bpf_attr->key = ptr_to_u64(key); + ptr_bpf_attr->value = ptr_to_u64(value); +} +*/ +import "C" + +// UpdateElement stores value in key in the map stored in mp. +// The flags can have the following values (if you include "uapi/linux/bpf.h"): +// C.BPF_ANY to create new element or update existing; +// C.BPF_NOEXIST to create new element if it didn't exist; +// C.BPF_EXIST to update existing element. +func (b *Module) UpdateElement(mp *Map, key, value unsafe.Pointer, flags uint64) error { + uba := C.union_bpf_attr{} + C.create_bpf_update_elem( + C.int(mp.m.fd), + key, + value, + C.ulonglong(flags), + unsafe.Pointer(&uba), + ) + ret, _, err := syscall.Syscall( + C.__NR_bpf, + C.BPF_MAP_UPDATE_ELEM, + uintptr(unsafe.Pointer(&uba)), + unsafe.Sizeof(uba), + ) + + if ret != 0 || err != 0 { + return fmt.Errorf("unable to update element: %s", err) + } + + return nil +} + +// LookupElement looks up the given key in the the map stored in mp. +// The value is stored in the value unsafe.Pointer. +func (b *Module) LookupElement(mp *Map, key, value unsafe.Pointer) error { + uba := C.union_bpf_attr{} + C.create_bpf_lookup_elem( + C.int(mp.m.fd), + key, + value, + unsafe.Pointer(&uba), + ) + ret, _, err := syscall.Syscall( + C.__NR_bpf, + C.BPF_MAP_LOOKUP_ELEM, + uintptr(unsafe.Pointer(&uba)), + unsafe.Sizeof(uba), + ) + + if ret != 0 || err != 0 { + return fmt.Errorf("unable to lookup element: %s", err) + } + + return nil +} diff --git a/vendor/github.com/iovisor/gobpf/elf/utsname_int8.go b/vendor/github.com/iovisor/gobpf/elf/utsname_int8.go new file mode 100644 index 0000000000..9e53508002 --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/utsname_int8.go @@ -0,0 +1,14 @@ +// +build linux,amd64 linux,arm64 + +package elf + +func utsnameStr(in []int8) string { + out := make([]byte, len(in)) + for i := 0; i < len(in); i++ { + if in[i] == 0 { + break + } + out = append(out, byte(in[i])) + } + return string(out) +} diff --git a/vendor/github.com/iovisor/gobpf/elf/utsname_uint8.go b/vendor/github.com/iovisor/gobpf/elf/utsname_uint8.go new file mode 100644 index 0000000000..654ed469c3 --- /dev/null +++ b/vendor/github.com/iovisor/gobpf/elf/utsname_uint8.go @@ -0,0 +1,14 @@ +// +build linux,arm linux,ppc64 linux,ppc64le s390x + +package elf + +func utsnameStr(in []uint8) string { + out := make([]byte, len(in)) + for i := 0; i < len(in); i++ { + if in[i] == 0 { + break + } + out = append(out, byte(in[i])) + } + return string(out) +} diff --git a/vendor/manifest b/vendor/manifest index 7b3bf7510a..cf0d9917d9 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -972,6 +972,15 @@ "revision": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75", "branch": "master" }, + { + "importpath": "github.com/iovisor/gobpf/elf", + "repository": "https://github.com/iovisor/gobpf", + "vcs": "git", + "revision": "7ed2b65341823cb357a639715b865216391bb921", + "branch": "master", + "path": "/elf", + "notests": true + }, { "importpath": "github.com/jmespath/go-jmespath", "repository": "https://github.com/jmespath/go-jmespath", @@ -1573,4 +1582,4 @@ "branch": "master" } ] -} \ No newline at end of file +}