From 8c11f4db4c6b2b6516059d1643d1e83922db8873 Mon Sep 17 00:00:00 2001
From: Dylan Hatch <dhatch@codeaurora.org>
Date: Wed, 27 Jun 2018 10:36:53 -0700
Subject: [PATCH] ion_buffer_parse: outputs to ionproc.txt information about
 dmabufs organized by process.

Ion buffer info printed, with buffers and processes sorted by size.

Change-Id: I22480f99a26a36e29bfd99c05701aab1bbe8e2d6
Signed-off-by: Dylan Hatch <dhatch@codeaurora.org>
---
 .../parsers/ion_buffer_parse.py               | 111 +++++++++++++++++-
 1 file changed, 110 insertions(+), 1 deletion(-)

diff --git a/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py b/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py
index 44f3167..bf47b17 100644
--- a/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py
+++ b/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py
@@ -53,7 +53,7 @@ def ion_buffer_info(self, ramdump, ion_info):
                        "buffer information")
         return
 
-    ion_info.write("*****Prasing dma buf info for ion leak debugging*****\n\n")
+    ion_info.write("*****Parsing dma buf info for ion leak debugging*****\n\n")
     head_offset = ramdump.field_offset('struct dma_buf_list', 'head')
     head = ramdump.read_word(db_list + head_offset)
     list_node_offset = ramdump.field_offset('struct dma_buf', 'list_node')
@@ -82,6 +82,114 @@ def ion_buffer_info(self, ramdump, ion_info):
         ion_info.write(str)
 
 
+def get_bufs(task, bufs, ion_info, ramdump):
+    t_size = 0
+    dma_buf_fops = ramdump.address_of('dma_buf_fops')
+    if dma_buf_fops is None:
+        ion_info.write("NOTE: 'dma_buf_fops' not found for file information\n")
+        return 0
+    timekeeper = ramdump.address_of('shadow_timekeeper')
+    if timekeeper is None:
+        ion_info.write("NOTE: 'timekeeper' not found for timing information\n")
+        return 0
+
+    files_offset = ramdump.field_offset('struct task_struct', 'files')
+    fdt_offset = ramdump.field_offset('struct files_struct', 'fdt')
+    fd_offset = ramdump.field_offset('struct fdtable', 'fd')
+    max_fds_offset = ramdump.field_offset('struct fdtable', 'max_fds')
+    f_op_offset = ramdump.field_offset('struct file', 'f_op')
+    private_data_offset = ramdump.field_offset('struct file', 'private_data')
+    size_offset = ramdump.field_offset('struct dma_buf', 'size')
+    name_offset = ramdump.field_offset('struct dma_buf', 'name')
+    stime_offset = ramdump.field_offset('struct timekeeper', 'xtime_sec')
+
+    if task is None:
+        return 0
+    files = ramdump.read_pointer(task + files_offset)
+    if files is None:
+        return 0
+    fdt = ramdump.read_pointer(files + fdt_offset)
+    if fdt is None:
+        return 0
+    fd = ramdump.read_pointer(fdt + fd_offset)
+    max_fds = ramdump.read_halfword(fdt + max_fds_offset)
+    stime = ramdump.read_word(timekeeper + stime_offset)
+    ctime_offset = ramdump.field_offset('struct dma_buf', 'ctime')
+    if ctime_offset is not None:
+        ctime_offset += ramdump.field_offset('struct timespec', 'tv_sec')
+    for i in range(max_fds):
+        file = ramdump.read_pointer(fd + i*8)
+        if (file == 0):
+            continue
+        f_op = ramdump.read_pointer(file + f_op_offset)
+        if (f_op != dma_buf_fops):
+            continue
+        dmabuf = ramdump.read_pointer(file + private_data_offset)
+        size = ramdump.read_word(dmabuf + size_offset)
+        time = 0
+        if ctime_offset is not None:
+            ctime = ramdump.read_word(dmabuf + ctime_offset)
+            time = stime - ctime
+        name = ramdump.read_word(dmabuf + name_offset)
+        name = ramdump.read_cstring(name, 48)
+
+        item = [name, hex(size), bytes_to_KB(size), time]
+        if item not in bufs:
+            t_size = t_size + size
+            bufs.append(item)
+    bufs.sort(key=lambda item: -item[2])
+    return t_size
+
+
+def get_proc_bufs(task, bufs, ion_info, ramdump):
+    group_offset = ramdump.field_offset('struct task_struct', 'thread_group')
+    group_node = ramdump.read_word(task + group_offset)
+    size = 0;
+    curr = None
+    while curr != task:
+        group_node = ramdump.read_pointer(group_node)
+        curr = group_node - group_offset
+        size += get_bufs(curr, bufs, ion_info, ramdump)
+    return size
+
+
+def ion_proc_info(self, ramdump, ion_info):
+    ion_info = ramdump.open_file('ionproc.txt')
+    init_task = ramdump.address_of('init_task')
+    if init_task is None:
+        ion_info.write("NOTE: 'init_task' not found for process information")
+        return
+    ion_info.write("*****Parsing dma proc info for ion leak debugging*****\n")
+    node_offset = ramdump.field_offset('struct task_struct', 'tasks')
+    list_node = ramdump.read_word(init_task + node_offset)
+    task = None
+    pid_offset = ramdump.field_offset('struct task_struct', 'tgid')
+    comm_offset = ramdump.field_offset('struct task_struct', 'comm')
+    dma_procs = []
+    while (task != init_task):
+        list_node = ramdump.read_pointer(list_node)
+        task = list_node - node_offset
+        bufs = []
+        size = get_proc_bufs(task, bufs, ion_info, ramdump)
+        if (size == 0):
+            continue
+        comm = ramdump.read_cstring(task + comm_offset)
+        pid = ramdump.read_int(task + pid_offset)
+        dma_procs.append([comm, pid, bytes_to_KB(size), bufs])
+
+    dma_procs.sort(key=lambda item: -item[2])
+    for proc in dma_procs:
+        str = "\n{0} (PID {1}) size (KB): {2}\n"\
+            .format(proc[0], proc[1], proc[2])
+        ion_info.write(str)
+        ion_info.write("{0:15} {1:15} {2:15} {3:15}\n".format(
+                'Name', 'Size', 'Size in KB', 'Time Alive(sec)'))
+        for item in proc[3]:
+            str = "{0:15} {1:15} {2:10} {3:15}\n".\
+                format(item[0], item[1], item[2], item[3])
+            ion_info.write(str)
+
+
 def do_dump_ionbuff_info(self, ramdump, ion_info):
     addressspace = 8
     heap_addr_array = []
@@ -413,5 +521,6 @@ class DumpIonBuffer(RamParser):
             self.logger.info("Starting --print-ionbuffer")
             if (self.ramdump.kernel_version >= (4, 14)):
                 ion_buffer_info(self, self.ramdump, ion_info)
+                ion_proc_info(self, self.ramdump, ion_info)
             else:
                 do_dump_ionbuff_info(self, self.ramdump, ion_info)
-- 
GitLab