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.
19 from linux import modules, utils
22 if hasattr(gdb, 'Breakpoint'):
23 class LoadModuleBreakpoint(gdb.Breakpoint):
24 def __init__(self, spec, gdb_command):
25 super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
27 self.gdb_command = gdb_command
30 module = gdb.parse_and_eval("mod")
31 module_name = module['name'].string()
32 cmd = self.gdb_command
34 # enforce update if object file is not found
35 cmd.module_files_updated = False
37 if module_name in cmd.loaded_modules:
38 gdb.write("refreshing all symbols to reload module "
39 "'{0}'\n".format(module_name))
40 cmd.load_all_symbols()
42 cmd.load_module_symbols(module)
46 class LxSymbols(gdb.Command):
47 """(Re-)load symbols of Linux kernel and currently loaded modules.
49 The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
50 are scanned recursively, starting in the same directory. Optionally, the module
51 search path can be extended by a space separated list of paths passed to the
52 lx-symbols command."""
56 module_files_updated = False
61 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
62 gdb.COMPLETE_FILENAME)
64 def _update_module_files(self):
65 self.module_files = []
66 for path in self.module_paths:
67 gdb.write("scanning for modules in {0}\n".format(path))
68 for root, dirs, files in os.walk(path):
70 if name.endswith(".ko"):
71 self.module_files.append(root + "/" + name)
72 self.module_files_updated = True
74 def _get_module_file(self, module_name):
75 module_pattern = ".*/{0}\.ko$".format(
76 string.replace(module_name, "_", r"[_\-]"))
77 for name in self.module_files:
78 if re.match(module_pattern, name) and os.path.exists(name):
82 def _section_arguments(self, module):
84 sect_attrs = module['sect_attrs'].dereference()
87 attrs = sect_attrs['attrs']
88 section_name_to_address = {
89 attrs[n]['name'].string() : attrs[n]['address']
90 for n in range(sect_attrs['nsections'])}
92 for section_name in [".data", ".data..read_mostly", ".rodata", ".bss"]:
93 address = section_name_to_address.get(section_name)
95 args.append(" -s {name} {addr}".format(
96 name=section_name, addr=str(address)))
99 def load_module_symbols(self, module):
100 module_name = module['name'].string()
101 module_addr = str(module['module_core']).split()[0]
103 module_file = self._get_module_file(module_name)
104 if not module_file and not self.module_files_updated:
105 self._update_module_files()
106 module_file = self._get_module_file(module_name)
109 gdb.write("loading @{addr}: {filename}\n".format(
110 addr=module_addr, filename=module_file))
111 cmdline = "add-symbol-file {filename} {addr}{sections}".format(
112 filename=module_file,
114 sections=self._section_arguments(module))
115 gdb.execute(cmdline, to_string=True)
116 if not module_name in self.loaded_modules:
117 self.loaded_modules.append(module_name)
119 gdb.write("no module object found for '{0}'\n".format(module_name))
121 def load_all_symbols(self):
122 gdb.write("loading vmlinux\n")
124 # Dropping symbols will disable all breakpoints. So save their states
125 # and restore them afterward.
127 if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
128 for bp in gdb.breakpoints():
129 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
131 # drop all current symbols and reload vmlinux
132 gdb.execute("symbol-file", to_string=True)
133 gdb.execute("symbol-file vmlinux")
135 self.loaded_modules = []
136 module_list = modules.ModuleList()
138 gdb.write("no modules found\n")
140 [self.load_module_symbols(module) for module in module_list]
142 for saved_state in saved_states:
143 saved_state['breakpoint'].enabled = saved_state['enabled']
145 def invoke(self, arg, from_tty):
146 self.module_paths = arg.split()
147 self.module_paths.append(os.getcwd())
150 self.module_files = []
151 self.module_files_updated = False
153 self.load_all_symbols()
155 if hasattr(gdb, 'Breakpoint'):
156 if not self.breakpoint is None:
157 self.breakpoint.delete()
158 self.breakpoint = None
159 self.breakpoint = LoadModuleBreakpoint(
160 "kernel/module.c:do_init_module", self)
162 gdb.write("Note: symbol update on module loading not supported "
163 "with this gdb version\n")