summaryrefslogtreecommitdiff
path: root/scripts/gdb/linux
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-12-06 14:01:20 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2025-12-06 14:01:20 -0800
commit509d3f45847627f4c5cdce004c3ec79262b5239c (patch)
tree3f5d650b393eeb0e560f78958bb20d6645ca55e0 /scripts/gdb/linux
parent09670b8c38b37bc2d6fc5d01fa7e02c38f7adf36 (diff)
parentaa514a297a0c175239f24a2e582ebd37f0727494 (diff)
Merge tag 'mm-nonmm-stable-2025-12-06-11-14' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull non-MM updates from Andrew Morton: - "panic: sys_info: Refactor and fix a potential issue" (Andy Shevchenko) fixes a build issue and does some cleanup in ib/sys_info.c - "Implement mul_u64_u64_div_u64_roundup()" (David Laight) enhances the 64-bit math code on behalf of a PWM driver and beefs up the test module for these library functions - "scripts/gdb/symbols: make BPF debug info available to GDB" (Ilya Leoshkevich) makes BPF symbol names, sizes, and line numbers available to the GDB debugger - "Enable hung_task and lockup cases to dump system info on demand" (Feng Tang) adds a sysctl which can be used to cause additional info dumping when the hung-task and lockup detectors fire - "lib/base64: add generic encoder/decoder, migrate users" (Kuan-Wei Chiu) adds a general base64 encoder/decoder to lib/ and migrates several users away from their private implementations - "rbree: inline rb_first() and rb_last()" (Eric Dumazet) makes TCP a little faster - "liveupdate: Rework KHO for in-kernel users" (Pasha Tatashin) reworks the KEXEC Handover interfaces in preparation for Live Update Orchestrator (LUO), and possibly for other future clients - "kho: simplify state machine and enable dynamic updates" (Pasha Tatashin) increases the flexibility of KEXEC Handover. Also preparation for LUO - "Live Update Orchestrator" (Pasha Tatashin) is a major new feature targeted at cloud environments. Quoting the cover letter: This series introduces the Live Update Orchestrator, a kernel subsystem designed to facilitate live kernel updates using a kexec-based reboot. This capability is critical for cloud environments, allowing hypervisors to be updated with minimal downtime for running virtual machines. LUO achieves this by preserving the state of selected resources, such as memory, devices and their dependencies, across the kernel transition. As a key feature, this series includes support for preserving memfd file descriptors, which allows critical in-memory data, such as guest RAM or any other large memory region, to be maintained in RAM across the kexec reboot. Mike Rappaport merits a mention here, for his extensive review and testing work. - "kexec: reorganize kexec and kdump sysfs" (Sourabh Jain) moves the kexec and kdump sysfs entries from /sys/kernel/ to /sys/kernel/kexec/ and adds back-compatibility symlinks which can hopefully be removed one day - "kho: fixes for vmalloc restoration" (Mike Rapoport) fixes a BUG which was being hit during KHO restoration of vmalloc() regions * tag 'mm-nonmm-stable-2025-12-06-11-14' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (139 commits) calibrate: update header inclusion Reinstate "resource: avoid unnecessary lookups in find_next_iomem_res()" vmcoreinfo: track and log recoverable hardware errors kho: fix restoring of contiguous ranges of order-0 pages kho: kho_restore_vmalloc: fix initialization of pages array MAINTAINERS: TPM DEVICE DRIVER: update the W-tag init: replace simple_strtoul with kstrtoul to improve lpj_setup KHO: fix boot failure due to kmemleak access to non-PRESENT pages Documentation/ABI: new kexec and kdump sysfs interface Documentation/ABI: mark old kexec sysfs deprecated kexec: move sysfs entries to /sys/kernel/kexec test_kho: always print restore status kho: free chunks using free_page() instead of kfree() selftests/liveupdate: add kexec test for multiple and empty sessions selftests/liveupdate: add simple kexec-based selftest for LUO selftests/liveupdate: add userspace API selftests docs: add documentation for memfd preservation via LUO mm: memfd_luo: allow preserving memfd liveupdate: luo_file: add private argument to store runtime state mm: shmem: export some functions to internal.h ...
Diffstat (limited to 'scripts/gdb/linux')
-rw-r--r--scripts/gdb/linux/bpf.py253
-rw-r--r--scripts/gdb/linux/constants.py.in3
-rw-r--r--scripts/gdb/linux/radixtree.py139
-rw-r--r--scripts/gdb/linux/symbols.py105
4 files changed, 481 insertions, 19 deletions
diff --git a/scripts/gdb/linux/bpf.py b/scripts/gdb/linux/bpf.py
new file mode 100644
index 000000000000..1870534ef6f9
--- /dev/null
+++ b/scripts/gdb/linux/bpf.py
@@ -0,0 +1,253 @@
+# SPDX-License-Identifier: GPL-2.0
+
+import json
+import subprocess
+import tempfile
+
+import gdb
+
+from linux import constants, lists, radixtree, utils
+
+
+if constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT:
+ bpf_ksym_type = utils.CachedType("struct bpf_ksym")
+if constants.LX_CONFIG_BPF_SYSCALL:
+ bpf_prog_type = utils.CachedType("struct bpf_prog")
+
+
+def get_ksym_name(ksym):
+ name = ksym["name"].bytes
+ end = name.find(b"\x00")
+ if end != -1:
+ name = name[:end]
+ return name.decode()
+
+
+def list_ksyms():
+ if not (constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT):
+ return []
+ bpf_kallsyms = gdb.parse_and_eval("&bpf_kallsyms")
+ bpf_ksym_ptr_type = bpf_ksym_type.get_type().pointer()
+ return list(lists.list_for_each_entry(bpf_kallsyms,
+ bpf_ksym_ptr_type,
+ "lnode"))
+
+
+class KsymAddBreakpoint(gdb.Breakpoint):
+ def __init__(self, monitor):
+ super(KsymAddBreakpoint, self).__init__("bpf_ksym_add", internal=True)
+ self.silent = True
+ self.monitor = monitor
+
+ def stop(self):
+ self.monitor.add(gdb.parse_and_eval("ksym"))
+ return False
+
+
+class KsymRemoveBreakpoint(gdb.Breakpoint):
+ def __init__(self, monitor):
+ super(KsymRemoveBreakpoint, self).__init__("bpf_ksym_del",
+ internal=True)
+ self.silent = True
+ self.monitor = monitor
+
+ def stop(self):
+ self.monitor.remove(gdb.parse_and_eval("ksym"))
+ return False
+
+
+class KsymMonitor:
+ def __init__(self, add, remove):
+ self.add = add
+ self.remove = remove
+
+ self.add_bp = KsymAddBreakpoint(self)
+ self.remove_bp = KsymRemoveBreakpoint(self)
+
+ self.notify_initial()
+
+ def notify_initial(self):
+ for ksym in list_ksyms():
+ self.add(ksym)
+
+ def delete(self):
+ self.add_bp.delete()
+ self.remove_bp.delete()
+
+
+def list_progs():
+ if not constants.LX_CONFIG_BPF_SYSCALL:
+ return []
+ idr_rt = gdb.parse_and_eval("&prog_idr.idr_rt")
+ bpf_prog_ptr_type = bpf_prog_type.get_type().pointer()
+ progs = []
+ for _, slot in radixtree.for_each_slot(idr_rt):
+ prog = slot.dereference().cast(bpf_prog_ptr_type)
+ progs.append(prog)
+ # Subprogs are not registered in prog_idr, fetch them manually.
+ # func[0] is the current prog.
+ aux = prog["aux"]
+ func = aux["func"]
+ real_func_cnt = int(aux["real_func_cnt"])
+ for i in range(1, real_func_cnt):
+ progs.append(func[i])
+ return progs
+
+
+class ProgAddBreakpoint(gdb.Breakpoint):
+ def __init__(self, monitor):
+ super(ProgAddBreakpoint, self).__init__("bpf_prog_kallsyms_add",
+ internal=True)
+ self.silent = True
+ self.monitor = monitor
+
+ def stop(self):
+ self.monitor.add(gdb.parse_and_eval("fp"))
+ return False
+
+
+class ProgRemoveBreakpoint(gdb.Breakpoint):
+ def __init__(self, monitor):
+ super(ProgRemoveBreakpoint, self).__init__("bpf_prog_free_id",
+ internal=True)
+ self.silent = True
+ self.monitor = monitor
+
+ def stop(self):
+ self.monitor.remove(gdb.parse_and_eval("prog"))
+ return False
+
+
+class ProgMonitor:
+ def __init__(self, add, remove):
+ self.add = add
+ self.remove = remove
+
+ self.add_bp = ProgAddBreakpoint(self)
+ self.remove_bp = ProgRemoveBreakpoint(self)
+
+ self.notify_initial()
+
+ def notify_initial(self):
+ for prog in list_progs():
+ self.add(prog)
+
+ def delete(self):
+ self.add_bp.delete()
+ self.remove_bp.delete()
+
+
+def btf_str_by_offset(btf, offset):
+ while offset < btf["start_str_off"]:
+ btf = btf["base_btf"]
+
+ offset -= btf["start_str_off"]
+ if offset < btf["hdr"]["str_len"]:
+ return (btf["strings"] + offset).string()
+
+ return None
+
+
+def bpf_line_info_line_num(line_col):
+ return line_col >> 10
+
+
+def bpf_line_info_line_col(line_col):
+ return line_col & 0x3ff
+
+
+class LInfoIter:
+ def __init__(self, prog):
+ # See bpf_prog_get_file_line() for details.
+ self.pos = 0
+ self.nr_linfo = 0
+
+ if prog is None:
+ return
+
+ self.bpf_func = int(prog["bpf_func"])
+ aux = prog["aux"]
+ self.btf = aux["btf"]
+ linfo_idx = aux["linfo_idx"]
+ self.nr_linfo = int(aux["nr_linfo"]) - linfo_idx
+ if self.nr_linfo == 0:
+ return
+
+ linfo_ptr = aux["linfo"]
+ tpe = linfo_ptr.type.target().array(self.nr_linfo).pointer()
+ self.linfo = (linfo_ptr + linfo_idx).cast(tpe).dereference()
+ jited_linfo_ptr = aux["jited_linfo"]
+ tpe = jited_linfo_ptr.type.target().array(self.nr_linfo).pointer()
+ self.jited_linfo = (jited_linfo_ptr + linfo_idx).cast(tpe).dereference()
+
+ self.filenos = {}
+
+ def get_code_off(self):
+ if self.pos >= self.nr_linfo:
+ return -1
+ return self.jited_linfo[self.pos] - self.bpf_func
+
+ def advance(self):
+ self.pos += 1
+
+ def get_fileno(self):
+ file_name_off = int(self.linfo[self.pos]["file_name_off"])
+ fileno = self.filenos.get(file_name_off)
+ if fileno is not None:
+ return fileno, None
+ file_name = btf_str_by_offset(self.btf, file_name_off)
+ fileno = len(self.filenos) + 1
+ self.filenos[file_name_off] = fileno
+ return fileno, file_name
+
+ def get_line_col(self):
+ line_col = int(self.linfo[self.pos]["line_col"])
+ return bpf_line_info_line_num(line_col), \
+ bpf_line_info_line_col(line_col)
+
+
+def generate_debug_obj(ksym, prog):
+ name = get_ksym_name(ksym)
+ # Avoid read_memory(); it throws bogus gdb.MemoryError in some contexts.
+ start = ksym["start"]
+ code = start.cast(gdb.lookup_type("unsigned char")
+ .array(int(ksym["end"]) - int(start))
+ .pointer()).dereference().bytes
+ linfo_iter = LInfoIter(prog)
+
+ result = tempfile.NamedTemporaryFile(suffix=".o", mode="wb")
+ try:
+ with tempfile.NamedTemporaryFile(suffix=".s", mode="w") as src:
+ # ".loc" does not apply to ".byte"s, only to ".insn"s, but since
+ # this needs to work for all architectures, the latter are not an
+ # option. Ask the assembler to apply ".loc"s to labels as well,
+ # and generate dummy labels after each ".loc".
+ src.write(".loc_mark_labels 1\n")
+
+ src.write(".globl {}\n".format(name))
+ src.write(".type {},@function\n".format(name))
+ src.write("{}:\n".format(name))
+ for code_off, code_byte in enumerate(code):
+ if linfo_iter.get_code_off() == code_off:
+ fileno, file_name = linfo_iter.get_fileno()
+ if file_name is not None:
+ src.write(".file {} {}\n".format(
+ fileno, json.dumps(file_name)))
+ line, col = linfo_iter.get_line_col()
+ src.write(".loc {} {} {}\n".format(fileno, line, col))
+ src.write("0:\n")
+ linfo_iter.advance()
+ src.write(".byte {}\n".format(code_byte))
+ src.write(".size {},{}\n".format(name, len(code)))
+ src.flush()
+
+ try:
+ subprocess.check_call(["as", "-c", src.name, "-o", result.name])
+ except FileNotFoundError:
+ # "as" is not installed.
+ result.close()
+ return None
+ return result
+ except:
+ result.close()
+ raise
diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
index c3886739a028..6d475540c6ba 100644
--- a/scripts/gdb/linux/constants.py.in
+++ b/scripts/gdb/linux/constants.py.in
@@ -170,3 +170,6 @@ LX_CONFIG(CONFIG_PAGE_OWNER)
LX_CONFIG(CONFIG_SLUB_DEBUG)
LX_CONFIG(CONFIG_SLAB_FREELIST_HARDENED)
LX_CONFIG(CONFIG_MMU)
+LX_CONFIG(CONFIG_BPF)
+LX_CONFIG(CONFIG_BPF_JIT)
+LX_CONFIG(CONFIG_BPF_SYSCALL)
diff --git a/scripts/gdb/linux/radixtree.py b/scripts/gdb/linux/radixtree.py
index 074543ac763d..bc2954e45c32 100644
--- a/scripts/gdb/linux/radixtree.py
+++ b/scripts/gdb/linux/radixtree.py
@@ -30,13 +30,16 @@ def entry_to_node(node):
def node_maxindex(node):
return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1
-def lookup(root, index):
+def resolve_root(root):
+ if root.type == radix_tree_root_type.get_type():
+ return root
if root.type == radix_tree_root_type.get_type().pointer():
- node = root.dereference()
- elif root.type != radix_tree_root_type.get_type():
- raise gdb.GdbError("must be {} not {}"
- .format(radix_tree_root_type.get_type(), root.type))
+ return root.dereference()
+ raise gdb.GdbError("must be {} not {}"
+ .format(radix_tree_root_type.get_type(), root.type))
+def lookup(root, index):
+ root = resolve_root(root)
node = root['xa_head']
if node == 0:
return None
@@ -71,14 +74,120 @@ def lookup(root, index):
return node
-class LxRadixTree(gdb.Function):
+def descend(parent, index):
+ offset = (index >> int(parent["shift"])) & constants.LX_RADIX_TREE_MAP_MASK
+ return offset, parent["slots"][offset]
+
+def load_root(root):
+ node = root["xa_head"]
+ nodep = node
+
+ if is_internal_node(node):
+ node = entry_to_node(node)
+ maxindex = node_maxindex(node)
+ return int(node["shift"]) + constants.LX_RADIX_TREE_MAP_SHIFT, \
+ nodep, maxindex
+
+ return 0, nodep, 0
+
+class RadixTreeIter:
+ def __init__(self, start):
+ self.index = 0
+ self.next_index = start
+ self.node = None
+
+def xa_mk_internal(v):
+ return (v << 2) | 2
+
+LX_XA_RETRY_ENTRY = xa_mk_internal(256)
+LX_RADIX_TREE_RETRY = LX_XA_RETRY_ENTRY
+
+def next_chunk(root, iter):
+ mask = (1 << (utils.get_ulong_type().sizeof * 8)) - 1
+
+ index = iter.next_index
+ if index == 0 and iter.index != 0:
+ return None
+
+ restart = True
+ while restart:
+ restart = False
+
+ _, child, maxindex = load_root(root)
+ if index > maxindex:
+ return None
+ if not child:
+ return None
+
+ if not is_internal_node(child):
+ iter.index = index
+ iter.next_index = (maxindex + 1) & mask
+ iter.node = None
+ return root["xa_head"].address
+
+ while True:
+ node = entry_to_node(child)
+ offset, child = descend(node, index)
+
+ if not child:
+ while True:
+ offset += 1
+ if offset >= constants.LX_RADIX_TREE_MAP_SIZE:
+ break
+ slot = node["slots"][offset]
+ if slot:
+ break
+ index &= ~node_maxindex(node)
+ index = (index + (offset << int(node["shift"]))) & mask
+ if index == 0:
+ return None
+ if offset == constants.LX_RADIX_TREE_MAP_SIZE:
+ restart = True
+ break
+ child = node["slots"][offset]
+
+ if not child:
+ restart = True
+ break
+ if child == LX_XA_RETRY_ENTRY:
+ break
+ if not node["shift"] or not is_internal_node(child):
+ break
+
+ iter.index = (index & ~node_maxindex(node)) | offset
+ iter.next_index = ((index | node_maxindex(node)) + 1) & mask
+ iter.node = node
+
+ return node["slots"][offset].address
+
+def next_slot(slot, iter):
+ mask = (1 << (utils.get_ulong_type().sizeof * 8)) - 1
+ for _ in range(iter.next_index - iter.index - 1):
+ slot += 1
+ iter.index = (iter.index + 1) & mask
+ if slot.dereference():
+ return slot
+ return None
+
+def for_each_slot(root, start=0):
+ iter = RadixTreeIter(start)
+ slot = None
+ while True:
+ if not slot:
+ slot = next_chunk(root, iter)
+ if not slot:
+ break
+ yield iter.index, slot
+ slot = next_slot(slot, iter)
+
+class LxRadixTreeLookup(gdb.Function):
""" Lookup and return a node from a RadixTree.
$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index.
If index is omitted, the root node is dereference and returned."""
def __init__(self):
- super(LxRadixTree, self).__init__("lx_radix_tree_lookup")
+ super(LxRadixTreeLookup, self).__init__("lx_radix_tree_lookup")
def invoke(self, root, index=0):
result = lookup(root, index)
@@ -87,4 +196,20 @@ If index is omitted, the root node is dereference and returned."""
return result
+class LxRadixTree(gdb.Command):
+ """Show all values stored in a RadixTree."""
+
+ def __init__(self):
+ super(LxRadixTree, self).__init__("lx-radix-tree", gdb.COMMAND_DATA,
+ gdb.COMPLETE_NONE)
+
+ def invoke(self, argument, from_tty):
+ args = gdb.string_to_argv(argument)
+ if len(args) != 1:
+ raise gdb.GdbError("Usage: lx-radix-tree ROOT")
+ root = gdb.parse_and_eval(args[0])
+ for index, slot in for_each_slot(root):
+ gdb.write("[{}] = {}\n".format(index, slot.dereference()))
+
LxRadixTree()
+LxRadixTreeLookup()
diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py
index 6edb99221675..d4308b726183 100644
--- a/scripts/gdb/linux/symbols.py
+++ b/scripts/gdb/linux/symbols.py
@@ -11,13 +11,14 @@
# This work is licensed under the terms of the GNU GPL version 2.
#
+import atexit
import gdb
import os
import re
import struct
from itertools import count
-from linux import modules, utils, constants
+from linux import bpf, constants, modules, utils
if hasattr(gdb, 'Breakpoint'):
@@ -114,17 +115,27 @@ class LxSymbols(gdb.Command):
The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
are scanned recursively, starting in the same directory. Optionally, the module
search path can be extended by a space separated list of paths passed to the
-lx-symbols command."""
+lx-symbols command.
+
+When the -bpf flag is specified, symbols from the currently loaded BPF programs
+are loaded as well."""
module_paths = []
module_files = []
module_files_updated = False
loaded_modules = []
breakpoint = None
+ bpf_prog_monitor = None
+ bpf_ksym_monitor = None
+ bpf_progs = {}
+ # The remove-symbol-file command, even when invoked with -a, requires the
+ # respective object file to exist, so keep them around.
+ bpf_debug_objs = {}
def __init__(self):
super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
gdb.COMPLETE_FILENAME)
+ atexit.register(self.cleanup_bpf)
def _update_module_files(self):
self.module_files = []
@@ -197,6 +208,51 @@ lx-symbols command."""
else:
gdb.write("no module object found for '{0}'\n".format(module_name))
+ def add_bpf_prog(self, prog):
+ if prog["jited"]:
+ self.bpf_progs[int(prog["bpf_func"])] = prog
+
+ def remove_bpf_prog(self, prog):
+ self.bpf_progs.pop(int(prog["bpf_func"]), None)
+
+ def add_bpf_ksym(self, ksym):
+ addr = int(ksym["start"])
+ name = bpf.get_ksym_name(ksym)
+ with utils.pagination_off():
+ gdb.write("loading @{addr}: {name}\n".format(
+ addr=hex(addr), name=name))
+ debug_obj = bpf.generate_debug_obj(ksym, self.bpf_progs.get(addr))
+ if debug_obj is None:
+ return
+ try:
+ cmdline = "add-symbol-file {obj} {addr}".format(
+ obj=debug_obj.name, addr=hex(addr))
+ gdb.execute(cmdline, to_string=True)
+ except:
+ debug_obj.close()
+ raise
+ self.bpf_debug_objs[addr] = debug_obj
+
+ def remove_bpf_ksym(self, ksym):
+ addr = int(ksym["start"])
+ debug_obj = self.bpf_debug_objs.pop(addr, None)
+ if debug_obj is None:
+ return
+ try:
+ name = bpf.get_ksym_name(ksym)
+ gdb.write("unloading @{addr}: {name}\n".format(
+ addr=hex(addr), name=name))
+ cmdline = "remove-symbol-file {path}".format(path=debug_obj.name)
+ gdb.execute(cmdline, to_string=True)
+ finally:
+ debug_obj.close()
+
+ def cleanup_bpf(self):
+ self.bpf_progs = {}
+ while len(self.bpf_debug_objs) > 0:
+ self.bpf_debug_objs.popitem()[1].close()
+
+
def load_all_symbols(self):
gdb.write("loading vmlinux\n")
@@ -224,34 +280,59 @@ lx-symbols command."""
else:
[self.load_module_symbols(module) for module in module_list]
+ self.cleanup_bpf()
+ if self.bpf_prog_monitor is not None:
+ self.bpf_prog_monitor.notify_initial()
+ if self.bpf_ksym_monitor is not None:
+ self.bpf_ksym_monitor.notify_initial()
+
for saved_state in saved_states:
saved_state['breakpoint'].enabled = saved_state['enabled']
def invoke(self, arg, from_tty):
skip_decompressor()
- self.module_paths = [os.path.abspath(os.path.expanduser(p))
- for p in arg.split()]
+ monitor_bpf = False
+ self.module_paths = []
+ for p in arg.split():
+ if p == "-bpf":
+ monitor_bpf = True
+ else:
+ p.append(os.path.abspath(os.path.expanduser(p)))
self.module_paths.append(os.getcwd())
+ if self.breakpoint is not None:
+ self.breakpoint.delete()
+ self.breakpoint = None
+ if self.bpf_prog_monitor is not None:
+ self.bpf_prog_monitor.delete()
+ self.bpf_prog_monitor = None
+ if self.bpf_ksym_monitor is not None:
+ self.bpf_ksym_monitor.delete()
+ self.bpf_ksym_monitor = None
+
# enforce update
self.module_files = []
self.module_files_updated = False
self.load_all_symbols()
- if not modules.has_modules():
+ if not hasattr(gdb, 'Breakpoint'):
+ gdb.write("Note: symbol update on module and BPF loading not "
+ "supported with this gdb version\n")
return
- if hasattr(gdb, 'Breakpoint'):
- if self.breakpoint is not None:
- self.breakpoint.delete()
- self.breakpoint = None
+ if modules.has_modules():
self.breakpoint = LoadModuleBreakpoint(
"kernel/module/main.c:do_init_module", self)
- else:
- gdb.write("Note: symbol update on module loading not supported "
- "with this gdb version\n")
+
+ if monitor_bpf:
+ if constants.LX_CONFIG_BPF_SYSCALL:
+ self.bpf_prog_monitor = bpf.ProgMonitor(self.add_bpf_prog,
+ self.remove_bpf_prog)
+ if constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT:
+ self.bpf_ksym_monitor = bpf.KsymMonitor(self.add_bpf_ksym,
+ self.remove_bpf_ksym)
LxSymbols()