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 | ||
22 | class LxSymbols(gdb.Command): | |
23 | """(Re-)load symbols of Linux kernel and currently loaded modules. | |
24 | ||
25 | The kernel (vmlinux) is taken from the current working directly. Modules (.ko) | |
26 | are scanned recursively, starting in the same directory. Optionally, the module | |
27 | search path can be extended by a space separated list of paths passed to the | |
28 | lx-symbols command.""" | |
29 | ||
30 | module_paths = [] | |
31 | module_files = [] | |
32 | module_files_updated = False | |
33 | ||
34 | def __init__(self): | |
35 | super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES, | |
36 | gdb.COMPLETE_FILENAME) | |
37 | ||
38 | def _update_module_files(self): | |
39 | self.module_files = [] | |
40 | for path in self.module_paths: | |
41 | gdb.write("scanning for modules in {0}\n".format(path)) | |
42 | for root, dirs, files in os.walk(path): | |
43 | for name in files: | |
44 | if name.endswith(".ko"): | |
45 | self.module_files.append(root + "/" + name) | |
46 | self.module_files_updated = True | |
47 | ||
48 | def _get_module_file(self, module_name): | |
49 | module_pattern = ".*/{0}\.ko$".format( | |
50 | string.replace(module_name, "_", r"[_\-]")) | |
51 | for name in self.module_files: | |
52 | if re.match(module_pattern, name) and os.path.exists(name): | |
53 | return name | |
54 | return None | |
55 | ||
56 | def _section_arguments(self, module): | |
57 | try: | |
58 | sect_attrs = module['sect_attrs'].dereference() | |
59 | except gdb.error: | |
60 | return "" | |
61 | attrs = sect_attrs['attrs'] | |
62 | section_name_to_address = { | |
63 | attrs[n]['name'].string() : attrs[n]['address'] | |
64 | for n in range(sect_attrs['nsections'])} | |
65 | args = [] | |
66 | for section_name in [".data", ".data..read_mostly", ".rodata", ".bss"]: | |
67 | address = section_name_to_address.get(section_name) | |
68 | if address: | |
69 | args.append(" -s {name} {addr}".format( | |
70 | name=section_name, addr=str(address))) | |
71 | return "".join(args) | |
72 | ||
73 | def load_module_symbols(self, module): | |
74 | module_name = module['name'].string() | |
75 | module_addr = str(module['module_core']).split()[0] | |
76 | ||
77 | module_file = self._get_module_file(module_name) | |
78 | if not module_file and not self.module_files_updated: | |
79 | self._update_module_files() | |
80 | module_file = self._get_module_file(module_name) | |
81 | ||
82 | if module_file: | |
83 | gdb.write("loading @{addr}: {filename}\n".format( | |
84 | addr=module_addr, filename=module_file)) | |
85 | cmdline = "add-symbol-file {filename} {addr}{sections}".format( | |
86 | filename=module_file, | |
87 | addr=module_addr, | |
88 | sections=self._section_arguments(module)) | |
89 | gdb.execute(cmdline, to_string=True) | |
90 | else: | |
91 | gdb.write("no module object found for '{0}'\n".format(module_name)) | |
92 | ||
93 | def load_all_symbols(self): | |
94 | gdb.write("loading vmlinux\n") | |
95 | ||
96 | # Dropping symbols will disable all breakpoints. So save their states | |
97 | # and restore them afterward. | |
98 | saved_states = [] | |
99 | if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None: | |
100 | for bp in gdb.breakpoints(): | |
101 | saved_states.append({'breakpoint': bp, 'enabled': bp.enabled}) | |
102 | ||
103 | # drop all current symbols and reload vmlinux | |
104 | gdb.execute("symbol-file", to_string=True) | |
105 | gdb.execute("symbol-file vmlinux") | |
106 | ||
107 | module_list = modules.ModuleList() | |
108 | if not module_list: | |
109 | gdb.write("no modules found\n") | |
110 | else: | |
111 | [self.load_module_symbols(module) for module in module_list] | |
112 | ||
113 | for saved_state in saved_states: | |
114 | saved_state['breakpoint'].enabled = saved_state['enabled'] | |
115 | ||
116 | def invoke(self, arg, from_tty): | |
117 | self.module_paths = arg.split() | |
118 | self.module_paths.append(os.getcwd()) | |
119 | ||
120 | # enforce update | |
121 | self.module_files = [] | |
122 | self.module_files_updated = False | |
123 | ||
124 | self.load_all_symbols() | |
125 | ||
126 | ||
127 | LxSymbols() |