gdb/mmleak: add diagnose API to report details of the leak

Example of json dump:

    {
        "title": "Memory Leak Report",
        "summary": "Total 105 blks, 22768 bytes leaked",
        "result": "fail",
        "command": "mm leak",
        "data": [
            {
                "count": 1,
                "pid": 0,
                "size": 48,
                "address": 1100447608,
                "seqno": 0,
                "alive": true,
                "backtrace": []
            },
            {
                "count": 1,
                "pid": 4,
                "size": 368,
                "address": 1100549056,
                "seqno": 1041,
                "alive": false,
                "backtrace": [
                    {
                        "address": 1076428472,
                        "function": "<mm_zalloc+8>",
                        "source": "mm_heap/mm_zalloc.c:45"
                    },
                    {
                        "address": 1076424018,
                        "function": "<mm_calloc+18>",
                        "source": "mm_heap/mm_calloc.c:57"
                    },
                    {
                        "address": 1076419750,
                        "function": "<calloc+22>",
                        "source": "umm_heap/umm_calloc.c:73"
                    },
                    ....
                 ]
            },
  }

Signed-off-by: xuxingliang <xuxingliang@xiaomi.com>
This commit is contained in:
xuxingliang
2024-11-13 11:07:18 +08:00
committed by Xiang Xiao
parent 3ad53656b9
commit 659e3f87a0
+62 -14
View File
@@ -22,7 +22,7 @@ import bisect
import json import json
import time import time
from os import path from os import path
from typing import Dict, Generator, List from typing import Dict, Generator, List, Tuple
import gdb import gdb
@@ -100,13 +100,9 @@ class MMLeak(gdb.Command):
return nodes return nodes
def invoke(self, arg: str, from_tty: bool) -> None: def collect_leaks(
heaps = memdump.get_heaps("g_mmheap") self, heaps: List[mm.MMHeap]
pids = [int(tcb["pid"]) for tcb in utils.get_tcbs()] ) -> Dict[memdump.MMNodeDump, List[memdump.MMNodeDump]]:
def is_pid_alive(pid):
return pid in pids
t = time.time() t = time.time()
print("Loading globals from elf...", flush=True, end="") print("Loading globals from elf...", flush=True, end="")
good_nodes = self.global_nodes() # Global memory are all good. good_nodes = self.global_nodes() # Global memory are all good.
@@ -155,15 +151,67 @@ class MMLeak(gdb.Command):
print(f" {time.time() - t:.2f}s", flush=True, end="\n") print(f" {time.time() - t:.2f}s", flush=True, end="\n")
leak_nodes = memdump.group_nodes(nodes_dict[addr] for addr in sorted_addr) return memdump.group_nodes((nodes_dict[addr] for addr in sorted_addr))
def _iterate_leaks(
self, nodes: Dict[memdump.MMNodeDump, List[memdump.MMNodeDump]]
) -> Generator[Tuple[memdump.MMNodeDump, bool, int], None, None]:
pids = [int(tcb["pid"]) for tcb in utils.get_tcbs()]
def is_pid_alive(pid):
return pid in pids
for node in nodes.keys():
count = len(nodes[node])
yield node, is_pid_alive(node.pid), count
def invoke(self, arg: str, from_tty: bool) -> None:
heaps = memdump.get_heaps("g_mmheap")
leak_nodes = self.collect_leaks(heaps)
memdump.print_header() memdump.print_header()
total_blk = total_size = 0 total_blk = total_size = 0
for node in leak_nodes.keys(): for node, alive, count in self._iterate_leaks(leak_nodes):
count = len(leak_nodes[node])
total_blk += count total_blk += count
total_size += count * node.nodesize total_size += count * node.nodesize
memdump.print_node( memdump.print_node(node, alive, count=count)
node, is_pid_alive(node.pid), count=len(leak_nodes[node])
)
print(f"Leaked {total_blk} blks, {total_size} bytes") print(f"Leaked {total_blk} blks, {total_size} bytes")
def diagnose(self, *args, **kwargs):
heaps = memdump.get_heaps("g_mmheap")
leak_nodes = self.collect_leaks(heaps)
total_blk = total_size = 0
data = []
for node, alive, count in self._iterate_leaks(leak_nodes):
total_blk += count
total_size += count * node.nodesize
info = {
"count": count,
"pid": node.pid,
"size": node.nodesize,
"address": node.address,
"seqno": node.seqno,
"alive": alive,
"backtrace": [],
}
if mm.CONFIG_MM_BACKTRACE and node.backtrace and node.backtrace[0]:
bt = utils.Backtrace(node.backtrace)
info["backtrace"] = [
{
"address": addr,
"function": func,
"source": source,
}
for addr, func, source in bt.backtrace
]
data.append(info)
return {
"title": "Memory Leak Report",
"summary": f"Total {total_blk} blks, {total_size} bytes leaked",
"result": "fail" if total_blk else "pass",
"command": "mm leak",
"data": data,
}