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 395090284a5ebc83a6d79107c9e4cfbaacca5298 Author: Zhe Weng <weng...@xiaomi.com> AuthorDate: Thu Aug 22 20:18:39 2024 +0800 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 <weng...@xiaomi.com> --- tools/gdb/net.py | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/gdb/utils.py | 27 ++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/tools/gdb/net.py b/tools/gdb/net.py index c2f2e3ca31..3b8287b472 100644 --- a/tools/gdb/net.py +++ b/tools/gdb/net.py @@ -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"): diff --git a/tools/gdb/utils.py b/tools/gdb/utils.py index 1f130893e9..9667be156f 100644 --- a/tools/gdb/utils.py +++ b/tools/gdb/utils.py @@ -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