xref: /OK3568_Linux_fs/kernel/scripts/gdb/linux/symbols.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#
2*4882a593Smuzhiyun# gdb helper commands and functions for Linux kernel debugging
3*4882a593Smuzhiyun#
4*4882a593Smuzhiyun#  load kernel and module symbols
5*4882a593Smuzhiyun#
6*4882a593Smuzhiyun# Copyright (c) Siemens AG, 2011-2013
7*4882a593Smuzhiyun#
8*4882a593Smuzhiyun# Authors:
9*4882a593Smuzhiyun#  Jan Kiszka <jan.kiszka@siemens.com>
10*4882a593Smuzhiyun#
11*4882a593Smuzhiyun# This work is licensed under the terms of the GNU GPL version 2.
12*4882a593Smuzhiyun#
13*4882a593Smuzhiyun
14*4882a593Smuzhiyunimport gdb
15*4882a593Smuzhiyunimport os
16*4882a593Smuzhiyunimport re
17*4882a593Smuzhiyun
18*4882a593Smuzhiyunfrom linux import modules, utils
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun
21*4882a593Smuzhiyunif hasattr(gdb, 'Breakpoint'):
22*4882a593Smuzhiyun    class LoadModuleBreakpoint(gdb.Breakpoint):
23*4882a593Smuzhiyun        def __init__(self, spec, gdb_command):
24*4882a593Smuzhiyun            super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
25*4882a593Smuzhiyun            self.silent = True
26*4882a593Smuzhiyun            self.gdb_command = gdb_command
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun        def stop(self):
29*4882a593Smuzhiyun            module = gdb.parse_and_eval("mod")
30*4882a593Smuzhiyun            module_name = module['name'].string()
31*4882a593Smuzhiyun            cmd = self.gdb_command
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun            # enforce update if object file is not found
34*4882a593Smuzhiyun            cmd.module_files_updated = False
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun            # Disable pagination while reporting symbol (re-)loading.
37*4882a593Smuzhiyun            # The console input is blocked in this context so that we would
38*4882a593Smuzhiyun            # get stuck waiting for the user to acknowledge paged output.
39*4882a593Smuzhiyun            show_pagination = gdb.execute("show pagination", to_string=True)
40*4882a593Smuzhiyun            pagination = show_pagination.endswith("on.\n")
41*4882a593Smuzhiyun            gdb.execute("set pagination off")
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun            if module_name in cmd.loaded_modules:
44*4882a593Smuzhiyun                gdb.write("refreshing all symbols to reload module "
45*4882a593Smuzhiyun                          "'{0}'\n".format(module_name))
46*4882a593Smuzhiyun                cmd.load_all_symbols()
47*4882a593Smuzhiyun            else:
48*4882a593Smuzhiyun                cmd.load_module_symbols(module)
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun            # restore pagination state
51*4882a593Smuzhiyun            gdb.execute("set pagination %s" % ("on" if pagination else "off"))
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun            return False
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun
56*4882a593Smuzhiyunclass LxSymbols(gdb.Command):
57*4882a593Smuzhiyun    """(Re-)load symbols of Linux kernel and currently loaded modules.
58*4882a593Smuzhiyun
59*4882a593SmuzhiyunThe kernel (vmlinux) is taken from the current working directly. Modules (.ko)
60*4882a593Smuzhiyunare scanned recursively, starting in the same directory. Optionally, the module
61*4882a593Smuzhiyunsearch path can be extended by a space separated list of paths passed to the
62*4882a593Smuzhiyunlx-symbols command."""
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun    module_paths = []
65*4882a593Smuzhiyun    module_files = []
66*4882a593Smuzhiyun    module_files_updated = False
67*4882a593Smuzhiyun    loaded_modules = []
68*4882a593Smuzhiyun    breakpoint = None
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun    def __init__(self):
71*4882a593Smuzhiyun        super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
72*4882a593Smuzhiyun                                        gdb.COMPLETE_FILENAME)
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun    def _update_module_files(self):
75*4882a593Smuzhiyun        self.module_files = []
76*4882a593Smuzhiyun        for path in self.module_paths:
77*4882a593Smuzhiyun            gdb.write("scanning for modules in {0}\n".format(path))
78*4882a593Smuzhiyun            for root, dirs, files in os.walk(path):
79*4882a593Smuzhiyun                for name in files:
80*4882a593Smuzhiyun                    if name.endswith(".ko") or name.endswith(".ko.debug"):
81*4882a593Smuzhiyun                        self.module_files.append(root + "/" + name)
82*4882a593Smuzhiyun        self.module_files_updated = True
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun    def _get_module_file(self, module_name):
85*4882a593Smuzhiyun        module_pattern = ".*/{0}\.ko(?:.debug)?$".format(
86*4882a593Smuzhiyun            module_name.replace("_", r"[_\-]"))
87*4882a593Smuzhiyun        for name in self.module_files:
88*4882a593Smuzhiyun            if re.match(module_pattern, name) and os.path.exists(name):
89*4882a593Smuzhiyun                return name
90*4882a593Smuzhiyun        return None
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun    def _section_arguments(self, module):
93*4882a593Smuzhiyun        try:
94*4882a593Smuzhiyun            sect_attrs = module['sect_attrs'].dereference()
95*4882a593Smuzhiyun        except gdb.error:
96*4882a593Smuzhiyun            return ""
97*4882a593Smuzhiyun        attrs = sect_attrs['attrs']
98*4882a593Smuzhiyun        section_name_to_address = {
99*4882a593Smuzhiyun            attrs[n]['battr']['attr']['name'].string(): attrs[n]['address']
100*4882a593Smuzhiyun            for n in range(int(sect_attrs['nsections']))}
101*4882a593Smuzhiyun        args = []
102*4882a593Smuzhiyun        for section_name in [".data", ".data..read_mostly", ".rodata", ".bss",
103*4882a593Smuzhiyun                             ".text", ".text.hot", ".text.unlikely"]:
104*4882a593Smuzhiyun            address = section_name_to_address.get(section_name)
105*4882a593Smuzhiyun            if address:
106*4882a593Smuzhiyun                args.append(" -s {name} {addr}".format(
107*4882a593Smuzhiyun                    name=section_name, addr=str(address)))
108*4882a593Smuzhiyun        return "".join(args)
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun    def load_module_symbols(self, module):
111*4882a593Smuzhiyun        module_name = module['name'].string()
112*4882a593Smuzhiyun        module_addr = str(module['core_layout']['base']).split()[0]
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun        module_file = self._get_module_file(module_name)
115*4882a593Smuzhiyun        if not module_file and not self.module_files_updated:
116*4882a593Smuzhiyun            self._update_module_files()
117*4882a593Smuzhiyun            module_file = self._get_module_file(module_name)
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun        if module_file:
120*4882a593Smuzhiyun            if utils.is_target_arch('s390'):
121*4882a593Smuzhiyun                # Module text is preceded by PLT stubs on s390.
122*4882a593Smuzhiyun                module_arch = module['arch']
123*4882a593Smuzhiyun                plt_offset = int(module_arch['plt_offset'])
124*4882a593Smuzhiyun                plt_size = int(module_arch['plt_size'])
125*4882a593Smuzhiyun                module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
126*4882a593Smuzhiyun            gdb.write("loading @{addr}: {filename}\n".format(
127*4882a593Smuzhiyun                addr=module_addr, filename=module_file))
128*4882a593Smuzhiyun            cmdline = "add-symbol-file {filename} {addr}{sections}".format(
129*4882a593Smuzhiyun                filename=module_file,
130*4882a593Smuzhiyun                addr=module_addr,
131*4882a593Smuzhiyun                sections=self._section_arguments(module))
132*4882a593Smuzhiyun            gdb.execute(cmdline, to_string=True)
133*4882a593Smuzhiyun            if module_name not in self.loaded_modules:
134*4882a593Smuzhiyun                self.loaded_modules.append(module_name)
135*4882a593Smuzhiyun        else:
136*4882a593Smuzhiyun            gdb.write("no module object found for '{0}'\n".format(module_name))
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun    def load_all_symbols(self):
139*4882a593Smuzhiyun        gdb.write("loading vmlinux\n")
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun        # Dropping symbols will disable all breakpoints. So save their states
142*4882a593Smuzhiyun        # and restore them afterward.
143*4882a593Smuzhiyun        saved_states = []
144*4882a593Smuzhiyun        if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
145*4882a593Smuzhiyun            for bp in gdb.breakpoints():
146*4882a593Smuzhiyun                saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun        # drop all current symbols and reload vmlinux
149*4882a593Smuzhiyun        orig_vmlinux = 'vmlinux'
150*4882a593Smuzhiyun        for obj in gdb.objfiles():
151*4882a593Smuzhiyun            if obj.filename.endswith('vmlinux'):
152*4882a593Smuzhiyun                orig_vmlinux = obj.filename
153*4882a593Smuzhiyun        gdb.execute("symbol-file", to_string=True)
154*4882a593Smuzhiyun        gdb.execute("symbol-file {0}".format(orig_vmlinux))
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun        self.loaded_modules = []
157*4882a593Smuzhiyun        module_list = modules.module_list()
158*4882a593Smuzhiyun        if not module_list:
159*4882a593Smuzhiyun            gdb.write("no modules found\n")
160*4882a593Smuzhiyun        else:
161*4882a593Smuzhiyun            [self.load_module_symbols(module) for module in module_list]
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun        for saved_state in saved_states:
164*4882a593Smuzhiyun            saved_state['breakpoint'].enabled = saved_state['enabled']
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun    def invoke(self, arg, from_tty):
167*4882a593Smuzhiyun        self.module_paths = [os.path.expanduser(p) for p in arg.split()]
168*4882a593Smuzhiyun        self.module_paths.append(os.getcwd())
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun        # enforce update
171*4882a593Smuzhiyun        self.module_files = []
172*4882a593Smuzhiyun        self.module_files_updated = False
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun        self.load_all_symbols()
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun        if hasattr(gdb, 'Breakpoint'):
177*4882a593Smuzhiyun            if self.breakpoint is not None:
178*4882a593Smuzhiyun                self.breakpoint.delete()
179*4882a593Smuzhiyun                self.breakpoint = None
180*4882a593Smuzhiyun            self.breakpoint = LoadModuleBreakpoint(
181*4882a593Smuzhiyun                "kernel/module.c:do_init_module", self)
182*4882a593Smuzhiyun        else:
183*4882a593Smuzhiyun            gdb.write("Note: symbol update on module loading not supported "
184*4882a593Smuzhiyun                      "with this gdb version\n")
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun
187*4882a593SmuzhiyunLxSymbols()
188