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