Merge tag 'amd-drm-fixes-6.7-2023-12-13' of https://gitlab.freedesktop.org/agd5f...
[linux-2.6-microblaze.git] / scripts / gdb / linux / proc.py
1 # SPDX-License-Identifier: GPL-2.0
2 #
3 # gdb helper commands and functions for Linux kernel debugging
4 #
5 #  Kernel proc information reader
6 #
7 # Copyright (c) 2016 Linaro Ltd
8 #
9 # Authors:
10 #  Kieran Bingham <kieran.bingham@linaro.org>
11 #
12 # This work is licensed under the terms of the GNU GPL version 2.
13 #
14
15 import gdb
16 from linux import constants
17 from linux import utils
18 from linux import tasks
19 from linux import lists
20 from linux import vfs
21 from struct import *
22
23
24 class LxCmdLine(gdb.Command):
25     """ Report the Linux Commandline used in the current kernel.
26         Equivalent to cat /proc/cmdline on a running target"""
27
28     def __init__(self):
29         super(LxCmdLine, self).__init__("lx-cmdline", gdb.COMMAND_DATA)
30
31     def invoke(self, arg, from_tty):
32         gdb.write(gdb.parse_and_eval("saved_command_line").string() + "\n")
33
34
35 LxCmdLine()
36
37
38 class LxVersion(gdb.Command):
39     """ Report the Linux Version of the current kernel.
40         Equivalent to cat /proc/version on a running target"""
41
42     def __init__(self):
43         super(LxVersion, self).__init__("lx-version", gdb.COMMAND_DATA)
44
45     def invoke(self, arg, from_tty):
46         # linux_banner should contain a newline
47         gdb.write(gdb.parse_and_eval("(char *)linux_banner").string())
48
49
50 LxVersion()
51
52
53 # Resource Structure Printers
54 #  /proc/iomem
55 #  /proc/ioports
56
57 def get_resources(resource, depth):
58     while resource:
59         yield resource, depth
60
61         child = resource['child']
62         if child:
63             for res, deep in get_resources(child, depth + 1):
64                 yield res, deep
65
66         resource = resource['sibling']
67
68
69 def show_lx_resources(resource_str):
70         resource = gdb.parse_and_eval(resource_str)
71         width = 4 if resource['end'] < 0x10000 else 8
72         # Iterate straight to the first child
73         for res, depth in get_resources(resource['child'], 0):
74             start = int(res['start'])
75             end = int(res['end'])
76             gdb.write(" " * depth * 2 +
77                       "{0:0{1}x}-".format(start, width) +
78                       "{0:0{1}x} : ".format(end, width) +
79                       res['name'].string() + "\n")
80
81
82 class LxIOMem(gdb.Command):
83     """Identify the IO memory resource locations defined by the kernel
84
85 Equivalent to cat /proc/iomem on a running target"""
86
87     def __init__(self):
88         super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA)
89
90     def invoke(self, arg, from_tty):
91         return show_lx_resources("iomem_resource")
92
93
94 LxIOMem()
95
96
97 class LxIOPorts(gdb.Command):
98     """Identify the IO port resource locations defined by the kernel
99
100 Equivalent to cat /proc/ioports on a running target"""
101
102     def __init__(self):
103         super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA)
104
105     def invoke(self, arg, from_tty):
106         return show_lx_resources("ioport_resource")
107
108
109 LxIOPorts()
110
111
112 # Mount namespace viewer
113 #  /proc/mounts
114
115 def info_opts(lst, opt):
116     opts = ""
117     for key, string in lst.items():
118         if opt & key:
119             opts += string
120     return opts
121
122
123 FS_INFO = {constants.LX_SB_SYNCHRONOUS: ",sync",
124            constants.LX_SB_MANDLOCK: ",mand",
125            constants.LX_SB_DIRSYNC: ",dirsync",
126            constants.LX_SB_NOATIME: ",noatime",
127            constants.LX_SB_NODIRATIME: ",nodiratime"}
128
129 MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid",
130             constants.LX_MNT_NODEV: ",nodev",
131             constants.LX_MNT_NOEXEC: ",noexec",
132             constants.LX_MNT_NOATIME: ",noatime",
133             constants.LX_MNT_NODIRATIME: ",nodiratime",
134             constants.LX_MNT_RELATIME: ",relatime"}
135
136 mount_type = utils.CachedType("struct mount")
137 mount_ptr_type = mount_type.get_type().pointer()
138
139
140 class LxMounts(gdb.Command):
141     """Report the VFS mounts of the current process namespace.
142
143 Equivalent to cat /proc/mounts on a running target
144 An integer value can be supplied to display the mount
145 values of that process namespace"""
146
147     def __init__(self):
148         super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA)
149
150     # Equivalent to proc_namespace.c:show_vfsmnt
151     # However, that has the ability to call into s_op functions
152     # whereas we cannot and must make do with the information we can obtain.
153     def invoke(self, arg, from_tty):
154         argv = gdb.string_to_argv(arg)
155         if len(argv) >= 1:
156             try:
157                 pid = int(argv[0])
158             except gdb.error:
159                 raise gdb.GdbError("Provide a PID as integer value")
160         else:
161             pid = 1
162
163         task = tasks.get_task_by_pid(pid)
164         if not task:
165             raise gdb.GdbError("Couldn't find a process with PID {}"
166                                .format(pid))
167
168         namespace = task['nsproxy']['mnt_ns']
169         if not namespace:
170             raise gdb.GdbError("No namespace for current process")
171
172         gdb.write("{:^18} {:^15} {:>9} {} {} options\n".format(
173                   "mount", "super_block", "devname", "pathname", "fstype"))
174
175         for mnt in lists.list_for_each_entry(namespace['list'],
176                                              mount_ptr_type, "mnt_list"):
177             devname = mnt['mnt_devname'].string()
178             devname = devname if devname else "none"
179
180             pathname = ""
181             parent = mnt
182             while True:
183                 mntpoint = parent['mnt_mountpoint']
184                 pathname = vfs.dentry_name(mntpoint) + pathname
185                 if (parent == parent['mnt_parent']):
186                     break
187                 parent = parent['mnt_parent']
188
189             if (pathname == ""):
190                 pathname = "/"
191
192             superblock = mnt['mnt']['mnt_sb']
193             fstype = superblock['s_type']['name'].string()
194             s_flags = int(superblock['s_flags'])
195             m_flags = int(mnt['mnt']['mnt_flags'])
196             rd = "ro" if (s_flags & constants.LX_SB_RDONLY) else "rw"
197
198             gdb.write("{} {} {} {} {} {}{}{} 0 0\n".format(
199                       mnt.format_string(), superblock.format_string(), devname,
200                       pathname, fstype, rd, info_opts(FS_INFO, s_flags),
201                       info_opts(MNT_INFO, m_flags)))
202
203
204 LxMounts()
205
206
207 class LxFdtDump(gdb.Command):
208     """Output Flattened Device Tree header and dump FDT blob to the filename
209        specified as the command argument. Equivalent to
210        'cat /proc/fdt > fdtdump.dtb' on a running target"""
211
212     def __init__(self):
213         super(LxFdtDump, self).__init__("lx-fdtdump", gdb.COMMAND_DATA,
214                                         gdb.COMPLETE_FILENAME)
215
216     def fdthdr_to_cpu(self, fdt_header):
217
218         fdt_header_be = ">IIIIIII"
219         fdt_header_le = "<IIIIIII"
220
221         if utils.get_target_endianness() == 1:
222             output_fmt = fdt_header_le
223         else:
224             output_fmt = fdt_header_be
225
226         return unpack(output_fmt, pack(fdt_header_be,
227                                        fdt_header['magic'],
228                                        fdt_header['totalsize'],
229                                        fdt_header['off_dt_struct'],
230                                        fdt_header['off_dt_strings'],
231                                        fdt_header['off_mem_rsvmap'],
232                                        fdt_header['version'],
233                                        fdt_header['last_comp_version']))
234
235     def invoke(self, arg, from_tty):
236
237         if not constants.LX_CONFIG_OF:
238             raise gdb.GdbError("Kernel not compiled with CONFIG_OF\n")
239
240         if len(arg) == 0:
241             filename = "fdtdump.dtb"
242         else:
243             filename = arg
244
245         py_fdt_header_ptr = gdb.parse_and_eval(
246             "(const struct fdt_header *) initial_boot_params")
247         py_fdt_header = py_fdt_header_ptr.dereference()
248
249         fdt_header = self.fdthdr_to_cpu(py_fdt_header)
250
251         if fdt_header[0] != constants.LX_OF_DT_HEADER:
252             raise gdb.GdbError("No flattened device tree magic found\n")
253
254         gdb.write("fdt_magic:         0x{:02X}\n".format(fdt_header[0]))
255         gdb.write("fdt_totalsize:     0x{:02X}\n".format(fdt_header[1]))
256         gdb.write("off_dt_struct:     0x{:02X}\n".format(fdt_header[2]))
257         gdb.write("off_dt_strings:    0x{:02X}\n".format(fdt_header[3]))
258         gdb.write("off_mem_rsvmap:    0x{:02X}\n".format(fdt_header[4]))
259         gdb.write("version:           {}\n".format(fdt_header[5]))
260         gdb.write("last_comp_version: {}\n".format(fdt_header[6]))
261
262         inf = gdb.inferiors()[0]
263         fdt_buf = utils.read_memoryview(inf, py_fdt_header_ptr,
264                                         fdt_header[1]).tobytes()
265
266         try:
267             f = open(filename, 'wb')
268         except gdb.error:
269             raise gdb.GdbError("Could not open file to dump fdt")
270
271         f.write(fdt_buf)
272         f.close()
273
274         gdb.write("Dumped fdt blob to " + filename + "\n")
275
276
277 LxFdtDump()