xref: /linux-6.15/scripts/gdb/linux/proc.py (revision 4b183f61)
1f4efbdafSGlenn Washburn# SPDX-License-Identifier: GPL-2.0
22d061d99SKieran Bingham#
32d061d99SKieran Bingham# gdb helper commands and functions for Linux kernel debugging
42d061d99SKieran Bingham#
52d061d99SKieran Bingham#  Kernel proc information reader
62d061d99SKieran Bingham#
72d061d99SKieran Bingham# Copyright (c) 2016 Linaro Ltd
82d061d99SKieran Bingham#
92d061d99SKieran Bingham# Authors:
102d061d99SKieran Bingham#  Kieran Bingham <[email protected]>
112d061d99SKieran Bingham#
122d061d99SKieran Bingham# This work is licensed under the terms of the GNU GPL version 2.
132d061d99SKieran Bingham#
142d061d99SKieran Bingham
152d061d99SKieran Binghamimport gdb
16c1a15399SKieran Binghamfrom linux import constants
17c1a15399SKieran Binghamfrom linux import utils
18c1a15399SKieran Binghamfrom linux import tasks
19c1a15399SKieran Binghamfrom linux import lists
20f4efbdafSGlenn Washburnfrom linux import vfs
21*4b183f61SKuan-Ying Leefrom linux import rbtree
22821f7440SPeter Griffinfrom struct import *
232d061d99SKieran Bingham
242d061d99SKieran Bingham
2572bf92ecSKieran Binghamclass LxCmdLine(gdb.Command):
2672bf92ecSKieran Bingham    """ Report the Linux Commandline used in the current kernel.
2772bf92ecSKieran Bingham        Equivalent to cat /proc/cmdline on a running target"""
2872bf92ecSKieran Bingham
2972bf92ecSKieran Bingham    def __init__(self):
3072bf92ecSKieran Bingham        super(LxCmdLine, self).__init__("lx-cmdline", gdb.COMMAND_DATA)
3172bf92ecSKieran Bingham
3272bf92ecSKieran Bingham    def invoke(self, arg, from_tty):
3372bf92ecSKieran Bingham        gdb.write(gdb.parse_and_eval("saved_command_line").string() + "\n")
3472bf92ecSKieran Bingham
35494dbe02SStephen Boyd
3672bf92ecSKieran BinghamLxCmdLine()
3772bf92ecSKieran Bingham
3872bf92ecSKieran Bingham
392d061d99SKieran Binghamclass LxVersion(gdb.Command):
402d061d99SKieran Bingham    """ Report the Linux Version of the current kernel.
412d061d99SKieran Bingham        Equivalent to cat /proc/version on a running target"""
422d061d99SKieran Bingham
432d061d99SKieran Bingham    def __init__(self):
442d061d99SKieran Bingham        super(LxVersion, self).__init__("lx-version", gdb.COMMAND_DATA)
452d061d99SKieran Bingham
462d061d99SKieran Bingham    def invoke(self, arg, from_tty):
472d061d99SKieran Bingham        # linux_banner should contain a newline
48b058809bSDu Changbin        gdb.write(gdb.parse_and_eval("(char *)linux_banner").string())
492d061d99SKieran Bingham
50494dbe02SStephen Boyd
512d061d99SKieran BinghamLxVersion()
52e7165a2dSKieran Bingham
53e7165a2dSKieran Bingham
54e7165a2dSKieran Bingham# Resource Structure Printers
55e7165a2dSKieran Bingham#  /proc/iomem
56e7165a2dSKieran Bingham#  /proc/ioports
57e7165a2dSKieran Bingham
58e7165a2dSKieran Binghamdef get_resources(resource, depth):
59e7165a2dSKieran Bingham    while resource:
60e7165a2dSKieran Bingham        yield resource, depth
61e7165a2dSKieran Bingham
62e7165a2dSKieran Bingham        child = resource['child']
63e7165a2dSKieran Bingham        if child:
64e7165a2dSKieran Bingham            for res, deep in get_resources(child, depth + 1):
65e7165a2dSKieran Bingham                yield res, deep
66e7165a2dSKieran Bingham
67e7165a2dSKieran Bingham        resource = resource['sibling']
68e7165a2dSKieran Bingham
69e7165a2dSKieran Bingham
70e7165a2dSKieran Binghamdef show_lx_resources(resource_str):
71e7165a2dSKieran Bingham        resource = gdb.parse_and_eval(resource_str)
72e7165a2dSKieran Bingham        width = 4 if resource['end'] < 0x10000 else 8
73e7165a2dSKieran Bingham        # Iterate straight to the first child
74e7165a2dSKieran Bingham        for res, depth in get_resources(resource['child'], 0):
75e7165a2dSKieran Bingham            start = int(res['start'])
76e7165a2dSKieran Bingham            end = int(res['end'])
77e7165a2dSKieran Bingham            gdb.write(" " * depth * 2 +
78e7165a2dSKieran Bingham                      "{0:0{1}x}-".format(start, width) +
79e7165a2dSKieran Bingham                      "{0:0{1}x} : ".format(end, width) +
80e7165a2dSKieran Bingham                      res['name'].string() + "\n")
81e7165a2dSKieran Bingham
82e7165a2dSKieran Bingham
83e7165a2dSKieran Binghamclass LxIOMem(gdb.Command):
84e7165a2dSKieran Bingham    """Identify the IO memory resource locations defined by the kernel
85e7165a2dSKieran Bingham
86e7165a2dSKieran BinghamEquivalent to cat /proc/iomem on a running target"""
87e7165a2dSKieran Bingham
88e7165a2dSKieran Bingham    def __init__(self):
89e7165a2dSKieran Bingham        super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA)
90e7165a2dSKieran Bingham
91e7165a2dSKieran Bingham    def invoke(self, arg, from_tty):
92e7165a2dSKieran Bingham        return show_lx_resources("iomem_resource")
93e7165a2dSKieran Bingham
94494dbe02SStephen Boyd
95e7165a2dSKieran BinghamLxIOMem()
96e7165a2dSKieran Bingham
97e7165a2dSKieran Bingham
98e7165a2dSKieran Binghamclass LxIOPorts(gdb.Command):
99e7165a2dSKieran Bingham    """Identify the IO port resource locations defined by the kernel
100e7165a2dSKieran Bingham
101e7165a2dSKieran BinghamEquivalent to cat /proc/ioports on a running target"""
102e7165a2dSKieran Bingham
103e7165a2dSKieran Bingham    def __init__(self):
104e7165a2dSKieran Bingham        super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA)
105e7165a2dSKieran Bingham
106e7165a2dSKieran Bingham    def invoke(self, arg, from_tty):
107e7165a2dSKieran Bingham        return show_lx_resources("ioport_resource")
108e7165a2dSKieran Bingham
109494dbe02SStephen Boyd
110e7165a2dSKieran BinghamLxIOPorts()
111c1a15399SKieran Bingham
112c1a15399SKieran Bingham
113c1a15399SKieran Bingham# Mount namespace viewer
114c1a15399SKieran Bingham#  /proc/mounts
115c1a15399SKieran Bingham
116c1a15399SKieran Binghamdef info_opts(lst, opt):
117c1a15399SKieran Bingham    opts = ""
118c1a15399SKieran Bingham    for key, string in lst.items():
119c1a15399SKieran Bingham        if opt & key:
120c1a15399SKieran Bingham            opts += string
121c1a15399SKieran Bingham    return opts
122c1a15399SKieran Bingham
123c1a15399SKieran Bingham
124663cb634SJackie LiuFS_INFO = {constants.LX_SB_SYNCHRONOUS: ",sync",
125663cb634SJackie Liu           constants.LX_SB_MANDLOCK: ",mand",
126663cb634SJackie Liu           constants.LX_SB_DIRSYNC: ",dirsync",
127663cb634SJackie Liu           constants.LX_SB_NOATIME: ",noatime",
128663cb634SJackie Liu           constants.LX_SB_NODIRATIME: ",nodiratime"}
129c1a15399SKieran Bingham
130c1a15399SKieran BinghamMNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid",
131c1a15399SKieran Bingham            constants.LX_MNT_NODEV: ",nodev",
132c1a15399SKieran Bingham            constants.LX_MNT_NOEXEC: ",noexec",
133c1a15399SKieran Bingham            constants.LX_MNT_NOATIME: ",noatime",
134c1a15399SKieran Bingham            constants.LX_MNT_NODIRATIME: ",nodiratime",
135c1a15399SKieran Bingham            constants.LX_MNT_RELATIME: ",relatime"}
136c1a15399SKieran Bingham
137c1a15399SKieran Binghammount_type = utils.CachedType("struct mount")
138c1a15399SKieran Binghammount_ptr_type = mount_type.get_type().pointer()
139c1a15399SKieran Bingham
140c1a15399SKieran Bingham
141c1a15399SKieran Binghamclass LxMounts(gdb.Command):
142c1a15399SKieran Bingham    """Report the VFS mounts of the current process namespace.
143c1a15399SKieran Bingham
144c1a15399SKieran BinghamEquivalent to cat /proc/mounts on a running target
145c1a15399SKieran BinghamAn integer value can be supplied to display the mount
146c1a15399SKieran Binghamvalues of that process namespace"""
147c1a15399SKieran Bingham
148c1a15399SKieran Bingham    def __init__(self):
149c1a15399SKieran Bingham        super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA)
150c1a15399SKieran Bingham
151c1a15399SKieran Bingham    # Equivalent to proc_namespace.c:show_vfsmnt
152c1a15399SKieran Bingham    # However, that has the ability to call into s_op functions
153c1a15399SKieran Bingham    # whereas we cannot and must make do with the information we can obtain.
154c1a15399SKieran Bingham    def invoke(self, arg, from_tty):
155c1a15399SKieran Bingham        argv = gdb.string_to_argv(arg)
156c1a15399SKieran Bingham        if len(argv) >= 1:
157c1a15399SKieran Bingham            try:
158c1a15399SKieran Bingham                pid = int(argv[0])
159494dbe02SStephen Boyd            except gdb.error:
160c1a15399SKieran Bingham                raise gdb.GdbError("Provide a PID as integer value")
161c1a15399SKieran Bingham        else:
162c1a15399SKieran Bingham            pid = 1
163c1a15399SKieran Bingham
164c1a15399SKieran Bingham        task = tasks.get_task_by_pid(pid)
165c1a15399SKieran Bingham        if not task:
166c1a15399SKieran Bingham            raise gdb.GdbError("Couldn't find a process with PID {}"
167c1a15399SKieran Bingham                               .format(pid))
168c1a15399SKieran Bingham
169c1a15399SKieran Bingham        namespace = task['nsproxy']['mnt_ns']
170c1a15399SKieran Bingham        if not namespace:
171c1a15399SKieran Bingham            raise gdb.GdbError("No namespace for current process")
172c1a15399SKieran Bingham
173998ec76bSRitesh Harjani        gdb.write("{:^18} {:^15} {:>9} {} {} options\n".format(
174998ec76bSRitesh Harjani                  "mount", "super_block", "devname", "pathname", "fstype"))
175998ec76bSRitesh Harjani
176*4b183f61SKuan-Ying Lee        for mnt in rbtree.rb_inorder_for_each_entry(namespace['mounts'], mount_ptr_type, "mnt_node"):
177f4efbdafSGlenn Washburn            devname = mnt['mnt_devname'].string()
178c1a15399SKieran Bingham            devname = devname if devname else "none"
179c1a15399SKieran Bingham
180c1a15399SKieran Bingham            pathname = ""
181f4efbdafSGlenn Washburn            parent = mnt
182c1a15399SKieran Bingham            while True:
183c1a15399SKieran Bingham                mntpoint = parent['mnt_mountpoint']
184f4efbdafSGlenn Washburn                pathname = vfs.dentry_name(mntpoint) + pathname
185c1a15399SKieran Bingham                if (parent == parent['mnt_parent']):
186c1a15399SKieran Bingham                    break
187c1a15399SKieran Bingham                parent = parent['mnt_parent']
188c1a15399SKieran Bingham
189c1a15399SKieran Bingham            if (pathname == ""):
190c1a15399SKieran Bingham                pathname = "/"
191c1a15399SKieran Bingham
192f4efbdafSGlenn Washburn            superblock = mnt['mnt']['mnt_sb']
193c1a15399SKieran Bingham            fstype = superblock['s_type']['name'].string()
194c1a15399SKieran Bingham            s_flags = int(superblock['s_flags'])
195f4efbdafSGlenn Washburn            m_flags = int(mnt['mnt']['mnt_flags'])
196663cb634SJackie Liu            rd = "ro" if (s_flags & constants.LX_SB_RDONLY) else "rw"
197c1a15399SKieran Bingham
198998ec76bSRitesh Harjani            gdb.write("{} {} {} {} {} {}{}{} 0 0\n".format(
199f4efbdafSGlenn Washburn                      mnt.format_string(), superblock.format_string(), devname,
200998ec76bSRitesh Harjani                      pathname, fstype, rd, info_opts(FS_INFO, s_flags),
201c1a15399SKieran Bingham                      info_opts(MNT_INFO, m_flags)))
202c1a15399SKieran Bingham
203494dbe02SStephen Boyd
204c1a15399SKieran BinghamLxMounts()
205821f7440SPeter Griffin
206821f7440SPeter Griffin
207821f7440SPeter Griffinclass LxFdtDump(gdb.Command):
208821f7440SPeter Griffin    """Output Flattened Device Tree header and dump FDT blob to the filename
209821f7440SPeter Griffin       specified as the command argument. Equivalent to
210821f7440SPeter Griffin       'cat /proc/fdt > fdtdump.dtb' on a running target"""
211821f7440SPeter Griffin
212821f7440SPeter Griffin    def __init__(self):
213821f7440SPeter Griffin        super(LxFdtDump, self).__init__("lx-fdtdump", gdb.COMMAND_DATA,
214821f7440SPeter Griffin                                        gdb.COMPLETE_FILENAME)
215821f7440SPeter Griffin
216821f7440SPeter Griffin    def fdthdr_to_cpu(self, fdt_header):
217821f7440SPeter Griffin
218821f7440SPeter Griffin        fdt_header_be = ">IIIIIII"
219821f7440SPeter Griffin        fdt_header_le = "<IIIIIII"
220821f7440SPeter Griffin
221821f7440SPeter Griffin        if utils.get_target_endianness() == 1:
222821f7440SPeter Griffin            output_fmt = fdt_header_le
223821f7440SPeter Griffin        else:
224821f7440SPeter Griffin            output_fmt = fdt_header_be
225821f7440SPeter Griffin
226821f7440SPeter Griffin        return unpack(output_fmt, pack(fdt_header_be,
227821f7440SPeter Griffin                                       fdt_header['magic'],
228821f7440SPeter Griffin                                       fdt_header['totalsize'],
229821f7440SPeter Griffin                                       fdt_header['off_dt_struct'],
230821f7440SPeter Griffin                                       fdt_header['off_dt_strings'],
231821f7440SPeter Griffin                                       fdt_header['off_mem_rsvmap'],
232821f7440SPeter Griffin                                       fdt_header['version'],
233821f7440SPeter Griffin                                       fdt_header['last_comp_version']))
234821f7440SPeter Griffin
235821f7440SPeter Griffin    def invoke(self, arg, from_tty):
236821f7440SPeter Griffin
237821f7440SPeter Griffin        if not constants.LX_CONFIG_OF:
238821f7440SPeter Griffin            raise gdb.GdbError("Kernel not compiled with CONFIG_OF\n")
239821f7440SPeter Griffin
240821f7440SPeter Griffin        if len(arg) == 0:
241821f7440SPeter Griffin            filename = "fdtdump.dtb"
242821f7440SPeter Griffin        else:
243821f7440SPeter Griffin            filename = arg
244821f7440SPeter Griffin
245821f7440SPeter Griffin        py_fdt_header_ptr = gdb.parse_and_eval(
246821f7440SPeter Griffin            "(const struct fdt_header *) initial_boot_params")
247821f7440SPeter Griffin        py_fdt_header = py_fdt_header_ptr.dereference()
248821f7440SPeter Griffin
249821f7440SPeter Griffin        fdt_header = self.fdthdr_to_cpu(py_fdt_header)
250821f7440SPeter Griffin
251821f7440SPeter Griffin        if fdt_header[0] != constants.LX_OF_DT_HEADER:
252821f7440SPeter Griffin            raise gdb.GdbError("No flattened device tree magic found\n")
253821f7440SPeter Griffin
254821f7440SPeter Griffin        gdb.write("fdt_magic:         0x{:02X}\n".format(fdt_header[0]))
255821f7440SPeter Griffin        gdb.write("fdt_totalsize:     0x{:02X}\n".format(fdt_header[1]))
256821f7440SPeter Griffin        gdb.write("off_dt_struct:     0x{:02X}\n".format(fdt_header[2]))
257821f7440SPeter Griffin        gdb.write("off_dt_strings:    0x{:02X}\n".format(fdt_header[3]))
258821f7440SPeter Griffin        gdb.write("off_mem_rsvmap:    0x{:02X}\n".format(fdt_header[4]))
259821f7440SPeter Griffin        gdb.write("version:           {}\n".format(fdt_header[5]))
260821f7440SPeter Griffin        gdb.write("last_comp_version: {}\n".format(fdt_header[6]))
261821f7440SPeter Griffin
262821f7440SPeter Griffin        inf = gdb.inferiors()[0]
263821f7440SPeter Griffin        fdt_buf = utils.read_memoryview(inf, py_fdt_header_ptr,
264821f7440SPeter Griffin                                        fdt_header[1]).tobytes()
265821f7440SPeter Griffin
266821f7440SPeter Griffin        try:
267821f7440SPeter Griffin            f = open(filename, 'wb')
268494dbe02SStephen Boyd        except gdb.error:
269821f7440SPeter Griffin            raise gdb.GdbError("Could not open file to dump fdt")
270821f7440SPeter Griffin
271821f7440SPeter Griffin        f.write(fdt_buf)
272821f7440SPeter Griffin        f.close()
273821f7440SPeter Griffin
274821f7440SPeter Griffin        gdb.write("Dumped fdt blob to " + filename + "\n")
275821f7440SPeter Griffin
276494dbe02SStephen Boyd
277821f7440SPeter GriffinLxFdtDump()
278