scripts/gdb/symbols: fix invalid escape sequence warning
[sfrench/cifs-2.6.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
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 = r".*/{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):
115         module_name = module['name'].string()
116         module_addr = str(module['mem'][constants.LX_MOD_TEXT]['base']).split()[0]
117
118         module_file = self._get_module_file(module_name)
119         if not module_file and not self.module_files_updated:
120             self._update_module_files()
121             module_file = self._get_module_file(module_name)
122
123         if module_file:
124             if utils.is_target_arch('s390'):
125                 # Module text is preceded by PLT stubs on s390.
126                 module_arch = module['arch']
127                 plt_offset = int(module_arch['plt_offset'])
128                 plt_size = int(module_arch['plt_size'])
129                 module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
130             gdb.write("loading @{addr}: {filename}\n".format(
131                 addr=module_addr, filename=module_file))
132             cmdline = "add-symbol-file {filename} {sections}".format(
133                 filename=module_file,
134                 sections=self._section_arguments(module, module_addr))
135             gdb.execute(cmdline, to_string=True)
136             if module_name not in self.loaded_modules:
137                 self.loaded_modules.append(module_name)
138         else:
139             gdb.write("no module object found for '{0}'\n".format(module_name))
140
141     def load_all_symbols(self):
142         gdb.write("loading vmlinux\n")
143
144         # Dropping symbols will disable all breakpoints. So save their states
145         # and restore them afterward.
146         saved_states = []
147         if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
148             for bp in gdb.breakpoints():
149                 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
150
151         # drop all current symbols and reload vmlinux
152         orig_vmlinux = 'vmlinux'
153         for obj in gdb.objfiles():
154             if (obj.filename.endswith('vmlinux') or
155                 obj.filename.endswith('vmlinux.debug')):
156                 orig_vmlinux = obj.filename
157         gdb.execute("symbol-file", to_string=True)
158         gdb.execute("symbol-file {0}".format(orig_vmlinux))
159
160         self.loaded_modules = []
161         module_list = modules.module_list()
162         if not module_list:
163             gdb.write("no modules found\n")
164         else:
165             [self.load_module_symbols(module) for module in module_list]
166
167         for saved_state in saved_states:
168             saved_state['breakpoint'].enabled = saved_state['enabled']
169
170     def invoke(self, arg, from_tty):
171         self.module_paths = [os.path.abspath(os.path.expanduser(p))
172                              for p in arg.split()]
173         self.module_paths.append(os.getcwd())
174
175         # enforce update
176         self.module_files = []
177         self.module_files_updated = False
178
179         self.load_all_symbols()
180
181         if hasattr(gdb, 'Breakpoint'):
182             if self.breakpoint is not None:
183                 self.breakpoint.delete()
184                 self.breakpoint = None
185             self.breakpoint = LoadModuleBreakpoint(
186                 "kernel/module/main.c:do_init_module", self)
187         else:
188             gdb.write("Note: symbol update on module loading not supported "
189                       "with this gdb version\n")
190
191
192 LxSymbols()