0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 import gdb
0015 from linux import constants
0016 from linux import utils
0017 from linux import tasks
0018 from linux import lists
0019 from struct import *
0020
0021
0022 class LxCmdLine(gdb.Command):
0023 """ Report the Linux Commandline used in the current kernel.
0024 Equivalent to cat /proc/cmdline on a running target"""
0025
0026 def __init__(self):
0027 super(LxCmdLine, self).__init__("lx-cmdline", gdb.COMMAND_DATA)
0028
0029 def invoke(self, arg, from_tty):
0030 gdb.write(gdb.parse_and_eval("saved_command_line").string() + "\n")
0031
0032
0033 LxCmdLine()
0034
0035
0036 class LxVersion(gdb.Command):
0037 """ Report the Linux Version of the current kernel.
0038 Equivalent to cat /proc/version on a running target"""
0039
0040 def __init__(self):
0041 super(LxVersion, self).__init__("lx-version", gdb.COMMAND_DATA)
0042
0043 def invoke(self, arg, from_tty):
0044
0045 gdb.write(gdb.parse_and_eval("(char *)linux_banner").string())
0046
0047
0048 LxVersion()
0049
0050
0051
0052
0053
0054
0055 def get_resources(resource, depth):
0056 while resource:
0057 yield resource, depth
0058
0059 child = resource['child']
0060 if child:
0061 for res, deep in get_resources(child, depth + 1):
0062 yield res, deep
0063
0064 resource = resource['sibling']
0065
0066
0067 def show_lx_resources(resource_str):
0068 resource = gdb.parse_and_eval(resource_str)
0069 width = 4 if resource['end'] < 0x10000 else 8
0070
0071 for res, depth in get_resources(resource['child'], 0):
0072 start = int(res['start'])
0073 end = int(res['end'])
0074 gdb.write(" " * depth * 2 +
0075 "{0:0{1}x}-".format(start, width) +
0076 "{0:0{1}x} : ".format(end, width) +
0077 res['name'].string() + "\n")
0078
0079
0080 class LxIOMem(gdb.Command):
0081 """Identify the IO memory resource locations defined by the kernel
0082
0083 Equivalent to cat /proc/iomem on a running target"""
0084
0085 def __init__(self):
0086 super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA)
0087
0088 def invoke(self, arg, from_tty):
0089 return show_lx_resources("iomem_resource")
0090
0091
0092 LxIOMem()
0093
0094
0095 class LxIOPorts(gdb.Command):
0096 """Identify the IO port resource locations defined by the kernel
0097
0098 Equivalent to cat /proc/ioports on a running target"""
0099
0100 def __init__(self):
0101 super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA)
0102
0103 def invoke(self, arg, from_tty):
0104 return show_lx_resources("ioport_resource")
0105
0106
0107 LxIOPorts()
0108
0109
0110
0111
0112
0113 def info_opts(lst, opt):
0114 opts = ""
0115 for key, string in lst.items():
0116 if opt & key:
0117 opts += string
0118 return opts
0119
0120
0121 FS_INFO = {constants.LX_SB_SYNCHRONOUS: ",sync",
0122 constants.LX_SB_MANDLOCK: ",mand",
0123 constants.LX_SB_DIRSYNC: ",dirsync",
0124 constants.LX_SB_NOATIME: ",noatime",
0125 constants.LX_SB_NODIRATIME: ",nodiratime"}
0126
0127 MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid",
0128 constants.LX_MNT_NODEV: ",nodev",
0129 constants.LX_MNT_NOEXEC: ",noexec",
0130 constants.LX_MNT_NOATIME: ",noatime",
0131 constants.LX_MNT_NODIRATIME: ",nodiratime",
0132 constants.LX_MNT_RELATIME: ",relatime"}
0133
0134 mount_type = utils.CachedType("struct mount")
0135 mount_ptr_type = mount_type.get_type().pointer()
0136
0137
0138 class LxMounts(gdb.Command):
0139 """Report the VFS mounts of the current process namespace.
0140
0141 Equivalent to cat /proc/mounts on a running target
0142 An integer value can be supplied to display the mount
0143 values of that process namespace"""
0144
0145 def __init__(self):
0146 super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA)
0147
0148
0149
0150
0151 def invoke(self, arg, from_tty):
0152 argv = gdb.string_to_argv(arg)
0153 if len(argv) >= 1:
0154 try:
0155 pid = int(argv[0])
0156 except gdb.error:
0157 raise gdb.GdbError("Provide a PID as integer value")
0158 else:
0159 pid = 1
0160
0161 task = tasks.get_task_by_pid(pid)
0162 if not task:
0163 raise gdb.GdbError("Couldn't find a process with PID {}"
0164 .format(pid))
0165
0166 namespace = task['nsproxy']['mnt_ns']
0167 if not namespace:
0168 raise gdb.GdbError("No namespace for current process")
0169
0170 gdb.write("{:^18} {:^15} {:>9} {} {} options\n".format(
0171 "mount", "super_block", "devname", "pathname", "fstype"))
0172
0173 for vfs in lists.list_for_each_entry(namespace['list'],
0174 mount_ptr_type, "mnt_list"):
0175 devname = vfs['mnt_devname'].string()
0176 devname = devname if devname else "none"
0177
0178 pathname = ""
0179 parent = vfs
0180 while True:
0181 mntpoint = parent['mnt_mountpoint']
0182 pathname = utils.dentry_name(mntpoint) + pathname
0183 if (parent == parent['mnt_parent']):
0184 break
0185 parent = parent['mnt_parent']
0186
0187 if (pathname == ""):
0188 pathname = "/"
0189
0190 superblock = vfs['mnt']['mnt_sb']
0191 fstype = superblock['s_type']['name'].string()
0192 s_flags = int(superblock['s_flags'])
0193 m_flags = int(vfs['mnt']['mnt_flags'])
0194 rd = "ro" if (s_flags & constants.LX_SB_RDONLY) else "rw"
0195
0196 gdb.write("{} {} {} {} {} {}{}{} 0 0\n".format(
0197 vfs.format_string(), superblock.format_string(), devname,
0198 pathname, fstype, rd, info_opts(FS_INFO, s_flags),
0199 info_opts(MNT_INFO, m_flags)))
0200
0201
0202 LxMounts()
0203
0204
0205 class LxFdtDump(gdb.Command):
0206 """Output Flattened Device Tree header and dump FDT blob to the filename
0207 specified as the command argument. Equivalent to
0208 'cat /proc/fdt > fdtdump.dtb' on a running target"""
0209
0210 def __init__(self):
0211 super(LxFdtDump, self).__init__("lx-fdtdump", gdb.COMMAND_DATA,
0212 gdb.COMPLETE_FILENAME)
0213
0214 def fdthdr_to_cpu(self, fdt_header):
0215
0216 fdt_header_be = ">IIIIIII"
0217 fdt_header_le = "<IIIIIII"
0218
0219 if utils.get_target_endianness() == 1:
0220 output_fmt = fdt_header_le
0221 else:
0222 output_fmt = fdt_header_be
0223
0224 return unpack(output_fmt, pack(fdt_header_be,
0225 fdt_header['magic'],
0226 fdt_header['totalsize'],
0227 fdt_header['off_dt_struct'],
0228 fdt_header['off_dt_strings'],
0229 fdt_header['off_mem_rsvmap'],
0230 fdt_header['version'],
0231 fdt_header['last_comp_version']))
0232
0233 def invoke(self, arg, from_tty):
0234
0235 if not constants.LX_CONFIG_OF:
0236 raise gdb.GdbError("Kernel not compiled with CONFIG_OF\n")
0237
0238 if len(arg) == 0:
0239 filename = "fdtdump.dtb"
0240 else:
0241 filename = arg
0242
0243 py_fdt_header_ptr = gdb.parse_and_eval(
0244 "(const struct fdt_header *) initial_boot_params")
0245 py_fdt_header = py_fdt_header_ptr.dereference()
0246
0247 fdt_header = self.fdthdr_to_cpu(py_fdt_header)
0248
0249 if fdt_header[0] != constants.LX_OF_DT_HEADER:
0250 raise gdb.GdbError("No flattened device tree magic found\n")
0251
0252 gdb.write("fdt_magic: 0x{:02X}\n".format(fdt_header[0]))
0253 gdb.write("fdt_totalsize: 0x{:02X}\n".format(fdt_header[1]))
0254 gdb.write("off_dt_struct: 0x{:02X}\n".format(fdt_header[2]))
0255 gdb.write("off_dt_strings: 0x{:02X}\n".format(fdt_header[3]))
0256 gdb.write("off_mem_rsvmap: 0x{:02X}\n".format(fdt_header[4]))
0257 gdb.write("version: {}\n".format(fdt_header[5]))
0258 gdb.write("last_comp_version: {}\n".format(fdt_header[6]))
0259
0260 inf = gdb.inferiors()[0]
0261 fdt_buf = utils.read_memoryview(inf, py_fdt_header_ptr,
0262 fdt_header[1]).tobytes()
0263
0264 try:
0265 f = open(filename, 'wb')
0266 except gdb.error:
0267 raise gdb.GdbError("Could not open file to dump fdt")
0268
0269 f.write(fdt_buf)
0270 f.close()
0271
0272 gdb.write("Dumped fdt blob to " + filename + "\n")
0273
0274
0275 LxFdtDump()