Remove gmodule.pl and rewrite as a python in gdb_helper.py. This removes Perl dependency for the GRUB GDB script, but adds Python as a dependency. This is more desirable because Python is tightly integrated with GDB and can do things not even available to GDB native scripting language. GDB must be built with Python, however this is not a major limitation because every major distro non-end-of-life versions build GDB with Python support. And GDB has had support for Python since around 7.1-ish, which is about a decade. This re-implementation has an added feature. If there is a user defined command named "onload_<module name>", then that command will be executed after the symbols for the specified module are loaded. When debugging a module it can be desirable to set break points on code in the module. This is difficult in GRUB because, at GDB start, the module is not loaded and on EFI platforms its not known ahead of time where the module will be loaded. So allow users to create an "onload_<modname>" command which will be run when the module with name "modname" is loaded. Another addition is a new convenience function is defined $is_user_command(), which returns true if its string argument is the name of a user-defined command. A secondary benefit of these changes is that the script does not write temporary files and has better error handling capabilities. Signed-off-by: Glenn Washburn <development@efficientek.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
83 lines
2.6 KiB
Python
83 lines
2.6 KiB
Python
import os
|
|
import re
|
|
import subprocess
|
|
|
|
##### Convenience functions #####
|
|
|
|
class IsUserCommand (gdb.Function):
|
|
"""Set the second argument to true value if first argument is the name
|
|
of a user-defined command.
|
|
"""
|
|
|
|
def __init__ (self):
|
|
super (IsUserCommand, self).__init__ ("is_user_command")
|
|
|
|
def invoke (self, fmt, *args):
|
|
name = fmt.string () % tuple(a.string () for a in args)
|
|
for line in gdb.execute ("help user-defined", to_string=True).splitlines ():
|
|
line_parts = line.split(' -- ', 1)
|
|
if len (line_parts) > 1 and line_parts[0] == name:
|
|
return True
|
|
return False
|
|
|
|
is_user_command = IsUserCommand ()
|
|
|
|
##### Commands #####
|
|
|
|
class GrubLoadModuleSymbols (gdb.Command):
|
|
"""Load module symbols at correct locations.
|
|
Takes one argument which is a pointer to a grub_dl_t struct."""
|
|
|
|
def __init__ (self):
|
|
super (GrubLoadModuleSymbols, self).__init__ ("load_module",
|
|
gdb.COMMAND_USER,
|
|
gdb.COMPLETE_EXPRESSION)
|
|
|
|
def invoke (self, arg, from_tty):
|
|
self.dont_repeat ()
|
|
args = gdb.string_to_argv (arg)
|
|
self.mod = gdb.parse_and_eval (args[0])
|
|
sections = self.get_section_offsets ()
|
|
section_names = self.get_section_names ()
|
|
|
|
sym_load_cmd_parts = ["add-symbol-file",
|
|
"%s.module" % (self.mod['name'].string (),)]
|
|
for idx, addr in sections:
|
|
section_name = section_names[idx]
|
|
if section_name == ".text":
|
|
sym_load_cmd_parts.append (addr)
|
|
else:
|
|
sym_load_cmd_parts.extend (["-s", section_name, addr])
|
|
gdb.execute (' '.join (sym_load_cmd_parts))
|
|
|
|
if is_user_command.invoke (gdb.Value ("onload_%s"), self.mod['name']):
|
|
gdb.execute ("onload_%s (grub_dl_t)%s" % (self.mod['name'].string (),
|
|
self.mod.format_string (format='x')))
|
|
|
|
def get_section_offsets (self):
|
|
sections = []
|
|
segment = self.mod['segment']
|
|
while segment:
|
|
sections.append ((int (segment['section']), segment['addr'].format_string (format='x')))
|
|
segment = segment['next']
|
|
return sections
|
|
|
|
def get_section_names (self):
|
|
re_index = re.compile ("^\s+\[\s*(\d+)\] (\S*)")
|
|
names = {}
|
|
modfilename = "%s.mod" % (self.mod['name'].string (),)
|
|
|
|
if not os.path.exists (modfilename):
|
|
raise RuntimeError ("%s not found in current directory" % (modfilename,))
|
|
|
|
c = subprocess.run (["readelf", "-SW", modfilename], text=True, capture_output=True)
|
|
for line in c.stdout.splitlines ()[4:]:
|
|
m = re_index.match (line)
|
|
if not m:
|
|
continue
|
|
idx, name = m.groups ()
|
|
names[int (idx)] = name
|
|
return names
|
|
|
|
grub_load_module = GrubLoadModuleSymbols ()
|