Linux 4.16-rc3
[cris-mirror.git] / scripts / gdb / linux / proc.py
blob086d27223c0cf3451105fad63fd5cb46e4f3bc7d
2 # gdb helper commands and functions for Linux kernel debugging
4 # Kernel proc information reader
6 # Copyright (c) 2016 Linaro Ltd
8 # Authors:
9 # Kieran Bingham <kieran.bingham@linaro.org>
11 # This work is licensed under the terms of the GNU GPL version 2.
14 import gdb
15 from linux import constants
16 from linux import utils
17 from linux import tasks
18 from linux import lists
19 from struct import *
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"""
26 def __init__(self):
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")
32 LxCmdLine()
35 class LxVersion(gdb.Command):
36 """ Report the Linux Version of the current kernel.
37 Equivalent to cat /proc/version on a running target"""
39 def __init__(self):
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())
46 LxVersion()
49 # Resource Structure Printers
50 # /proc/iomem
51 # /proc/ioports
53 def get_resources(resource, depth):
54 while resource:
55 yield resource, depth
57 child = resource['child']
58 if child:
59 for res, deep in get_resources(child, depth + 1):
60 yield res, deep
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'])
71 end = int(res['end'])
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"""
83 def __init__(self):
84 super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA)
86 def invoke(self, arg, from_tty):
87 return show_lx_resources("iomem_resource")
89 LxIOMem()
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"""
97 def __init__(self):
98 super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA)
100 def invoke(self, arg, from_tty):
101 return show_lx_resources("ioport_resource")
103 LxIOPorts()
106 # Mount namespace viewer
107 # /proc/mounts
109 def info_opts(lst, opt):
110 opts = ""
111 for key, string in lst.items():
112 if opt & key:
113 opts += string
114 return opts
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"""
141 def __init__(self):
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)
149 if len(argv) >= 1:
150 try:
151 pid = int(argv[0])
152 except:
153 raise gdb.GdbError("Provide a PID as integer value")
154 else:
155 pid = 1
157 task = tasks.get_task_by_pid(pid)
158 if not task:
159 raise gdb.GdbError("Couldn't find a process with PID {}"
160 .format(pid))
162 namespace = task['nsproxy']['mnt_ns']
163 if not namespace:
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"
171 pathname = ""
172 parent = vfs
173 while True:
174 mntpoint = parent['mnt_mountpoint']
175 pathname = utils.dentry_name(mntpoint) + pathname
176 if (parent == parent['mnt_parent']):
177 break
178 parent = parent['mnt_parent']
180 if (pathname == ""):
181 pathname = "/"
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"
189 gdb.write(
190 "{} {} {} {}{}{} 0 0\n"
191 .format(devname,
192 pathname,
193 fstype,
195 info_opts(FS_INFO, s_flags),
196 info_opts(MNT_INFO, m_flags)))
198 LxMounts()
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"""
206 def __init__(self):
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
217 else:
218 output_fmt = fdt_header_be
220 return unpack(output_fmt, pack(fdt_header_be,
221 fdt_header['magic'],
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")
234 if len(arg) == 0:
235 filename = "fdtdump.dtb"
236 else:
237 filename = arg
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()
260 try:
261 f = open(filename, 'wb')
262 except:
263 raise gdb.GdbError("Could not open file to dump fdt")
265 f.write(fdt_buf)
266 f.close()
268 gdb.write("Dumped fdt blob to " + filename + "\n")
270 LxFdtDump()