This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 06d640a6778c7f9369650246210e4dd3cbb620cd
Author: Gao Jiawei <gaojia...@xiaomi.com>
AuthorDate: Tue Jul 9 11:38:24 2024 +0800

    implement `ps` nx shell utility for ez debugging with GDB
    
    Signed-off-by: Gao Jiawei <gaojia...@xiaomi.com>
---
 tools/gdb/thread.py | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 138 insertions(+)

diff --git a/tools/gdb/thread.py b/tools/gdb/thread.py
index 2e5c9c11f1..bb303561f9 100644
--- a/tools/gdb/thread.py
+++ b/tools/gdb/thread.py
@@ -22,6 +22,8 @@
 
 import gdb
 import utils
+from stack import Stack
+from enum import Enum, auto
 
 UINT16_MAX = 0xFFFF
 SEM_TYPE_MUTEX = 4
@@ -282,6 +284,7 @@ class Nxcontinue(gdb.Command):
         restore_regs()
         gdb.execute("continue")
 
+
 class Nxstep(gdb.Command):
     def __init__(self):
         super(Nxstep, self).__init__("nxstep", gdb.COMMAND_USER)
@@ -290,6 +293,140 @@ class Nxstep(gdb.Command):
         restore_regs()
         gdb.execute("step")
 
+class TaskType(Enum):
+    TASK = 0
+    PTHREAD = 1
+    KTHREAD = 2
+
+class TaskSchedPolicy(Enum):
+    FIFO = 0
+    RR = 1
+    SPORADIC = 2
+
+class TaskState(Enum):
+    Invalid = 0
+    Waiting_Unlock = auto()
+    Ready = auto()
+    if utils.get_symbol_value("CONFIG_SMP"):
+        Assigned = auto()
+    Running = auto()
+    Inactive = auto()
+    Waiting_Semaphore = auto()
+    Waiting_Signal = auto()
+    if not utils.get_symbol_value("CONFIG_DISABLE_MQUEUE") or \
+        not utils.get_symbol_value("CONFIG_DISABLE_MQUEUE_SYSV"):
+        Waiting_MQEmpty = auto()
+        Waiting_MQFull = auto()
+    if utils.get_symbol_value("CONFIG_PAGING"):
+        Waiting_PagingFill = auto()
+    if utils.get_symbol_value("CONFIG_SIG_SIGSTOP_ACTION"):
+        Stopped = auto()
+
+class Ps(gdb.Command):
+    def __init__(self):
+        super(Ps, self).__init__("ps", gdb.COMMAND_USER)
+        self._fmt_wxl = "{0: <{width}}"
+        # By default we align to the right, whcih respects the nuttx foramt
+        self._fmt_wx = "{0: >{width}}"
+
+    def parse_and_show_info(self, tcb):
+        get_macro = lambda x : utils.get_symbol_value(x)
+        eval2str = lambda cls, x : cls(int(x)).name
+        cast2ptr = lambda x, t : x.cast(gdb.lookup_type(t).pointer())
+
+        pid = int(tcb["pid"])
+        group = int(tcb["group"]["tg_pid"])
+        priority = int(tcb["sched_priority"])
+
+        policy = eval2str(TaskSchedPolicy, (tcb["flags"] & 
get_macro("TCB_FLAG_POLICY_MASK")) \
+            >> get_macro("TCB_FLAG_POLICY_SHIFT"))
+
+        task_type = eval2str(TaskType, (tcb["flags"] & 
get_macro("TCB_FLAG_TTYPE_MASK")) \
+            >> get_macro("TCB_FLAG_TTYPE_SHIFT"))
+
+        npx = 'P' if (tcb["flags"] & get_macro("TCB_FLAG_EXIT_PROCESSING")) 
else '-'
+
+        waiter = str(int(cast2ptr(tcb["waitobj"], "mutex_t")["holder"])) \
+        if tcb["waitobj"] and cast2ptr(tcb["waitobj"], "sem_t")["flags"] & 
get_macro("SEM_TYPE_MUTEX") else ""
+        state_and_event = eval2str(TaskState, (tcb["task_state"])) + 
("@Mutex_Holder: " + waiter if waiter else "")
+        state_and_event = state_and_event.split("_")
+
+        # Append a null str here so we don't need to worry
+        # about the number of elements as we only want the first two
+        state, event = state_and_event if len(state_and_event) > 1 else 
state_and_event + [""]
+
+        sigmask = "{0:#0{1}x}".format( \
+            sum([int(tcb["sigprocmask"]['_elem'][i] << i) for i in 
range(get_macro("_SIGSET_NELEM"))]), \
+            get_macro("_SIGSET_NELEM") * 8 + 2 \
+        )[2:] # exclude "0x"
+
+        st = Stack(
+            tcb["name"].string(),
+            hex(tcb["entry"]['pthread']), # should use main?
+            int(tcb["stack_base_ptr"]),
+            int(tcb["stack_alloc_ptr"]),
+            int(tcb["adj_stack_size"]),
+            utils.get_register_byname("sp", tcb),
+            4,)
+
+        stacksz = st._stack_size
+        used = st.max_usage()
+        filled = "{0:.2%}".format(st.max_usage() / st._stack_size)
+
+        cpu = tcb['cpu'] if get_macro("CONFIG_SMP") else 0
+
+        # For a task we need to display its cmdline arguments, while for a 
thread we display
+        # pointers to its entry and argument
+        cmd = ""
+        name = tcb['name'].string()
+
+        if int(tcb["flags"] & get_macro("TCB_FLAG_TTYPE_MASK")) == 
int(get_macro("TCB_FLAG_TTYPE_PTHREAD")):
+            entry = tcb["entry"]["main"]
+            ptcb = cast2ptr(tcb, "struct pthread_tcb_s")
+            arg = ptcb["arg"]
+            cmd = " ".join((name, hex(entry), hex(arg)))
+        else:
+            argv = tcb["group"]["tg_info"]["ta_argv"] + 1
+
+            args = []
+            parg = argv
+            while (parg.dereference()):
+                args.append(parg.dereference().string())
+                parg += 1
+
+            cmd = " ".join([name] + args)
+
+        if not utils.get_symbol_value("CONFIG_SCHED_CPULOAD_NONE"):
+            load = "{0:.1%}".format(int(tcb['ticks']) / 
int(gdb.parse_and_eval("g_cpuload_total")))
+        else:
+            load = "Dis."
+
+        gdb.write(" ".join((
+            self._fmt_wx.format(pid, width=5), self._fmt_wx.format(group, 
width=5), \
+            self._fmt_wx.format(cpu, width=3), \
+            self._fmt_wx.format(priority, width=3), 
self._fmt_wxl.format(policy, width=8), self._fmt_wxl.format(task_type, 
width=7), \
+            self._fmt_wx.format(npx, width=3), self._fmt_wxl.format(state, 
width=8), self._fmt_wxl.format(event, width=9), \
+            self._fmt_wxl.format(sigmask, width=8), \
+            self._fmt_wx.format(stacksz, width=7), self._fmt_wx.format(used, 
width=7), self._fmt_wx.format(filled, width=6), \
+            self._fmt_wx.format(load, width=6), cmd,
+        )))
+        gdb.write("\n")
+
+    def invoke(self, args, from_tty):
+        gdb.write(" ".join((
+            self._fmt_wx.format("PID", width=5), self._fmt_wx.format("GROUP", 
width=5), \
+            self._fmt_wx.format("CPU", width=3), \
+            self._fmt_wx.format("PRI", width=3), 
self._fmt_wxl.format("POLICY", width=8), self._fmt_wxl.format("TYPE", width=7), 
\
+            self._fmt_wx.format("NPX", width=3), self._fmt_wxl.format("STATE", 
width=8), self._fmt_wxl.format("EVENT", width=9), \
+            self._fmt_wxl.format("SIGMASK", 
width=utils.get_symbol_value("_SIGSET_NELEM") * 8), \
+            self._fmt_wx.format("STACK", width=7), self._fmt_wx.format("USED", 
width=7), self._fmt_wx.format("FILLED", width=3), \
+            self._fmt_wx.format("LOAD", width=6), "COMMAND",
+        )))
+        gdb.write("\n")
+
+        for tcb in utils.get_tcbs():
+            self.parse_and_show_info(tcb)
+
 # We can't use a user command to rename continue it will recursion
 
 gdb.execute("define c\n nxcontinue \n end\n")
@@ -302,3 +439,4 @@ Nxinfothreads()
 Nxthread()
 Nxcontinue()
 Nxstep()
+Ps()

Reply via email to