forked from nuttx/nuttx-update
tools/gdb: Add UDP in netstats
(gdb) netstats IOB: size ntotal nfree nwait nthrottle 1518 72 70 0 38 <...> UDP Conn: flg txbuf rxbuf local_address remote_address 0 41 0/16384 0/16384 :::19279 fc00::1:5001 1 41 0/16384 0/16384 :::19280 fc00::1:5001 2 41 0/16384 0/16384 :::19281 fc00::1:5001 3 41 0/16384 0/16384 :::19282 fc00::1:5001 4 41 0/16384 0/16384 :::19283 fc00::1:5001 5 41 0/16384 0/16384 0.0.0.0:19284 10.0.1.1:5001 6 41 0/16384 0/16384 0.0.0.0:19285 10.0.1.1:5001 7 41 0/16384 0/16384 0.0.0.0:19286 10.0.1.1:5001 8 41 0/16384 0/16384 0.0.0.0:19287 10.0.1.1:5001 9 41 0/16384 0/16384 0.0.0.0:19288 10.0.1.1:5001 Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
parent
1c884ee230
commit
395090284a
2 changed files with 121 additions and 0 deletions
|
@ -18,8 +18,78 @@
|
|||
#
|
||||
############################################################################
|
||||
|
||||
import socket
|
||||
|
||||
import gdb
|
||||
import utils
|
||||
from lists import dq_for_every, sq_for_every
|
||||
|
||||
NET_IPv4 = utils.get_symbol_value("CONFIG_NET_IPv4")
|
||||
NET_IPv6 = utils.get_symbol_value("CONFIG_NET_IPv6")
|
||||
|
||||
# NuttX's AF_INET and AF_INET6 have same value as Linux's
|
||||
AF_INET = socket.AF_INET
|
||||
AF_INET6 = socket.AF_INET6
|
||||
|
||||
|
||||
def ntohs(val):
|
||||
"""Convert a 16-bit value from network byte order to host byte order"""
|
||||
|
||||
if utils.get_target_endianness() == utils.BIG_ENDIAN:
|
||||
return val
|
||||
return utils.swap16(val)
|
||||
|
||||
|
||||
def get_ip_port(conn):
|
||||
"""Get the IP address and port of a network connection"""
|
||||
|
||||
domain = utils.get_field(conn, "domain", AF_INET if NET_IPv4 else AF_INET6)
|
||||
ip_binding = conn["u"]["ipv4" if domain == AF_INET else "ipv6"]
|
||||
lport = ntohs(conn["lport"])
|
||||
rport = ntohs(conn["rport"])
|
||||
laddr = inet_ntop(domain, ip_binding["laddr"])
|
||||
raddr = inet_ntop(domain, ip_binding["raddr"])
|
||||
return laddr, lport, raddr, rport
|
||||
|
||||
|
||||
def inet_ntop(domain, addr):
|
||||
"""Convert a network address to a string"""
|
||||
|
||||
addr_len = 16 if domain == AF_INET6 else 4
|
||||
return socket.inet_ntop(domain, utils.get_bytes(addr, addr_len))
|
||||
|
||||
|
||||
def socket_for_each_entry(proto):
|
||||
"""Iterate over a dq of socket structs, usage:
|
||||
for conn in socket_for_each_entry("icmp"):
|
||||
readahead = conn["readahead"]
|
||||
"""
|
||||
|
||||
sock_gdbtype = gdb.lookup_type("struct socket_conn_s").pointer()
|
||||
conn_gdbtype = gdb.lookup_type("struct %s_conn_s" % proto).pointer()
|
||||
|
||||
for node in dq_for_every(
|
||||
gdb.parse_and_eval("g_active_%s_connections" % proto), None
|
||||
):
|
||||
yield utils.container_of(
|
||||
utils.container_of(
|
||||
node, sock_gdbtype, "node"
|
||||
), # struct socket_conn_s::dq_entry_t node
|
||||
conn_gdbtype,
|
||||
"sconn",
|
||||
) # udp_conn_s::socket_conn_s sconn
|
||||
|
||||
|
||||
def wrbuffer_inqueue_size(queue=None, protocol="tcp"):
|
||||
"""Calculate the total size of all iob in the write queue of a udp connection"""
|
||||
|
||||
total = 0
|
||||
if queue:
|
||||
wrb_gdbtype = gdb.lookup_type("struct %s_wrbuffer_s" % protocol).pointer()
|
||||
for entry in sq_for_every(queue, None):
|
||||
entry = utils.container_of(entry, wrb_gdbtype, "wb_node")
|
||||
total += entry["wb_iob"]["io_pktlen"]
|
||||
return total
|
||||
|
||||
|
||||
class NetStats(gdb.Command):
|
||||
|
@ -83,6 +153,27 @@ class NetStats(gdb.Command):
|
|||
except gdb.error as e:
|
||||
gdb.write("Failed to get Net Stats: %s\n" % e)
|
||||
|
||||
def udp_stats(self):
|
||||
try:
|
||||
gdb.write(
|
||||
"UDP Conn: %4s %11s %11s %21s %21s\n"
|
||||
% ("flg", "txbuf", "rxbuf", "local_address", "remote_address")
|
||||
)
|
||||
for idx, conn in enumerate(socket_for_each_entry("udp")):
|
||||
flags = conn["sconn"]["s_flags"]
|
||||
txbuf = utils.get_field(conn, "sndbufs", -1)
|
||||
rxbuf = utils.get_field(conn, "rcvbufs", -1)
|
||||
txsz = wrbuffer_inqueue_size(utils.get_field(conn, "write_q"), "udp")
|
||||
rxsz = conn["readahead"]["io_pktlen"] if conn["readahead"] else 0
|
||||
laddr, lport, raddr, rport = get_ip_port(conn)
|
||||
|
||||
gdb.write(
|
||||
"%-4d %4x %5d/%-5d %5d/%-5d %15s:%-5d %15s:%-5d\n"
|
||||
% (idx, flags, txsz, txbuf, rxsz, rxbuf, laddr, lport, raddr, rport)
|
||||
)
|
||||
except gdb.error as e:
|
||||
gdb.write("Failed to get UDP stats: %s\n" % e)
|
||||
|
||||
def invoke(self, args, from_tty):
|
||||
if utils.get_symbol_value("CONFIG_MM_IOB"):
|
||||
self.iob_stats()
|
||||
|
@ -90,6 +181,9 @@ class NetStats(gdb.Command):
|
|||
if utils.get_symbol_value("CONFIG_NET_STATISTICS"):
|
||||
self.pkt_stats()
|
||||
gdb.write("\n")
|
||||
if utils.get_symbol_value("CONFIG_NET_UDP"):
|
||||
self.udp_stats()
|
||||
gdb.write("\n")
|
||||
|
||||
|
||||
if utils.get_symbol_value("CONFIG_NET"):
|
||||
|
|
|
@ -177,6 +177,16 @@ def get_field(val, key, default=None):
|
|||
return default
|
||||
|
||||
|
||||
def get_bytes(val, size):
|
||||
"""Convert a gdb value to a bytes object"""
|
||||
try:
|
||||
return val.bytes[:size]
|
||||
except AttributeError: # Sometimes we don't have gdb.Value.bytes
|
||||
inf = gdb.inferiors()[0]
|
||||
mem = inf.read_memory(val.address, size)
|
||||
return mem.tobytes()
|
||||
|
||||
|
||||
def import_check(module, name="", errmsg=""):
|
||||
try:
|
||||
module = __import__(module, fromlist=[name])
|
||||
|
@ -345,6 +355,23 @@ def read_ulong(buffer, offset):
|
|||
return read_u32(buffer, offset)
|
||||
|
||||
|
||||
def bswap(val, size):
|
||||
"""Reverses the byte order in a gdb.Value or int value of size bytes"""
|
||||
return int.from_bytes(int(val).to_bytes(size, byteorder="little"), byteorder="big")
|
||||
|
||||
|
||||
def swap16(val):
|
||||
return bswap(val, 2)
|
||||
|
||||
|
||||
def swap32(val):
|
||||
return bswap(val, 4)
|
||||
|
||||
|
||||
def swap64(val):
|
||||
return bswap(val, 8)
|
||||
|
||||
|
||||
target_arch = None
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue