2 # gdb helper commands and functions for Linux kernel debugging
4 # Kernel proc information reader
6 # Copyright (c) 2016 Linaro Ltd
9 # Kieran Bingham <kieran.bingham@linaro.org>
11 # This work is licensed under the terms of the GNU GPL version 2.
15 from linux
import constants
16 from linux
import utils
17 from linux
import tasks
18 from linux
import lists
22 class LxCmdLine(gdb
.Command
):
23 """ Report the Linux Commandline used in the current kernel.
24 Equivalent to cat /proc/cmdline on a running target"""
27 super(LxCmdLine
, self
).__init
__("lx-cmdline", gdb
.COMMAND_DATA
)
29 def invoke(self
, arg
, from_tty
):
30 gdb
.write(gdb
.parse_and_eval("saved_command_line").string() + "\n")
35 class LxVersion(gdb
.Command
):
36 """ Report the Linux Version of the current kernel.
37 Equivalent to cat /proc/version on a running target"""
40 super(LxVersion
, self
).__init
__("lx-version", gdb
.COMMAND_DATA
)
42 def invoke(self
, arg
, from_tty
):
43 # linux_banner should contain a newline
44 gdb
.write(gdb
.parse_and_eval("linux_banner").string())
49 # Resource Structure Printers
53 def get_resources(resource
, depth
):
57 child
= resource
['child']
59 for res
, deep
in get_resources(child
, depth
+ 1):
62 resource
= resource
['sibling']
65 def show_lx_resources(resource_str
):
66 resource
= gdb
.parse_and_eval(resource_str
)
67 width
= 4 if resource
['end'] < 0x10000 else 8
68 # Iterate straight to the first child
69 for res
, depth
in get_resources(resource
['child'], 0):
70 start
= int(res
['start'])
72 gdb
.write(" " * depth
* 2 +
73 "{0:0{1}x}-".format(start
, width
) +
74 "{0:0{1}x} : ".format(end
, width
) +
75 res
['name'].string() + "\n")
78 class LxIOMem(gdb
.Command
):
79 """Identify the IO memory resource locations defined by the kernel
81 Equivalent to cat /proc/iomem on a running target"""
84 super(LxIOMem
, self
).__init
__("lx-iomem", gdb
.COMMAND_DATA
)
86 def invoke(self
, arg
, from_tty
):
87 return show_lx_resources("iomem_resource")
92 class LxIOPorts(gdb
.Command
):
93 """Identify the IO port resource locations defined by the kernel
95 Equivalent to cat /proc/ioports on a running target"""
98 super(LxIOPorts
, self
).__init
__("lx-ioports", gdb
.COMMAND_DATA
)
100 def invoke(self
, arg
, from_tty
):
101 return show_lx_resources("ioport_resource")
106 # Mount namespace viewer
109 def info_opts(lst
, opt
):
111 for key
, string
in lst
.items():
117 FS_INFO
= {constants
.LX_MS_SYNCHRONOUS
: ",sync",
118 constants
.LX_MS_MANDLOCK
: ",mand",
119 constants
.LX_MS_DIRSYNC
: ",dirsync",
120 constants
.LX_MS_NOATIME
: ",noatime",
121 constants
.LX_MS_NODIRATIME
: ",nodiratime"}
123 MNT_INFO
= {constants
.LX_MNT_NOSUID
: ",nosuid",
124 constants
.LX_MNT_NODEV
: ",nodev",
125 constants
.LX_MNT_NOEXEC
: ",noexec",
126 constants
.LX_MNT_NOATIME
: ",noatime",
127 constants
.LX_MNT_NODIRATIME
: ",nodiratime",
128 constants
.LX_MNT_RELATIME
: ",relatime"}
130 mount_type
= utils
.CachedType("struct mount")
131 mount_ptr_type
= mount_type
.get_type().pointer()
134 class LxMounts(gdb
.Command
):
135 """Report the VFS mounts of the current process namespace.
137 Equivalent to cat /proc/mounts on a running target
138 An integer value can be supplied to display the mount
139 values of that process namespace"""
142 super(LxMounts
, self
).__init
__("lx-mounts", gdb
.COMMAND_DATA
)
144 # Equivalent to proc_namespace.c:show_vfsmnt
145 # However, that has the ability to call into s_op functions
146 # whereas we cannot and must make do with the information we can obtain.
147 def invoke(self
, arg
, from_tty
):
148 argv
= gdb
.string_to_argv(arg
)
153 raise gdb
.GdbError("Provide a PID as integer value")
157 task
= tasks
.get_task_by_pid(pid
)
159 raise gdb
.GdbError("Couldn't find a process with PID {}"
162 namespace
= task
['nsproxy']['mnt_ns']
164 raise gdb
.GdbError("No namespace for current process")
166 for vfs
in lists
.list_for_each_entry(namespace
['list'],
167 mount_ptr_type
, "mnt_list"):
168 devname
= vfs
['mnt_devname'].string()
169 devname
= devname
if devname
else "none"
174 mntpoint
= parent
['mnt_mountpoint']
175 pathname
= utils
.dentry_name(mntpoint
) + pathname
176 if (parent
== parent
['mnt_parent']):
178 parent
= parent
['mnt_parent']
183 superblock
= vfs
['mnt']['mnt_sb']
184 fstype
= superblock
['s_type']['name'].string()
185 s_flags
= int(superblock
['s_flags'])
186 m_flags
= int(vfs
['mnt']['mnt_flags'])
187 rd
= "ro" if (s_flags
& constants
.LX_MS_RDONLY
) else "rw"
190 "{} {} {} {}{}{} 0 0\n"
195 info_opts(FS_INFO
, s_flags
),
196 info_opts(MNT_INFO
, m_flags
)))
201 class LxFdtDump(gdb
.Command
):
202 """Output Flattened Device Tree header and dump FDT blob to the filename
203 specified as the command argument. Equivalent to
204 'cat /proc/fdt > fdtdump.dtb' on a running target"""
207 super(LxFdtDump
, self
).__init
__("lx-fdtdump", gdb
.COMMAND_DATA
,
208 gdb
.COMPLETE_FILENAME
)
210 def fdthdr_to_cpu(self
, fdt_header
):
212 fdt_header_be
= ">IIIIIII"
213 fdt_header_le
= "<IIIIIII"
215 if utils
.get_target_endianness() == 1:
216 output_fmt
= fdt_header_le
218 output_fmt
= fdt_header_be
220 return unpack(output_fmt
, pack(fdt_header_be
,
222 fdt_header
['totalsize'],
223 fdt_header
['off_dt_struct'],
224 fdt_header
['off_dt_strings'],
225 fdt_header
['off_mem_rsvmap'],
226 fdt_header
['version'],
227 fdt_header
['last_comp_version']))
229 def invoke(self
, arg
, from_tty
):
231 if not constants
.LX_CONFIG_OF
:
232 raise gdb
.GdbError("Kernel not compiled with CONFIG_OF\n")
235 filename
= "fdtdump.dtb"
239 py_fdt_header_ptr
= gdb
.parse_and_eval(
240 "(const struct fdt_header *) initial_boot_params")
241 py_fdt_header
= py_fdt_header_ptr
.dereference()
243 fdt_header
= self
.fdthdr_to_cpu(py_fdt_header
)
245 if fdt_header
[0] != constants
.LX_OF_DT_HEADER
:
246 raise gdb
.GdbError("No flattened device tree magic found\n")
248 gdb
.write("fdt_magic: 0x{:02X}\n".format(fdt_header
[0]))
249 gdb
.write("fdt_totalsize: 0x{:02X}\n".format(fdt_header
[1]))
250 gdb
.write("off_dt_struct: 0x{:02X}\n".format(fdt_header
[2]))
251 gdb
.write("off_dt_strings: 0x{:02X}\n".format(fdt_header
[3]))
252 gdb
.write("off_mem_rsvmap: 0x{:02X}\n".format(fdt_header
[4]))
253 gdb
.write("version: {}\n".format(fdt_header
[5]))
254 gdb
.write("last_comp_version: {}\n".format(fdt_header
[6]))
256 inf
= gdb
.inferiors()[0]
257 fdt_buf
= utils
.read_memoryview(inf
, py_fdt_header_ptr
,
258 fdt_header
[1]).tobytes()
261 f
= open(filename
, 'wb')
263 raise gdb
.GdbError("Could not open file to dump fdt")
268 gdb
.write("Dumped fdt blob to " + filename
+ "\n")