diff --git a/dcc_parser/dcc_parser.py b/dcc_parser/dcc_parser.py index b296cd52acdda87c0b95a3a1d95065e86e4a6264..bfa26ebe6f283668896f9a8dd165c222ece3d8c6 100644 --- a/dcc_parser/dcc_parser.py +++ b/dcc_parser/dcc_parser.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 @@ -44,6 +44,12 @@ def add_addr(base, offset, length): address.append(addr) +def add_loop_addr(loop_nr, loop_count): + for i in range(0, loop_count): + for j in range(len(address) - loop_nr, len(address)): + address.append(address[j]) + + def read_data(data_pt): nr = count while nr > 0: @@ -59,9 +65,30 @@ def read_data(data_pt): def read_config(config_pt): - nr = 0 + list_nr = [] + list_nr.append(0) offset = 0 base = 0 + + if options.version is None: + address_descriptor = 0x1 << 31 + link_descriptor = 0 + loop_descriptor = None + rd_mod_wr_descriptor = None + dcc_write_ind = None + link_second_arg = 8 + # We return zero and fail + on_zero_link_len = 0 + else: + address_descriptor = 0 + link_descriptor = 0x3 << 30 + loop_descriptor = 0x1 << 30 + rd_mod_wr_descriptor = 0x1 << 31 + dcc_write_ind = 0x1 << 28 + link_second_arg = 7 + #indicates end of list + on_zero_link_len = -1 + while True: word = config_pt.read(4) if len(word) != 4: @@ -72,27 +99,64 @@ def read_config(config_pt): if val == 0: break - if val & (1 << 31): + descriptor = val & (0x3 << 30) + read_write_ind = val & (0x1 << 28) + + if read_write_ind == dcc_write_ind: + config_pt.seek(8, 1) + elif descriptor == address_descriptor: base = ((val & 0x0FFFFFFF) << 4) offset = 0 - else: + elif descriptor == link_descriptor: for i in range(0, 2): offset = offset + (val & 0xFF) * 4 val = val >> 8 length = (val & 0x7f) - val = val >> 8 + val = val >> link_second_arg if length != 0: - nr += length + list_nr.append(length + list_nr[- 1]) add_addr(base, offset, length) else: - if (i == 0): - log.error("Error! Found zero length!") - return 0 + if (i == 0 ): + return list_nr[on_zero_link_len] else: offset = 0 - return nr + elif descriptor == loop_descriptor: + loop_offset = val & 0x1FFF + loop_count = (val & 0xFFFE000) >> 13 + + if loop_offset == 0: + continue + + loop_nr = list_nr[-1] - list_nr[-loop_offset] + list_nr.append(loop_nr * loop_count + list_nr[-1]) + add_loop_addr(loop_nr, loop_count) + + elif descriptor == rd_mod_wr_descriptor: + ''' + Skip over mask and value of rd_mod_wr. + There is no gaurantee of this being actually written + and we never read the value back to confirm. + ''' + config_pt.seek(8, 1) + + return list_nr[-1] + + +def new_linked_list(config_pt): + word = config_pt.read(4) + + if len(word)!= 4: + return False + else: + val = struct.unpack('<L', word)[0] + if val != 0: + config_pt.seek(-4, 1) + return True + else: + return False def dump_regs_json(options): @@ -128,11 +192,16 @@ def dump_regs_xml(options): def dump_regs(options): + if not address: + log.error('No configuration found in SRAM!!') + sys.exit(1) + if options.json is True: dump_regs_json(options) else: dump_regs_xml(options) + if __name__ == '__main__': usage = 'usage: %prog [options to print]. Run with --help for more details' parser = OptionParser(usage) @@ -148,6 +217,8 @@ if __name__ == '__main__': parser.add_option('', '--chip-name', dest='chipname', help='chip name') parser.add_option('', '--chip-version', dest='chipversion', help='chip version') + parser.add_option('--v2', dest='version', action="store_const", const='2', + help='DCC driver version 2') (options, args) = parser.parse_args() @@ -199,18 +270,20 @@ if __name__ == '__main__': sys.exit(1) count = 0 - count = read_config(sram_file) - if options.atbfile is None: - atb_file = sram_file - if count == 0: - log.error('No configuration found in SRAM!!') - sys.exit(1) + while True: + count = read_config(sram_file) - if read_data(atb_file): - log.error('Couldn\'t read complete data.') - else: - parsed_data = log_init('PARSED_DATA', options.outdir, options.outfile) - dump_regs(options) + if options.atbfile is None: + atb_file = sram_file + + if read_data(sram_file): + log.error('Couldn\'t read complete data.') + break + + if new_linked_list(sram_file) is False: + parsed_data = log_init('PARSED_DATA', options.outdir, options.outfile) + dump_regs(options) + break sram_file.close() diff --git a/linux-ramdump-parser-v2/README b/linux-ramdump-parser-v2/README index efeea31b704496bf2a433ad2decd78694b32158a..ac50385e585f2d8409b5bd9e69f94e35bd6e7acd 100644 --- a/linux-ramdump-parser-v2/README +++ b/linux-ramdump-parser-v2/README @@ -72,6 +72,11 @@ specify the paths to these tools. This can be done in three ways 1) Using --gdb-path and --nm-path to specify the absolute path 2) Using CROSS_COMPILE to specify the prefix 3) Using local_settings.py as described below +4) Install this library from https://github.com/eliben/pyelftools + - Download the code from avobe github link. Download the zip file. + - After download the zip file, you will find a folder pyelftools-master. + - Inside this folder you will find another folder named "elftools" + - copy that entire folder and paste it in below directory <installed Python path>\Lib\site-packages Just having gdb/nm on the path is not supported as there are too many variations on names to invoke. diff --git a/linux-ramdump-parser-v2/boards.py b/linux-ramdump-parser-v2/boards.py old mode 100755 new mode 100644 index 3909b106623b8774ad99ede4b8d907230b00d093..fc96d4dcb10a9cbc6f71baf349f91e20ef9ea1cc --- a/linux-ramdump-parser-v2/boards.py +++ b/linux-ramdump-parser-v2/boards.py @@ -451,6 +451,7 @@ class Board660(Board): self.cpu = 'CORTEXA53' self.ram_start = 0x80000000 self.smem_addr = 0x6000000 + self.smem_addr_buildinfo = 0x6006ec0 self.phys_offset = 0x80000000 self.imem_start = 0x14680000 self.kaslr_addr = 0x146bf6d0 diff --git a/linux-ramdump-parser-v2/cachedumplib.py b/linux-ramdump-parser-v2/cachedumplib.py index ce5014be815fbfa28d846ae77cd403c4e57fafa5..40ba0cfc1196814da5569035604c5a4d93dd2020 100644 --- a/linux-ramdump-parser-v2/cachedumplib.py +++ b/linux-ramdump-parser-v2/cachedumplib.py @@ -445,7 +445,7 @@ class L1_DCache_KRYO3XX_SILVER(CacheDumpType_v1): self.NumSets = 0x80 self.NumWays = 4 - def MESI_to_string(MESI_d): + def MESI_to_string(self, MESI_d): if MESI_d == 0: return 'I' elif MESI_d == 1: @@ -483,7 +483,7 @@ class L1_ICache_KRYO3XX_SILVER(CacheDumpType_v1): self.NumSets = 0x80 self.NumWays = 4 - def valid_to_string(valid_d): + def valid_to_string(self, valid_d): if valid_d == 0: return 'A32' elif valid_d == 1: @@ -518,7 +518,7 @@ class L1_DCache_KRYO3XX_GOLD(CacheDumpType_v1): self.NumSets = 0x40 self.NumWays = 16 - def MESI_to_string(MESI_d): + def MESI_to_string(self, MESI_d): if MESI_d == 0: return 'I' elif MESI_d == 1: @@ -537,7 +537,7 @@ class L1_DCache_KRYO3XX_GOLD(CacheDumpType_v1): mesi_d = (data[0] >> 2) & 0x3 addr = (addr_higher << 22) | addr_lower - mesi = MESI_to_string(mesi_d) + mesi = self.MESI_to_string(mesi_d) output.append(addr) output.append(mesi) diff --git a/linux-ramdump-parser-v2/debug_image_v2.py b/linux-ramdump-parser-v2/debug_image_v2.py old mode 100755 new mode 100644 index 51539703c26f8c1c671ad02367f14143594d9328..5e6332a970db917c28675cb722962d21fe52b562 --- a/linux-ramdump-parser-v2/debug_image_v2.py +++ b/linux-ramdump-parser-v2/debug_image_v2.py @@ -86,6 +86,25 @@ qdss_tag_to_field_name = { 'MSM_DUMP_DATA_DBGUI_REG': 'dbgui_start', } +# Client functions will be executed in top-to-bottom order +minidump_dump_table_type = [ + ('MSM_DUMP_DATA_SCANDUMP', 'KSCANDUMP'), + ('MSM_DUMP_DATA_CPU_CTX', 'KCPU_CTX'), + ('MSM_DUMP_DATA_L1_INST_TLB', 'KCPUSS'), + ('MSM_DUMP_DATA_L1_DATA_TLB','KCPUSS'), + ('MSM_DUMP_DATA_L1_INST_CACHE', 'KCPUSS'), + ('MSM_DUMP_DATA_L1_DATA_CACHE', 'KCPUSS'), + ('MSM_DUMP_DATA_L2_CACHE', 'KCPUSS'), + ('MSM_DUMP_DATA_L3_CACHE', 'KCPUSS'), + ('MSM_DUMP_DATA_VSENSE', 'KVSENSE'), + ('MSM_DUMP_DATA_PMIC', 'KPMIC'), + ('MSM_DUMP_DATA_DCC_REG', 'KDCC_REG'), + ('MSM_DUMP_DATA_DCC_SRAM', 'KDCC_SRAM'), + ('MSM_DUMP_DATA_TMC_ETF', 'KTMC_ETF'), + ('MSM_DUMP_DATA_TMC_REG', 'KTMC_REG') + +] + class DebugImage_v2(): def __init__(self, ramdump): @@ -476,7 +495,7 @@ class DebugImage_v2(): client_entry + dump_entry_id_offset, False) if (client_id < 0 or - client_id > len(self.dump_data_id_lookup_table)): + client_id >= len(self.dump_data_id_lookup_table)): print_out_str( '!!! Invalid dump client id found {0:x}'.format(client_id)) continue @@ -491,6 +510,21 @@ class DebugImage_v2(): results.sort(key=lambda(x): client_names.index(x[0])) return results + def minidump_data_clients(self, ram_dump, client_id,entry_pa_addr, + end_addr): + results = list() + client_table = dict(client_types) + # get first column of client_types + + client_name = self.dump_data_id_lookup_table[client_id] + + if client_name not in client_table: + print_out_str( + '!!! {0} Does not have an associated function. Skipping!'.format(client_name)) + return None + + results.append((client_name, client_id,client_table[client_name], entry_pa_addr,end_addr)) + return results def parse_dump_v2(self, ram_dump): self.dump_type_lookup_table = ram_dump.gdbmi.get_enum_lookup_table( @@ -532,141 +566,207 @@ class DebugImage_v2(): client.MSM_DUMP_DATA_LOG_BUF_FIRST_IDX] = 'MSM_DUMP_DATA_LOG_BUF_FIRST_IDX' self.dump_data_id_lookup_table[ client.MSM_DUMP_DATA_L2_TLB] = 'MSM_DUMP_DATA_L2_TLB' - dump_table_ptr_offset = ram_dump.field_offset( - 'struct msm_memory_dump', 'table') - dump_table_version_offset = ram_dump.field_offset( - 'struct msm_dump_table', 'version') - dump_table_num_entry_offset = ram_dump.field_offset( - 'struct msm_dump_table', 'num_entries') - dump_table_entry_offset = ram_dump.field_offset( - 'struct msm_dump_table', 'entries') - dump_entry_id_offset = ram_dump.field_offset( - 'struct msm_dump_entry', 'id') - dump_entry_name_offset = ram_dump.field_offset( - 'struct msm_dump_entry', 'name') - dump_entry_type_offset = ram_dump.field_offset( - 'struct msm_dump_entry', 'type') - dump_entry_addr_offset = ram_dump.field_offset( - 'struct msm_dump_entry', 'addr') - dump_data_version_offset = ram_dump.field_offset( - 'struct msm_dump_data', 'version') - dump_data_magic_offset = ram_dump.field_offset( - 'struct msm_dump_data', 'magic') - dump_data_name_offset = ram_dump.field_offset( - 'struct msm_dump_data', 'name') - dump_data_addr_offset = ram_dump.field_offset( - 'struct msm_dump_data', 'addr') - dump_data_len_offset = ram_dump.field_offset( - 'struct msm_dump_data', 'len') - dump_data_reserved_offset = ram_dump.field_offset( - 'struct msm_dump_data', 'reserved') - dump_entry_size = ram_dump.sizeof('struct msm_dump_entry') - dump_data_size = ram_dump.sizeof('struct msm_dump_data') - - mem_dump_data = ram_dump.address_of('memdump') - - mem_dump_table = ram_dump.read_word( - mem_dump_data + dump_table_ptr_offset) - - mem_table_version = ram_dump.read_u32( - mem_dump_table + dump_table_version_offset) - if mem_table_version is None: - print_out_str('Version is bogus! Can\'t parse debug image') - return - mem_table_num_entry = ram_dump.read_u32( - mem_dump_table + dump_table_num_entry_offset) - if mem_table_num_entry is None or mem_table_num_entry > 100: - print_out_str('num_entries is bogus! Can\'t parse debug image') - return - - print_out_str('\nDebug image version: {0}.{1} Number of table entries {2}'.format( - mem_table_version >> 20, mem_table_version & 0xFFFFF, mem_table_num_entry)) - print_out_str('--------') - - for i in range(0, mem_table_num_entry): - this_entry = mem_dump_table + dump_table_entry_offset + \ - i * dump_entry_size - entry_id = ram_dump.read_u32(this_entry + dump_entry_id_offset) - entry_type = ram_dump.read_u32(this_entry + dump_entry_type_offset) - entry_addr = ram_dump.read_word(this_entry + dump_entry_addr_offset) - - if entry_id < 0 or entry_id > len(self.dump_table_id_lookup_table): - print_out_str( - '!!! Invalid dump table entry id found {0:x}'.format(entry_id)) - continue - - if entry_type > len(self.dump_type_lookup_table): - print_out_str( - '!!! Invalid dump table entry type found {0:x}'.format(entry_type)) - continue - table_version = ram_dump.read_u32( - entry_addr + dump_table_version_offset, False) - if table_version is None: - print_out_str('Dump table entry version is bogus! Can\'t parse debug image') + if not ram_dump.minidump: + dump_table_ptr_offset = ram_dump.field_offset( + 'struct msm_memory_dump', 'table') + dump_table_version_offset = ram_dump.field_offset( + 'struct msm_dump_table', 'version') + dump_table_num_entry_offset = ram_dump.field_offset( + 'struct msm_dump_table', 'num_entries') + dump_table_entry_offset = ram_dump.field_offset( + 'struct msm_dump_table', 'entries') + dump_entry_id_offset = ram_dump.field_offset( + 'struct msm_dump_entry', 'id') + dump_entry_name_offset = ram_dump.field_offset( + 'struct msm_dump_entry', 'name') + dump_entry_type_offset = ram_dump.field_offset( + 'struct msm_dump_entry', 'type') + dump_entry_addr_offset = ram_dump.field_offset( + 'struct msm_dump_entry', 'addr') + dump_data_version_offset = ram_dump.field_offset( + 'struct msm_dump_data', 'version') + dump_data_magic_offset = ram_dump.field_offset( + 'struct msm_dump_data', 'magic') + dump_data_name_offset = ram_dump.field_offset( + 'struct msm_dump_data', 'name') + dump_data_addr_offset = ram_dump.field_offset( + 'struct msm_dump_data', 'addr') + dump_data_len_offset = ram_dump.field_offset( + 'struct msm_dump_data', 'len') + dump_data_reserved_offset = ram_dump.field_offset( + 'struct msm_dump_data', 'reserved') + dump_entry_size = ram_dump.sizeof('struct msm_dump_entry') + dump_data_size = ram_dump.sizeof('struct msm_dump_data') + + mem_dump_data = ram_dump.address_of('memdump') + + mem_dump_table = ram_dump.read_word( + mem_dump_data + dump_table_ptr_offset) + + mem_table_version = ram_dump.read_u32( + mem_dump_table + dump_table_version_offset) + if mem_table_version is None: + print_out_str('Version is bogus! Can\'t parse debug image') return - table_num_entries = ram_dump.read_u32( - entry_addr + dump_table_num_entry_offset, False) - if table_num_entries is None or table_num_entries > 100: - print_out_str('Dump table entry num_entries is bogus! Can\'t parse debug image') + mem_table_num_entry = ram_dump.read_u32( + mem_dump_table + dump_table_num_entry_offset) + if mem_table_num_entry is None or mem_table_num_entry > 100: + print_out_str('num_entries is bogus! Can\'t parse debug image') return - print_out_str( - 'Debug image version: {0}.{1} Entry id: {2} Entry type: {3} Number of entries: {4}'.format( - table_version >> 20, table_version & 0xFFFFF, self.dump_table_id_lookup_table[entry_id], - self.dump_type_lookup_table[entry_type], table_num_entries)) - - lst = self.sorted_dump_data_clients( - ram_dump, entry_addr + dump_table_entry_offset, - table_num_entries) - for (client_name, func, client_entry) in lst: - print_out_str('--------') - client_id = ram_dump.read_u32( - client_entry + dump_entry_id_offset, False) - client_type = ram_dump.read_u32( - client_entry + dump_entry_type_offset, False) - client_addr = ram_dump.read_word( - client_entry + dump_entry_addr_offset, False) - - if client_type > len(self.dump_type_lookup_table): + print_out_str('\nDebug image version: {0}.{1} Number of table entries {2}'.format( + mem_table_version >> 20, mem_table_version & 0xFFFFF, mem_table_num_entry)) + print_out_str('--------') + + for i in range(0, mem_table_num_entry): + this_entry = mem_dump_table + dump_table_entry_offset + \ + i * dump_entry_size + entry_id = ram_dump.read_u32(this_entry + dump_entry_id_offset) + entry_type = ram_dump.read_u32(this_entry + dump_entry_type_offset) + entry_addr = ram_dump.read_word(this_entry + dump_entry_addr_offset) + + if entry_id < 0 or entry_id > len(self.dump_table_id_lookup_table): print_out_str( - '!!! Invalid dump client type found {0:x}'.format(client_type)) + '!!! Invalid dump table entry id found {0:x}'.format(entry_id)) continue - dump_data_magic = ram_dump.read_u32( - client_addr + dump_data_magic_offset, False) - dump_data_version = ram_dump.read_u32( - client_addr + dump_data_version_offset, False) - dump_data_name = ram_dump.read_cstring( - client_addr + dump_data_name_offset, - ram_dump.sizeof('((struct msm_dump_data *)0x0)->name'), - False) - dump_data_addr = ram_dump.read_dword( - client_addr + dump_data_addr_offset, False) - dump_data_len = ram_dump.read_dword( - client_addr + dump_data_len_offset, False) - print_out_str('Parsing debug information for {0}. Version: {1} Magic: {2:x} Source: {3}'.format( - client_name, dump_data_version, dump_data_magic, - dump_data_name)) - - if dump_data_magic is None: - print_out_str("!!! Address {0:x} is bogus! Can't parse!".format( - client_addr + dump_data_magic_offset)) + if entry_type > len(self.dump_type_lookup_table): + print_out_str( + '!!! Invalid dump table entry type found {0:x}'.format(entry_type)) continue - if dump_data_magic != MEMDUMPV2_MAGIC: - print_out_str("!!! Magic {0:x} doesn't match! No context will be parsed".format(dump_data_magic)) + table_version = ram_dump.read_u32( + entry_addr + dump_table_version_offset, False) + if table_version is None: + print_out_str('Dump table entry version is bogus! Can\'t parse debug image') + return + table_num_entries = ram_dump.read_u32( + entry_addr + dump_table_num_entry_offset, False) + if table_num_entries is None or table_num_entries > 100: + print_out_str('Dump table entry num_entries is bogus! Can\'t parse debug image') + return + + print_out_str( + 'Debug image version: {0}.{1} Entry id: {2} Entry type: {3} Number of entries: {4}'.format( + table_version >> 20, table_version & 0xFFFFF, self.dump_table_id_lookup_table[entry_id], + self.dump_type_lookup_table[entry_type], table_num_entries)) + + lst = self.sorted_dump_data_clients( + ram_dump, entry_addr + dump_table_entry_offset, + table_num_entries) + for (client_name, func, client_entry) in lst: + print_out_str('--------') + client_id = ram_dump.read_u32( + client_entry + dump_entry_id_offset, False) + client_type = ram_dump.read_u32( + client_entry + dump_entry_type_offset, False) + client_addr = ram_dump.read_word( + client_entry + dump_entry_addr_offset, False) + + if client_type > len(self.dump_type_lookup_table): + print_out_str( + '!!! Invalid dump client type found {0:x}'.format(client_type)) + continue + + dump_data_magic = ram_dump.read_u32( + client_addr + dump_data_magic_offset, False) + dump_data_version = ram_dump.read_u32( + client_addr + dump_data_version_offset, False) + dump_data_name = ram_dump.read_cstring( + client_addr + dump_data_name_offset, + ram_dump.sizeof('((struct msm_dump_data *)0x0)->name'), + False) + dump_data_addr = ram_dump.read_dword( + client_addr + dump_data_addr_offset, False) + dump_data_len = ram_dump.read_dword( + client_addr + dump_data_len_offset, False) + print_out_str('Parsing debug information for {0}. Version: {1} Magic: {2:x} Source: {3}'.format( + client_name, dump_data_version, dump_data_magic, + dump_data_name)) + + if dump_data_magic is None: + print_out_str("!!! Address {0:x} is bogus! Can't parse!".format( + client_addr + dump_data_magic_offset)) + continue + + if dump_data_magic != MEMDUMPV2_MAGIC: + print_out_str("!!! Magic {0:x} doesn't match! No context will be parsed".format(dump_data_magic)) + continue + + getattr(DebugImage_v2, func)( + self, dump_data_version, dump_data_addr, + dump_data_addr + dump_data_len, client_id, ram_dump) + else: + dump_smem_table_ptr_offset = ram_dump.field_offset( + 'struct md_table', 'md_smem_table') + dump_table_version_offset = ram_dump.field_offset( + 'struct md_smem_table', 'version') + dump_table_num_entry_offset = ram_dump.field_offset( + 'struct md_table', 'num_regions') + dump_table_entry_offset = ram_dump.field_offset( + 'struct md_table', 'entry') + dump_entry_name_offset = ram_dump.field_offset( + 'struct md_region', 'name') + dump_entry_id_offset = ram_dump.field_offset( + 'struct md_region', 'id') + dump_entry_va_offset = ram_dump.field_offset( + 'struct md_region', 'virt_addr') + dump_entry_pa_offset = ram_dump.field_offset( + 'struct md_region', 'phys_addr') + dump_entry_size_offset = ram_dump.field_offset( + 'struct md_region', 'size') + + dump_entry_size = ram_dump.sizeof('struct md_region') + + mem_dump_data = ram_dump.address_of('minidump_table') + + mem_dump_table = ram_dump.read_word( + mem_dump_data + dump_table_entry_offset) + + mem_dump_smem_table = ram_dump.read_word( + mem_dump_data + dump_smem_table_ptr_offset) + + mem_table_version = ram_dump.read_u32( + mem_dump_smem_table + dump_table_version_offset) + mem_table_num_entry = ram_dump.read_u32( + mem_dump_data + dump_table_num_entry_offset) + + print_out_str('--------') + + for i in range(0, mem_table_num_entry): + this_entry = mem_dump_data + dump_table_entry_offset + \ + i * dump_entry_size + entry_id = ram_dump.read_u32(this_entry + dump_entry_id_offset) + entry_va_addr = ram_dump.read_u64(this_entry + dump_entry_va_offset) + entry_pa_addr = ram_dump.read_u64(this_entry + dump_entry_pa_offset) + entry_size = ram_dump.read_u64(this_entry + dump_entry_size_offset) + + if entry_id < 0 or entry_id > len(self.dump_table_id_lookup_table): + print_out_str( + '!!! Invalid dump table entry id found {0:x}'.format(entry_id)) continue + end_addr = entry_pa_addr + entry_size + minidump_dump_table_value = dict(minidump_dump_table_type) + if entry_pa_addr in ram_dump.ebi_pa_name_map: + section_name = ram_dump.ebi_pa_name_map[entry_pa_addr] + section_name = re.sub("\d+", "", section_name) + if section_name in minidump_dump_table_value.values(): + lst = self.minidump_data_clients( + ram_dump, entry_id,entry_pa_addr,end_addr) + if lst: + client_name, client_id,func,\ + client_entry,client_end = lst[0] + print_out_str('--------') + getattr(DebugImage_v2, func)( + self, 20, client_entry, + client_end, client_id, ram_dump) + if ram_dump.dcc: + self.parse_dcc(ram_dump) + self.qdss.dump_standard(ram_dump) + if not ram_dump.skip_qdss_bin: + self.qdss.save_etf_bin(ram_dump) + self.qdss.save_etr_bin(ram_dump) + if ram_dump.qtf: + self.parse_qtf(ram_dump) - getattr(DebugImage_v2, func)( - self, dump_data_version, dump_data_addr, - dump_data_addr + dump_data_len, client_id, ram_dump) - - self.qdss.dump_standard(ram_dump) - if not ram_dump.skip_qdss_bin: - self.qdss.save_etf_bin(ram_dump) - self.qdss.save_etr_bin(ram_dump) - if ram_dump.qtf: - self.parse_qtf(ram_dump) - if ram_dump.dcc: - self.parse_dcc(ram_dump) diff --git a/linux-ramdump-parser-v2/minidump_util.py b/linux-ramdump-parser-v2/minidump_util.py new file mode 100644 index 0000000000000000000000000000000000000000..92ef72b29cb6355f2e4a107989076fff2bb966ed --- /dev/null +++ b/linux-ramdump-parser-v2/minidump_util.py @@ -0,0 +1,56 @@ +# Copyright (c) 2012-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 sys +import re +import os +from print_out import print_out_str + + +def minidump_virt_to_phys(ebi_files,addr): + pa_addr = None + for a in ebi_files: + idx, pa, end_addr, va,size = a + if addr >= va and addr <= va + size: + offset = addr - va + pa_addr = pa + offset + return pa_addr + return pa_addr + +def read_physical_minidump(ebi_files,ebi_files_ramfile,elffile,addr,length): + ebi = [-1, -1, -1, -1, -1] + for a in ebi_files: + idx, start, end, va, size = a + if addr >= start and addr <= end: + ebi = a + break + if ebi[0] != -1: + idx = ebi[0] + textSec = elffile.get_segment(idx) + off = addr - ebi[1] + elf_content = bytearray(a[4]) + val = textSec.data() + elf_content[0:a[4]] = val + data = elf_content[off:] + return data[:length] + else: + ebi = (-1, -1, -1) + for a in ebi_files_ramfile: + fd, start, end, path = a + if addr >= start and addr <= end: + ebi = a + break + if ebi[0] is -1: + return None + offset = addr - ebi[1] + ebi[0].seek(offset) + a = ebi[0].read(length) + return a diff --git a/linux-ramdump-parser-v2/parsers/memusage.py b/linux-ramdump-parser-v2/parsers/memusage.py old mode 100755 new mode 100644 index ef86e54ef07198f9debce60e410a5e2c11d916c0..e610f429f6d194ae7af46d0523e73f403c82191a --- a/linux-ramdump-parser-v2/parsers/memusage.py +++ b/linux-ramdump-parser-v2/parsers/memusage.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 @@ -18,7 +18,10 @@ def do_dump_process_memory(ramdump): "NR_FREE_PAGES", "NR_SLAB_RECLAIMABLE", "NR_SLAB_UNRECLAIMABLE", "NR_SHMEM"] vmstat_data = {} - vmstats_addr = ramdump.address_of('vm_stat') + if(ramdump.kernel_version >= (4,9,0)): + vmstats_addr = ramdump.address_of('vm_zone_stat') + else: + vmstats_addr = ramdump.address_of('vm_stat') for x in vmstat_names: i = ramdump.gdbmi.get_value_of(x) vmstat_data[x] = ramdump.read_word( diff --git a/linux-ramdump-parser-v2/parsers/slabsummary.py b/linux-ramdump-parser-v2/parsers/slabsummary.py index 328cafd53d1872c9835d9a77dba14a035c3bb465..f9358090b8ed919c41df402673fe8ad87b0175f4 100644 --- a/linux-ramdump-parser-v2/parsers/slabsummary.py +++ b/linux-ramdump-parser-v2/parsers/slabsummary.py @@ -145,5 +145,8 @@ class Slabinfo_summary(RamParser): def parse(self): slab_out = self.ramdump.open_file('slabsummary.txt') - self.print_slab_summary(slab_out) + if(self.ramdump.is_config_defined('CONFIG_SLUB_DEBUG_ON')): + self.print_slab_summary(slab_out) + else: + slab_out.write('CONFIG_SLUB_DEBUG_ON is disabled in this build') slab_out.close() diff --git a/linux-ramdump-parser-v2/parsers/timerlist.py b/linux-ramdump-parser-v2/parsers/timerlist.py index a6ddaecb1496e9885f62d79fdc9fa32a1d160f87..650fea738f561b64a003d7bf9c2424d10829caa9 100644 --- a/linux-ramdump-parser-v2/parsers/timerlist.py +++ b/linux-ramdump-parser-v2/parsers/timerlist.py @@ -27,6 +27,7 @@ class TimerList(RamParser) : self.tvec_base = 'struct tvec_base' self.tvec_bases = 'tvec_bases' self.next_timer = 'next_timer' + self.global_deferrable = 'tvec_base_deferrable' if (major, minor) >= (4, 9): self.vectors = {'vectors': 512} @@ -34,6 +35,7 @@ class TimerList(RamParser) : self.tvec_base = 'struct timer_base' self.tvec_bases = 'timer_bases' self.next_timer = 'next_expiry' + self.global_deferrable = 'timer_base_deferrable' # Timerlist structure changed in kernel 4.2 # Requires separate processing if (major, minor) >= (4, 2): @@ -110,7 +112,7 @@ class TimerList(RamParser) : def get_timer_list(self): self.output_file.write("Timer List Dump\n\n") - tvec_base_deferral_addr = self.ramdump.address_of('tvec_base_deferrable') + tvec_base_deferral_addr = self.ramdump.address_of(self.global_deferrable) if tvec_base_deferral_addr: 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) diff --git a/linux-ramdump-parser-v2/ramdump.py b/linux-ramdump-parser-v2/ramdump.py index 8d126080e578ad26bf71c80875335732cd1a8ba1..d6814a8da1463bfe6cc31633b43c463fe535736c 100644 --- a/linux-ramdump-parser-v2/ramdump.py +++ b/linux-ramdump-parser-v2/ramdump.py @@ -27,6 +27,8 @@ import gdbmi from print_out import print_out_str from mmu import Armv7MMU, Armv7LPAEMMU, Armv8MMU import parser_util +import minidump_util +from importlib import import_module FP = 11 SP = 13 @@ -49,7 +51,8 @@ extra_mem_file_names = ['EBI1CS1.BIN', 'DDRCS1.BIN', 'ebi1_cs1.bin', DDR_FILE_NAMES = ['DDRCS0.BIN', 'DDRCS1.BIN', 'DDRCS0_0.BIN', 'DDRCS1_0.BIN', 'DDRCS0_1.BIN', 'DDRCS1_1.BIN'] -OTHER_DUMP_FILE_NAMES = ['PIMEM.BIN', 'OCIMEM.BIN'] +OTHER_DUMP_FILE_NAMES = ['PIMEM.BIN', 'OCIMEM.BIN','md_shared_imem.BIN', + 'md_smem_info.BIN'] RAM_FILE_NAMES = set(DDR_FILE_NAMES + OTHER_DUMP_FILE_NAMES + first_mem_file_names + @@ -499,6 +502,8 @@ class RamDump(): def __init__(self, options, nm_path, gdb_path, objdump_path): self.ebi_files = [] + self.ebi_files_minidump = [] + self.ebi_pa_name_map = {} self.phys_offset = None self.kaslr_offset = options.kaslr_offset self.tz_start = 0 @@ -530,6 +535,20 @@ class RamDump(): self.ipc_log_help = options.ipc_help self.use_stdout = options.stdout self.kernel_version = (0, 0, 0) + self.minidump = options.minidump + self.elffile = None + self.ram_elf_file = None + + if self.minidump: + try: + mod = import_module('elftools.elf.elffile') + ELFFile = mod.ELFFile + StringTableSection = mod.StringTableSection + mod = import_module('elftools.common.py3compat') + bytes2str = mod.bytes2str + except ImportError: + print "Oops, missing required library for minidump. Check README" + sys.exit(1) if options.ram_addr is not None: # TODO sanity check to make sure the memory regions don't overlap @@ -540,11 +559,31 @@ class RamDump(): 'Could not open {0}. Will not be part of dump'.format(file_path)) continue self.ebi_files.append((fd, start, end, file_path)) - else: + elif not options.minidump: if not self.auto_parse(options.autodump): return None - if self.ebi_start == 0: - self.ebi_start = self.ebi_files[0][1] + if options.minidump: + file_path = options.ram_elf_addr + self.ram_elf_file = file_path + fd = open(file_path, 'rb') + self.elffile = ELFFile(fd) + for idx, s in enumerate(self.elffile.iter_segments()): + pa = int(s['p_paddr']) + va = int(s['p_vaddr']) + size = int(s['p_filesz']) + end_addr = pa + size + for section in self.elffile.iter_sections(): + if (not section.is_null() and + s.section_in_segment(section)): + self.ebi_pa_name_map[pa] = section.name + self.ebi_files_minidump.append((idx, pa, end_addr, va,size)) + + if options.minidump: + if self.ebi_start == 0: + self.ebi_start = self.ebi_files_minidump[0][1] + else: + if self.ebi_start == 0: + self.ebi_start = self.ebi_files[0][1] if self.phys_offset is None: self.get_hw_id() @@ -600,10 +639,12 @@ class RamDump(): self.swapper_pg_dir_addr = self.address_of('swapper_pg_dir') if self.swapper_pg_dir_addr is None: print_out_str('!!! Could not get the swapper page directory!') - print_out_str( - '!!! Your vmlinux is probably wrong for these dumps') - print_out_str('!!! Exiting now') - sys.exit(1) + if not self.minidump: + print_out_str( + '!!! Your vmlinux is probably wrong for these dumps') + + print_out_str('!!! Exiting now') + sys.exit(1) stext = self.address_of('stext') if self.kimage_voffset is None: @@ -664,11 +705,12 @@ class RamDump(): '!!! Your vmlinux is probably wrong for these dumps') print_out_str('!!! Exiting now') sys.exit(1) - if not self.get_config(): - print_out_str('!!! Could not get saved configuration') - print_out_str( - '!!! This is really bad and probably indicates RAM corruption') - print_out_str('!!! Some features may be disabled!') + if not self.minidump: + if not self.get_config(): + print_out_str('!!! Could not get saved configuration') + print_out_str( + '!!! This is really bad and probably indicates RAM corruption') + print_out_str('!!! Some features may be disabled!') self.unwind = self.Unwinder(self) @@ -755,14 +797,17 @@ class RamDump(): return s in self.config def kernel_virt_to_phys(self, addr): - va_bits = 39 - if self.kimage_voffset is None: - return addr - self.page_offset + self.phys_offset + if self.minidump: + return minidump_util.minidump_virt_to_phys(self.ebi_files_minidump,addr) else: - if addr & (1 << (va_bits - 1)): + va_bits = 39 + if self.kimage_voffset is None: return addr - self.page_offset + self.phys_offset else: - return addr - (self.kimage_voffset) + if addr & (1 << (va_bits - 1)): + return addr - self.page_offset + self.phys_offset + else: + return addr - (self.kimage_voffset) def get_version(self): banner_addr = self.address_of('linux_banner') @@ -803,10 +848,34 @@ class RamDump(): else: print_out_str('!!! Could not lookup saved command line address') return False + + def print_socinfo_minidump(self): + content_socinfo = None + boards = get_supported_boards() + for board in boards: + if self.hw_id == board.board_num: + content_socinfo = board.ram_start + board.smem_addr_buildinfo + break + sernum_offset = self.field_offset('struct socinfo_v10', 'serial_number') + if sernum_offset is None: + sernum_offset = self.field_offset('struct socinfo_v0_10', 'serial_number') + if sernum_offset is None: + print_out_str("No serial number information available") + return False + if content_socinfo: + addr_of_sernum = content_socinfo + sernum_offset + serial_number = self.read_u32(addr_of_sernum, False) + if serial_number is not None: + print_out_str('Serial number %s' % hex(serial_number)) + return True + return False + + return False def print_socinfo(self): content_socinfo = hex(self.read_pointer('socinfo')) content_socinfo = content_socinfo.strip('L') + sernum_offset = self.field_offset('struct socinfo_v10', 'serial_number') if sernum_offset is None: sernum_offset = self.field_offset('struct socinfo_v0_10', 'serial_number') @@ -819,6 +888,7 @@ class RamDump(): if serial_number is not None: print_out_str('Serial number %s' % hex(serial_number)) return True + return False def auto_parse(self, file_path): @@ -889,41 +959,46 @@ class RamDump(): ebi_path = os.path.abspath(ram[3]) startup_script.write('data.load.binary {0} 0x{1:x}\n'.format( ebi_path, ram[1]).encode('ascii', 'ignore')) - if self.arm64: - startup_script.write('Register.Set NS 1\n'.encode('ascii', 'ignore')) - startup_script.write('Data.Set SPR:0x30201 %Quad 0x{0:x}\n'.format( - self.kernel_virt_to_phys(self.swapper_pg_dir_addr)) - .encode('ascii', 'ignore')) - - if is_cortex_a53: - startup_script.write('Data.Set SPR:0x30202 %Quad 0x00000012B5193519\n'.encode('ascii', 'ignore')) - startup_script.write('Data.Set SPR:0x30A20 %Quad 0x000000FF440C0400\n'.encode('ascii', 'ignore')) - startup_script.write('Data.Set SPR:0x30A30 %Quad 0x0000000000000000\n'.encode('ascii', 'ignore')) - startup_script.write('Data.Set SPR:0x30100 %Quad 0x0000000034D5D91D\n'.encode('ascii', 'ignore')) + if self.minidump: + dload_ram_elf = 'data.load.elf {} /LOGLOAD /nosymbol\n'.format(self.ram_elf_file) + startup_script.write(dload_ram_elf.encode('ascii', 'ignore')) + + if not self.minidump: + if self.arm64: + startup_script.write('Register.Set NS 1\n'.encode('ascii', 'ignore')) + startup_script.write('Data.Set SPR:0x30201 %Quad 0x{0:x}\n'.format( + self.kernel_virt_to_phys(self.swapper_pg_dir_addr)) + .encode('ascii', 'ignore')) + + if is_cortex_a53: + startup_script.write('Data.Set SPR:0x30202 %Quad 0x00000012B5193519\n'.encode('ascii', 'ignore')) + startup_script.write('Data.Set SPR:0x30A20 %Quad 0x000000FF440C0400\n'.encode('ascii', 'ignore')) + startup_script.write('Data.Set SPR:0x30A30 %Quad 0x0000000000000000\n'.encode('ascii', 'ignore')) + startup_script.write('Data.Set SPR:0x30100 %Quad 0x0000000034D5D91D\n'.encode('ascii', 'ignore')) + else: + startup_script.write('Data.Set SPR:0x30202 %Quad 0x00000032B5193519\n'.encode('ascii', 'ignore')) + startup_script.write('Data.Set SPR:0x30A20 %Quad 0x000000FF440C0400\n'.encode('ascii', 'ignore')) + startup_script.write('Data.Set SPR:0x30A30 %Quad 0x0000000000000000\n'.encode('ascii', 'ignore')) + startup_script.write('Data.Set SPR:0x30100 %Quad 0x0000000004C5D93D\n'.encode('ascii', 'ignore')) + + startup_script.write('Register.Set CPSR 0x3C5\n'.encode('ascii', 'ignore')) + startup_script.write('MMU.Delete\n'.encode('ascii', 'ignore')) + startup_script.write('MMU.SCAN PT 0xFFFFFF8000000000--0xFFFFFFFFFFFFFFFF\n'.encode('ascii', 'ignore')) + startup_script.write('mmu.on\n'.encode('ascii', 'ignore')) + startup_script.write('mmu.pt.list 0xffffff8000000000\n'.encode('ascii', 'ignore')) else: - startup_script.write('Data.Set SPR:0x30202 %Quad 0x00000032B5193519\n'.encode('ascii', 'ignore')) - startup_script.write('Data.Set SPR:0x30A20 %Quad 0x000000FF440C0400\n'.encode('ascii', 'ignore')) - startup_script.write('Data.Set SPR:0x30A30 %Quad 0x0000000000000000\n'.encode('ascii', 'ignore')) - startup_script.write('Data.Set SPR:0x30100 %Quad 0x0000000004C5D93D\n'.encode('ascii', 'ignore')) - - startup_script.write('Register.Set CPSR 0x3C5\n'.encode('ascii', 'ignore')) - startup_script.write('MMU.Delete\n'.encode('ascii', 'ignore')) - startup_script.write('MMU.SCAN PT 0xFFFFFF8000000000--0xFFFFFFFFFFFFFFFF\n'.encode('ascii', 'ignore')) - startup_script.write('mmu.on\n'.encode('ascii', 'ignore')) - startup_script.write('mmu.pt.list 0xffffff8000000000\n'.encode('ascii', 'ignore')) - else: - startup_script.write( - 'PER.S.F C15:0x2 %L 0x{0:x}\n'.format(self.mmu.ttbr).encode('ascii', 'ignore')) - if isinstance(self.mmu, Armv7LPAEMMU): - # TTBR1. This gets setup once and never change again even if TTBR0 - # changes - startup_script.write('PER.S.F C15:0x102 %L 0x{0:x}\n'.format( - self.mmu.ttbr + 0x4000).encode('ascii', 'ignore')) - # TTBCR with EAE and T1SZ set approprately startup_script.write( - 'PER.S.F C15:0x202 %L 0x80030000\n'.encode('ascii', 'ignore')) - startup_script.write('mmu.on\n'.encode('ascii', 'ignore')) - startup_script.write('mmu.scan\n'.encode('ascii', 'ignore')) + 'PER.S.F C15:0x2 %L 0x{0:x}\n'.format(self.mmu.ttbr).encode('ascii', 'ignore')) + if isinstance(self.mmu, Armv7LPAEMMU): + # TTBR1. This gets setup once and never change again even if TTBR0 + # changes + startup_script.write('PER.S.F C15:0x102 %L 0x{0:x}\n'.format( + self.mmu.ttbr + 0x4000).encode('ascii', 'ignore')) + # TTBCR with EAE and T1SZ set approprately + startup_script.write( + 'PER.S.F C15:0x202 %L 0x80030000\n'.encode('ascii', 'ignore')) + startup_script.write('mmu.on\n'.encode('ascii', 'ignore')) + startup_script.write('mmu.scan\n'.encode('ascii', 'ignore')) where = os.path.abspath(self.vmlinux) if self.kaslr_offset is not None: @@ -953,8 +1028,8 @@ class RamDump(): 'task.config /opt/t32/demo/arm/kernel/linux/linux.t32\n'.encode('ascii', 'ignore')) startup_script.write( 'menu.reprogram /opt/t32/demo/arm/kernel/linux/linux.men\n'.encode('ascii', 'ignore')) - - startup_script.write('task.dtask\n'.encode('ascii', 'ignore')) + if not self.minidump: + startup_script.write('task.dtask\n'.encode('ascii', 'ignore')) startup_script.write( 'v.v %ASCII %STRING linux_banner\n'.encode('ascii', 'ignore')) if os.path.exists(out_path + '/regs_panic.cmm'): @@ -1024,30 +1099,38 @@ class RamDump(): boards = get_supported_boards() if (self.hw_id is None): - heap_toc_offset = self.field_offset('struct smem_shared', 'heap_toc') - if heap_toc_offset is None: - print_out_str( - '!!!! Could not get a necessary offset for auto detection!') - print_out_str( - '!!!! Please check the gdb path which is used for offsets!') - print_out_str('!!!! Also check that the vmlinux is not stripped') - print_out_str('!!!! Exiting...') - sys.exit(1) + if not self.minidump: + heap_toc_offset = self.field_offset('struct smem_shared', 'heap_toc') + if heap_toc_offset is None: + print_out_str( + '!!!! Could not get a necessary offset for auto detection!') + print_out_str( + '!!!! Please check the gdb path which is used for offsets!') + print_out_str('!!!! Also check that the vmlinux is not stripped') + print_out_str('!!!! Exiting...') + sys.exit(1) - smem_heap_entry_size = self.sizeof('struct smem_heap_entry') - offset_offset = self.field_offset('struct smem_heap_entry', 'offset') + smem_heap_entry_size = self.sizeof('struct smem_heap_entry') + offset_offset = self.field_offset('struct smem_heap_entry', 'offset') for board in boards: - socinfo_start_addr = board.smem_addr + heap_toc_offset + smem_heap_entry_size * SMEM_HW_SW_BUILD_ID + offset_offset + if not self.minidump: + socinfo_start_addr = board.smem_addr + heap_toc_offset + smem_heap_entry_size * SMEM_HW_SW_BUILD_ID + offset_offset + else: + if hasattr(board, 'smem_addr_buildinfo'): + socinfo_start_addr = board.smem_addr_buildinfo + else: + continue if add_offset: socinfo_start_addr += board.ram_start - soc_start = self.read_int(socinfo_start_addr, False) - if soc_start is None: - continue - - socinfo_start = board.smem_addr + soc_start - if add_offset: - socinfo_start += board.ram_start - + if not self.minidump: + soc_start = self.read_int(socinfo_start_addr, False) + if soc_start is None: + continue + socinfo_start = board.smem_addr + soc_start + if add_offset: + socinfo_start += board.ram_start + else: + socinfo_start = socinfo_start_addr socinfo_id = self.read_int(socinfo_start + 4, False) if socinfo_id != board.socid: continue @@ -1117,7 +1200,10 @@ class RamDump(): def virt_to_phys(self, virt_or_name): """Does a virtual-to-physical address lookup of the virtual address or variable name.""" - return self.mmu.virt_to_phys(self.resolve_virt(virt_or_name)) + if self.minidump: + return minidump_util.minidump_virt_to_phys(self.ebi_files_minidump,self.resolve_virt(virt_or_name)) + else: + return self.mmu.virt_to_phys(self.resolve_virt(virt_or_name)) def setup_symbol_tables(self): stream = os.popen(self.nm_path + ' -n ' + self.vmlinux) @@ -1249,18 +1335,24 @@ class RamDump(): return (self.lookup_table[mid][1], self.lookup_table[mid + 1][0] - self.lookup_table[mid][0]) def read_physical(self, addr, length): - ebi = (-1, -1, -1) - for a in self.ebi_files: - fd, start, end, path = a - if addr >= start and addr <= end: - ebi = a - break - if ebi[0] is -1: - return None - offset = addr - ebi[1] - ebi[0].seek(offset) - a = ebi[0].read(length) - return a + if self.minidump: + addr_data = minidump_util.read_physical_minidump( + self.ebi_files_minidump, self.ebi_files,self.elffile, + addr, length) + return addr_data + else: + ebi = (-1, -1, -1) + for a in self.ebi_files: + fd, start, end, path = a + if addr >= start and addr <= end: + ebi = a + break + if ebi[0] is -1: + return None + offset = addr - ebi[1] + ebi[0].seek(offset) + a = ebi[0].read(length) + return a def read_dword(self, addr_or_name, virtual=True, cpu=None): s = self.read_string(addr_or_name, '<Q', virtual, cpu) diff --git a/linux-ramdump-parser-v2/ramparse.py b/linux-ramdump-parser-v2/ramparse.py index 7245e9bbb3a05809f892c1985ac666f1af0f249c..89a6257a7e216c4b2dd790207d231a5c93986759 100644 --- a/linux-ramdump-parser-v2/ramparse.py +++ b/linux-ramdump-parser-v2/ramparse.py @@ -152,6 +152,10 @@ if __name__ == '__main__': parser.add_option('', '--eval', help='Evaluate some python code directly, or from stdin if "-" is passed. The "dump" variable will be available, as it is with the --shell option.') # noqa parser.add_option('', '--wlan', dest='wlan', help='wlan.ko path') + parser.add_option('', '--minidump', action='store_true', dest='minidump', + help='Parse minidump') + parser.add_option('', '--ram-elf', dest='ram_elf_addr', + help='pass ap_minidump.elf generated by crashscope') for p in parser_util.get_parsers(): parser.add_option(p.shortopt or '', @@ -161,6 +165,11 @@ if __name__ == '__main__': action='store_true') (options, args) = parser.parse_args() + if options.minidump: + default_list = [] + default_list.append("Dmesg") + default_list.append("RTB") + default_list.append("DebugImage") if options.outdir: if not os.path.exists(options.outdir): @@ -224,7 +233,7 @@ if __name__ == '__main__': print_out_str('using vmlinux file {0}'.format(options.vmlinux)) - if options.ram_addr is None and options.autodump is None: + if options.ram_addr is None and options.autodump is None and not options.minidump: print_out_str('Need one of --auto-dump or at least one --ram-file') sys.exit(1) @@ -343,14 +352,20 @@ if __name__ == '__main__': shell.interact() sys.exit(0) - if not dump.print_command_line(): - print_out_str('!!! Error printing saved command line.') - print_out_str('!!! The vmlinux is probably wrong for the ramdumps') - print_out_str('!!! Exiting now...') - sys.exit(1) + if not options.minidump: + if not dump.print_command_line(): + print_out_str('!!! Error printing saved command line.') + print_out_str('!!! The vmlinux is probably wrong for the ramdumps') + print_out_str('!!! Exiting now...') + sys.exit(1) - if not dump.print_socinfo(): - print_out_str('!!! No serial number information available.') + if options.minidump: + if not dump.print_socinfo_minidump(): + print_out_str('!!! No serial number information ' + 'available for this minidump.') + else: + if not dump.print_socinfo(): + print_out_str('!!! No serial number information available.') if options.qdss: print_out_str('!!! --parse-qdss is now deprecated') @@ -365,12 +380,24 @@ if __name__ == '__main__': # we called parser.add_option with dest=p.cls.__name__ above, # so if the user passed that option then `options' will have a # p.cls.__name__ attribute. - parsers_to_run = [p for p in parser_util.get_parsers() + if options.minidump: + parsers_to_run = [p for p in parser_util.get_parsers() + if getattr(options, p.cls.__name__) + or (options.everything and p.cls.__name__ in default_list)] + else: + parsers_to_run = [p for p in parser_util.get_parsers() if getattr(options, p.cls.__name__) or (options.everything and not p.optional)] for i,p in enumerate(parsers_to_run): if i == 0: sys.stderr.write("\n") + if options.minidump: + if p.cls.__name__ not in default_list: + sys.stderr.write(" [%d/%d] %s ... not supported in minidump \n" % + (i + 1, len(parsers_to_run), p.longopt)) + continue + + sys.stderr.write(" [%d/%d] %s ... " % (i + 1, len(parsers_to_run), p.longopt)) before = time.time() @@ -387,5 +414,6 @@ if __name__ == '__main__': sys.stderr.write("\n") - if options.t32launcher or options.everything: + if options.t32launcher or options.everything or options.minidump: dump.create_t32_launcher() +