Example #1
0
def rbtree_postorder_for_each(root: gdb.Value) -> Iterable[gdb.Value]:
    """
    Iterate over nodes of a rooted RB tree in post-order fashion

    Args:
        root: The tree to iterate.  The value must be of type
            ``struct rb_root`` or ``struct rb_root *``.

    Yields:
        gdb.Value: The next node of the tree. The value is
        of type ``struct rb_node``.

    Raises:
        :obj:`.CorruptTreeError`: the list is corrupted
    """
    if not isinstance(root, gdb.Value):
        raise ArgumentTypeError('root', root, gdb.Value)
    if root.type == types.rb_root_type.pointer():
        root = root.dereference()
    elif root.type != types.rb_root_type:
        raise UnexpectedGDBTypeError('root', root, types.rb_root_type)

    if root.type is not types.rb_root_type:
        types.override('struct rb_root', root.type)

    if int(root.address) == 0:
        raise CorruptTreeError("root is NULL pointer")

    node = _rb_left_deepest_node(root['rb_node'])

    while node is not None:
        yield node.dereference()
        node = _rb_next_postorder(node)
Example #2
0
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])
Example #3
0
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
Example #4
0
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()))
Example #5
0
def container_of(val: gdb.Value, gdbtype: gdb.Type, member: str) -> gdb.Value:
    """
    Returns an object that contains the specified object at the given
    offset.

    Args:
        val (gdb.Value): The value to be converted.  It can refer to an
            allocated structure or a pointer.
        gdbtype (gdb.Type): The type of the object that will be generated
        member (str):
            The name of the member in the target struct that contains `val`.

    Returns:
        gdb.Value<gdbtype>: The converted object, of the type specified by
            the caller.
    Raises:
        TypeError: val is not a gdb.Value
    """
    if not isinstance(val, gdb.Value):
        raise ArgumentTypeError('val', val, gdb.Value)
    if not isinstance(gdbtype, gdb.Type):
        raise ArgumentTypeError('gdbtype', gdbtype, gdb.Type)
    charp = types.char_p_type
    if val.type.code != gdb.TYPE_CODE_PTR:
        val = val.address
    offset = offsetof(gdbtype, member)
    return (val.cast(charp) - offset).cast(gdbtype.pointer()).dereference()
Example #6
0
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
Example #8
0
def print_icolumn_type(col: gdb.Value) -> str:
    obj_type: gdb.Type = col.dynamic_type
    obj_casted: gdb.Value = col.cast(obj_type)

    if obj_type == t_col_array:
        offsets: gdb.Value = gdb.dereference(obj_casted["offsets"]).cast(t_col_offsets)["data"]

        start, end, _= get_podarray_bounds(offsets)

        nested_printed: str = print_icolumn_type(gdb.dereference(obj_casted["data"]))

        return "ColumnArray[size: {}, {}]".format(end - start, nested_printed)
    elif obj_type == t_col_const:
        data: gdb.Value = gdb.dereference(obj_casted["data"])
        nested_printed: str = print_icolumn_type(data)

        return "ColumnConst[size: {}, {}]".format(obj_casted["s"], nested_printed)
    elif obj_type == t_col_lc:
        dictionary: gdb.Value = obj_casted["dictionary"]
        index: gdb.Value = obj_casted["idx"]

        size_of_index_type: int = int(index["size_of_type"])

        index_type: str = "UInt8"

        if size_of_index_type == t_uint16.sizeof:
            index_type = "UInt16"
        elif size_of_index_type == t_uint32.sizeof:
            index_type = "UInt32"
        else:
            index_type = "UInt64"

        nested_col: gdb.Value = gdb.dereference(
            gdb.dereference(dictionary["column_unique"])["column_holder"])

        nested_printed: str = print_icolumn_type(nested_col)

        return "ColumnLowCardinality[index: {}, {}]".format(index_type, nested_printed)
    elif obj_type == t_col_nullable:
        col_nested: gdb.Value = gdb.dereference(obj_casted["nested_column"])
        nested_printed: str = print_icolumn_type(col_nested)

        return "ColumnNullable[{}]".format(nested_printed)
    elif obj_type == t_col_vector:
        nested_type = obj_casted.template_argument(0)
        start, end, _ = get_podarray_bounds(obj_casted["data"])

        return "ColumnArray[size: {}, {}]".format(nested_type, end - start)
    else:
        return "NI {}".format(obj_type)
    def invoke(self, obj: gdb.Value, type: gdb.Value) -> gdb.Value:
        try:
            type_string = type.string()
        except gdb.error:
            raise gdb.error('the second argument must be literal string')

        try:
            dispatch = self._dispatch[parse_type(obj)]
        except KeyError:
            raise gdb.error(
                'the first argument must be of supported types: interface, literal address, void*'
            )

        return dispatch(obj, type_string)
Example #10
0
    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))
Example #11
0
    def children(self):
        start = int(self.data_ptr) & ~1

        hashes = self.hash_uint_size * self.capacity
        align = self.pair_type_size
        len_rounded_up = ((((
            (hashes + align) % self.modulo - 1) % self.modulo) & ~(
                (align - 1) % self.modulo)) % self.modulo -
                          hashes) % self.modulo

        pairs_offset = hashes + len_rounded_up
        pairs_start = Value(start + pairs_offset).cast(
            self.pair_type.pointer())

        for index in range(self.size):
            table_index = self.valid_indices[index]
            idx = table_index & self.capacity_mask
            element = (pairs_start + idx).dereference()
            if self.show_values:
                yield "key{}".format(index), element[ZERO_FIELD]
                yield "val{}".format(index), element[FIRST_FIELD]
            else:
                yield "[{}]".format(index), element[ZERO_FIELD]
Example #12
0
    def __call__(self, value: gdb.Value):
        """  """

        # Get basic typename
        typename = self.get_basic_type(value.type)
        if typename is None: return None

        # Match against lookup regex
        match = self.lookup_regex.match(typename)
        if match is None: return None

        if value.type.code == gdb.TYPE_CODE_REF:
            if hasattr(gdb.Value, 'referenced_value'):
                value = value.referenced_value()

        # Match against lookup table
        try:
            basename = match.group(1)
            subprinter = self.lookup_table[basename]
            return subprinter(value)
        except KeyError:
            # Printer not found, return None
            return None
def cast_interface(obj: gdb.Value, type: str) -> gdb.Value:
    gdb_type = gdb.lookup_type(type)
    return obj.cast(gdb_type)
def cast_address(obj: gdb.Value, type: str) -> gdb.Value:
    gdb_type = gdb.lookup_type(type).pointer()
    return obj.cast(gdb_type)
Example #15
0
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
Example #16
0
 def string_value(self, value: gdb.Value) -> str:
     return value.string()
Example #17
0
 def pointer_to_ast(self, pointer: gdb.Value) -> gdb.Value:
     return pointer.cast(gdb.lookup_type("ast_t").pointer())