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