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