]> Git Repo - J-linux.git/blob - scripts/gdb/linux/proc.py
Merge branch 'for-6.13/wacom' into for-linus
[J-linux.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 <[email protected]>
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 linux import rbtree
22 from struct import *
23
24
25 class LxCmdLine(gdb.Command):
26     """ Report the Linux Commandline used in the current kernel.
27         Equivalent to cat /proc/cmdline on a running target"""
28
29     def __init__(self):
30         super(LxCmdLine, self).__init__("lx-cmdline", gdb.COMMAND_DATA)
31
32     def invoke(self, arg, from_tty):
33         gdb.write(gdb.parse_and_eval("saved_command_line").string() + "\n")
34
35
36 LxCmdLine()
37
38
39 class LxVersion(gdb.Command):
40     """ Report the Linux Version of the current kernel.
41         Equivalent to cat /proc/version on a running target"""
42
43     def __init__(self):
44         super(LxVersion, self).__init__("lx-version", gdb.COMMAND_DATA)
45
46     def invoke(self, arg, from_tty):
47         # linux_banner should contain a newline
48         gdb.write(gdb.parse_and_eval("(char *)linux_banner").string())
49
50
51 LxVersion()
52
53
54 # Resource Structure Printers
55 #  /proc/iomem
56 #  /proc/ioports
57
58 def get_resources(resource, depth):
59     while resource:
60         yield resource, depth
61
62         child = resource['child']
63         if child:
64             for res, deep in get_resources(child, depth + 1):
65                 yield res, deep
66
67         resource = resource['sibling']
68
69
70 def show_lx_resources(resource_str):
71         resource = gdb.parse_and_eval(resource_str)
72         width = 4 if resource['end'] < 0x10000 else 8
73         # Iterate straight to the first child
74         for res, depth in get_resources(resource['child'], 0):
75             start = int(res['start'])
76             end = int(res['end'])
77             gdb.write(" " * depth * 2 +
78                       "{0:0{1}x}-".format(start, width) +
79                       "{0:0{1}x} : ".format(end, width) +
80                       res['name'].string() + "\n")
81
82
83 class LxIOMem(gdb.Command):
84     """Identify the IO memory resource locations defined by the kernel
85
86 Equivalent to cat /proc/iomem on a running target"""
87
88     def __init__(self):
89         super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA)
90
91     def invoke(self, arg, from_tty):
92         return show_lx_resources("iomem_resource")
93
94
95 LxIOMem()
96
97
98 class LxIOPorts(gdb.Command):
99     """Identify the IO port resource locations defined by the kernel
100
101 Equivalent to cat /proc/ioports on a running target"""
102
103     def __init__(self):
104         super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA)
105
106     def invoke(self, arg, from_tty):
107         return show_lx_resources("ioport_resource")
108
109
110 LxIOPorts()
111
112
113 # Mount namespace viewer
114 #  /proc/mounts
115
116 def info_opts(lst, opt):
117     opts = ""
118     for key, string in lst.items():
119         if opt & key:
120             opts += string
121     return opts
122
123
124 FS_INFO = {constants.LX_SB_SYNCHRONOUS: ",sync",
125            constants.LX_SB_MANDLOCK: ",mand",
126            constants.LX_SB_DIRSYNC: ",dirsync",
127            constants.LX_SB_NOATIME: ",noatime",
128            constants.LX_SB_NODIRATIME: ",nodiratime"}
129
130 MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid",
131             constants.LX_MNT_NODEV: ",nodev",
132             constants.LX_MNT_NOEXEC: ",noexec",
133             constants.LX_MNT_NOATIME: ",noatime",
134             constants.LX_MNT_NODIRATIME: ",nodiratime",
135             constants.LX_MNT_RELATIME: ",relatime"}
136
137 mount_type = utils.CachedType("struct mount")
138 mount_ptr_type = mount_type.get_type().pointer()
139
140
141 class LxMounts(gdb.Command):
142     """Report the VFS mounts of the current process namespace.
143
144 Equivalent to cat /proc/mounts on a running target
145 An integer value can be supplied to display the mount
146 values of that process namespace"""
147
148     def __init__(self):
149         super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA)
150
151     # Equivalent to proc_namespace.c:show_vfsmnt
152     # However, that has the ability to call into s_op functions
153     # whereas we cannot and must make do with the information we can obtain.
154     def invoke(self, arg, from_tty):
155         argv = gdb.string_to_argv(arg)
156         if len(argv) >= 1:
157             try:
158                 pid = int(argv[0])
159             except gdb.error:
160                 raise gdb.GdbError("Provide a PID as integer value")
161         else:
162             pid = 1
163
164         task = tasks.get_task_by_pid(pid)
165         if not task:
166             raise gdb.GdbError("Couldn't find a process with PID {}"
167                                .format(pid))
168
169         namespace = task['nsproxy']['mnt_ns']
170         if not namespace:
171             raise gdb.GdbError("No namespace for current process")
172
173         gdb.write("{:^18} {:^15} {:>9} {} {} options\n".format(
174                   "mount", "super_block", "devname", "pathname", "fstype"))
175
176         for mnt in rbtree.rb_inorder_for_each_entry(namespace['mounts'], mount_ptr_type, "mnt_node"):
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()
This page took 0.043164 seconds and 4 git commands to generate.