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
860 "kunmap" => "kunmap_local",860 "kunmap" => "kunmap_local",
861 "kmap_atomic" => "kmap_local_page",861 "kmap_atomic" => "kmap_local_page",
862 "kunmap_atomic" => "kunmap_local",862 "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"
863);867);
864 868
865#Create a search pattern for all these strings to speed up a loop below869#Create a search pattern for all these strings to speed up a loop below
@@ -3345,6 +3349,13 @@ sub process { · 2479 unmodified lines
3345 }3349 }
3346 }3350 }
3347 3351
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
3348# Check for git id commit length and improperly formed commit descriptions3359# Check for git id commit length and improperly formed commit descriptions
3349# A correctly formed commit description is:3360# A correctly formed commit description is:
3350# commit <SHA-1 hash length 12+ chars> ("Complete commit subject")3361# 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
3import json
4import subprocess
5import tempfile
6
7import gdb
8
9from linux import constants, lists, radixtree, utils
10
11
12if constants.LX_CONFIG_BPF and constants.LX_CONFIG_BPF_JIT:
13 bpf_ksym_type = utils.CachedType("struct bpf_ksym")
14if constants.LX_CONFIG_BPF_SYSCALL:
15 bpf_prog_type = utils.CachedType("struct bpf_prog")
16
17
18def 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
26def 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
36class 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
47class 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
59class 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
78def 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
97class 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
109class 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
121class 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
140def 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
151def bpf_line_info_line_num(line_col):
152 return line_col >> 10
153
154
155def bpf_line_info_line_col(line_col):
156 return line_col & 0x3ff
157
158
159class 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
209def 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
170LX_CONFIG(CONFIG_SLUB_DEBUG)170LX_CONFIG(CONFIG_SLUB_DEBUG)
171LX_CONFIG(CONFIG_SLAB_FREELIST_HARDENED)171LX_CONFIG(CONFIG_SLAB_FREELIST_HARDENED)
172LX_CONFIG(CONFIG_MMU)172LX_CONFIG(CONFIG_MMU)
173LX_CONFIG(CONFIG_BPF)
174LX_CONFIG(CONFIG_BPF_JIT)
175LX_CONFIG(CONFIG_BPF_SYSCALL)
scripts/gdb/linux/radixtree.py+132−7
@@ -30,13 +30,16 @@ def entry_to_node(node): · 29 unmodified lines
30def node_maxindex(node):30def node_maxindex(node):
31 return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 131 return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1
32 32
33def lookup(root, index):33def resolve_root(root):
34 if root.type == radix_tree_root_type.get_type():
35 return root
34 if root.type == radix_tree_root_type.get_type().pointer():36 if root.type == radix_tree_root_type.get_type().pointer():
35 node = root.dereference()37 return root.dereference()
36 elif root.type != radix_tree_root_type.get_type():38 raise gdb.GdbError("must be {} not {}"
37 raise gdb.GdbError("must be {} not {}"39 .format(radix_tree_root_type.get_type(), root.type))
38 .format(radix_tree_root_type.get_type(), root.type))
39 40
41def lookup(root, index):
42 root = resolve_root(root)
40 node = root['xa_head']43 node = root['xa_head']
41 if node == 0:44 if node == 0:
42 return None45 return None
@@ -71,14 +74,120 @@ def lookup(root, index): · 28 unmodified lines
71 74
72 return node75 return node
73 76
74class LxRadixTree(gdb.Function):77def descend(parent, index):
78 offset = (index >> int(parent["shift"])) & constants.LX_RADIX_TREE_MAP_MASK
79 return offset, parent["slots"][offset]
80
81def 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
93class RadixTreeIter:
94 def __init__(self, start):
95 self.index = 0
96 self.next_index = start
97 self.node = None
98
99def xa_mk_internal(v):
100 return (v << 2) | 2
101
102LX_XA_RETRY_ENTRY = xa_mk_internal(256)
103LX_RADIX_TREE_RETRY = LX_XA_RETRY_ENTRY
104
105def 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
163def 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
172def 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
183class LxRadixTreeLookup(gdb.Function):
75 """ Lookup and return a node from a RadixTree.184 """ Lookup and return a node from a RadixTree.
76 185
77$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index.186$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index.
78If index is omitted, the root node is dereference and returned."""187If index is omitted, the root node is dereference and returned."""
79 188
80 def __init__(self):189 def __init__(self):
81 super(LxRadixTree, self).__init__("lx_radix_tree_lookup")190 super(LxRadixTreeLookup, self).__init__("lx_radix_tree_lookup")
82 191
83 def invoke(self, root, index=0):192 def invoke(self, root, index=0):
84 result = lookup(root, index)193 result = lookup(root, index)
@@ -87,4 +196,20 @@ If index is omitted, the root node is dereference and returned.""" · 2 unmodified lines
87 196
88 return result197 return result
89 198
199class 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
90LxRadixTree()214LxRadixTree()
215LxRadixTreeLookup()
scripts/gdb/linux/symbols.py+93−12
@@ -11,13 +11,14 @@ · 10 unmodified lines
11# This work is licensed under the terms of the GNU GPL version 2.11# This work is licensed under the terms of the GNU GPL version 2.
12#12#
13 13
14import atexit
14import gdb15import gdb
15import os16import os
16import re17import re
17import struct18import struct
18 19
19from itertools import count20from itertools import count
20from linux import modules, utils, constants21from linux import bpf, constants, modules, utils
21 22
22 23
23if hasattr(gdb, 'Breakpoint'):24if hasattr(gdb, 'Breakpoint'):
@@ -114,17 +115,27 @@ class LxSymbols(gdb.Command): · 90 unmodified lines
114The kernel (vmlinux) is taken from the current working directly. Modules (.ko)115The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
115are scanned recursively, starting in the same directory. Optionally, the module116are scanned recursively, starting in the same directory. Optionally, the module
116search path can be extended by a space separated list of paths passed to the117search path can be extended by a space separated list of paths passed to the
117lx-symbols command."""118lx-symbols command.
119
120When the -bpf flag is specified, symbols from the currently loaded BPF programs
121are loaded as well."""
118 122
119 module_paths = []123 module_paths = []
120 module_files = []124 module_files = []
121 module_files_updated = False125 module_files_updated = False
122 loaded_modules = []126 loaded_modules = []
123 breakpoint = None127 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 = {}
124 134
125 def __init__(self):135 def __init__(self):
126 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,136 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
127 gdb.COMPLETE_FILENAME)137 gdb.COMPLETE_FILENAME)
138 atexit.register(self.cleanup_bpf)
128 139
129 def _update_module_files(self):140 def _update_module_files(self):
130 self.module_files = []141 self.module_files = []
@@ -197,6 +208,51 @@ lx-symbols command.""" · 66 unmodified lines
197 else:208 else:
198 gdb.write("no module object found for '{0}'\n".format(module_name))209 gdb.write("no module object found for '{0}'\n".format(module_name))
199 210
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
200 def load_all_symbols(self):256 def load_all_symbols(self):
201 gdb.write("loading vmlinux\n")257 gdb.write("loading vmlinux\n")
202 258
@@ -224,34 +280,59 @@ lx-symbols command.""" · 21 unmodified lines
224 else:280 else:
225 [self.load_module_symbols(module) for module in module_list]281 [self.load_module_symbols(module) for module in module_list]
226 282
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
227 for saved_state in saved_states:289 for saved_state in saved_states:
228 saved_state['breakpoint'].enabled = saved_state['enabled']290 saved_state['breakpoint'].enabled = saved_state['enabled']
229 291
230 def invoke(self, arg, from_tty):292 def invoke(self, arg, from_tty):
231 skip_decompressor()293 skip_decompressor()
232 294
233 self.module_paths = [os.path.abspath(os.path.expanduser(p))295 monitor_bpf = False
234 for p in arg.split()]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)))
235 self.module_paths.append(os.getcwd())302 self.module_paths.append(os.getcwd())
236 303
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
237 # enforce update314 # enforce update
238 self.module_files = []315 self.module_files = []
239 self.module_files_updated = False316 self.module_files_updated = False
240 317
241 self.load_all_symbols()318 self.load_all_symbols()
242 319
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")
244 return323 return
245 324
246 if hasattr(gdb, 'Breakpoint'):325 if modules.has_modules():
247 if self.breakpoint is not None:
248 self.breakpoint.delete()
249 self.breakpoint = None
250 self.breakpoint = LoadModuleBreakpoint(326 self.breakpoint = LoadModuleBreakpoint(
251 "kernel/module/main.c:do_init_module", self)327 "kernel/module/main.c:do_init_module", self)
252 else:328
253 gdb.write("Note: symbol update on module loading not supported "329 if monitor_bpf:
254 "with this gdb version\n")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)
255 336
256 337
257LxSymbols()338LxSymbols()