2 # gdb helper commands and functions for Linux kernel debugging
4 # load kernel and module symbols
6 # Copyright (c) Siemens AG, 2011-2013
9 # Jan Kiszka <jan.kiszka@siemens.com>
11 # This work is licensed under the terms of the GNU GPL version 2.
18 from linux
import modules
21 if hasattr(gdb
, 'Breakpoint'):
22 class LoadModuleBreakpoint(gdb
.Breakpoint
):
23 def __init__(self
, spec
, gdb_command
):
24 super(LoadModuleBreakpoint
, self
).__init
__(spec
, internal
=True)
26 self
.gdb_command
= gdb_command
29 module
= gdb
.parse_and_eval("mod")
30 module_name
= module
['name'].string()
31 cmd
= self
.gdb_command
33 # enforce update if object file is not found
34 cmd
.module_files_updated
= False
36 # Disable pagination while reporting symbol (re-)loading.
37 # The console input is blocked in this context so that we would
38 # get stuck waiting for the user to acknowledge paged output.
39 show_pagination
= gdb
.execute("show pagination", to_string
=True)
40 pagination
= show_pagination
.endswith("on.\n")
41 gdb
.execute("set pagination off")
43 if module_name
in cmd
.loaded_modules
:
44 gdb
.write("refreshing all symbols to reload module "
45 "'{0}'\n".format(module_name
))
46 cmd
.load_all_symbols()
48 cmd
.load_module_symbols(module
)
50 # restore pagination state
51 gdb
.execute("set pagination %s" % ("on" if pagination
else "off"))
56 class LxSymbols(gdb
.Command
):
57 """(Re-)load symbols of Linux kernel and currently loaded modules.
59 The kernel (vmlinux) is taken from the current working directly. Modules (.ko)
60 are scanned recursively, starting in the same directory. Optionally, the module
61 search path can be extended by a space separated list of paths passed to the
62 lx-symbols command."""
66 module_files_updated
= False
71 super(LxSymbols
, self
).__init
__("lx-symbols", gdb
.COMMAND_FILES
,
72 gdb
.COMPLETE_FILENAME
)
74 def _update_module_files(self
):
75 self
.module_files
= []
76 for path
in self
.module_paths
:
77 gdb
.write("scanning for modules in {0}\n".format(path
))
78 for root
, dirs
, files
in os
.walk(path
):
80 if name
.endswith(".ko"):
81 self
.module_files
.append(root
+ "/" + name
)
82 self
.module_files_updated
= True
84 def _get_module_file(self
, module_name
):
85 module_pattern
= ".*/{0}\.ko$".format(
86 module_name
.replace("_", r
"[_\-]"))
87 for name
in self
.module_files
:
88 if re
.match(module_pattern
, name
) and os
.path
.exists(name
):
92 def _section_arguments(self
, module
):
94 sect_attrs
= module
['sect_attrs'].dereference()
97 attrs
= sect_attrs
['attrs']
98 section_name_to_address
= {
99 attrs
[n
]['name'].string(): attrs
[n
]['address']
100 for n
in range(int(sect_attrs
['nsections']))}
102 for section_name
in [".data", ".data..read_mostly", ".rodata", ".bss"]:
103 address
= section_name_to_address
.get(section_name
)
105 args
.append(" -s {name} {addr}".format(
106 name
=section_name
, addr
=str(address
)))
109 def load_module_symbols(self
, module
):
110 module_name
= module
['name'].string()
111 module_addr
= str(module
['core_layout']['base']).split()[0]
113 module_file
= self
._get
_module
_file
(module_name
)
114 if not module_file
and not self
.module_files_updated
:
115 self
._update
_module
_files
()
116 module_file
= self
._get
_module
_file
(module_name
)
119 gdb
.write("loading @{addr}: {filename}\n".format(
120 addr
=module_addr
, filename
=module_file
))
121 cmdline
= "add-symbol-file {filename} {addr}{sections}".format(
122 filename
=module_file
,
124 sections
=self
._section
_arguments
(module
))
125 gdb
.execute(cmdline
, to_string
=True)
126 if module_name
not in self
.loaded_modules
:
127 self
.loaded_modules
.append(module_name
)
129 gdb
.write("no module object found for '{0}'\n".format(module_name
))
131 def load_all_symbols(self
):
132 gdb
.write("loading vmlinux\n")
134 # Dropping symbols will disable all breakpoints. So save their states
135 # and restore them afterward.
137 if hasattr(gdb
, 'breakpoints') and not gdb
.breakpoints() is None:
138 for bp
in gdb
.breakpoints():
139 saved_states
.append({'breakpoint': bp
, 'enabled': bp
.enabled
})
141 # drop all current symbols and reload vmlinux
142 gdb
.execute("symbol-file", to_string
=True)
143 gdb
.execute("symbol-file vmlinux")
145 self
.loaded_modules
= []
146 module_list
= modules
.module_list()
148 gdb
.write("no modules found\n")
150 [self
.load_module_symbols(module
) for module
in module_list
]
152 for saved_state
in saved_states
:
153 saved_state
['breakpoint'].enabled
= saved_state
['enabled']
155 def invoke(self
, arg
, from_tty
):
156 self
.module_paths
= [os
.path
.expanduser(p
) for p
in arg
.split()]
157 self
.module_paths
.append(os
.getcwd())
160 self
.module_files
= []
161 self
.module_files_updated
= False
163 self
.load_all_symbols()
165 if hasattr(gdb
, 'Breakpoint'):
166 if self
.breakpoint
is not None:
167 self
.breakpoint
.delete()
168 self
.breakpoint
= None
169 self
.breakpoint
= LoadModuleBreakpoint(
170 "kernel/module.c:do_init_module", self
)
172 gdb
.write("Note: symbol update on module loading not supported "
173 "with this gdb version\n")