0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 import gdb
0015 import os
0016 import re
0017
0018 from linux import modules, utils
0019
0020
0021 if hasattr(gdb, 'Breakpoint'):
0022 class LoadModuleBreakpoint(gdb.Breakpoint):
0023 def __init__(self, spec, gdb_command):
0024 super(LoadModuleBreakpoint, self).__init__(spec, internal=True)
0025 self.silent = True
0026 self.gdb_command = gdb_command
0027
0028 def stop(self):
0029 module = gdb.parse_and_eval("mod")
0030 module_name = module['name'].string()
0031 cmd = self.gdb_command
0032
0033
0034 cmd.module_files_updated = False
0035
0036
0037
0038
0039 show_pagination = gdb.execute("show pagination", to_string=True)
0040 pagination = show_pagination.endswith("on.\n")
0041 gdb.execute("set pagination off")
0042
0043 if module_name in cmd.loaded_modules:
0044 gdb.write("refreshing all symbols to reload module "
0045 "'{0}'\n".format(module_name))
0046 cmd.load_all_symbols()
0047 else:
0048 cmd.load_module_symbols(module)
0049
0050
0051 gdb.execute("set pagination %s" % ("on" if pagination else "off"))
0052
0053 return False
0054
0055
0056 class LxSymbols(gdb.Command):
0057 """(Re-)load symbols of Linux kernel and currently loaded modules.
0058
0059 The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
0060 are scanned recursively, starting in the same directory. Optionally, the module
0061 search path can be extended by a space separated list of paths passed to the
0062 lx-symbols command."""
0063
0064 module_paths = []
0065 module_files = []
0066 module_files_updated = False
0067 loaded_modules = []
0068 breakpoint = None
0069
0070 def __init__(self):
0071 super(LxSymbols, self).__init__("lx-symbols", gdb.COMMAND_FILES,
0072 gdb.COMPLETE_FILENAME)
0073
0074 def _update_module_files(self):
0075 self.module_files = []
0076 for path in self.module_paths:
0077 gdb.write("scanning for modules in {0}\n".format(path))
0078 for root, dirs, files in os.walk(path):
0079 for name in files:
0080 if name.endswith(".ko") or name.endswith(".ko.debug"):
0081 self.module_files.append(root + "/" + name)
0082 self.module_files_updated = True
0083
0084 def _get_module_file(self, module_name):
0085 module_pattern = ".*/{0}\.ko(?:.debug)?$".format(
0086 module_name.replace("_", r"[_\-]"))
0087 for name in self.module_files:
0088 if re.match(module_pattern, name) and os.path.exists(name):
0089 return name
0090 return None
0091
0092 def _section_arguments(self, module):
0093 try:
0094 sect_attrs = module['sect_attrs'].dereference()
0095 except gdb.error:
0096 return ""
0097 attrs = sect_attrs['attrs']
0098 section_name_to_address = {
0099 attrs[n]['battr']['attr']['name'].string(): attrs[n]['address']
0100 for n in range(int(sect_attrs['nsections']))}
0101 args = []
0102 for section_name in [".data", ".data..read_mostly", ".rodata", ".bss",
0103 ".text", ".text.hot", ".text.unlikely"]:
0104 address = section_name_to_address.get(section_name)
0105 if address:
0106 args.append(" -s {name} {addr}".format(
0107 name=section_name, addr=str(address)))
0108 return "".join(args)
0109
0110 def load_module_symbols(self, module):
0111 module_name = module['name'].string()
0112 module_addr = str(module['core_layout']['base']).split()[0]
0113
0114 module_file = self._get_module_file(module_name)
0115 if not module_file and not self.module_files_updated:
0116 self._update_module_files()
0117 module_file = self._get_module_file(module_name)
0118
0119 if module_file:
0120 if utils.is_target_arch('s390'):
0121
0122 module_arch = module['arch']
0123 plt_offset = int(module_arch['plt_offset'])
0124 plt_size = int(module_arch['plt_size'])
0125 module_addr = hex(int(module_addr, 0) + plt_offset + plt_size)
0126 gdb.write("loading @{addr}: {filename}\n".format(
0127 addr=module_addr, filename=module_file))
0128 cmdline = "add-symbol-file {filename} {addr}{sections}".format(
0129 filename=module_file,
0130 addr=module_addr,
0131 sections=self._section_arguments(module))
0132 gdb.execute(cmdline, to_string=True)
0133 if module_name not in self.loaded_modules:
0134 self.loaded_modules.append(module_name)
0135 else:
0136 gdb.write("no module object found for '{0}'\n".format(module_name))
0137
0138 def load_all_symbols(self):
0139 gdb.write("loading vmlinux\n")
0140
0141
0142
0143 saved_states = []
0144 if hasattr(gdb, 'breakpoints') and not gdb.breakpoints() is None:
0145 for bp in gdb.breakpoints():
0146 saved_states.append({'breakpoint': bp, 'enabled': bp.enabled})
0147
0148
0149 orig_vmlinux = 'vmlinux'
0150 for obj in gdb.objfiles():
0151 if (obj.filename.endswith('vmlinux') or
0152 obj.filename.endswith('vmlinux.debug')):
0153 orig_vmlinux = obj.filename
0154 gdb.execute("symbol-file", to_string=True)
0155 gdb.execute("symbol-file {0}".format(orig_vmlinux))
0156
0157 self.loaded_modules = []
0158 module_list = modules.module_list()
0159 if not module_list:
0160 gdb.write("no modules found\n")
0161 else:
0162 [self.load_module_symbols(module) for module in module_list]
0163
0164 for saved_state in saved_states:
0165 saved_state['breakpoint'].enabled = saved_state['enabled']
0166
0167 def invoke(self, arg, from_tty):
0168 self.module_paths = [os.path.abspath(os.path.expanduser(p))
0169 for p in arg.split()]
0170 self.module_paths.append(os.getcwd())
0171
0172
0173 self.module_files = []
0174 self.module_files_updated = False
0175
0176 self.load_all_symbols()
0177
0178 if hasattr(gdb, 'Breakpoint'):
0179 if self.breakpoint is not None:
0180 self.breakpoint.delete()
0181 self.breakpoint = None
0182 self.breakpoint = LoadModuleBreakpoint(
0183 "kernel/module/main.c:do_init_module", self)
0184 else:
0185 gdb.write("Note: symbol update on module loading not supported "
0186 "with this gdb version\n")
0187
0188
0189 LxSymbols()