From c3aa69a97f1fc33133e6af571a0fc712f928b6b2 Mon Sep 17 00:00:00 2001
From: Ankur Bansal <ankban@codeaurora.org>
Date: Fri, 22 Jun 2018 17:00:06 +0530
Subject: [PATCH] lrdp_v2 : Add reserved_mem parser to linux-ramdump-parser

with this change, we can get reserverd_mem info, cma regions
and __softirq_pending stats.

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

diff --git a/linux-ramdump-parser-v2/parsers/reserved_mem.py b/linux-ramdump-parser-v2/parsers/reserved_mem.py
new file mode 100644
index 0000000..f45e526
--- /dev/null
+++ b/linux-ramdump-parser-v2/parsers/reserved_mem.py
@@ -0,0 +1,337 @@
+# Copyright (c) 2018 The Linux Foundation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 and
+# only version 2 as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+
+from parser_util import register_parser, RamParser
+from print_out import print_out_str
+from mm import get_vmemmap, page_buddy
+
+
+def print_reserved_mem(ramdump):
+    reserved_mem_addr = ramdump.address_of('reserved_mem')
+    output_file = ramdump.open_file("reserved_mem.txt")
+    reserved_mem_count = ramdump.read_int('reserved_mem_count')
+    size_of_reserved_mem = ramdump.sizeof('struct reserved_mem')
+    output_file.write("reserved_mem {\n")
+    str = "name = 0x{0:x} '{1}'\n\t\tbase = 0x{2:x}\n\t\tsize = 0x{" \
+          "3:x} ({4})KB\n\t\trange = <0x{5:x} - 0x{6:x}>\n\t"
+    index = 0
+    while index < reserved_mem_count:
+        reserved_mem = reserved_mem_addr + index*size_of_reserved_mem
+        name_addr = ramdump.read_structure_field(
+                            reserved_mem, 'struct reserved_mem', 'name')
+        name = ramdump.read_cstring(name_addr, 48)
+        base = ramdump.read_structure_field(
+                            reserved_mem, 'struct reserved_mem', 'base')
+        size = ramdump.read_structure_field(
+                            reserved_mem, 'struct reserved_mem', 'size')
+        output_file.write("\t{\n\t\t")
+        output_file.write(str.format(name_addr, name, base, size, size/1024,
+                                     base, base+size))
+        output_file.write("}\n")
+        index = index + 1
+    output_file.write("\n}")
+    output_file.close()
+
+
+def page_trace(ramdump, pfn):
+    if ramdump.is_config_defined("CONFIG_SPARSEMEM"):
+        mem_section = ramdump.read_word('mem_section')
+        if ramdump.kernel_version >= (4, 14):
+            mem_section = ramdump.read_word(mem_section)
+    else:
+        mem_section = ramdump.address_of('contig_page_data')
+    nr_entries_offset = 0
+    trace_entries_offset = 0
+    offset = 0
+    struct_holding_trace_entries = 0
+    trace_entry_size = ramdump.sizeof("unsigned long")
+    if ramdump.is_config_defined('CONFIG_SPARSEMEM'):
+        page_ext_offset = ramdump.field_offset(
+                            'struct mem_section', 'page_ext')
+    else:
+        page_ext_offset = ramdump.field_offset(
+                            'struct pglist_data', 'node_page_ext')
+    if ramdump.is_config_defined('CONFIG_STACKDEPOT'):
+        trace_entries_offset = ramdump.field_offset(
+                            'struct stack_record', 'entries')
+    else:
+        trace_entries_offset = ramdump.field_offset(
+                            'struct page_ext', 'trace_entries')
+    nr_entries_offset = ramdump.field_offset(
+                            'struct page_ext', 'nr_entries')
+    if ramdump.is_config_defined('CONFIG_SPARSEMEM'):
+        mem_section_size = ramdump.sizeof('struct mem_section')
+    else:
+        mem_section_size = 0
+    page_ext_size = ramdump.sizeof('struct page_ext')
+    if ramdump.kernel_version >= (4, 9):
+        page_owner_size = ramdump.sizeof('struct page_owner')
+        page_ext_size = page_ext_size + page_owner_size
+        page_owner_ops_offset = ramdump.read_structure_field(
+                'page_owner_ops', 'struct page_ext_operations', 'offset')
+    phys = pfn << 12
+    if phys is None or phys is 0:
+        return
+    offset = phys >> 30
+    if ramdump.is_config_defined("CONFIG_SPARSEMEM"):
+        mem_section_0_offset = (mem_section + (offset * mem_section_size))
+        page_ext = ramdump.read_word(
+                        mem_section_0_offset + page_ext_offset)
+    else:
+        page_ext = ramdump.read_word(mem_section + page_ext_offset)
+    if ramdump.arm64:
+        temp_page_ext = page_ext + (pfn * page_ext_size)
+    else:
+        pfn_index = pfn - (ramdump.phys_offset >> 12)
+        temp_page_ext = page_ext + (pfn_index * page_ext_size)
+
+    temp_page_ext = temp_page_ext + page_owner_ops_offset
+    if not ramdump.is_config_defined('CONFIG_STACKDEPOT'):
+        nr_trace_entries = ramdump.read_int(
+                            temp_page_ext + nr_entries_offset)
+        struct_holding_trace_entries = temp_page_ext
+    else:
+        handle = ramdump.read_structure_field(
+                    temp_page_ext, 'struct page_owner', 'handle')
+
+        slabindex = handle & 0x1fffff
+        handle_offset = (handle >> 0x15) & 0x3ff
+        handle_offset = handle_offset << 4
+        stack_slab = ramdump.address_of('stack_slabs')
+        stack_slab_size = ramdump.sizeof('void *')
+        slab = ramdump.read_word(
+                    stack_slab + (stack_slab_size * slabindex))
+        stack = slab + handle_offset
+        nr_trace_entries = ramdump.read_structure_field(
+                            stack, 'struct stack_record', 'size')
+        struct_holding_trace_entries = stack
+    if nr_trace_entries <= 0 or nr_trace_entries > 16:
+        return
+    alloc_str = ''
+    for i in range(0, nr_trace_entries):
+        addr = ramdump.read_word(
+                struct_holding_trace_entries + trace_entries_offset +
+                i*trace_entry_size)
+        if addr == 0:
+            break
+        look = ramdump.unwind_lookup(addr)
+        if look is None:
+            break
+        symname, offset = look
+        unwind_dat = '      [<{0:x}>] {1}+0x{2:x}\n'.format(
+                                addr, symname, offset)
+        alloc_str = alloc_str + unwind_dat
+    return alloc_str
+
+
+def parse_pfn(ramdump, pfn, cma, op_file):
+
+    vmemmap = get_vmemmap(ramdump)
+    page_size = ramdump.sizeof('struct page')
+    page = vmemmap + pfn*page_size
+    str = "{0} pfn : 0x{1:x} page : 0x{2:x} flag : 0x{3:x} mapping : 0x{" \
+          "4:x} count : {5} _mapcount : {6:x} {7}\n{8}\n"
+    str1 = "{0} pfn : 0x{1:x}--0x{2:x} head_page : 0x{3:x} flag : {4:x} " \
+           "mapping : 0x{5:x} count : {6} _mapcount : {7:x} {8}\n{9}\n"
+    str2 = "{0} pfn : 0x{1:x} pge : 0x{2:x} count : {3} _mapcount : " \
+           "{4:x} {5}\n"
+    str3 = "{0} pfn : 0x{1:x}--0x{2:x} head_page : 0x{3:x} count : {4} " \
+           "_mapcount : {5:x}  {6}\n"
+    page_flags = ramdump.read_structure_field(page, 'struct page', 'flags')
+    tail_page = ramdump.read_structure_field(
+                            page, 'struct page', 'compound_head')
+    if (tail_page & 1) == 1:
+        page = tail_page-1
+    nr_pages = 1
+    page_count = ramdump.read_structure_field(
+                            page, 'struct page', '_refcount.counter')
+    mapcount_offset = ramdump.field_offset('struct page', '_mapcount')
+    page_mapcount = ramdump.read_int(page + mapcount_offset)
+
+    if page_mapcount == 0xffffffff:
+        page_mapcount = -1
+    page_mapping = ramdump.read_structure_field(page, 'struct page', 'mapping')
+    is_pinned_str = ""
+    if (page_mapcount >= 0)and ((page_count - page_mapcount) >= 2):
+        is_pinned_str = "<===pinned"
+    if cma == 1:
+        cma_usage = "[devm]"
+    else:
+        cma_usage = "[ncma]"
+        # test if buddy
+        if page_mapcount == 0xffffff80:
+            cma_usage = "[budd]"
+            nr_pages = ramdump.read_structure_field(
+                            page, 'struct page', 'private')
+            nr_pages = 1 << nr_pages
+        elif page_mapping != 0:
+            anon_page = page_mapping & 0x1
+            if anon_page != 0:
+                cma_usage = "[anon]"
+            else:
+                cma_usage = "[file]"
+        else:
+            cma_usage = "[unkw]"
+
+    if ramdump.is_config_defined('CONFIG_PAGE_OWNER'):
+        if (page_buddy(ramdump, page)) or page_count == 0:
+            function_list = ""
+        else:
+            function_list = page_trace(ramdump, pfn)
+        if nr_pages == 1:
+            op_file.write(str.format(
+                cma_usage, pfn, page, page_flags, page_mapping, page_count,
+                page_mapcount, is_pinned_str, function_list))
+        else:
+            op_file.write(str1.format(cma_usage, pfn, pfn+nr_pages-1,
+                                      page, page_flags, page_mapping,
+                                      page_count, page_mapcount,
+                                      is_pinned_str, function_list))
+    else:
+        if nr_pages == 1:
+            op_file.write(str2.format(cma_usage, pfn, page, page_count,
+                                      page_mapcount, is_pinned_str))
+        else:
+            op_file.write(str3.format(
+                cma_usage, pfn, pfn+nr_pages-1, page, page_count,
+                page_mapcount, is_pinned_str))
+    return nr_pages
+
+
+def cma_region_dump(ramdump, cma, cma_name):
+    base_pfn = ramdump.read_structure_field(
+                        cma, 'struct cma', 'base_pfn')
+    cma_count = ramdump.read_structure_field(
+                        cma, 'struct cma', 'count')
+    bitmap = ramdump.read_structure_field(
+                        cma, 'struct cma', 'bitmap')
+    bitmap_end = bitmap + cma_count / 8
+    in_system = 1
+    end_pfn = base_pfn + cma_count
+    name = "cma_report_" + cma_name + ".txt"
+    op_file = ramdump.open_file(name)
+    op_file.write("CMA report\n")
+    op_file.write(" - name : {0}\n".format(cma_name))
+    op_file.write(" - base_pfn\t\t\t: 0x{0:x}\n".format(base_pfn))
+    op_file.write(" - end_pfn\t\t\t: 0x{0:x}\n".format(end_pfn))
+    op_file.write(" - count\t\t\t: 0x{0:x}\n".format(cma_count))
+    op_file.write(" - size\t\t\t\t: {0}KB\n".format(cma_count << 0x2))
+    op_file.write(" - bitmap_start\t\t: 0x{0:x}\n".format(bitmap))
+    op_file.write(" - bitmap_end\t\t: 0x{0:x}\n".format(bitmap_end))
+    op_file.write(" - in_system\t\t: {0}\n\n".format(in_system))
+
+    byte_index = 0
+    PFNS_PER_BYTE = 8
+    COUNT_TO_BYTE = cma_count / PFNS_PER_BYTE
+
+    while byte_index < COUNT_TO_BYTE:
+        pfn_index = 0
+        pfn = 0
+        while byte_index < COUNT_TO_BYTE:
+            value = ramdump.read_byte(bitmap+byte_index)
+            byte_to_advance = 1
+            while pfn_index < PFNS_PER_BYTE:
+                pfn = base_pfn + byte_index*PFNS_PER_BYTE + pfn_index
+                bit_value = (value >> pfn_index) & 0x1
+                cma = 0
+                if bit_value != 0:
+                    cma = 1
+                else:
+                    cma = 0
+                pfn_to_avance = 1
+                pfn_to_avance = parse_pfn(ramdump, pfn, cma, op_file)
+                pfn_index = pfn_index+pfn_to_avance
+                if pfn_index >= PFNS_PER_BYTE:
+                    byte_to_advance = pfn_index / PFNS_PER_BYTE
+                    pfn_index = pfn_index % 8
+                    byte_index = byte_index + byte_to_advance
+                    if byte_index >= COUNT_TO_BYTE:
+                        break
+            byte_index = byte_index+1
+    op_file.close()
+
+
+def print_cma_areas(ramdump):
+    output_file = ramdump.open_file("cma_report_simple.txt")
+    cma_area_count = ramdump.read_u32('cma_area_count')
+    cma_area_base_addr = ramdump.address_of('cma_areas')
+    cma_index = 0
+    size_of_cma_area = ramdump.sizeof('struct cma')
+    str = "cma : 0x{0:x} cma_base_pfn : 0x{1:x} size : 0x{2:x} pages ({3}KB)\n"
+    str1 = "name : {0}\n\n"
+    cma = [0] * cma_area_count
+    cma_name = [None] * cma_area_count
+
+    while cma_index < cma_area_count:
+        cma_area = cma_area_base_addr + cma_index*size_of_cma_area
+        base_pfn = ramdump.read_structure_field(
+                                cma_area, 'struct cma', 'base_pfn')
+        cma_size = ramdump.read_structure_field(
+                                cma_area, 'struct cma', 'count')
+        name_addr = ramdump.read_structure_field(
+                                cma_area, 'struct cma', 'name')
+        name = ramdump.read_cstring(name_addr, 48)
+        if name == "linux,cma":
+            name = "dma_contiguous_default_area"
+        cma[cma_index] = cma_area
+        cma_name[cma_index] = name
+        output_file.write(str.format(cma_area, base_pfn, cma_size, cma_size*4))
+        output_file.write(str1.format(name))
+        cma_index = cma_index + 1
+
+    output_file.close()
+
+    cma_index = 0
+    while cma_index < cma_area_count:
+        cma1 = cma[cma_index]
+        cma_name1 = cma_name[cma_index]
+        cma_region_dump(ramdump, cma1, cma_name1)
+        cma_index = cma_index + 1
+
+
+def parse_softirq_stat(ramdump):
+    irq_stat_addr = ramdump.address_of('irq_stat')
+    no_of_cpus = ramdump.get_num_cpus()
+    index = 0
+    size_of_irq_stat = ramdump.sizeof('irq_cpustat_t')
+    while index < no_of_cpus:
+        irq_stat = irq_stat_addr + index*size_of_irq_stat
+        softirq_pending = ramdump.read_structure_field(
+                                irq_stat, 'irq_cpustat_t', '__softirq_pending')
+        print_out_str("core {0} : __softirq_pending = {1}".format(
+                                index, softirq_pending))
+        index = index + 1
+
+
+@register_parser('--print-reserved-mem', 'Print reserved memory info ')
+class ReservedMem(RamParser):
+
+    def parse(self):
+        print_reserved_mem(self.ramdump)
+
+
+@register_parser('--print-cma-areas', 'Print cma memory region info ')
+class CmaAreas(RamParser):
+
+    def parse(self):
+        if self.ramdump.kernel_version < (4, 9):
+            print_out_str("Linux version lower than 4.9 is not supported!!")
+            return
+        else:
+            print_cma_areas(self.ramdump)
+
+
+@register_parser('--print-softirq-stat', 'Print softirq pending info ')
+class SoftirqStat(RamParser):
+
+    def parse(self):
+        parse_softirq_stat(self.ramdump)
-- 
GitLab