From de5f70b3c807734678ca3484c1caaa3b2379b321 Mon Sep 17 00:00:00 2001 From: xuxingliang Date: Wed, 14 Aug 2024 13:49:56 +0800 Subject: [PATCH] tools/gdb: remove 'Nx' prefix for unique commands 1. Remove Nx prefix for nuttx unique commands. 2. Add docstring for most of the commands in order to show help message. 3. Add 'init_once' method for Memmap command. The prerequisite is checked the moment it's used. Signed-off-by: xuxingliang --- tools/gdb/lists.py | 24 +++++++-------- tools/gdb/memdump.py | 42 ++++++++++++++++--------- tools/gdb/thread.py | 73 ++++++++++++++++++++++++++------------------ 3 files changed, 84 insertions(+), 55 deletions(-) diff --git a/tools/gdb/lists.py b/tools/gdb/lists.py index e0999f9f38b..8e6674681f2 100644 --- a/tools/gdb/lists.py +++ b/tools/gdb/lists.py @@ -218,12 +218,12 @@ def dq_check(dq): gdb.write("dq_queue is consistent: {} node(s)\n".format(nb)) -class Nxlistcheck(gdb.Command): +class ListCheck(gdb.Command): """Verify a list consistency""" def __init__(self): - super(Nxlistcheck, self).__init__( - "listcheck", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION + super(ListCheck, self).__init__( + "list_check", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION ) def invoke(self, arg, from_tty): @@ -240,23 +240,22 @@ class Nxlistcheck(gdb.Command): raise gdb.GdbError("Invalid argument type: {}".format(obj.type)) -Nxlistcheck() - - -class Nxlistforentry(gdb.Command): +class ListForEveryEntry(gdb.Command): """Dump list members for a given list""" def __init__(self): - super(Nxlistforentry, self).__init__( - "listforentry", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION + super(ListForEveryEntry, self).__init__( + "list_for_every_entry", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION ) def invoke(self, arg, from_tty): argv = gdb.string_to_argv(arg) if len(argv) != 3: - gdb.write("listforentry takes three arguments" "head, type, member\n") - gdb.write("eg: listforentry &g_list 'struct type' 'node '\n") + gdb.write( + "list_for_every_entry takes three arguments" "head, type, member\n" + ) + gdb.write("eg: list_for_every_entry &g_list 'struct type' 'node '\n") return i = 0 @@ -268,4 +267,5 @@ class Nxlistforentry(gdb.Command): i += 1 -Nxlistforentry() +ListCheck() +ListForEveryEntry() diff --git a/tools/gdb/memdump.py b/tools/gdb/memdump.py index b179ec8a80f..d04da3afe03 100644 --- a/tools/gdb/memdump.py +++ b/tools/gdb/memdump.py @@ -27,13 +27,6 @@ import gdb from lists import sq_for_every, sq_queue_type from utils import get_long_type, get_symbol_value, lookup_type, read_ulong -try: - import numpy as np - from matplotlib import pyplot as plt -except ImportError: - print("Please install matplotlib and numpy to use this command") - print("pip install matplotlib numpy") - MM_ALLOC_BIT = 0x1 MM_PREVFREE_BIT = 0x2 MM_MASK_BIT = MM_ALLOC_BIT | MM_PREVFREE_BIT @@ -784,6 +777,27 @@ have {i} some backtrace leak, total leak memory is {int(leaksize)} bytes\n" class Memmap(gdb.Command): def __init__(self): super(Memmap, self).__init__("memmap", gdb.COMMAND_USER) + self.initialized = False + + def init_once(self) -> bool: + """ + Return True if all prerequisites are met and perform one-time initialization. + """ + if self.initialized: + return True + + try: + import numpy as np + from matplotlib import pyplot as plt + except ImportError: + print("Please install matplotlib and numpy to use this command") + print("pip install matplotlib numpy") + return False + + self.np = np + self.plt = plt + self.initialized = True + return True def save_memory_map(self, mallinfo, output_file): mallinfo = sorted(mallinfo, key=lambda item: item["addr"]) @@ -791,7 +805,7 @@ class Memmap(gdb.Command): size = mallinfo[-1]["addr"] - start order = math.ceil(size**0.5) - img = np.zeros([order, order]) + img = self.np.zeros([order, order]) for node in mallinfo: addr = node["addr"] @@ -800,7 +814,7 @@ class Memmap(gdb.Command): end_index = start_index + size img.flat[start_index:end_index] = 1 + math.log2(node["sequence"] + 1) - plt.imsave(output_file, img, cmap=plt.get_cmap("Greens")) + self.plt.imsave(output_file, img, cmap=self.plt.get_cmap("Greens")) def allocinfo(self): info = [] @@ -831,16 +845,13 @@ class Memmap(gdb.Command): return args.output def invoke(self, args, from_tty): + if not self.init_once(): + return output_file = self.parse_arguments(args.split(" ")) meminfo = self.allocinfo() self.save_memory_map(meminfo, output_file + ".png") -Memdump() -Memleak() -Memmap() - - class Memfrag(gdb.Command): def __init__(self): super(Memfrag, self).__init__("memfrag", gdb.COMMAND_USER) @@ -899,3 +910,6 @@ class Memfrag(gdb.Command): Memfrag() +Memdump() +Memleak() +Memmap() diff --git a/tools/gdb/thread.py b/tools/gdb/thread.py index de596280d58..2791359b8e5 100644 --- a/tools/gdb/thread.py +++ b/tools/gdb/thread.py @@ -1,8 +1,6 @@ ############################################################################ # tools/gdb/thread.py # -# SPDX-License-Identifier: Apache-2.0 -# # 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 @@ -20,6 +18,7 @@ # ############################################################################ +import argparse from enum import Enum, auto import gdb @@ -36,7 +35,7 @@ def save_regs(): global saved_regs tcbinfo = gdb.parse_and_eval("g_tcbinfo") - if saved_regs is not None: + if saved_regs: return arch = gdb.selected_frame().architecture() saved_regs = [] @@ -53,7 +52,7 @@ def restore_regs(): tcbinfo = gdb.parse_and_eval("g_tcbinfo") global saved_regs - if saved_regs is None: + if not saved_regs: return arch = gdb.selected_frame().architecture() @@ -68,42 +67,50 @@ def restore_regs(): saved_regs = None -class Nxsetregs(gdb.Command): - """ - Set registers to the specified values. - Usage: nxsetregs [regs] +class SetRegs(gdb.Command): + """Set registers to the specified values. + Usage: setregs [regs] - Etc: nxsetregs - nxsetregs g_current_regs[0] - nxsetregs tcb->xcp.regs - Nxsetregs g_pidhash[0].tcb->xcp.regs - - Default regs is g_current_regs[0],if regs is NULL, it will not set registers. + Etc: setregs + setregs tcb->xcp.regs + setregs g_pidhash[0]->xcp.regs + Default regs is tcbinfo_current_regs(),if regs is NULL, it will not set registers. """ def __init__(self): - super(Nxsetregs, self).__init__("nxsetregs", gdb.COMMAND_USER) + super(SetRegs, self).__init__("setregs", gdb.COMMAND_USER) - def invoke(self, args, from_tty): - gdb.execute("set $_current_regs=tcbinfo_running_regs()") - current_regs = gdb.parse_and_eval("$_current_regs") - tcbinfo = gdb.parse_and_eval("g_tcbinfo") - arg = args.split(" ") + def invoke(self, arg, from_tty): + parser = argparse.ArgumentParser( + description="Set registers to the specified values" + ) - if arg[0] != "": - regs = gdb.parse_and_eval(f"{arg[0]}").cast( + parser.add_argument( + "regs", + nargs="?", + default="", + help="The registers to set, use tcbinfo_current_regs() if not specified", + ) + + try: + args = parser.parse_args(gdb.string_to_argv(arg)) + except SystemExit: + return + + if args and args.regs: + regs = gdb.parse_and_eval(f"{args.regs}").cast( utils.lookup_type("char").pointer() ) else: - gdb.execute("set $_current_regs=tcbinfo_current_regs()") - current_regs = gdb.parse_and_eval("$_current_regs") + current_regs = gdb.parse_and_eval("tcbinfo_current_regs()") regs = current_regs.cast(utils.lookup_type("char").pointer()) if regs == 0: gdb.write("regs is NULL\n") return + tcbinfo = gdb.parse_and_eval("g_tcbinfo") save_regs() arch = gdb.selected_frame().architecture() i = 0 @@ -122,6 +129,8 @@ class Nxsetregs(gdb.Command): class Nxinfothreads(gdb.Command): + """Display information of all threads""" + def __init__(self): super(Nxinfothreads, self).__init__("info threads", gdb.COMMAND_USER) @@ -211,6 +220,8 @@ class Nxinfothreads(gdb.Command): class Nxthread(gdb.Command): + """Switch to a specified thread""" + def __init__(self): super(Nxthread, self).__init__("thread", gdb.COMMAND_USER) @@ -237,7 +248,7 @@ class Nxthread(gdb.Command): except gdb.error and UnicodeDecodeError: gdb.write(f"Thread {i}\n") - gdb.execute(f"nxsetregs g_pidhash[{i}]->xcp.regs") + gdb.execute(f"setregs g_pidhash[{i}]->xcp.regs") cmd_arg = "" for cmd in arg[2:]: cmd_arg += cmd + " " @@ -269,7 +280,7 @@ class Nxthread(gdb.Command): except gdb.error and UnicodeDecodeError: gdb.write(f"Thread {i}\n") - gdb.execute(f"nxsetregs g_pidhash[{i}]->xcp.regs") + gdb.execute(f"setregs g_pidhash[{i}]->xcp.regs") gdb.execute(f"{cmd}\n") restore_regs() @@ -280,12 +291,14 @@ class Nxthread(gdb.Command): ): restore_regs() else: - gdb.execute("nxsetregs g_pidhash[%s]->xcp.regs" % arg[0]) + gdb.execute("setregs g_pidhash[%s]->xcp.regs" % arg[0]) else: gdb.write(f"Invalid thread id {arg[0]}\n") class Nxcontinue(gdb.Command): + """Restore the registers and continue the execution""" + def __init__(self): super(Nxcontinue, self).__init__("nxcontinue", gdb.COMMAND_USER) @@ -295,6 +308,8 @@ class Nxcontinue(gdb.Command): class Nxstep(gdb.Command): + """Restore the registers and step the execution""" + def __init__(self): super(Nxstep, self).__init__("nxstep", gdb.COMMAND_USER) @@ -500,7 +515,7 @@ class Ps(gdb.Command): def register_commands(): - Nxsetregs() + SetRegs() Ps() # Disable thread commands for core dump and gdb-stub. @@ -508,7 +523,7 @@ def register_commands(): ncpus = utils.get_symbol_value("CONFIG_SMP_NCPUS") or 1 nthreads = len(gdb.selected_inferior().threads()) if nthreads <= ncpus: - Nxsetregs() + SetRegs() Nxinfothreads() Nxthread() Nxcontinue()