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