blob: 004b0ac7fa72d25598d26fbab4b2035e3e882305 [file] [log] [blame]
Jan Kiszka66051722015-02-17 13:46:47 -08001#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# load kernel and module symbols
5#
6# Copyright (c) Siemens AG, 2011-2013
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import gdb
15import os
16import re
Jan Kiszka66051722015-02-17 13:46:47 -080017
Thiébaud Weksteen6ad18b72015-06-30 14:58:18 -070018from linux import modules
Jan Kiszka66051722015-02-17 13:46:47 -080019
20
Jan Kiszka82b41e32015-02-17 13:46:52 -080021if hasattr(gdb, 'Breakpoint'):
22 class LoadModuleBreakpoint(gdb.Breakpoint):
23 def __init__(self, spec, gdb_command):
24 super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
25 self.silent = True
26 self.gdb_command = gdb_command
27
28 def stop(self):
29 module = gdb.parse_and_eval("mod")
30 module_name = module['name'].string()
31 cmd = self.gdb_command
32
33 # enforce update if object file is not found
34 cmd.module_files_updated = False
35
Jan Kiszkaa9c5bcf2015-02-17 13:47:52 -080036 # 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")
42
Jan Kiszka82b41e32015-02-17 13:46:52 -080043 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()
47 else:
48 cmd.load_module_symbols(module)
Jan Kiszkaa9c5bcf2015-02-17 13:47:52 -080049
50 # restore pagination state
51 gdb.execute("set pagination %s" % ("on" if pagination else "off"))
52
Jan Kiszka82b41e32015-02-17 13:46:52 -080053 return False
54
55
Jan Kiszka66051722015-02-17 13:46:47 -080056class LxSymbols(gdb.Command):
57 """(Re-)load symbols of Linux kernel and currently loaded modules.
58
59The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
60are scanned recursively, starting in the same directory. Optionally, the module
61search path can be extended by a space separated list of paths passed to the
62lx-symbols command."""
63
64 module_paths = []
65 module_files = []
66 module_files_updated = False
Jan Kiszka82b41e32015-02-17 13:46:52 -080067 loaded_modules = []
68 breakpoint = None
Jan Kiszka66051722015-02-17 13:46:47 -080069
70 def __init__(self):
71 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
72 gdb.COMPLETE_FILENAME)
73
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):
79 for name in files:
80 if name.endswith(".ko"):
81 self.module_files.append(root + "/" + name)
82 self.module_files_updated = True
83
84 def _get_module_file(self, module_name):
85 module_pattern = ".*/{0}\.ko$".format(
Pantelis Koukousoulas276d97d2015-02-17 13:47:35 -080086 module_name.replace("_", r"[_\-]"))
Jan Kiszka66051722015-02-17 13:46:47 -080087 for name in self.module_files:
88 if re.match(module_pattern, name) and os.path.exists(name):
89 return name
90 return None
91
92 def _section_arguments(self, module):
93 try:
94 sect_attrs = module['sect_attrs'].dereference()
95 except gdb.error:
96 return ""
97 attrs = sect_attrs['attrs']
98 section_name_to_address = {
Thiébaud Weksteen6ad18b72015-06-30 14:58:18 -070099 attrs[n]['name'].string(): attrs[n]['address']
Pantelis Koukousoulas276d97d2015-02-17 13:47:35 -0800100 for n in range(int(sect_attrs['nsections']))}
Jan Kiszka66051722015-02-17 13:46:47 -0800101 args = []
102 for section_name in [".data", ".data..read_mostly", ".rodata", ".bss"]:
103 address = section_name_to_address.get(section_name)
104 if address:
105 args.append(" -s {name} {addr}".format(
106 name=section_name, addr=str(address)))
107 return "".join(args)
108
109 def load_module_symbols(self, module):
110 module_name = module['name'].string()
Jan Kiszkaad4db3b2016-03-22 14:27:39 -0700111 module_addr = str(module['core_layout']['base']).split()[0]
Jan Kiszka66051722015-02-17 13:46:47 -0800112
113 module_file = self._get_module_file(module_name)
114 if not module_file and not self.module_files_updated:
115 self._update_module_files()
116 module_file = self._get_module_file(module_name)
117
118 if module_file:
119 gdb.write("loading @{addr}: {filename}\n".format(
120 addr=module_addr, filename=module_file))
121 cmdline = "add-symbol-file {filename} {addr}{sections}".format(
122 filename=module_file,
123 addr=module_addr,
124 sections=self._section_arguments(module))
125 gdb.execute(cmdline, to_string=True)
Thiébaud Weksteen6ad18b72015-06-30 14:58:18 -0700126 if module_name not in self.loaded_modules:
Jan Kiszka82b41e32015-02-17 13:46:52 -0800127 self.loaded_modules.append(module_name)
Jan Kiszka66051722015-02-17 13:46:47 -0800128 else:
129 gdb.write("no module object found for '{0}'\n".format(module_name))
130
131 def load_all_symbols(self):
132 gdb.write("loading vmlinux\n")
133
134 # Dropping symbols will disable all breakpoints. So save their states
135 # and restore them afterward.
136 saved_states = []
137 if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
138 for bp in gdb.breakpoints():
139 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
140
141 # drop all current symbols and reload vmlinux
142 gdb.execute("symbol-file", to_string=True)
143 gdb.execute("symbol-file vmlinux")
144
Jan Kiszka82b41e32015-02-17 13:46:52 -0800145 self.loaded_modules = []
Jan Kiszkafffb9442015-02-17 13:47:44 -0800146 module_list = modules.module_list()
Jan Kiszka66051722015-02-17 13:46:47 -0800147 if not module_list:
148 gdb.write("no modules found\n")
149 else:
150 [self.load_module_symbols(module) for module in module_list]
151
152 for saved_state in saved_states:
153 saved_state['breakpoint'].enabled = saved_state['enabled']
154
155 def invoke(self, arg, from_tty):
Nikolay Borisov552ab2a2016-07-14 12:07:04 -0700156 self.module_paths = [os.path.expanduser(p) for p in arg.split()]
Jan Kiszka66051722015-02-17 13:46:47 -0800157 self.module_paths.append(os.getcwd())
158
159 # enforce update
160 self.module_files = []
161 self.module_files_updated = False
162
163 self.load_all_symbols()
164
Jan Kiszka82b41e32015-02-17 13:46:52 -0800165 if hasattr(gdb, 'Breakpoint'):
Thiébaud Weksteen6ad18b72015-06-30 14:58:18 -0700166 if self.breakpoint is not None:
Jan Kiszka82b41e32015-02-17 13:46:52 -0800167 self.breakpoint.delete()
168 self.breakpoint = None
169 self.breakpoint = LoadModuleBreakpoint(
170 "kernel/module.c:do_init_module", self)
171 else:
172 gdb.write("Note: symbol update on module loading not supported "
173 "with this gdb version\n")
174
Jan Kiszka66051722015-02-17 13:46:47 -0800175
176LxSymbols()