2 # gdb helper commands and functions for Linux kernel debugging
4 # load kernel and module symbols
6 # Copyright (c) Siemens AG, 2011-2013
9 # Jan Kiszka <jan.kiszka@siemens.com>
11 # This work is licensed under the terms of the GNU GPL version 2.
18 from linux import modules
21 if hasattr(gdb, 'Breakpoint'):
22 class LoadModuleBreakpoint(gdb.Breakpoint):
23 def __init__(self, spec, gdb_command):
24 super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
26 self.gdb_command = gdb_command
29 module = gdb.parse_and_eval("mod")
30 module_name = module['name'].string()
31 cmd = self.gdb_command
33 # enforce update if object file is not found
34 cmd.module_files_updated = False
36 # Disable pagination while reporting symbol (re-)loading.
37 # The console input is blocked in this context so that we would
38 # get stuck waiting for the user to acknowledge paged output.
39 show_pagination = gdb.execute("show pagination", to_string=True)
40 pagination = show_pagination.endswith("on.\n")
41 gdb.execute("set pagination off")
43 if module_name in cmd.loaded_modules:
44 gdb.write("refreshing all symbols to reload module "
45 "'{0}'\n".format(module_name))
46 cmd.load_all_symbols()
48 cmd.load_module_symbols(module)
50 # restore pagination state
51 gdb.execute("set pagination %s" % ("on" if pagination else "off"))
56 class LxSymbols(gdb.Command):
57 """(Re-)load symbols of Linux kernel and currently loaded modules.
59 The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
60 are scanned recursively, starting in the same directory. Optionally, the module
61 search path can be extended by a space separated list of paths passed to the
62 lx-symbols command."""
66 module_files_updated = False
71 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
72 gdb.COMPLETE_FILENAME)
74 def _update_module_files(self):
75 self.module_files = []
76 for path in self.module_paths:
77 gdb.write("scanning for modules in {0}\n".format(path))
78 for root, dirs, files in os.walk(path):
80 if name.endswith(".ko"):
81 self.module_files.append(root + "/" + name)
82 self.module_files_updated = True
84 def _get_module_file(self, module_name):
85 module_pattern = ".*/{0}\.ko$".format(
86 module_name.replace("_", r"[_\-]"))
87 for name in self.module_files:
88 if re.match(module_pattern, name) and os.path.exists(name):
92 def _section_arguments(self, module):
94 sect_attrs = module['sect_attrs'].dereference()
97 attrs = sect_attrs['attrs']
98 section_name_to_address = {
99 attrs[n]['name'].string(): attrs[n]['address']
100 for n in range(int(sect_attrs['nsections']))}
102 for section_name in [".data", ".data..read_mostly", ".rodata", ".bss",
103 ".text", ".text.hot", ".text.unlikely"]:
104 address = section_name_to_address.get(section_name)
106 args.append(" -s {name} {addr}".format(
107 name=section_name, addr=str(address)))
110 def load_module_symbols(self, module):
111 module_name = module['name'].string()
112 module_addr = str(module['core_layout']['base']).split()[0]
114 module_file = self._get_module_file(module_name)
115 if not module_file and not self.module_files_updated:
116 self._update_module_files()
117 module_file = self._get_module_file(module_name)
120 gdb.write("loading @{addr}: {filename}\n".format(
121 addr=module_addr, filename=module_file))
122 cmdline = "add-symbol-file {filename} {addr}{sections}".format(
123 filename=module_file,
125 sections=self._section_arguments(module))
126 gdb.execute(cmdline, to_string=True)
127 if module_name not in self.loaded_modules:
128 self.loaded_modules.append(module_name)
130 gdb.write("no module object found for '{0}'\n".format(module_name))
132 def load_all_symbols(self):
133 gdb.write("loading vmlinux\n")
135 # Dropping symbols will disable all breakpoints. So save their states
136 # and restore them afterward.
138 if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
139 for bp in gdb.breakpoints():
140 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
142 # drop all current symbols and reload vmlinux
143 gdb.execute("symbol-file", to_string=True)
144 gdb.execute("symbol-file vmlinux")
146 self.loaded_modules = []
147 module_list = modules.module_list()
149 gdb.write("no modules found\n")
151 [self.load_module_symbols(module) for module in module_list]
153 for saved_state in saved_states:
154 saved_state['breakpoint'].enabled = saved_state['enabled']
156 def invoke(self, arg, from_tty):
157 self.module_paths = [os.path.expanduser(p) for p in arg.split()]
158 self.module_paths.append(os.getcwd())
161 self.module_files = []
162 self.module_files_updated = False
164 self.load_all_symbols()
166 if hasattr(gdb, 'Breakpoint'):
167 if self.breakpoint is not None:
168 self.breakpoint.delete()
169 self.breakpoint = None
170 self.breakpoint = LoadModuleBreakpoint(
171 "kernel/module.c:do_init_module", self)
173 gdb.write("Note: symbol update on module loading not supported "
174 "with this gdb version\n")