From c21e8e2a14df3c5a056d860eeffb581f41e2f963 Mon Sep 17 00:00:00 2001
From: Avinash Jain <jainavinash@codeaurora.org>
Date: Mon, 22 Aug 2016 18:37:55 +0530
Subject: [PATCH] lrdp-v2: script to fetch ion buffers from ramdump

Script to fetch ion buffers(allocated, orphaned) from dump.

Change-Id: I088813d6017e67e98d8ae0e7913892e70b12c1fd
---
 .../parsers/ion_buffer_parse.py               | 371 ++++++++++++++++++
 1 file changed, 371 insertions(+)
 create mode 100644 linux-ramdump-parser-v2/parsers/ion_buffer_parse.py

diff --git a/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py b/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py
new file mode 100644
index 0000000..47972f1
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/ion_buffer_parse.py
@@ -0,0 +1,371 @@
+"""
+Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+
+from parser_util import register_parser, RamParser
+
+RB_PARENT_COLOR_MASK = 0xFFFFFFFFFFFFFFFC
+grand_total = 0
+TASK_NAME_LENGTH = 16
+ion_heap_buffers = []
+
+
+def bytes_to_KB(bytes):
+    kb_val = 0
+    if bytes != 0:
+        kb_val = bytes / 1024
+    return kb_val
+
+
+def do_dump_ionbuff_info(self, ramdump, ion_info):
+    addressspace = 8
+    heap_addr_array = []
+    ion_info = ramdump.open_file('ionbuffer.txt')
+    # read num of heaps
+    number_of_heaps = ramdump.read_word('num_heaps')
+    ion_info.write('Number of heaps:{0} \n'.format(number_of_heaps))
+
+    # get heap starting address
+    heap_addr = ramdump.read_pointer('heaps')
+
+    if self.ramdump.arm64:
+        addressspace = 8
+    else:
+        addressspace = 4
+
+    # get address of all heaps
+    nIndex = 0
+    for nIndex in range(0, number_of_heaps):
+        heap_addr_array.append(heap_addr + (nIndex*addressspace))
+
+    # parse a heap
+    nIndex = 0
+    for nIndex in range(0, number_of_heaps):
+        str = "\n\n parsing {0:0} of {1:0} heap    Heap: 0x{2:x}"
+        ion_info.write(str.format(
+                                    nIndex + 1,
+                                    number_of_heaps,
+                                    ramdump.read_word(
+                                                heap_addr_array[nIndex])))
+        parse_heap(self, ramdump, heap_addr_array[nIndex], ion_info)
+    ion_info.write(
+                    '\n Total ION buffer size: {0:1} KB'.format(
+                                            bytes_to_KB(grand_total)))
+
+
+def parse_heap(self, ramdump, heap_addr,  ion_info):
+    global grand_total
+
+    nr_clients = 0
+    total_orphan_buffer_size = 0
+    ion_heap = ramdump.read_word(heap_addr)
+    ionheap_id = ramdump.read_structure_field(
+                        ion_heap, 'struct ion_heap',  'id')
+    ionheap_name_addr = ramdump.read_structure_field(
+                    ion_heap, 'struct ion_heap',  'name')
+    ionheap_name = ramdump.read_cstring(ionheap_name_addr, TASK_NAME_LENGTH)
+    ionheap_type = ramdump.read_structure_field(
+                    ion_heap, 'struct ion_heap',  'type')
+    ionheap_total_allocated = ramdump.read_structure_field(
+                    ion_heap, 'struct ion_heap',  'total_allocated.counter')
+    ionheap_total_handles = ramdump.read_structure_field(
+                    ion_heap, 'struct ion_heap',  'total_handles.counter')
+    self.ion_handle_node_offset = ramdump.field_offset(
+                                    'struct ion_handle', 'node')
+
+    ion_info.write("\n*********************************************")
+    str = "\n Heap ID : {0} Heap Type: {1} Heap Name : {2}\n"
+    ion_info.write(str.format(ionheap_id, ionheap_type, ionheap_name))
+    ion_info.write('\n Total allocated : {0:1} KB'.format(
+                    bytes_to_KB(ionheap_total_allocated)))
+    ion_info.write('\n Total Handles   : {0:1} KB'.format(
+                            bytes_to_KB(ionheap_total_handles)))
+    orphan = bytes_to_KB(ionheap_total_allocated - ionheap_total_handles)
+    ion_info.write('\n Orphan          : {0:1} KB'.format(orphan))
+    ion_info.write("\n*********************************************")
+
+    ion_dev = ramdump.read_structure_field(
+                    ion_heap, 'struct ion_heap',  'dev')
+
+    ion_dev_rb_root = ramdump.read_structure_field(
+                    ion_dev, 'struct ion_device',  'clients')
+
+    if ionheap_total_allocated != 0:
+        nr_clients = show_ion_dev_client(
+                            self, ramdump,
+                            ion_dev_rb_root,
+                            ionheap_id, ion_info)
+
+        str = "\n \nTotal number of clients: {0:1}"
+        ion_info.write(str.format(nr_clients))
+        ion_info.write("\n ----------------------------------")
+        str = "\n orphaned allocations (info is from last known client):\n"
+        ion_info.write(str)
+        total_orphan_buffer_size,  total_buffer_size = \
+            parse_orphan_buffers(self, ramdump, ion_dev, ionheap_id, ion_info)
+        ion_info.write("\n ----------------------------------")
+        ion_info.write(
+                '\n total orphan size: {0} KB'.format(
+                        bytes_to_KB(total_orphan_buffer_size)))
+        ion_info.write(
+                    '\n total buffer size: {0} KB'.format(
+                            bytes_to_KB(total_buffer_size)))
+        ion_info.write("\n ----------------------------------")
+        grand_total = grand_total + total_buffer_size
+
+
+def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info):
+    orphan_buffer_size = 0
+    total_buffer_size = 0
+    ion_dev_buffer_rb_root = ramdump.read_structure_field(
+                    ion_dev, 'struct ion_device',  'buffers')
+
+    rb_node = parser(
+                self, 1, ramdump,  ion_dev_buffer_rb_root,  ion_info)
+
+    ion_buffer_rb_node_offset = ramdump.field_offset(
+                                'struct ion_buffer', 'node')
+    ion_buffer_task_comm_offset = ramdump.field_offset(
+                                'struct ion_buffer', 'task_comm')
+    ion_buffer_ref_offset = ramdump.field_offset(
+                                'struct ion_buffer', 'ref')
+    str = "\n buffer: 0x{0:x}, Buffer size: {1} KB "
+    str = str + "comm: {2} PID: {3} kmap count: {4} ref_count : {5}"
+    while rb_node != 0:
+        ion_buffer = rb_node - ion_buffer_rb_node_offset
+        ion_buffer_ref_add = ion_buffer + ion_buffer_ref_offset
+        ion_buffer_heap = ramdump.read_structure_field(
+                ion_buffer, 'struct ion_buffer', 'heap')
+        ion_heap_id = ramdump.read_structure_field(
+                ion_buffer_heap, 'struct ion_heap', 'id')
+        ion_buffer_size = ramdump.read_structure_field(
+                ion_buffer, 'struct ion_buffer', 'size')
+        ion_buffer_handlecount = ramdump.read_structure_field(
+                ion_buffer, 'struct ion_buffer', 'handle_count')
+        ref_counter = ramdump.read_structure_field(
+                ion_buffer_ref_add, 'struct kref', 'refcount.counter')
+        if heap_id == ion_heap_id:
+            total_buffer_size = total_buffer_size + ion_buffer_size
+            # if orphaned allocation
+            if ion_buffer_handlecount == 0:
+                ion_buffer_pid = ramdump.read_structure_field(
+                                ion_buffer, 'struct ion_buffer', 'pid')
+                ion_buffer_kmap_count = ramdump.read_structure_field(
+                                ion_buffer, 'struct ion_buffer', 'kmap_cnt')
+                client_name = ramdump.read_cstring(
+                                (ion_buffer + ion_buffer_task_comm_offset),
+                                TASK_NAME_LENGTH)
+                ion_info.write(str.format(
+                                            ion_buffer,
+                                            bytes_to_KB(ion_buffer_size),
+                                            client_name,
+                                            ion_buffer_pid,
+                                            ion_buffer_kmap_count,
+                                            ref_counter))
+                orphan_buffer_size = orphan_buffer_size + ion_buffer_size
+        rb_node = parser(self, 2, ramdump,  rb_node, ion_info)
+    return orphan_buffer_size,  total_buffer_size
+
+
+def show_ion_dev_client(
+                        self,
+                        ramdump,
+                        ion_dev_rb_root,
+                        ionheap_id, ion_info):
+    global ion_heap_buffers
+    nr_clients = 0
+    client_name = 0
+    rb_node = parser(self, 1, ramdump,  ion_dev_rb_root,  ion_info)
+    ion_client_node_offset = ramdump.field_offset(
+                            'struct ion_client',  'node')
+    task_comm_offset = ramdump.field_offset(
+                        'struct task_struct',  'comm')
+    tempstr = "\n\n CLIENT: (struct ion_client *)0x{0:x} ,  "
+    str = tempstr + "task : {1} / ion_client : {2} / PID: {3} / Size : {4} KB"
+    str1 = tempstr + "ion_client : {1} / PID: {2} / Size : {3} KB"
+    if rb_node != 0:
+        while rb_node != 0:
+            ion_client = rb_node - ion_client_node_offset
+            heap_size = traverse_ion_heap_buffer(
+                                                            self,
+                                                            ramdump,
+                                                            ion_client,
+                                                            ionheap_id,
+                                                            ion_info)
+            if heap_size > 0:
+                nr_clients = nr_clients + 1
+                ion_client_task = ramdump.read_structure_field(
+                                    ion_client, 'struct ion_client', 'task')
+                task_comm = ion_client_task + task_comm_offset
+                client_name = ramdump.read_cstring(
+                                task_comm, TASK_NAME_LENGTH)
+                ion_client_name = ramdump.read_structure_field(
+                                    ion_client,
+                                    'struct ion_client',
+                                    'display_name')
+                ion_client_name = ramdump.read_cstring(
+                                    ion_client_name,
+                                    TASK_NAME_LENGTH)
+
+                client_PID = ramdump.read_structure_field(
+                                ion_client, 'struct ion_client', 'pid')
+                if ion_client_task != 0:
+                    ion_info.write(str.format(
+                                    ion_client, client_name, ion_client_name,
+                                    client_PID, bytes_to_KB(heap_size)))
+                else:
+                    ion_info.write(str1.format(
+                                    ion_client,  ion_client_name,
+                                    client_PID, bytes_to_KB(heap_size)))
+                for heap_buffer in ion_heap_buffers:
+                    ion_info.write(heap_buffer)
+            rb_node = parser(self, 2, ramdump,  rb_node,  ion_info)
+    return nr_clients
+
+
+def traverse_ion_heap_buffer(self, ramdump, ion_client,  ionheap_id, ion_info):
+    global ion_heap_buffers
+    ion_handle_root_offset = ramdump.field_offset(
+                            'struct ion_client', 'handles')
+    ion_handle_root_address = ion_client + ion_handle_root_offset
+    ion_buffer_heap_size = 0
+    ion_heap_buffers = []
+    str = "\n (+) ion_buffer: 0x{0:x} size: {1:0} KB Handle Count: {2:0}"
+    ion_handle_rb_node = parser(
+                        self, 1, ramdump, ion_handle_root_address, ion_info)
+    while ion_handle_rb_node != 0:
+        ion_handle = ion_handle_rb_node - self.ion_handle_node_offset
+        ion_buffer = ramdump.read_structure_field(
+                            ion_handle, 'struct ion_handle', 'buffer')
+        ion_buffer_size = ramdump.read_structure_field(
+                            ion_buffer, 'struct ion_buffer', 'size')
+        ion_buffer_heap = ramdump.read_structure_field(
+                            ion_buffer, 'struct ion_buffer', 'heap')
+        ion_heap_id = ramdump.read_structure_field(
+                            ion_buffer_heap, 'struct ion_heap', 'id')
+        if ionheap_id == ion_heap_id:
+            ion_buffer_heap_size = ion_buffer_heap_size + ion_buffer_size
+            ion_buffer_handlecount = ramdump.read_structure_field(
+                                        ion_buffer,
+                                        'struct ion_buffer', 'handle_count')
+            temp = str.format(
+                            ion_buffer,
+                            bytes_to_KB(ion_buffer_size),
+                            ion_buffer_handlecount)
+            ion_heap_buffers.append(temp)
+        ion_handle_rb_node = parser(
+                            self, 2, ramdump, ion_handle_rb_node, ion_info)
+    return ion_buffer_heap_size
+
+
+def parser(self, arg, ramdump, node, ion_info):
+    rb_root = 0
+    last_node = 0
+    self.orphan_size = 0
+    rbnode_left_offset = ramdump.field_offset('struct rb_node',  'rb_left')
+    temp = ramdump.read_word(node)
+    if temp == 0:
+        return 0
+    if arg == 1:
+        rb_root = find_rb_root(self, ramdump, node, ion_info)
+        last_node = find_rb_first(
+                    self, ramdump,  rb_root, rbnode_left_offset, ion_info)
+    if arg == 2:
+        last_node = find_rb_next(
+                    self, arg, ramdump, node, rbnode_left_offset, ion_info)
+    return last_node
+
+
+def find_rb_next(self, arg, ramdump, node, rbnode_left_offset, ion_info):
+    parent = cal_rb_parent(self, ramdump, node, ion_info)
+    tmp_node = 0
+    if parent == node:
+        ion_info.write("RETURNING NULL")
+        return 0
+    rbnode_right_offset = ramdump.field_offset('struct rb_node',  'rb_right')
+    rb_right = ramdump.read_word(node + rbnode_right_offset)
+    if rb_right != 0:  # right node exist
+        next_rb_node = find_rb_first(
+                        self, ramdump, rb_right, rbnode_left_offset,  ion_info)
+        return next_rb_node
+    else:  # no right node,  parse left node
+        flag = 1
+        while flag:
+            if parent == 0 or None:
+                tmp_node = 0
+                parent = 0
+            else:
+                parent = cal_rb_parent(self, ramdump, node, ion_info)
+                tmp_node = ramdump.read_word(parent + rbnode_right_offset)
+            if tmp_node == node:
+                node = parent
+                continue
+            else:
+                return parent
+    return 0
+
+
+def find_rb_first(self, ramdump, node, rbnode_left_offset, ion_info):
+    last_node = node
+    while node != 0:
+        last_node = node
+        node = ramdump.read_word(node + rbnode_left_offset)
+    return last_node
+
+
+def cal_rb_parent(self, ramdump, ion_dev_rb_root, ion_info):
+    rbnode_color_offset = ramdump.field_offset(
+                        'struct rb_node',  '__rb_parent_color')
+    color = ramdump.read_word(ion_dev_rb_root + rbnode_color_offset)
+    color = color & RB_PARENT_COLOR_MASK
+    return color
+
+
+def find_rb_root(self, ramdump, ion_dev_rb_root, ion_info):
+    parent = ion_dev_rb_root
+    rbnode_color_offset = ramdump.field_offset(
+                        'struct rb_node',  '__rb_parent_color')
+    color = ramdump.read_word(ion_dev_rb_root + rbnode_color_offset)
+    while color != 1:
+        parent = cal_rb_parent(self,  ramdump,  parent,  ion_info)
+        color = ramdump.read_word(parent + rbnode_color_offset)
+    return parent
+
+
+@register_parser('--print-ionbuffer',  'Print ion buffer',  optional=True)
+class DumpIonBuffer(RamParser):
+
+    def parse(self):
+        with self.ramdump.open_file('ionbuffer.txt') as ion_info:
+            if (self.ramdump.kernel_version < (3, 18, 0)):
+                ion_info.write('Kernel version 3.18 \
+                and above are supported, current version {0}.\
+                {1}'.format(self.ramdump.kernel_version[0],
+                            self.ramdump.kernel_version[1]))
+                return
+            do_dump_ionbuff_info(self, self.ramdump, ion_info)
-- 
GitLab