def gendisk_name(gendisk: gdb.Value) -> str: """ Returns the name of the provided block device. This method evaluates the block device and returns the name, including partition number, if applicable. Args: gendisk: A ``struct gendisk`` or ``struct hd_struct`` for which to return the name. The value must be of type ``struct gendisk`` or ``struct hd_struct``. Returns: :obj:`str`: The name of the block device Raises: :obj:`.InvalidArgumentError`: gendisk does not describe a ``struct gendisk`` or ``struct hd_struct`` """ if gendisk.type.code == gdb.TYPE_CODE_PTR: gendisk = gendisk.dereference() if get_basic_type(gendisk.type) == types.gendisk_type: return gendisk['disk_name'].string() if get_basic_type(gendisk.type) == types.hd_struct_type: parent = dev_to_gendisk(part_to_dev(gendisk)['parent']) return "{}{:d}".format(gendisk_name(parent), int(gendisk['partno'])) raise InvalidArgumentError("expected {} or {}, not {}".format( types.gendisk_type, types.hd_struct_type, gendisk.type.unqualified()))
def klist_for_each(klist: gdb.Value) -> Iterable[gdb.Value]: """ Iterate over a klist and yield each node Args: klist: The list to iterate. The value must be of type ``struct klist`` or ``struct klist *``. Yields: :obj:`gdb.Value`: The next node in the list. The value is of type ``struct klist_node``. """ if klist.type == types.klist_type.pointer(): klist = klist.dereference() elif klist.type != types.klist_type: raise InvalidArgumentError( "klist must be gdb.Value representing 'struct klist' or 'struct klist *' not {}" .format(klist.type)) if klist.type is not types.klist_type: types.override('struct klist', klist.type) for node in list_for_each_entry(klist['k_list'], types.klist_node_type, 'n_node'): if node['n_klist'] != klist.address: raise KlistCorruptedError("Corrupted") yield node
def decode_uuid_t(value: gdb.Value) -> uuid.UUID: """ Decode a Linux kernel uuid_t into a Python-style UUID object Args: value (gdb.Value): The uuid_t to be decoded Returns: uuid.UUID: The UUID object that describes the value Raises: TypeError: value is not gdb.Value<uuid_t> """ if not isinstance(value, gdb.Value): raise TypeError("value must be gdb.Value") if value.type != types.uuid_t_type: if (value.type.code == gdb.TYPE_CODE_PTR and value.type.target() == types.uuid_t_type): value = value.dereference() else: raise TypeError("value must describe a uuid_t") if struct_has_member(types.uuid_t_type, 'b'): member = 'b' else: member = '__u_bits' return decode_uuid(value[member])
def make_node_iterator(node_ptr: gdb.Value): """ """ # Yield nodes, from left to right while node_ptr != 0: node = node_ptr.dereference() node_ptr = node['next'] yield node['data']
def _to_ast_ptr(value: gdb.Value) -> gdb.Value: if value.type.code == gdb.TYPE_CODE_PTR: if value.type.target().name == "ast_t": return value else: return _to_ast_ptr(value.dereference()) elif value.type.code == gdb.TYPE_CODE_TYPEDEF and value.type.name == "ast_ptr_t": return value raise ValueError
def show_one_mount(self, mnt: gdb.Value, args: argparse.Namespace) -> None: if mnt.type.code == gdb.TYPE_CODE_PTR: mnt = mnt.dereference() flags = "" if args.f: flags = " ({})".format(mount_flags(mnt)) path = d_path(mnt, mount_root(mnt)) if args.v: print("{:016x} {:016x} {:<10} {:<16} {}" .format(int(mnt.address), int(mount_super(mnt)), mount_fstype(mnt), mount_device(mnt), path)) else: print("{} on {} type {}{}" .format(mount_device(mnt), path, mount_fstype(mnt), flags))
def list_for_each(list_head: gdb.Value, include_head: bool = False, reverse: bool = False, print_broken_links: bool = True, exact_cycles: bool = False) -> Iterator[gdb.Value]: """ Iterate over a list and yield each node Args: list_head: The list to iterate. The value must be of type ``struct list_head`` or ``struct list_head *``. include_head (optional): Include the head of the list in iteration - useful for lists with no anchors reverse (optional): Iterate the list in reverse order (follow the ``prev`` links) print_broken_links (optional): Print warnings about broken links exact_cycles (optional): Detect and raise an exception if a cycle is detected in the list Yields: gdb.Value: The next node in the list. The value is of type ``struct list_head``. Raises: :obj:`.CorruptListError`: the list is corrupted :obj:`.ListCycleError`: the list contains cycles :obj:`BufferError`: portions of the list cannot be read :obj:`gdb.NotAvailableError`: The target value is not available. """ pending_exception = None if not isinstance(list_head, gdb.Value): raise ArgumentTypeError('list_head', list_head, gdb.Value) if list_head.type == types.list_head_type.pointer(): list_head = list_head.dereference() elif list_head.type != types.list_head_type: raise UnexpectedGDBTypeError('list_head', list_head, types.list_head_type) if list_head.type is not types.list_head_type: types.override('struct list_head', list_head.type) fast = None if int(list_head.address) == 0: raise CorruptListError("list_head is NULL pointer.") next_ = 'next' prev_ = 'prev' if reverse: next_ = 'prev' prev_ = 'next' if exact_cycles: visited: Set[int] = set() if include_head: yield list_head try: nxt = list_head[next_] prev = list_head if int(nxt) == 0: raise CorruptListError("{} pointer is NULL".format(next_)) node = nxt.dereference() except gdb.error as e: raise BufferError("Failed to read list_head {:#x}: {}".format( int(list_head.address), str(e))) from e last_good_addr = None while node.address != list_head.address: if exact_cycles: if int(node.address) in visited: raise ListCycleError("Cycle in list detected.") visited.add(int(node.address)) try: if int(prev.address) != int(node[prev_]): error = f"broken {prev_} link {int(prev.address):#x} " error += f"-{next_}-> {int(node.address):#x} " error += f"-{prev_}-> {int(node[prev_]):#x}" pending_exception = CorruptListError(error) if print_broken_links: print(error) # broken prev link means there might be a cycle that # does not include the initial head, so start detecting # cycles if not exact_cycles and fast is None: fast = node nxt = node[next_] # only yield after trying to read something from the node, no # point in giving out bogus list elements yield node except gdb.error as e: if last_good_addr is not None: last_good_str = f"0x{last_good_addr:x}" else: last_good_str = "(none)" raise BufferError( f"Failed to read list_head 0x{int(node.address):x} " f"in list 0x{int(list_head.address):x}, last good " f"list_head {last_good_str}: {str(e)}") from e try: if fast is not None: # are we detecting cycles? advance fast 2 times and compare # each with our current node (Floyd's Tortoise and Hare # algorithm) for i in range(2): # pylint: disable=unused-variable fast = fast[next_].dereference() if int(node.address) == int(fast.address): raise ListCycleError("Cycle in list detected.") except gdb.error: # we hit an unreadable element, so just stop detecting cycles # and the slow iterator will hit it as well fast = None prev = node if int(nxt) == 0: raise CorruptListError("{} -> {} pointer is NULL".format( node.address, next_)) last_good_addr = int(node.address) node = nxt.dereference() if pending_exception is not None: # The pylint error seems to think we'll raise None here raise pending_exception # pylint: disable=raising-bad-type