]> Git Repo - linux.git/blob - scripts/gdb/linux/symbols.py
Merge drm/drm-fixes into drm-misc-fixes
[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
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):
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 = {
99             attrs[n]['battr']['attr']['name'].string(): attrs[n]['address']
100             for n in range(int(sect_attrs['nsections']))}
101         args = []
102         for section_name in [".data", ".data..read_mostly", ".rodata", ".bss",
103                              ".text", ".text.hot", ".text.unlikely"]:
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['core_layout']['base']).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             if utils.is_target_arch('s390'):
121                 # Module text is preceded by PLT stubs on s390.
122                 module_arch = module['arch']
123                 plt_offset = int(module_arch['plt_offset'])
124                 plt_size = int(module_arch['plt_size'])
125                 module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
126             gdb.write("loading @{addr}: {filename}\n".format(
127                 addr=module_addr, filename=module_file))
128             cmdline = "add-symbol-file {filename} {addr}{sections}".format(
129                 filename=module_file,
130                 addr=module_addr,
131                 sections=self._section_arguments(module))
132             gdb.execute(cmdline, to_string=True)
133             if module_name not in self.loaded_modules:
134                 self.loaded_modules.append(module_name)
135         else:
136             gdb.write("no module object found for '{0}'\n".format(module_name))
137
138     def load_all_symbols(self):
139         gdb.write("loading vmlinux\n")
140
141         # Dropping symbols will disable all breakpoints. So save their states
142         # and restore them afterward.
143         saved_states = []
144         if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
145             for bp in gdb.breakpoints():
146                 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
147
148         # drop all current symbols and reload vmlinux
149         orig_vmlinux = 'vmlinux'
150         for obj in gdb.objfiles():
151             if (obj.filename.endswith('vmlinux') or
152                 obj.filename.endswith('vmlinux.debug')):
153                 orig_vmlinux = obj.filename
154         gdb.execute("symbol-file", to_string=True)
155         gdb.execute("symbol-file {0}".format(orig_vmlinux))
156
157         self.loaded_modules = []
158         module_list = modules.module_list()
159         if not module_list:
160             gdb.write("no modules found\n")
161         else:
162             [self.load_module_symbols(module) for module in module_list]
163
164         for saved_state in saved_states:
165             saved_state['breakpoint'].enabled = saved_state['enabled']
166
167     def invoke(self, arg, from_tty):
168         self.module_paths = [os.path.abspath(os.path.expanduser(p))
169                              for p in arg.split()]
170         self.module_paths.append(os.getcwd())
171
172         # enforce update
173         self.module_files = []
174         self.module_files_updated = False
175
176         self.load_all_symbols()
177
178         if hasattr(gdb, 'Breakpoint'):
179             if self.breakpoint is not None:
180                 self.breakpoint.delete()
181                 self.breakpoint = None
182             self.breakpoint = LoadModuleBreakpoint(
183                 "kernel/module/main.c:do_init_module", self)
184         else:
185             gdb.write("Note: symbol update on module loading not supported "
186                       "with this gdb version\n")
187
188
189 LxSymbols()
This page took 0.045753 seconds and 4 git commands to generate.