diff --git a/linux-ramdump-parser-v2/README b/linux-ramdump-parser-v2/README index 84993be6db794deadcb6770e0fd9595329fa77a7..efeea31b704496bf2a433ad2decd78694b32158a 100644 --- a/linux-ramdump-parser-v2/README +++ b/linux-ramdump-parser-v2/README @@ -92,6 +92,13 @@ gdb64_path - absolute path to the 64-bit gdb tool for the ramdumps nm64_path - absolute path to the 64-bit nm tool for the ramdumps qtf_path - absolute path to qtf tool executable scandump_parser_path - absolute path to scandump parser for the ramdumps +crashtool - absolute path to the 'crash' tool that is able to provide + gdb like debugging and also host an extension that extracts + ftrace +trace_ext - shared library extension that allows the 'crash' tool to read + raw ftrace data from a ramdump and dump it into a binary format +tracecmdtool - absolute path to the trace-cmd tool that converts the binary + trace format created by trace_ext to human readable ftrace Note that local_settings.py is just a python file so the file may take advantage of python features. diff --git a/linux-ramdump-parser-v2/aarch64iommulib.py b/linux-ramdump-parser-v2/aarch64iommulib.py old mode 100755 new mode 100644 index de13e0bec26b29337b38a408ae584d7d9e091228..f14a9b4ec17a8c5c0a2180eb6589f3868b37c818 --- a/linux-ramdump-parser-v2/aarch64iommulib.py +++ b/linux-ramdump-parser-v2/aarch64iommulib.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, The Linux Foundation. All rights reserved. +# Copyright (c) 2016-2017, 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 @@ -28,26 +28,42 @@ LL_PAGE_MASK = 0xFFFFFFFFF000 LL_AP_BITS = (0x3 << 6) LL_CH = (0x1 << 52) +LL_XN = (0x1 << 54) +LL_ATTR_INDX = (0x7 << 2) +LL_SH_BITS = (0x3 << 8) + +ATTR_IDX_NONCACHED = 0x0 +ATTR_IDX_CACHE = 0x1 +ATTR_IDX_DEV = 0x2 + +SH_NON_SHARE = (0x0 << 8) +SH_RESERVED = (0x1 << 8) +SH_OUTER_SHARE = (0x2 << 8) +SH_INNER_SHARE = (0x3 << 8) LL_AP_RO = (0x3 << 6) LL_AP_RW = (0x1 << 6) LL_AP_PR_RW = (0x0 << 6) LL_AP_PR_RO = (0x2 << 6) - class FlatMapping(object): - def __init__(self, virt, phys=-1, type='[]', size=SZ_4K, mapped=False): + def __init__(self, virt, phys=-1, type='[]', size=SZ_4K, attr_indx_str='[]', + shareability_str='[]', execute_never_str='[]', mapped=False): self.virt = virt self.phys = phys self.type = type self.map_size = size + self.attr_indx_str = attr_indx_str + self.shareability_str = shareability_str + self.execute_never_str = execute_never_str self.mapped = mapped class CollapsedMapping(object): def __init__(self, virt_start, virt_end, phys_start=-1, phys_end=-1, - map_type='[]', map_size=SZ_4K, mapped=False): + map_type='[]', map_size=SZ_4K, attr_indx_str='[]', + shareability_str='[]', execute_never_str='[]', mapped=False): self.virt_start = virt_start self.virt_end = virt_end - 1 @@ -55,13 +71,18 @@ class CollapsedMapping(object): self.phys_end = phys_end - 1 self.map_type = map_type self.map_size = map_size + self.attr_indx_str = attr_indx_str + self.shareability_str = shareability_str + self.execute_never_str = execute_never_str self.mapped = mapped def add_collapsed_mapping(mappings, virt_start, virt_end, phys_start, phys_end, - map_type, map_size, mapped): + map_type, map_size, attr_indx_str, shareability_str, + execute_never_str, mapped): map = CollapsedMapping(virt_start, virt_end, phys_start, phys_end, - map_type, map_size, mapped) + map_type, map_size, attr_indx_str, shareability_str, + execute_never_str, mapped) if virt_start not in mappings: mappings[virt_start] = map @@ -101,7 +122,9 @@ def create_collapsed_mapping(flat_mapping): collapsed_mapping, start_map.virt, map.virt, start_map.phys, start_map.phys + start_map.map_size, - start_map.type, start_map.map_size, start_map.mapped) + start_map.type, start_map.map_size, map.attr_indx_str, + map.shareability_str, map.execute_never_str, + start_map.mapped) start_map = map elif last_mapping: @@ -109,14 +132,17 @@ def create_collapsed_mapping(flat_mapping): collapsed_mapping, start_map.virt, 0xFFFFFFFFFFFF + 1, start_map.phys, start_map.phys + start_map.map_size, - start_map.type, start_map.map_size, start_map.mapped) + start_map.type, start_map.map_size, map.attr_indx_str, + map.shareability_str, map.execute_never_str, + start_map.mapped) prev_map = map return collapsed_mapping -def add_flat_mapping(mappings, fl_idx, sl_idx, tl_idx, ll_idx, - phy_addr, map_type, page_size, mapped): +def add_flat_mapping(mappings, fl_idx, sl_idx, tl_idx, ll_idx, phy_addr, + map_type, page_size, attr_indx, shareability, + xn_bit, mapped): virt = (fl_idx << 39) | (sl_idx << 30) | (tl_idx << 21) | (ll_idx << 12) map_type_str = '[R/W]' @@ -127,7 +153,37 @@ def add_flat_mapping(mappings, fl_idx, sl_idx, tl_idx, ll_idx, elif map_type == LL_AP_PR_RO: map_type_str = '[P RO]' - map = FlatMapping(virt, phy_addr, map_type_str, page_size, mapped) + if shareability != -1: + if shareability == SH_NON_SHARE: + shareability_str = 'Non-Shareable' + if shareability == SH_RESERVED: + shareability_str = 'Reserved' + if shareability == SH_OUTER_SHARE: + shareability_str = 'Outer-Shareable' + if shareability == SH_INNER_SHARE: + shareability_str = 'Inner-Shareable' + else: + shareability_str = 'N/A' + + if attr_indx != -1: + if attr_indx == ATTR_IDX_NONCACHED: + attr_indx_str = 'Non-Cached' + if attr_indx == ATTR_IDX_CACHE: + attr_indx_str = 'Cached' + if attr_indx == ATTR_IDX_DEV: + attr_indx_str = 'Device' + else: + attr_indx_str = 'N/A' + + if xn_bit == 1: + execute_never_str = 'True' + elif xn_bit == 0: + execute_never_str = 'False' + elif xn_bit == -1: + execute_never_str = 'N/A' + + map = FlatMapping(virt, phy_addr, map_type_str, page_size, attr_indx_str, + shareability_str, execute_never_str, mapped) if virt not in mappings: mappings[virt] = map @@ -153,7 +209,6 @@ def get_super_section_mapping_info(ramdump, pg_table, index): return (current_phy_addr, current_page_size, current_map_type, status) - def get_section_mapping_info(ramdump, pg_table, index): phy_addr = ramdump.read_u64(pg_table, False) current_phy_addr = -1 @@ -161,10 +216,22 @@ def get_section_mapping_info(ramdump, pg_table, index): current_map_type = 0 status = True section_skip_count = 0 + attr_indx = 0 + sh_bits = -1 + xn_bit = 0 + if phy_addr is not None: current_map_type = phy_addr & LL_AP_BITS + attr_indx = ( (phy_addr & LL_ATTR_INDX) >> 2 ) + if attr_indx == ATTR_IDX_NONCACHED or attr_indx == ATTR_IDX_CACHE: + sh_bits = phy_addr & LL_SH_BITS # Shareability info available + # only for Normal Memory + + if phy_addr & LL_XN: + xn_bit = 1 + if phy_addr & LL_CH: current_phy_addr = phy_addr & 0xFFFFFE000000 current_page_size = SZ_32M @@ -175,7 +242,7 @@ def get_section_mapping_info(ramdump, pg_table, index): current_page_size = SZ_2M return (current_phy_addr, current_page_size, current_map_type, - status, section_skip_count) + status, section_skip_count, attr_indx, sh_bits, xn_bit) def get_mapping_info(ramdump, pg_table, index): @@ -186,12 +253,23 @@ def get_mapping_info(ramdump, pg_table, index): current_map_type = 0 status = True skip_count = 0 + attr_indx = 0 + sh_bits = -1 + xn_bit = 0 if phy_addr is not None: current_map_type = phy_addr & LL_AP_BITS if phy_addr & LL_TYPE_PAGE: current_phy_addr = phy_addr & 0xFFFFFFFFF000 + attr_indx = ( (phy_addr & LL_ATTR_INDX) >> 2 ) + if attr_indx == ATTR_IDX_NONCACHED or attr_indx == ATTR_IDX_CACHE: + sh_bits = phy_addr & LL_SH_BITS # Shareability info available + # only for Normal Memory + + if phy_addr & LL_XN: + xn_bit = 1 + if phy_addr & LL_CH: current_phy_addr = phy_addr & 0xFFFFFFFF0000 current_page_size = SZ_64K @@ -203,7 +281,7 @@ def get_mapping_info(ramdump, pg_table, index): current_phy_addr = phy_addr status = False return (current_phy_addr, current_page_size, current_map_type, - status, skip_count) + status, skip_count, attr_indx, sh_bits, xn_bit) def fl_entry(ramdump, fl_pte, skip_fl): @@ -233,7 +311,7 @@ def parse_2nd_level_table(ramdump, sl_pg_table_entry, fl_index, tmp_mapping = add_flat_mapping( tmp_mapping, fl_index, sl_index, tl_index, 0, -1, - -1, SZ_2M, False) + -1, SZ_2M, -1, -1, -1, False) tl_pte += 8 continue @@ -248,41 +326,37 @@ def parse_2nd_level_table(ramdump, sl_pg_table_entry, fl_index, continue (phy_addr, page_size, map_type, status, - skip_count) = get_mapping_info( - ramdump, ll_pte, - ll_index) + skip_count, attr_indx, shareability, + xn_bit) = get_mapping_info(ramdump, ll_pte, ll_index) if status and phy_addr != -1: tmp_mapping = add_flat_mapping( tmp_mapping, fl_index, sl_index, - tl_index, ll_index, phy_addr, - map_type, page_size, True) + tl_index, ll_index, phy_addr, map_type, + page_size, attr_indx, shareability, xn_bit, True) else: tmp_mapping = add_flat_mapping( tmp_mapping, fl_index, sl_index, tl_index, ll_index, -1, - -1, page_size, False) + -1, page_size, attr_indx, shareability, xn_bit, False) elif tl_entry_type == FLSL_TYPE_BLOCK: if section_skip_count: section_skip_count -= 1 continue - (phy_addr, page_size, - map_type, status, - section_skip_count) = get_section_mapping_info( - ramdump, tl_pte, tl_index) - + (phy_addr, page_size, map_type, status, + section_skip_count, attr_indx, shareability, + xn_bit) = get_section_mapping_info(ramdump, tl_pte, tl_index) if status and phy_addr != -1: tmp_mapping = add_flat_mapping( tmp_mapping, fl_index, sl_index, tl_index, 0, phy_addr, - map_type, page_size, True) + map_type, page_size, attr_indx, shareability, xn_bit, True) tl_pte += 8 return tmp_mapping - def create_flat_mappings(ramdump, pg_table, level): tmp_mapping = {} fl_pte = pg_table @@ -307,7 +381,7 @@ def create_flat_mappings(ramdump, pg_table, level): if fl_pg_table_entry == 0: tmp_mapping = add_flat_mapping( tmp_mapping, fl_index, 0, 0, 0, - -1, -1, SZ_256G, False) + -1, -1, SZ_256G, -1, -1, -1, False) fl_pte += 8 continue @@ -318,7 +392,7 @@ def create_flat_mappings(ramdump, pg_table, level): if sl_pg_table_entry == 0 or sl_pg_table_entry is None: tmp_mapping = add_flat_mapping(tmp_mapping, fl_index, sl_index, 0, 0, - -1, -1, SZ_1G, False) + -1, -1, SZ_1G, -1, -1, -1, False) sl_pte += 8 continue @@ -332,9 +406,10 @@ def create_flat_mappings(ramdump, pg_table, level): = get_super_section_mapping_info(ramdump, sl_pte, sl_index) if status and phy_addr != -1: + #TODO: Fix memory attributes for 2nd-level entry tmp_mapping = add_flat_mapping( tmp_mapping, fl_index, sl_index, 0, 0, - phy_addr, map_type, page_size, True) + phy_addr, map_type, page_size, -1, -1, -1, True) sl_pte += 8 fl_pte += 8 @@ -355,12 +430,13 @@ def parse_aarch64_tables(ramdump, d, domain_num): iommu_context = iommu_context or 'None attached' outfile.write( - 'IOMMU Context: %s. Domain: %s' + 'IOMMU Contextttt: %s. Domain: %s' '[L2 cache redirect for page tables is %s]\n' % ( iommu_context, d.client_name, redirect)) outfile.write( '[VA Start -- VA End ] [Size ] [PA Start -- PA End ] ' - '[Attributes][Page Table Entry Size]\n') + '[Attributes][Page Table Entry Size] [Memory Type] ' + '[Shareability] [Non-Executable] \n') if d.pg_table == 0: outfile.write( 'No Page Table Found. (Probably a secure domain)\n') @@ -373,11 +449,14 @@ def parse_aarch64_tables(ramdump, d, domain_num): if mapping.mapped: outfile.write( - '0x%x--0x%x [0x%x] A:0x%x--0x%x [0x%x] %s[%s] \n' % + '0x%x--0x%x [0x%x] A:0x%x--0x%x [0x%x] %s[%s] [%s] ' + '[%s] [%s]\n' % (mapping.virt_start, mapping.virt_end, mapping.map_size, mapping.phys_start, mapping.phys_end, mapping.map_size, mapping.map_type, - order_size_strings[get_order(mapping.map_size)])) + order_size_strings[get_order(mapping.map_size)], + mapping.attr_indx_str, mapping.shareability_str, + mapping.execute_never_str)) else: outfile.write( '0x%x--0x%x [0x%x] [UNMAPPED]\n' % diff --git a/linux-ramdump-parser-v2/boards.py b/linux-ramdump-parser-v2/boards.py index 79c385f49f1e66e6a61788c434c3d8a56f4f3bad..3909b106623b8774ad99ede4b8d907230b00d093 100755 --- a/linux-ramdump-parser-v2/boards.py +++ b/linux-ramdump-parser-v2/boards.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +# Copyright (c) 2014-2017, 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 @@ -415,6 +415,20 @@ class BoardCobalt(Board): self.wdog_addr = 0x146BF658 self.imem_file_name = 'OCIMEM.BIN' +class BoardSDM845(Board): + def __init__(self, socid): + super(BoardSDM845, self).__init__() + self.socid = socid + self.board_num = "sdm845" + self.cpu = 'CORTEXA53' + self.ram_start = 0x80000000 + self.smem_addr = 0x6000000 + self.phys_offset = 0x80000000 + self.imem_start = 0x14680000 + self.kaslr_addr = 0x146bf6d0 + self.wdog_addr = 0x146BF658 + self.imem_file_name = 'OCIMEM.BIN' + class Board8998(Board): def __init__(self, socid): super(Board8998, self).__init__() @@ -439,6 +453,7 @@ class Board660(Board): self.smem_addr = 0x6000000 self.phys_offset = 0x80000000 self.imem_start = 0x14680000 + self.kaslr_addr = 0x146bf6d0 self.wdog_addr = 0x146BF658 self.imem_file_name = 'OCIMEM.BIN' @@ -452,6 +467,7 @@ class Board630(Board): self.smem_addr = 0x6000000 self.phys_offset = 0x80000000 self.imem_start = 0x14680000 + self.kaslr_addr = 0x146bf6d0 self.wdog_addr = 0x146BF658 self.imem_file_name = 'OCIMEM.BIN' @@ -665,6 +681,8 @@ boards.append(Board660(socid=326)) boards.append(Board630(socid=318)) boards.append(Board630(socid=327)) +boards.append(BoardSDM845(socid=321)) + def get_supported_boards(): """ Called by other part of the code to get a list of boards """ return boards diff --git a/linux-ramdump-parser-v2/cachedumplib.py b/linux-ramdump-parser-v2/cachedumplib.py old mode 100755 new mode 100644 index d6568940a26e451978584a2a60658f8b70be809f..18b43e8c483134c27fa9e8c6fcd46c66555d2705 --- a/linux-ramdump-parser-v2/cachedumplib.py +++ b/linux-ramdump-parser-v2/cachedumplib.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +# Copyright (c) 2015-2017, 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 @@ -431,6 +431,181 @@ class L1_ICache_KRYO2XX_GOLD(CacheDumpType_v1): output.append(n) output.append(addr) +class L1_DCache_KRYO3XX_SILVER(CacheDumpType_v1): + """Refer to documentation:ad003_atrm""" + def __init__(self): + super(L1_DCache_KRYO3XX_SILVER, self).__init__() + self.tableformat.addColumn('MESI') + self.tableformat.addColumn('Tag Address [39:12]') + self.tableformat.addColumn('NS') + self.tableformat.addColumn('Outer Allocation Hint') + self.unsupported_header_offset = 0 + self.TagSize = 2 + self.LineSize = 16 + self.NumSets = 0x80 + self.NumWays = 4 + + def MESI_to_string(MESI_d): + if MESI_d == 0: + return 'I' + elif MESI_d == 1: + return 'S' + elif MESI_d == 2: + return 'E' + else: + return 'M' + + def parse_tag_fn(self, output, data, nset, nway): + if self.TagSize != 2: + raise Exception('cache tag size mismatch') + + MESI_d = (data[1] >> 30) & 0x3 + addr = (data[1] >> 1) & 0xfffffff + ns = (data[1] >> 29) & 0x1 + alloc_hint = data[0] & 0x1 + + mesi = self.MESI_to_string(MESI_d) + output.append(mesi) + output.append(addr) + output.append(ns) + output.append(alloc_hint) + +class L1_ICache_KRYO3XX_SILVER(CacheDumpType_v1): + """Refer to documentation:ad003_atrm""" + def __init__(self): + super(L1_ICache_KRYO3XX_SILVER, self).__init__() + self.tableformat.addColumn('Valid and set mode') + self.tableformat.addColumn('NS') + self.tableformat.addColumn('Tag address') + self.unsupported_header_offset = 0 + self.TagSize = 2 + self.LineSize = 16 + self.NumSets = 0x80 + self.NumWays = 4 + + def valid_to_string(valid_d): + if valid_d == 0: + return 'A32' + elif valid_d == 1: + return 'T32' + elif valid_d == 2: + return 'A64' + else: + return 'Invalid' + + def parse_tag_fn(self, output, data, nset, nway): + if self.TagSize != 2: + raise Exception('cache tag size mismatch') + + valid_d = (data[0] >> 29) & 0x3 + ns = (data[0] >> 28) & 0x1 + addr = data[0] & 0xfffffff + + set_mode = self.valid_to_string(valid_d) + output.append(set_mode) + output.append(ns) + output.append(addr) + +class L1_DCache_KRYO3XX_GOLD(CacheDumpType_v1): + """Refer to documentation:ad003_atrm""" + def __init__(self): + super(L1_DCache_KRYO3XX_GOLD, self).__init__() + self.tableformat.addColumn('PA [43:12]') + self.tableformat.addColumn('MESI') + self.unsupported_header_offset = 0 + self.TagSize = 3 + self.LineSize = 16 + self.NumSets = 0x40 + self.NumWays = 16 + + def MESI_to_string(MESI_d): + if MESI_d == 0: + return 'I' + elif MESI_d == 1: + return 'S' + elif MESI_d == 2: + return 'E' + else: + return 'M' + + def parse_tag_fn(self, output, data, nset, nway): + if self.TagSize != 3: + raise Exception('cache tag size mismatch') + + addr_lower = (data[0] >> 10) & 0x3fffff + addr_higher = data[1] & 0x3ff + mesi_d = (data[0] >> 2) & 0x3 + + addr = (addr_higher << 22) | addr_lower + mesi = MESI_to_string(mesi_d) + output.append(addr) + output.append(mesi) + + +class L1_ICache_KRYO3XX_GOLD(CacheDumpType_v1): + """Refer to documentation:ad003_atrm""" + def __init__(self): + super(L1_ICache_KRYO3XX_GOLD, self).__init__() + self.tableformat.addColumn('Valid and set mode') + self.tableformat.addColumn('NS') + self.tableformat.addColumn('Tag address') + self.unsupported_header_offset = 0 + self.TagSize = 2 + self.LineSize = 16 + self.NumSets = 0x100 + self.NumWays = 4 + + def parse_tag_fn(self, output, data, nset, nway): + if self.TagSize != 2: + raise Exception('cache tag size mismatch') + + valid = (data[0] >> 29) & 0x1 + ns = (data[0] >> 28) & 0x1 + addr = data[0] & 0xfffffff + + output.append(valid) + output.append(ns) + output.append(addr) + +class LLC_SYSTEM_CACHE_KRYO3XX(CacheDumpType_v1): + """Refer to documentation:LLC_HDD""" + def __init__(self): + super(LLC_SYSTEM_CACHE_KRYO3XX, self).__init__() + self.tableformat.addColumn('G0 Valid') + self.tableformat.addColumn('G0 Dirty') + self.tableformat.addColumn('G1 Valid') + self.tableformat.addColumn('G1 Dirty') + self.tableformat.addColumn('SCID') + self.tableformat.addColumn('ECC') + self.tableformat.addColumn('Tag address') + self.unsupported_header_offset = 0 + self.TagSize = 2 + self.LineSize = 16 + self.NumSets = 0x400 + self.NumWays = 12 + + def parse_tag_fn(self, output, data, nset, nway): + if self.TagSize != 2: + raise Exception('cache tag size mismatch') + + G0_valid = data[0] & 0x1 + G1_valid = (data[0] >> 2) & 0x1 + G0_dirty = (data[0] >> 3) & 0x1 + G1_dirty = (data[0] >> 4) & 0x1 + SCID = (data[0] >> 7) & 0x1f + ECC_bits = (data[0] >> 14) & 0x7f + + DONE_bit = (data[1] >> 28) & 0x1 + addr = data[1] & 0x3fffffff + + output.append(G0_valid) + output.append(G0_dirty) + output.append(G1_valid) + output.append(G1_dirty) + output.append(SCID) + output.append(ECC_bits) + output.append(addr) + L1_DCache_KRYO2XX_SILVER = L1_DCache_A53 L1_ICache_KYRO2XX_SILVER = L1_ICache_A53 @@ -454,6 +629,32 @@ lookuptable[("8998", 0x65, 0x14)] = L1_ICache_KRYO2XX_GOLD() lookuptable[("8998", 0x66, 0x14)] = L1_ICache_KRYO2XX_GOLD() lookuptable[("8998", 0x67, 0x14)] = L1_ICache_KRYO2XX_GOLD() +# "sdm845" +lookuptable[("sdm845", 0x80, 0x14)] = L1_DCache_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x81, 0x14)] = L1_DCache_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x82, 0x14)] = L1_DCache_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x83, 0x14)] = L1_DCache_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x84, 0x14)] = L1_DCache_KRYO3XX_GOLD() +lookuptable[("sdm845", 0x85, 0x14)] = L1_DCache_KRYO3XX_GOLD() +lookuptable[("sdm845", 0x86, 0x14)] = L1_DCache_KRYO3XX_GOLD() +lookuptable[("sdm845", 0x87, 0x14)] = L1_DCache_KRYO3XX_GOLD() + + +lookuptable[("sdm845", 0x60, 0x14)] = L1_ICache_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x61, 0x14)] = L1_ICache_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x62, 0x14)] = L1_ICache_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x63, 0x14)] = L1_ICache_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x64, 0x14)] = L1_ICache_KRYO3XX_GOLD() +lookuptable[("sdm845", 0x65, 0x14)] = L1_ICache_KRYO3XX_GOLD() +lookuptable[("sdm845", 0x66, 0x14)] = L1_ICache_KRYO3XX_GOLD() +lookuptable[("sdm845", 0x67, 0x14)] = L1_ICache_KRYO3XX_GOLD() + + +lookuptable[("sdm845", 0x121, 0x14)] = LLC_SYSTEM_CACHE_KRYO3XX() +lookuptable[("sdm845", 0x122, 0x14)] = LLC_SYSTEM_CACHE_KRYO3XX() +lookuptable[("sdm845", 0x123, 0x14)] = LLC_SYSTEM_CACHE_KRYO3XX() +lookuptable[("sdm845", 0x124, 0x14)] = LLC_SYSTEM_CACHE_KRYO3XX() + # "sdm660" lookuptable[("660", 0x80, 0x14)] = L1_DCache_KRYO2XX_SILVER() lookuptable[("660", 0x81, 0x14)] = L1_DCache_KRYO2XX_SILVER() @@ -545,12 +746,20 @@ lookuptable[("8917", 0x84, 0x14)] = L1_DCache_A53() lookuptable[("8917", 0x85, 0x14)] = L1_DCache_A53() lookuptable[("8917", 0x86, 0x14)] = L1_DCache_A53() lookuptable[("8917", 0x87, 0x14)] = L1_DCache_A53() +lookuptable[("8917", 0x64, 0x14)] = L1_ICache_A53() +lookuptable[("8917", 0x65, 0x14)] = L1_ICache_A53() +lookuptable[("8917", 0x66, 0x14)] = L1_ICache_A53() +lookuptable[("8917", 0x67, 0x14)] = L1_ICache_A53() # 8920 lookuptable[("8920", 0x84, 0x14)] = L1_DCache_A53() lookuptable[("8920", 0x85, 0x14)] = L1_DCache_A53() lookuptable[("8920", 0x86, 0x14)] = L1_DCache_A53() lookuptable[("8920", 0x87, 0x14)] = L1_DCache_A53() +lookuptable[("8920", 0x64, 0x14)] = L1_ICache_A53() +lookuptable[("8920", 0x65, 0x14)] = L1_ICache_A53() +lookuptable[("8920", 0x66, 0x14)] = L1_ICache_A53() +lookuptable[("8920", 0x67, 0x14)] = L1_ICache_A53() # 8937 lookuptable[("8937", 0x80, 0x14)] = L1_DCache_A53() @@ -561,6 +770,14 @@ lookuptable[("8937", 0x84, 0x14)] = L1_DCache_A53() lookuptable[("8937", 0x85, 0x14)] = L1_DCache_A53() lookuptable[("8937", 0x86, 0x14)] = L1_DCache_A53() lookuptable[("8937", 0x87, 0x14)] = L1_DCache_A53() +lookuptable[("8937", 0x60, 0x14)] = L1_ICache_A53() +lookuptable[("8937", 0x61, 0x14)] = L1_ICache_A53() +lookuptable[("8937", 0x62, 0x14)] = L1_ICache_A53() +lookuptable[("8937", 0x63, 0x14)] = L1_ICache_A53() +lookuptable[("8937", 0x64, 0x14)] = L1_ICache_A53() +lookuptable[("8937", 0x65, 0x14)] = L1_ICache_A53() +lookuptable[("8937", 0x66, 0x14)] = L1_ICache_A53() +lookuptable[("8937", 0x67, 0x14)] = L1_ICache_A53() # 8940 lookuptable[("8940", 0x80, 0x14)] = L1_DCache_A53() @@ -571,6 +788,14 @@ lookuptable[("8940", 0x84, 0x14)] = L1_DCache_A53() lookuptable[("8940", 0x85, 0x14)] = L1_DCache_A53() lookuptable[("8940", 0x86, 0x14)] = L1_DCache_A53() lookuptable[("8940", 0x87, 0x14)] = L1_DCache_A53() +lookuptable[("8940", 0x60, 0x14)] = L1_ICache_A53() +lookuptable[("8940", 0x61, 0x14)] = L1_ICache_A53() +lookuptable[("8940", 0x62, 0x14)] = L1_ICache_A53() +lookuptable[("8940", 0x63, 0x14)] = L1_ICache_A53() +lookuptable[("8940", 0x64, 0x14)] = L1_ICache_A53() +lookuptable[("8940", 0x65, 0x14)] = L1_ICache_A53() +lookuptable[("8940", 0x66, 0x14)] = L1_ICache_A53() +lookuptable[("8940", 0x67, 0x14)] = L1_ICache_A53() # 8953 lookuptable[("8953", 0x80, 0x14)] = L1_DCache_A53() diff --git a/linux-ramdump-parser-v2/debug_image_v2.py b/linux-ramdump-parser-v2/debug_image_v2.py index 8d0e7b12a0dda3dbf16ee153041eaa6882df97c4..81e54907f5663a985d5fa654577c37075504450b 100755 --- a/linux-ramdump-parser-v2/debug_image_v2.py +++ b/linux-ramdump-parser-v2/debug_image_v2.py @@ -27,6 +27,7 @@ from print_out import print_out_str, print_out_exception from qdss import QDSSDump from watchdog_v2 import TZRegDump_v2 from cachedumplib import lookup_cache_type +from tlbdumplib import lookup_tlb_type from vsens import VsensData MEMDUMPV2_MAGIC = 0x42445953 @@ -51,6 +52,7 @@ class client(object): MSM_DUMP_DATA_LOG_BUF = 0x110 MSM_DUMP_DATA_LOG_BUF_FIRST_IDX = 0x111 MSM_DUMP_DATA_L2_TLB = 0x120 + MSM_DUMP_DATA_LLC_CACHE = 0x121 MSM_DUMP_DATA_SCANDUMP = 0xEB MSM_DUMP_DATA_MAX = MAX_NUM_ENTRIES @@ -58,8 +60,8 @@ class client(object): client_types = [ ('MSM_DUMP_DATA_SCANDUMP', 'parse_scandump'), ('MSM_DUMP_DATA_CPU_CTX', 'parse_cpu_ctx'), - ('MSM_DUMP_DATA_L1_INST_TLB', 'parse_l1_inst_tlb'), - ('MSM_DUMP_DATA_L1_DATA_TLB', 'parse_l1_data_tlb'), + ('MSM_DUMP_DATA_L1_INST_TLB', 'parse_tlb_common'), + ('MSM_DUMP_DATA_L1_DATA_TLB', 'parse_tlb_common'), ('MSM_DUMP_DATA_L1_INST_CACHE', 'parse_cache_common'), ('MSM_DUMP_DATA_L1_DATA_CACHE', 'parse_cache_common'), ('MSM_DUMP_DATA_L2_CACHE', 'parse_cache_common'), @@ -73,6 +75,7 @@ client_types = [ ('MSM_DUMP_DATA_TMC_ETF', 'parse_qdss_common'), ('MSM_DUMP_DATA_TMC_REG', 'parse_qdss_common'), ('MSM_DUMP_DATA_L2_TLB', 'parse_l2_tlb'), + ('MSM_DUMP_DATA_LLC_CACHE', 'parse_system_cache_common'), ] qdss_tag_to_field_name = { @@ -95,7 +98,6 @@ class DebugImage_v2(): else: self.event_call = 'struct ftrace_event_call' self.event_class = 'struct ftrace_event_class' - self.has_scan_dump = False def parse_scandump(self, version, start, end, client_id, ram_dump): scandump_file_prefix = "scandump" @@ -104,8 +106,6 @@ class DebugImage_v2(): except AttributeError: print_out_str('Could not find scandump_parser_path . Please define scandump_parser_path in local_settings') return - if client_id == client.MSM_DUMP_DATA_SCANDUMP: - self.has_scan_dump = True output = os.path.join(ram_dump.outdir, scandump_file_prefix) input = os.path.join(ram_dump.outdir, "vv_msg_4_header.bin") print_out_str( @@ -126,7 +126,7 @@ class DebugImage_v2(): print_out_str( 'Parsing CPU{2} context start {0:x} end {1:x}'.format(start, end, core)) - regs = TZRegDump_v2(self.has_scan_dump) + regs = TZRegDump_v2() if regs.init_regs(version, start, end, core, ram_dump) is False: print_out_str('!!! Could not get registers from TZ dump') return @@ -212,6 +212,40 @@ class DebugImage_v2(): print_out_exception() outfile.close() + def parse_system_cache_common(self, version, start, end, client_id, ramdump): + client_name = self.dump_data_id_lookup_table[client_id] + bank_number = client_id - client.MSM_DUMP_DATA_LLC_CACHE + + filename = '{0}_0x{1:x}'.format(client_name, bank_number) + outfile = ramdump.open_file(filename) + cache_type = lookup_cache_type(ramdump.hw_id, client_id, version) + try: + cache_type.parse(start, end, ramdump, outfile) + except NotImplementedError: + print_out_str('System cache dumping not supported' + % client_name) + except: + print_out_str('!!! Unhandled exception while running {0}'.format(client_name)) + print_out_exception() + outfile.close() + + def parse_tlb_common(self, version, start, end, client_id, ramdump): + client_name = self.dump_data_id_lookup_table[client_id] + core = client_id & 0xF + filename = '{0}_0x{1:x}'.format(client_name, core) + outfile = ramdump.open_file(filename) + cache_type = lookup_tlb_type(ramdump.hw_id, client_id, version) + try: + cache_type.parse(start, end, ramdump, outfile) + except NotImplementedError: + print_out_str('TLB dumping not supported for %s on this target' + % client_name) + except: + print_out_str('!!! Unhandled exception while running {0}'.format(client_name)) + print_out_exception() + outfile.close() + + def ftrace_field_func(self, common_list, ram_dump): name_offset = ram_dump.field_offset('struct ftrace_event_field', 'name') type_offset = ram_dump.field_offset('struct ftrace_event_field', 'type') @@ -470,6 +504,10 @@ class DebugImage_v2(): client.MSM_DUMP_DATA_L2_CACHE + i] = 'MSM_DUMP_DATA_L2_CACHE' self.dump_data_id_lookup_table[ client.MSM_DUMP_DATA_ETM_REG + i] = 'MSM_DUMP_DATA_ETM_REG' + + for i in range(0, 4): + self.dump_data_id_lookup_table[ + client.MSM_DUMP_DATA_LLC_CACHE + i] = 'MSM_DUMP_DATA_LLC_CACHE' # 0x100 - tmc-etr registers and 0x101 - for tmc-etf registers self.dump_data_id_lookup_table[ client.MSM_DUMP_DATA_TMC_REG + 1] = 'MSM_DUMP_DATA_TMC_REG' diff --git a/linux-ramdump-parser-v2/mm.py b/linux-ramdump-parser-v2/mm.py index 02fa7aa918566760d150651f7fc3148cf4f5b07d..efca724830789ce95123989d4146d72c2f375acb 100644 --- a/linux-ramdump-parser-v2/mm.py +++ b/linux-ramdump-parser-v2/mm.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +# Copyright (c) 2013-2017, 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 @@ -19,6 +19,21 @@ def page_buddy(ramdump, page): return val == 0xffffff80 +def page_count(ramdump, page): + """Commit: 0139aa7b7fa12ceef095d99dc36606a5b10ab83a + mm: rename _count, field of the struct page, to _refcount""" + if (ramdump.version < (4, 6, 0)): + count = ramdump.read_structure_field(page, 'struct page', + '_count.counter') + else: + count = ramdump.read_structure_field(page, 'struct page', + '_refcount.counter') + return count + + +def page_ref_count(ramdump, page): + return page_count(ramdump, page) + def get_debug_flags(ramdump, page): debug_flag_offset = ramdump.field_offset('struct page', 'debug_flags') flagval = ramdump.read_word(page + debug_flag_offset) @@ -135,6 +150,7 @@ def get_vmemmap(ramdump): # See: include/asm-generic/pgtable-nopud.h, # arch/arm64/include/asm/pgtable-hwdef.h, # arch/arm64/include/asm/pgtable.h + # kernel/arch/arm64/include/asm/memory.h if (ramdump.kernel_version < (3, 18, 0)): nlevels = int(ramdump.get_config_val("CONFIG_ARM64_PGTABLE_LEVELS")) else: @@ -151,16 +167,27 @@ def get_vmemmap(ramdump): spsize = ramdump.sizeof('struct page') vmemmap_size = bitops.align((1 << (va_bits - page_shift)) * spsize, pud_size) + + memstart_addr = ramdump.read_s64('memstart_addr') + page_section_mask = ~((1 << 18) - 1) + memstart_offset = (memstart_addr >> page_shift) & page_section_mask + memstart_offset *= spsize + if (ramdump.kernel_version < (3, 18, 31)): - vmalloc_end = ramdump.page_offset - pud_size - vmemmap_size # vmalloc_end = 0xFFFFFFBC00000000 - else: + vmemmap = ramdump.page_offset - pud_size - vmemmap_size + elif (ramdump.kernel_version < (4, 9, 0)): # for version >= 3.18.31, # vmemmap is shifted to base addr (0x80000000) pfn. - pfn_offset = (ramdump.phys_offset >> page_shift) - offset = pfn_offset * spsize - vmalloc_end = ramdump.page_offset - pud_size - vmemmap_size - offset - return vmalloc_end + vmemmap = (ramdump.page_offset - pud_size - vmemmap_size - + memstart_offset) + else: + # for version >= 4.9.0, + # vmemmap_size = ( 1 << (39 - 12 - 1 + 6)) + struct_page_max_shift = 6 + vmemmap_size = ( 1 << (va_bits - page_shift - 1 + struct_page_max_shift)) + vmemmap = ramdump.page_offset - vmemmap_size - memstart_offset + return vmemmap def page_to_pfn_vmemmap(ramdump, page): @@ -277,3 +304,30 @@ def page_address(ramdump, page): pam = ramdump.read_word(pam + lh_offset) if pam == start: return None + + +def for_each_pfn(ramdump): + """ creates a generator for looping through valid pfn + Example: + for i in for_each_pfn(ramdump): + page = pfn_to_page(i) + """ + page_size = (1 << 12) + cnt = ramdump.read_structure_field('memblock', 'struct memblock', + 'memory.cnt') + region = ramdump.read_structure_field('memblock', 'struct memblock', + 'memory.regions') + memblock_region_size = ramdump.sizeof('struct memblock_region') + for i in range(cnt): + start = ramdump.read_structure_field(region, 'struct memblock_region', + 'base') + end = start + ramdump.read_structure_field( + region, 'struct memblock_region', 'size') + + pfn = start / page_size + end /= page_size + while pfn < end: + yield pfn + pfn += 1 + + region += memblock_region_size diff --git a/linux-ramdump-parser-v2/mmu.py b/linux-ramdump-parser-v2/mmu.py index 4444cd2dd4eaf067f90120688b0d3c7a5bd014ad..0d395a6006a6d6b662d94c8998d2feca2bda1ee4 100644 --- a/linux-ramdump-parser-v2/mmu.py +++ b/linux-ramdump-parser-v2/mmu.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +# Copyright (c) 2013-2017, 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 @@ -51,16 +51,21 @@ class MMU(object): if addr is None: return None + page_addr = (addr >> 12) << 12 + page_offset = addr & 0xFFF + if not skip_tlb: - if addr in self._tlb: - return self._tlb[addr] + if page_addr in self._tlb: + return self._tlb[page_addr] + page_offset - phys_addr = self.page_table_walk(addr) + phys_addr = self.page_table_walk(page_addr) + if phys_addr is None: + return None if save_in_tlb: - self._tlb[addr] = phys_addr + self._tlb[page_addr] = phys_addr - return phys_addr + return phys_addr + page_offset def load_page_tables(self): raise NotImplementedError diff --git a/linux-ramdump-parser-v2/parsers/clockdump.py b/linux-ramdump-parser-v2/parsers/clockdump.py old mode 100755 new mode 100644 index 09b4657d3c1efe6ecd92acf4be0d2afb75688b49..fd7eedccb4e152f6a97ef6c7d439b6a29e14dead --- a/linux-ramdump-parser-v2/parsers/clockdump.py +++ b/linux-ramdump-parser-v2/parsers/clockdump.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, The Linux Foundation. All rights reserved. +# Copyright (c) 2015,2017 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 @@ -13,8 +13,9 @@ import linux_list from print_out import print_out_str from parser_util import register_parser, RamParser + @register_parser('--clock-dump', 'Dump all the clocks in the system') -class ClockDumps(RamParser) : +class ClockDumps(RamParser): def __init__(self, *args): super(ClockDumps, self).__init__(*args) @@ -118,14 +119,7 @@ class ClockDumps(RamParser) : clk_providers_walker = linux_list.ListWalker(self.ramdump, head, node_offset) clk_providers_walker.walk(head, self.clk_providers_walker) - def clk_providers_walker(self, node): - if node == self.head: - return - - data_address = node + self.ramdump.field_offset('struct of_clk_provider', 'data') - node_address = node + self.ramdump.field_offset('struct of_clk_provider', 'node') - data = self.ramdump.read_word(data_address, True) - node = self.ramdump.read_word(node_address, True) + def print_clk_of_msm_provider_data(self, data): table_address = data + self.ramdump.field_offset('struct of_msm_provider_data', 'table') size_address = data + self.ramdump.field_offset('struct of_msm_provider_data', 'size') table = self.ramdump.read_word(table_address, True) @@ -163,6 +157,73 @@ class ClockDumps(RamParser) : counter = counter + 1 table = table + self.ramdump.sizeof('struct clk_lookup') + def print_clk_onecell_data(self, data): + offset_clk_onecell_data_clks = ( + self.ramdump.field_offset('struct clk_onecell_data', 'clks')) + offset_clk_onecell_data_clknum = ( + self.ramdump.field_offset( + 'struct clk_onecell_data', 'clk_num')) + clks = self.ramdump.read_word(data + offset_clk_onecell_data_clks) + size = self.ramdump.read_int(data + offset_clk_onecell_data_clknum) + sizeof_clk_pointer = self.ramdump.sizeof('struct clk *') + offset_vdd_cur_level = self.ramdump.field_offset( + 'struct clk_vdd_class', 'cur_level') + counter = 0 + + while counter < size: + clk = self.ramdump.read_word(clks + (sizeof_clk_pointer * counter)) + if clk == 0 or clk is None: + counter = counter + 1 + continue + clk_core = self.ramdump.read_structure_field( + clk, 'struct clk', 'core') + if clk_core == 0 or clk_core is None: + counter = counter + 1 + continue + clk_name_addr = self.ramdump.read_structure_field( + clk_core, 'struct clk_core', 'name') + clk_name = self.ramdump.read_cstring(clk_name_addr, 48) + clk_prepare_count = self.ramdump.read_structure_field( + clk_core, 'struct clk_core', 'prepare_count') + clk_enable_count = self.ramdump.read_structure_field( + clk_core, 'struct clk_core', 'enable_count') + clk_rate = self.ramdump.read_structure_field( + clk_core, 'struct clk_core', 'rate') + clk_vdd_class_addr = ( + self.ramdump.read_structure_field( + clk_core, 'struct clk_core', 'vdd_class')) + vdd_class = self.ramdump.read_word(clk_vdd_class_addr) + cur_level = 0 + if vdd_class != 0 and vdd_class is not None: + cur_level_address = (vdd_class + offset_vdd_cur_level) + cur_level = self.ramdump.read_word(cur_level_address, True) + formatStr = "{0:40} {1:<2}/ {2:<17} {3:<25} {4:<10} v.v (struct clk_core *)0x{5:<20x}\n" + output = formatStr.format( + clk_name, + clk_enable_count, + clk_prepare_count, + clk_rate, cur_level, + clk_core) + if clk_enable_count > 0: + self.enabled_clocks.append(output) + elif clk_prepare_count > 0: + self.prepared_clocks.append(output) + else: + self.disabled_clocks.append(output) + counter = counter + 1 + + def clk_providers_walker(self, node): + if node == self.head: + return + data_address = node + self.ramdump.field_offset( + 'struct of_clk_provider', 'data') + data = self.ramdump.read_word(data_address, True) + + if (self.ramdump.kernel_version < (4, 4, 38)): + self.print_clk_of_msm_provider_data(data) + else: + self.print_clk_onecell_data(data) + def parse(self): self.output_file = self.ramdump.open_file('ClockDumps.txt') diff --git a/linux-ramdump-parser-v2/parsers/ftrace.py b/linux-ramdump-parser-v2/parsers/ftrace.py new file mode 100644 index 0000000000000000000000000000000000000000..90ea0765a5902adc3b725f580302220c16a12b15 --- /dev/null +++ b/linux-ramdump-parser-v2/parsers/ftrace.py @@ -0,0 +1,144 @@ +# Copyright (c) 2017, 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. + +import parser_util +import local_settings +import os +import subprocess + +from parser_util import register_parser, RamParser +from print_out import print_out_str +from tempfile import NamedTemporaryFile + +@register_parser( + '--dump-ftrace', + 'Use \'crash\' to extract ftrace and trace-cmd to parse it.', + optional=True) +class FtraceParser(RamParser): + + def __init__(self, *args): + super(FtraceParser, self).__init__(*args) + + def parse(self): + if parser_util.get_system_type() != 'Linux': + print_out_str("Run the ramdump parser on Linux to get ftrace") + return False + + try: + crashtool = local_settings.crashtool + trace_ext = local_settings.trace_ext + tracecmdtool = local_settings.tracecmdtool + except AttributeError: + print_out_str("One of crashtool, the trace extension or" + + " trace-cmd is missing from local-settings.py") + return False + + if not os.path.exists(crashtool): + print_out_str("Couldn't find the crash tool") + return False + if not os.path.exists(trace_ext): + print_out_str("Couldn't find the crash tool trace extension") + return False + if not os.path.exists(tracecmdtool): + print_out_str("Couldn't find the trace-cmd tool") + return False + + print_out_str(crashtool) + dumps="" + for (f, start, end, filename) in self.ramdump.ebi_files: + if "DDR" in filename or "dram" in filename: + dumps += '{0}@0x{1:x},'.format(filename, start) + pagesize = "-p 4096" + + commandsfile = NamedTemporaryFile(mode='w', delete=False, + dir=self.ramdump.outdir) + commandsfile.write("extend " + trace_ext + "\n") + commandsfile.write("trace dump -t " + self.ramdump.outdir + + "/rawtracedata\n") + commandsfile.write("quit\n") + commandsfile.close() + + commands = "-i " + commandsfile.name + + crashargs = [crashtool] + + if self.ramdump.kaslr_offset is not None: + kaslroffset = "--kaslr={0}".format(hex(self.ramdump.kaslr_offset)) + crashargs.append(kaslroffset) + + if self.ramdump.kimage_voffset is not None: + kimagevoff="kimage_voffset={0}".format(hex(self.ramdump.kimage_voffset).replace('L','')) + crashargs.append("--machdep") + crashargs.append(kimagevoff) + + crashargs.extend([dumps, self.ramdump.vmlinux, + pagesize, commands]) + + print_out_str('args to crash: {0}'.format(crashargs)) + + sp = subprocess.Popen(crashargs, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = sp.communicate() + + if out: + print_out_str("crash standard output recorded.") + std = self.ramdump.open_file('stdout_crashtool.txt') + std.write(out); + std.close(); + if err: + print_out_str("crash standard error recorded.") + std = self.ramdump.open_file('stderr_crashtool.txt') + std.write(err); + std.close(); + + os.remove(commandsfile.name) + + if not os.path.exists(self.ramdump.outdir + "/rawtracedata"): + print_out_str("crash failed to extract raw ftrace data") + return False + + tracecmd_arg = self.ramdump.outdir + "/rawtracedata" + sp = subprocess.Popen([tracecmdtool, "report", "-l", tracecmd_arg], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = sp.communicate(); + + if out: + ftrace_out = self.ramdump.open_file('ftrace.txt') + ftrace_out.write(out); + ftrace_out.close(); + print_out_str("Ftrace successfully extracted."); + if err: + print_out_str("trace-cmd standard error recorded.") + std = self.ramdump.open_file('stderr_tracecmd.txt') + std.write(err); + std.close(); + + return True diff --git a/linux-ramdump-parser-v2/parsers/memstat.py b/linux-ramdump-parser-v2/parsers/memstat.py index aabe62bf3982d70fffee167255d65871f155e55f..322a0508856e56505fd4809af4ac325d1ed13b63 100644 --- a/linux-ramdump-parser-v2/parsers/memstat.py +++ b/linux-ramdump-parser-v2/parsers/memstat.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 The Linux Foundation. All rights reserved. +# Copyright (c) 2016-2017 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 @@ -50,7 +50,7 @@ class MemStats(RamParser): list_walker.walk(vmlist, self.list_func) self.vmalloc_size = self.bytes_to_mb(self.vmalloc_size) - def calculate_others(self): + def calculate_vm_stat(self): # Other memory : NR_ANON_PAGES + NR_FILE_PAGES + NR_PAGETABLE \ # + NR_KERNEL_STACK - NR_SWAPCACHE vmstat_anon_pages = self.ramdump.read_word( @@ -68,6 +68,22 @@ class MemStats(RamParser): other_mem = self.pages_to_mb(other_mem) return other_mem + def calculate_vm_node_zone_stat(self): + # Other memory : NR_ANON_MAPPED + NR_FILE_PAGES + NR_PAGETABLE \ + # + NR_KERNEL_STACK_KB + vmstat_anon_pages = self.ramdump.read_word( + 'vm_node_stat[NR_ANON_MAPPED]') + vmstat_file_pages = self.ramdump.read_word( + 'vm_node_stat[NR_FILE_PAGES]') + vmstat_pagetbl = self.ramdump.read_word( + 'vm_zone_stat[NR_PAGETABLE]') + vmstat_kernelstack = self.ramdump.read_word( + 'vm_zone_stat[NR_KERNEL_STACK_KB]') + other_mem = (vmstat_anon_pages + vmstat_file_pages + vmstat_pagetbl + + (vmstat_kernelstack/4)) + other_mem = self.pages_to_mb(other_mem) + return other_mem + def calculate_ionmem(self): number_of_ion_heaps = self.ramdump.read_int('num_heaps') heap_addr = self.ramdump.read_word('heaps') @@ -98,16 +114,33 @@ class MemStats(RamParser): total_mem = self.ramdump.read_word('totalram_pages') total_mem = self.pages_to_mb(total_mem) - # Free Memory - total_free = self.ramdump.read_word('vm_stat[NR_FREE_PAGES]') - total_free = self.pages_to_mb(total_free) + if (self.ramdump.kernel_version < (4, 9, 0)): + # Free Memory + total_free = self.ramdump.read_word('vm_stat[NR_FREE_PAGES]') + total_free = self.pages_to_mb(total_free) - # slab Memory - slab_rec = \ - self.ramdump.read_word('vm_stat[NR_SLAB_RECLAIMABLE]') - slab_unrec = \ - self.ramdump.read_word('vm_stat[NR_SLAB_UNRECLAIMABLE]') - total_slab = self.pages_to_mb(slab_rec + slab_unrec) + # slab Memory + slab_rec = \ + self.ramdump.read_word('vm_stat[NR_SLAB_RECLAIMABLE]') + slab_unrec = \ + self.ramdump.read_word('vm_stat[NR_SLAB_UNRECLAIMABLE]') + total_slab = self.pages_to_mb(slab_rec + slab_unrec) + + #others + other_mem = self.calculate_vm_stat() + else: + # Free Memory + total_free = self.ramdump.read_word('vm_zone_stat[NR_FREE_PAGES]') + total_free = self.pages_to_mb(total_free) + + # slab Memory + slab_rec = \ + self.ramdump.read_word('vm_zone_stat[NR_SLAB_RECLAIMABLE]') + slab_unrec = \ + self.ramdump.read_word('vm_zone_stat[NR_SLAB_UNRECLAIMABLE]') + total_slab = self.pages_to_mb(slab_rec + slab_unrec) + #others + other_mem = self.calculate_vm_node_zone_stat() # ion memory ion_mem = self.calculate_ionmem() @@ -136,9 +169,6 @@ class MemStats(RamParser): # vmalloc area self.calculate_vmalloc() - # Others - other_mem = self.calculate_others() - # Output prints out_mem_stat.write('{0:30}: {1:8} MB'.format( "Total RAM", total_mem)) diff --git a/linux-ramdump-parser-v2/parsers/mmcdoctor.py b/linux-ramdump-parser-v2/parsers/mmcdoctor.py new file mode 100644 index 0000000000000000000000000000000000000000..0d6a820809d7576477fdd9e15d8ce74bdc645c00 --- /dev/null +++ b/linux-ramdump-parser-v2/parsers/mmcdoctor.py @@ -0,0 +1,368 @@ +# Copyright (c) 2017, 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. + +import os +from parser_util import register_parser, RamParser +from parsers.irqstate import IrqParse +from dmesglib import DmesgLib +from print_out import print_out_str + +MMC0_IRQ = 0 +MMC1_IRQ = 0 +SDHCI_IRQ_NAME = "sdhci" +SDHCI_IRQ_CD_NAME = "sdhci cd" + +F_MMCDEBUG = "mmcreport.txt" +F_MMCTEMP = "mmctemp.txt" + +PATTERN_ST = "========== REGISTER DUMP (mmc0)==========" +PATTERN_END = "sdhci: ====================" + +MMC_DATA_HEAD = "#################### MMC(mmc%d) INFO START #######################\n" +MMC_DATA_FOOT = "#################### MMC(mmc%d) INFO END #########################\n\n" + +MMC_TRACE_HEADER = "\n################ MMC(mmc%d) RING BUFFER ################\n" +MMC_TRACE_BUF_EVENTS = 64 +MMC_TRACE_EVENT_SIZE = 256 + +card_data = { + 0x2: "SANDISK", + 0x11: "TOSHIBA", + 0x13: "MICRON", + 0x15: "SAMSUNG", + 0x70: "KINGSTON", + 0x90: "HYNIX", +} + +card_err_data = { + "Card Timeout" : ["err: -110", "error: -110"], + "Soft Timeout" : ["Timeout waiting for hardware interrupt", "request with tag"], + "CRC ERROR" : ["err: -84", "error: -84"], + "Resp_error" : ["status: 0x00000006", "status: 0x00000004"], + "Spurious_cmd_intr" : ["Got command interrupt", "even though no command"], + "Spurious_data_intr": ["Got data interrupt", "even though no data"], + "Spurious_intr" : ["Unexpected interrupt", "Unexpected interrupt"], +} + + +# +# This class defines parsing function +# to parse for mmclog +# +class ParseMmcLog(): + + def __init__(self, ramdump): + self.ramdump = ramdump + self.error = 0 + self.error_line = "" + + def dumptemplog(self): + fd_temp = self.ramdump.open_file(F_MMCTEMP, "w+") + d = DmesgLib(self.ramdump, fd_temp) + d.extract_dmesg() + fd_temp.close() + + def check_for_error(self, line): + if (self.error): + return + for key, item in card_err_data.iteritems(): + if (item[0] in line or item[1] in line): + self.error = key + self.error_line = line + break + + def dumpmemreport(self): + self.dumptemplog() + self.error = 0 + self.error_line = "" + fdr = self.ramdump.open_file(F_MMCTEMP, "r") + fdw = self.ramdump.open_file(F_MMCDEBUG, "a") + line = fdr.readline() + while (line): + if ("mmc" in line): + fdw.write(line) + self.check_for_error(line) + if (PATTERN_ST in line): + line = fdr.readline() + while (line and (PATTERN_END not in line)): + fdw.write("ERROR" + line) + line = fdr.readline() + if (line and PATTERN_END in line): + fdw.write("ERROR" + line) + line = fdr.readline() + fdw.close() + fdr.close() + self.ramdump.remove_file(F_MMCTEMP) + + +# +# Function definition to find all relevant structure +# + +def get_sdhci_irqs(ram_dump): + irqs = IrqParse(RamParser) + count = 0 + global MMC0_IRQ + global MMC1_IRQ + irq_action_offset = ram_dump.field_offset('struct irq_desc', 'action') + action_name_offset = ram_dump.field_offset('struct irqaction', 'name') + irq_desc_tree = ram_dump.address_of('irq_desc_tree') + nr_irqs = ram_dump.read_int(ram_dump.address_of('nr_irqs')) + + if nr_irqs > 50000: + return + for i in range(0, nr_irqs): + irq_desc = irqs.radix_tree_lookup_element( + ram_dump, irq_desc_tree, i) + if irq_desc is None: + continue + action = ram_dump.read_word(irq_desc + irq_action_offset) + if action != 0 and count < 2: + name_addr = ram_dump.read_word(action + action_name_offset) + name = ram_dump.read_cstring(name_addr, 48) + if (not name): + continue + if (SDHCI_IRQ_NAME in name and not SDHCI_IRQ_CD_NAME in name): + if (count == 0): + MMC0_IRQ = i + elif (count == 1): + MMC1_IRQ = i + count += 1 + return count + +def find_sdhci_host(ramdump, irq): + irq_desc_tree = ramdump.address_of('irq_desc_tree') + irq_action_offset = ramdump.field_offset('struct irq_desc', 'action') + dev_id = ramdump.field_offset('struct irqaction', 'dev_id') + irqs = IrqParse(RamParser) + sdhci_irq_desc = irqs.radix_tree_lookup_element(ramdump, irq_desc_tree, irq) + sdhci_irq_action = ramdump.read_word(sdhci_irq_desc + irq_action_offset) + sdhci_host = ramdump.read_word(sdhci_irq_action + dev_id) + return sdhci_host + + +def find_mmc_host(ramdump, sdhci_host): + mmc_offset = ramdump.field_offset('struct sdhci_host', 'mmc') + mmc_host = ramdump.read_word(sdhci_host + mmc_offset) + return mmc_host + + +def find_mmc_card(ramdump, mmc_host): + card_offset = ramdump.field_offset('struct mmc_host', 'card') + mmc_card = ramdump.read_word(mmc_host + card_offset) + return mmc_card + + +def find_sdhci_msm_host(ramdump, sdhci_host): + sdhci_pltfm_host = (sdhci_host + ramdump.sizeof('struct sdhci_host')) + msm_offset = ramdump.field_offset('struct sdhci_pltfm_host', 'priv') + sdhci_msm_host = ramdump.read_word(sdhci_pltfm_host + msm_offset) + return sdhci_msm_host + + +class MmcCardInfo(): + + def __init__(self, ramdump, mmc_card): + self.ramdump = ramdump + self.card = mmc_card + self.type = self.find_mmc_cid() + self.ext_csd_fwrev = self.find_ext_csd() + self.cmdq_init = self.find_cmdq_init() + + def find_ext_csd(self): + if (not self.card): + return 0 + ext_csd_off = self.card + \ + self.ramdump.field_offset('struct mmc_card', 'ext_csd') + self.mmc_ext_csd = ext_csd_off + fw_version_offset = self.ramdump.field_offset('struct mmc_ext_csd', 'fw_version') + if (fw_version_offset is None): + return -2 + ext_csd_fwrev = ext_csd_off + fw_version_offset + return self.ramdump.read_byte(ext_csd_fwrev) + + def find_mmc_cid(self): + if (not self.card): + return 0 + cid = self.card + self.ramdump.field_offset('struct mmc_card', 'cid') + self.mmc_cid = cid + manfid = self.ramdump.read_u32(cid) + if manfid in card_data.keys(): + return card_data[manfid] + else: + return manfid + + def find_cmdq_init(self): + if (not self.card): + return 0 + cmdq_init = self.card + self.ramdump.field_offset('struct mmc_card', 'cmdq_init') + return self.ramdump.read_bool(cmdq_init) + + +class MmcHostInfo(): + + def __init__(self, ramdump, mmc_host): + self.ramdump = ramdump + self.host = mmc_host + self.clk_gated = self.ramdump.read_bool(self.host + + self.ramdump.field_offset('struct mmc_host', 'clk_gated')) + self.clk_requests = self.ramdump.read_int(self.host + + self.ramdump.field_offset('struct mmc_host', 'clk_requests')) + self.clk_old = self.ramdump.read_int(self.host + + self.ramdump.field_offset('struct mmc_host', 'clk_old')) + + offset = self.ramdump.field_offset('struct mmc_host', 'err_occurred') + if (offset): + self.err_occurred = self.ramdump.read_bool(self.host + offset) + else: + self.err_occurred = -1 + self.ios = self.find_ios() + self.ios_clock = self.ramdump.read_int(self.ios + + self.ramdump.field_offset('struct mmc_ios', 'clock')) + self.ios_old_rate = self.ramdump.read_int(self.ios + + self.ramdump.field_offset('struct mmc_ios', 'old_rate')) + self.ios_vdd = self.ramdump.read_u16(self.ios + + self.ramdump.field_offset('struct mmc_ios', 'vdd')) + self.ios_bus_width = self.ramdump.read_byte(self.ios + + self.ramdump.field_offset('struct mmc_ios', 'bus_width')) + self.ios_timing = self.ramdump.read_byte(self.ios + + self.ramdump.field_offset('struct mmc_ios', 'timing')) + self.ios_signal_voltage = self.ramdump.read_byte(self.ios + + self.ramdump.field_offset('struct mmc_ios', 'signal_voltage')) + self.ios_drv_type= self.ramdump.read_byte(self.ios + + self.ramdump.field_offset('struct mmc_ios', 'drv_type')) + + def find_ios(self): + return (self.host + self.ramdump.field_offset('struct mmc_host', 'ios')) + + +# +# Base class which save all mmc data structure info +# This uses other classes for card and host related +# info +# +class MmcDataStructure(): + global MMC0_IRQ + global MMC1_IRQ + + def __init__(self, ramdump, index): + self.mmclist_irq = {0 : MMC0_IRQ, 1 : MMC1_IRQ} + self.index = index + self.irq = self.mmclist_irq[index] + if (self.irq == 0): + return + self.ramdump = ramdump + self.sdhci_host = find_sdhci_host(self.ramdump, self.irq) + self.mmc_host = find_mmc_host(self.ramdump, self.sdhci_host) + self.mmc_card = find_mmc_card(self.ramdump, self.mmc_host) + self.sdhci_msm_host = find_sdhci_msm_host(self.ramdump, self.sdhci_host) + self.cardinfo = MmcCardInfo(self.ramdump, self.mmc_card) + self.hostinfo = MmcHostInfo(self.ramdump, self.mmc_host) + self.parse = ParseMmcLog(self.ramdump) + return + + def dump_trace_buf(self, fd): + if (not self.mmc_host or (fd <= 0) or (self.ramdump.kernel_version < (4, 4))): + return + mmc_host = self.mmc_host + ramdump = self.ramdump + + fd.write(MMC_TRACE_HEADER % self.index) + buf_offset = ramdump.field_offset('struct mmc_host', 'trace_buf') + if (not buf_offset): + return 0 + + data_offset = ramdump.field_offset('struct mmc_trace_buffer', 'data') + if (not data_offset): + return 0 + + trace_buf = mmc_host + buf_offset + wr_idx = ramdump.read_int(trace_buf) + if (wr_idx >= 0xFFFFFFFF): + fd.write("mmc%d trace buffer empty\n" %(self.index)) + return 0 + + dataptr = ramdump.read_word(trace_buf + data_offset) + if (not dataptr): + return + + datastr = [] + for i in xrange(MMC_TRACE_BUF_EVENTS): + trace_str = ramdump.read_cstring(dataptr, MMC_TRACE_EVENT_SIZE) + dataptr += MMC_TRACE_EVENT_SIZE + datastr.append(trace_str) + num = MMC_TRACE_BUF_EVENTS - 1 + idx = wr_idx & num + cur_idx = (idx + 1) & num + for i in xrange(MMC_TRACE_BUF_EVENTS): + fd.write("event[%d] = %s" %(cur_idx, datastr[cur_idx])) + cur_idx = (cur_idx + 1 ) & num + + def dump_data(self, mode): + fd = self.ramdump.open_file(F_MMCDEBUG, mode) + fd.write(MMC_DATA_HEAD % self.index) + fd.write("mmc_card = 0x%x\n" % self.mmc_card) + fd.write("mmc_host = 0x%x\n" % self.mmc_host) + fd.write("sdhci_host = 0x%x\n" % self.sdhci_host) + fd.write("sdhci_msm_host = 0x%x\n\n" % self.sdhci_msm_host) + fd.write("mmc_host->err_occurred = %d\n" % self.hostinfo.err_occurred) + fd.write("Grep MMC_ERROR TYPE at End of File\n\n") + fd.write("CARD MANFID = %s\n" %self.cardinfo.type) + fd.write("CARD Fw_rev = 0x%x\n" %self.cardinfo.ext_csd_fwrev) + fd.write("CARD CMDQ INIT = %d\n\n" %self.cardinfo.cmdq_init) + fd.write("Host clk_requests = %d\n" %self.hostinfo.clk_requests) + fd.write("Host clk_gated = %d\n" %self.hostinfo.clk_gated) + fd.write("Host clk_old = %dHz\n" %self.hostinfo.clk_old) + fd.write("Host ios_clock = %dHz\n" %self.hostinfo.ios_clock) + fd.write("Host ios_old_rate = %uHz\n" %self.hostinfo.ios_old_rate) + fd.write("Host ios_vdd = %d\n" %self.hostinfo.ios_vdd) + fd.write("Host ios_bus_width = %d\n" %self.hostinfo.ios_bus_width) + fd.write("Host ios_timing = %d\n" %self.hostinfo.ios_timing) + fd.write("Host ios_signal_voltage = %d\n" %self.hostinfo.ios_signal_voltage) + fd.write("Host ios_drv_type = %d\n" %self.hostinfo.ios_drv_type) + self.dump_trace_buf(fd) + fd.write(MMC_DATA_FOOT % self.index) + fd.close() + return + + +def dump_mmc_info(ramdump, count): + mmc0 = MmcDataStructure(ramdump, 0) + mmc0.dump_data("w+") + + if (count > 1): + mmc1 = MmcDataStructure(ramdump, 1) + mmc1.dump_data("a") + + mmc0.parse.dumpmemreport() + fd = ramdump.open_file(F_MMCDEBUG, "a") + fd.write("\n\n\n#########MMC_ERROR#########\n") + if (mmc0.parse.error): + fd.write("ERROR TYPE = %s\n" %mmc0.parse.error) + else: + fd.write("ERROR TYPE = Unknown Error\n") + fd.write("ERROR SIGN = %s\n\n" % mmc0.parse.error_line) + fd.close() + + +@register_parser('--mmcdoctor', 'Generate MMC diagnose report') +class MmcDebug(RamParser): + def parse(self): + count_irq = 0 + if self.ramdump.is_config_defined('CONFIG_SPARSE_IRQ'): + count_irq = get_sdhci_irqs(self.ramdump) + if (count_irq == 0): + return + dump_mmc_info(self.ramdump, count_irq) + else: + print_out_str("\n Could not generate MMC diagnose report\n") + return diff --git a/linux-ramdump-parser-v2/parsers/pagealloccorruption.py b/linux-ramdump-parser-v2/parsers/pagealloccorruption.py old mode 100755 new mode 100644 index 302d46da03c12fabe67c143c609d42781c1a4220..d4174dde027829467f28af2ef5827768720aa3f7 --- a/linux-ramdump-parser-v2/parsers/pagealloccorruption.py +++ b/linux-ramdump-parser-v2/parsers/pagealloccorruption.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved. +# Copyright (c) 2012,2014-2017 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 @@ -27,6 +27,14 @@ class PageallocCorruption(RamParser): cnt = self.ramdump.read_word(memblock_addr + memblock_memory_offset + memblock_memory_cnt_offset) region_offset = self.ramdump.field_offset('struct memblock_type', 'regions') regions_baseaddr = self.ramdump.read_word(memblock_addr + memblock_memory_offset + region_offset) + page_ext_offset = self.ramdump.field_offset( + 'struct mem_section', 'page_ext') + page_flags_offset = self.ramdump.field_offset( + 'struct page_ext', 'flags') + mem_section_size = self.ramdump.sizeof("struct mem_section") + mem_section = self.ramdump.read_word('mem_section') + page_ext_size = self.ramdump.sizeof("struct page_ext") + for r in range(0,cnt) : region_addr = regions_baseaddr + r * self.ramdump.sizeof('struct memblock_region') start_addr_offset = self.ramdump.field_offset('struct memblock_region', 'base') @@ -41,11 +49,23 @@ class PageallocCorruption(RamParser): for pfn in range(min_pfn, max_pfn): page = pfn_to_page(self.ramdump, pfn) page_pa = (pfn << 12) - # debug_flags value should be 1 for pages having poisoned value 0xaa - free = get_debug_flags(self.ramdump, page) + if (self.ramdump.kernel_version > (3, 18, 0)): + free = 0 + offset = page_pa >> 30 + mem_section_0_offset = ( + mem_section + (offset * mem_section_size)) + page_ext = self.ramdump.read_word( + mem_section_0_offset + page_ext_offset) + temp_page_ext = page_ext + (pfn * page_ext_size) + page_ext_flags = self.ramdump.read_word( + temp_page_ext + page_flags_offset) + # enum PAGE_EXT_DEBUG_POISON ( == 0th bit is set ) for page poisioning + free = page_ext_flags & 1 + else: + # debug_flags value should be 1 for pages having poisoned value 0xaa + free = get_debug_flags(self.ramdump, page) if free == 1: - page_pa = (pfn << 12) flag = 0; for i in range(0,1024): readval = self.ramdump.read_u32(page_pa+i*4, False) diff --git a/linux-ramdump-parser-v2/parsers/pagetracking.py b/linux-ramdump-parser-v2/parsers/pagetracking.py index c7d4d87d8ecc87ae3d1f4be6055d3387aa16e9d2..c627ac87f9ea7473780c5e2748134d3af8e5e8b1 100644 --- a/linux-ramdump-parser-v2/parsers/pagetracking.py +++ b/linux-ramdump-parser-v2/parsers/pagetracking.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved. +# Copyright (c) 2012,2014-2015,2017 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 @@ -11,54 +11,90 @@ from print_out import print_out_str from parser_util import register_parser, RamParser -from mm import pfn_to_page, page_buddy +from mm import pfn_to_page, page_buddy, page_count, for_each_pfn + @register_parser('--print-pagetracking', 'print page tracking information (if available)') class PageTracking(RamParser): def parse(self): if not self.ramdump.is_config_defined('CONFIG_PAGE_OWNER'): + print_out_str('CONFIG_PAGE_OWNER not defined') return - min_pfn_addr = self.ramdump.address_of('min_low_pfn') - max_pfn_addr = self.ramdump.address_of('max_pfn') - min_pfn = self.ramdump.read_word( - min_pfn_addr) + (self.ramdump.phys_offset >> 12) - max_pfn = self.ramdump.read_word( - max_pfn_addr) + (self.ramdump.phys_offset >> 12) - - order_offset = self.ramdump.field_offset('struct page', 'order') - flags_offset = self.ramdump.field_offset('struct page', 'flags') - trace_offset = self.ramdump.field_offset('struct page', 'trace') - nr_entries_offset = self.ramdump.field_offset( - 'struct stack_trace', 'nr_entries') - trace_entries_offset = self.ramdump.field_offset( - 'struct page', 'trace_entries') + if (self.ramdump.kernel_version >= (3, 19, 0)): + mem_section = self.ramdump.read_word('mem_section') + + trace_offset = 0 + nr_entries_offset = 0 + trace_entries_offset = 0 + offset = 0 + struct_holding_trace_entries = 0 + trace_entry_size = self.ramdump.sizeof("unsigned long") + + if (self.ramdump.kernel_version <= (3, 19, 0)): + trace_offset = self.ramdump.field_offset('struct page', 'trace') + nr_entries_offset = self.ramdump.field_offset( + 'struct stack_trace', 'nr_entries') + trace_entries_offset = self.ramdump.field_offset( + 'struct page', 'trace_entries') + else: + page_ext_offset = self.ramdump.field_offset( + 'struct mem_section', 'page_ext') + trace_offset = self.ramdump.field_offset( + 'struct page_ext', 'trace') + trace_entries_offset = self.ramdump.field_offset( + 'struct page_ext', 'trace_entries') + nr_entries_offset = self.ramdump.field_offset( + 'struct page_ext', 'nr_entries') + mem_section_size = self.ramdump.sizeof("struct mem_section") + page_ext_size = self.ramdump.sizeof("struct page_ext") out_tracking = self.ramdump.open_file('page_tracking.txt') out_frequency = self.ramdump.open_file('page_frequency.txt') sorted_pages = {} - trace_entry_size = self.ramdump.sizeof("unsigned long") - for pfn in range(min_pfn, max_pfn): + for pfn in for_each_pfn(self.ramdump): page = pfn_to_page(self.ramdump, pfn) + order = 0 - # validate this page is free - if page_buddy(self.ramdump, page): + """must be allocated, and the first pfn of an order > 0 page""" + if (page_buddy(self.ramdump, page) or + page_count(self.ramdump, page) == 0): continue - - nr_trace_entries = self.ramdump.read_int( - page + trace_offset + nr_entries_offset) + if (self.ramdump.kernel_version <= (3, 19, 0)): + nr_trace_entries = self.ramdump.read_int( + page + trace_offset + nr_entries_offset) + struct_holding_trace_entries = page + order = self.ramdump.read_structure_field( + page, 'struct page', 'order') + else: + phys = pfn << 12 + if phys is None or phys is 0: + continue + offset = phys >> 30 + + mem_section_0_offset = ( + mem_section + (offset * mem_section_size)) + page_ext = self.ramdump.read_word( + mem_section_0_offset + page_ext_offset) + temp_page_ext = page_ext + (pfn * page_ext_size) + nr_trace_entries = self.ramdump.read_int( + temp_page_ext + nr_entries_offset) + struct_holding_trace_entries = temp_page_ext + order = self.ramdump.read_structure_field( + temp_page_ext, 'struct page_ext', 'order') if nr_trace_entries <= 0 or nr_trace_entries > 16: continue - out_tracking.write('PFN 0x{0:x} page 0x{1:x}\n'.format(pfn, page)) + out_tracking.write('PFN 0x{:x}-0x{:x} page 0x{:x}\n'.format( + pfn, pfn + (1 << order) - 1, page)) alloc_str = '' for i in range(0, nr_trace_entries): addr = self.ramdump.read_word( - page + trace_entries_offset + i * trace_entry_size) + struct_holding_trace_entries + trace_entries_offset + i * trace_entry_size) if addr == 0: break @@ -66,8 +102,8 @@ class PageTracking(RamParser): if look is None: break symname, offset = look - unwind_dat = ' [<{0:x}>] {1}+0x{2:x}\n'.format(addr, - symname, offset) + unwind_dat = ' [<{0:x}>] {1}+0x{2:x}\n'.format( + addr, symname, offset) out_tracking.write(unwind_dat) alloc_str = alloc_str + unwind_dat diff --git a/linux-ramdump-parser-v2/parsers/slabinfo.py b/linux-ramdump-parser-v2/parsers/slabinfo.py index e65fb1504c95cc409ba78f931414868eff9a9fa1..ff9dcaca2563c4d9af904a1e744d8d28c8da2309 100644 --- a/linux-ramdump-parser-v2/parsers/slabinfo.py +++ b/linux-ramdump-parser-v2/parsers/slabinfo.py @@ -26,7 +26,26 @@ SLUB_RED_ACTIVE = 0xcc POISON_INUSE = 0x5a POISON_FREE = 0x6b POISON_END = 0xa5 -g_printfreeobjStack = False + +FREQUENCY = 0 +CALLSTACK_INDEX = 1 +CALL_STACK = 2 +TRACK_TYPE = 3 + +# g_Optimization - if false will print : +# 1. Free objects callstacks +# 2. Object address range of allocated and FREE objects +g_Optimization = True + +# When optimization is true, below two parameters will be used +# 1. MAX_NO_OF_CALLSTACK_TO_PRINT : Maximum number of callstacks to print +# in a slab. +# 2. CALLSTACK_FREQ_IN_SLAB: Print callstack only if occurance of +# each unique callstack in a slab is more than particular +# value(CALLSTACK_FREQ_IN_SLAB) + +MAX_NO_OF_CALLSTACK_TO_PRINT = 5 +CALLSTACK_FREQ_IN_SLAB = 10 class kmem_cache(object): @@ -89,6 +108,8 @@ class struct_member_offset(object): 'struct page', 'freelist') self.sizeof_struct_track = ramdump.sizeof( 'struct track') + self.cpu_cache_page_offset = ramdump.field_offset( + 'struct kmem_cache_cpu', 'page') self.sizeof_void_pointer = ramdump.sizeof( "void *") self.sizeof_unsignedlong = ramdump.sizeof( @@ -131,7 +152,7 @@ class Slabinfo(RamParser): p = obj + slab.inuse return p + track_type * track_size - def extract_callstack(self, ramdump, a, stack, out_file): + def extract_callstack(self, ramdump, stack, out_file): for a in stack: look = ramdump.unwind_lookup(a) if look is None: @@ -159,28 +180,17 @@ class Slabinfo(RamParser): if stackstr_len == 0: return try: - self.g_allstacks[stackstr][0] += 1 - if self.g_allstacks[stackstr][0] > 1: + self.g_allstacks[stackstr][FREQUENCY] += 1 + if self.g_allstacks[stackstr][FREQUENCY] > 1: return - self.extract_callstack(self.ramdump, a, stack, out_file) except KeyError: - if g_printfreeobjStack is False: + if g_Optimization is True: if track_type != 0: - # if free object and g_printfreeobjStack is False, + # if free object and g_Optimization is True, # ignore it for printing its call stack return - if track_type == 1: - out_file.write( - "FREE Call stack index:{0}".format( - self.g_index)) - else: - out_file.write( - "ALLOCATED Call stack index:{0}".format( - self.g_index)) - self.extract_callstack(self.ramdump, a, stack, out_file) - self.g_allstacks[stackstr] = [1, self.g_index] + self.g_allstacks[stackstr] = [1, self.g_index, stack, track_type] self.g_index += 1 - out_file.write('\n') def print_slab( self, ramdump, slab, page, @@ -206,13 +216,41 @@ class Slabinfo(RamParser): page, out_file, out_slabs_addrs) p = p + slab.size - def printsummary(self, slabs_output_summary): + def printsummary(self, slabs_output_summary, slab_out): + nCounter = 0 + write_output = False + str = " Call stack index:{0} frequency: {1}\n" sorted_val = sorted( self.g_allstacks.items(), key=operator.itemgetter(1), reverse=True) - for key, value in sorted_val: + + if g_Optimization is False: + write_output = True + + for key, val in sorted_val: + if g_Optimization is True: + if nCounter >= MAX_NO_OF_CALLSTACK_TO_PRINT: + break + if( + (nCounter < MAX_NO_OF_CALLSTACK_TO_PRINT) + and (val[FREQUENCY] > CALLSTACK_FREQ_IN_SLAB)): + write_output = True + else: + write_output = False + nCounter = nCounter + 1 + if write_output is True: + if val[TRACK_TYPE] == 1: # free object + slab_out.write( + "\nFREE" + str.format( + val[CALLSTACK_INDEX], val[FREQUENCY])) + else: # allocated object + slab_out.write( + "\nALLOCATED" + str.format( + val[CALLSTACK_INDEX], val[FREQUENCY])) + self.extract_callstack(self.ramdump, val[CALL_STACK], slab_out) slabs_output_summary.write( - " stack index:{0} frequency:{1}\n".format(value[1], value[0])) + " stack index:{0} frequency:{1}\n".format( + val[CALLSTACK_INDEX], val[FREQUENCY])) def print_slab_page_info( self, ramdump, slab_obj, slab_node, start, @@ -239,29 +277,31 @@ class Slabinfo(RamParser): page = self.ramdump.read_word(page + g_offsetof.page_lru) def print_per_cpu_slab_info( - self, ramdump, slab, slab_node, start, out_file, map_fn): + self, ramdump, slab, slab_node, start, out_file, map_fn, + out_slabs_addrs): page = self.ramdump.read_word(start) if page == 0: return if page is None: return - page_addr = page_address(self.ramdump, page) self.print_slab( - self.ramdump, page_addr, slab, page, out_file, map_fn) + self.ramdump, slab, page, out_file, map_fn, out_slabs_addrs) def print_all_objects( - self, ramdump, p, free, slab, page, out_file, out_slabs_addrs): - - if free: - out_slabs_addrs.write( - '\n Object {0:x}-{1:x} FREE'.format( + self, ramdump, p, free, slab, page, + out_file, out_slabs_addrs): + + if g_Optimization is False: + if free: + out_slabs_addrs.write( + '\n Object {0:x}-{1:x} FREE'.format( + p, p + slab.size)) + else: + out_slabs_addrs.write( + '\n Object {0:x}-{1:x} ALLOCATED'.format( p, p + slab.size)) - else: - out_slabs_addrs.write( - '\n Object {0:x}-{1:x} ALLOCATED'.format( - p, p + slab.size)) if self.ramdump.is_config_defined('CONFIG_SLUB_DEBUG_ON'): - if g_printfreeobjStack is True: + if g_Optimization is False: self.print_track(ramdump, slab, p, 0, out_file) self.print_track(ramdump, slab, p, 1, out_file) else: @@ -285,6 +325,7 @@ class Slabinfo(RamParser): slab_name_found = False original_slab = self.ramdump.address_of('slab_caches') cpus = self.ramdump.get_num_cpus() + offsetof = struct_member_offset(self.ramdump) self.initializeOffset() slab_list_offset = g_offsetof.kmemcache_list @@ -296,6 +337,16 @@ class Slabinfo(RamParser): slab = self.ramdump.read_word(original_slab) slabs_output_summary = self.ramdump.open_file('slabs_output.txt') out_slabs_addrs = self.ramdump.open_file('out_slabs_addrs.txt') + if g_Optimization is True: + msg = ( + "To optimize slab traverse time," + "print of object address are skipped." + " Supply option perf_off in command" + "prompt to print object address as well." + ) + + out_slabs_addrs.write(msg) + while slab != original_slab: slab = slab - slab_list_offset slab_obj = kmem_cache(self.ramdump, slab) @@ -322,6 +373,9 @@ class Slabinfo(RamParser): print_out_str( '\nExtracting slab details of : {0}'.format( slab_name)) + if g_Optimization is False: + out_slabs_addrs.write( + '\nslab address of : {0}'.format(slab_name)) cpu_slab_addr = self.ramdump.read_word( slab + cpu_slab_offset) nr_total_objects = self.ramdump.read_structure_field( @@ -352,8 +406,7 @@ class Slabinfo(RamParser): self.ramdump, slab_obj, slab_node, cpu_slabn_addr + offsetof.cpu_cache_page_offset, slab_out, map_fn) - - self.printsummary(slabs_output_summary) + self.printsummary(slabs_output_summary, slab_out) self.g_allstacks.clear() if slab_name_found is True: break @@ -362,13 +415,13 @@ class Slabinfo(RamParser): slabs_output_summary.close() def parse(self): - global g_printfreeobjStack + global g_Optimization slabname = None for arg in sys.argv: if 'slabname=' in arg: k, slabname = arg.split('=') - if 'freeobj' in arg: - g_printfreeobjStack = True + if 'perf_off' in arg: + g_Optimization = False slab_out = self.ramdump.open_file('slabs.txt') self.validate_slab_cache(slab_out, slabname, self.print_all_objects) slab_out.close() diff --git a/linux-ramdump-parser-v2/parsers/timerlist.py b/linux-ramdump-parser-v2/parsers/timerlist.py old mode 100755 new mode 100644 index 80510a01f43caa7044c5b4751280b22bd9e109d9..a6ddaecb1496e9885f62d79fdc9fa32a1d160f87 --- a/linux-ramdump-parser-v2/parsers/timerlist.py +++ b/linux-ramdump-parser-v2/parsers/timerlist.py @@ -21,13 +21,24 @@ class TimerList(RamParser) : super(TimerList, self).__init__(*args) self.vectors = {'tv1': 256, 'tv2': 64, 'tv3': 64, 'tv4': 64, 'tv5': 64} self.output = [] + major, minor, patch = self.ramdump.kernel_version self.timer_42 = False - + self.timer_jiffies = 'timer_jiffies' + self.tvec_base = 'struct tvec_base' + self.tvec_bases = 'tvec_bases' + self.next_timer = 'next_timer' + + if (major, minor) >= (4, 9): + self.vectors = {'vectors': 512} + self.timer_jiffies = 'clk' + self.tvec_base = 'struct timer_base' + self.tvec_bases = 'timer_bases' + self.next_timer = 'next_expiry' # Timerlist structure changed in kernel 4.2 # Requires separate processing - if self.ramdump.kernel_version[0] >= 4: - if self.ramdump.kernel_version[1] >= 2: - self.timer_42 = True + if (major, minor) >= (4, 2): + self.timer_42 = True + def timer_list_walker(self, node, type, index, base): if node == self.head: @@ -65,7 +76,7 @@ class TimerList(RamParser) : self.output.append(output) def iterate_vec(self, type, base): - vec_addr = base + self.ramdump.field_offset('struct tvec_base', type) + vec_addr = base + self.ramdump.field_offset(self.tvec_base, type) for i in range(0, self.vectors[type]): index = self.ramdump.array_index(vec_addr, 'struct list_head', i) self.head = index @@ -74,7 +85,7 @@ class TimerList(RamParser) : timer_list_walker.walk(index, self.timer_list_walker, type, i, base) def iterate_vec_v2(self, type, base): - vec_addr = base + self.ramdump.field_offset('struct tvec_base', type) + vec_addr = base + self.ramdump.field_offset(self.tvec_base, type) for i in range(0, self.vectors[type]): index = self.ramdump.array_index(vec_addr, 'struct hlist_head', i) self.head = index @@ -101,14 +112,14 @@ class TimerList(RamParser) : tvec_base_deferral_addr = self.ramdump.address_of('tvec_base_deferrable') if tvec_base_deferral_addr: - timer_jiffies_addr = tvec_base_deferral_addr + self.ramdump.field_offset('struct tvec_base', 'timer_jiffies') - next_timer_addr = tvec_base_deferral_addr + self.ramdump.field_offset('struct tvec_base', 'next_timer') + timer_jiffies_addr = tvec_base_deferral_addr + self.ramdump.field_offset(self.tvec_base, self.timer_jiffies) + next_timer_addr = tvec_base_deferral_addr + self.ramdump.field_offset(self.tvec_base, self.next_timer) timer_jiffies = self.ramdump.read_word(timer_jiffies_addr) next_timer = self.ramdump.read_word(next_timer_addr) - active_timers_offset = self.ramdump.field_offset('struct tvec_base', 'active_timers') + active_timers_offset = self.ramdump.field_offset(self.tvec_base, 'active_timers') if active_timers_offset is not None: - active_timers_addr = tvec_base_deferral_addr + self.ramdump.field_offset('struct tvec_base', 'active_timers') + active_timers_addr = tvec_base_deferral_addr + self.ramdump.field_offset(self.tvec_base, 'active_timers') active_timers = self.ramdump.read_word(active_timers_addr) else: active_timers = "NA" @@ -127,8 +138,7 @@ class TimerList(RamParser) : self.iterate_vec(vec, tvec_base_deferral_addr) self.print_vec(vec) - tvec_bases_addr = self.ramdump.address_of('tvec_bases') - + tvec_bases_addr = self.ramdump.address_of(self.tvec_bases) for cpu in range(0, self.ramdump.get_num_cpus()): title = "CPU {0}".format(cpu) @@ -140,14 +150,14 @@ class TimerList(RamParser) : title += "(tvec_base: {0:x} ".format(base) - timer_jiffies_addr = base + self.ramdump.field_offset('struct tvec_base', 'timer_jiffies') - next_timer_addr = base + self.ramdump.field_offset('struct tvec_base', 'next_timer') + timer_jiffies_addr = base + self.ramdump.field_offset(self.tvec_base, self.timer_jiffies) + next_timer_addr = base + self.ramdump.field_offset(self.tvec_base, self.next_timer) timer_jiffies = self.ramdump.read_word(timer_jiffies_addr) next_timer = self.ramdump.read_word(next_timer_addr) - active_timers_offset = self.ramdump.field_offset('struct tvec_base', 'active_timers') + active_timers_offset = self.ramdump.field_offset(self.tvec_base, 'active_timers') if active_timers_offset is not None: - active_timers_addr = base + self.ramdump.field_offset('struct tvec_base', 'active_timers') + active_timers_addr = base + self.ramdump.field_offset(self.tvec_base, 'active_timers') active_timers = self.ramdump.read_word(active_timers_addr) else: active_timers = "NA" diff --git a/linux-ramdump-parser-v2/ramdump.py b/linux-ramdump-parser-v2/ramdump.py index 289b850cde1e491610f1cf7cf64e97879c37c92d..e0a379cd4d5c11884d38dfd6e1c1885af2fab48c 100755 --- a/linux-ramdump-parser-v2/ramdump.py +++ b/linux-ramdump-parser-v2/ramdump.py @@ -590,6 +590,7 @@ class RamDump(): if self.kimage_voffset is not None: self.kimage_voffset = self.kimage_vaddr - self.phys_offset self.modules_end = self.kimage_vaddr + print_out_str("The kimage_voffset extracted is: {:x}".format(self.kimage_voffset)) # The address of swapper_pg_dir can be used to determine # whether or not we're running with LPAE enabled since an @@ -695,6 +696,16 @@ class RamDump(): sys.exit(1) return f + def remove_file(self, file_name): + file_path = os.path.join(self.outdir, file_name) + try: + if (os.path.exists(file_path)): + os.remove(file_path) + except: + print_out_str('Could not remove file {0}'.format(file_path)) + print_out_str('Do you have write/read permissions on the path?') + sys.exit(1) + def get_config(self): kconfig_addr = self.address_of('kernel_config_data') if kconfig_addr is None: @@ -1264,6 +1275,11 @@ class RamDump(): s = self.read_string(addr_or_name, '<?', virtual, cpu) return s[0] if s is not None else None + def read_s64(self, addr_or_name, virtual=True, cpu=None): + """returns a value guaranteed to be 64 bits""" + s = self.read_string(addr_or_name, '<q', virtual, cpu) + return s[0] if s is not None else None + def read_u64(self, addr_or_name, virtual=True, cpu=None): """returns a value guaranteed to be 64 bits""" s = self.read_string(addr_or_name, '<Q', virtual, cpu) @@ -1302,6 +1318,9 @@ class RamDump(): """reads a 4 or 8 byte field from a structure""" size = self.sizeof("(({0} *)0)->{1}".format(struct_name, field)) virt = self.resolve_virt(addr_or_name) + if virt is None or size is None: + return None + if size == 4: return self.read_u32(virt + self.field_offset(struct_name, field)) diff --git a/linux-ramdump-parser-v2/tlbdumplib.py b/linux-ramdump-parser-v2/tlbdumplib.py new file mode 100644 index 0000000000000000000000000000000000000000..03e9f77793224c1e9bb5b85e80d0c84c715618b3 --- /dev/null +++ b/linux-ramdump-parser-v2/tlbdumplib.py @@ -0,0 +1,398 @@ +# Copyright (c) 2017, 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. + +import struct + +"""dictionary mapping from (hw_id, client_id, version) to class CacheDump""" +lookuptable = {} + + +def lookup_tlb_type(hwid, client_id, version): + """defaults to CacheDump() if no match found""" + return lookuptable.get((hwid, client_id, version), TlbDump()) + + +def formatwidth(string, limit): + if len(string) >= limit: + return string[0:limit] + formatstr = '{{0:{0}}}'.format(limit) + return formatstr.format(string) + +class TableOutputFormat: + """ Not sure if using PrettyTable (python lib) is a good idea, since people + would need to install it""" + + def __init__(self): + self.titlebar = [] + self.datafmt = [] + self.have_printed_title = False + self.separator = ' ' + + def addColumn(self, string, datafmt='{0}', width=0): + width = max(len(string), width) + string = formatwidth(string, width) + self.titlebar.append(string) + self.datafmt.append(datafmt) + + def printline(self, array, outfile): + if (len(array) != len(self.titlebar)): + raise Exception('BadTableDataSize', array, self.titlebar) + + if (not self.have_printed_title): + self.have_printed_title = True + outfile.write(self.separator.join(self.titlebar)) + outfile.write('\n') + + for item, title, fmt in zip(array, self.titlebar, self.datafmt): + item = fmt.format(item) + item = formatwidth(item, len(title)) + outfile.write(item) + outfile.write(self.separator) + + outfile.write('\n') + + +class TlbDump(object): + """ Class to describe a method to parse a particular type of tlbdump. + Users should not make instances of this class.""" + def __init__(self): + """do nothing""" + + def parse(self, start, end, ramdump, outfile): + """Called from debug_image_v2.py. Overriden by child classes""" + raise NotImplementedError + +class TlbDumpType(TlbDump): + def __init__(self): + super(TlbDumpType, self).__init__() + self.tableformat = TableOutputFormat() + self.tableformat.addColumn('Way', '{0:01x}') + self.tableformat.addColumn('Set', '{0:03x}') + self.ramdump = None + self.linefmt = None + + def add_table_data_columns(self): + for i in range(0, self.LineSize): + str = "DATA{0}".format(i) + self.tableformat.addColumn(str, '{0:08x}', 8) + + def read_line(self, start): + if self.linefmt is None: + self.linefmt = '<' + self.linefmt += 'I'* self.LineSize + return self.ramdump.read_string(start, self.linefmt, virtual=False) + + +class TlbDumpType_v1(TlbDumpType): + def __init__(self): + super(TlbDumpType_v1, self).__init__() + + def parse(self, start, end, ramdump, outfile): + self.ramdump = ramdump + self.add_table_data_columns() + + for nset in range(self.NumSets): + for nway in range(self.NumWays): + if start > end: + raise Exception('past the end of array') + + output = [nway, nset] + line = self.read_line(start) + output.extend(line) + self.tableformat.printline(output, outfile) + start = start + self.LineSize * 0x4 + +class TlbDumpType_v2(TlbDumpType): + def __init__(self): + super(TlbDumpType_v2, self).__init__() + self.tableformat.addColumn('RAM') + self.tableformat.addColumn('TYPE') + self.tableformat.addColumn('PA', '{0:016x}', 16) + self.tableformat.addColumn('VA', '{0:016x}', 16) + self.tableformat.addColumn('VALID') + self.tableformat.addColumn('VMID', '{0:02x}', 4) + self.tableformat.addColumn('ASID', '{0:04x}', 4) + self.tableformat.addColumn('S1_MODE', '{0:01x}', 7) + self.tableformat.addColumn('S1_LEVEL', '{0:01x}', 8) + self.tableformat.addColumn('SIZE') + + def parse(self, start, end, ramdump, outfile): + self.ramdump = ramdump + self.add_table_data_columns() + + ram = 0 + for nway in range(self.NumWaysRam0): + offset = 0 + for nset in range(self.NumSetsRam0): + if start > end: + raise Exception('past the end of array') + + output = [nway, nset] + line = self.read_line(start) + self.parse_tag_fn(output, line, nset, nway, ram, offset) + output.extend(line) + self.tableformat.printline(output, outfile) + start = start + self.LineSize * 0x4 + offset = offset + 0x1000 + + ram = 1 + for nway in range(self.NumWaysRam0): + offset = 0 + for nset in range(self.NumSetsRam1): + if start > end: + raise Exception('past the end of array') + + output = [nway, nset] + line = self.read_line(start) + self.parse_tag_fn(output, line, nset, nway, ram, offset) + output.extend(line) + self.tableformat.printline(output, outfile) + start = start + self.LineSize * 0x4 + offset = (offset + 0x1000) + +class L1_TLB_KRYO2XX_GOLD(TlbDumpType_v2): + def __init__(self): + super(L1_TLB_KRYO2XX_GOLD, self).__init__() + self.unsupported_header_offset = 0 + self.LineSize = 4 + self.NumSetsRam0 = 0x100 + self.NumSetsRam1 = 0x3c + self.NumWaysRam0 = 4 + self.NumWaysRam1 = 2 + + def parse_tag_fn(self, output, data, nset, nway, ram, offset): + tlb_type = self.parse_tlb_type(data) + + s1_mode = (data[0] >> 2) & 0x3 + + s1_level = data[0] & 0x3 + + pa = (data[2] >> 4) * 0x1000 + pa = pa + offset + + va_l = (data[1] >> 2) + va_h = (data[2]) & 0x7 + va = (va_h << 45) | (va_l << 16) + va = va + offset + + if ((va >> 40) & 0xff )== 0xff: + va = va + 0xffff000000000000 + + valid = (data[2] >> 3) & 0x1 + + vmid_1 = (data[0] >> 26) & 0x3f + vmid_2 = data[1] & 0x3 + vmid = (vmid_2 << 6) | vmid_1 + + asid = (data[0] >> 10) & 0xffff + + size = self.parse_size(data, ram, tlb_type) + output.append(ram) + output.append(tlb_type) + output.append(pa) + output.append(va) + output.append(valid) + output.append(vmid) + output.append(asid) + output.append(s1_mode) + output.append(s1_level) + output.append(size) + + def parse_tlb_type(self, data): + type_num = (data[3] >> 20) & 0x1 + if type_num == 0x0: + s1_level = data[0] & 0x3 + if s1_level == 0x3: + return "IPA" + else: + return "REG" + else: + return "WALK" + + def parse_size(self, data, ram, tlb_type): + size = (data[0] >> 6) & 0x7 + if tlb_type == "REG": + if ram == 0: + if size == 0x0: + return "4KB" + elif size == 0x1: + return "16KB" + else: + return "64KB" + else: + if size == 0x0: + return "1MB" + elif size == 0x1: + return "2MB" + elif size == 0x2: + return "16MB" + elif size == 0x3: + return "32MB" + elif size == 0x4: + return "512MB" + else: + return "1GB" + else: + if size == 0x1: + return "4KB" + elif size == 0x3: + return "16KB" + elif size == 0x4: + return "64KB" + +class L1_TLB_A53(TlbDumpType_v1): + def __init__(self): + super(L1_TLB_A53, self).__init__() + self.unsupported_header_offset = 0 + self.LineSize = 4 + self.NumSets = 0x100 + self.NumWays = 4 + +class L1_TLB_KRYO3XX_GOLD(TlbDumpType_v2): + def __init__(self): + super(L1_TLB_KRYO3XX_GOLD, self).__init__() + self.unsupported_header_offset = 0 + self.LineSize = 4 + self.NumSetsRam0 = 0x100 + self.NumSetsRam1 = 0x3c + self.NumWaysRam0 = 4 + self.NumWaysRam1 = 2 + + def parse_tag_fn(self, output, data, nset, nway, ram, offset): + #tlb_type = self.parse_tlb_type(data) + + s1_mode = (data[0] >> 2) & 0x3 + + s1_level = data[0] & 0x3 + + pa_l = data[2] >> 14 + pa_h = (data[3])& 0x1fff + pa = (pa_h << 18 | pa_l) * 0x1000 + pa = pa + offset + + va_l = (data[1] >> 10) + va_h = (data[2]) & 0x3ff + va = ((va_h << 22) | (va_l)) * 0x1000 + va = va + offset + + if ((va >> 40) & 0xff )== 0xff: + va = va + 0xffff000000000000 + + valid = (data[2] >> 11) & 0x1 + + vmid_1 = (data[0] >> 26) & 0x3f + vmid_2 = data[1] & 0x3ff + vmid = (vmid_2 << 6) | vmid_1 + + asid = (data[0] >> 10) & 0xffff + + size = self.parse_size(data, ram, tlb_type) + output.append(ram) + output.append("N/A") + output.append(pa) + output.append(va) + output.append(valid) + output.append(vmid) + output.append(asid) + output.append(s1_mode) + output.append(s1_level) + output.append(size) + + def parse_tlb_type(self, data): + type_num = (data[3] >> 20) & 0x1 + if type_num == 0x0: + s1_level = data[0] & 0x3 + if s1_level == 0x3: + return "IPA" + else: + return "REG" + else: + return "WALK" + + def parse_size(self, data, ram, tlb_type): + size = (data[0] >> 6) & 0x7 + if ram == 0: + if size == 0x0: + return "4KB" + elif size == 0x1: + return "16KB" + else: + return "64KB" + else: + if size == 0x0: + return "1MB" + elif size == 0x1: + return "2MB" + elif size == 0x2: + return "16MB" + elif size == 0x3: + return "32MB" + elif size == 0x4: + return "512MB" + else: + return "1GB" + +class L1_TLB_KRYO3XX_SILVER(TlbDumpType_v1): + def __init__(self): + super(L1_TLB_KRYO3XX_SILVER, self).__init__() + self.unsupported_header_offset = 0 + self.LineSize = 4 + self.NumSets = 0x100 + self.NumWays = 4 + +# "sdm845" +lookuptable[("sdm845", 0x20, 0x14)] = L1_TLB_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x21, 0x14)] = L1_TLB_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x22, 0x14)] = L1_TLB_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x23, 0x14)] = L1_TLB_KRYO3XX_SILVER() +lookuptable[("sdm845", 0x24, 0x14)] = L1_TLB_KRYO3XX_GOLD() +lookuptable[("sdm845", 0x25, 0x14)] = L1_TLB_KRYO3XX_GOLD() +lookuptable[("sdm845", 0x26, 0x14)] = L1_TLB_KRYO3XX_GOLD() +lookuptable[("sdm845", 0x27, 0x14)] = L1_TLB_KRYO3XX_GOLD() + +# "msm8998" +lookuptable[("8998", 0x20, 0x14)] = L1_TLB_A53() +lookuptable[("8998", 0x21, 0x14)] = L1_TLB_A53() +lookuptable[("8998", 0x22, 0x14)] = L1_TLB_A53() +lookuptable[("8998", 0x23, 0x14)] = L1_TLB_A53() +lookuptable[("8998", 0x24, 0x14)] = L1_TLB_KRYO2XX_GOLD() +lookuptable[("8998", 0x25, 0x14)] = L1_TLB_KRYO2XX_GOLD() +lookuptable[("8998", 0x26, 0x14)] = L1_TLB_KRYO2XX_GOLD() +lookuptable[("8998", 0x27, 0x14)] = L1_TLB_KRYO2XX_GOLD() + + +lookuptable[("8998", 0x40, 0x14)] = L1_TLB_A53() +lookuptable[("8998", 0x41, 0x14)] = L1_TLB_A53() +lookuptable[("8998", 0x42, 0x14)] = L1_TLB_A53() +lookuptable[("8998", 0x43, 0x14)] = L1_TLB_A53() +lookuptable[("8998", 0x44, 0x14)] = L1_TLB_KRYO2XX_GOLD() +lookuptable[("8998", 0x45, 0x14)] = L1_TLB_KRYO2XX_GOLD() +lookuptable[("8998", 0x46, 0x14)] = L1_TLB_KRYO2XX_GOLD() +lookuptable[("8998", 0x47, 0x14)] = L1_TLB_KRYO2XX_GOLD() + diff --git a/linux-ramdump-parser-v2/watchdog_v2.py b/linux-ramdump-parser-v2/watchdog_v2.py index c9e856e8513de3c531534ae985cd0a2777c9d9cd..f74a42a6aed63d23958879dbd714497eeebd525f 100755 --- a/linux-ramdump-parser-v2/watchdog_v2.py +++ b/linux-ramdump-parser-v2/watchdog_v2.py @@ -12,7 +12,6 @@ import struct import re -from scandump_reader import Scandump_v2 from print_out import print_out_str from bitops import is_set from parser_util import register_parser, RamParser @@ -696,7 +695,7 @@ class TZCpuCtx_v2(): class TZRegDump_v2(): - def __init__(self, has_scan_dump): + def __init__(self): self.core_regs = None self.sec_regs = None self.neon_regs = {} @@ -706,7 +705,6 @@ class TZRegDump_v2(): self.core = 0 self.status = [] self.neon_fields = [] - self.has_scan_dump = has_scan_dump def dump_all_regs(self, ram_dump): coren_regs = ram_dump.open_file('core{0}_regs.cmm'.format(self.core)) @@ -819,21 +817,9 @@ class TZRegDump_v2(): self.start_addr += struct.calcsize( sysdbg_cpu32_ctxt_regs_type[self.version]) - if self.has_scan_dump: - if core > 3: - self.scan_data = Scandump_v2(self.core, ram_dump, self.version) - self.scan_regs = self.scan_data.prepare_dict() - else: - print_out_str("No Scan dump data to be processed...") - self.core_regs = TZCpuCtx_v2(self.version, sc_regs, self.neon_regs, ram_dump) - if core > 3: - if self.has_scan_dump: - self.scan_regs['pc'] = self.core_regs.regs['pc'] - self.core_regs.regs = self.scan_regs - self.sec_regs = TZCpuCtx_v2(self.version, sc_secure, self.neon_regs, ram_dump) return True