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, utils, constants
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") or name.endswith(".ko.debug"):
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(?:.debug)?$".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, module_addr):
94 sect_attrs = module['sect_attrs'].dereference()
96 return str(module_addr)
98 attrs = sect_attrs['attrs']
99 section_name_to_address = {
100 attrs[n]['battr']['attr']['name'].string(): attrs[n]['address']
101 for n in range(int(sect_attrs['nsections']))}
103 textaddr = section_name_to_address.get(".text", module_addr)
105 for section_name in [".data", ".data..read_mostly", ".rodata", ".bss",
106 ".text.hot", ".text.unlikely"]:
107 address = section_name_to_address.get(section_name)
109 args.append(" -s {name} {addr}".format(
110 name=section_name, addr=str(address)))
111 return "{textaddr} {sections}".format(
112 textaddr=textaddr, sections="".join(args))
114 def load_module_symbols(self, module):
115 module_name = module['name'].string()
116 module_addr = str(module['mem'][constants.LX_MOD_TEXT]['base']).split()[0]
118 module_file = self._get_module_file(module_name)
119 if not module_file and not self.module_files_updated:
120 self._update_module_files()
121 module_file = self._get_module_file(module_name)
124 if utils.is_target_arch('s390'):
125 # Module text is preceded by PLT stubs on s390.
126 module_arch = module['arch']
127 plt_offset = int(module_arch['plt_offset'])
128 plt_size = int(module_arch['plt_size'])
129 module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
130 gdb.write("loading @{addr}: {filename}\n".format(
131 addr=module_addr, filename=module_file))
132 cmdline = "add-symbol-file {filename} {sections}".format(
133 filename=module_file,
134 sections=self._section_arguments(module, module_addr))
135 gdb.execute(cmdline, to_string=True)
136 if module_name not in self.loaded_modules:
137 self.loaded_modules.append(module_name)
139 gdb.write("no module object found for '{0}'\n".format(module_name))
141 def load_all_symbols(self):
142 gdb.write("loading vmlinux\n")
144 # Dropping symbols will disable all breakpoints. So save their states
145 # and restore them afterward.
147 if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
148 for bp in gdb.breakpoints():
149 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
151 # drop all current symbols and reload vmlinux
152 orig_vmlinux = 'vmlinux'
153 for obj in gdb.objfiles():
154 if (obj.filename.endswith('vmlinux') or
155 obj.filename.endswith('vmlinux.debug')):
156 orig_vmlinux = obj.filename
157 gdb.execute("symbol-file", to_string=True)
158 gdb.execute("symbol-file {0}".format(orig_vmlinux))
160 self.loaded_modules = []
161 module_list = modules.module_list()
163 gdb.write("no modules found\n")
165 [self.load_module_symbols(module) for module in module_list]
167 for saved_state in saved_states:
168 saved_state['breakpoint'].enabled = saved_state['enabled']
170 def invoke(self, arg, from_tty):
171 self.module_paths = [os.path.abspath(os.path.expanduser(p))
172 for p in arg.split()]
173 self.module_paths.append(os.getcwd())
176 self.module_files = []
177 self.module_files_updated = False
179 self.load_all_symbols()
181 if hasattr(gdb, 'Breakpoint'):
182 if self.breakpoint is not None:
183 self.breakpoint.delete()
184 self.breakpoint = None
185 self.breakpoint = LoadModuleBreakpoint(
186 "kernel/module/main.c:do_init_module", self)
188 gdb.write("Note: symbol update on module loading not supported "
189 "with this gdb version\n")