Commit | Line | Data |
---|---|---|
66051720 JK |
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 | ||
82b41e3d JK |
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 | ||
66051720 JK |
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 | |
82b41e3d JK |
57 | loaded_modules = [] |
58 | breakpoint = None | |
66051720 JK |
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( | |
276d97d9 | 76 | module_name.replace("_", r"[_\-]")) |
66051720 JK |
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'] | |
276d97d9 | 90 | for n in range(int(sect_attrs['nsections']))} |
66051720 JK |
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) | |
82b41e3d JK |
116 | if not module_name in self.loaded_modules: |
117 | self.loaded_modules.append(module_name) | |
66051720 JK |
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 | ||
82b41e3d | 135 | self.loaded_modules = [] |
fffb944c | 136 | module_list = modules.module_list() |
66051720 JK |
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 | ||
82b41e3d JK |
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 | ||
66051720 JK |
165 | |
166 | LxSymbols() |