1f4efbdafSGlenn Washburn# SPDX-License-Identifier: GPL-2.0 22d061d99SKieran Bingham# 32d061d99SKieran Bingham# gdb helper commands and functions for Linux kernel debugging 42d061d99SKieran Bingham# 52d061d99SKieran Bingham# Kernel proc information reader 62d061d99SKieran Bingham# 72d061d99SKieran Bingham# Copyright (c) 2016 Linaro Ltd 82d061d99SKieran Bingham# 92d061d99SKieran Bingham# Authors: 102d061d99SKieran Bingham# Kieran Bingham <[email protected]> 112d061d99SKieran Bingham# 122d061d99SKieran Bingham# This work is licensed under the terms of the GNU GPL version 2. 132d061d99SKieran Bingham# 142d061d99SKieran Bingham 152d061d99SKieran Binghamimport gdb 16c1a15399SKieran Binghamfrom linux import constants 17c1a15399SKieran Binghamfrom linux import utils 18c1a15399SKieran Binghamfrom linux import tasks 19c1a15399SKieran Binghamfrom linux import lists 20f4efbdafSGlenn Washburnfrom linux import vfs 21*4b183f61SKuan-Ying Leefrom linux import rbtree 22821f7440SPeter Griffinfrom struct import * 232d061d99SKieran Bingham 242d061d99SKieran Bingham 2572bf92ecSKieran Binghamclass LxCmdLine(gdb.Command): 2672bf92ecSKieran Bingham """ Report the Linux Commandline used in the current kernel. 2772bf92ecSKieran Bingham Equivalent to cat /proc/cmdline on a running target""" 2872bf92ecSKieran Bingham 2972bf92ecSKieran Bingham def __init__(self): 3072bf92ecSKieran Bingham super(LxCmdLine, self).__init__("lx-cmdline", gdb.COMMAND_DATA) 3172bf92ecSKieran Bingham 3272bf92ecSKieran Bingham def invoke(self, arg, from_tty): 3372bf92ecSKieran Bingham gdb.write(gdb.parse_and_eval("saved_command_line").string() + "\n") 3472bf92ecSKieran Bingham 35494dbe02SStephen Boyd 3672bf92ecSKieran BinghamLxCmdLine() 3772bf92ecSKieran Bingham 3872bf92ecSKieran Bingham 392d061d99SKieran Binghamclass LxVersion(gdb.Command): 402d061d99SKieran Bingham """ Report the Linux Version of the current kernel. 412d061d99SKieran Bingham Equivalent to cat /proc/version on a running target""" 422d061d99SKieran Bingham 432d061d99SKieran Bingham def __init__(self): 442d061d99SKieran Bingham super(LxVersion, self).__init__("lx-version", gdb.COMMAND_DATA) 452d061d99SKieran Bingham 462d061d99SKieran Bingham def invoke(self, arg, from_tty): 472d061d99SKieran Bingham # linux_banner should contain a newline 48b058809bSDu Changbin gdb.write(gdb.parse_and_eval("(char *)linux_banner").string()) 492d061d99SKieran Bingham 50494dbe02SStephen Boyd 512d061d99SKieran BinghamLxVersion() 52e7165a2dSKieran Bingham 53e7165a2dSKieran Bingham 54e7165a2dSKieran Bingham# Resource Structure Printers 55e7165a2dSKieran Bingham# /proc/iomem 56e7165a2dSKieran Bingham# /proc/ioports 57e7165a2dSKieran Bingham 58e7165a2dSKieran Binghamdef get_resources(resource, depth): 59e7165a2dSKieran Bingham while resource: 60e7165a2dSKieran Bingham yield resource, depth 61e7165a2dSKieran Bingham 62e7165a2dSKieran Bingham child = resource['child'] 63e7165a2dSKieran Bingham if child: 64e7165a2dSKieran Bingham for res, deep in get_resources(child, depth + 1): 65e7165a2dSKieran Bingham yield res, deep 66e7165a2dSKieran Bingham 67e7165a2dSKieran Bingham resource = resource['sibling'] 68e7165a2dSKieran Bingham 69e7165a2dSKieran Bingham 70e7165a2dSKieran Binghamdef show_lx_resources(resource_str): 71e7165a2dSKieran Bingham resource = gdb.parse_and_eval(resource_str) 72e7165a2dSKieran Bingham width = 4 if resource['end'] < 0x10000 else 8 73e7165a2dSKieran Bingham # Iterate straight to the first child 74e7165a2dSKieran Bingham for res, depth in get_resources(resource['child'], 0): 75e7165a2dSKieran Bingham start = int(res['start']) 76e7165a2dSKieran Bingham end = int(res['end']) 77e7165a2dSKieran Bingham gdb.write(" " * depth * 2 + 78e7165a2dSKieran Bingham "{0:0{1}x}-".format(start, width) + 79e7165a2dSKieran Bingham "{0:0{1}x} : ".format(end, width) + 80e7165a2dSKieran Bingham res['name'].string() + "\n") 81e7165a2dSKieran Bingham 82e7165a2dSKieran Bingham 83e7165a2dSKieran Binghamclass LxIOMem(gdb.Command): 84e7165a2dSKieran Bingham """Identify the IO memory resource locations defined by the kernel 85e7165a2dSKieran Bingham 86e7165a2dSKieran BinghamEquivalent to cat /proc/iomem on a running target""" 87e7165a2dSKieran Bingham 88e7165a2dSKieran Bingham def __init__(self): 89e7165a2dSKieran Bingham super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA) 90e7165a2dSKieran Bingham 91e7165a2dSKieran Bingham def invoke(self, arg, from_tty): 92e7165a2dSKieran Bingham return show_lx_resources("iomem_resource") 93e7165a2dSKieran Bingham 94494dbe02SStephen Boyd 95e7165a2dSKieran BinghamLxIOMem() 96e7165a2dSKieran Bingham 97e7165a2dSKieran Bingham 98e7165a2dSKieran Binghamclass LxIOPorts(gdb.Command): 99e7165a2dSKieran Bingham """Identify the IO port resource locations defined by the kernel 100e7165a2dSKieran Bingham 101e7165a2dSKieran BinghamEquivalent to cat /proc/ioports on a running target""" 102e7165a2dSKieran Bingham 103e7165a2dSKieran Bingham def __init__(self): 104e7165a2dSKieran Bingham super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA) 105e7165a2dSKieran Bingham 106e7165a2dSKieran Bingham def invoke(self, arg, from_tty): 107e7165a2dSKieran Bingham return show_lx_resources("ioport_resource") 108e7165a2dSKieran Bingham 109494dbe02SStephen Boyd 110e7165a2dSKieran BinghamLxIOPorts() 111c1a15399SKieran Bingham 112c1a15399SKieran Bingham 113c1a15399SKieran Bingham# Mount namespace viewer 114c1a15399SKieran Bingham# /proc/mounts 115c1a15399SKieran Bingham 116c1a15399SKieran Binghamdef info_opts(lst, opt): 117c1a15399SKieran Bingham opts = "" 118c1a15399SKieran Bingham for key, string in lst.items(): 119c1a15399SKieran Bingham if opt & key: 120c1a15399SKieran Bingham opts += string 121c1a15399SKieran Bingham return opts 122c1a15399SKieran Bingham 123c1a15399SKieran Bingham 124663cb634SJackie LiuFS_INFO = {constants.LX_SB_SYNCHRONOUS: ",sync", 125663cb634SJackie Liu constants.LX_SB_MANDLOCK: ",mand", 126663cb634SJackie Liu constants.LX_SB_DIRSYNC: ",dirsync", 127663cb634SJackie Liu constants.LX_SB_NOATIME: ",noatime", 128663cb634SJackie Liu constants.LX_SB_NODIRATIME: ",nodiratime"} 129c1a15399SKieran Bingham 130c1a15399SKieran BinghamMNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid", 131c1a15399SKieran Bingham constants.LX_MNT_NODEV: ",nodev", 132c1a15399SKieran Bingham constants.LX_MNT_NOEXEC: ",noexec", 133c1a15399SKieran Bingham constants.LX_MNT_NOATIME: ",noatime", 134c1a15399SKieran Bingham constants.LX_MNT_NODIRATIME: ",nodiratime", 135c1a15399SKieran Bingham constants.LX_MNT_RELATIME: ",relatime"} 136c1a15399SKieran Bingham 137c1a15399SKieran Binghammount_type = utils.CachedType("struct mount") 138c1a15399SKieran Binghammount_ptr_type = mount_type.get_type().pointer() 139c1a15399SKieran Bingham 140c1a15399SKieran Bingham 141c1a15399SKieran Binghamclass LxMounts(gdb.Command): 142c1a15399SKieran Bingham """Report the VFS mounts of the current process namespace. 143c1a15399SKieran Bingham 144c1a15399SKieran BinghamEquivalent to cat /proc/mounts on a running target 145c1a15399SKieran BinghamAn integer value can be supplied to display the mount 146c1a15399SKieran Binghamvalues of that process namespace""" 147c1a15399SKieran Bingham 148c1a15399SKieran Bingham def __init__(self): 149c1a15399SKieran Bingham super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA) 150c1a15399SKieran Bingham 151c1a15399SKieran Bingham # Equivalent to proc_namespace.c:show_vfsmnt 152c1a15399SKieran Bingham # However, that has the ability to call into s_op functions 153c1a15399SKieran Bingham # whereas we cannot and must make do with the information we can obtain. 154c1a15399SKieran Bingham def invoke(self, arg, from_tty): 155c1a15399SKieran Bingham argv = gdb.string_to_argv(arg) 156c1a15399SKieran Bingham if len(argv) >= 1: 157c1a15399SKieran Bingham try: 158c1a15399SKieran Bingham pid = int(argv[0]) 159494dbe02SStephen Boyd except gdb.error: 160c1a15399SKieran Bingham raise gdb.GdbError("Provide a PID as integer value") 161c1a15399SKieran Bingham else: 162c1a15399SKieran Bingham pid = 1 163c1a15399SKieran Bingham 164c1a15399SKieran Bingham task = tasks.get_task_by_pid(pid) 165c1a15399SKieran Bingham if not task: 166c1a15399SKieran Bingham raise gdb.GdbError("Couldn't find a process with PID {}" 167c1a15399SKieran Bingham .format(pid)) 168c1a15399SKieran Bingham 169c1a15399SKieran Bingham namespace = task['nsproxy']['mnt_ns'] 170c1a15399SKieran Bingham if not namespace: 171c1a15399SKieran Bingham raise gdb.GdbError("No namespace for current process") 172c1a15399SKieran Bingham 173998ec76bSRitesh Harjani gdb.write("{:^18} {:^15} {:>9} {} {} options\n".format( 174998ec76bSRitesh Harjani "mount", "super_block", "devname", "pathname", "fstype")) 175998ec76bSRitesh Harjani 176*4b183f61SKuan-Ying Lee for mnt in rbtree.rb_inorder_for_each_entry(namespace['mounts'], mount_ptr_type, "mnt_node"): 177f4efbdafSGlenn Washburn devname = mnt['mnt_devname'].string() 178c1a15399SKieran Bingham devname = devname if devname else "none" 179c1a15399SKieran Bingham 180c1a15399SKieran Bingham pathname = "" 181f4efbdafSGlenn Washburn parent = mnt 182c1a15399SKieran Bingham while True: 183c1a15399SKieran Bingham mntpoint = parent['mnt_mountpoint'] 184f4efbdafSGlenn Washburn pathname = vfs.dentry_name(mntpoint) + pathname 185c1a15399SKieran Bingham if (parent == parent['mnt_parent']): 186c1a15399SKieran Bingham break 187c1a15399SKieran Bingham parent = parent['mnt_parent'] 188c1a15399SKieran Bingham 189c1a15399SKieran Bingham if (pathname == ""): 190c1a15399SKieran Bingham pathname = "/" 191c1a15399SKieran Bingham 192f4efbdafSGlenn Washburn superblock = mnt['mnt']['mnt_sb'] 193c1a15399SKieran Bingham fstype = superblock['s_type']['name'].string() 194c1a15399SKieran Bingham s_flags = int(superblock['s_flags']) 195f4efbdafSGlenn Washburn m_flags = int(mnt['mnt']['mnt_flags']) 196663cb634SJackie Liu rd = "ro" if (s_flags & constants.LX_SB_RDONLY) else "rw" 197c1a15399SKieran Bingham 198998ec76bSRitesh Harjani gdb.write("{} {} {} {} {} {}{}{} 0 0\n".format( 199f4efbdafSGlenn Washburn mnt.format_string(), superblock.format_string(), devname, 200998ec76bSRitesh Harjani pathname, fstype, rd, info_opts(FS_INFO, s_flags), 201c1a15399SKieran Bingham info_opts(MNT_INFO, m_flags))) 202c1a15399SKieran Bingham 203494dbe02SStephen Boyd 204c1a15399SKieran BinghamLxMounts() 205821f7440SPeter Griffin 206821f7440SPeter Griffin 207821f7440SPeter Griffinclass LxFdtDump(gdb.Command): 208821f7440SPeter Griffin """Output Flattened Device Tree header and dump FDT blob to the filename 209821f7440SPeter Griffin specified as the command argument. Equivalent to 210821f7440SPeter Griffin 'cat /proc/fdt > fdtdump.dtb' on a running target""" 211821f7440SPeter Griffin 212821f7440SPeter Griffin def __init__(self): 213821f7440SPeter Griffin super(LxFdtDump, self).__init__("lx-fdtdump", gdb.COMMAND_DATA, 214821f7440SPeter Griffin gdb.COMPLETE_FILENAME) 215821f7440SPeter Griffin 216821f7440SPeter Griffin def fdthdr_to_cpu(self, fdt_header): 217821f7440SPeter Griffin 218821f7440SPeter Griffin fdt_header_be = ">IIIIIII" 219821f7440SPeter Griffin fdt_header_le = "<IIIIIII" 220821f7440SPeter Griffin 221821f7440SPeter Griffin if utils.get_target_endianness() == 1: 222821f7440SPeter Griffin output_fmt = fdt_header_le 223821f7440SPeter Griffin else: 224821f7440SPeter Griffin output_fmt = fdt_header_be 225821f7440SPeter Griffin 226821f7440SPeter Griffin return unpack(output_fmt, pack(fdt_header_be, 227821f7440SPeter Griffin fdt_header['magic'], 228821f7440SPeter Griffin fdt_header['totalsize'], 229821f7440SPeter Griffin fdt_header['off_dt_struct'], 230821f7440SPeter Griffin fdt_header['off_dt_strings'], 231821f7440SPeter Griffin fdt_header['off_mem_rsvmap'], 232821f7440SPeter Griffin fdt_header['version'], 233821f7440SPeter Griffin fdt_header['last_comp_version'])) 234821f7440SPeter Griffin 235821f7440SPeter Griffin def invoke(self, arg, from_tty): 236821f7440SPeter Griffin 237821f7440SPeter Griffin if not constants.LX_CONFIG_OF: 238821f7440SPeter Griffin raise gdb.GdbError("Kernel not compiled with CONFIG_OF\n") 239821f7440SPeter Griffin 240821f7440SPeter Griffin if len(arg) == 0: 241821f7440SPeter Griffin filename = "fdtdump.dtb" 242821f7440SPeter Griffin else: 243821f7440SPeter Griffin filename = arg 244821f7440SPeter Griffin 245821f7440SPeter Griffin py_fdt_header_ptr = gdb.parse_and_eval( 246821f7440SPeter Griffin "(const struct fdt_header *) initial_boot_params") 247821f7440SPeter Griffin py_fdt_header = py_fdt_header_ptr.dereference() 248821f7440SPeter Griffin 249821f7440SPeter Griffin fdt_header = self.fdthdr_to_cpu(py_fdt_header) 250821f7440SPeter Griffin 251821f7440SPeter Griffin if fdt_header[0] != constants.LX_OF_DT_HEADER: 252821f7440SPeter Griffin raise gdb.GdbError("No flattened device tree magic found\n") 253821f7440SPeter Griffin 254821f7440SPeter Griffin gdb.write("fdt_magic: 0x{:02X}\n".format(fdt_header[0])) 255821f7440SPeter Griffin gdb.write("fdt_totalsize: 0x{:02X}\n".format(fdt_header[1])) 256821f7440SPeter Griffin gdb.write("off_dt_struct: 0x{:02X}\n".format(fdt_header[2])) 257821f7440SPeter Griffin gdb.write("off_dt_strings: 0x{:02X}\n".format(fdt_header[3])) 258821f7440SPeter Griffin gdb.write("off_mem_rsvmap: 0x{:02X}\n".format(fdt_header[4])) 259821f7440SPeter Griffin gdb.write("version: {}\n".format(fdt_header[5])) 260821f7440SPeter Griffin gdb.write("last_comp_version: {}\n".format(fdt_header[6])) 261821f7440SPeter Griffin 262821f7440SPeter Griffin inf = gdb.inferiors()[0] 263821f7440SPeter Griffin fdt_buf = utils.read_memoryview(inf, py_fdt_header_ptr, 264821f7440SPeter Griffin fdt_header[1]).tobytes() 265821f7440SPeter Griffin 266821f7440SPeter Griffin try: 267821f7440SPeter Griffin f = open(filename, 'wb') 268494dbe02SStephen Boyd except gdb.error: 269821f7440SPeter Griffin raise gdb.GdbError("Could not open file to dump fdt") 270821f7440SPeter Griffin 271821f7440SPeter Griffin f.write(fdt_buf) 272821f7440SPeter Griffin f.close() 273821f7440SPeter Griffin 274821f7440SPeter Griffin gdb.write("Dumped fdt blob to " + filename + "\n") 275821f7440SPeter Griffin 276494dbe02SStephen Boyd 277821f7440SPeter GriffinLxFdtDump() 278