• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2015 PLUMgrid
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from __future__ import print_function
16import atexit
17import ctypes as ct
18import fcntl
19import json
20import os
21import re
22import errno
23import sys
24import platform
25
26from .libbcc import lib, bcc_symbol, bcc_symbol_option, bcc_stacktrace_build_id, _SYM_CB_TYPE
27from .table import Table, PerfEventArray, RingBuf, BPF_MAP_TYPE_QUEUE, BPF_MAP_TYPE_STACK
28from .perf import Perf
29from .utils import get_online_cpus, printb, _assert_is_bytes, ArgString, StrcmpRewrite
30from .version import __version__
31from .disassembler import disassemble_prog, decode_map
32from .usdt import USDT, USDTException
33
34try:
35    basestring
36except NameError:  # Python 3
37    basestring = str
38
39_default_probe_limit = 1000
40_num_open_probes = 0
41
42# for tests
43def _get_num_open_probes():
44    global _num_open_probes
45    return _num_open_probes
46
47TRACEFS = "/sys/kernel/debug/tracing"
48
49# Debug flags
50
51# Debug output compiled LLVM IR.
52DEBUG_LLVM_IR = 0x1
53# Debug output loaded BPF bytecode and register state on branches.
54DEBUG_BPF = 0x2
55# Debug output pre-processor result.
56DEBUG_PREPROCESSOR = 0x4
57# Debug output ASM instructions embedded with source.
58DEBUG_SOURCE = 0x8
59# Debug output register state on all instructions in addition to DEBUG_BPF.
60DEBUG_BPF_REGISTER_STATE = 0x10
61# Debug BTF.
62DEBUG_BTF = 0x20
63
64class SymbolCache(object):
65    def __init__(self, pid):
66        self.cache = lib.bcc_symcache_new(
67                pid, ct.cast(None, ct.POINTER(bcc_symbol_option)))
68
69    def resolve(self, addr, demangle):
70        """
71        Return a tuple of the symbol (function), its offset from the beginning
72        of the function, and the module in which it lies. For example:
73            ("start_thread", 0x202, "/usr/lib/.../libpthread-2.24.so")
74        If the symbol cannot be found but we know which module it is in,
75        return the module name and the offset from the beginning of the
76        module. If we don't even know the module, return the absolute
77        address as the offset.
78        """
79
80        sym = bcc_symbol()
81        if demangle:
82            res = lib.bcc_symcache_resolve(self.cache, addr, ct.byref(sym))
83        else:
84            res = lib.bcc_symcache_resolve_no_demangle(self.cache, addr,
85                                                       ct.byref(sym))
86        if res < 0:
87            if sym.module and sym.offset:
88                return (None, sym.offset,
89                        ct.cast(sym.module, ct.c_char_p).value)
90            return (None, addr, None)
91        if demangle:
92            name_res = sym.demangle_name
93            lib.bcc_symbol_free_demangle_name(ct.byref(sym))
94        else:
95            name_res = sym.name
96        return (name_res, sym.offset, ct.cast(sym.module, ct.c_char_p).value)
97
98    def resolve_name(self, module, name):
99        module = _assert_is_bytes(module)
100        name = _assert_is_bytes(name)
101        addr = ct.c_ulonglong()
102        if lib.bcc_symcache_resolve_name(self.cache, module, name,
103                ct.byref(addr)) < 0:
104            return -1
105        return addr.value
106
107class PerfType:
108    # From perf_type_id in uapi/linux/perf_event.h
109    HARDWARE = 0
110    SOFTWARE = 1
111    TRACEPOINT = 2
112    HW_CACHE = 3
113    RAW = 4
114    BREAKPOINT = 5
115
116class PerfHWConfig:
117    # From perf_hw_id in uapi/linux/perf_event.h
118    CPU_CYCLES = 0
119    INSTRUCTIONS = 1
120    CACHE_REFERENCES = 2
121    CACHE_MISSES = 3
122    BRANCH_INSTRUCTIONS = 4
123    BRANCH_MISSES = 5
124    BUS_CYCLES = 6
125    STALLED_CYCLES_FRONTEND = 7
126    STALLED_CYCLES_BACKEND = 8
127    REF_CPU_CYCLES = 9
128
129class PerfSWConfig:
130    # From perf_sw_id in uapi/linux/perf_event.h
131    CPU_CLOCK = 0
132    TASK_CLOCK = 1
133    PAGE_FAULTS = 2
134    CONTEXT_SWITCHES = 3
135    CPU_MIGRATIONS = 4
136    PAGE_FAULTS_MIN = 5
137    PAGE_FAULTS_MAJ = 6
138    ALIGNMENT_FAULTS = 7
139    EMULATION_FAULTS = 8
140    DUMMY = 9
141    BPF_OUTPUT = 10
142
143class PerfEventSampleFormat:
144    # from perf_event_sample_format in uapi/linux/bpf.h
145    IP = (1 << 0)
146    TID = (1 << 1)
147    TIME = (1 << 2)
148    ADDR = (1 << 3)
149    READ = (1 << 4)
150    CALLCHAIN = (1 << 5)
151    ID = (1 << 6)
152    CPU = (1 << 7)
153    PERIOD = (1 << 8)
154    STREAM_ID = (1 << 9)
155    RAW = (1 << 10)
156    BRANCH_STACK = (1 << 11)
157    REGS_USER = (1 << 12)
158    STACK_USER = (1 << 13)
159    WEIGHT = (1 << 14)
160    DATA_SRC = (1 << 15)
161    IDENTIFIER = (1 << 16)
162    TRANSACTION = (1 << 17)
163    REGS_INTR = (1 << 18)
164    PHYS_ADDR = (1 << 19)
165    AUX = (1 << 20)
166    CGROUP = (1 << 21)
167    DATA_PAGE_SIZE = (1 << 22)
168    CODE_PAGE_SIZE = (1 << 23)
169    WEIGHT_STRUCT = (1 << 24)
170
171class BPFProgType:
172    # From bpf_prog_type in uapi/linux/bpf.h
173    SOCKET_FILTER = 1
174    KPROBE = 2
175    SCHED_CLS = 3
176    SCHED_ACT = 4
177    TRACEPOINT = 5
178    XDP = 6
179    PERF_EVENT = 7
180    CGROUP_SKB = 8
181    CGROUP_SOCK = 9
182    LWT_IN = 10
183    LWT_OUT = 11
184    LWT_XMIT = 12
185    SOCK_OPS = 13
186    SK_SKB = 14
187    CGROUP_DEVICE = 15
188    SK_MSG = 16
189    RAW_TRACEPOINT = 17
190    CGROUP_SOCK_ADDR = 18
191    TRACING = 26
192    LSM = 29
193
194class BPFAttachType:
195    # from bpf_attach_type uapi/linux/bpf.h
196    CGROUP_INET_INGRESS = 0
197    CGROUP_INET_EGRESS = 1
198    CGROUP_INET_SOCK_CREATE = 2
199    CGROUP_SOCK_OPS = 3
200    SK_SKB_STREAM_PARSER = 4
201    SK_SKB_STREAM_VERDICT = 5
202    CGROUP_DEVICE = 6
203    SK_MSG_VERDICT = 7
204    CGROUP_INET4_BIND = 8
205    CGROUP_INET6_BIND = 9
206    CGROUP_INET4_CONNECT = 10
207    CGROUP_INET6_CONNECT = 11
208    CGROUP_INET4_POST_BIND = 12
209    CGROUP_INET6_POST_BIND = 13
210    CGROUP_UDP4_SENDMSG = 14
211    CGROUP_UDP6_SENDMSG = 15
212    LIRC_MODE2 = 16
213    FLOW_DISSECTOR = 17
214    CGROUP_SYSCTL = 18
215    CGROUP_UDP4_RECVMSG = 19
216    CGROUP_UDP6_RECVMSG = 20
217    CGROUP_GETSOCKOPT = 21
218    CGROUP_SETSOCKOPT = 22
219    TRACE_RAW_TP = 23
220    TRACE_FENTRY = 24
221    TRACE_FEXIT  = 25
222    MODIFY_RETURN = 26
223    LSM_MAC = 27
224    TRACE_ITER = 28
225    CGROUP_INET4_GETPEERNAME = 29
226    CGROUP_INET6_GETPEERNAME = 30
227    CGROUP_INET4_GETSOCKNAME = 31
228    CGROUP_INET6_GETSOCKNAME = 32
229    XDP_DEVMAP = 33
230    CGROUP_INET_SOCK_RELEASE = 34
231    XDP_CPUMAP = 35
232    SK_LOOKUP = 36
233    XDP = 37
234    SK_SKB_VERDICT = 38
235
236class XDPAction:
237    # from xdp_action uapi/linux/bpf.h
238    XDP_ABORTED = 0
239    XDP_DROP = 1
240    XDP_PASS = 2
241    XDP_TX = 3
242    XDP_REDIRECT = 4
243
244class XDPFlags:
245    # from xdp_flags uapi/linux/if_link.h
246    # unlike similar enum-type holder classes in this file, source for these
247    # is #define XDP_FLAGS_UPDATE_IF_NOEXIST, #define XDP_FLAGS_SKB_MODE, ...
248    UPDATE_IF_NOEXIST = (1 << 0)
249    SKB_MODE = (1 << 1)
250    DRV_MODE = (1 << 2)
251    HW_MODE = (1 << 3)
252    REPLACE = (1 << 4)
253
254class BPF(object):
255    # Here for backwards compatibility only, add new enum members and types
256    # the appropriate wrapper class elsewhere in this file to avoid namespace
257    # collision issues
258    SOCKET_FILTER = BPFProgType.SOCKET_FILTER
259    KPROBE = BPFProgType.KPROBE
260    SCHED_CLS = BPFProgType.SCHED_CLS
261    SCHED_ACT = BPFProgType.SCHED_ACT
262    TRACEPOINT = BPFProgType.TRACEPOINT
263    XDP = BPFProgType.XDP
264    PERF_EVENT = BPFProgType.PERF_EVENT
265    CGROUP_SKB = BPFProgType.CGROUP_SKB
266    CGROUP_SOCK = BPFProgType.CGROUP_SOCK
267    LWT_IN = BPFProgType.LWT_IN
268    LWT_OUT = BPFProgType.LWT_OUT
269    LWT_XMIT = BPFProgType.LWT_XMIT
270    SOCK_OPS = BPFProgType.SOCK_OPS
271    SK_SKB = BPFProgType.SK_SKB
272    CGROUP_DEVICE = BPFProgType.CGROUP_DEVICE
273    SK_MSG = BPFProgType.SK_MSG
274    RAW_TRACEPOINT = BPFProgType.RAW_TRACEPOINT
275    CGROUP_SOCK_ADDR = BPFProgType.CGROUP_SOCK_ADDR
276    TRACING = BPFProgType.TRACING
277    LSM = BPFProgType.LSM
278
279    XDP_ABORTED = XDPAction.XDP_ABORTED
280    XDP_DROP = XDPAction.XDP_DROP
281    XDP_PASS = XDPAction.XDP_PASS
282    XDP_TX = XDPAction.XDP_TX
283    XDP_REDIRECT = XDPAction.XDP_REDIRECT
284
285    XDP_FLAGS_UPDATE_IF_NOEXIST = XDPFlags.UPDATE_IF_NOEXIST
286    XDP_FLAGS_SKB_MODE = XDPFlags.SKB_MODE
287    XDP_FLAGS_DRV_MODE = XDPFlags.DRV_MODE
288    XDP_FLAGS_HW_MODE = XDPFlags.HW_MODE
289    XDP_FLAGS_REPLACE = XDPFlags.REPLACE
290    # END enum backwards compat
291
292    _probe_repl = re.compile(b"[^a-zA-Z0-9_]")
293    _sym_caches = {}
294    _bsymcache =  lib.bcc_buildsymcache_new()
295
296    _auto_includes = {
297        "linux/time.h": ["time"],
298        "linux/fs.h": ["fs", "file"],
299        "linux/blkdev.h": ["bio", "request"],
300        "linux/slab.h": ["alloc"],
301        "linux/netdevice.h": ["sk_buff", "net_device"]
302    }
303
304    _syscall_prefixes = [
305        b"sys_",
306        b"__x64_sys_",
307        b"__x32_compat_sys_",
308        b"__ia32_compat_sys_",
309        b"__arm64_sys_",
310        b"__s390x_sys_",
311        b"__s390_sys_",
312    ]
313
314    # BPF timestamps come from the monotonic clock. To be able to filter
315    # and compare them from Python, we need to invoke clock_gettime.
316    # Adapted from http://stackoverflow.com/a/1205762
317    CLOCK_MONOTONIC = 1         # see <linux/time.h>
318
319    class timespec(ct.Structure):
320        _fields_ = [('tv_sec', ct.c_long), ('tv_nsec', ct.c_long)]
321
322    _librt = ct.CDLL('librt.so.1', use_errno=True)
323    _clock_gettime = _librt.clock_gettime
324    _clock_gettime.argtypes = [ct.c_int, ct.POINTER(timespec)]
325
326    @classmethod
327    def monotonic_time(cls):
328        """monotonic_time()
329        Returns the system monotonic time from clock_gettime, using the
330        CLOCK_MONOTONIC constant. The time returned is in nanoseconds.
331        """
332        t = cls.timespec()
333        if cls._clock_gettime(cls.CLOCK_MONOTONIC, ct.byref(t)) != 0:
334            errno = ct.get_errno()
335            raise OSError(errno, os.strerror(errno))
336        return t.tv_sec * 1e9 + t.tv_nsec
337
338    @classmethod
339    def generate_auto_includes(cls, program_words):
340        """
341        Generates #include statements automatically based on a set of
342        recognized types such as sk_buff and bio. The input is all the words
343        that appear in the BPF program, and the output is a (possibly empty)
344        string of #include statements, such as "#include <linux/fs.h>".
345        """
346        headers = ""
347        for header, keywords in cls._auto_includes.items():
348            for keyword in keywords:
349                for word in program_words:
350                    if keyword in word and header not in headers:
351                        headers += "#include <%s>\n" % header
352        return headers
353
354    # defined for compatibility reasons, to be removed
355    Table = Table
356
357    class Function(object):
358        def __init__(self, bpf, name, fd):
359            self.bpf = bpf
360            self.name = name
361            self.fd = fd
362
363    @staticmethod
364    def _find_file(filename):
365        """ If filename is invalid, search in ./ of argv[0] """
366        if filename:
367            if not os.path.isfile(filename):
368                argv0 = ArgString(sys.argv[0])
369                t = b"/".join([os.path.abspath(os.path.dirname(argv0.__bytes__())), filename])
370                if os.path.isfile(t):
371                    filename = t
372                else:
373                    raise Exception("Could not find file %s" % filename)
374        return filename
375
376    @staticmethod
377    def find_exe(bin_path):
378        """
379        find_exe(bin_path)
380
381        Traverses the PATH environment variable, looking for the first
382        directory that contains an executable file named bin_path, and
383        returns the full path to that file, or None if no such file
384        can be found. This is meant to replace invocations of the
385        "which" shell utility, which doesn't have portable semantics
386        for skipping aliases.
387        """
388        # Source: http://stackoverflow.com/a/377028
389        def is_exe(fpath):
390            return os.path.isfile(fpath) and \
391                os.access(fpath, os.X_OK)
392
393        fpath, fname = os.path.split(bin_path)
394        if fpath:
395            if is_exe(bin_path):
396                return bin_path
397        else:
398            for path in os.environ["PATH"].split(os.pathsep):
399                path = path.strip('"')
400                exe_file = os.path.join(path.encode(), bin_path)
401                if is_exe(exe_file):
402                    return exe_file
403        return None
404
405    def __init__(self, src_file=b"", hdr_file=b"", text=None, debug=0,
406            cflags=[], usdt_contexts=[], allow_rlimit=True, device=None,
407            attach_usdt_ignore_pid=False):
408        """Create a new BPF module with the given source code.
409
410        Note:
411            All fields are marked as optional, but either `src_file` or `text`
412            must be supplied, and not both.
413
414        Args:
415            src_file (Optional[str]): Path to a source file for the module
416            hdr_file (Optional[str]): Path to a helper header file for the `src_file`
417            text (Optional[str]): Contents of a source file for the module
418            debug (Optional[int]): Flags used for debug prints, can be |'d together
419                                   See "Debug flags" for explanation
420        """
421
422        src_file = _assert_is_bytes(src_file)
423        hdr_file = _assert_is_bytes(hdr_file)
424        text = _assert_is_bytes(text)
425
426        assert not (text and src_file)
427
428        self.kprobe_fds = {}
429        self.uprobe_fds = {}
430        self.tracepoint_fds = {}
431        self.raw_tracepoint_fds = {}
432        self.kfunc_entry_fds = {}
433        self.kfunc_exit_fds = {}
434        self.lsm_fds = {}
435        self.perf_buffers = {}
436        self.open_perf_events = {}
437        self._ringbuf_manager = None
438        self.tracefile = None
439        atexit.register(self.cleanup)
440
441        self.debug = debug
442        self.funcs = {}
443        self.tables = {}
444        self.module = None
445        cflags_array = (ct.c_char_p * len(cflags))()
446        for i, s in enumerate(cflags): cflags_array[i] = bytes(ArgString(s))
447
448        if src_file:
449            src_file = BPF._find_file(src_file)
450            hdr_file = BPF._find_file(hdr_file)
451
452        if src_file:
453            # Read the BPF C source file into the text variable. This ensures,
454            # that files and inline text are treated equally.
455            with open(src_file, mode="rb") as file:
456                text = file.read()
457
458        ctx_array = (ct.c_void_p * len(usdt_contexts))()
459        for i, usdt in enumerate(usdt_contexts):
460            ctx_array[i] = ct.c_void_p(usdt.get_context())
461        usdt_text = lib.bcc_usdt_genargs(ctx_array, len(usdt_contexts))
462        if usdt_text is None:
463            raise Exception("can't generate USDT probe arguments; " +
464                            "possible cause is missing pid when a " +
465                            "probe in a shared object has multiple " +
466                            "locations")
467        text = usdt_text + text
468
469
470        self.module = lib.bpf_module_create_c_from_string(text,
471                                                          self.debug,
472                                                          cflags_array, len(cflags_array),
473                                                          allow_rlimit, device)
474        if not self.module:
475            raise Exception("Failed to compile BPF module %s" % (src_file or "<text>"))
476
477        for usdt_context in usdt_contexts:
478            usdt_context.attach_uprobes(self, attach_usdt_ignore_pid)
479
480        # If any "kprobe__" or "tracepoint__" or "raw_tracepoint__"
481        # prefixed functions were defined,
482        # they will be loaded and attached here.
483        self._trace_autoload()
484
485    def load_funcs(self, prog_type=KPROBE):
486        """load_funcs(prog_type=KPROBE)
487
488        Load all functions in this BPF module with the given type.
489        Returns a list of the function handles."""
490
491        fns = []
492        for i in range(0, lib.bpf_num_functions(self.module)):
493            func_name = lib.bpf_function_name(self.module, i)
494            fns.append(self.load_func(func_name, prog_type))
495
496        return fns
497
498    def load_func(self, func_name, prog_type, device = None):
499        func_name = _assert_is_bytes(func_name)
500        if func_name in self.funcs:
501            return self.funcs[func_name]
502        if not lib.bpf_function_start(self.module, func_name):
503            raise Exception("Unknown program %s" % func_name)
504        log_level = 0
505        if (self.debug & DEBUG_BPF_REGISTER_STATE):
506            log_level = 2
507        elif (self.debug & DEBUG_BPF):
508            log_level = 1
509        fd = lib.bcc_func_load(self.module, prog_type, func_name,
510                lib.bpf_function_start(self.module, func_name),
511                lib.bpf_function_size(self.module, func_name),
512                lib.bpf_module_license(self.module),
513                lib.bpf_module_kern_version(self.module),
514                log_level, None, 0, device)
515
516        if fd < 0:
517            atexit.register(self.donothing)
518            if ct.get_errno() == errno.EPERM:
519                raise Exception("Need super-user privileges to run")
520
521            errstr = os.strerror(ct.get_errno())
522            raise Exception("Failed to load BPF program %s: %s" %
523                            (func_name, errstr))
524
525        fn = BPF.Function(self, func_name, fd)
526        self.funcs[func_name] = fn
527
528        return fn
529
530    def dump_func(self, func_name):
531        """
532        Return the eBPF bytecodes for the specified function as a string
533        """
534        func_name = _assert_is_bytes(func_name)
535        if not lib.bpf_function_start(self.module, func_name):
536            raise Exception("Unknown program %s" % func_name)
537
538        start, = lib.bpf_function_start(self.module, func_name),
539        size, = lib.bpf_function_size(self.module, func_name),
540        return ct.string_at(start, size)
541
542    def disassemble_func(self, func_name):
543        bpfstr = self.dump_func(func_name)
544        return disassemble_prog(func_name, bpfstr)
545
546    def decode_table(self, table_name, sizeinfo=False):
547        table_obj = self[table_name]
548        table_type = lib.bpf_table_type_id(self.module, table_obj.map_id)
549        return decode_map(table_name, table_obj, table_type, sizeinfo=sizeinfo)
550
551    str2ctype = {
552        u"_Bool": ct.c_bool,
553        u"char": ct.c_char,
554        u"wchar_t": ct.c_wchar,
555        u"unsigned char": ct.c_ubyte,
556        u"short": ct.c_short,
557        u"unsigned short": ct.c_ushort,
558        u"int": ct.c_int,
559        u"unsigned int": ct.c_uint,
560        u"long": ct.c_long,
561        u"unsigned long": ct.c_ulong,
562        u"long long": ct.c_longlong,
563        u"unsigned long long": ct.c_ulonglong,
564        u"float": ct.c_float,
565        u"double": ct.c_double,
566        u"long double": ct.c_longdouble,
567        u"__int128": ct.c_int64 * 2,
568        u"unsigned __int128": ct.c_uint64 * 2,
569    }
570    @staticmethod
571    def _decode_table_type(desc):
572        if isinstance(desc, basestring):
573            return BPF.str2ctype[desc]
574        anon = []
575        fields = []
576        for t in desc[1]:
577            if len(t) == 2:
578                fields.append((t[0], BPF._decode_table_type(t[1])))
579            elif len(t) == 3:
580                if isinstance(t[2], list):
581                    fields.append((t[0], BPF._decode_table_type(t[1]) * t[2][0]))
582                elif isinstance(t[2], int):
583                    fields.append((t[0], BPF._decode_table_type(t[1]), t[2]))
584                elif isinstance(t[2], basestring) and (
585                        t[2] == u"union" or t[2] == u"struct" or
586                        t[2] == u"struct_packed"):
587                    name = t[0]
588                    if name == "":
589                        name = "__anon%d" % len(anon)
590                        anon.append(name)
591                    fields.append((name, BPF._decode_table_type(t)))
592                else:
593                    raise Exception("Failed to decode type %s" % str(t))
594            else:
595                raise Exception("Failed to decode type %s" % str(t))
596        base = ct.Structure
597        is_packed = False
598        if len(desc) > 2:
599            if desc[2] == u"union":
600                base = ct.Union
601            elif desc[2] == u"struct":
602                base = ct.Structure
603            elif desc[2] == u"struct_packed":
604                base = ct.Structure
605                is_packed = True
606        if is_packed:
607            cls = type(str(desc[0]), (base,), dict(_anonymous_=anon, _pack_=1,
608                _fields_=fields))
609        else:
610            cls = type(str(desc[0]), (base,), dict(_anonymous_=anon,
611                _fields_=fields))
612        return cls
613
614    def get_table(self, name, keytype=None, leaftype=None, reducer=None):
615        name = _assert_is_bytes(name)
616        map_id = lib.bpf_table_id(self.module, name)
617        map_fd = lib.bpf_table_fd(self.module, name)
618        is_queuestack = lib.bpf_table_type_id(self.module, map_id) in [BPF_MAP_TYPE_QUEUE, BPF_MAP_TYPE_STACK]
619        if map_fd < 0:
620            raise KeyError
621        if not keytype and not is_queuestack:
622            key_desc = lib.bpf_table_key_desc(self.module, name).decode("utf-8")
623            if not key_desc:
624                raise Exception("Failed to load BPF Table %s key desc" % name)
625            keytype = BPF._decode_table_type(json.loads(key_desc))
626        if not leaftype:
627            leaf_desc = lib.bpf_table_leaf_desc(self.module, name).decode("utf-8")
628            if not leaf_desc:
629                raise Exception("Failed to load BPF Table %s leaf desc" % name)
630            leaftype = BPF._decode_table_type(json.loads(leaf_desc))
631        return Table(self, map_id, map_fd, keytype, leaftype, name, reducer=reducer)
632
633    def __getitem__(self, key):
634        if key not in self.tables:
635            self.tables[key] = self.get_table(key)
636        return self.tables[key]
637
638    def __setitem__(self, key, leaf):
639        self.tables[key] = leaf
640
641    def __len__(self):
642        return len(self.tables)
643
644    def __delitem__(self, key):
645        del self.tables[key]
646
647    def __iter__(self):
648        return self.tables.__iter__()
649
650    @staticmethod
651    def attach_func(fn, attachable_fd, attach_type, flags=0):
652        if not isinstance(fn, BPF.Function):
653            raise Exception("arg 1 must be of type BPF.Function")
654
655        res = lib.bpf_prog_attach(fn.fd, attachable_fd, attach_type, flags)
656        if res < 0:
657            raise Exception("Failed to attach BPF function with attach_type "\
658                            "{0}: {1}".format(attach_type, os.strerror(-res)))
659
660    @staticmethod
661    def detach_func(fn, attachable_fd, attach_type):
662        if not isinstance(fn, BPF.Function):
663            raise Exception("arg 1 must be of type BPF.Function")
664
665        res = lib.bpf_prog_detach2(fn.fd, attachable_fd, attach_type)
666        if res < 0:
667            raise Exception("Failed to detach BPF function with attach_type "\
668                            "{0}: {1}".format(attach_type, os.strerror(-res)))
669
670    @staticmethod
671    def attach_raw_socket(fn, dev):
672        dev = _assert_is_bytes(dev)
673        if not isinstance(fn, BPF.Function):
674            raise Exception("arg 1 must be of type BPF.Function")
675        sock = lib.bpf_open_raw_sock(dev)
676        if sock < 0:
677            errstr = os.strerror(ct.get_errno())
678            raise Exception("Failed to open raw device %s: %s" % (dev, errstr))
679        res = lib.bpf_attach_socket(sock, fn.fd)
680        if res < 0:
681            errstr = os.strerror(ct.get_errno())
682            raise Exception("Failed to attach BPF to device %s: %s"
683                    % (dev, errstr))
684        fn.sock = sock
685
686    @staticmethod
687    def get_kprobe_functions(event_re):
688        blacklist_file = "%s/../kprobes/blacklist" % TRACEFS
689        try:
690            with open(blacklist_file, "rb") as blacklist_f:
691                blacklist = set([line.rstrip().split()[1] for line in blacklist_f])
692        except IOError as e:
693            if e.errno != errno.EPERM:
694                raise e
695            blacklist = set([])
696
697        fns = []
698
699        in_init_section = 0
700        in_irq_section = 0
701        with open("/proc/kallsyms", "rb") as avail_file:
702            for line in avail_file:
703                (t, fn) = line.rstrip().split()[1:3]
704                # Skip all functions defined between __init_begin and
705                # __init_end
706                if in_init_section == 0:
707                    if fn == b'__init_begin':
708                        in_init_section = 1
709                        continue
710                elif in_init_section == 1:
711                    if fn == b'__init_end':
712                        in_init_section = 2
713                    continue
714                # Skip all functions defined between __irqentry_text_start and
715                # __irqentry_text_end
716                if in_irq_section == 0:
717                    if fn == b'__irqentry_text_start':
718                        in_irq_section = 1
719                        continue
720                    # __irqentry_text_end is not always after
721                    # __irqentry_text_start. But only happens when
722                    # no functions between two irqentry_text
723                    elif fn == b'__irqentry_text_end':
724                        in_irq_section = 2
725                        continue
726                elif in_irq_section == 1:
727                    if fn == b'__irqentry_text_end':
728                        in_irq_section = 2
729                    continue
730                # All functions defined as NOKPROBE_SYMBOL() start with the
731                # prefix _kbl_addr_*, blacklisting them by looking at the name
732                # allows to catch also those symbols that are defined in kernel
733                # modules.
734                if fn.startswith(b'_kbl_addr_'):
735                    continue
736                # Explicitly blacklist perf-related functions, they are all
737                # non-attachable.
738                elif fn.startswith(b'__perf') or fn.startswith(b'perf_'):
739                    continue
740                # Exclude all static functions with prefix __SCT__, they are
741                # all non-attachable
742                elif fn.startswith(b'__SCT__'):
743                    continue
744                # Exclude all gcc 8's extra .cold functions
745                elif re.match(b'^.*\.cold(\.\d+)?$', fn):
746                    continue
747                if (t.lower() in [b't', b'w']) and re.match(event_re, fn) \
748                    and fn not in blacklist:
749                    fns.append(fn)
750        return set(fns)     # Some functions may appear more than once
751
752    def _check_probe_quota(self, num_new_probes):
753        global _num_open_probes
754        if _num_open_probes + num_new_probes > BPF.get_probe_limit():
755            raise Exception("Number of open probes would exceed global quota")
756
757    @staticmethod
758    def get_probe_limit():
759        env_probe_limit = os.environ.get('BCC_PROBE_LIMIT')
760        if env_probe_limit and env_probe_limit.isdigit():
761            return int(env_probe_limit)
762        else:
763            return _default_probe_limit
764
765    def _add_kprobe_fd(self, ev_name, fn_name, fd):
766        global _num_open_probes
767        if ev_name not in self.kprobe_fds:
768            self.kprobe_fds[ev_name] = {}
769        self.kprobe_fds[ev_name][fn_name] = fd
770        _num_open_probes += 1
771
772    def _del_kprobe_fd(self, ev_name, fn_name):
773        global _num_open_probes
774        del self.kprobe_fds[ev_name][fn_name]
775        _num_open_probes -= 1
776
777    def _add_uprobe_fd(self, name, fd):
778        global _num_open_probes
779        self.uprobe_fds[name] = fd
780        _num_open_probes += 1
781
782    def _del_uprobe_fd(self, name):
783        global _num_open_probes
784        del self.uprobe_fds[name]
785        _num_open_probes -= 1
786
787    # Find current system's syscall prefix by testing on the BPF syscall.
788    # If no valid value found, will return the first possible value which
789    # would probably lead to error in later API calls.
790    def get_syscall_prefix(self):
791        for prefix in self._syscall_prefixes:
792            if self.ksymname(b"%sbpf" % prefix) != -1:
793                return prefix
794        return self._syscall_prefixes[0]
795
796    # Given a syscall's name, return the full Kernel function name with current
797    # system's syscall prefix. For example, given "clone" the helper would
798    # return "sys_clone" or "__x64_sys_clone".
799    def get_syscall_fnname(self, name):
800        name = _assert_is_bytes(name)
801        return self.get_syscall_prefix() + name
802
803    # Given a Kernel function name that represents a syscall but already has a
804    # prefix included, transform it to current system's prefix. For example,
805    # if "sys_clone" provided, the helper may translate it to "__x64_sys_clone".
806    def fix_syscall_fnname(self, name):
807        name = _assert_is_bytes(name)
808        for prefix in self._syscall_prefixes:
809            if name.startswith(prefix):
810                return self.get_syscall_fnname(name[len(prefix):])
811        return name
812
813    def attach_kprobe(self, event=b"", event_off=0, fn_name=b"", event_re=b""):
814        event = _assert_is_bytes(event)
815        fn_name = _assert_is_bytes(fn_name)
816        event_re = _assert_is_bytes(event_re)
817
818        # allow the caller to glob multiple functions together
819        if event_re:
820            matches = BPF.get_kprobe_functions(event_re)
821            self._check_probe_quota(len(matches))
822            failed = 0
823            probes = []
824            for line in matches:
825                try:
826                    self.attach_kprobe(event=line, fn_name=fn_name)
827                except:
828                    failed += 1
829                    probes.append(line)
830            if failed == len(matches):
831                raise Exception("Failed to attach BPF program %s to kprobe %s" %
832                                (fn_name, '/'.join(probes)))
833            return
834
835        self._check_probe_quota(1)
836        fn = self.load_func(fn_name, BPF.KPROBE)
837        ev_name = b"p_" + event.replace(b"+", b"_").replace(b".", b"_")
838        fd = lib.bpf_attach_kprobe(fn.fd, 0, ev_name, event, event_off, 0)
839        if fd < 0:
840            raise Exception("Failed to attach BPF program %s to kprobe %s" %
841                            (fn_name, event))
842        self._add_kprobe_fd(ev_name, fn_name, fd)
843        return self
844
845    def attach_kretprobe(self, event=b"", fn_name=b"", event_re=b"", maxactive=0):
846        event = _assert_is_bytes(event)
847        fn_name = _assert_is_bytes(fn_name)
848        event_re = _assert_is_bytes(event_re)
849
850        # allow the caller to glob multiple functions together
851        if event_re:
852            matches = BPF.get_kprobe_functions(event_re)
853            failed = 0
854            probes = []
855            for line in matches:
856                try:
857                    self.attach_kretprobe(event=line, fn_name=fn_name,
858                                          maxactive=maxactive)
859                except:
860                    failed += 1
861                    probes.append(line)
862            if failed == len(matches):
863                raise Exception("Failed to attach BPF program %s to kretprobe %s" %
864                                (fn_name, '/'.join(probes)))
865            return
866
867        self._check_probe_quota(1)
868        fn = self.load_func(fn_name, BPF.KPROBE)
869        ev_name = b"r_" + event.replace(b"+", b"_").replace(b".", b"_")
870        fd = lib.bpf_attach_kprobe(fn.fd, 1, ev_name, event, 0, maxactive)
871        if fd < 0:
872            raise Exception("Failed to attach BPF program %s to kretprobe %s" %
873                            (fn_name, event))
874        self._add_kprobe_fd(ev_name, fn_name, fd)
875        return self
876
877    def detach_kprobe_event(self, ev_name):
878        ev_name = _assert_is_bytes(ev_name)
879        fn_names = list(self.kprobe_fds[ev_name].keys())
880        for fn_name in fn_names:
881            self.detach_kprobe_event_by_fn(ev_name, fn_name)
882
883    def detach_kprobe_event_by_fn(self, ev_name, fn_name):
884        ev_name = _assert_is_bytes(ev_name)
885        fn_name = _assert_is_bytes(fn_name)
886        if ev_name not in self.kprobe_fds:
887            raise Exception("Kprobe %s is not attached" % ev_name)
888        res = lib.bpf_close_perf_event_fd(self.kprobe_fds[ev_name][fn_name])
889        if res < 0:
890            raise Exception("Failed to close kprobe FD")
891        self._del_kprobe_fd(ev_name, fn_name)
892        if len(self.kprobe_fds[ev_name]) == 0:
893            res = lib.bpf_detach_kprobe(ev_name)
894            if res < 0:
895                raise Exception("Failed to detach BPF from kprobe")
896
897    def detach_kprobe(self, event, fn_name=None):
898        event = _assert_is_bytes(event)
899        ev_name = b"p_" + event.replace(b"+", b"_").replace(b".", b"_")
900        if fn_name:
901            fn_name = _assert_is_bytes(fn_name)
902            self.detach_kprobe_event_by_fn(ev_name, fn_name)
903        else:
904            self.detach_kprobe_event(ev_name)
905
906    def detach_kretprobe(self, event, fn_name=None):
907        event = _assert_is_bytes(event)
908        ev_name = b"r_" + event.replace(b"+", b"_").replace(b".", b"_")
909        if fn_name:
910            fn_name = _assert_is_bytes(fn_name)
911            self.detach_kprobe_event_by_fn(ev_name, fn_name)
912        else:
913            self.detach_kprobe_event(ev_name)
914
915    @staticmethod
916    def attach_xdp(dev, fn, flags=0):
917        '''
918            This function attaches a BPF function to a device on the device
919            driver level (XDP)
920        '''
921        dev = _assert_is_bytes(dev)
922        if not isinstance(fn, BPF.Function):
923            raise Exception("arg 1 must be of type BPF.Function")
924        res = lib.bpf_attach_xdp(dev, fn.fd, flags)
925        if res < 0:
926            err_no = ct.get_errno()
927            if err_no == errno.EBADMSG:
928                raise Exception("Internal error while attaching BPF to device,"+
929                    " try increasing the debug level!")
930            else:
931                errstr = os.strerror(err_no)
932                raise Exception("Failed to attach BPF to device %s: %s"
933                            % (dev, errstr))
934
935    @staticmethod
936    def remove_xdp(dev, flags=0):
937        '''
938            This function removes any BPF function from a device on the
939            device driver level (XDP)
940        '''
941        dev = _assert_is_bytes(dev)
942        res = lib.bpf_attach_xdp(dev, -1, flags)
943        if res < 0:
944            errstr = os.strerror(ct.get_errno())
945            raise Exception("Failed to detach BPF from device %s: %s"
946                            % (dev, errstr))
947
948    @classmethod
949    def _check_path_symbol(cls, module, symname, addr, pid, sym_off=0):
950        module = _assert_is_bytes(module)
951        symname = _assert_is_bytes(symname)
952        sym = bcc_symbol()
953        c_pid = 0 if pid == -1 else pid
954        if lib.bcc_resolve_symname(
955            module, symname,
956            addr or 0x0, c_pid,
957            ct.cast(None, ct.POINTER(bcc_symbol_option)),
958            ct.byref(sym),
959        ) < 0:
960            raise Exception("could not determine address of symbol %s in %s"
961                            % (symname.decode(), module.decode()))
962        new_addr = sym.offset + sym_off
963        module_path = ct.cast(sym.module, ct.c_char_p).value
964        lib.bcc_procutils_free(sym.module)
965        return module_path, new_addr
966
967    @staticmethod
968    def find_library(libname):
969        libname = _assert_is_bytes(libname)
970        res = lib.bcc_procutils_which_so(libname, 0)
971        if not res:
972            return None
973        libpath = ct.cast(res, ct.c_char_p).value
974        lib.bcc_procutils_free(res)
975        return libpath
976
977    @staticmethod
978    def get_tracepoints(tp_re):
979        results = []
980        events_dir = os.path.join(TRACEFS, "events")
981        for category in os.listdir(events_dir):
982            cat_dir = os.path.join(events_dir, category)
983            if not os.path.isdir(cat_dir):
984                continue
985            for event in os.listdir(cat_dir):
986                evt_dir = os.path.join(cat_dir, event)
987                if os.path.isdir(evt_dir):
988                    tp = ("%s:%s" % (category, event))
989                    if re.match(tp_re.decode(), tp):
990                        results.append(tp)
991        return results
992
993    @staticmethod
994    def tracepoint_exists(category, event):
995        evt_dir = os.path.join(TRACEFS, "events", category, event)
996        return os.path.isdir(evt_dir)
997
998    def attach_tracepoint(self, tp=b"", tp_re=b"", fn_name=b""):
999        """attach_tracepoint(tp="", tp_re="", fn_name="")
1000
1001        Run the bpf function denoted by fn_name every time the kernel tracepoint
1002        specified by 'tp' is hit. The optional parameters pid, cpu, and group_fd
1003        can be used to filter the probe. The tracepoint specification is simply
1004        the tracepoint category and the tracepoint name, separated by a colon.
1005        For example: sched:sched_switch, syscalls:sys_enter_bind, etc.
1006
1007        Instead of a tracepoint name, a regular expression can be provided in
1008        tp_re. The program will then attach to tracepoints that match the
1009        provided regular expression.
1010
1011        To obtain a list of kernel tracepoints, use the tplist tool or cat the
1012        file /sys/kernel/debug/tracing/available_events.
1013
1014        Examples:
1015            BPF(text).attach_tracepoint(tp="sched:sched_switch", fn_name="on_switch")
1016            BPF(text).attach_tracepoint(tp_re="sched:.*", fn_name="on_switch")
1017        """
1018
1019        tp = _assert_is_bytes(tp)
1020        tp_re = _assert_is_bytes(tp_re)
1021        fn_name = _assert_is_bytes(fn_name)
1022        if tp_re:
1023            for tp in BPF.get_tracepoints(tp_re):
1024                self.attach_tracepoint(tp=tp, fn_name=fn_name)
1025            return
1026
1027        fn = self.load_func(fn_name, BPF.TRACEPOINT)
1028        (tp_category, tp_name) = tp.split(b':')
1029        fd = lib.bpf_attach_tracepoint(fn.fd, tp_category, tp_name)
1030        if fd < 0:
1031            raise Exception("Failed to attach BPF program %s to tracepoint %s" %
1032                            (fn_name, tp))
1033        self.tracepoint_fds[tp] = fd
1034        return self
1035
1036    def attach_raw_tracepoint(self, tp=b"", fn_name=b""):
1037        """attach_raw_tracepoint(self, tp=b"", fn_name=b"")
1038
1039        Run the bpf function denoted by fn_name every time the kernel tracepoint
1040        specified by 'tp' is hit. The bpf function should be loaded as a
1041        RAW_TRACEPOINT type. The fn_name is the kernel tracepoint name,
1042        e.g., sched_switch, sys_enter_bind, etc.
1043
1044        Examples:
1045            BPF(text).attach_raw_tracepoint(tp="sched_switch", fn_name="on_switch")
1046        """
1047
1048        tp = _assert_is_bytes(tp)
1049        if tp in self.raw_tracepoint_fds:
1050            raise Exception("Raw tracepoint %s has been attached" % tp)
1051
1052        fn_name = _assert_is_bytes(fn_name)
1053        fn = self.load_func(fn_name, BPF.RAW_TRACEPOINT)
1054        fd = lib.bpf_attach_raw_tracepoint(fn.fd, tp)
1055        if fd < 0:
1056            raise Exception("Failed to attach BPF to raw tracepoint")
1057        self.raw_tracepoint_fds[tp] = fd
1058        return self
1059
1060    def detach_raw_tracepoint(self, tp=b""):
1061        """detach_raw_tracepoint(tp="")
1062
1063        Stop running the bpf function that is attached to the kernel tracepoint
1064        specified by 'tp'.
1065
1066        Example: bpf.detach_raw_tracepoint("sched_switch")
1067        """
1068
1069        tp = _assert_is_bytes(tp)
1070        if tp not in self.raw_tracepoint_fds:
1071            raise Exception("Raw tracepoint %s is not attached" % tp)
1072        os.close(self.raw_tracepoint_fds[tp])
1073        del self.raw_tracepoint_fds[tp]
1074
1075    @staticmethod
1076    def add_prefix(prefix, name):
1077        if not name.startswith(prefix):
1078            name = prefix + name
1079        return name
1080
1081    @staticmethod
1082    def support_kfunc():
1083        # there's no trampoline support for other than x86_64 arch
1084        if platform.machine() != 'x86_64':
1085            return False
1086        if not lib.bpf_has_kernel_btf():
1087            return False
1088        # kernel symbol "bpf_trampoline_link_prog" indicates kfunc support
1089        if BPF.ksymname("bpf_trampoline_link_prog") != -1:
1090            return True
1091        return False
1092
1093    @staticmethod
1094    def support_lsm():
1095        if not lib.bpf_has_kernel_btf():
1096            return False
1097        # kernel symbol "bpf_lsm_bpf" indicates BPF LSM support
1098        if BPF.ksymname(b"bpf_lsm_bpf") != -1:
1099            return True
1100        return False
1101
1102    def detach_kfunc(self, fn_name=b""):
1103        fn_name = _assert_is_bytes(fn_name)
1104        fn_name = BPF.add_prefix(b"kfunc__", fn_name)
1105
1106        if fn_name not in self.kfunc_entry_fds:
1107            raise Exception("Kernel entry func %s is not attached" % fn_name)
1108        os.close(self.kfunc_entry_fds[fn_name])
1109        del self.kfunc_entry_fds[fn_name]
1110
1111    def detach_kretfunc(self, fn_name=b""):
1112        fn_name = _assert_is_bytes(fn_name)
1113        fn_name = BPF.add_prefix(b"kretfunc__", fn_name)
1114
1115        if fn_name not in self.kfunc_exit_fds:
1116            raise Exception("Kernel exit func %s is not attached" % fn_name)
1117        os.close(self.kfunc_exit_fds[fn_name])
1118        del self.kfunc_exit_fds[fn_name]
1119
1120    def attach_kfunc(self, fn_name=b""):
1121        fn_name = _assert_is_bytes(fn_name)
1122        fn_name = BPF.add_prefix(b"kfunc__", fn_name)
1123
1124        if fn_name in self.kfunc_entry_fds:
1125            raise Exception("Kernel entry func %s has been attached" % fn_name)
1126
1127        fn = self.load_func(fn_name, BPF.TRACING)
1128        fd = lib.bpf_attach_kfunc(fn.fd)
1129        if fd < 0:
1130            raise Exception("Failed to attach BPF to entry kernel func")
1131        self.kfunc_entry_fds[fn_name] = fd
1132        return self
1133
1134    def attach_kretfunc(self, fn_name=b""):
1135        fn_name = _assert_is_bytes(fn_name)
1136        fn_name = BPF.add_prefix(b"kretfunc__", fn_name)
1137
1138        if fn_name in self.kfunc_exit_fds:
1139            raise Exception("Kernel exit func %s has been attached" % fn_name)
1140
1141        fn = self.load_func(fn_name, BPF.TRACING)
1142        fd = lib.bpf_attach_kfunc(fn.fd)
1143        if fd < 0:
1144            raise Exception("Failed to attach BPF to exit kernel func")
1145        self.kfunc_exit_fds[fn_name] = fd
1146        return self
1147
1148    def detach_lsm(self, fn_name=b""):
1149        fn_name = _assert_is_bytes(fn_name)
1150        fn_name = BPF.add_prefix(b"lsm__", fn_name)
1151
1152        if fn_name not in self.lsm_fds:
1153            raise Exception("LSM %s is not attached" % fn_name)
1154        os.close(self.lsm_fds[fn_name])
1155        del self.lsm_fds[fn_name]
1156
1157    def attach_lsm(self, fn_name=b""):
1158        fn_name = _assert_is_bytes(fn_name)
1159        fn_name = BPF.add_prefix(b"lsm__", fn_name)
1160
1161        if fn_name in self.lsm_fds:
1162            raise Exception("LSM %s has been attached" % fn_name)
1163
1164        fn = self.load_func(fn_name, BPF.LSM)
1165        fd = lib.bpf_attach_lsm(fn.fd)
1166        if fd < 0:
1167            raise Exception("Failed to attach LSM")
1168        self.lsm_fds[fn_name] = fd
1169        return self
1170
1171    @staticmethod
1172    def support_raw_tracepoint():
1173        # kernel symbol "bpf_find_raw_tracepoint" indicates raw_tracepoint support
1174        if BPF.ksymname("bpf_find_raw_tracepoint") != -1 or \
1175           BPF.ksymname("bpf_get_raw_tracepoint") != -1:
1176            return True
1177        return False
1178
1179    @staticmethod
1180    def support_raw_tracepoint_in_module():
1181        # kernel symbol "bpf_trace_modules" indicates raw tp support in modules, ref: kernel commit a38d1107
1182        kallsyms = "/proc/kallsyms"
1183        with open(kallsyms) as syms:
1184            for line in syms:
1185                (_, _, name) = line.rstrip().split(" ", 2)
1186                name = name.split("\t")[0]
1187                if name == "bpf_trace_modules":
1188                    return True
1189            return False
1190
1191    @staticmethod
1192    def kernel_struct_has_field(struct_name, field_name):
1193        struct_name = _assert_is_bytes(struct_name)
1194        field_name = _assert_is_bytes(field_name)
1195        return lib.kernel_struct_has_field(struct_name, field_name)
1196
1197    def detach_tracepoint(self, tp=b""):
1198        """detach_tracepoint(tp="")
1199
1200        Stop running a bpf function that is attached to the kernel tracepoint
1201        specified by 'tp'.
1202
1203        Example: bpf.detach_tracepoint("sched:sched_switch")
1204        """
1205
1206        tp = _assert_is_bytes(tp)
1207        if tp not in self.tracepoint_fds:
1208            raise Exception("Tracepoint %s is not attached" % tp)
1209        res = lib.bpf_close_perf_event_fd(self.tracepoint_fds[tp])
1210        if res < 0:
1211            raise Exception("Failed to detach BPF from tracepoint")
1212        (tp_category, tp_name) = tp.split(b':')
1213        res = lib.bpf_detach_tracepoint(tp_category, tp_name)
1214        if res < 0:
1215            raise Exception("Failed to detach BPF from tracepoint")
1216        del self.tracepoint_fds[tp]
1217
1218    def _attach_perf_event(self, progfd, ev_type, ev_config,
1219            sample_period, sample_freq, pid, cpu, group_fd):
1220        res = lib.bpf_attach_perf_event(progfd, ev_type, ev_config,
1221                sample_period, sample_freq, pid, cpu, group_fd)
1222        if res < 0:
1223            raise Exception("Failed to attach BPF to perf event")
1224        return res
1225
1226    def attach_perf_event(self, ev_type=-1, ev_config=-1, fn_name=b"",
1227            sample_period=0, sample_freq=0, pid=-1, cpu=-1, group_fd=-1):
1228        fn_name = _assert_is_bytes(fn_name)
1229        fn = self.load_func(fn_name, BPF.PERF_EVENT)
1230        res = {}
1231        if cpu >= 0:
1232            res[cpu] = self._attach_perf_event(fn.fd, ev_type, ev_config,
1233                    sample_period, sample_freq, pid, cpu, group_fd)
1234        else:
1235            for i in get_online_cpus():
1236                res[i] = self._attach_perf_event(fn.fd, ev_type, ev_config,
1237                        sample_period, sample_freq, pid, i, group_fd)
1238        self.open_perf_events[(ev_type, ev_config)] = res
1239
1240    def _attach_perf_event_raw(self, progfd, attr, pid, cpu, group_fd):
1241        res = lib.bpf_attach_perf_event_raw(progfd, ct.byref(attr), pid,
1242                cpu, group_fd, 0)
1243        if res < 0:
1244            raise Exception("Failed to attach BPF to perf raw event")
1245        return res
1246
1247    def attach_perf_event_raw(self, attr=-1, fn_name=b"", pid=-1, cpu=-1, group_fd=-1):
1248        fn_name = _assert_is_bytes(fn_name)
1249        fn = self.load_func(fn_name, BPF.PERF_EVENT)
1250        res = {}
1251        if cpu >= 0:
1252            res[cpu] = self._attach_perf_event_raw(fn.fd, attr,
1253                    pid, cpu, group_fd)
1254        else:
1255            for i in get_online_cpus():
1256                res[i] = self._attach_perf_event_raw(fn.fd, attr,
1257                        pid, i, group_fd)
1258        self.open_perf_events[(attr.type, attr.config)] = res
1259
1260    def detach_perf_event(self, ev_type=-1, ev_config=-1):
1261        try:
1262            fds = self.open_perf_events[(ev_type, ev_config)]
1263        except KeyError:
1264            raise Exception("Perf event type {} config {} not attached".format(
1265                ev_type, ev_config))
1266
1267        res = 0
1268        for fd in fds.values():
1269            res = lib.bpf_close_perf_event_fd(fd) or res
1270        if res != 0:
1271            raise Exception("Failed to detach BPF from perf event")
1272        del self.open_perf_events[(ev_type, ev_config)]
1273
1274    @staticmethod
1275    def get_user_functions(name, sym_re):
1276        return set([name for (name, _) in
1277                    BPF.get_user_functions_and_addresses(name, sym_re)])
1278
1279    @staticmethod
1280    def get_user_addresses(name, sym_re):
1281        """
1282        We are returning addresses here instead of symbol names because it
1283        turns out that the same name may appear multiple times with different
1284        addresses, and the same address may appear multiple times with the same
1285        name. We can't attach a uprobe to the same address more than once, so
1286        it makes sense to return the unique set of addresses that are mapped to
1287        a symbol that matches the provided regular expression.
1288        """
1289        return set([address for (_, address) in
1290                    BPF.get_user_functions_and_addresses(name, sym_re)])
1291
1292    @staticmethod
1293    def get_user_functions_and_addresses(name, sym_re):
1294        name = _assert_is_bytes(name)
1295        sym_re = _assert_is_bytes(sym_re)
1296        addresses = []
1297        def sym_cb(sym_name, addr):
1298            dname = sym_name
1299            if re.match(sym_re, dname):
1300                addresses.append((dname, addr))
1301            return 0
1302
1303        res = lib.bcc_foreach_function_symbol(name, _SYM_CB_TYPE(sym_cb))
1304        if res < 0:
1305            raise Exception("Error %d enumerating symbols in %s" % (res, name))
1306        return addresses
1307
1308    def _get_uprobe_evname(self, prefix, path, addr, pid):
1309        if pid == -1:
1310            return b"%s_%s_0x%x" % (prefix, self._probe_repl.sub(b"_", path), addr)
1311        else:
1312            # if pid is valid, put pid in the name, so different pid
1313            # can have different event names
1314            return b"%s_%s_0x%x_%d" % (prefix, self._probe_repl.sub(b"_", path), addr, pid)
1315
1316    def attach_uprobe(self, name=b"", sym=b"", sym_re=b"", addr=None,
1317            fn_name=b"", pid=-1, sym_off=0):
1318        """attach_uprobe(name="", sym="", sym_re="", addr=None, fn_name=""
1319                         pid=-1, sym_off=0)
1320
1321        Run the bpf function denoted by fn_name every time the symbol sym in
1322        the library or binary 'name' is encountered. Optional parameters pid,
1323        cpu, and group_fd can be used to filter the probe.
1324
1325        If sym_off is given, attach uprobe to offset within the symbol.
1326
1327        The real address addr may be supplied in place of sym, in which case sym
1328        must be set to its default value. If the file is a non-PIE executable,
1329        addr must be a virtual address, otherwise it must be an offset relative
1330        to the file load address.
1331
1332        Instead of a symbol name, a regular expression can be provided in
1333        sym_re. The uprobe will then attach to symbols that match the provided
1334        regular expression.
1335
1336        Libraries can be given in the name argument without the lib prefix, or
1337        with the full path (/usr/lib/...). Binaries can be given only with the
1338        full path (/bin/sh). If a PID is given, the uprobe will attach to the
1339        version of the library used by the process.
1340
1341        Example: BPF(text).attach_uprobe("c", "malloc")
1342                 BPF(text).attach_uprobe("/usr/bin/python", "main")
1343        """
1344
1345        assert sym_off >= 0
1346        if addr is not None:
1347            assert sym_off == 0, "offset with addr is not supported"
1348
1349        name = _assert_is_bytes(name)
1350        sym = _assert_is_bytes(sym)
1351        sym_re = _assert_is_bytes(sym_re)
1352        fn_name = _assert_is_bytes(fn_name)
1353
1354        if sym_re:
1355            addresses = BPF.get_user_addresses(name, sym_re)
1356            self._check_probe_quota(len(addresses))
1357            for sym_addr in addresses:
1358                self.attach_uprobe(name=name, addr=sym_addr,
1359                                   fn_name=fn_name, pid=pid)
1360            return
1361
1362        (path, addr) = BPF._check_path_symbol(name, sym, addr, pid, sym_off)
1363
1364        self._check_probe_quota(1)
1365        fn = self.load_func(fn_name, BPF.KPROBE)
1366        ev_name = self._get_uprobe_evname(b"p", path, addr, pid)
1367        fd = lib.bpf_attach_uprobe(fn.fd, 0, ev_name, path, addr, pid)
1368        if fd < 0:
1369            raise Exception("Failed to attach BPF to uprobe")
1370        self._add_uprobe_fd(ev_name, fd)
1371        return self
1372
1373    def attach_uretprobe(self, name=b"", sym=b"", sym_re=b"", addr=None,
1374            fn_name=b"", pid=-1):
1375        """attach_uretprobe(name="", sym="", sym_re="", addr=None, fn_name=""
1376                            pid=-1)
1377
1378        Run the bpf function denoted by fn_name every time the symbol sym in
1379        the library or binary 'name' finishes execution. See attach_uprobe for
1380        meaning of additional parameters.
1381        """
1382
1383        name = _assert_is_bytes(name)
1384        sym = _assert_is_bytes(sym)
1385        sym_re = _assert_is_bytes(sym_re)
1386        fn_name = _assert_is_bytes(fn_name)
1387
1388        if sym_re:
1389            for sym_addr in BPF.get_user_addresses(name, sym_re):
1390                self.attach_uretprobe(name=name, addr=sym_addr,
1391                                      fn_name=fn_name, pid=pid)
1392            return
1393
1394        (path, addr) = BPF._check_path_symbol(name, sym, addr, pid)
1395
1396        self._check_probe_quota(1)
1397        fn = self.load_func(fn_name, BPF.KPROBE)
1398        ev_name = self._get_uprobe_evname(b"r", path, addr, pid)
1399        fd = lib.bpf_attach_uprobe(fn.fd, 1, ev_name, path, addr, pid)
1400        if fd < 0:
1401            raise Exception("Failed to attach BPF to uretprobe")
1402        self._add_uprobe_fd(ev_name, fd)
1403        return self
1404
1405    def detach_uprobe_event(self, ev_name):
1406        if ev_name not in self.uprobe_fds:
1407            raise Exception("Uprobe %s is not attached" % ev_name)
1408        res = lib.bpf_close_perf_event_fd(self.uprobe_fds[ev_name])
1409        if res < 0:
1410            raise Exception("Failed to detach BPF from uprobe")
1411        res = lib.bpf_detach_uprobe(ev_name)
1412        if res < 0:
1413            raise Exception("Failed to detach BPF from uprobe")
1414        self._del_uprobe_fd(ev_name)
1415
1416    def detach_uprobe(self, name=b"", sym=b"", addr=None, pid=-1, sym_off=0):
1417        """detach_uprobe(name="", sym="", addr=None, pid=-1)
1418
1419        Stop running a bpf function that is attached to symbol 'sym' in library
1420        or binary 'name'.
1421        """
1422
1423        name = _assert_is_bytes(name)
1424        sym = _assert_is_bytes(sym)
1425        (path, addr) = BPF._check_path_symbol(name, sym, addr, pid, sym_off)
1426        ev_name = self._get_uprobe_evname(b"p", path, addr, pid)
1427        self.detach_uprobe_event(ev_name)
1428
1429    def detach_uretprobe(self, name=b"", sym=b"", addr=None, pid=-1):
1430        """detach_uretprobe(name="", sym="", addr=None, pid=-1)
1431
1432        Stop running a bpf function that is attached to symbol 'sym' in library
1433        or binary 'name'.
1434        """
1435
1436        name = _assert_is_bytes(name)
1437        sym = _assert_is_bytes(sym)
1438
1439        (path, addr) = BPF._check_path_symbol(name, sym, addr, pid)
1440        ev_name = self._get_uprobe_evname(b"r", path, addr, pid)
1441        self.detach_uprobe_event(ev_name)
1442
1443    def _trace_autoload(self):
1444        for i in range(0, lib.bpf_num_functions(self.module)):
1445            func_name = lib.bpf_function_name(self.module, i)
1446            if func_name.startswith(b"kprobe__"):
1447                fn = self.load_func(func_name, BPF.KPROBE)
1448                self.attach_kprobe(
1449                    event=self.fix_syscall_fnname(func_name[8:]),
1450                    fn_name=fn.name)
1451            elif func_name.startswith(b"kretprobe__"):
1452                fn = self.load_func(func_name, BPF.KPROBE)
1453                self.attach_kretprobe(
1454                    event=self.fix_syscall_fnname(func_name[11:]),
1455                    fn_name=fn.name)
1456            elif func_name.startswith(b"tracepoint__"):
1457                fn = self.load_func(func_name, BPF.TRACEPOINT)
1458                tp = fn.name[len(b"tracepoint__"):].replace(b"__", b":")
1459                self.attach_tracepoint(tp=tp, fn_name=fn.name)
1460            elif func_name.startswith(b"raw_tracepoint__"):
1461                fn = self.load_func(func_name, BPF.RAW_TRACEPOINT)
1462                tp = fn.name[len(b"raw_tracepoint__"):]
1463                self.attach_raw_tracepoint(tp=tp, fn_name=fn.name)
1464            elif func_name.startswith(b"kfunc__"):
1465                self.attach_kfunc(fn_name=func_name)
1466            elif func_name.startswith(b"kretfunc__"):
1467                self.attach_kretfunc(fn_name=func_name)
1468            elif func_name.startswith(b"lsm__"):
1469                self.attach_lsm(fn_name=func_name)
1470
1471    def trace_open(self, nonblocking=False):
1472        """trace_open(nonblocking=False)
1473
1474        Open the trace_pipe if not already open
1475        """
1476        if not self.tracefile:
1477            self.tracefile = open("%s/trace_pipe" % TRACEFS, "rb")
1478            if nonblocking:
1479                fd = self.tracefile.fileno()
1480                fl = fcntl.fcntl(fd, fcntl.F_GETFL)
1481                fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
1482        return self.tracefile
1483
1484    def trace_fields(self, nonblocking=False):
1485        """trace_fields(nonblocking=False)
1486
1487        Read from the kernel debug trace pipe and return a tuple of the
1488        fields (task, pid, cpu, flags, timestamp, msg) or None if no
1489        line was read (nonblocking=True)
1490        """
1491        while True:
1492            line = self.trace_readline(nonblocking)
1493            if not line and nonblocking: return (None,) * 6
1494            # don't print messages related to lost events
1495            if line.startswith(b"CPU:"): continue
1496            task = line[:16].lstrip()
1497            line = line[17:]
1498            ts_end = line.find(b":")
1499            try:
1500                pid, cpu, flags, ts = line[:ts_end].split()
1501            except Exception as e:
1502                continue
1503            cpu = cpu[1:-1]
1504            # line[ts_end:] will have ": [sym_or_addr]: msgs"
1505            # For trace_pipe debug output, the addr typically
1506            # is invalid (e.g., 0x1). For kernel 4.12 or earlier,
1507            # if address is not able to match a kernel symbol,
1508            # nothing will be printed out. For kernel 4.13 and later,
1509            # however, the illegal address will be printed out.
1510            # Hence, both cases are handled here.
1511            line = line[ts_end + 1:]
1512            sym_end = line.find(b":")
1513            msg = line[sym_end + 2:]
1514            try:
1515                return (task, int(pid), int(cpu), flags, float(ts), msg)
1516            except Exception as e:
1517                return ("Unknown", 0, 0, "Unknown", 0.0, "Unknown")
1518
1519    def trace_readline(self, nonblocking=False):
1520        """trace_readline(nonblocking=False)
1521
1522        Read from the kernel debug trace pipe and return one line
1523        If nonblocking is False, this will block until ctrl-C is pressed.
1524        """
1525
1526        trace = self.trace_open(nonblocking)
1527
1528        line = None
1529        try:
1530            line = trace.readline(1024).rstrip()
1531        except IOError:
1532            pass
1533        return line
1534
1535    def trace_print(self, fmt=None):
1536        """trace_print(self, fmt=None)
1537
1538        Read from the kernel debug trace pipe and print on stdout.
1539        If fmt is specified, apply as a format string to the output. See
1540        trace_fields for the members of the tuple
1541        example: trace_print(fmt="pid {1}, msg = {5}")
1542        """
1543
1544        while True:
1545            if fmt:
1546                fields = self.trace_fields(nonblocking=False)
1547                if not fields: continue
1548                line = fmt.format(*fields)
1549            else:
1550                line = self.trace_readline(nonblocking=False)
1551            print(line)
1552            sys.stdout.flush()
1553
1554    @staticmethod
1555    def _sym_cache(pid):
1556        """_sym_cache(pid)
1557
1558        Returns a symbol cache for the specified PID.
1559        The kernel symbol cache is accessed by providing any PID less than zero.
1560        """
1561        if pid < 0 and pid != -1:
1562            pid = -1
1563        if not pid in BPF._sym_caches:
1564            BPF._sym_caches[pid] = SymbolCache(pid)
1565        return BPF._sym_caches[pid]
1566
1567    @staticmethod
1568    def sym(addr, pid, show_module=False, show_offset=False, demangle=True):
1569        """sym(addr, pid, show_module=False, show_offset=False)
1570
1571        Translate a memory address into a function name for a pid, which is
1572        returned. When show_module is True, the module name is also included.
1573        When show_offset is True, the instruction offset as a hexadecimal
1574        number is also included in the string.
1575
1576        A pid of less than zero will access the kernel symbol cache.
1577
1578        Example output when both show_module and show_offset are True:
1579            "start_thread+0x202 [libpthread-2.24.so]"
1580
1581        Example output when both show_module and show_offset are False:
1582            "start_thread"
1583        """
1584
1585        #addr is of type stacktrace_build_id
1586        #so invoke the bsym address resolver
1587        typeofaddr = str(type(addr))
1588        if typeofaddr.find('bpf_stack_build_id') != -1:
1589          sym = bcc_symbol()
1590          b = bcc_stacktrace_build_id()
1591          b.status = addr.status
1592          b.build_id = addr.build_id
1593          b.u.offset = addr.offset
1594          res = lib.bcc_buildsymcache_resolve(BPF._bsymcache,
1595                                              ct.byref(b),
1596                                              ct.byref(sym))
1597          if res < 0:
1598            if sym.module and sym.offset:
1599              name,offset,module = (None, sym.offset,
1600                        ct.cast(sym.module, ct.c_char_p).value)
1601            else:
1602              name, offset, module = (None, addr, None)
1603          else:
1604            name, offset, module = (sym.name, sym.offset,
1605                                    ct.cast(sym.module, ct.c_char_p).value)
1606        else:
1607          name, offset, module = BPF._sym_cache(pid).resolve(addr, demangle)
1608
1609        offset = b"+0x%x" % offset if show_offset and name is not None else b""
1610        name = name or b"[unknown]"
1611        name = name + offset
1612        module = b" [%s]" % os.path.basename(module) \
1613            if show_module and module is not None else b""
1614        return name + module
1615
1616    @staticmethod
1617    def ksym(addr, show_module=False, show_offset=False):
1618        """ksym(addr)
1619
1620        Translate a kernel memory address into a kernel function name, which is
1621        returned. When show_module is True, the module name ("kernel") is also
1622        included. When show_offset is true, the instruction offset as a
1623        hexadecimal number is also included in the string.
1624
1625        Example output when both show_module and show_offset are True:
1626            "default_idle+0x0 [kernel]"
1627        """
1628        return BPF.sym(addr, -1, show_module, show_offset, False)
1629
1630    @staticmethod
1631    def ksymname(name):
1632        """ksymname(name)
1633
1634        Translate a kernel name into an address. This is the reverse of
1635        ksym. Returns -1 when the function name is unknown."""
1636        return BPF._sym_cache(-1).resolve_name(None, name)
1637
1638    def num_open_kprobes(self):
1639        """num_open_kprobes()
1640
1641        Get the number of open K[ret]probes. Can be useful for scenarios where
1642        event_re is used while attaching and detaching probes.
1643        """
1644        return len(self.kprobe_fds)
1645
1646    def num_open_uprobes(self):
1647        """num_open_uprobes()
1648
1649        Get the number of open U[ret]probes.
1650        """
1651        return len(self.uprobe_fds)
1652
1653    def num_open_tracepoints(self):
1654        """num_open_tracepoints()
1655
1656        Get the number of open tracepoints.
1657        """
1658        return len(self.tracepoint_fds)
1659
1660    def perf_buffer_poll(self, timeout = -1):
1661        """perf_buffer_poll(self)
1662
1663        Poll from all open perf ring buffers, calling the callback that was
1664        provided when calling open_perf_buffer for each entry.
1665        """
1666        readers = (ct.c_void_p * len(self.perf_buffers))()
1667        for i, v in enumerate(self.perf_buffers.values()):
1668            readers[i] = v
1669        lib.perf_reader_poll(len(readers), readers, timeout)
1670
1671    def perf_buffer_consume(self):
1672        """perf_buffer_consume(self)
1673
1674        Consume all open perf buffers, regardless of whether or not
1675        they currently contain events data. Necessary to catch 'remainder'
1676        events when wakeup_events > 1 is set in open_perf_buffer
1677        """
1678        readers = (ct.c_void_p * len(self.perf_buffers))()
1679        for i, v in enumerate(self.perf_buffers.values()):
1680            readers[i] = v
1681        lib.perf_reader_consume(len(readers), readers)
1682
1683    def kprobe_poll(self, timeout = -1):
1684        """kprobe_poll(self)
1685
1686        Deprecated. Use perf_buffer_poll instead.
1687        """
1688        self.perf_buffer_poll(timeout)
1689
1690    def _open_ring_buffer(self, map_fd, fn, ctx=None):
1691        if not self._ringbuf_manager:
1692            self._ringbuf_manager = lib.bpf_new_ringbuf(map_fd, fn, ctx)
1693            if not self._ringbuf_manager:
1694                raise Exception("Could not open ring buffer")
1695        else:
1696            ret = lib.bpf_add_ringbuf(self._ringbuf_manager, map_fd, fn, ctx)
1697            if ret < 0:
1698                raise Exception("Could not open ring buffer")
1699
1700    def ring_buffer_poll(self, timeout = -1):
1701        """ring_buffer_poll(self)
1702
1703        Poll from all open ringbuf buffers, calling the callback that was
1704        provided when calling open_ring_buffer for each entry.
1705        """
1706        if not self._ringbuf_manager:
1707            raise Exception("No ring buffers to poll")
1708        lib.bpf_poll_ringbuf(self._ringbuf_manager, timeout)
1709
1710    def ring_buffer_consume(self):
1711        """ring_buffer_consume(self)
1712
1713        Consume all open ringbuf buffers, regardless of whether or not
1714        they currently contain events data. This is best for use cases
1715        where low latency is desired, but it can impact performance.
1716        If you are unsure, use ring_buffer_poll instead.
1717        """
1718        if not self._ringbuf_manager:
1719            raise Exception("No ring buffers to poll")
1720        lib.bpf_consume_ringbuf(self._ringbuf_manager)
1721
1722    def free_bcc_memory(self):
1723        return lib.bcc_free_memory()
1724
1725    @staticmethod
1726    def add_module(modname):
1727      """add_module(modname)
1728
1729        Add a library or exe to buildsym cache
1730      """
1731      try:
1732        lib.bcc_buildsymcache_add_module(BPF._bsymcache, modname.encode())
1733      except Exception as e:
1734        print("Error adding module to build sym cache"+str(e))
1735
1736    def donothing(self):
1737        """the do nothing exit handler"""
1738
1739    def cleanup(self):
1740        # Clean up opened probes
1741        for k, v in list(self.kprobe_fds.items()):
1742            self.detach_kprobe_event(k)
1743        for k, v in list(self.uprobe_fds.items()):
1744            self.detach_uprobe_event(k)
1745        for k, v in list(self.tracepoint_fds.items()):
1746            self.detach_tracepoint(k)
1747        for k, v in list(self.raw_tracepoint_fds.items()):
1748            self.detach_raw_tracepoint(k)
1749        for k, v in list(self.kfunc_entry_fds.items()):
1750            self.detach_kfunc(k)
1751        for k, v in list(self.kfunc_exit_fds.items()):
1752            self.detach_kretfunc(k)
1753        for k, v in list(self.lsm_fds.items()):
1754            self.detach_lsm(k)
1755
1756        # Clean up opened perf ring buffer and perf events
1757        table_keys = list(self.tables.keys())
1758        for key in table_keys:
1759            if isinstance(self.tables[key], PerfEventArray):
1760                del self.tables[key]
1761        for (ev_type, ev_config) in list(self.open_perf_events.keys()):
1762            self.detach_perf_event(ev_type, ev_config)
1763        if self.tracefile:
1764            self.tracefile.close()
1765            self.tracefile = None
1766        for name, fn in list(self.funcs.items()):
1767            os.close(fn.fd)
1768            del self.funcs[name]
1769        if self.module:
1770            lib.bpf_module_destroy(self.module)
1771            self.module = None
1772
1773        # Clean up ringbuf
1774        if self._ringbuf_manager:
1775            lib.bpf_free_ringbuf(self._ringbuf_manager)
1776            self._ringbuf_manager = None
1777
1778    def __enter__(self):
1779        return self
1780
1781    def __exit__(self, exc_type, exc_val, exc_tb):
1782        self.cleanup()
1783