at v4.8 5.9 kB view raw
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 14import gdb 15from linux import constants 16from linux import utils 17from linux import tasks 18from linux import lists 19 20 21class 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 31LxCmdLine() 32 33 34class 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("linux_banner").string()) 44 45LxVersion() 46 47 48# Resource Structure Printers 49# /proc/iomem 50# /proc/ioports 51 52def 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 64def 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 77class LxIOMem(gdb.Command): 78 """Identify the IO memory resource locations defined by the kernel 79 80Equivalent 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 88LxIOMem() 89 90 91class LxIOPorts(gdb.Command): 92 """Identify the IO port resource locations defined by the kernel 93 94Equivalent 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 102LxIOPorts() 103 104 105# Mount namespace viewer 106# /proc/mounts 107 108def 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 116FS_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 122MNT_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 129mount_type = utils.CachedType("struct mount") 130mount_ptr_type = mount_type.get_type().pointer() 131 132 133class LxMounts(gdb.Command): 134 """Report the VFS mounts of the current process namespace. 135 136Equivalent to cat /proc/mounts on a running target 137An integer value can be supplied to display the mount 138values 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 197LxMounts()