Skip to content

Commit

Permalink
gdb/fs: use Value and Protocol for easy access and hinting
Browse files Browse the repository at this point in the history
Signed-off-by: xuxingliang <[email protected]>
  • Loading branch information
XuNeo authored and xiaoxiang781216 committed Nov 24, 2024
1 parent a59a28d commit 9f9cc7e
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 55 deletions.
111 changes: 57 additions & 54 deletions tools/gdb/nuttxgdb/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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 ""

Expand Down Expand Up @@ -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]:
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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(
Expand All @@ -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
Expand Down Expand Up @@ -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))
Expand All @@ -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:
Expand Down Expand Up @@ -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 + "│ "
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
64 changes: 64 additions & 0 deletions tools/gdb/nuttxgdb/protocols/fs.py
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion tools/gdb/nuttxgdb/protocols/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#
############################################################################

from .fs import FileList
from .value import Value


Expand Down Expand Up @@ -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


Expand Down

0 comments on commit 9f9cc7e

Please sign in to comment.