xref: /linux/scripts/gdb/linux/symbols.py (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
166051720SJan Kiszka#
266051720SJan Kiszka# gdb helper commands and functions for Linux kernel debugging
366051720SJan Kiszka#
466051720SJan Kiszka#  load kernel and module symbols
566051720SJan Kiszka#
666051720SJan Kiszka# Copyright (c) Siemens AG, 2011-2013
766051720SJan Kiszka#
866051720SJan Kiszka# Authors:
966051720SJan Kiszka#  Jan Kiszka <jan.kiszka@siemens.com>
1066051720SJan Kiszka#
1166051720SJan Kiszka# This work is licensed under the terms of the GNU GPL version 2.
1266051720SJan Kiszka#
1366051720SJan Kiszka
1466051720SJan Kiszkaimport gdb
1566051720SJan Kiszkaimport os
1666051720SJan Kiszkaimport re
1766051720SJan Kiszka
18b4aff751SPankaj Raghavfrom linux import modules, utils, constants
1966051720SJan Kiszka
2066051720SJan Kiszka
2182b41e3dSJan Kiszkaif hasattr(gdb, 'Breakpoint'):
2282b41e3dSJan Kiszka    class LoadModuleBreakpoint(gdb.Breakpoint):
2382b41e3dSJan Kiszka        def __init__(self, spec, gdb_command):
2482b41e3dSJan Kiszka            super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
2582b41e3dSJan Kiszka            self.silent = True
2682b41e3dSJan Kiszka            self.gdb_command = gdb_command
2782b41e3dSJan Kiszka
2882b41e3dSJan Kiszka        def stop(self):
2982b41e3dSJan Kiszka            module = gdb.parse_and_eval("mod")
3082b41e3dSJan Kiszka            module_name = module['name'].string()
3182b41e3dSJan Kiszka            cmd = self.gdb_command
3282b41e3dSJan Kiszka
3382b41e3dSJan Kiszka            # enforce update if object file is not found
3482b41e3dSJan Kiszka            cmd.module_files_updated = False
3582b41e3dSJan Kiszka
36a9c5bcfaSJan Kiszka            # Disable pagination while reporting symbol (re-)loading.
37a9c5bcfaSJan Kiszka            # The console input is blocked in this context so that we would
38a9c5bcfaSJan Kiszka            # get stuck waiting for the user to acknowledge paged output.
39a9c5bcfaSJan Kiszka            show_pagination = gdb.execute("show pagination", to_string=True)
40a9c5bcfaSJan Kiszka            pagination = show_pagination.endswith("on.\n")
41a9c5bcfaSJan Kiszka            gdb.execute("set pagination off")
42a9c5bcfaSJan Kiszka
4382b41e3dSJan Kiszka            if module_name in cmd.loaded_modules:
4482b41e3dSJan Kiszka                gdb.write("refreshing all symbols to reload module "
4582b41e3dSJan Kiszka                          "'{0}'\n".format(module_name))
4682b41e3dSJan Kiszka                cmd.load_all_symbols()
4782b41e3dSJan Kiszka            else:
4882b41e3dSJan Kiszka                cmd.load_module_symbols(module)
49a9c5bcfaSJan Kiszka
50a9c5bcfaSJan Kiszka            # restore pagination state
51a9c5bcfaSJan Kiszka            gdb.execute("set pagination %s" % ("on" if pagination else "off"))
52a9c5bcfaSJan Kiszka
5382b41e3dSJan Kiszka            return False
5482b41e3dSJan Kiszka
5582b41e3dSJan Kiszka
5666051720SJan Kiszkaclass LxSymbols(gdb.Command):
5766051720SJan Kiszka    """(Re-)load symbols of Linux kernel and currently loaded modules.
5866051720SJan Kiszka
5966051720SJan KiszkaThe kernel (vmlinux) is taken from the current working directly. Modules (.ko)
6066051720SJan Kiszkaare scanned recursively, starting in the same directory. Optionally, the module
6166051720SJan Kiszkasearch path can be extended by a space separated list of paths passed to the
6266051720SJan Kiszkalx-symbols command."""
6366051720SJan Kiszka
6466051720SJan Kiszka    module_paths = []
6566051720SJan Kiszka    module_files = []
6666051720SJan Kiszka    module_files_updated = False
6782b41e3dSJan Kiszka    loaded_modules = []
6882b41e3dSJan Kiszka    breakpoint = None
6966051720SJan Kiszka
7066051720SJan Kiszka    def __init__(self):
7166051720SJan Kiszka        super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
7266051720SJan Kiszka                                        gdb.COMPLETE_FILENAME)
7366051720SJan Kiszka
7466051720SJan Kiszka    def _update_module_files(self):
7566051720SJan Kiszka        self.module_files = []
7666051720SJan Kiszka        for path in self.module_paths:
7766051720SJan Kiszka            gdb.write("scanning for modules in {0}\n".format(path))
7866051720SJan Kiszka            for root, dirs, files in os.walk(path):
7966051720SJan Kiszka                for name in files:
80da036ae1SDouglas Anderson                    if name.endswith(".ko") or name.endswith(".ko.debug"):
8166051720SJan Kiszka                        self.module_files.append(root + "/" + name)
8266051720SJan Kiszka        self.module_files_updated = True
8366051720SJan Kiszka
8466051720SJan Kiszka    def _get_module_file(self, module_name):
85*ded79af4SAndrew Ballance        module_pattern = r".*/{0}\.ko(?:.debug)?$".format(
86276d97d9SPantelis Koukousoulas            module_name.replace("_", r"[_\-]"))
8766051720SJan Kiszka        for name in self.module_files:
8866051720SJan Kiszka            if re.match(module_pattern, name) and os.path.exists(name):
8966051720SJan Kiszka                return name
9066051720SJan Kiszka        return None
9166051720SJan Kiszka
921677bf76SKoudai Iwahori    def _section_arguments(self, module, module_addr):
9366051720SJan Kiszka        try:
9466051720SJan Kiszka            sect_attrs = module['sect_attrs'].dereference()
9566051720SJan Kiszka        except gdb.error:
961677bf76SKoudai Iwahori            return str(module_addr)
971677bf76SKoudai Iwahori
9866051720SJan Kiszka        attrs = sect_attrs['attrs']
9966051720SJan Kiszka        section_name_to_address = {
1007359608aSStefano Garzarella            attrs[n]['battr']['attr']['name'].string(): attrs[n]['address']
101276d97d9SPantelis Koukousoulas            for n in range(int(sect_attrs['nsections']))}
1021677bf76SKoudai Iwahori
1031677bf76SKoudai Iwahori        textaddr = section_name_to_address.get(".text", module_addr)
10466051720SJan Kiszka        args = []
1058731acc5SIlya Leoshkevich        for section_name in [".data", ".data..read_mostly", ".rodata", ".bss",
1061677bf76SKoudai Iwahori                             ".text.hot", ".text.unlikely"]:
10766051720SJan Kiszka            address = section_name_to_address.get(section_name)
10866051720SJan Kiszka            if address:
10966051720SJan Kiszka                args.append(" -s {name} {addr}".format(
11066051720SJan Kiszka                    name=section_name, addr=str(address)))
1111677bf76SKoudai Iwahori        return "{textaddr} {sections}".format(
1121677bf76SKoudai Iwahori            textaddr=textaddr, sections="".join(args))
11366051720SJan Kiszka
114493d4eecSAndrew Morton    def load_module_symbols(self, module):
11566051720SJan Kiszka        module_name = module['name'].string()
116b4aff751SPankaj Raghav        module_addr = str(module['mem'][constants.LX_MOD_TEXT]['base']).split()[0]
11766051720SJan Kiszka
11866051720SJan Kiszka        module_file = self._get_module_file(module_name)
11966051720SJan Kiszka        if not module_file and not self.module_files_updated:
12066051720SJan Kiszka            self._update_module_files()
12166051720SJan Kiszka            module_file = self._get_module_file(module_name)
12266051720SJan Kiszka
12366051720SJan Kiszka        if module_file:
124585d730dSIlya Leoshkevich            if utils.is_target_arch('s390'):
125585d730dSIlya Leoshkevich                # Module text is preceded by PLT stubs on s390.
126585d730dSIlya Leoshkevich                module_arch = module['arch']
127585d730dSIlya Leoshkevich                plt_offset = int(module_arch['plt_offset'])
128585d730dSIlya Leoshkevich                plt_size = int(module_arch['plt_size'])
129585d730dSIlya Leoshkevich                module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
13066051720SJan Kiszka            gdb.write("loading @{addr}: {filename}\n".format(
13166051720SJan Kiszka                addr=module_addr, filename=module_file))
1321677bf76SKoudai Iwahori            cmdline = "add-symbol-file {filename} {sections}".format(
13366051720SJan Kiszka                filename=module_file,
1341677bf76SKoudai Iwahori                sections=self._section_arguments(module, module_addr))
13566051720SJan Kiszka            gdb.execute(cmdline, to_string=True)
1366ad18b73SThiébaud Weksteen            if module_name not in self.loaded_modules:
13782b41e3dSJan Kiszka                self.loaded_modules.append(module_name)
13866051720SJan Kiszka        else:
13966051720SJan Kiszka            gdb.write("no module object found for '{0}'\n".format(module_name))
14066051720SJan Kiszka
14166051720SJan Kiszka    def load_all_symbols(self):
14266051720SJan Kiszka        gdb.write("loading vmlinux\n")
14366051720SJan Kiszka
14466051720SJan Kiszka        # Dropping symbols will disable all breakpoints. So save their states
14566051720SJan Kiszka        # and restore them afterward.
14666051720SJan Kiszka        saved_states = []
14766051720SJan Kiszka        if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
14866051720SJan Kiszka            for bp in gdb.breakpoints():
14966051720SJan Kiszka                saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
15066051720SJan Kiszka
15166051720SJan Kiszka        # drop all current symbols and reload vmlinux
152dfe4529eSStephen Boyd        orig_vmlinux = 'vmlinux'
153dfe4529eSStephen Boyd        for obj in gdb.objfiles():
1543b294118SDouglas Anderson            if (obj.filename.endswith('vmlinux') or
1553b294118SDouglas Anderson                obj.filename.endswith('vmlinux.debug')):
156dfe4529eSStephen Boyd                orig_vmlinux = obj.filename
15766051720SJan Kiszka        gdb.execute("symbol-file", to_string=True)
158dfe4529eSStephen Boyd        gdb.execute("symbol-file {0}".format(orig_vmlinux))
15966051720SJan Kiszka
16082b41e3dSJan Kiszka        self.loaded_modules = []
161fffb944cSJan Kiszka        module_list = modules.module_list()
16266051720SJan Kiszka        if not module_list:
16366051720SJan Kiszka            gdb.write("no modules found\n")
16466051720SJan Kiszka        else:
16566051720SJan Kiszka            [self.load_module_symbols(module) for module in module_list]
16666051720SJan Kiszka
16766051720SJan Kiszka        for saved_state in saved_states:
16866051720SJan Kiszka            saved_state['breakpoint'].enabled = saved_state['enabled']
16966051720SJan Kiszka
17066051720SJan Kiszka    def invoke(self, arg, from_tty):
17123921540SJohannes Berg        self.module_paths = [os.path.abspath(os.path.expanduser(p))
17223921540SJohannes Berg                             for p in arg.split()]
17366051720SJan Kiszka        self.module_paths.append(os.getcwd())
17466051720SJan Kiszka
17566051720SJan Kiszka        # enforce update
17666051720SJan Kiszka        self.module_files = []
17766051720SJan Kiszka        self.module_files_updated = False
17866051720SJan Kiszka
17966051720SJan Kiszka        self.load_all_symbols()
18066051720SJan Kiszka
18182b41e3dSJan Kiszka        if hasattr(gdb, 'Breakpoint'):
1826ad18b73SThiébaud Weksteen            if self.breakpoint is not None:
18382b41e3dSJan Kiszka                self.breakpoint.delete()
18482b41e3dSJan Kiszka                self.breakpoint = None
18582b41e3dSJan Kiszka            self.breakpoint = LoadModuleBreakpoint(
18623a67619SKhalid Masum                "kernel/module/main.c:do_init_module", self)
18782b41e3dSJan Kiszka        else:
18882b41e3dSJan Kiszka            gdb.write("Note: symbol update on module loading not supported "
18982b41e3dSJan Kiszka                      "with this gdb version\n")
19082b41e3dSJan Kiszka
19166051720SJan Kiszka
19266051720SJan KiszkaLxSymbols()
193