History

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 ...

Linus Torvalds committed 11 months ago

Commit 509d3f42 parents 09670b8 aa514a2439 files · +8031 −1801Browse files

Showing the changes to scripts (5 of 439 files). Show all

Unified · Split

5 files
  1. scripts/checkpatch.pl +11 −0
  2. scripts/gdb/linux/bpf.py +253 −0
  3. scripts/gdb/linux/constants.py.in +3 −0
  4. scripts/gdb/linux/radixtree.py +132 −7
  5. scripts/gdb/linux/symbols.py +93 −12
scripts/checkpatch.pl+11−0
@@ -860,6 +860,10 @@ our %deprecated_apis = ( · 859 unmodified lines
860860 "kunmap" => "kunmap_local",
861861 "kmap_atomic" => "kmap_local_page",
862862 "kunmap_atomic" => "kunmap_local",
863+ #These should be enough to drive away new IDR users
864+ "DEFINE_IDR" => "DEFINE_XARRAY",
865+ "idr_init" => "xa_init",
866+ "idr_init_base" => "xa_init_flags"
863867 );
864868
865869 #Create a search pattern for all these strings to speed up a loop below
@@ -3345,6 +3349,13 @@ sub process { · 2479 unmodified lines
33453349 }
33463350 }
33473351
3352+# Check for auto-generated unhandled placeholder text (mostly for cover letters)
3353+ if (($in_commit_log || $in_header_lines) &&
3354+ $rawline =~ /(?:SUBJECT|BLURB) HERE/) {
3355+ ERROR("PLACEHOLDER_USE",
3356+ "Placeholder text detected\n" . $herecurr);
3357+ }
3358+
33483359 # Check for git id commit length and improperly formed commit descriptions
33493360 # A correctly formed commit description is:
33503361 # commit <SHA-1 hash length 12+ chars> ("Complete commit subject")
scripts/gdb/linux/bpf.py+253−0
@@ -0,0 +1,253 @@
1+# SPDX-License-Identifier: GPL-2.0
2+
3+import json
4+import subprocess
5+import tempfile
6+
7+import gdb
8+
9+from linux import constants, lists, radixtree, utils
10+
11+
12+if constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT:
13+ bpf_ksym_type = utils.CachedType("struct bpf_ksym")
14+if constants.LX_CONFIG_BPF_SYSCALL:
15+ bpf_prog_type = utils.CachedType("struct bpf_prog")
16+
17+
18+def get_ksym_name(ksym):
19+ name = ksym["name"].bytes
20+ end = name.find(b"\x00")
21+ if end != -1:
22+ name = name[:end]
23+ return name.decode()
24+
25+
26+def list_ksyms():
27+ if not (constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT):
28+ return []
29+ bpf_kallsyms = gdb.parse_and_eval("&bpf_kallsyms")
30+ bpf_ksym_ptr_type = bpf_ksym_type.get_type().pointer()
31+ return list(lists.list_for_each_entry(bpf_kallsyms,
32+ bpf_ksym_ptr_type,
33+ "lnode"))
34+
35+
36+class KsymAddBreakpoint(gdb.Breakpoint):
37+ def __init__(self, monitor):
38+ super(KsymAddBreakpoint, self).__init__("bpf_ksym_add", internal=True)
39+ self.silent = True
40+ self.monitor = monitor
41+
42+ def stop(self):
43+ self.monitor.add(gdb.parse_and_eval("ksym"))
44+ return False
45+
46+
47+class KsymRemoveBreakpoint(gdb.Breakpoint):
48+ def __init__(self, monitor):
49+ super(KsymRemoveBreakpoint, self).__init__("bpf_ksym_del",
50+ internal=True)
51+ self.silent = True
52+ self.monitor = monitor
53+
54+ def stop(self):
55+ self.monitor.remove(gdb.parse_and_eval("ksym"))
56+ return False
57+
58+
59+class KsymMonitor:
60+ def __init__(self, add, remove):
61+ self.add = add
62+ self.remove = remove
63+
64+ self.add_bp = KsymAddBreakpoint(self)
65+ self.remove_bp = KsymRemoveBreakpoint(self)
66+
67+ self.notify_initial()
68+
69+ def notify_initial(self):
70+ for ksym in list_ksyms():
71+ self.add(ksym)
72+
73+ def delete(self):
74+ self.add_bp.delete()
75+ self.remove_bp.delete()
76+
77+
78+def list_progs():
79+ if not constants.LX_CONFIG_BPF_SYSCALL:
80+ return []
81+ idr_rt = gdb.parse_and_eval("&prog_idr.idr_rt")
82+ bpf_prog_ptr_type = bpf_prog_type.get_type().pointer()
83+ progs = []
84+ for _, slot in radixtree.for_each_slot(idr_rt):
85+ prog = slot.dereference().cast(bpf_prog_ptr_type)
86+ progs.append(prog)
87+ # Subprogs are not registered in prog_idr, fetch them manually.
88+ # func[0] is the current prog.
89+ aux = prog["aux"]
90+ func = aux["func"]
91+ real_func_cnt = int(aux["real_func_cnt"])
92+ for i in range(1, real_func_cnt):
93+ progs.append(func[i])
94+ return progs
95+
96+
97+class ProgAddBreakpoint(gdb.Breakpoint):
98+ def __init__(self, monitor):
99+ super(ProgAddBreakpoint, self).__init__("bpf_prog_kallsyms_add",
100+ internal=True)
101+ self.silent = True
102+ self.monitor = monitor
103+
104+ def stop(self):
105+ self.monitor.add(gdb.parse_and_eval("fp"))
106+ return False
107+
108+
109+class ProgRemoveBreakpoint(gdb.Breakpoint):
110+ def __init__(self, monitor):
111+ super(ProgRemoveBreakpoint, self).__init__("bpf_prog_free_id",
112+ internal=True)
113+ self.silent = True
114+ self.monitor = monitor
115+
116+ def stop(self):
117+ self.monitor.remove(gdb.parse_and_eval("prog"))
118+ return False
119+
120+
121+class ProgMonitor:
122+ def __init__(self, add, remove):
123+ self.add = add
124+ self.remove = remove
125+
126+ self.add_bp = ProgAddBreakpoint(self)
127+ self.remove_bp = ProgRemoveBreakpoint(self)
128+
129+ self.notify_initial()
130+
131+ def notify_initial(self):
132+ for prog in list_progs():
133+ self.add(prog)
134+
135+ def delete(self):
136+ self.add_bp.delete()
137+ self.remove_bp.delete()
138+
139+
140+def btf_str_by_offset(btf, offset):
141+ while offset < btf["start_str_off"]:
142+ btf = btf["base_btf"]
143+
144+ offset -= btf["start_str_off"]
145+ if offset < btf["hdr"]["str_len"]:
146+ return (btf["strings"] + offset).string()
147+
148+ return None
149+
150+
151+def bpf_line_info_line_num(line_col):
152+ return line_col >> 10
153+
154+
155+def bpf_line_info_line_col(line_col):
156+ return line_col & 0x3ff
157+
158+
159+class LInfoIter:
160+ def __init__(self, prog):
161+ # See bpf_prog_get_file_line() for details.
162+ self.pos = 0
163+ self.nr_linfo = 0
164+
165+ if prog is None:
166+ return
167+
168+ self.bpf_func = int(prog["bpf_func"])
169+ aux = prog["aux"]
170+ self.btf = aux["btf"]
171+ linfo_idx = aux["linfo_idx"]
172+ self.nr_linfo = int(aux["nr_linfo"]) - linfo_idx
173+ if self.nr_linfo == 0:
174+ return
175+
176+ linfo_ptr = aux["linfo"]
177+ tpe = linfo_ptr.type.target().array(self.nr_linfo).pointer()
178+ self.linfo = (linfo_ptr + linfo_idx).cast(tpe).dereference()
179+ jited_linfo_ptr = aux["jited_linfo"]
180+ tpe = jited_linfo_ptr.type.target().array(self.nr_linfo).pointer()
181+ self.jited_linfo = (jited_linfo_ptr + linfo_idx).cast(tpe).dereference()
182+
183+ self.filenos = {}
184+
185+ def get_code_off(self):
186+ if self.pos >= self.nr_linfo:
187+ return -1
188+ return self.jited_linfo[self.pos] - self.bpf_func
189+
190+ def advance(self):
191+ self.pos += 1
192+
193+ def get_fileno(self):
194+ file_name_off = int(self.linfo[self.pos]["file_name_off"])
195+ fileno = self.filenos.get(file_name_off)
196+ if fileno is not None:
197+ return fileno, None
198+ file_name = btf_str_by_offset(self.btf, file_name_off)
199+ fileno = len(self.filenos) + 1
200+ self.filenos[file_name_off] = fileno
201+ return fileno, file_name
202+
203+ def get_line_col(self):
204+ line_col = int(self.linfo[self.pos]["line_col"])
205+ return bpf_line_info_line_num(line_col), \
206+ bpf_line_info_line_col(line_col)
207+
208+
209+def generate_debug_obj(ksym, prog):
210+ name = get_ksym_name(ksym)
211+ # Avoid read_memory(); it throws bogus gdb.MemoryError in some contexts.
212+ start = ksym["start"]
213+ code = start.cast(gdb.lookup_type("unsigned char")
214+ .array(int(ksym["end"]) - int(start))
215+ .pointer()).dereference().bytes
216+ linfo_iter = LInfoIter(prog)
217+
218+ result = tempfile.NamedTemporaryFile(suffix=".o", mode="wb")
219+ try:
220+ with tempfile.NamedTemporaryFile(suffix=".s", mode="w") as src:
221+ # ".loc" does not apply to ".byte"s, only to ".insn"s, but since
222+ # this needs to work for all architectures, the latter are not an
223+ # option. Ask the assembler to apply ".loc"s to labels as well,
224+ # and generate dummy labels after each ".loc".
225+ src.write(".loc_mark_labels 1\n")
226+
227+ src.write(".globl {}\n".format(name))
228+ src.write(".type {},@function\n".format(name))
229+ src.write("{}:\n".format(name))
230+ for code_off, code_byte in enumerate(code):
231+ if linfo_iter.get_code_off() == code_off:
232+ fileno, file_name = linfo_iter.get_fileno()
233+ if file_name is not None:
234+ src.write(".file {} {}\n".format(
235+ fileno, json.dumps(file_name)))
236+ line, col = linfo_iter.get_line_col()
237+ src.write(".loc {} {} {}\n".format(fileno, line, col))
238+ src.write("0:\n")
239+ linfo_iter.advance()
240+ src.write(".byte {}\n".format(code_byte))
241+ src.write(".size {},{}\n".format(name, len(code)))
242+ src.flush()
243+
244+ try:
245+ subprocess.check_call(["as", "-c", src.name, "-o", result.name])
246+ except FileNotFoundError:
247+ # "as" is not installed.
248+ result.close()
249+ return None
250+ return result
251+ except:
252+ result.close()
253+ raise
scripts/gdb/linux/constants.py.in+3−0
@@ -170,3 +170,6 @@ LX_CONFIG(CONFIG_PAGE_OWNER) · 169 unmodified lines
170170 LX_CONFIG(CONFIG_SLUB_DEBUG)
171171 LX_CONFIG(CONFIG_SLAB_FREELIST_HARDENED)
172172 LX_CONFIG(CONFIG_MMU)
173+LX_CONFIG(CONFIG_BPF)
174+LX_CONFIG(CONFIG_BPF_JIT)
175+LX_CONFIG(CONFIG_BPF_SYSCALL)
scripts/gdb/linux/radixtree.py+132−7
@@ -30,13 +30,16 @@ def entry_to_node(node): · 29 unmodified lines
3030 def node_maxindex(node):
3131 return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1
3232
33−def lookup(root, index):
33+def resolve_root(root):
34+ if root.type == radix_tree_root_type.get_type():
35+ return root
3436 if root.type == radix_tree_root_type.get_type().pointer():
35− node = root.dereference()
36− elif root.type != radix_tree_root_type.get_type():
37− raise gdb.GdbError("must be {} not {}"
38− .format(radix_tree_root_type.get_type(), root.type))
37+ return root.dereference()
38+ raise gdb.GdbError("must be {} not {}"
39+ .format(radix_tree_root_type.get_type(), root.type))
3940
41+def lookup(root, index):
42+ root = resolve_root(root)
4043 node = root['xa_head']
4144 if node == 0:
4245 return None
@@ -71,14 +74,120 @@ def lookup(root, index): · 28 unmodified lines
7174
7275 return node
7376
74−class LxRadixTree(gdb.Function):
77+def descend(parent, index):
78+ offset = (index >> int(parent["shift"])) & constants.LX_RADIX_TREE_MAP_MASK
79+ return offset, parent["slots"][offset]
80+
81+def load_root(root):
82+ node = root["xa_head"]
83+ nodep = node
84+
85+ if is_internal_node(node):
86+ node = entry_to_node(node)
87+ maxindex = node_maxindex(node)
88+ return int(node["shift"]) + constants.LX_RADIX_TREE_MAP_SHIFT, \
89+ nodep, maxindex
90+
91+ return 0, nodep, 0
92+
93+class RadixTreeIter:
94+ def __init__(self, start):
95+ self.index = 0
96+ self.next_index = start
97+ self.node = None
98+
99+def xa_mk_internal(v):
100+ return (v << 2) | 2
101+
102+LX_XA_RETRY_ENTRY = xa_mk_internal(256)
103+LX_RADIX_TREE_RETRY = LX_XA_RETRY_ENTRY
104+
105+def next_chunk(root, iter):
106+ mask = (1 << (utils.get_ulong_type().sizeof * 8)) - 1
107+
108+ index = iter.next_index
109+ if index == 0 and iter.index != 0:
110+ return None
111+
112+ restart = True
113+ while restart:
114+ restart = False
115+
116+ _, child, maxindex = load_root(root)
117+ if index > maxindex:
118+ return None
119+ if not child:
120+ return None
121+
122+ if not is_internal_node(child):
123+ iter.index = index
124+ iter.next_index = (maxindex + 1) & mask
125+ iter.node = None
126+ return root["xa_head"].address
127+
128+ while True:
129+ node = entry_to_node(child)
130+ offset, child = descend(node, index)
131+
132+ if not child:
133+ while True:
134+ offset += 1
135+ if offset >= constants.LX_RADIX_TREE_MAP_SIZE:
136+ break
137+ slot = node["slots"][offset]
138+ if slot:
139+ break
140+ index &= ~node_maxindex(node)
141+ index = (index + (offset << int(node["shift"]))) & mask
142+ if index == 0:
143+ return None
144+ if offset == constants.LX_RADIX_TREE_MAP_SIZE:
145+ restart = True
146+ break
147+ child = node["slots"][offset]
148+
149+ if not child:
150+ restart = True
151+ break
152+ if child == LX_XA_RETRY_ENTRY:
153+ break
154+ if not node["shift"] or not is_internal_node(child):
155+ break
156+
157+ iter.index = (index & ~node_maxindex(node)) | offset
158+ iter.next_index = ((index | node_maxindex(node)) + 1) & mask
159+ iter.node = node
160+
161+ return node["slots"][offset].address
162+
163+def next_slot(slot, iter):
164+ mask = (1 << (utils.get_ulong_type().sizeof * 8)) - 1
165+ for _ in range(iter.next_index - iter.index - 1):
166+ slot += 1
167+ iter.index = (iter.index + 1) & mask
168+ if slot.dereference():
169+ return slot
170+ return None
171+
172+def for_each_slot(root, start=0):
173+ iter = RadixTreeIter(start)
174+ slot = None
175+ while True:
176+ if not slot:
177+ slot = next_chunk(root, iter)
178+ if not slot:
179+ break
180+ yield iter.index, slot
181+ slot = next_slot(slot, iter)
182+
183+class LxRadixTreeLookup(gdb.Function):
75184 """ Lookup and return a node from a RadixTree.
76185
77186 $lx_radix_tree_lookup(root_node [, index]): Return the node at the given index.
78187 If index is omitted, the root node is dereference and returned."""
79188
80189 def __init__(self):
81− super(LxRadixTree, self).__init__("lx_radix_tree_lookup")
190+ super(LxRadixTreeLookup, self).__init__("lx_radix_tree_lookup")
82191
83192 def invoke(self, root, index=0):
84193 result = lookup(root, index)
@@ -87,4 +196,20 @@ If index is omitted, the root node is dereference and returned.""" · 2 unmodified lines
87196
88197 return result
89198
199+class LxRadixTree(gdb.Command):
200+ """Show all values stored in a RadixTree."""
201+
202+ def __init__(self):
203+ super(LxRadixTree, self).__init__("lx-radix-tree", gdb.COMMAND_DATA,
204+ gdb.COMPLETE_NONE)
205+
206+ def invoke(self, argument, from_tty):
207+ args = gdb.string_to_argv(argument)
208+ if len(args) != 1:
209+ raise gdb.GdbError("Usage: lx-radix-tree ROOT")
210+ root = gdb.parse_and_eval(args[0])
211+ for index, slot in for_each_slot(root):
212+ gdb.write("[{}] = {}\n".format(index, slot.dereference()))
213+
90214 LxRadixTree()
215+LxRadixTreeLookup()
scripts/gdb/linux/symbols.py+93−12
@@ -11,13 +11,14 @@ · 10 unmodified lines
1111 # This work is licensed under the terms of the GNU GPL version 2.
1212 #
1313
14+import atexit
1415 import gdb
1516 import os
1617 import re
1718 import struct
1819
1920 from itertools import count
20−from linux import modules, utils, constants
21+from linux import bpf, constants, modules, utils
2122
2223
2324 if hasattr(gdb, 'Breakpoint'):
@@ -114,17 +115,27 @@ class LxSymbols(gdb.Command): · 90 unmodified lines
114115 The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
115116 are scanned recursively, starting in the same directory. Optionally, the module
116117 search path can be extended by a space separated list of paths passed to the
117−lx-symbols command."""
118+lx-symbols command.
119+
120+When the -bpf flag is specified, symbols from the currently loaded BPF programs
121+are loaded as well."""
118122
119123 module_paths = []
120124 module_files = []
121125 module_files_updated = False
122126 loaded_modules = []
123127 breakpoint = None
128+ bpf_prog_monitor = None
129+ bpf_ksym_monitor = None
130+ bpf_progs = {}
131+ # The remove-symbol-file command, even when invoked with -a, requires the
132+ # respective object file to exist, so keep them around.
133+ bpf_debug_objs = {}
124134
125135 def __init__(self):
126136 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
127137 gdb.COMPLETE_FILENAME)
138+ atexit.register(self.cleanup_bpf)
128139
129140 def _update_module_files(self):
130141 self.module_files = []
@@ -197,6 +208,51 @@ lx-symbols command.""" · 66 unmodified lines
197208 else:
198209 gdb.write("no module object found for '{0}'\n".format(module_name))
199210
211+ def add_bpf_prog(self, prog):
212+ if prog["jited"]:
213+ self.bpf_progs[int(prog["bpf_func"])] = prog
214+
215+ def remove_bpf_prog(self, prog):
216+ self.bpf_progs.pop(int(prog["bpf_func"]), None)
217+
218+ def add_bpf_ksym(self, ksym):
219+ addr = int(ksym["start"])
220+ name = bpf.get_ksym_name(ksym)
221+ with utils.pagination_off():
222+ gdb.write("loading @{addr}: {name}\n".format(
223+ addr=hex(addr), name=name))
224+ debug_obj = bpf.generate_debug_obj(ksym, self.bpf_progs.get(addr))
225+ if debug_obj is None:
226+ return
227+ try:
228+ cmdline = "add-symbol-file {obj} {addr}".format(
229+ obj=debug_obj.name, addr=hex(addr))
230+ gdb.execute(cmdline, to_string=True)
231+ except:
232+ debug_obj.close()
233+ raise
234+ self.bpf_debug_objs[addr] = debug_obj
235+
236+ def remove_bpf_ksym(self, ksym):
237+ addr = int(ksym["start"])
238+ debug_obj = self.bpf_debug_objs.pop(addr, None)
239+ if debug_obj is None:
240+ return
241+ try:
242+ name = bpf.get_ksym_name(ksym)
243+ gdb.write("unloading @{addr}: {name}\n".format(
244+ addr=hex(addr), name=name))
245+ cmdline = "remove-symbol-file {path}".format(path=debug_obj.name)
246+ gdb.execute(cmdline, to_string=True)
247+ finally:
248+ debug_obj.close()
249+
250+ def cleanup_bpf(self):
251+ self.bpf_progs = {}
252+ while len(self.bpf_debug_objs) > 0:
253+ self.bpf_debug_objs.popitem()[1].close()
254+
255+
200256 def load_all_symbols(self):
201257 gdb.write("loading vmlinux\n")
202258
@@ -224,34 +280,59 @@ lx-symbols command.""" · 21 unmodified lines
224280 else:
225281 [self.load_module_symbols(module) for module in module_list]
226282
283+ self.cleanup_bpf()
284+ if self.bpf_prog_monitor is not None:
285+ self.bpf_prog_monitor.notify_initial()
286+ if self.bpf_ksym_monitor is not None:
287+ self.bpf_ksym_monitor.notify_initial()
288+
227289 for saved_state in saved_states:
228290 saved_state['breakpoint'].enabled = saved_state['enabled']
229291
230292 def invoke(self, arg, from_tty):
231293 skip_decompressor()
232294
233− self.module_paths = [os.path.abspath(os.path.expanduser(p))
234− for p in arg.split()]
295+ monitor_bpf = False
296+ self.module_paths = []
297+ for p in arg.split():
298+ if p == "-bpf":
299+ monitor_bpf = True
300+ else:
301+ p.append(os.path.abspath(os.path.expanduser(p)))
235302 self.module_paths.append(os.getcwd())
236303
304+ if self.breakpoint is not None:
305+ self.breakpoint.delete()
306+ self.breakpoint = None
307+ if self.bpf_prog_monitor is not None:
308+ self.bpf_prog_monitor.delete()
309+ self.bpf_prog_monitor = None
310+ if self.bpf_ksym_monitor is not None:
311+ self.bpf_ksym_monitor.delete()
312+ self.bpf_ksym_monitor = None
313+
237314 # enforce update
238315 self.module_files = []
239316 self.module_files_updated = False
240317
241318 self.load_all_symbols()
242319
243− if not modules.has_modules():
320+ if not hasattr(gdb, 'Breakpoint'):
321+ gdb.write("Note: symbol update on module and BPF loading not "
322+ "supported with this gdb version\n")
244323 return
245324
246− if hasattr(gdb, 'Breakpoint'):
247− if self.breakpoint is not None:
248− self.breakpoint.delete()
249− self.breakpoint = None
325+ if modules.has_modules():
250326 self.breakpoint = LoadModuleBreakpoint(
251327 "kernel/module/main.c:do_init_module", self)
252− else:
253− gdb.write("Note: symbol update on module loading not supported "
254− "with this gdb version\n")
328+
329+ if monitor_bpf:
330+ if constants.LX_CONFIG_BPF_SYSCALL:
331+ self.bpf_prog_monitor = bpf.ProgMonitor(self.add_bpf_prog,
332+ self.remove_bpf_prog)
333+ if constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT:
334+ self.bpf_ksym_monitor = bpf.KsymMonitor(self.add_bpf_ksym,
335+ self.remove_bpf_ksym)
255336
256337
257338 LxSymbols()