]> Git Repo - linux.git/blob - scripts/gdb/linux/symbols.py
Merge tag 'for-6.6-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[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 <[email protected]>
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
18 from linux import modules, utils, constants
19
20
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)
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
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")
42
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()
47             else:
48                 cmd.load_module_symbols(module)
49
50             # restore pagination state
51             gdb.execute("set pagination %s" % ("on" if pagination else "off"))
52
53             return False
54
55
56 class LxSymbols(gdb.Command):
57     """(Re-)load symbols of Linux kernel and currently loaded modules.
58
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."""
63
64     module_paths = []
65     module_files = []
66     module_files_updated = False
67     loaded_modules = []
68     breakpoint = None
69
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") or name.endswith(".ko.debug"):
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(?:.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):
89                 return name
90         return None
91
92     def _section_arguments(self, module, module_addr):
93         try:
94             sect_attrs = module['sect_attrs'].dereference()
95         except gdb.error:
96             return str(module_addr)
97
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']))}
102
103         textaddr = section_name_to_address.get(".text", module_addr)
104         args = []
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)
108             if address:
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))
113
114     def load_module_symbols(self, module, module_file=None):
115         module_name = module['name'].string()
116         module_addr = str(module['mem'][constants.LX_MOD_TEXT]['base']).split()[0]
117
118         if not module_file:
119             module_file = self._get_module_file(module_name)
120         if not module_file and not self.module_files_updated:
121             self._update_module_files()
122             module_file = self._get_module_file(module_name)
123
124         if module_file:
125             if utils.is_target_arch('s390'):
126                 # Module text is preceded by PLT stubs on s390.
127                 module_arch = module['arch']
128                 plt_offset = int(module_arch['plt_offset'])
129                 plt_size = int(module_arch['plt_size'])
130                 module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
131             gdb.write("loading @{addr}: {filename}\n".format(
132                 addr=module_addr, filename=module_file))
133             cmdline = "add-symbol-file {filename} {sections}".format(
134                 filename=module_file,
135                 sections=self._section_arguments(module, module_addr))
136             gdb.execute(cmdline, to_string=True)
137             if module_name not in self.loaded_modules:
138                 self.loaded_modules.append(module_name)
139         else:
140             gdb.write("no module object found for '{0}'\n".format(module_name))
141
142     def load_ko_symbols(self, mod_path):
143         self.loaded_modules = []
144         module_list = modules.module_list()
145
146         for module in module_list:
147             module_name = module['name'].string()
148             module_pattern = ".*/{0}\.ko(?:.debug)?$".format(
149                 module_name.replace("_", r"[_\-]"))
150             if re.match(module_pattern, mod_path) and os.path.exists(mod_path):
151                 self.load_module_symbols(module, mod_path)
152                 return
153         raise gdb.GdbError("%s is not a valid .ko\n" % mod_path)
154
155     def load_all_symbols(self):
156         gdb.write("loading vmlinux\n")
157
158         # Dropping symbols will disable all breakpoints. So save their states
159         # and restore them afterward.
160         saved_states = []
161         if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
162             for bp in gdb.breakpoints():
163                 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
164
165         # drop all current symbols and reload vmlinux
166         orig_vmlinux = 'vmlinux'
167         for obj in gdb.objfiles():
168             if (obj.filename.endswith('vmlinux') or
169                 obj.filename.endswith('vmlinux.debug')):
170                 orig_vmlinux = obj.filename
171         gdb.execute("symbol-file", to_string=True)
172         gdb.execute("symbol-file {0}".format(orig_vmlinux))
173
174         self.loaded_modules = []
175         module_list = modules.module_list()
176         if not module_list:
177             gdb.write("no modules found\n")
178         else:
179             [self.load_module_symbols(module) for module in module_list]
180
181         for saved_state in saved_states:
182             saved_state['breakpoint'].enabled = saved_state['enabled']
183
184     def invoke(self, arg, from_tty):
185         self.module_paths = [os.path.abspath(os.path.expanduser(p))
186                              for p in arg.split()]
187         self.module_paths.append(os.getcwd())
188
189         # enforce update
190         self.module_files = []
191         self.module_files_updated = False
192
193         argv = gdb.string_to_argv(arg)
194         if len(argv) == 1:
195             self.load_ko_symbols(argv[0])
196             return
197
198         self.load_all_symbols()
199
200         if hasattr(gdb, 'Breakpoint'):
201             if self.breakpoint is not None:
202                 self.breakpoint.delete()
203                 self.breakpoint = None
204             self.breakpoint = LoadModuleBreakpoint(
205                 "kernel/module/main.c:do_init_module", self)
206         else:
207             gdb.write("Note: symbol update on module loading not supported "
208                       "with this gdb version\n")
209
210
211 LxSymbols()
This page took 0.047087 seconds and 4 git commands to generate.