1 # SPDX-License-Identifier: GPL-2.0 << 2 # 1 # 3 # gdb helper commands and functions for Linux 2 # gdb helper commands and functions for Linux kernel debugging 4 # 3 # 5 # Kernel proc information reader 4 # Kernel proc information reader 6 # 5 # 7 # Copyright (c) 2016 Linaro Ltd 6 # Copyright (c) 2016 Linaro Ltd 8 # 7 # 9 # Authors: 8 # Authors: 10 # Kieran Bingham <kieran.bingham@linaro.org> 9 # Kieran Bingham <kieran.bingham@linaro.org> 11 # 10 # 12 # This work is licensed under the terms of the 11 # This work is licensed under the terms of the GNU GPL version 2. 13 # 12 # 14 13 15 import gdb 14 import gdb 16 from linux import constants 15 from linux import constants 17 from linux import utils 16 from linux import utils 18 from linux import tasks 17 from linux import tasks 19 from linux import lists 18 from linux import lists 20 from linux import vfs << 21 from linux import rbtree << 22 from struct import * << 23 19 24 20 25 class LxCmdLine(gdb.Command): 21 class LxCmdLine(gdb.Command): 26 """ Report the Linux Commandline used in t 22 """ Report the Linux Commandline used in the current kernel. 27 Equivalent to cat /proc/cmdline on a r 23 Equivalent to cat /proc/cmdline on a running target""" 28 24 29 def __init__(self): 25 def __init__(self): 30 super(LxCmdLine, self).__init__("lx-cm 26 super(LxCmdLine, self).__init__("lx-cmdline", gdb.COMMAND_DATA) 31 27 32 def invoke(self, arg, from_tty): 28 def invoke(self, arg, from_tty): 33 gdb.write(gdb.parse_and_eval("saved_co 29 gdb.write(gdb.parse_and_eval("saved_command_line").string() + "\n") 34 30 35 << 36 LxCmdLine() 31 LxCmdLine() 37 32 38 33 39 class LxVersion(gdb.Command): 34 class LxVersion(gdb.Command): 40 """ Report the Linux Version of the curren 35 """ Report the Linux Version of the current kernel. 41 Equivalent to cat /proc/version on a r 36 Equivalent to cat /proc/version on a running target""" 42 37 43 def __init__(self): 38 def __init__(self): 44 super(LxVersion, self).__init__("lx-ve 39 super(LxVersion, self).__init__("lx-version", gdb.COMMAND_DATA) 45 40 46 def invoke(self, arg, from_tty): 41 def invoke(self, arg, from_tty): 47 # linux_banner should contain a newlin 42 # linux_banner should contain a newline 48 gdb.write(gdb.parse_and_eval("(char *) !! 43 gdb.write(gdb.parse_and_eval("linux_banner").string()) 49 << 50 44 51 LxVersion() 45 LxVersion() 52 46 53 47 54 # Resource Structure Printers 48 # Resource Structure Printers 55 # /proc/iomem 49 # /proc/iomem 56 # /proc/ioports 50 # /proc/ioports 57 51 58 def get_resources(resource, depth): 52 def get_resources(resource, depth): 59 while resource: 53 while resource: 60 yield resource, depth 54 yield resource, depth 61 55 62 child = resource['child'] 56 child = resource['child'] 63 if child: 57 if child: 64 for res, deep in get_resources(chi 58 for res, deep in get_resources(child, depth + 1): 65 yield res, deep 59 yield res, deep 66 60 67 resource = resource['sibling'] 61 resource = resource['sibling'] 68 62 69 63 70 def show_lx_resources(resource_str): 64 def show_lx_resources(resource_str): 71 resource = gdb.parse_and_eval(resource 65 resource = gdb.parse_and_eval(resource_str) 72 width = 4 if resource['end'] < 0x10000 66 width = 4 if resource['end'] < 0x10000 else 8 73 # Iterate straight to the first child 67 # Iterate straight to the first child 74 for res, depth in get_resources(resour 68 for res, depth in get_resources(resource['child'], 0): 75 start = int(res['start']) 69 start = int(res['start']) 76 end = int(res['end']) 70 end = int(res['end']) 77 gdb.write(" " * depth * 2 + 71 gdb.write(" " * depth * 2 + 78 "{0:0{1}x}-".format(star 72 "{0:0{1}x}-".format(start, width) + 79 "{0:0{1}x} : ".format(en 73 "{0:0{1}x} : ".format(end, width) + 80 res['name'].string() + " 74 res['name'].string() + "\n") 81 75 82 76 83 class LxIOMem(gdb.Command): 77 class LxIOMem(gdb.Command): 84 """Identify the IO memory resource locatio 78 """Identify the IO memory resource locations defined by the kernel 85 79 86 Equivalent to cat /proc/iomem on a running tar 80 Equivalent to cat /proc/iomem on a running target""" 87 81 88 def __init__(self): 82 def __init__(self): 89 super(LxIOMem, self).__init__("lx-iome 83 super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA) 90 84 91 def invoke(self, arg, from_tty): 85 def invoke(self, arg, from_tty): 92 return show_lx_resources("iomem_resour 86 return show_lx_resources("iomem_resource") 93 87 94 << 95 LxIOMem() 88 LxIOMem() 96 89 97 90 98 class LxIOPorts(gdb.Command): 91 class LxIOPorts(gdb.Command): 99 """Identify the IO port resource locations 92 """Identify the IO port resource locations defined by the kernel 100 93 101 Equivalent to cat /proc/ioports on a running t 94 Equivalent to cat /proc/ioports on a running target""" 102 95 103 def __init__(self): 96 def __init__(self): 104 super(LxIOPorts, self).__init__("lx-io 97 super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA) 105 98 106 def invoke(self, arg, from_tty): 99 def invoke(self, arg, from_tty): 107 return show_lx_resources("ioport_resou 100 return show_lx_resources("ioport_resource") 108 101 109 << 110 LxIOPorts() 102 LxIOPorts() 111 103 112 104 113 # Mount namespace viewer 105 # Mount namespace viewer 114 # /proc/mounts 106 # /proc/mounts 115 107 116 def info_opts(lst, opt): 108 def info_opts(lst, opt): 117 opts = "" 109 opts = "" 118 for key, string in lst.items(): 110 for key, string in lst.items(): 119 if opt & key: 111 if opt & key: 120 opts += string 112 opts += string 121 return opts 113 return opts 122 114 123 115 124 FS_INFO = {constants.LX_SB_SYNCHRONOUS: ",sync !! 116 FS_INFO = {constants.LX_MS_SYNCHRONOUS: ",sync", 125 constants.LX_SB_MANDLOCK: ",mand", !! 117 constants.LX_MS_MANDLOCK: ",mand", 126 constants.LX_SB_DIRSYNC: ",dirsync" !! 118 constants.LX_MS_DIRSYNC: ",dirsync", 127 constants.LX_SB_NOATIME: ",noatime" !! 119 constants.LX_MS_NOATIME: ",noatime", 128 constants.LX_SB_NODIRATIME: ",nodir !! 120 constants.LX_MS_NODIRATIME: ",nodiratime"} 129 121 130 MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid" 122 MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid", 131 constants.LX_MNT_NODEV: ",nodev", 123 constants.LX_MNT_NODEV: ",nodev", 132 constants.LX_MNT_NOEXEC: ",noexec" 124 constants.LX_MNT_NOEXEC: ",noexec", 133 constants.LX_MNT_NOATIME: ",noatim 125 constants.LX_MNT_NOATIME: ",noatime", 134 constants.LX_MNT_NODIRATIME: ",nod 126 constants.LX_MNT_NODIRATIME: ",nodiratime", 135 constants.LX_MNT_RELATIME: ",relat 127 constants.LX_MNT_RELATIME: ",relatime"} 136 128 137 mount_type = utils.CachedType("struct mount") 129 mount_type = utils.CachedType("struct mount") 138 mount_ptr_type = mount_type.get_type().pointer 130 mount_ptr_type = mount_type.get_type().pointer() 139 131 140 132 141 class LxMounts(gdb.Command): 133 class LxMounts(gdb.Command): 142 """Report the VFS mounts of the current pr 134 """Report the VFS mounts of the current process namespace. 143 135 144 Equivalent to cat /proc/mounts on a running ta 136 Equivalent to cat /proc/mounts on a running target 145 An integer value can be supplied to display th 137 An integer value can be supplied to display the mount 146 values of that process namespace""" 138 values of that process namespace""" 147 139 148 def __init__(self): 140 def __init__(self): 149 super(LxMounts, self).__init__("lx-mou 141 super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA) 150 142 151 # Equivalent to proc_namespace.c:show_vfsm 143 # Equivalent to proc_namespace.c:show_vfsmnt 152 # However, that has the ability to call in 144 # However, that has the ability to call into s_op functions 153 # whereas we cannot and must make do with 145 # whereas we cannot and must make do with the information we can obtain. 154 def invoke(self, arg, from_tty): 146 def invoke(self, arg, from_tty): 155 argv = gdb.string_to_argv(arg) 147 argv = gdb.string_to_argv(arg) 156 if len(argv) >= 1: 148 if len(argv) >= 1: 157 try: 149 try: 158 pid = int(argv[0]) 150 pid = int(argv[0]) 159 except gdb.error: !! 151 except: 160 raise gdb.GdbError("Provide a 152 raise gdb.GdbError("Provide a PID as integer value") 161 else: 153 else: 162 pid = 1 154 pid = 1 163 155 164 task = tasks.get_task_by_pid(pid) 156 task = tasks.get_task_by_pid(pid) 165 if not task: 157 if not task: 166 raise gdb.GdbError("Couldn't find 158 raise gdb.GdbError("Couldn't find a process with PID {}" 167 .format(pid)) 159 .format(pid)) 168 160 169 namespace = task['nsproxy']['mnt_ns'] 161 namespace = task['nsproxy']['mnt_ns'] 170 if not namespace: 162 if not namespace: 171 raise gdb.GdbError("No namespace f 163 raise gdb.GdbError("No namespace for current process") 172 164 173 gdb.write("{:^18} {:^15} {:>9} {} {} o !! 165 for vfs in lists.list_for_each_entry(namespace['list'], 174 "mount", "super_block", "dev !! 166 mount_ptr_type, "mnt_list"): 175 !! 167 devname = vfs['mnt_devname'].string() 176 for mnt in rbtree.rb_inorder_for_each_ << 177 devname = mnt['mnt_devname'].strin << 178 devname = devname if devname else 168 devname = devname if devname else "none" 179 169 180 pathname = "" 170 pathname = "" 181 parent = mnt !! 171 parent = vfs 182 while True: 172 while True: 183 mntpoint = parent['mnt_mountpo 173 mntpoint = parent['mnt_mountpoint'] 184 pathname = vfs.dentry_name(mnt !! 174 pathname = utils.dentry_name(mntpoint) + pathname 185 if (parent == parent['mnt_pare 175 if (parent == parent['mnt_parent']): 186 break 176 break 187 parent = parent['mnt_parent'] 177 parent = parent['mnt_parent'] 188 178 189 if (pathname == ""): 179 if (pathname == ""): 190 pathname = "/" 180 pathname = "/" 191 181 192 superblock = mnt['mnt']['mnt_sb'] !! 182 superblock = vfs['mnt']['mnt_sb'] 193 fstype = superblock['s_type']['nam 183 fstype = superblock['s_type']['name'].string() 194 s_flags = int(superblock['s_flags' 184 s_flags = int(superblock['s_flags']) 195 m_flags = int(mnt['mnt']['mnt_flag !! 185 m_flags = int(vfs['mnt']['mnt_flags']) 196 rd = "ro" if (s_flags & constants. !! 186 rd = "ro" if (s_flags & constants.LX_MS_RDONLY) else "rw" 197 << 198 gdb.write("{} {} {} {} {} {}{}{} 0 << 199 mnt.format_string(), sup << 200 pathname, fstype, rd, in << 201 info_opts(MNT_INFO, m_fl << 202 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))) 203 196 204 LxMounts() 197 LxMounts() 205 << 206 << 207 class LxFdtDump(gdb.Command): << 208 """Output Flattened Device Tree header and << 209 specified as the command argument. Equi << 210 'cat /proc/fdt > fdtdump.dtb' on a runn << 211 << 212 def __init__(self): << 213 super(LxFdtDump, self).__init__("lx-fd << 214 gdb.CO << 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_hea << 227 fdt_hea << 228 fdt_hea << 229 fdt_hea << 230 fdt_hea << 231 fdt_hea << 232 fdt_hea << 233 fdt_hea << 234 << 235 def invoke(self, arg, from_tty): << 236 << 237 if not constants.LX_CONFIG_OF: << 238 raise gdb.GdbError("Kernel not com << 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 *) initi << 247 py_fdt_header = py_fdt_header_ptr.dere << 248 << 249 fdt_header = self.fdthdr_to_cpu(py_fdt << 250 << 251 if fdt_header[0] != constants.LX_OF_DT << 252 raise gdb.GdbError("No flattened d << 253 << 254 gdb.write("fdt_magic: 0x{:02X} << 255 gdb.write("fdt_totalsize: 0x{:02X} << 256 gdb.write("off_dt_struct: 0x{:02X} << 257 gdb.write("off_dt_strings: 0x{:02X} << 258 gdb.write("off_mem_rsvmap: 0x{:02X} << 259 gdb.write("version: {}\n".fo << 260 gdb.write("last_comp_version: {}\n".fo << 261 << 262 inf = gdb.inferiors()[0] << 263 fdt_buf = utils.read_memoryview(inf, p << 264 fdt_he << 265 << 266 try: << 267 f = open(filename, 'wb') << 268 except gdb.error: << 269 raise gdb.GdbError("Could not open << 270 << 271 f.write(fdt_buf) << 272 f.close() << 273 << 274 gdb.write("Dumped fdt blob to " + file << 275 << 276 << 277 LxFdtDump() <<
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.