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