cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

symbols.py (7110B)


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