tools/gdb: add pyproject.toml to build as a package

Now the GDB tool can be built with python -m build . to generate a
package.

Signed-off-by: xuxingliang <xuxingliang@xiaomi.com>
This commit is contained in:
xuxingliang
2024-09-09 18:36:20 +08:00
committed by Xiang Xiao
parent 5a82e21edb
commit 04b35a2e8f
14 changed files with 233 additions and 192 deletions
+2
View File
@@ -0,0 +1,2 @@
dist/
nuttxgdb.egg-info/
+35
View File
@@ -0,0 +1,35 @@
############################################################################
# tools/gdb/gdbinit.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
# 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.
#
############################################################################
import sys
from os import path
here = path.dirname(path.abspath(__file__))
if __name__ == "__main__":
if here not in sys.path:
sys.path.insert(0, here)
if "nuttxgdb" in sys.modules:
del sys.modules["nuttxgdb"]
import nuttxgdb # noqa: F401
@@ -1,5 +1,5 @@
############################################################################
# tools/gdb/__init__.py
# tools/gdb/nuttxgdb/__init__.py
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -20,19 +20,17 @@
#
############################################################################
import glob
import os
import sys
import importlib
from os import listdir, path
import gdb
python_dir = os.path.abspath(__file__)
python_dir = os.path.dirname(python_dir)
here = path.dirname(path.abspath(__file__))
sys.path.insert(1, python_dir)
# Search the python dir for all .py files, and source each
py_files = glob.glob(f"{python_dir}/*.py")
py_files.remove(os.path.abspath(__file__))
# Scan dir to get all modules available
modules = [
path.splitext(path.basename(f))[0] for f in listdir(here) if f.endswith(".py")
]
def register_commands(event):
@@ -41,20 +39,29 @@ def register_commands(event):
register_commands.registered = True
gdb.write("Registering NuttX GDB commands...\n")
gdb.write(f"Registering NuttX GDB commands from {here}\n")
gdb.execute("set pagination off")
gdb.write("set pagination off\n")
gdb.execute("set python print-stack full")
gdb.write("set python print-stack full\n")
for py_file in py_files:
gdb.execute(f"source {py_file}")
gdb.write(f"source {py_file}\n")
utils = __import__("utils")
utils.check_version()
gdb.execute('handle SIGUSR1 "nostop" "pass" "noprint"')
gdb.write('"handle SIGUSR1 "nostop" "pass" "noprint"\n')
# Register all modules
for m in modules:
if m == "__init__":
continue
module = importlib.import_module(f"{__package__}.{m}")
# Get all classes inherited from gdb.Command
for c in module.__dict__.values():
if isinstance(c, type) and issubclass(c, gdb.Command):
c()
utils = importlib.import_module(f"{__package__}.utils")
utils.check_version()
if len(gdb.objfiles()) == 0:
gdb.events.new_objfile.connect(register_commands)
@@ -1,5 +1,7 @@
############################################################################
# tools/gdb/dmesg.py
# tools/gdb/nuttxgdb/dmesg.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
@@ -19,14 +21,16 @@
############################################################################
import gdb
import utils
from . import utils
CONFIG_RAMLOG_SYSLOG = utils.get_symbol_value("CONFIG_RAMLOG_SYSLOG")
class Dmesg(gdb.Command):
def __init__(self):
super().__init__("dmesg", gdb.COMMAND_USER)
if CONFIG_RAMLOG_SYSLOG:
super().__init__("dmesg", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
sysdev = utils.gdb_eval_or_none("g_sysdev")
@@ -43,7 +47,3 @@ class Dmesg(gdb.Command):
clean_data = bytes(buf).replace(b"\x00", "".encode("utf-8"))
gdb.write(clean_data.decode("utf-8"))
gdb.write("\n")
if CONFIG_RAMLOG_SYSLOG:
Dmesg()
+9 -15
View File
@@ -1,5 +1,7 @@
############################################################################
# tools/gdb/fs.py
# tools/gdb/nuttxgdb/fs.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
@@ -22,7 +24,8 @@ import argparse
import enum
import gdb
import utils
from . import utils
FSNODEFLAG_TYPE_MASK = utils.get_symbol_value("FSNODEFLAG_TYPE_MASK")
@@ -220,7 +223,8 @@ class Fdinfo(gdb.Command):
class Mount(gdb.Command):
def __init__(self):
super().__init__("mount", gdb.COMMAND_USER)
if not utils.get_symbol_value("CONFIG_DISABLE_MOUNTPOINT"):
super().__init__("mount", gdb.COMMAND_USER)
def mountpt_filter(self, node, path):
if inode_gettype(node) == InodeType.MOUNTPT:
@@ -339,7 +343,8 @@ class InfoShmfs(gdb.Command):
"""Show share memory usage"""
def __init__(self):
super().__init__("info shm", gdb.COMMAND_USER)
if CONFIG_FS_SHMFS:
super().__init__("info shm", gdb.COMMAND_USER)
def shm_filter(self, node, path):
if inode_gettype(node) != InodeType.SHM:
@@ -352,14 +357,3 @@ class InfoShmfs(gdb.Command):
def invoke(self, args, from_tty):
foreach_inode(self.shm_filter)
Fdinfo()
if not utils.get_symbol_value("CONFIG_DISABLE_MOUNTPOINT"):
Mount()
ForeachInode()
if CONFIG_FS_SHMFS:
InfoShmfs()
@@ -1,5 +1,5 @@
############################################################################
# tools/gdb/gcore.py
# tools/gdb/nuttxgdb/gcore.py
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -25,7 +25,8 @@ import os
import shutil
import gdb
import utils
from . import utils
def create_file_with_size(filename, size):
@@ -133,6 +134,3 @@ class NXGcore(gdb.Command):
tmpfile.close()
print(f"Please run gdbserver.py to parse {corefile}")
NXGcore()
@@ -1,5 +1,5 @@
############################################################################
# tools/gdb/lists.py
# tools/gdb/nuttxgdb/lists.py
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -23,7 +23,8 @@
import argparse
import gdb
import utils
from . import utils
list_node_type = utils.lookup_type("struct list_node")
sq_queue_type = utils.lookup_type("sq_queue_t")
@@ -1,5 +1,5 @@
############################################################################
# tools/gdb/macros.py
# tools/gdb/nuttxgdb/macros.py
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -1,5 +1,5 @@
############################################################################
# tools/gdb/memdump.py
# tools/gdb/nuttxgdb/memdump.py
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -25,9 +25,10 @@ import bisect
import time
import gdb
import utils
from lists import NxSQueue
from utils import get_long_type, get_symbol_value, lookup_type, read_ulong
from . import utils
from .lists import NxSQueue
from .utils import get_long_type, get_symbol_value, lookup_type, read_ulong
MM_ALLOC_BIT = 0x1
MM_PREVFREE_BIT = 0x2
@@ -1014,9 +1015,3 @@ class Memfrag(gdb.Command):
f"heap size: {heapsize}, free size: {freesize}, uordblks:"
f"{info.__len__()} largest block: {info[0]['size']} \n"
)
Memfrag()
Memdump()
Memleak()
Memmap()
@@ -1,5 +1,7 @@
############################################################################
# tools/gdb/net.py
# tools/gdb/nuttxgdb/net.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
@@ -19,8 +21,9 @@
############################################################################
import gdb
import utils
from lists import NxDQueue, NxSQueue
from . import utils
from .lists import NxDQueue, NxSQueue
socket = utils.import_check(
"socket", errmsg="No socket module found, please try gdb-multiarch instead.\n"
@@ -108,7 +111,8 @@ class NetStats(gdb.Command):
"""
def __init__(self):
super().__init__("netstats", gdb.COMMAND_USER)
if utils.get_symbol_value("CONFIG_NET") and socket:
super().__init__("netstats", gdb.COMMAND_USER)
def iob_stats(self):
try:
@@ -242,7 +246,3 @@ class NetStats(gdb.Command):
if utils.get_symbol_value("CONFIG_NET_UDP") and "udp" in args:
self.udp_stats()
gdb.write("\n")
if utils.get_symbol_value("CONFIG_NET") and socket:
NetStats()
@@ -1,5 +1,5 @@
############################################################################
# tools/gdb/stack.py
# tools/gdb/nuttxgdb/stack.py
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -23,7 +23,8 @@
import traceback
import gdb
import utils
from . import utils
STACK_COLORATION_PATTERN = utils.get_symbol_value(
"STACK_COLOR", locspec="up_create_stack"
@@ -217,6 +218,3 @@ class StackUsage(gdb.Command):
continue
self.format_print(pid, stack)
StackUsage()
@@ -1,5 +1,5 @@
############################################################################
# tools/gdb/thread.py
# tools/gdb/nuttxgdb/thread.py
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -25,12 +25,20 @@ import re
from enum import Enum, auto
import gdb
import utils
from stack import Stack
from . import utils
from .stack import Stack
UINT16_MAX = 0xFFFF
SEM_TYPE_MUTEX = 4
TSTATE_TASK_RUNNING = utils.get_symbol_value("TSTATE_TASK_RUNNING")
CONFIG_SMP_NCPUS = utils.get_symbol_value("CONFIG_SMP_NCPUS") or 1
def is_thread_command_supported():
# Check if the native thread command is available by compare the number of threads.
# It should have at least CONFIG_SMP_NCPUS of idle threads.
return len(gdb.selected_inferior().threads()) > CONFIG_SMP_NCPUS
class Registers:
@@ -207,6 +215,8 @@ class Nxinfothreads(gdb.Command):
def __init__(self):
super().__init__("info nxthreads", gdb.COMMAND_USER)
if not is_thread_command_supported():
gdb.execute("define info threads\n info nxthreads \n end\n")
def invoke(self, args, from_tty):
npidhash = gdb.parse_and_eval("g_npidhash")
@@ -298,6 +308,8 @@ class Nxthread(gdb.Command):
def __init__(self):
super().__init__("nxthread", gdb.COMMAND_USER)
if not is_thread_command_supported():
gdb.execute("define thread\n nxthread \n end\n")
def invoke(self, args, from_tty):
npidhash = gdb.parse_and_eval("g_npidhash")
@@ -375,6 +387,11 @@ class Nxcontinue(gdb.Command):
def __init__(self):
super().__init__("nxcontinue", gdb.COMMAND_USER)
if not is_thread_command_supported():
gdb.execute("define c\n nxcontinue \n end\n")
gdb.write(
"\n\x1b[31;1m if use thread command, please don't use 'continue', use 'c' instead !!!\x1b[m\n"
)
def invoke(self, args, from_tty):
g_registers.restore()
@@ -386,6 +403,11 @@ class Nxstep(gdb.Command):
def __init__(self):
super().__init__("nxstep", gdb.COMMAND_USER)
if not is_thread_command_supported():
gdb.execute("define s\n nxstep \n end\n")
gdb.write(
"\x1b[31;1m if use thread command, please don't use 'step', use 's' instead !!!\x1b[m\n"
)
def invoke(self, args, from_tty):
g_registers.restore()
@@ -637,36 +659,3 @@ class DeadLock(gdb.Command):
gdb.write("No deadlock detected.")
gdb.write("\n")
def register_commands():
DeadLock()
SetRegs()
Ps()
Nxcontinue()
Nxinfothreads()
Nxstep()
Nxthread()
# Use custom command for thread if current target does not support it.
# The recognized threads count is less than or equal to the number of CPUs in this case.
# For coredump and gdb-stub, use native thread commands.
ncpus = utils.get_symbol_value("CONFIG_SMP_NCPUS") or 1
nthreads = len(gdb.selected_inferior().threads())
if nthreads <= ncpus:
# Native threads command is not available, override the threads command
gdb.execute("define info threads\n info nxthreads \n end\n")
gdb.execute("define thread\n nxthread \n end\n")
# We can't use a user command to rename continue it will recursion
gdb.execute("define c\n nxcontinue \n end\n")
gdb.execute("define s\n nxstep \n end\n")
gdb.write(
"\n\x1b[31;1m if use thread command, please don't use 'continue', use 'c' instead !!!\x1b[m\n"
)
gdb.write(
"\x1b[31;1m if use thread command, please don't use 'step', use 's' instead !!!\x1b[m\n"
)
register_commands()
@@ -1,5 +1,5 @@
############################################################################
# tools/gdb/utils.py
# tools/gdb/nuttxgdb/utils.py
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -25,7 +25,8 @@ import shlex
from typing import List, Tuple, Union
import gdb
from macros import fetch_macro_info, try_expand
from .macros import fetch_macro_info, try_expand
g_symbol_cache = {}
g_type_cache = {}
@@ -293,90 +294,6 @@ def parse_arg(arg: str) -> Union[gdb.Value, int]:
return None
class Hexdump(gdb.Command):
"""hexdump address/symbol <size>"""
def __init__(self):
super().__init__("hexdump", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
args = shlex.split(args)
if not args or len(args) < 1:
gdb.write("Usage: hexdump address/symbol <size>\n")
return
address = parse_arg(args[0])
size = parse_arg(args[1]) if len(args) > 1 else None
if not size:
size = address.type.sizeof if isinstance(address, gdb.Value) else 128
print(f"Dumping {size} bytes from {hex(address)}")
hexdump(address, size)
Hexdump()
class Addr2Line(gdb.Command):
"""Convert addresses or expressions
Usage: addr2line address1 address2 expression1
Example: addr2line 0x1234 0x5678
addr2line "0x1234 + pointer->abc" &var var->field function_name var
addr2line $pc $r1 "$r2 + var"
addr2line [24/08/29 20:51:02] [CPU1] [209] [ap] sched_dumpstack: backtrace| 0: 0x402cd484 0x4028357e
"""
def __init__(self):
super().__init__("addr2line", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
if not args:
gdb.write(Addr2Line.__doc__ + "\n")
return
addresses = []
for arg in shlex.split(args):
v = parse_arg(arg)
if not v:
gdb.write(f'Ignore "{arg}"\n')
continue
addresses.append(v)
backtraces = backtrace(addresses)
formatter = "{:<20} {:<32} {}\n"
gdb.write(formatter.format("Address", "Symbol", "Source"))
for addr, func, source in backtraces:
gdb.write(formatter.format(hex(addr), func, source))
Addr2Line()
class Profile(gdb.Command):
"""Profile a gdb command
Usage: profile <gdb command>
"""
def __init__(self):
self.cProfile = import_check(
"cProfile", errmsg="cProfile module not found, try gdb-multiarch.\n"
)
if not self.cProfile:
return
super().__init__("profile", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
self.cProfile.run(f"gdb.execute('{args}')", sort="cumulative")
Profile()
def nitems(array):
array_type = array.type
element_type = array_type.target()
@@ -681,3 +598,86 @@ def check_version():
switch_inferior(1) # Switch back
suppress_cli_notifications(state)
class Hexdump(gdb.Command):
"""hexdump address/symbol <size>"""
def __init__(self):
super().__init__("hexdump", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
argv = args.split(" ")
address = 0
size = 0
if argv[0] == "":
gdb.write("Usage: hexdump address/symbol <size>\n")
return
if is_decimal(argv[0]) or is_hexadecimal(argv[0]):
address = int(argv[0], 0)
size = int(argv[1], 0)
else:
var = gdb.parse_and_eval(f"{argv[0]}")
address = int(var.address)
size = int(var.type.sizeof)
gdb.write(f"{argv[0]} {hex(address)} {int(size)}\n")
hexdump(address, size)
class Addr2Line(gdb.Command):
"""Convert addresses or expressions
Usage: addr2line address1 address2 expression1
Example: addr2line 0x1234 0x5678
addr2line "0x1234 + pointer->abc" &var var->field function_name var
addr2line $pc $r1 "$r2 + var"
addr2line [24/08/29 20:51:02] [CPU1] [209] [ap] sched_dumpstack: backtrace| 0: 0x402cd484 0x4028357e
"""
def __init__(self):
super().__init__("addr2line", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
if not args:
gdb.write(Addr2Line.__doc__ + "\n")
return
addresses = []
for arg in shlex.split(args):
if is_decimal(arg):
addresses.append(int(arg))
elif is_hexadecimal(arg):
addresses.append(int(arg, 16))
else:
try:
var = gdb.parse_and_eval(f"{arg}")
addresses.append(var)
except gdb.error as e:
gdb.write(f"Ignore {arg}: {e}\n")
backtraces = backtrace(addresses)
formatter = "{:<20} {:<32} {}\n"
gdb.write(formatter.format("Address", "Symbol", "Source"))
for addr, func, source in backtraces:
gdb.write(formatter.format(hex(addr), func, source))
class Profile(gdb.Command):
"""Profile a gdb command
Usage: profile <gdb command>
"""
def __init__(self):
self.cProfile = import_check(
"cProfile", errmsg="cProfile module not found, try gdb-multiarch.\n"
)
if not self.cProfile:
return
super().__init__("profile", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
self.cProfile.run(f"gdb.execute('{args}')", sort="cumulative")
+22
View File
@@ -0,0 +1,22 @@
[build-system]
requires = ["setuptools>=61", "wheel"]
build-backend = "setuptools.build_meta"
[project]
version = "0.0.1"
name = 'nuttxgdb'
description = 'NuttX RTOS GDB extensions'
readme = "README.md"
license = { file = 'LICENSE' }
classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
]
dependencies = ["matplotlib", "numpy", "pyelftools"]
requires-python = ">=3.8"
[tool.setuptools.package-dir]
nuttxgdb = "nuttxgdb"