1 # 1 # 2 # gdb helper commands and functions for Linux 2 # gdb helper commands and functions for Linux kernel debugging 3 # 3 # 4 # load kernel and module symbols 4 # load kernel and module symbols 5 # 5 # 6 # Copyright (c) Siemens AG, 2011-2013 6 # Copyright (c) Siemens AG, 2011-2013 7 # 7 # 8 # Authors: 8 # Authors: 9 # Jan Kiszka <jan.kiszka@siemens.com> 9 # Jan Kiszka <jan.kiszka@siemens.com> 10 # 10 # 11 # This work is licensed under the terms of the 11 # This work is licensed under the terms of the GNU GPL version 2. 12 # 12 # 13 13 14 import gdb 14 import gdb 15 import os 15 import os 16 import re 16 import re 17 17 18 from linux import modules, utils, constants 18 from linux import modules, utils, constants 19 19 20 20 21 if hasattr(gdb, 'Breakpoint'): 21 if hasattr(gdb, 'Breakpoint'): 22 class LoadModuleBreakpoint(gdb.Breakpoint) 22 class LoadModuleBreakpoint(gdb.Breakpoint): 23 def __init__(self, spec, gdb_command): 23 def __init__(self, spec, gdb_command): 24 super(LoadModuleBreakpoint, self). 24 super(LoadModuleBreakpoint, self).__init__(spec, internal=True) 25 self.silent = True 25 self.silent = True 26 self.gdb_command = gdb_command 26 self.gdb_command = gdb_command 27 27 28 def stop(self): 28 def stop(self): 29 module = gdb.parse_and_eval("mod") 29 module = gdb.parse_and_eval("mod") 30 module_name = module['name'].strin 30 module_name = module['name'].string() 31 cmd = self.gdb_command 31 cmd = self.gdb_command 32 32 33 # enforce update if object file is 33 # enforce update if object file is not found 34 cmd.module_files_updated = False 34 cmd.module_files_updated = False 35 35 36 # Disable pagination while reporti 36 # Disable pagination while reporting symbol (re-)loading. 37 # The console input is blocked in 37 # The console input is blocked in this context so that we would 38 # get stuck waiting for the user t 38 # get stuck waiting for the user to acknowledge paged output. 39 show_pagination = gdb.execute("sho 39 show_pagination = gdb.execute("show pagination", to_string=True) 40 pagination = show_pagination.endsw 40 pagination = show_pagination.endswith("on.\n") 41 gdb.execute("set pagination off") 41 gdb.execute("set pagination off") 42 42 43 if module_name in cmd.loaded_modul 43 if module_name in cmd.loaded_modules: 44 gdb.write("refreshing all symb 44 gdb.write("refreshing all symbols to reload module " 45 "'{0}'\n".format(mod 45 "'{0}'\n".format(module_name)) 46 cmd.load_all_symbols() 46 cmd.load_all_symbols() 47 else: 47 else: 48 cmd.load_module_symbols(module 48 cmd.load_module_symbols(module) 49 49 50 # restore pagination state 50 # restore pagination state 51 gdb.execute("set pagination %s" % 51 gdb.execute("set pagination %s" % ("on" if pagination else "off")) 52 52 53 return False 53 return False 54 54 55 55 56 class LxSymbols(gdb.Command): 56 class LxSymbols(gdb.Command): 57 """(Re-)load symbols of Linux kernel and c 57 """(Re-)load symbols of Linux kernel and currently loaded modules. 58 58 59 The kernel (vmlinux) is taken from the current 59 The kernel (vmlinux) is taken from the current working directly. Modules (.ko) 60 are scanned recursively, starting in the same 60 are scanned recursively, starting in the same directory. Optionally, the module 61 search path can be extended by a space separat 61 search path can be extended by a space separated list of paths passed to the 62 lx-symbols command.""" 62 lx-symbols command.""" 63 63 64 module_paths = [] 64 module_paths = [] 65 module_files = [] 65 module_files = [] 66 module_files_updated = False 66 module_files_updated = False 67 loaded_modules = [] 67 loaded_modules = [] 68 breakpoint = None 68 breakpoint = None 69 69 70 def __init__(self): 70 def __init__(self): 71 super(LxSymbols, self).__init__("lx-sy 71 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES, 72 gdb.CO 72 gdb.COMPLETE_FILENAME) 73 73 74 def _update_module_files(self): 74 def _update_module_files(self): 75 self.module_files = [] 75 self.module_files = [] 76 for path in self.module_paths: 76 for path in self.module_paths: 77 gdb.write("scanning for modules in 77 gdb.write("scanning for modules in {0}\n".format(path)) 78 for root, dirs, files in os.walk(p 78 for root, dirs, files in os.walk(path): 79 for name in files: 79 for name in files: 80 if name.endswith(".ko") or 80 if name.endswith(".ko") or name.endswith(".ko.debug"): 81 self.module_files.appe 81 self.module_files.append(root + "/" + name) 82 self.module_files_updated = True 82 self.module_files_updated = True 83 83 84 def _get_module_file(self, module_name): 84 def _get_module_file(self, module_name): 85 module_pattern = r".*/{0}\.ko(?:.debug 85 module_pattern = r".*/{0}\.ko(?:.debug)?$".format( 86 module_name.replace("_", r"[_\-]") 86 module_name.replace("_", r"[_\-]")) 87 for name in self.module_files: 87 for name in self.module_files: 88 if re.match(module_pattern, name) 88 if re.match(module_pattern, name) and os.path.exists(name): 89 return name 89 return name 90 return None 90 return None 91 91 92 def _section_arguments(self, module, modul 92 def _section_arguments(self, module, module_addr): 93 try: 93 try: 94 sect_attrs = module['sect_attrs']. 94 sect_attrs = module['sect_attrs'].dereference() 95 except gdb.error: 95 except gdb.error: 96 return str(module_addr) 96 return str(module_addr) 97 97 98 attrs = sect_attrs['attrs'] 98 attrs = sect_attrs['attrs'] 99 section_name_to_address = { 99 section_name_to_address = { 100 attrs[n]['battr']['attr']['name']. 100 attrs[n]['battr']['attr']['name'].string(): attrs[n]['address'] 101 for n in range(int(sect_attrs['nse 101 for n in range(int(sect_attrs['nsections']))} 102 102 103 textaddr = section_name_to_address.get 103 textaddr = section_name_to_address.get(".text", module_addr) 104 args = [] 104 args = [] 105 for section_name in [".data", ".data.. 105 for section_name in [".data", ".data..read_mostly", ".rodata", ".bss", 106 ".text.hot", ".te 106 ".text.hot", ".text.unlikely"]: 107 address = section_name_to_address. 107 address = section_name_to_address.get(section_name) 108 if address: 108 if address: 109 args.append(" -s {name} {addr} 109 args.append(" -s {name} {addr}".format( 110 name=section_name, addr=st 110 name=section_name, addr=str(address))) 111 return "{textaddr} {sections}".format( 111 return "{textaddr} {sections}".format( 112 textaddr=textaddr, sections="".joi 112 textaddr=textaddr, sections="".join(args)) 113 113 114 def load_module_symbols(self, module): 114 def load_module_symbols(self, module): 115 module_name = module['name'].string() 115 module_name = module['name'].string() 116 module_addr = str(module['mem'][consta 116 module_addr = str(module['mem'][constants.LX_MOD_TEXT]['base']).split()[0] 117 117 118 module_file = self._get_module_file(mo 118 module_file = self._get_module_file(module_name) 119 if not module_file and not self.module 119 if not module_file and not self.module_files_updated: 120 self._update_module_files() 120 self._update_module_files() 121 module_file = self._get_module_fil 121 module_file = self._get_module_file(module_name) 122 122 123 if module_file: 123 if module_file: 124 if utils.is_target_arch('s390'): 124 if utils.is_target_arch('s390'): 125 # Module text is preceded by P 125 # Module text is preceded by PLT stubs on s390. 126 module_arch = module['arch'] 126 module_arch = module['arch'] 127 plt_offset = int(module_arch[' 127 plt_offset = int(module_arch['plt_offset']) 128 plt_size = int(module_arch['pl 128 plt_size = int(module_arch['plt_size']) 129 module_addr = hex(int(module_a 129 module_addr = hex(int(module_addr, 0) + plt_offset + plt_size) 130 gdb.write("loading @{addr}: {filen 130 gdb.write("loading @{addr}: {filename}\n".format( 131 addr=module_addr, filename=mod 131 addr=module_addr, filename=module_file)) 132 cmdline = "add-symbol-file {filena 132 cmdline = "add-symbol-file {filename} {sections}".format( 133 filename=module_file, 133 filename=module_file, 134 sections=self._section_argumen 134 sections=self._section_arguments(module, module_addr)) 135 gdb.execute(cmdline, to_string=Tru 135 gdb.execute(cmdline, to_string=True) 136 if module_name not in self.loaded_ 136 if module_name not in self.loaded_modules: 137 self.loaded_modules.append(mod 137 self.loaded_modules.append(module_name) 138 else: 138 else: 139 gdb.write("no module object found 139 gdb.write("no module object found for '{0}'\n".format(module_name)) 140 140 141 def load_all_symbols(self): 141 def load_all_symbols(self): 142 gdb.write("loading vmlinux\n") 142 gdb.write("loading vmlinux\n") 143 143 144 # Dropping symbols will disable all br 144 # Dropping symbols will disable all breakpoints. So save their states 145 # and restore them afterward. 145 # and restore them afterward. 146 saved_states = [] 146 saved_states = [] 147 if hasattr(gdb, 'breakpoints') and not 147 if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None: 148 for bp in gdb.breakpoints(): 148 for bp in gdb.breakpoints(): 149 saved_states.append({'breakpoi 149 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled}) 150 150 151 # drop all current symbols and reload 151 # drop all current symbols and reload vmlinux 152 orig_vmlinux = 'vmlinux' 152 orig_vmlinux = 'vmlinux' 153 for obj in gdb.objfiles(): 153 for obj in gdb.objfiles(): 154 if (obj.filename.endswith('vmlinux 154 if (obj.filename.endswith('vmlinux') or 155 obj.filename.endswith('vmlinux 155 obj.filename.endswith('vmlinux.debug')): 156 orig_vmlinux = obj.filename 156 orig_vmlinux = obj.filename 157 gdb.execute("symbol-file", to_string=T 157 gdb.execute("symbol-file", to_string=True) 158 gdb.execute("symbol-file {0}".format(o 158 gdb.execute("symbol-file {0}".format(orig_vmlinux)) 159 159 160 self.loaded_modules = [] 160 self.loaded_modules = [] 161 module_list = modules.module_list() 161 module_list = modules.module_list() 162 if not module_list: 162 if not module_list: 163 gdb.write("no modules found\n") 163 gdb.write("no modules found\n") 164 else: 164 else: 165 [self.load_module_symbols(module) 165 [self.load_module_symbols(module) for module in module_list] 166 166 167 for saved_state in saved_states: 167 for saved_state in saved_states: 168 saved_state['breakpoint'].enabled 168 saved_state['breakpoint'].enabled = saved_state['enabled'] 169 169 170 def invoke(self, arg, from_tty): 170 def invoke(self, arg, from_tty): 171 self.module_paths = [os.path.abspath(o 171 self.module_paths = [os.path.abspath(os.path.expanduser(p)) 172 for p in arg.spli 172 for p in arg.split()] 173 self.module_paths.append(os.getcwd()) 173 self.module_paths.append(os.getcwd()) 174 174 175 # enforce update 175 # enforce update 176 self.module_files = [] 176 self.module_files = [] 177 self.module_files_updated = False 177 self.module_files_updated = False 178 178 179 self.load_all_symbols() 179 self.load_all_symbols() 180 180 181 if hasattr(gdb, 'Breakpoint'): 181 if hasattr(gdb, 'Breakpoint'): 182 if self.breakpoint is not None: 182 if self.breakpoint is not None: 183 self.breakpoint.delete() 183 self.breakpoint.delete() 184 self.breakpoint = None 184 self.breakpoint = None 185 self.breakpoint = LoadModuleBreakp 185 self.breakpoint = LoadModuleBreakpoint( 186 "kernel/module/main.c:do_init_ 186 "kernel/module/main.c:do_init_module", self) 187 else: 187 else: 188 gdb.write("Note: symbol update on 188 gdb.write("Note: symbol update on module loading not supported " 189 "with this gdb version\n 189 "with this gdb version\n") 190 190 191 191 192 LxSymbols() 192 LxSymbols()
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.