]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - scripts/gdb/linux/symbols.py
scripts/gdb: add automatic symbol reloading on module insertion
[karo-tx-linux.git] / scripts / gdb / linux / symbols.py
1 #
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
14 import gdb
15 import os
16 import re
17 import string
18
19 from linux import modules, utils
20
21
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)
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
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()
41             else:
42                 cmd.load_module_symbols(module)
43             return False
44
45
46 class LxSymbols(gdb.Command):
47     """(Re-)load symbols of Linux kernel and currently loaded modules.
48
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."""
53
54     module_paths = []
55     module_files = []
56     module_files_updated = False
57     loaded_modules = []
58     breakpoint = None
59
60     def __init__(self):
61         super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
62                                         gdb.COMPLETE_FILENAME)
63
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):
69                 for name in files:
70                     if name.endswith(".ko"):
71                         self.module_files.append(root + "/" + name)
72         self.module_files_updated = True
73
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):
79                 return name
80         return None
81
82     def _section_arguments(self, module):
83         try:
84             sect_attrs = module['sect_attrs'].dereference()
85         except gdb.error:
86             return ""
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'])}
91         args = []
92         for section_name in [".data", ".data..read_mostly", ".rodata", ".bss"]:
93             address = section_name_to_address.get(section_name)
94             if address:
95                 args.append(" -s {name} {addr}".format(
96                     name=section_name, addr=str(address)))
97         return "".join(args)
98
99     def load_module_symbols(self, module):
100         module_name = module['name'].string()
101         module_addr = str(module['module_core']).split()[0]
102
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)
107
108         if module_file:
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,
113                 addr=module_addr,
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)
118         else:
119             gdb.write("no module object found for '{0}'\n".format(module_name))
120
121     def load_all_symbols(self):
122         gdb.write("loading vmlinux\n")
123
124         # Dropping symbols will disable all breakpoints. So save their states
125         # and restore them afterward.
126         saved_states = []
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})
130
131         # drop all current symbols and reload vmlinux
132         gdb.execute("symbol-file", to_string=True)
133         gdb.execute("symbol-file vmlinux")
134
135         self.loaded_modules = []
136         module_list = modules.ModuleList()
137         if not module_list:
138             gdb.write("no modules found\n")
139         else:
140             [self.load_module_symbols(module) for module in module_list]
141
142         for saved_state in saved_states:
143             saved_state['breakpoint'].enabled = saved_state['enabled']
144
145     def invoke(self, arg, from_tty):
146         self.module_paths = arg.split()
147         self.module_paths.append(os.getcwd())
148
149         # enforce update
150         self.module_files = []
151         self.module_files_updated = False
152
153         self.load_all_symbols()
154
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)
161         else:
162             gdb.write("Note: symbol update on module loading not supported "
163                       "with this gdb version\n")
164
165
166 LxSymbols()