From 2bdcad4e9d57926dfd6ef78f2af19f349709a3ba Mon Sep 17 00:00:00 2001 From: xuxingliang Date: Tue, 26 Nov 2024 09:57:42 +0800 Subject: [PATCH 1/2] nxgdb/fs: use default args Instead of storing it to self Signed-off-by: xuxingliang --- tools/pynuttx/nxgdb/fs.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/tools/pynuttx/nxgdb/fs.py b/tools/pynuttx/nxgdb/fs.py index 8ecf5017b67af..718c47a4eeacd 100644 --- a/tools/pynuttx/nxgdb/fs.py +++ b/tools/pynuttx/nxgdb/fs.py @@ -305,7 +305,6 @@ class ForeachInode(gdb.Command): def __init__(self): super().__init__("foreach inode", gdb.COMMAND_USER) - self.level = 4096 def get_root_inode(self, addr_or_expr): try: @@ -321,7 +320,7 @@ def parse_arguments(self, argv): "-L", "--level", type=int, - default=None, + default=4096, help="Only render the tree to a specific depth", ) parser.add_argument( @@ -335,18 +334,13 @@ def parse_arguments(self, argv): args = parser.parse_args(argv) except SystemExit: return None - return { - "level": args.level if args.level else 4096, - "root_inode": ( - self.get_root_inode(args.addr_or_expr) - if args.addr_or_expr - else utils.gdb_eval_or_none("g_root_inode") - ), - } - def print_inode_info(self, node: Inode, level, prefix): - if level > self.level: + return args + + def print_inode_info(self, node: Inode, level=1, prefix="", maxlevel=4096): + if level > maxlevel: return + while node: if node.i_peer: initial_indent = prefix + "├── " @@ -391,7 +385,7 @@ def print_inode_info(self, node: Inode, level, prefix): ) ) if node.i_child: - self.print_inode_info(node.i_child, level + 1, newprefix) + self.print_inode_info(node.i_child, level + 1, newprefix, maxlevel) node = node.i_peer def diagnose(self, *args, **kwargs): @@ -406,11 +400,16 @@ def diagnose(self, *args, **kwargs): } def invoke(self, args, from_tty): - arg = self.parse_arguments(args.split(" ")) - if not arg: + args = self.parse_arguments(args.split(" ")) + if not args: return - self.level = arg["level"] - self.print_inode_info(arg["root_inode"], 1, "") + + root = ( + self.get_root_inode(args.addr_or_expr) + if args.addr_or_expr + else utils.gdb_eval_or_none("g_root_inode") + ) + self.print_inode_info(root, maxlevel=args.level) class InfoShmfs(gdb.Command): From 2799aa23d8bf8149a98845d772ae18f52e7d6a18 Mon Sep 17 00:00:00 2001 From: xuxingliang Date: Tue, 26 Nov 2024 11:00:26 +0800 Subject: [PATCH 2/2] nxgdb/fs: simplify inode print and add more options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use Inode.__repr__ for print and use single line for all information. Add 'verbose' and 'nodetype' option to show more details and only print specifiy node type like PIPE. Add / to name for pseudodir. Catch memory error when accessing node element. E.g. (gdb) foreach inode --nodetype pipe ├── run/ 0x41a27a50 PSEUDODIR │ ├── bt:bluetoothCS1fd26 0x4530c510 PIPE │ ├── bt:bluetoothCS20 0x42daae40 PIPE │ ├── socketpair0x457fd2e0SC20540 0x44ea27b0 PIPE │ └── tmp/ 0x42dd7cf0 PSEUDODIR │ │ └── usock/ 0x42dd6c10 PSEUDODIR │ │ └── speech.usockHD 0x42dc8270 PIPE │ ├── central_lite.socketCS5e 0x42e1e7b0 PIPE │ ├── central_service_lite.socketSC86 0x432ee6d0 PIPE │ │ └── usock/ 0x43d6ed60 PSEUDODIR │ │ └── speech.usockHD 0x43da2ba0 PIPE │ ├── uv-feature-sockSC8d 0x43540430 PIPE │ ├── uv-miot-sockCS54 0x42e272e0 PIPE │ └── uv-miot-sockSC54 0x42e270b0 PIPE Signed-off-by: xuxingliang --- tools/pynuttx/nxgdb/fs.py | 197 ++++++++++++++++++++++---------------- 1 file changed, 117 insertions(+), 80 deletions(-) diff --git a/tools/pynuttx/nxgdb/fs.py b/tools/pynuttx/nxgdb/fs.py index 718c47a4eeacd..4db3f25e1329e 100644 --- a/tools/pynuttx/nxgdb/fs.py +++ b/tools/pynuttx/nxgdb/fs.py @@ -27,7 +27,7 @@ import gdb from . import utils -from .protocols.fs import File, Inode +from .protocols import fs as p from .protocols.thread import Tcb FSNODEFLAG_TYPE_MASK = utils.get_symbol_value("FSNODEFLAG_TYPE_MASK") @@ -72,55 +72,91 @@ class InodeType(enum.Enum): UNKNOWN = 12 -def get_inode_name(inode: Inode): - if not inode: - return "" - - def special_inode_name(inode): - global g_special_inodes - if not g_special_inodes: - g_special_inodes = {} - for special in ( - "perf", - "timerfd", - "signalfd", - "dir", - "inotify", - "epoll", - "eventfd", - "sock", - ): - value = utils.gdb_eval_or_none(f"g_{special}_inode") - if value: - g_special_inodes[special] = value.address +class Inode(utils.Value, p.Inode): + def __init__(self, obj: gdb.Value | utils.Value): + super().__init__(obj) - for name, value in g_special_inodes.items(): - if value == inode: - return name + def __str__(self) -> str: + name = get_inode_name(self) + type = inode_gettype(self) + return f"{name}{'/' if type == InodeType.PSEUDODIR else ''}{int(self): #x} {type.name}" - return None + def __repr__(self) -> str: + return self.__str__() - if name := special_inode_name(inode): - return name + def details(self) -> str: + details = ( + f"ino: {self.i_ino}, crefs: {self.i_crefs}" + f", flags: {self.i_flags}, private: {self.i_private}" + ) + + if CONFIG_PSEUDOFS_FILE: + details += f", i_size: {self.i_size}" + if CONFIG_PSEUDOFS_ATTRIBUTES: + details += f", i_mode: {self.i_mode}, i_owner: {self.i_owner}, i_group: {self.i_group}" + details += f", i_atime: {self.i_atime}, i_mtime: {self.i_mtime}, i_ctime: {self.i_ctime}" + return details + + @property + def nodetype(self) -> InodeType: + return inode_gettype(self) + + +def get_inode_name(inode: p.Inode): + try: + if not inode: + return "" + + def special_inode_name(inode): + global g_special_inodes + if not g_special_inodes: + g_special_inodes = {} + for special in ( + "perf", + "timerfd", + "signalfd", + "dir", + "inotify", + "epoll", + "eventfd", + "sock", + ): + value = utils.gdb_eval_or_none(f"g_{special}_inode") + if value: + g_special_inodes[special] = value.address + + for name, value in g_special_inodes.items(): + if value == inode: + return name + + return None - ptr = inode.i_name.cast(gdb.lookup_type("char").pointer()) - return ptr.string() + if name := special_inode_name(inode): + return name + ptr = inode.i_name.cast(gdb.lookup_type("char").pointer()) + return ptr.string() + except gdb.MemoryError: + return "" -def inode_getpath(inode: Inode): + +def inode_getpath(inode: p.Inode): """get path fron inode""" - if not inode: - return "" + try: + if not inode: + return "" - name = get_inode_name(inode) + 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 + return name + except gdb.MemoryError: + return "" -def inode_gettype(inode: Inode) -> InodeType: +def inode_gettype(inode: p.Inode) -> InodeType: if not inode: return InodeType.UNKNOWN @@ -148,8 +184,8 @@ def get_file(tcb: Tcb, fd): return fl_files[row][col] -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 +def foreach_inode(root=None, path="") -> Generator[Tuple[p.Inode, str], None, None]: + node: p.Inode = root or utils.parse_and_eval("g_root_inode").i_child while node: newpath = path + "/" + get_inode_name(node) yield node, newpath @@ -184,7 +220,7 @@ def __init__(self): super().__init__("fdinfo", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION) self.total_fd_count = 0 - def print_file_info(self, fd, file: File, formatter: str): + def print_file_info(self, fd, file: p.File, formatter: str): backtrace_formatter = "{0:<5} {1:<36} {2}" oflags = int(file.f_oflags) @@ -323,6 +359,19 @@ def parse_arguments(self, argv): default=4096, help="Only render the tree to a specific depth", ) + parser.add_argument( + "--nodetype", + type=str, + choices=[e.name.lower() for e in InodeType], + default=None, + help="Only show the specific type of inode", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="Show more information", + ) parser.add_argument( "addr_or_expr", type=str, @@ -330,6 +379,7 @@ def parse_arguments(self, argv): default=None, help="set the start inode to be tranversed", ) + try: args = parser.parse_args(argv) except SystemExit: @@ -337,56 +387,34 @@ def parse_arguments(self, argv): return args - def print_inode_info(self, node: Inode, level=1, prefix="", maxlevel=4096): + def print_inode_info( + self, node: Inode, level=1, prefix="", maxlevel=4096, type=None, verbose=False + ): if level > maxlevel: return while node: if node.i_peer: initial_indent = prefix + "├── " - subsequent_indent = prefix + "│ " newprefix = prefix + "│ " else: initial_indent = prefix + "└── " - subsequent_indent = prefix + " " newprefix = prefix + " " - gdb.write( - "%s [%s], %s, %s\n" - % (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, - ) - ) - if CONFIG_PSEUDOFS_FILE: - 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, - ) - ) + + if ( + not type + or node.nodetype == type + or any(n.i_parent == node for n, _ in self.nodes) + ): gdb.write( - "%s i_atime: %s, i_mtime: %s, i_ctime: %s\n" - % ( - subsequent_indent, - node.i_atime, - node.i_mtime, - node.i_ctime, - ) + f"{initial_indent}{node} {node.details() if verbose else ''}\n" ) + if node.i_child: - self.print_inode_info(node.i_child, level + 1, newprefix, maxlevel) - node = node.i_peer + self.print_inode_info( + Inode(node.i_child), level + 1, newprefix, maxlevel, type, verbose + ) + node = Inode(node.i_peer) def diagnose(self, *args, **kwargs): output = gdb.execute("foreach inode", to_string=True) @@ -409,7 +437,16 @@ def invoke(self, args, from_tty): if args.addr_or_expr else utils.gdb_eval_or_none("g_root_inode") ) - self.print_inode_info(root, maxlevel=args.level) + + nodetype = InodeType[args.nodetype.upper()] if args.nodetype else None + if nodetype: + self.nodes = list( + filter(lambda x: inode_gettype(x[0]) == nodetype, foreach_inode(root)) + ) + + self.print_inode_info( + Inode(root), maxlevel=args.level, type=nodetype, verbose=args.verbose + ) class InfoShmfs(gdb.Command): @@ -421,7 +458,7 @@ def __init__(self): self.total_size = 0 self.block_count = 0 - def shm_filter(self, node: Inode, path): + def shm_filter(self, node: p.Inode, path): if inode_gettype(node) != InodeType.SHM: return