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/main.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() 190