diff --git a/tools/gdb/nuttxgdb/fs.py b/tools/gdb/nuttxgdb/fs.py index a9c8fd4c5e26e..ea527cbf835e7 100644 --- a/tools/gdb/nuttxgdb/fs.py +++ b/tools/gdb/nuttxgdb/fs.py @@ -22,10 +22,13 @@ import argparse import enum +from typing import Generator, Tuple import gdb from . import utils +from .protocols.fs import File, Inode +from .protocols.thread import Tcb FSNODEFLAG_TYPE_MASK = utils.get_symbol_value("FSNODEFLAG_TYPE_MASK") @@ -69,7 +72,7 @@ class InodeType(enum.Enum): UNKNOWN = 12 -def get_inode_name(inode): +def get_inode_name(inode: Inode): if not inode: return "" @@ -100,28 +103,28 @@ def special_inode_name(inode): if name := special_inode_name(inode): return name - ptr = inode["i_name"].cast(gdb.lookup_type("char").pointer()) + ptr = inode.i_name.cast(gdb.lookup_type("char").pointer()) return ptr.string() -def inode_getpath(inode): +def inode_getpath(inode: Inode): """get path fron inode""" if not inode: return "" name = get_inode_name(inode) - if inode["i_parent"]: - return inode_getpath(inode["i_parent"]) + "/" + name + if inode.i_parent: + return inode_getpath(inode.i_parent) + "/" + name return name -def inode_gettype(inode) -> InodeType: +def inode_gettype(inode: Inode) -> InodeType: if not inode: return InodeType.UNKNOWN - type = int(inode["i_flags"] & FSNODEFLAG_TYPE_MASK) + type = int(inode.i_flags & FSNODEFLAG_TYPE_MASK) # check if it's a valid type in InodeType if type in [e.value for e in InodeType]: @@ -130,11 +133,11 @@ def inode_gettype(inode) -> InodeType: return InodeType.UNKNOWN -def get_file(tcb, fd): - group = tcb["group"] - filelist = group["tg_filelist"] - fl_files = filelist["fl_files"] - fl_rows = filelist["fl_rows"] +def get_file(tcb: Tcb, fd): + group = tcb.group + filelist = group.tg_filelist + fl_files = filelist.fl_files + fl_rows = filelist.fl_rows row = fd // CONFIG_NFILE_DESCRIPTORS_PER_BLOCK col = fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK @@ -145,28 +148,28 @@ def get_file(tcb, fd): return fl_files[row][col] -def foreach_inode(root=None, path=""): - node = root or gdb.parse_and_eval("g_root_inode")["i_child"] +def foreach_inode(root=None, path="") -> Generator[Tuple[Inode, str], None, None]: + node: Inode = root or utils.parse_and_eval("g_root_inode").i_child while node: newpath = path + "/" + get_inode_name(node) yield node, newpath - if node["i_child"]: - yield from foreach_inode(node["i_child"], newpath) - node = node["i_peer"] + if node.i_child: + yield from foreach_inode(node.i_child, newpath) + node = node.i_peer -def foreach_file(tcb): +def foreach_file(tcb: Tcb): """Iterate over all file descriptors in a tcb""" - group = tcb["group"] - filelist = group["tg_filelist"] - fl_files = filelist["fl_files"] - fl_rows = filelist["fl_rows"] + group = tcb.group + filelist = group.tg_filelist + fl_files = filelist.fl_files + fl_rows = filelist.fl_rows for row in range(fl_rows): for col in range(CONFIG_NFILE_DESCRIPTORS_PER_BLOCK): file = fl_files[row][col] - if not file or not file["f_inode"]: + if not file or not file.f_inode: continue fd = row * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + col @@ -181,17 +184,17 @@ def __init__(self): super().__init__("fdinfo", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION) self.total_fd_count = 0 - def print_file_info(self, fd, file, formatter): + def print_file_info(self, fd, file: File, formatter: str): backtrace_formatter = "{0:<5} {1:<36} {2}" - oflags = int(file["f_oflags"]) - pos = int(file["f_pos"]) - path = inode_getpath(file["f_inode"]) + oflags = int(file.f_oflags) + pos = int(file.f_pos) + path = inode_getpath(file.f_inode) output = [] if CONFIG_FS_BACKTRACE: backtrace = utils.Backtrace( - utils.ArrayIterator(file["f_backtrace"]), formatter=backtrace_formatter + utils.ArrayIterator(file.f_backtrace), formatter=backtrace_formatter ) output.append( @@ -215,7 +218,7 @@ def print_file_info(self, fd, file, formatter): def print_fdinfo_by_tcb(self, tcb): """print fdlist from tcb""" gdb.write(f"PID: {tcb['pid']}\n") - group = tcb["group"] + group = tcb.group if not group: return @@ -290,7 +293,7 @@ def invoke(self, args, from_tty): lambda x: inode_gettype(x[0]) == InodeType.MOUNTPT, foreach_inode() ) for node, path in nodes: - statfs = node["u"]["i_mops"]["statfs"] + statfs = node.u.i_mops.statfs funcname = gdb.block_for_pc(int(statfs)).function.print_name fstype = funcname.split("_")[0] gdb.write(" %s type %s\n" % (path, fstype)) @@ -306,7 +309,7 @@ def __init__(self): def get_root_inode(self, addr_or_expr): try: - return gdb.Value(int(addr_or_expr, 0)).cast( + return utils.Value(int(addr_or_expr, 0)).cast( gdb.lookup_type("struct inode").pointer() ) except ValueError: @@ -341,11 +344,11 @@ def parse_arguments(self, argv): ), } - def print_inode_info(self, node, level, prefix): + def print_inode_info(self, node: Inode, level, prefix): if level > self.level: return while node: - if node["i_peer"]: + if node.i_peer: initial_indent = prefix + "├── " subsequent_indent = prefix + "│ " newprefix = prefix + "│ " @@ -355,41 +358,41 @@ def print_inode_info(self, node, level, prefix): newprefix = prefix + " " gdb.write( "%s [%s], %s, %s\n" - % (initial_indent, get_inode_name(node), node["i_ino"], node) + % (initial_indent, get_inode_name(node), node.i_ino, node) ) gdb.write( "%s i_crefs: %s, i_flags: %s, i_private: %s\n" % ( subsequent_indent, - node["i_crefs"], - node["i_flags"], - node["i_private"], + node.i_crefs, + node.i_flags, + node.i_private, ) ) if CONFIG_PSEUDOFS_FILE: - gdb.write("%s i_size: %s\n" % (subsequent_indent, node["i_size"])) + gdb.write("%s i_size: %s\n" % (subsequent_indent, node.i_size)) if CONFIG_PSEUDOFS_ATTRIBUTES: gdb.write( "%s i_mode: %s, i_owner: %s, i_group: %s\n" % ( subsequent_indent, - node["i_mode"], - node["i_owner"], - node["i_group"], + node.i_mode, + node.i_owner, + node.i_group, ) ) gdb.write( "%s i_atime: %s, i_mtime: %s, i_ctime: %s\n" % ( subsequent_indent, - node["i_atime"], - node["i_mtime"], - node["i_ctime"], + node.i_atime, + node.i_mtime, + node.i_ctime, ) ) - if node["i_child"]: - self.print_inode_info(node["i_child"], level + 1, newprefix) - node = node["i_peer"] + if node.i_child: + self.print_inode_info(node.i_child, level + 1, newprefix) + node = node.i_peer def diagnose(self, *args, **kwargs): output = gdb.execute("foreach inode", to_string=True) @@ -419,13 +422,13 @@ def __init__(self): self.total_size = 0 self.block_count = 0 - def shm_filter(self, node, path): + def shm_filter(self, node: Inode, path): if inode_gettype(node) != InodeType.SHM: return - obj = node["i_private"].cast(gdb.lookup_type("struct shmfs_object_s").pointer()) - length = obj["length"] - paddr = obj["paddr"] + obj = node.i_private.cast(gdb.lookup_type("struct shmfs_object_s").pointer()) + length = obj.length + paddr = obj.paddr print(f" {path} memsize: {length}, paddr: {paddr}") self.total_size += length / 1024 @@ -447,11 +450,11 @@ def invoke(self, args, from_tty): self.block_count = 0 nodes = filter(lambda x: inode_gettype(x[0]) == InodeType.SHM, foreach_inode()) for node, path in nodes: - obj = node["i_private"].cast( + obj = node.i_private.cast( gdb.lookup_type("struct shmfs_object_s").pointer() ) - length = obj["length"] - paddr = obj["paddr"] + length = obj.length + paddr = obj.paddr print(f" {path} memsize: {length}, paddr: {paddr}") self.total_size += length / 1024 diff --git a/tools/gdb/nuttxgdb/protocols/fs.py b/tools/gdb/nuttxgdb/protocols/fs.py new file mode 100644 index 0000000000000..aa67bb9245e34 --- /dev/null +++ b/tools/gdb/nuttxgdb/protocols/fs.py @@ -0,0 +1,64 @@ +############################################################################ +# tools/gdb/nuttxgdb/protocols/fs.py +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +from .value import Value + + +class File(Value): + """struct file""" + + f_oflags: Value + f_refs: Value + f_pos: Value + f_inode: Value + f_priv: Value + f_tag_fdsan: Value + f_tag_fdcheck: Value + f_backtrace: Value + locked: Value + + +class Inode(Value): + """struct inode""" + + i_parent: Value + i_peer: Value + i_child: Value + i_crefs: Value + i_flags: Value + u: Value + i_ino: Value + i_size: Value + i_mode: Value + i_owner: Value + i_group: Value + i_atime: Value + i_mtime: Value + i_ctime: Value + i_private: Value + i_name: Value + + +class FileList(Value): + """struct filelist_s""" + + fl_rows: Value + fl_crefs: Value + fl_files: Value diff --git a/tools/gdb/nuttxgdb/protocols/thread.py b/tools/gdb/nuttxgdb/protocols/thread.py index 5cb05bb032c43..9572b0feaaf59 100644 --- a/tools/gdb/nuttxgdb/protocols/thread.py +++ b/tools/gdb/nuttxgdb/protocols/thread.py @@ -18,6 +18,7 @@ # ############################################################################ +from .fs import FileList from .value import Value @@ -49,7 +50,7 @@ class Group(Value): tg_envp: Value tg_envc: Value itimer: Value - tg_filelist: Value + tg_filelist: FileList tg_mm_map: Value