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