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 struct 23import errno 24import sys 25basestring = (unicode if sys.version_info[0] < 3 else str) 26 27from .libbcc import lib, bcc_symbol, bcc_symbol_option, _SYM_CB_TYPE 28from .table import Table, PerfEventArray 29from .perf import Perf 30from .syscall import syscall_name 31from .utils import get_online_cpus, printb, _assert_is_bytes, ArgString 32from .version import __version__ 33 34_probe_limit = 1000 35_num_open_probes = 0 36 37# for tests 38def _get_num_open_probes(): 39 global _num_open_probes 40 return _num_open_probes 41 42TRACEFS = "/sys/kernel/debug/tracing" 43 44# Debug flags 45 46# Debug output compiled LLVM IR. 47DEBUG_LLVM_IR = 0x1 48# Debug output loaded BPF bytecode and register state on branches. 49DEBUG_BPF = 0x2 50# Debug output pre-processor result. 51DEBUG_PREPROCESSOR = 0x4 52# Debug output ASM instructions embedded with source. 53DEBUG_SOURCE = 0x8 54#Debug output register state on all instructions in addition to DEBUG_BPF. 55DEBUG_BPF_REGISTER_STATE = 0x10 56 57class SymbolCache(object): 58 def __init__(self, pid): 59 self.cache = lib.bcc_symcache_new( 60 pid, ct.cast(None, ct.POINTER(bcc_symbol_option))) 61 62 def resolve(self, addr, demangle): 63 """ 64 Return a tuple of the symbol (function), its offset from the beginning 65 of the function, and the module in which it lies. For example: 66 ("start_thread", 0x202, "/usr/lib/.../libpthread-2.24.so") 67 If the symbol cannot be found but we know which module it is in, 68 return the module name and the offset from the beginning of the 69 module. If we don't even know the module, return the absolute 70 address as the offset. 71 """ 72 sym = bcc_symbol() 73 if demangle: 74 res = lib.bcc_symcache_resolve(self.cache, addr, ct.byref(sym)) 75 else: 76 res = lib.bcc_symcache_resolve_no_demangle(self.cache, addr, 77 ct.byref(sym)) 78 if res < 0: 79 if sym.module and sym.offset: 80 return (None, sym.offset, 81 ct.cast(sym.module, ct.c_char_p).value) 82 return (None, addr, None) 83 if demangle: 84 name_res = sym.demangle_name 85 lib.bcc_symbol_free_demangle_name(ct.byref(sym)) 86 else: 87 name_res = sym.name 88 return (name_res, sym.offset, ct.cast(sym.module, ct.c_char_p).value) 89 90 def resolve_name(self, module, name): 91 module = _assert_is_bytes(module) 92 name = _assert_is_bytes(name) 93 addr = ct.c_ulonglong() 94 if lib.bcc_symcache_resolve_name(self.cache, module, name, 95 ct.byref(addr)) < 0: 96 return -1 97 return addr.value 98 99class PerfType: 100 # From perf_type_id in uapi/linux/perf_event.h 101 HARDWARE = 0 102 SOFTWARE = 1 103 104class PerfHWConfig: 105 # From perf_hw_id in uapi/linux/perf_event.h 106 CPU_CYCLES = 0 107 INSTRUCTIONS = 1 108 CACHE_REFERENCES = 2 109 CACHE_MISSES = 3 110 BRANCH_INSTRUCTIONS = 4 111 BRANCH_MISSES = 5 112 BUS_CYCLES = 6 113 STALLED_CYCLES_FRONTEND = 7 114 STALLED_CYCLES_BACKEND = 8 115 REF_CPU_CYCLES = 9 116 117class PerfSWConfig: 118 # From perf_sw_id in uapi/linux/perf_event.h 119 CPU_CLOCK = 0 120 TASK_CLOCK = 1 121 PAGE_FAULTS = 2 122 CONTEXT_SWITCHES = 3 123 CPU_MIGRATIONS = 4 124 PAGE_FAULTS_MIN = 5 125 PAGE_FAULTS_MAJ = 6 126 ALIGNMENT_FAULTS = 7 127 EMULATION_FAULTS = 8 128 DUMMY = 9 129 BPF_OUTPUT = 10 130 131class BPF(object): 132 # From bpf_prog_type in uapi/linux/bpf.h 133 SOCKET_FILTER = 1 134 KPROBE = 2 135 SCHED_CLS = 3 136 SCHED_ACT = 4 137 TRACEPOINT = 5 138 XDP = 6 139 PERF_EVENT = 7 140 CGROUP_SKB = 8 141 CGROUP_SOCK = 9 142 LWT_IN = 10 143 LWT_OUT = 11 144 LWT_XMIT = 12 145 SOCK_OPS = 13 146 SK_SKB = 14 147 CGROUP_DEVICE = 15 148 SK_MSG = 16 149 RAW_TRACEPOINT = 17 150 CGROUP_SOCK_ADDR = 18 151 152 # from xdp_action uapi/linux/bpf.h 153 XDP_ABORTED = 0 154 XDP_DROP = 1 155 XDP_PASS = 2 156 XDP_TX = 3 157 XDP_REDIRECT = 4 158 159 _probe_repl = re.compile(b"[^a-zA-Z0-9_]") 160 _sym_caches = {} 161 162 _auto_includes = { 163 "linux/time.h": ["time"], 164 "linux/fs.h": ["fs", "file"], 165 "linux/blkdev.h": ["bio", "request"], 166 "linux/slab.h": ["alloc"], 167 "linux/netdevice.h": ["sk_buff", "net_device"] 168 } 169 170 _syscall_prefixes = [ 171 b"sys_", 172 b"__x64_sys_", 173 b"__x32_compat_sys_", 174 b"__ia32_compat_sys_", 175 b"__arm64_sys_", 176 ] 177 178 # BPF timestamps come from the monotonic clock. To be able to filter 179 # and compare them from Python, we need to invoke clock_gettime. 180 # Adapted from http://stackoverflow.com/a/1205762 181 CLOCK_MONOTONIC = 1 # see <linux/time.h> 182 183 class timespec(ct.Structure): 184 _fields_ = [('tv_sec', ct.c_long), ('tv_nsec', ct.c_long)] 185 186 _librt = ct.CDLL('librt.so.1', use_errno=True) 187 _clock_gettime = _librt.clock_gettime 188 _clock_gettime.argtypes = [ct.c_int, ct.POINTER(timespec)] 189 190 @classmethod 191 def monotonic_time(cls): 192 """monotonic_time() 193 Returns the system monotonic time from clock_gettime, using the 194 CLOCK_MONOTONIC constant. The time returned is in nanoseconds. 195 """ 196 t = cls.timespec() 197 if cls._clock_gettime(cls.CLOCK_MONOTONIC, ct.byref(t)) != 0: 198 errno = ct.get_errno() 199 raise OSError(errno, os.strerror(errno)) 200 return t.tv_sec * 1e9 + t.tv_nsec 201 202 @classmethod 203 def generate_auto_includes(cls, program_words): 204 """ 205 Generates #include statements automatically based on a set of 206 recognized types such as sk_buff and bio. The input is all the words 207 that appear in the BPF program, and the output is a (possibly empty) 208 string of #include statements, such as "#include <linux/fs.h>". 209 """ 210 headers = "" 211 for header, keywords in cls._auto_includes.items(): 212 for keyword in keywords: 213 for word in program_words: 214 if keyword in word and header not in headers: 215 headers += "#include <%s>\n" % header 216 return headers 217 218 # defined for compatibility reasons, to be removed 219 Table = Table 220 221 class Function(object): 222 def __init__(self, bpf, name, fd): 223 self.bpf = bpf 224 self.name = name 225 self.fd = fd 226 227 @staticmethod 228 def _find_file(filename): 229 """ If filename is invalid, search in ./ of argv[0] """ 230 if filename: 231 if not os.path.isfile(filename): 232 argv0 = ArgString(sys.argv[0]) 233 t = b"/".join([os.path.abspath(os.path.dirname(argv0.__str__())), filename]) 234 if os.path.isfile(t): 235 filename = t 236 else: 237 raise Exception("Could not find file %s" % filename) 238 return filename 239 240 @staticmethod 241 def find_exe(bin_path): 242 """ 243 find_exe(bin_path) 244 245 Traverses the PATH environment variable, looking for the first 246 directory that contains an executable file named bin_path, and 247 returns the full path to that file, or None if no such file 248 can be found. This is meant to replace invocations of the 249 "which" shell utility, which doesn't have portable semantics 250 for skipping aliases. 251 """ 252 # Source: http://stackoverflow.com/a/377028 253 def is_exe(fpath): 254 return os.path.isfile(fpath) and \ 255 os.access(fpath, os.X_OK) 256 257 fpath, fname = os.path.split(bin_path) 258 if fpath: 259 if is_exe(bin_path): 260 return bin_path 261 else: 262 for path in os.environ["PATH"].split(os.pathsep): 263 path = path.strip('"') 264 exe_file = os.path.join(path, bin_path) 265 if is_exe(exe_file): 266 return exe_file 267 return None 268 269 def __init__(self, src_file=b"", hdr_file=b"", text=None, debug=0, 270 cflags=[], usdt_contexts=[]): 271 """Create a new BPF module with the given source code. 272 273 Note: 274 All fields are marked as optional, but either `src_file` or `text` 275 must be supplied, and not both. 276 277 Args: 278 src_file (Optional[str]): Path to a source file for the module 279 hdr_file (Optional[str]): Path to a helper header file for the `src_file` 280 text (Optional[str]): Contents of a source file for the module 281 debug (Optional[int]): Flags used for debug prints, can be |'d together 282 See "Debug flags" for explanation 283 """ 284 285 src_file = _assert_is_bytes(src_file) 286 hdr_file = _assert_is_bytes(hdr_file) 287 text = _assert_is_bytes(text) 288 289 self.kprobe_fds = {} 290 self.uprobe_fds = {} 291 self.tracepoint_fds = {} 292 self.raw_tracepoint_fds = {} 293 self.perf_buffers = {} 294 self.open_perf_events = {} 295 self.tracefile = None 296 atexit.register(self.cleanup) 297 298 self.debug = debug 299 self.funcs = {} 300 self.tables = {} 301 self.module = None 302 cflags_array = (ct.c_char_p * len(cflags))() 303 for i, s in enumerate(cflags): cflags_array[i] = bytes(ArgString(s)) 304 if text: 305 ctx_array = (ct.c_void_p * len(usdt_contexts))() 306 for i, usdt in enumerate(usdt_contexts): 307 ctx_array[i] = ct.c_void_p(usdt.get_context()) 308 usdt_text = lib.bcc_usdt_genargs(ctx_array, len(usdt_contexts)) 309 if usdt_text is None: 310 raise Exception("can't generate USDT probe arguments; " + 311 "possible cause is missing pid when a " + 312 "probe in a shared object has multiple " + 313 "locations") 314 text = usdt_text + text 315 316 if text: 317 self.module = lib.bpf_module_create_c_from_string(text, 318 self.debug, cflags_array, len(cflags_array)) 319 if not self.module: 320 raise Exception("Failed to compile BPF text") 321 else: 322 src_file = BPF._find_file(src_file) 323 hdr_file = BPF._find_file(hdr_file) 324 if src_file.endswith(b".b"): 325 self.module = lib.bpf_module_create_b(src_file, hdr_file, 326 self.debug) 327 else: 328 self.module = lib.bpf_module_create_c(src_file, self.debug, 329 cflags_array, len(cflags_array)) 330 if not self.module: 331 raise Exception("Failed to compile BPF module %s" % src_file) 332 333 for usdt_context in usdt_contexts: 334 usdt_context.attach_uprobes(self) 335 336 # If any "kprobe__" or "tracepoint__" or "raw_tracepoint__" 337 # prefixed functions were defined, 338 # they will be loaded and attached here. 339 self._trace_autoload() 340 341 def load_funcs(self, prog_type=KPROBE): 342 """load_funcs(prog_type=KPROBE) 343 344 Load all functions in this BPF module with the given type. 345 Returns a list of the function handles.""" 346 347 fns = [] 348 for i in range(0, lib.bpf_num_functions(self.module)): 349 func_name = lib.bpf_function_name(self.module, i) 350 fns.append(self.load_func(func_name, prog_type)) 351 352 return fns 353 354 def load_func(self, func_name, prog_type): 355 func_name = _assert_is_bytes(func_name) 356 if func_name in self.funcs: 357 return self.funcs[func_name] 358 if not lib.bpf_function_start(self.module, func_name): 359 raise Exception("Unknown program %s" % func_name) 360 log_level = 0 361 if (self.debug & DEBUG_BPF_REGISTER_STATE): 362 log_level = 2 363 elif (self.debug & DEBUG_BPF): 364 log_level = 1 365 fd = lib.bpf_prog_load(prog_type, func_name, 366 lib.bpf_function_start(self.module, func_name), 367 lib.bpf_function_size(self.module, func_name), 368 lib.bpf_module_license(self.module), 369 lib.bpf_module_kern_version(self.module), 370 log_level, None, 0); 371 372 if fd < 0: 373 atexit.register(self.donothing) 374 if ct.get_errno() == errno.EPERM: 375 raise Exception("Need super-user privileges to run") 376 377 errstr = os.strerror(ct.get_errno()) 378 raise Exception("Failed to load BPF program %s: %s" % 379 (func_name, errstr)) 380 381 fn = BPF.Function(self, func_name, fd) 382 self.funcs[func_name] = fn 383 384 return fn 385 386 def dump_func(self, func_name): 387 """ 388 Return the eBPF bytecodes for the specified function as a string 389 """ 390 func_name = _assert_is_bytes(func_name) 391 if not lib.bpf_function_start(self.module, func_name): 392 raise Exception("Unknown program %s" % func_name) 393 394 start, = lib.bpf_function_start(self.module, func_name), 395 size, = lib.bpf_function_size(self.module, func_name), 396 return ct.string_at(start, size) 397 398 str2ctype = { 399 u"_Bool": ct.c_bool, 400 u"char": ct.c_char, 401 u"wchar_t": ct.c_wchar, 402 u"unsigned char": ct.c_ubyte, 403 u"short": ct.c_short, 404 u"unsigned short": ct.c_ushort, 405 u"int": ct.c_int, 406 u"unsigned int": ct.c_uint, 407 u"long": ct.c_long, 408 u"unsigned long": ct.c_ulong, 409 u"long long": ct.c_longlong, 410 u"unsigned long long": ct.c_ulonglong, 411 u"float": ct.c_float, 412 u"double": ct.c_double, 413 u"long double": ct.c_longdouble, 414 u"__int128": ct.c_int64 * 2, 415 u"unsigned __int128": ct.c_uint64 * 2, 416 } 417 @staticmethod 418 def _decode_table_type(desc): 419 if isinstance(desc, basestring): 420 return BPF.str2ctype[desc] 421 anon = [] 422 fields = [] 423 for t in desc[1]: 424 if len(t) == 2: 425 fields.append((t[0], BPF._decode_table_type(t[1]))) 426 elif len(t) == 3: 427 if isinstance(t[2], list): 428 fields.append((t[0], BPF._decode_table_type(t[1]) * t[2][0])) 429 elif isinstance(t[2], int): 430 fields.append((t[0], BPF._decode_table_type(t[1]), t[2])) 431 elif isinstance(t[2], basestring) and ( 432 t[2] == u"union" or t[2] == u"struct" or 433 t[2] == u"struct_packed"): 434 name = t[0] 435 if name == "": 436 name = "__anon%d" % len(anon) 437 anon.append(name) 438 fields.append((name, BPF._decode_table_type(t))) 439 else: 440 raise Exception("Failed to decode type %s" % str(t)) 441 else: 442 raise Exception("Failed to decode type %s" % str(t)) 443 base = ct.Structure 444 is_packed = False 445 if len(desc) > 2: 446 if desc[2] == u"union": 447 base = ct.Union 448 elif desc[2] == u"struct": 449 base = ct.Structure 450 elif desc[2] == u"struct_packed": 451 base = ct.Structure 452 is_packed = True 453 if is_packed: 454 cls = type(str(desc[0]), (base,), dict(_anonymous_=anon, _pack_=1, 455 _fields_=fields)) 456 else: 457 cls = type(str(desc[0]), (base,), dict(_anonymous_=anon, 458 _fields_=fields)) 459 return cls 460 461 def get_table(self, name, keytype=None, leaftype=None, reducer=None): 462 name = _assert_is_bytes(name) 463 map_id = lib.bpf_table_id(self.module, name) 464 map_fd = lib.bpf_table_fd(self.module, name) 465 if map_fd < 0: 466 raise KeyError 467 if not keytype: 468 key_desc = lib.bpf_table_key_desc(self.module, name).decode("utf-8") 469 if not key_desc: 470 raise Exception("Failed to load BPF Table %s key desc" % name) 471 keytype = BPF._decode_table_type(json.loads(key_desc)) 472 if not leaftype: 473 leaf_desc = lib.bpf_table_leaf_desc(self.module, name).decode("utf-8") 474 if not leaf_desc: 475 raise Exception("Failed to load BPF Table %s leaf desc" % name) 476 leaftype = BPF._decode_table_type(json.loads(leaf_desc)) 477 return Table(self, map_id, map_fd, keytype, leaftype, reducer=reducer) 478 479 def __getitem__(self, key): 480 if key not in self.tables: 481 self.tables[key] = self.get_table(key) 482 return self.tables[key] 483 484 def __setitem__(self, key, leaf): 485 self.tables[key] = leaf 486 487 def __len__(self): 488 return len(self.tables) 489 490 def __delitem__(self, key): 491 del self.tables[key] 492 493 def __iter__(self): 494 return self.tables.__iter__() 495 496 @staticmethod 497 def attach_raw_socket(fn, dev): 498 dev = _assert_is_bytes(dev) 499 if not isinstance(fn, BPF.Function): 500 raise Exception("arg 1 must be of type BPF.Function") 501 sock = lib.bpf_open_raw_sock(dev) 502 if sock < 0: 503 errstr = os.strerror(ct.get_errno()) 504 raise Exception("Failed to open raw device %s: %s" % (dev, errstr)) 505 res = lib.bpf_attach_socket(sock, fn.fd) 506 if res < 0: 507 errstr = os.strerror(ct.get_errno()) 508 raise Exception("Failed to attach BPF to device %s: %s" 509 % (dev, errstr)) 510 fn.sock = sock 511 512 @staticmethod 513 def get_kprobe_functions(event_re): 514 with open("%s/../kprobes/blacklist" % TRACEFS, "rb") as blacklist_f: 515 blacklist = set([line.rstrip().split()[1] for line in blacklist_f]) 516 fns = [] 517 518 in_init_section = 0 519 in_irq_section = 0 520 with open("/proc/kallsyms", "rb") as avail_file: 521 for line in avail_file: 522 (t, fn) = line.rstrip().split()[1:3] 523 # Skip all functions defined between __init_begin and 524 # __init_end 525 if in_init_section == 0: 526 if fn == b'__init_begin': 527 in_init_section = 1 528 continue 529 elif in_init_section == 1: 530 if fn == b'__init_end': 531 in_init_section = 2 532 continue 533 # Skip all functions defined between __irqentry_text_start and 534 # __irqentry_text_end 535 if in_irq_section == 0: 536 if fn == b'__irqentry_text_start': 537 in_irq_section = 1 538 continue 539 elif in_irq_section == 1: 540 if fn == b'__irqentry_text_end': 541 in_irq_section = 2 542 continue 543 # All functions defined as NOKPROBE_SYMBOL() start with the 544 # prefix _kbl_addr_*, blacklisting them by looking at the name 545 # allows to catch also those symbols that are defined in kernel 546 # modules. 547 if fn.startswith(b'_kbl_addr_'): 548 continue 549 # Explicitly blacklist perf-related functions, they are all 550 # non-attachable. 551 elif fn.startswith(b'__perf') or fn.startswith(b'perf_'): 552 continue 553 if (t.lower() in [b't', b'w']) and re.match(event_re, fn) \ 554 and fn not in blacklist: 555 fns.append(fn) 556 return set(fns) # Some functions may appear more than once 557 558 def _check_probe_quota(self, num_new_probes): 559 global _num_open_probes 560 if _num_open_probes + num_new_probes > _probe_limit: 561 raise Exception("Number of open probes would exceed global quota") 562 563 def _add_kprobe_fd(self, name, fd): 564 global _num_open_probes 565 self.kprobe_fds[name] = fd 566 _num_open_probes += 1 567 568 def _del_kprobe_fd(self, name): 569 global _num_open_probes 570 del self.kprobe_fds[name] 571 _num_open_probes -= 1 572 573 def _add_uprobe_fd(self, name, fd): 574 global _num_open_probes 575 self.uprobe_fds[name] = fd 576 _num_open_probes += 1 577 578 def _del_uprobe_fd(self, name): 579 global _num_open_probes 580 del self.uprobe_fds[name] 581 _num_open_probes -= 1 582 583 # Find current system's syscall prefix by testing on the BPF syscall. 584 # If no valid value found, will return the first possible value which 585 # would probably lead to error in later API calls. 586 def get_syscall_prefix(self): 587 for prefix in self._syscall_prefixes: 588 if self.ksymname(b"%sbpf" % prefix) != -1: 589 return prefix 590 return self._syscall_prefixes[0] 591 592 # Given a syscall's name, return the full Kernel function name with current 593 # system's syscall prefix. For example, given "clone" the helper would 594 # return "sys_clone" or "__x64_sys_clone". 595 def get_syscall_fnname(self, name): 596 name = _assert_is_bytes(name) 597 return self.get_syscall_prefix() + name 598 599 # Given a Kernel function name that represents a syscall but already has a 600 # prefix included, transform it to current system's prefix. For example, 601 # if "sys_clone" provided, the helper may translate it to "__x64_sys_clone". 602 def fix_syscall_fnname(self, name): 603 name = _assert_is_bytes(name) 604 for prefix in self._syscall_prefixes: 605 if name.startswith(prefix): 606 return self.get_syscall_fnname(name[len(prefix):]) 607 return name 608 609 def attach_kprobe(self, event=b"", event_off=0, fn_name=b"", event_re=b""): 610 event = _assert_is_bytes(event) 611 fn_name = _assert_is_bytes(fn_name) 612 event_re = _assert_is_bytes(event_re) 613 614 # allow the caller to glob multiple functions together 615 if event_re: 616 matches = BPF.get_kprobe_functions(event_re) 617 self._check_probe_quota(len(matches)) 618 for line in matches: 619 try: 620 self.attach_kprobe(event=line, fn_name=fn_name) 621 except: 622 pass 623 return 624 625 self._check_probe_quota(1) 626 fn = self.load_func(fn_name, BPF.KPROBE) 627 ev_name = b"p_" + event.replace(b"+", b"_").replace(b".", b"_") 628 fd = lib.bpf_attach_kprobe(fn.fd, 0, ev_name, event, event_off) 629 if fd < 0: 630 raise Exception("Failed to attach BPF program %s to kprobe %s" % 631 (fn_name, event)) 632 self._add_kprobe_fd(ev_name, fd) 633 return self 634 635 def attach_kretprobe(self, event=b"", fn_name=b"", event_re=b""): 636 event = _assert_is_bytes(event) 637 fn_name = _assert_is_bytes(fn_name) 638 event_re = _assert_is_bytes(event_re) 639 640 # allow the caller to glob multiple functions together 641 if event_re: 642 for line in BPF.get_kprobe_functions(event_re): 643 try: 644 self.attach_kretprobe(event=line, fn_name=fn_name) 645 except: 646 pass 647 return 648 649 self._check_probe_quota(1) 650 fn = self.load_func(fn_name, BPF.KPROBE) 651 ev_name = b"r_" + event.replace(b"+", b"_").replace(b".", b"_") 652 fd = lib.bpf_attach_kprobe(fn.fd, 1, ev_name, event, 0) 653 if fd < 0: 654 raise Exception("Failed to attach BPF program %s to kretprobe %s" % 655 (fn_name, event)) 656 self._add_kprobe_fd(ev_name, fd) 657 return self 658 659 def detach_kprobe_event(self, ev_name): 660 if ev_name not in self.kprobe_fds: 661 raise Exception("Kprobe %s is not attached" % ev_name) 662 res = lib.bpf_close_perf_event_fd(self.kprobe_fds[ev_name]) 663 if res < 0: 664 raise Exception("Failed to close kprobe FD") 665 res = lib.bpf_detach_kprobe(ev_name) 666 if res < 0: 667 raise Exception("Failed to detach BPF from kprobe") 668 self._del_kprobe_fd(ev_name) 669 670 def detach_kprobe(self, event): 671 event = _assert_is_bytes(event) 672 ev_name = b"p_" + event.replace(b"+", b"_").replace(b".", b"_") 673 self.detach_kprobe_event(ev_name) 674 675 def detach_kretprobe(self, event): 676 event = _assert_is_bytes(event) 677 ev_name = b"r_" + event.replace(b"+", b"_").replace(b".", b"_") 678 self.detach_kprobe_event(ev_name) 679 680 @staticmethod 681 def attach_xdp(dev, fn, flags=0): 682 ''' 683 This function attaches a BPF function to a device on the device 684 driver level (XDP) 685 ''' 686 dev = _assert_is_bytes(dev) 687 if not isinstance(fn, BPF.Function): 688 raise Exception("arg 1 must be of type BPF.Function") 689 res = lib.bpf_attach_xdp(dev, fn.fd, flags) 690 if res < 0: 691 err_no = ct.get_errno() 692 if err_no == errno.EBADMSG: 693 raise Exception("Internal error while attaching BPF to device,"+ 694 " try increasing the debug level!") 695 else: 696 errstr = os.strerror(err_no) 697 raise Exception("Failed to attach BPF to device %s: %s" 698 % (dev, errstr)) 699 700 @staticmethod 701 def remove_xdp(dev, flags=0): 702 ''' 703 This function removes any BPF function from a device on the 704 device driver level (XDP) 705 ''' 706 dev = _assert_is_bytes(dev) 707 res = lib.bpf_attach_xdp(dev, -1, flags) 708 if res < 0: 709 errstr = os.strerror(ct.get_errno()) 710 raise Exception("Failed to detach BPF from device %s: %s" 711 % (dev, errstr)) 712 713 714 715 @classmethod 716 def _check_path_symbol(cls, module, symname, addr, pid): 717 module = _assert_is_bytes(module) 718 symname = _assert_is_bytes(symname) 719 sym = bcc_symbol() 720 c_pid = 0 if pid == -1 else pid 721 if lib.bcc_resolve_symname( 722 module, symname, 723 addr or 0x0, c_pid, 724 ct.cast(None, ct.POINTER(bcc_symbol_option)), 725 ct.byref(sym), 726 ) < 0: 727 raise Exception("could not determine address of symbol %s" % symname) 728 module_path = ct.cast(sym.module, ct.c_char_p).value 729 lib.bcc_procutils_free(sym.module) 730 return module_path, sym.offset 731 732 @staticmethod 733 def find_library(libname): 734 libname = _assert_is_bytes(libname) 735 res = lib.bcc_procutils_which_so(libname, 0) 736 if not res: 737 return None 738 libpath = ct.cast(res, ct.c_char_p).value 739 lib.bcc_procutils_free(res) 740 return libpath 741 742 @staticmethod 743 def get_tracepoints(tp_re): 744 results = [] 745 events_dir = os.path.join(TRACEFS, "events") 746 for category in os.listdir(events_dir): 747 cat_dir = os.path.join(events_dir, category) 748 if not os.path.isdir(cat_dir): 749 continue 750 for event in os.listdir(cat_dir): 751 evt_dir = os.path.join(cat_dir, event) 752 if os.path.isdir(evt_dir): 753 tp = ("%s:%s" % (category, event)) 754 if re.match(tp_re, tp): 755 results.append(tp) 756 return results 757 758 @staticmethod 759 def tracepoint_exists(category, event): 760 evt_dir = os.path.join(TRACEFS, "events", category, event) 761 return os.path.isdir(evt_dir) 762 763 def attach_tracepoint(self, tp=b"", tp_re=b"", fn_name=b""): 764 """attach_tracepoint(tp="", tp_re="", fn_name="") 765 766 Run the bpf function denoted by fn_name every time the kernel tracepoint 767 specified by 'tp' is hit. The optional parameters pid, cpu, and group_fd 768 can be used to filter the probe. The tracepoint specification is simply 769 the tracepoint category and the tracepoint name, separated by a colon. 770 For example: sched:sched_switch, syscalls:sys_enter_bind, etc. 771 772 Instead of a tracepoint name, a regular expression can be provided in 773 tp_re. The program will then attach to tracepoints that match the 774 provided regular expression. 775 776 To obtain a list of kernel tracepoints, use the tplist tool or cat the 777 file /sys/kernel/debug/tracing/available_events. 778 779 Examples: 780 BPF(text).attach_tracepoint(tp="sched:sched_switch", fn_name="on_switch") 781 BPF(text).attach_tracepoint(tp_re="sched:.*", fn_name="on_switch") 782 """ 783 784 tp = _assert_is_bytes(tp) 785 tp_re = _assert_is_bytes(tp_re) 786 fn_name = _assert_is_bytes(fn_name) 787 if tp_re: 788 for tp in BPF.get_tracepoints(tp_re): 789 self.attach_tracepoint(tp=tp, fn_name=fn_name) 790 return 791 792 fn = self.load_func(fn_name, BPF.TRACEPOINT) 793 (tp_category, tp_name) = tp.split(b':') 794 fd = lib.bpf_attach_tracepoint(fn.fd, tp_category, tp_name) 795 if fd < 0: 796 raise Exception("Failed to attach BPF program %s to tracepoint %s" % 797 (fn_name, tp)) 798 self.tracepoint_fds[tp] = fd 799 return self 800 801 def attach_raw_tracepoint(self, tp=b"", fn_name=b""): 802 """attach_raw_tracepoint(self, tp=b"", fn_name=b"") 803 804 Run the bpf function denoted by fn_name every time the kernel tracepoint 805 specified by 'tp' is hit. The bpf function should be loaded as a 806 RAW_TRACEPOINT type. The fn_name is the kernel tracepoint name, 807 e.g., sched_switch, sys_enter_bind, etc. 808 809 Examples: 810 BPF(text).attach_raw_tracepoint(tp="sched_switch", fn_name="on_switch") 811 """ 812 813 tp = _assert_is_bytes(tp) 814 if tp in self.raw_tracepoint_fds: 815 raise Exception("Raw tracepoint %s has been attached" % tp) 816 817 fn_name = _assert_is_bytes(fn_name) 818 fn = self.load_func(fn_name, BPF.RAW_TRACEPOINT) 819 fd = lib.bpf_attach_raw_tracepoint(fn.fd, tp) 820 if fd < 0: 821 raise Exception("Failed to attach BPF to raw tracepoint") 822 self.raw_tracepoint_fds[tp] = fd; 823 return self 824 825 def detach_raw_tracepoint(self, tp=b""): 826 """detach_raw_tracepoint(tp="") 827 828 Stop running the bpf function that is attached to the kernel tracepoint 829 specified by 'tp'. 830 831 Example: bpf.detach_raw_tracepoint("sched_switch") 832 """ 833 834 tp = _assert_is_bytes(tp) 835 if tp not in self.raw_tracepoint_fds: 836 raise Exception("Raw tracepoint %s is not attached" % tp) 837 os.close(self.raw_tracepoint_fds[tp]) 838 del self.raw_tracepoint_fds[tp] 839 840 @staticmethod 841 def support_raw_tracepoint(): 842 # kernel symbol "bpf_find_raw_tracepoint" indicates raw_tracepint support 843 if BPF.ksymname("bpf_find_raw_tracepoint") != -1: 844 return True 845 return False 846 847 def detach_tracepoint(self, tp=b""): 848 """detach_tracepoint(tp="") 849 850 Stop running a bpf function that is attached to the kernel tracepoint 851 specified by 'tp'. 852 853 Example: bpf.detach_tracepoint("sched:sched_switch") 854 """ 855 856 tp = _assert_is_bytes(tp) 857 if tp not in self.tracepoint_fds: 858 raise Exception("Tracepoint %s is not attached" % tp) 859 res = lib.bpf_close_perf_event_fd(self.tracepoint_fds[tp]) 860 if res < 0: 861 raise Exception("Failed to detach BPF from tracepoint") 862 (tp_category, tp_name) = tp.split(b':') 863 res = lib.bpf_detach_tracepoint(tp_category, tp_name) 864 if res < 0: 865 raise Exception("Failed to detach BPF from tracepoint") 866 del self.tracepoint_fds[tp] 867 868 def _attach_perf_event(self, progfd, ev_type, ev_config, 869 sample_period, sample_freq, pid, cpu, group_fd): 870 res = lib.bpf_attach_perf_event(progfd, ev_type, ev_config, 871 sample_period, sample_freq, pid, cpu, group_fd) 872 if res < 0: 873 raise Exception("Failed to attach BPF to perf event") 874 return res 875 876 def attach_perf_event(self, ev_type=-1, ev_config=-1, fn_name=b"", 877 sample_period=0, sample_freq=0, pid=-1, cpu=-1, group_fd=-1): 878 fn_name = _assert_is_bytes(fn_name) 879 fn = self.load_func(fn_name, BPF.PERF_EVENT) 880 res = {} 881 if cpu >= 0: 882 res[cpu] = self._attach_perf_event(fn.fd, ev_type, ev_config, 883 sample_period, sample_freq, pid, cpu, group_fd) 884 else: 885 for i in get_online_cpus(): 886 res[i] = self._attach_perf_event(fn.fd, ev_type, ev_config, 887 sample_period, sample_freq, pid, i, group_fd) 888 self.open_perf_events[(ev_type, ev_config)] = res 889 890 def detach_perf_event(self, ev_type=-1, ev_config=-1): 891 try: 892 fds = self.open_perf_events[(ev_type, ev_config)] 893 except KeyError: 894 raise Exception("Perf event type {} config {} not attached".format( 895 ev_type, ev_config)) 896 897 res = 0 898 for fd in fds.values(): 899 res = lib.bpf_close_perf_event_fd(fd) or res 900 if res != 0: 901 raise Exception("Failed to detach BPF from perf event") 902 del self.open_perf_events[(ev_type, ev_config)] 903 904 @staticmethod 905 def get_user_functions(name, sym_re): 906 return set([name for (name, _) in 907 BPF.get_user_functions_and_addresses(name, sym_re)]) 908 909 @staticmethod 910 def get_user_addresses(name, sym_re): 911 """ 912 We are returning addresses here instead of symbol names because it 913 turns out that the same name may appear multiple times with different 914 addresses, and the same address may appear multiple times with the same 915 name. We can't attach a uprobe to the same address more than once, so 916 it makes sense to return the unique set of addresses that are mapped to 917 a symbol that matches the provided regular expression. 918 """ 919 return set([address for (_, address) in 920 BPF.get_user_functions_and_addresses(name, sym_re)]) 921 922 @staticmethod 923 def get_user_functions_and_addresses(name, sym_re): 924 name = _assert_is_bytes(name) 925 sym_re = _assert_is_bytes(sym_re) 926 addresses = [] 927 def sym_cb(sym_name, addr): 928 dname = sym_name 929 if re.match(sym_re, dname): 930 addresses.append((dname, addr)) 931 return 0 932 933 res = lib.bcc_foreach_function_symbol(name, _SYM_CB_TYPE(sym_cb)) 934 if res < 0: 935 raise Exception("Error %d enumerating symbols in %s" % (res, name)) 936 return addresses 937 938 def _get_uprobe_evname(self, prefix, path, addr, pid): 939 if pid == -1: 940 return b"%s_%s_0x%x" % (prefix, self._probe_repl.sub(b"_", path), addr) 941 else: 942 # if pid is valid, put pid in the name, so different pid 943 # can have different event names 944 return b"%s_%s_0x%x_%d" % (prefix, self._probe_repl.sub(b"_", path), addr, pid) 945 946 def attach_uprobe(self, name=b"", sym=b"", sym_re=b"", addr=None, 947 fn_name=b"", pid=-1): 948 """attach_uprobe(name="", sym="", sym_re="", addr=None, fn_name="" 949 pid=-1) 950 951 Run the bpf function denoted by fn_name every time the symbol sym in 952 the library or binary 'name' is encountered. The real address addr may 953 be supplied in place of sym. Optional parameters pid, cpu, and group_fd 954 can be used to filter the probe. 955 956 Instead of a symbol name, a regular expression can be provided in 957 sym_re. The uprobe will then attach to symbols that match the provided 958 regular expression. 959 960 Libraries can be given in the name argument without the lib prefix, or 961 with the full path (/usr/lib/...). Binaries can be given only with the 962 full path (/bin/sh). If a PID is given, the uprobe will attach to the 963 version of the library used by the process. 964 965 Example: BPF(text).attach_uprobe("c", "malloc") 966 BPF(text).attach_uprobe("/usr/bin/python", "main") 967 """ 968 969 name = _assert_is_bytes(name) 970 sym = _assert_is_bytes(sym) 971 sym_re = _assert_is_bytes(sym_re) 972 fn_name = _assert_is_bytes(fn_name) 973 974 if sym_re: 975 addresses = BPF.get_user_addresses(name, sym_re) 976 self._check_probe_quota(len(addresses)) 977 for sym_addr in addresses: 978 self.attach_uprobe(name=name, addr=sym_addr, 979 fn_name=fn_name, pid=pid) 980 return 981 982 (path, addr) = BPF._check_path_symbol(name, sym, addr, pid) 983 984 self._check_probe_quota(1) 985 fn = self.load_func(fn_name, BPF.KPROBE) 986 ev_name = self._get_uprobe_evname(b"p", path, addr, pid) 987 fd = lib.bpf_attach_uprobe(fn.fd, 0, ev_name, path, addr, pid) 988 if fd < 0: 989 raise Exception("Failed to attach BPF to uprobe") 990 self._add_uprobe_fd(ev_name, fd) 991 return self 992 993 def attach_uretprobe(self, name=b"", sym=b"", sym_re=b"", addr=None, 994 fn_name=b"", pid=-1): 995 """attach_uretprobe(name="", sym="", sym_re="", addr=None, fn_name="" 996 pid=-1) 997 998 Run the bpf function denoted by fn_name every time the symbol sym in 999 the library or binary 'name' finishes execution. See attach_uprobe for 1000 meaning of additional parameters. 1001 """ 1002 1003 name = _assert_is_bytes(name) 1004 sym = _assert_is_bytes(sym) 1005 sym_re = _assert_is_bytes(sym_re) 1006 fn_name = _assert_is_bytes(fn_name) 1007 1008 if sym_re: 1009 for sym_addr in BPF.get_user_addresses(name, sym_re): 1010 self.attach_uretprobe(name=name, addr=sym_addr, 1011 fn_name=fn_name, pid=pid) 1012 return 1013 1014 (path, addr) = BPF._check_path_symbol(name, sym, addr, pid) 1015 1016 self._check_probe_quota(1) 1017 fn = self.load_func(fn_name, BPF.KPROBE) 1018 ev_name = self._get_uprobe_evname(b"r", path, addr, pid) 1019 fd = lib.bpf_attach_uprobe(fn.fd, 1, ev_name, path, addr, pid) 1020 if fd < 0: 1021 raise Exception("Failed to attach BPF to uretprobe") 1022 self._add_uprobe_fd(ev_name, fd) 1023 return self 1024 1025 def detach_uprobe_event(self, ev_name): 1026 if ev_name not in self.uprobe_fds: 1027 raise Exception("Uprobe %s is not attached" % ev_name) 1028 res = lib.bpf_close_perf_event_fd(self.uprobe_fds[ev_name]) 1029 if res < 0: 1030 raise Exception("Failed to detach BPF from uprobe") 1031 res = lib.bpf_detach_uprobe(ev_name) 1032 if res < 0: 1033 raise Exception("Failed to detach BPF from uprobe") 1034 self._del_uprobe_fd(ev_name) 1035 1036 def detach_uprobe(self, name=b"", sym=b"", addr=None, pid=-1): 1037 """detach_uprobe(name="", sym="", addr=None, pid=-1) 1038 1039 Stop running a bpf function that is attached to symbol 'sym' in library 1040 or binary 'name'. 1041 """ 1042 1043 name = _assert_is_bytes(name) 1044 sym = _assert_is_bytes(sym) 1045 (path, addr) = BPF._check_path_symbol(name, sym, addr, pid) 1046 ev_name = self._get_uprobe_evname(b"p", path, addr, pid) 1047 self.detach_uprobe_event(ev_name) 1048 1049 def detach_uretprobe(self, name=b"", sym=b"", addr=None, pid=-1): 1050 """detach_uretprobe(name="", sym="", addr=None, pid=-1) 1051 1052 Stop running a bpf function that is attached to symbol 'sym' in library 1053 or binary 'name'. 1054 """ 1055 1056 name = _assert_is_bytes(name) 1057 sym = _assert_is_bytes(sym) 1058 1059 (path, addr) = BPF._check_path_symbol(name, sym, addr, pid) 1060 ev_name = self._get_uprobe_evname(b"r", path, addr, pid) 1061 self.detach_uprobe_event(ev_name) 1062 1063 def _trace_autoload(self): 1064 for i in range(0, lib.bpf_num_functions(self.module)): 1065 func_name = lib.bpf_function_name(self.module, i) 1066 if func_name.startswith(b"kprobe__"): 1067 fn = self.load_func(func_name, BPF.KPROBE) 1068 self.attach_kprobe( 1069 event=self.fix_syscall_fnname(func_name[8:]), 1070 fn_name=fn.name) 1071 elif func_name.startswith(b"kretprobe__"): 1072 fn = self.load_func(func_name, BPF.KPROBE) 1073 self.attach_kretprobe( 1074 event=self.fix_syscall_fnname(func_name[11:]), 1075 fn_name=fn.name) 1076 elif func_name.startswith(b"tracepoint__"): 1077 fn = self.load_func(func_name, BPF.TRACEPOINT) 1078 tp = fn.name[len(b"tracepoint__"):].replace(b"__", b":") 1079 self.attach_tracepoint(tp=tp, fn_name=fn.name) 1080 elif func_name.startswith(b"raw_tracepoint__"): 1081 fn = self.load_func(func_name, BPF.RAW_TRACEPOINT) 1082 tp = fn.name[len(b"raw_tracepoint__"):] 1083 self.attach_raw_tracepoint(tp=tp, fn_name=fn.name) 1084 1085 def trace_open(self, nonblocking=False): 1086 """trace_open(nonblocking=False) 1087 1088 Open the trace_pipe if not already open 1089 """ 1090 if not self.tracefile: 1091 self.tracefile = open("%s/trace_pipe" % TRACEFS, "rb") 1092 if nonblocking: 1093 fd = self.tracefile.fileno() 1094 fl = fcntl.fcntl(fd, fcntl.F_GETFL) 1095 fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) 1096 return self.tracefile 1097 1098 def trace_fields(self, nonblocking=False): 1099 """trace_fields(nonblocking=False) 1100 1101 Read from the kernel debug trace pipe and return a tuple of the 1102 fields (task, pid, cpu, flags, timestamp, msg) or None if no 1103 line was read (nonblocking=True) 1104 """ 1105 while True: 1106 line = self.trace_readline(nonblocking) 1107 if not line and nonblocking: return (None,) * 6 1108 # don't print messages related to lost events 1109 if line.startswith(b"CPU:"): continue 1110 task = line[:16].lstrip() 1111 line = line[17:] 1112 ts_end = line.find(b":") 1113 pid, cpu, flags, ts = line[:ts_end].split() 1114 cpu = cpu[1:-1] 1115 # line[ts_end:] will have ": [sym_or_addr]: msgs" 1116 # For trace_pipe debug output, the addr typically 1117 # is invalid (e.g., 0x1). For kernel 4.12 or earlier, 1118 # if address is not able to match a kernel symbol, 1119 # nothing will be printed out. For kernel 4.13 and later, 1120 # however, the illegal address will be printed out. 1121 # Hence, both cases are handled here. 1122 line = line[ts_end + 1:] 1123 sym_end = line.find(b":") 1124 msg = line[sym_end + 2:] 1125 return (task, int(pid), int(cpu), flags, float(ts), msg) 1126 1127 def trace_readline(self, nonblocking=False): 1128 """trace_readline(nonblocking=False) 1129 1130 Read from the kernel debug trace pipe and return one line 1131 If nonblocking is False, this will block until ctrl-C is pressed. 1132 """ 1133 1134 trace = self.trace_open(nonblocking) 1135 1136 line = None 1137 try: 1138 line = trace.readline(1024).rstrip() 1139 except IOError: 1140 pass 1141 return line 1142 1143 def trace_print(self, fmt=None): 1144 """trace_print(self, fmt=None) 1145 1146 Read from the kernel debug trace pipe and print on stdout. 1147 If fmt is specified, apply as a format string to the output. See 1148 trace_fields for the members of the tuple 1149 example: trace_print(fmt="pid {1}, msg = {5}") 1150 """ 1151 1152 while True: 1153 if fmt: 1154 fields = self.trace_fields(nonblocking=False) 1155 if not fields: continue 1156 line = fmt.format(*fields) 1157 else: 1158 line = self.trace_readline(nonblocking=False) 1159 print(line) 1160 sys.stdout.flush() 1161 1162 @staticmethod 1163 def _sym_cache(pid): 1164 """_sym_cache(pid) 1165 1166 Returns a symbol cache for the specified PID. 1167 The kernel symbol cache is accessed by providing any PID less than zero. 1168 """ 1169 if pid < 0 and pid != -1: 1170 pid = -1 1171 if not pid in BPF._sym_caches: 1172 BPF._sym_caches[pid] = SymbolCache(pid) 1173 return BPF._sym_caches[pid] 1174 1175 @staticmethod 1176 def sym(addr, pid, show_module=False, show_offset=False, demangle=True): 1177 """sym(addr, pid, show_module=False, show_offset=False) 1178 1179 Translate a memory address into a function name for a pid, which is 1180 returned. When show_module is True, the module name is also included. 1181 When show_offset is True, the instruction offset as a hexadecimal 1182 number is also included in the string. 1183 1184 A pid of less than zero will access the kernel symbol cache. 1185 1186 Example output when both show_module and show_offset are True: 1187 "start_thread+0x202 [libpthread-2.24.so]" 1188 1189 Example output when both show_module and show_offset are False: 1190 "start_thread" 1191 """ 1192 name, offset, module = BPF._sym_cache(pid).resolve(addr, demangle) 1193 offset = b"+0x%x" % offset if show_offset and name is not None else b"" 1194 name = name or b"[unknown]" 1195 name = name + offset 1196 module = b" [%s]" % os.path.basename(module) \ 1197 if show_module and module is not None else b"" 1198 return name + module 1199 1200 @staticmethod 1201 def ksym(addr, show_module=False, show_offset=False): 1202 """ksym(addr) 1203 1204 Translate a kernel memory address into a kernel function name, which is 1205 returned. When show_module is True, the module name ("kernel") is also 1206 included. When show_offset is true, the instruction offset as a 1207 hexadecimal number is also included in the string. 1208 1209 Example output when both show_module and show_offset are True: 1210 "default_idle+0x0 [kernel]" 1211 """ 1212 return BPF.sym(addr, -1, show_module, show_offset, False) 1213 1214 @staticmethod 1215 def ksymname(name): 1216 """ksymname(name) 1217 1218 Translate a kernel name into an address. This is the reverse of 1219 ksym. Returns -1 when the function name is unknown.""" 1220 return BPF._sym_cache(-1).resolve_name(None, name) 1221 1222 def num_open_kprobes(self): 1223 """num_open_kprobes() 1224 1225 Get the number of open K[ret]probes. Can be useful for scenarios where 1226 event_re is used while attaching and detaching probes. 1227 """ 1228 return len(self.kprobe_fds) 1229 1230 def num_open_uprobes(self): 1231 """num_open_uprobes() 1232 1233 Get the number of open U[ret]probes. 1234 """ 1235 return len(self.uprobe_fds) 1236 1237 def num_open_tracepoints(self): 1238 """num_open_tracepoints() 1239 1240 Get the number of open tracepoints. 1241 """ 1242 return len(self.tracepoint_fds) 1243 1244 def perf_buffer_poll(self, timeout = -1): 1245 """perf_buffer_poll(self) 1246 1247 Poll from all open perf ring buffers, calling the callback that was 1248 provided when calling open_perf_buffer for each entry. 1249 """ 1250 readers = (ct.c_void_p * len(self.perf_buffers))() 1251 for i, v in enumerate(self.perf_buffers.values()): 1252 readers[i] = v 1253 lib.perf_reader_poll(len(readers), readers, timeout) 1254 1255 def kprobe_poll(self, timeout = -1): 1256 """kprobe_poll(self) 1257 1258 Deprecated. Use perf_buffer_poll instead. 1259 """ 1260 self.perf_buffer_poll(timeout) 1261 1262 def free_bcc_memory(self): 1263 return lib.bcc_free_memory() 1264 1265 def donothing(self): 1266 """the do nothing exit handler""" 1267 1268 def cleanup(self): 1269 # Clean up opened probes 1270 for k, v in list(self.kprobe_fds.items()): 1271 self.detach_kprobe_event(k) 1272 for k, v in list(self.uprobe_fds.items()): 1273 self.detach_uprobe_event(k) 1274 for k, v in list(self.tracepoint_fds.items()): 1275 self.detach_tracepoint(k) 1276 for k, v in list(self.raw_tracepoint_fds.items()): 1277 self.detach_raw_tracepoint(k) 1278 1279 # Clean up opened perf ring buffer and perf events 1280 table_keys = list(self.tables.keys()) 1281 for key in table_keys: 1282 if isinstance(self.tables[key], PerfEventArray): 1283 del self.tables[key] 1284 for (ev_type, ev_config) in list(self.open_perf_events.keys()): 1285 self.detach_perf_event(ev_type, ev_config) 1286 if self.tracefile: 1287 self.tracefile.close() 1288 self.tracefile = None 1289 if self.module: 1290 lib.bpf_module_destroy(self.module) 1291 self.module = None 1292 1293 def __enter__(self): 1294 return self 1295 1296 def __exit__(self, exc_type, exc_val, exc_tb): 1297 self.cleanup() 1298 1299 1300from .usdt import USDT, USDTException 1301