diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-03-04 00:35:43 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-03-04 00:35:43 -0500 |
commit | d2c032e3dc58137a7261a7824d3acce435db1d66 (patch) | |
tree | 7eea1c7c6103eefe879f07472eec99b3c41eb792 /scripts/gdb/linux/symbols.py | |
parent | 7e8e385aaf6ed5b64b5d9108081cfcdcdd021b78 (diff) | |
parent | 13a7a6ac0a11197edcd0f756a035f472b42cdf8b (diff) |
Merge tag 'v4.0-rc2' into x86/asm, to refresh the tree
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'scripts/gdb/linux/symbols.py')
-rw-r--r-- | scripts/gdb/linux/symbols.py | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py new file mode 100644 index 000000000000..cd5bea965d4e --- /dev/null +++ b/scripts/gdb/linux/symbols.py | |||
@@ -0,0 +1,177 @@ | |||
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 | # 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 | |||
44 | 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) | ||
50 | |||
51 | # restore pagination state | ||
52 | gdb.execute("set pagination %s" % ("on" if pagination else "off")) | ||
53 | |||
54 | return False | ||
55 | |||
56 | |||
57 | class LxSymbols(gdb.Command): | ||
58 | """(Re-)load symbols of Linux kernel and currently loaded modules. | ||
59 | |||
60 | The kernel (vmlinux) is taken from the current working directly. Modules (.ko) | ||
61 | are scanned recursively, starting in the same directory. Optionally, the module | ||
62 | search path can be extended by a space separated list of paths passed to the | ||
63 | lx-symbols command.""" | ||
64 | |||
65 | module_paths = [] | ||
66 | module_files = [] | ||
67 | module_files_updated = False | ||
68 | loaded_modules = [] | ||
69 | breakpoint = None | ||
70 | |||
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( | ||
87 | module_name.replace("_", r"[_\-]")) | ||
88 | 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'] | ||
101 | for n in range(int(sect_attrs['nsections']))} | ||
102 | 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) | ||
127 | if not module_name in self.loaded_modules: | ||
128 | self.loaded_modules.append(module_name) | ||
129 | 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 | |||
146 | self.loaded_modules = [] | ||
147 | module_list = modules.module_list() | ||
148 | 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 | |||
166 | 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 | |||
176 | |||
177 | LxSymbols() | ||