forked from nuttx/nuttx-update
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 <xuxingliang@xiaomi.com>
This commit is contained in:
parent
3a46b6e6af
commit
de5f70b3c8
3 changed files with 84 additions and 55 deletions
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue