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