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 itertools import count
20 from linux import modules, utils, constants
23 if hasattr(gdb, 'Breakpoint'):
24 class LoadModuleBreakpoint(gdb.Breakpoint):
25 def __init__(self, spec, gdb_command):
26 super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
28 self.gdb_command = gdb_command
31 module = gdb.parse_and_eval("mod")
32 module_name = module['name'].string()
33 cmd = self.gdb_command
35 # enforce update if object file is not found
36 cmd.module_files_updated = False
38 # Disable pagination while reporting symbol (re-)loading.
39 # The console input is blocked in this context so that we would
40 # get stuck waiting for the user to acknowledge paged output.
41 with utils.pagination_off():
42 if module_name in cmd.loaded_modules:
43 gdb.write("refreshing all symbols to reload module "
44 "'{0}'\n".format(module_name))
45 cmd.load_all_symbols()
47 cmd.load_module_symbols(module)
52 def get_vmcore_s390():
53 with utils.qemu_phy_mem_mode():
55 paddr_vmcoreinfo_note = gdb.parse_and_eval("*(unsigned long long *)" +
57 if paddr_vmcoreinfo_note == 0 or paddr_vmcoreinfo_note & 1:
58 # In the early boot case, extract vm_layout.kaslr_offset from the
59 # vmlinux image in physical memory.
60 if paddr_vmcoreinfo_note == 0:
63 kaslr_offset_phys = paddr_vmcoreinfo_note - 1
64 with utils.pagination_off():
65 gdb.execute("symbol-file {0} -o {1}".format(
66 utils.get_vmlinux(), hex(kaslr_offset_phys)))
67 kaslr_offset = gdb.parse_and_eval("vm_layout.kaslr_offset")
68 return "KERNELOFFSET=" + hex(kaslr_offset)[2:]
69 inferior = gdb.selected_inferior()
70 elf_note = inferior.read_memory(paddr_vmcoreinfo_note, 12)
71 n_namesz, n_descsz, n_type = struct.unpack(">III", elf_note)
72 desc_paddr = paddr_vmcoreinfo_note + len(elf_note) + n_namesz + 1
73 return gdb.parse_and_eval("(char *)" + hex(desc_paddr)).string()
76 def get_kerneloffset():
77 if utils.is_target_arch('s390'):
79 vmcore_str = get_vmcore_s390()
80 except gdb.error as e:
81 gdb.write("{}\n".format(e))
83 return utils.parse_vmcore(vmcore_str).kerneloffset
87 class LxSymbols(gdb.Command):
88 """(Re-)load symbols of Linux kernel and currently loaded modules.
90 The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
91 are scanned recursively, starting in the same directory. Optionally, the module
92 search path can be extended by a space separated list of paths passed to the
93 lx-symbols command."""
97 module_files_updated = False
102 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
103 gdb.COMPLETE_FILENAME)
105 def _update_module_files(self):
106 self.module_files = []
107 for path in self.module_paths:
108 gdb.write("scanning for modules in {0}\n".format(path))
109 for root, dirs, files in os.walk(path):
111 if name.endswith(".ko") or name.endswith(".ko.debug"):
112 self.module_files.append(root + "/" + name)
113 self.module_files_updated = True
115 def _get_module_file(self, module_name):
116 module_pattern = r".*/{0}\.ko(?:.debug)?$".format(
117 module_name.replace("_", r"[_\-]"))
118 for name in self.module_files:
119 if re.match(module_pattern, name) and os.path.exists(name):
123 def _section_arguments(self, module, module_addr):
125 sect_attrs = module['sect_attrs'].dereference()
127 return str(module_addr)
129 section_name_to_address = {}
131 # this is a NULL terminated array
132 if sect_attrs['grp']['bin_attrs'][i] == 0x0:
135 attr = sect_attrs['grp']['bin_attrs'][i].dereference()
136 section_name_to_address[attr['attr']['name'].string()] = attr['private']
138 textaddr = section_name_to_address.get(".text", module_addr)
140 for section_name in [".data", ".data..read_mostly", ".rodata", ".bss",
141 ".text.hot", ".text.unlikely"]:
142 address = section_name_to_address.get(section_name)
144 args.append(" -s {name} {addr}".format(
145 name=section_name, addr=str(address)))
146 return "{textaddr} {sections}".format(
147 textaddr=textaddr, sections="".join(args))
149 def load_module_symbols(self, module):
150 module_name = module['name'].string()
151 module_addr = str(module['mem'][constants.LX_MOD_TEXT]['base']).split()[0]
153 module_file = self._get_module_file(module_name)
154 if not module_file and not self.module_files_updated:
155 self._update_module_files()
156 module_file = self._get_module_file(module_name)
159 if utils.is_target_arch('s390'):
160 # Module text is preceded by PLT stubs on s390.
161 module_arch = module['arch']
162 plt_offset = int(module_arch['plt_offset'])
163 plt_size = int(module_arch['plt_size'])
164 module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
165 gdb.write("loading @{addr}: {filename}\n".format(
166 addr=module_addr, filename=module_file))
167 cmdline = "add-symbol-file {filename} {sections}".format(
168 filename=module_file,
169 sections=self._section_arguments(module, module_addr))
170 gdb.execute(cmdline, to_string=True)
171 if module_name not in self.loaded_modules:
172 self.loaded_modules.append(module_name)
174 gdb.write("no module object found for '{0}'\n".format(module_name))
176 def load_all_symbols(self):
177 gdb.write("loading vmlinux\n")
179 # Dropping symbols will disable all breakpoints. So save their states
180 # and restore them afterward.
182 if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
183 for bp in gdb.breakpoints():
184 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
186 # drop all current symbols and reload vmlinux
187 orig_vmlinux = utils.get_vmlinux()
188 gdb.execute("symbol-file", to_string=True)
189 kerneloffset = get_kerneloffset()
190 if kerneloffset is None:
193 offset_arg = " -o " + hex(kerneloffset)
194 gdb.execute("symbol-file {0}{1}".format(orig_vmlinux, offset_arg))
196 self.loaded_modules = []
197 module_list = modules.module_list()
199 gdb.write("no modules found\n")
201 [self.load_module_symbols(module) for module in module_list]
203 for saved_state in saved_states:
204 saved_state['breakpoint'].enabled = saved_state['enabled']
206 def invoke(self, arg, from_tty):
207 self.module_paths = [os.path.abspath(os.path.expanduser(p))
208 for p in arg.split()]
209 self.module_paths.append(os.getcwd())
212 self.module_files = []
213 self.module_files_updated = False
215 self.load_all_symbols()
217 if not modules.has_modules():
220 if hasattr(gdb, 'Breakpoint'):
221 if self.breakpoint is not None:
222 self.breakpoint.delete()
223 self.breakpoint = None
224 self.breakpoint = LoadModuleBreakpoint(
225 "kernel/module/main.c:do_init_module", self)
227 gdb.write("Note: symbol update on module loading not supported "
228 "with this gdb version\n")