blob: cd5bea965d4eb015f57b0baec1b9d4b75ac44964 [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
17import string
18
19from linux import modules, utils
20
21
Jan Kiszka82b41e32015-02-17 13:46:52 -080022if hasattr(gdb, 'Breakpoint'):
23 class LoadModuleBreakpoint(gdb.Breakpoint):
24 def __init__(self, spec, gdb_command):
25 super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
26 self.silent = True
27 self.gdb_command = gdb_command
28
29 def stop(self):
30 module = gdb.parse_and_eval("mod")
31 module_name = module['name'].string()
32 cmd = self.gdb_command
33
34 # enforce update if object file is not found
35 cmd.module_files_updated = False
36
Jan Kiszkaa9c5bcf2015-02-17 13:47:52 -080037 # Disable pagination while reporting symbol (re-)loading.
38 # The console input is blocked in this context so that we would
39 # get stuck waiting for the user to acknowledge paged output.
40 show_pagination = gdb.execute("show pagination", to_string=True)
41 pagination = show_pagination.endswith("on.\n")
42 gdb.execute("set pagination off")
43
Jan Kiszka82b41e32015-02-17 13:46:52 -080044 if module_name in cmd.loaded_modules:
45 gdb.write("refreshing all symbols to reload module "
46 "'{0}'\n".format(module_name))
47 cmd.load_all_symbols()
48 else:
49 cmd.load_module_symbols(module)
Jan Kiszkaa9c5bcf2015-02-17 13:47:52 -080050
51 # restore pagination state
52 gdb.execute("set pagination %s" % ("on" if pagination else "off"))
53
Jan Kiszka82b41e32015-02-17 13:46:52 -080054 return False
55
56
Jan Kiszka66051722015-02-17 13:46:47 -080057class LxSymbols(gdb.Command):
58 """(Re-)load symbols of Linux kernel and currently loaded modules.
59
60The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
61are scanned recursively, starting in the same directory. Optionally, the module
62search path can be extended by a space separated list of paths passed to the
63lx-symbols command."""
64
65 module_paths = []
66 module_files = []
67 module_files_updated = False
Jan Kiszka82b41e32015-02-17 13:46:52 -080068 loaded_modules = []
69 breakpoint = None
Jan Kiszka66051722015-02-17 13:46:47 -080070
71 def __init__(self):
72 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
73 gdb.COMPLETE_FILENAME)
74
75 def _update_module_files(self):
76 self.module_files = []
77 for path in self.module_paths:
78 gdb.write("scanning for modules in {0}\n".format(path))
79 for root, dirs, files in os.walk(path):
80 for name in files:
81 if name.endswith(".ko"):
82 self.module_files.append(root + "/" + name)
83 self.module_files_updated = True
84
85 def _get_module_file(self, module_name):
86 module_pattern = ".*/{0}\.ko$".format(
Pantelis Koukousoulas276d97d2015-02-17 13:47:35 -080087 module_name.replace("_", r"[_\-]"))
Jan Kiszka66051722015-02-17 13:46:47 -080088 for name in self.module_files:
89 if re.match(module_pattern, name) and os.path.exists(name):
90 return name
91 return None
92
93 def _section_arguments(self, module):
94 try:
95 sect_attrs = module['sect_attrs'].dereference()
96 except gdb.error:
97 return ""
98 attrs = sect_attrs['attrs']
99 section_name_to_address = {
100 attrs[n]['name'].string() : attrs[n]['address']
Pantelis Koukousoulas276d97d2015-02-17 13:47:35 -0800101 for n in range(int(sect_attrs['nsections']))}
Jan Kiszka66051722015-02-17 13:46:47 -0800102 args = []
103 for section_name in [".data", ".data..read_mostly", ".rodata", ".bss"]:
104 address = section_name_to_address.get(section_name)
105 if address:
106 args.append(" -s {name} {addr}".format(
107 name=section_name, addr=str(address)))
108 return "".join(args)
109
110 def load_module_symbols(self, module):
111 module_name = module['name'].string()
112 module_addr = str(module['module_core']).split()[0]
113
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)
118
119 if module_file:
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,
124 addr=module_addr,
125 sections=self._section_arguments(module))
126 gdb.execute(cmdline, to_string=True)
Jan Kiszka82b41e32015-02-17 13:46:52 -0800127 if not module_name in self.loaded_modules:
128 self.loaded_modules.append(module_name)
Jan Kiszka66051722015-02-17 13:46:47 -0800129 else:
130 gdb.write("no module object found for '{0}'\n".format(module_name))
131
132 def load_all_symbols(self):
133 gdb.write("loading vmlinux\n")
134
135 # Dropping symbols will disable all breakpoints. So save their states
136 # and restore them afterward.
137 saved_states = []
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})
141
142 # drop all current symbols and reload vmlinux
143 gdb.execute("symbol-file", to_string=True)
144 gdb.execute("symbol-file vmlinux")
145
Jan Kiszka82b41e32015-02-17 13:46:52 -0800146 self.loaded_modules = []
Jan Kiszkafffb9442015-02-17 13:47:44 -0800147 module_list = modules.module_list()
Jan Kiszka66051722015-02-17 13:46:47 -0800148 if not module_list:
149 gdb.write("no modules found\n")
150 else:
151 [self.load_module_symbols(module) for module in module_list]
152
153 for saved_state in saved_states:
154 saved_state['breakpoint'].enabled = saved_state['enabled']
155
156 def invoke(self, arg, from_tty):
157 self.module_paths = arg.split()
158 self.module_paths.append(os.getcwd())
159
160 # enforce update
161 self.module_files = []
162 self.module_files_updated = False
163
164 self.load_all_symbols()
165
Jan Kiszka82b41e32015-02-17 13:46:52 -0800166 if hasattr(gdb, 'Breakpoint'):
167 if not self.breakpoint is None:
168 self.breakpoint.delete()
169 self.breakpoint = None
170 self.breakpoint = LoadModuleBreakpoint(
171 "kernel/module.c:do_init_module", self)
172 else:
173 gdb.write("Note: symbol update on module loading not supported "
174 "with this gdb version\n")
175
Jan Kiszka66051722015-02-17 13:46:47 -0800176
177LxSymbols()