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 eded2017d4daf81a804dd6a63b19c6767ca72269
Author: anjiahao <anjia...@xiaomi.com>
AuthorDate: Fri Aug 2 20:09:58 2024 +0800

    memdump.py:Enhance the printing function of memdump
    
    Signed-off-by: anjiahao <anjia...@xiaomi.com>
---
 tools/gdb/memdump.py | 397 ++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 265 insertions(+), 132 deletions(-)

diff --git a/tools/gdb/memdump.py b/tools/gdb/memdump.py
index eb35304b48..570b6b99eb 100644
--- a/tools/gdb/memdump.py
+++ b/tools/gdb/memdump.py
@@ -1,8 +1,6 @@
 ############################################################################
 # tools/gdb/memdump.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
@@ -52,15 +50,85 @@ def mm_foreach(heap):
     node = gdb.Value(heap["mm_heapstart"][0]).cast(
         gdb.lookup_type("struct mm_allocnode_s").pointer()
     )
-    while 1:
-        yield node
-        next = gdb.Value(node).cast(gdb.lookup_type("char").pointer())
-        next = gdb.Value(next + mm_nodesize(node["size"])).cast(
-            gdb.lookup_type("struct mm_allocnode_s").pointer()
+
+    for region in range(0, get_symbol_value("CONFIG_MM_REGIONS")):
+        while 1:
+            yield node
+            next = gdb.Value(node).cast(gdb.lookup_type("char").pointer())
+            next = gdb.Value(next + mm_nodesize(node["size"])).cast(
+                gdb.lookup_type("struct mm_allocnode_s").pointer()
+            )
+
+            if next >= heap["mm_heapend"][region] or next == node:
+                break
+            node = next
+
+
+def mm_dumpnode(node, count, align, simple, detail, alive):
+    if node["size"] & MM_ALLOC_BIT != 0:
+        charnode = gdb.Value(node).cast(gdb.lookup_type("char").pointer())
+        if not alive:
+            # if pid is not alive put a red asterisk.
+            gdb.write("\x1b[33;1m*\x1b[m")
+
+        if not detail:
+            gdb.write("%*d" % (6 if alive else 5, count))
+
+        gdb.write(
+            "%6d%12u%12u%#*x"
+            % (
+                node["pid"],
+                mm_nodesize(node["size"]),
+                node["seqno"],
+                align,
+                (int)(
+                    charnode
+                    + gdb.lookup_type("struct mm_allocnode_s").sizeof
+                ),
+            )
         )
-        if node >= heap["mm_heapend"].dereference() or next == node:
-            break
-        node = next
+
+        if node.type.has_key("backtrace"):
+            max = node["backtrace"].type.range()[1]
+            firstrow = True
+            for x in range(0, max):
+                if (int(node["backtrace"][x]) == 0):
+                    break
+
+                if simple:
+                    gdb.write(" %0#*x" % (align, int(node["backtrace"][x])))
+                else:
+                    if firstrow:
+                        firstrow = False
+                    else:
+                        if not detail:
+                            gdb.write(" " * 6)
+                        gdb.write(" " * (6 + 12 + 12 + align))
+                    gdb.write(
+                        "  [%0#*x] %-20s %s:%d\n"
+                        % (
+                            align, int(node["backtrace"][x]),
+                            node["backtrace"][x].format_string(raw=False, 
symbols=True, address=False),
+                            gdb.find_pc_line(node["backtrace"][x]).symtab,
+                            gdb.find_pc_line(node["backtrace"][x]).line
+                        )
+                    )
+
+    else:
+        charnode = gdb.Value(node).cast(gdb.lookup_type("char").pointer())
+        gdb.write(
+            "%12u%#*x"
+            % (
+                mm_nodesize(node["size"]),
+                align,
+                (int)(
+                    charnode
+                    + gdb.lookup_type("struct mm_allocnode_s").sizeof
+                ),
+            )
+        )
+
+    gdb.write("\n")
 
 
 def mempool_multiple_foreach(mpool):
@@ -75,25 +143,58 @@ def mempool_multiple_foreach(mpool):
 def mempool_realblocksize(pool):
     """Return the real block size of a mempool"""
 
-    if get_symbol_value("CONFIG_MM_DFAULT_ALIGNMENT") == 0:
+    if get_symbol_value("CONFIG_MM_DFAULT_ALIGNMENT") is None:
         mempool_align = 2 * gdb.lookup_type("size_t").sizeof
     else:
         mempool_align = get_symbol_value("CONFIG_MM_DFAULT_ALIGNMENT")
 
+    if mempool_align == 0:
+        mempool_align = 2 * gdb.lookup_type("size_t").sizeof
+
     if get_symbol_value("CONFIG_MM_BACKTRACE") >= 0:
-        return align_up(
-            pool["blocksize"] + gdb.lookup_type("struct 
mempool_backtrace_s").sizeof,
-            mempool_align,
-        )
+        return align_up(pool["blocksize"] + gdb.lookup_type("struct 
mempool_backtrace_s").sizeof, mempool_align)
     else:
         return pool["blocksize"]
 
 
+def get_backtrace(node):
+
+    backtrace_list = []
+    max = node["backtrace"].type.range()[1]
+    for x in range(0, max):
+        if (node["backtrace"][x] != 0):
+            backtrace_list.append(int(node["backtrace"][x]))
+        else:
+            break
+
+    return tuple(backtrace_list)
+
+
+def record_backtrace(node, size, backtrace_dict):
+    if node.type.has_key("backtrace"):
+        backtrace = get_backtrace(node)
+        if (backtrace, int(node["pid"])) not in backtrace_dict.keys():
+            info = {}
+            info["node"] = node
+            info["count"] = 1
+            info["size"] = size
+            info["pid"] = node["pid"]
+            backtrace_dict[(backtrace, int(node["pid"]))] = info
+        else:
+            backtrace_dict[(backtrace, int(node["pid"]))]["count"] += 1
+
+    return backtrace_dict
+
+
+def get_count(element):
+    return element['count']
+
+
 def mempool_foreach(pool):
     """Iterate over all block in a mempool"""
 
     blocksize = mempool_realblocksize(pool)
-    if pool["ibase"] != 0:
+    if (pool["ibase"] != 0):
         nblk = pool["interruptsize"] / blocksize
         while nblk > 0:
             bufaddr = gdb.Value(pool["ibase"] + nblk * blocksize + 
pool["blocksize"])
@@ -104,9 +205,7 @@ def mempool_foreach(pool):
     entry = sq_queue.get_type().pointer()
     for entry in sq_for_every(pool["equeue"], entry):
         nblk = (pool["expandsize"] - gdb.lookup_type("sq_entry_t").sizeof) / 
blocksize
-        base = (
-            gdb.Value(entry).cast(gdb.lookup_type("char").pointer()) - nblk * 
blocksize
-        )
+        base = gdb.Value(entry).cast(gdb.lookup_type("char").pointer()) - nblk 
* blocksize
         while nblk > 0:
             nblk -= 1
             bufaddr = gdb.Value(base + nblk * blocksize + pool["blocksize"])
@@ -114,13 +213,68 @@ def mempool_foreach(pool):
             yield buf
 
 
+def mempool_dumpbuf(buf, blksize, count, align, simple, detail, alive):
+    charnode = gdb.Value(buf).cast(
+        gdb.lookup_type("char").pointer()
+    )
+
+    if not alive:
+        # if pid is not alive put a red asterisk.
+        gdb.write("\x1b[33;1m*\x1b[m")
+
+    if not detail:
+        gdb.write("%*d" % (6 if alive else 5, count))
+
+    gdb.write(
+        "%6d%12u%12u%#*x"
+        % (
+            buf["pid"],
+            blksize,
+            buf["seqno"],
+            align,
+            (int)(charnode - blksize),
+        )
+    )
+
+    if buf.type.has_key("backtrace"):
+        max = buf["backtrace"].type.range()[1]
+        firstrow = True
+        for x in range(0, max):
+            if (buf["backtrace"][x] == 0):
+                break
+
+            if simple:
+                gdb.write(" %0#*x" % (align, int(buf["backtrace"][x])))
+            else:
+                if firstrow:
+                    firstrow = False
+                else:
+                    if not detail:
+                        gdb.write(" " * 6)
+                    gdb.write(" " * (6 + 12 + 12 + align))
+                gdb.write(
+                    "  [%0#*x] %-20s %s:%d\n"
+                    % (
+                        align, int(buf["backtrace"][x]),
+                        buf["backtrace"][x].format_string(raw=False, 
symbols=True, address=False),
+                        gdb.find_pc_line(buf["backtrace"][x]).symtab,
+                        gdb.find_pc_line(buf["backtrace"][x]).line
+                    )
+                )
+
+    gdb.write("\n")
+
+
 class Nxmemdump(gdb.Command):
     """Dump the heap and mempool memory"""
 
     def __init__(self):
         super(Nxmemdump, self).__init__("memdump", gdb.COMMAND_USER)
 
-    def mempool_dump(self, mpool, pid, seqmin, seqmax, address):
+    def check_alive(self, pid):
+        return self.pidhash[pid & self.npidhash - 1] != 0
+
+    def mempool_dump(self, mpool, pid, seqmin, seqmax, address, simple, 
detail):
         """Dump the mempool memory"""
         for pool in mempool_multiple_foreach(mpool):
             if pid == PID_MM_FREE:
@@ -137,54 +291,40 @@ class Nxmemdump(gdb.Command):
                     self.uordblks += pool["blocksize"]
             else:
                 for buf in mempool_foreach(pool):
-                    if (
-                        (pid == buf["pid"] or pid == PID_MM_ALLOC)
-                        and (buf["seqno"] >= seqmin and buf["seqno"] < seqmax)
-                        and buf["magic"] == MEMPOOL_MAGIC_ALLOC
-                    ):
+                    if (pid == buf["pid"] or pid == PID_MM_ALLOC) and (
+                        buf["seqno"] >= seqmin and buf["seqno"] < seqmax
+                    ) and buf["magic"] == MEMPOOL_MAGIC_ALLOC:
                         charnode = gdb.Value(buf).cast(
                             gdb.lookup_type("char").pointer()
                         )
-                        gdb.write(
-                            "%6d%12u%12u%#*x"
-                            % (
-                                buf["pid"],
-                                mm_nodesize(pool["blocksize"]),
-                                buf["seqno"],
-                                self.align,
-                                (int)(charnode - pool["blocksize"]),
-                            )
-                        )
-                        if buf.type.has_key("backtrace"):
-                            max = buf["backtrace"].type.range()[1]
-                            for x in range(0, max):
-                                gdb.write(" ")
-                                gdb.write(
-                                    buf["backtrace"][x].format_string(
-                                        raw=False, symbols=True, address=False
-                                    )
-                                )
-
-                        if address and (
-                            address < int(charnode)
-                            and address >= (int)(charnode - pool["blocksize"])
-                        ):
-                            gdb.write(
-                                "\nThe address 0x%x found belongs to"
-                                "the mempool node with base address 0x%x\n"
-                                % (address, charnode)
-                            )
+                        if detail:
+                            mempool_dumpbuf(buf, pool["blocksize"], 1, 
self.align, simple, detail,
+                                            self.check_alive(buf["pid"]))
+                        else:
+                            self.backtrace_dict = record_backtrace(buf, 
pool["blocksize"], self.backtrace_dict)
+                        if address \
+                           and (address < int(charnode)
+                                and address >= (int)(charnode - 
pool["blocksize"])):
+
+                            mempool_dumpbuf(buf, pool["blocksize"], 1, 
self.align, simple, detail,
+                                            self.check_alive(buf["pid"]))
+                            gdb.write("\nThe address 0x%x found belongs to"
+                                      "the mempool node with base address 
0x%x\n" % (address, charnode))
+                            print_node = "p *(struct mempool_backtrace_s 
*)0x%x" % (charnode)
+                            gdb.write(print_node + "\n")
+                            gdb.execute(print_node)
                             return True
-
-                        gdb.write("\n")
                         self.aordblks += 1
                         self.uordblks += pool["blocksize"]
         return False
 
-    def memdump(self, pid, seqmin, seqmax, address):
+    def memdump(self, pid, seqmin, seqmax, address, simple, detail):
         """Dump the heap memory"""
         if pid >= PID_MM_ALLOC:
-            gdb.write("Dump all used memory node info:\n")
+            gdb.write("Dump all used memory node info, use '\x1b[33;1m*\x1b[m' 
mark pid is not exist:\n")
+            if not detail:
+                gdb.write("%6s" % ("CNT"))
+
             gdb.write(
                 "%6s%12s%12s%*s %s\n"
                 % ("PID", "Size", "Sequence", self.align, "Address", 
"Callstack")
@@ -195,7 +335,7 @@ class Nxmemdump(gdb.Command):
 
         heap = gdb.parse_and_eval("g_mmheap")
         if heap.type.has_key("mm_mpool"):
-            if self.mempool_dump(heap["mm_mpool"], pid, seqmin, seqmax, 
address):
+            if self.mempool_dump(heap["mm_mpool"], pid, seqmin, seqmax, 
address, simple, detail):
                 return
 
         for node in mm_foreach(heap):
@@ -204,66 +344,42 @@ class Nxmemdump(gdb.Command):
                     pid == node["pid"]
                     or (pid == PID_MM_ALLOC and node["pid"] != PID_MM_MEMPOOL)
                 ) and (node["seqno"] >= seqmin and node["seqno"] < seqmax):
-                    charnode = 
gdb.Value(node).cast(gdb.lookup_type("char").pointer())
-                    gdb.write(
-                        "%6d%12u%12u%#*x"
-                        % (
-                            node["pid"],
-                            mm_nodesize(node["size"]),
-                            node["seqno"],
-                            self.align,
-                            (int)(
-                                charnode
-                                + gdb.lookup_type("struct 
mm_allocnode_s").sizeof
-                            ),
-                        )
-                    )
+                    if detail:
+                        mm_dumpnode(node, 1, self.align, simple, detail, 
self.check_alive(node["pid"]))
+                    else:
+                        self.backtrace_dict = record_backtrace(node, 
mm_nodesize(node["size"]), self.backtrace_dict)
 
-                    if node.type.has_key("backtrace"):
-                        max = node["backtrace"].type.range()[1]
-                        for x in range(0, max):
-                            gdb.write(" ")
-                            gdb.write(
-                                node["backtrace"][x].format_string(
-                                    raw=False, symbols=True, address=False
-                                )
-                            )
-
-                    gdb.write("\n")
-
-                    if address and (
-                        address < int(charnode + node["size"])
-                        and address
-                        >= (int)(
-                            charnode + gdb.lookup_type("struct 
mm_allocnode_s").sizeof
-                        )
-                    ):
-                        gdb.write(
-                            "\nThe address 0x%x found belongs to"
-                            "the memory node with base address 0x%x\n"
-                            % (address, charnode)
-                        )
+                    charnode = 
gdb.Value(node).cast(gdb.lookup_type("char").pointer())
+                    if address and (address < int(charnode + node["size"])
+                                    and address >= (int)(charnode + 
gdb.lookup_type("struct mm_allocnode_s").sizeof)):
+                        mm_dumpnode(node, 1, self.align, simple, detail, 
self.check_alive(node["pid"]))
+                        gdb.write("\nThe address 0x%x found belongs to"
+                                  "the memory node with base address 0x%x\n" % 
(address, charnode))
+                        print_node = "p *(struct mm_allocnode_s *)0x%x" % 
(charnode)
+                        gdb.write(print_node + "\n")
+                        gdb.execute(print_node)
                         return
-
                     self.aordblks += 1
                     self.uordblks += mm_nodesize(node["size"])
             else:
                 if pid == PID_MM_FREE:
-                    charnode = 
gdb.Value(node).cast(gdb.lookup_type("char").pointer())
-                    gdb.write(
-                        "%12u%#*x\n"
-                        % (
-                            mm_nodesize(node["size"]),
-                            self.align,
-                            (int)(
-                                charnode
-                                + gdb.lookup_type("struct 
mm_allocnode_s").sizeof
-                            ),
-                        )
-                    )
+                    mm_dumpnode(node, 1, self.align, simple, detail, 
self.check_alive(node["pid"]))
                     self.aordblks += 1
                     self.uordblks += mm_nodesize(node["size"])
 
+        if not detail:
+            output = []
+            for node in self.backtrace_dict.values():
+                output.append(node)
+
+            output.sort(key=get_count, reverse=True)
+            for node in output:
+                if node["node"].type == gdb.lookup_type("struct 
mm_allocnode_s").pointer():
+                    mm_dumpnode(node["node"], node["count"], self.align, 
simple, detail, self.check_alive(node["pid"]))
+                else:
+                    mempool_dumpbuf(node["node"], node["size"], node["count"], 
self.align, simple, detail,
+                                    self.check_alive(node["pid"]))
+
         gdb.write("%12s%12s\n" % ("Total Blks", "Total Size"))
         gdb.write("%12d%12d\n" % (self.aordblks, self.uordblks))
 
@@ -271,22 +387,31 @@ class Nxmemdump(gdb.Command):
         return gdb.COMPLETE_SYMBOL
 
     def parse_arguments(self, argv):
-        parser = argparse.ArgumentParser(description="memdump command")
-        parser.add_argument("-p", "--pid", type=str, help="Thread PID")
-        parser.add_argument("-a", "--addr", type=str, help="Query memory 
address")
-        parser.add_argument("-i", "--min", type=str, help="Minimum value")
-        parser.add_argument("-x", "--max", type=str, help="Maximum value")
-        parser.add_argument("--used", action="store_true", help="Used flag")
-        parser.add_argument("--free", action="store_true", help="Free flag")
-        args = parser.parse_args(args=(None if len(argv) == 1 else argv))
-        return {
-            "pid": int(args.pid, 0) if args.pid else None,
-            "seqmin": int(args.min, 0) if args.min else 0,
-            "seqmax": int(args.max, 0) if args.max else 0xFFFFFFFF,
-            "used": args.used,
-            "free": args.free,
-            "addr": int(args.addr, 0) if args.addr else None,
-        }
+        parser = argparse.ArgumentParser(description='memdump command')
+        parser.add_argument('-p', "--pid", type=str, help='Thread PID')
+        parser.add_argument('-a', "--addr", type=str, help='Query memory 
address')
+        parser.add_argument('-i', "--min", type=str, help='Minimum value')
+        parser.add_argument('-x', "--max", type=str, help='Maximum value')
+        parser.add_argument('--used', action='store_true', help='Used flag')
+        parser.add_argument('--free', action='store_true', help='Free flag')
+        parser.add_argument('-d', '--detail', action='store_true', 
help='Output details of each node', default=False)
+        parser.add_argument('-s', '--simple', action='store_true', 
help='Simplified Output', default=False)
+
+        if argv[0] == '':
+            argv = None
+        try:
+            args = parser.parse_args(argv)
+        except SystemExit:
+            return None
+
+        return {'pid': int(args.pid, 0) if args.pid else None,
+                'seqmin': int(args.min, 0) if args.min else 0,
+                'seqmax': int(args.max, 0) if args.max else 0xFFFFFFFF,
+                'used': args.used,
+                'free': args.free,
+                'addr': int(args.addr, 0) if args.addr else None,
+                'simple': args.simple,
+                'detail': args.detail}
 
     def invoke(self, args, from_tty):
         if gdb.lookup_type("size_t").sizeof == 4:
@@ -296,17 +421,25 @@ class Nxmemdump(gdb.Command):
 
         arg = self.parse_arguments(args.split(" "))
 
+        if arg is None:
+            return
+
         pid = PID_MM_ALLOC
-        if arg["used"]:
+        if arg['used']:
             pid = PID_MM_ALLOC
-        elif arg["free"]:
-            pid = PID_MM_LEAK
-        elif arg["pid"]:
-            pid = arg["pid"]
+        elif arg['free']:
+            pid = PID_MM_FREE
+        elif arg['pid']:
+            pid = arg['pid']
+        if get_symbol_value("CONFIG_MM_BACKTRACE") <= 0:
+            arg['detail'] = True
 
         self.aordblks = 0
         self.uordblks = 0
-        self.memdump(pid, arg["seqmin"], arg["seqmax"], arg["addr"])
+        self.backtrace_dict = {}
+        self.npidhash = gdb.parse_and_eval("g_npidhash")
+        self.pidhash = gdb.parse_and_eval("g_pidhash")
+        self.memdump(pid, arg['seqmin'], arg['seqmax'], arg['addr'], 
arg['simple'], arg['detail'])
 
 
 Nxmemdump()

Reply via email to