GNU Linux-libre 4.9.294-gnu1
[releases.git] / scripts / gdb / linux / proc.py
1 #
2 # gdb helper commands and functions for Linux kernel debugging
3 #
4 #  Kernel proc information reader
5 #
6 # Copyright (c) 2016 Linaro Ltd
7 #
8 # Authors:
9 #  Kieran Bingham <kieran.bingham@linaro.org>
10 #
11 # This work is licensed under the terms of the GNU GPL version 2.
12 #
13
14 import gdb
15 from linux import constants
16 from linux import utils
17 from linux import tasks
18 from linux import lists
19
20
21 class LxCmdLine(gdb.Command):
22     """ Report the Linux Commandline used in the current kernel.
23         Equivalent to cat /proc/cmdline on a running target"""
24
25     def __init__(self):
26         super(LxCmdLine, self).__init__("lx-cmdline", gdb.COMMAND_DATA)
27
28     def invoke(self, arg, from_tty):
29         gdb.write(gdb.parse_and_eval("saved_command_line").string() + "\n")
30
31 LxCmdLine()
32
33
34 class LxVersion(gdb.Command):
35     """ Report the Linux Version of the current kernel.
36         Equivalent to cat /proc/version on a running target"""
37
38     def __init__(self):
39         super(LxVersion, self).__init__("lx-version", gdb.COMMAND_DATA)
40
41     def invoke(self, arg, from_tty):
42         # linux_banner should contain a newline
43         gdb.write(gdb.parse_and_eval("(char *)linux_banner").string())
44
45 LxVersion()
46
47
48 # Resource Structure Printers
49 #  /proc/iomem
50 #  /proc/ioports
51
52 def get_resources(resource, depth):
53     while resource:
54         yield resource, depth
55
56         child = resource['child']
57         if child:
58             for res, deep in get_resources(child, depth + 1):
59                 yield res, deep
60
61         resource = resource['sibling']
62
63
64 def show_lx_resources(resource_str):
65         resource = gdb.parse_and_eval(resource_str)
66         width = 4 if resource['end'] < 0x10000 else 8
67         # Iterate straight to the first child
68         for res, depth in get_resources(resource['child'], 0):
69             start = int(res['start'])
70             end = int(res['end'])
71             gdb.write(" " * depth * 2 +
72                       "{0:0{1}x}-".format(start, width) +
73                       "{0:0{1}x} : ".format(end, width) +
74                       res['name'].string() + "\n")
75
76
77 class LxIOMem(gdb.Command):
78     """Identify the IO memory resource locations defined by the kernel
79
80 Equivalent to cat /proc/iomem on a running target"""
81
82     def __init__(self):
83         super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA)
84
85     def invoke(self, arg, from_tty):
86         return show_lx_resources("iomem_resource")
87
88 LxIOMem()
89
90
91 class LxIOPorts(gdb.Command):
92     """Identify the IO port resource locations defined by the kernel
93
94 Equivalent to cat /proc/ioports on a running target"""
95
96     def __init__(self):
97         super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA)
98
99     def invoke(self, arg, from_tty):
100         return show_lx_resources("ioport_resource")
101
102 LxIOPorts()
103
104
105 # Mount namespace viewer
106 #  /proc/mounts
107
108 def info_opts(lst, opt):
109     opts = ""
110     for key, string in lst.items():
111         if opt & key:
112             opts += string
113     return opts
114
115
116 FS_INFO = {constants.LX_MS_SYNCHRONOUS: ",sync",
117            constants.LX_MS_MANDLOCK: ",mand",
118            constants.LX_MS_DIRSYNC: ",dirsync",
119            constants.LX_MS_NOATIME: ",noatime",
120            constants.LX_MS_NODIRATIME: ",nodiratime"}
121
122 MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid",
123             constants.LX_MNT_NODEV: ",nodev",
124             constants.LX_MNT_NOEXEC: ",noexec",
125             constants.LX_MNT_NOATIME: ",noatime",
126             constants.LX_MNT_NODIRATIME: ",nodiratime",
127             constants.LX_MNT_RELATIME: ",relatime"}
128
129 mount_type = utils.CachedType("struct mount")
130 mount_ptr_type = mount_type.get_type().pointer()
131
132
133 class LxMounts(gdb.Command):
134     """Report the VFS mounts of the current process namespace.
135
136 Equivalent to cat /proc/mounts on a running target
137 An integer value can be supplied to display the mount
138 values of that process namespace"""
139
140     def __init__(self):
141         super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA)
142
143     # Equivalent to proc_namespace.c:show_vfsmnt
144     # However, that has the ability to call into s_op functions
145     # whereas we cannot and must make do with the information we can obtain.
146     def invoke(self, arg, from_tty):
147         argv = gdb.string_to_argv(arg)
148         if len(argv) >= 1:
149             try:
150                 pid = int(argv[0])
151             except:
152                 raise gdb.GdbError("Provide a PID as integer value")
153         else:
154             pid = 1
155
156         task = tasks.get_task_by_pid(pid)
157         if not task:
158             raise gdb.GdbError("Couldn't find a process with PID {}"
159                                .format(pid))
160
161         namespace = task['nsproxy']['mnt_ns']
162         if not namespace:
163             raise gdb.GdbError("No namespace for current process")
164
165         for vfs in lists.list_for_each_entry(namespace['list'],
166                                              mount_ptr_type, "mnt_list"):
167             devname = vfs['mnt_devname'].string()
168             devname = devname if devname else "none"
169
170             pathname = ""
171             parent = vfs
172             while True:
173                 mntpoint = parent['mnt_mountpoint']
174                 pathname = utils.dentry_name(mntpoint) + pathname
175                 if (parent == parent['mnt_parent']):
176                     break
177                 parent = parent['mnt_parent']
178
179             if (pathname == ""):
180                 pathname = "/"
181
182             superblock = vfs['mnt']['mnt_sb']
183             fstype = superblock['s_type']['name'].string()
184             s_flags = int(superblock['s_flags'])
185             m_flags = int(vfs['mnt']['mnt_flags'])
186             rd = "ro" if (s_flags & constants.LX_MS_RDONLY) else "rw"
187
188             gdb.write(
189                 "{} {} {} {}{}{} 0 0\n"
190                 .format(devname,
191                         pathname,
192                         fstype,
193                         rd,
194                         info_opts(FS_INFO, s_flags),
195                         info_opts(MNT_INFO, m_flags)))
196
197 LxMounts()