예제 #1
0
 def __init__(self, ramdump):
     self.qdss = QDSSDump()
     self.dump_type_lookup_table = []
     self.dump_table_id_lookup_table = []
     self.dump_data_id_lookup_table  = []
     version = re.findall(r'\d+', ramdump.version)
     if int(version[0]) > 3:
         self.event_call = 'struct trace_event_call'
         self.event_class = 'struct trace_event_class'
     else:
         self.event_call = 'struct ftrace_event_call'
         self.event_class = 'struct ftrace_event_class'
 def __init__(self):
     self.qdss = QDSSDump()
     self.dump_type_lookup_table = []
     self.dump_table_id_lookup_table = []
     self.dump_data_id_lookup_table  = []
class DebugImage_v2():

    def __init__(self):
        self.qdss = QDSSDump()
        self.dump_type_lookup_table = []
        self.dump_table_id_lookup_table = []
        self.dump_data_id_lookup_table  = []

    def parse_cpu_ctx(self, start, end, client_id, ram_dump):
        core = client_id - client.MSM_DUMP_DATA_CPU_CTX

        print_out_str(
            'Parsing CPU{2} context start {0:x} end {1:x}'.format(start, end, core))

        regs = TZRegDump_v2()
        if regs.init_regs(start, end, core, ram_dump) is False:
            print_out_str('!!! Could not get registers from TZ dump')
            return
        regs.dump_core_pc(ram_dump)
        regs.dump_all_regs(ram_dump)

    def parse_qdss_common(self, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        if client_id == client.MSM_DUMP_DATA_TMC_ETF_REG:
            setattr(self.qdss, 'tmc_etf_start', start)
        else:
            setattr(self.qdss, qdss_tag_to_field_name[client_name], start)

    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')
        filter_type_offset = ram_dump.field_offset('struct ftrace_event_field', 'filter_type')
        field_offset = ram_dump.field_offset('struct ftrace_event_field', 'offset')
        size_offset = ram_dump.field_offset('struct ftrace_event_field', 'size')
        signed_offset = ram_dump.field_offset('struct ftrace_event_field', 'is_signed')

        name = ram_dump.read_word(common_list + name_offset)
        field_name = ram_dump.read_cstring(name, 256)
        type_name = ram_dump.read_word(common_list + type_offset)
        type_str = ram_dump.read_cstring(type_name, 256)
        offset = ram_dump.read_u32(common_list + field_offset)
        size = ram_dump.read_u32(common_list + size_offset)
        signed = ram_dump.read_u32(common_list + signed_offset)

        if re.match('(.*)\[(.*)', type_str) and not(re.match('__data_loc', type_str)):
            s = re.split('\[', type_str)
            s[1] = '[' + s[1]
            self.formats_out.write("\tfield:{0} {1}{2};\toffset:{3};\tsize:{4};\tsigned:{5};\n".format(s[0], field_name, s[1], offset, size, signed))
        else:
            self.formats_out.write("\tfield:{0} {1};\toffset:{2};\tsize:{3};\tsigned:{4};\n".format(type_str, field_name, offset, size, signed))

    def ftrace_events_func(self, ftrace_list, ram_dump):
        name_offset = ram_dump.field_offset('struct ftrace_event_call', 'name')
        event_offset = ram_dump.field_offset('struct ftrace_event_call', 'event')
        fmt_offset = ram_dump.field_offset('struct ftrace_event_call', 'print_fmt')
        class_offset = ram_dump.field_offset('struct ftrace_event_call', 'class')
        type_offset = ram_dump.field_offset('struct trace_event', 'type')
        fields_offset = ram_dump.field_offset('struct ftrace_event_class', 'fields')
        common_field_list = ram_dump.addr_lookup('ftrace_common_fields')
        field_next_offset = ram_dump.field_offset('struct ftrace_event_field', 'link')

        name = ram_dump.read_word(ftrace_list + name_offset)
        name_str = ram_dump.read_cstring(name, 512)
        event_id = ram_dump.read_word(ftrace_list + event_offset + type_offset)
        fmt = ram_dump.read_word(ftrace_list + fmt_offset)
        fmt_str = ram_dump.read_cstring(fmt, 2048)

        self.formats_out.write("name: {0}\n".format(name_str))
        self.formats_out.write("ID: {0}\n".format(event_id))
        self.formats_out.write("format:\n")

        list_walker = llist.ListWalker(ram_dump, common_field_list, field_next_offset)
        list_walker.walk_prev(common_field_list, self.ftrace_field_func, ram_dump)
        self.formats_out.write("\n")

        event_class = ram_dump.read_word(ftrace_list + class_offset)
        field_list =  event_class + fields_offset
        list_walker = llist.ListWalker(ram_dump, field_list, field_next_offset)
        list_walker.walk_prev(field_list, self.ftrace_field_func, ram_dump)
        self.formats_out.write("\n")
        self.formats_out.write("print fmt: {0}\n".format(fmt_str))

    def collect_ftrace_format(self, ram_dump):
        formats = os.path.join('qtf', 'map_files', 'formats.txt')
        formats_out = ram_dump.open_file(formats)
        self.formats_out = formats_out

        ftrace_events_list = ram_dump.addr_lookup('ftrace_events')
        next_offset = ram_dump.field_offset('struct ftrace_event_call', 'list')
        list_walker = llist.ListWalker(ram_dump, ftrace_events_list, next_offset)
        list_walker.walk_prev(ftrace_events_list, self.ftrace_events_func, ram_dump)

        self.formats_out.close

    def parse_qtf(self, ram_dump):
        out_dir = ram_dump.outdir
        if platform.system() != 'Windows':
            return

        qtf_path = ram_dump.qtf_path
        if qtf_path is None:
            try:
                import local_settings
                try:
                    qtf_path = local_settings.qtf_path
                except AttributeError as e:
                    print_out_str("attribute qtf_path in local_settings.py looks bogus. Please see README.txt")
                    print_out_str("Full message: %s" % e.message)
                    return
            except ImportError:
                print_out_str("missing qtf_path local_settings.")
                print_out_str("Please see the README for instructions on setting up local_settings.py")
                return

        if qtf_path is None:
            print_out_str("!!! Incorrect path for qtf specified.")
            print_out_str("!!! Please see the README for instructions on setting up local_settings.py")
            return

        if not os.path.exists(qtf_path):
            print_out_str("!!! qtf_path {0} does not exist! Check your settings!".format(qtf_path))
            return

        if not os.access(qtf_path, os.X_OK):
            print_out_str("!!! No execute permissions on qtf path {0}".format(qtf_path))
            return

        if os.path.getsize(os.path.join(out_dir, 'tmc-etf.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etf.bin')
        elif os.path.getsize(os.path.join(out_dir, 'tmc-etr.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etr.bin')
        else:
            return

        port = 12345
        qtf_dir = os.path.join(out_dir, 'qtf')
        workspace = os.path.join(qtf_dir, 'qtf.workspace')
        qtf_out = os.path.join(out_dir, 'qtf.txt')
        chipset = 'msm' + str(ram_dump.hw_id)
        hlos = 'LA'

        p = subprocess.Popen([qtf_path, '-s', '{0}'.format(port)])
        subprocess.call('{0} -c {1} new workspace {2} {3} {4}'.format(qtf_path, port, qtf_dir, chipset, hlos))

        self.collect_ftrace_format(ram_dump)

        subprocess.call('{0} -c {1} open workspace {2}'.format(qtf_path, port, workspace))
        subprocess.call('{0} -c {1} open bin {2}'.format(qtf_path, port, trace_file))
        subprocess.call('{0} -c {1} stream trace table {2}'.format(qtf_path, port, qtf_out))
        subprocess.call('{0} -c {1} exit'.format(qtf_path, port))
        p.communicate('quit')

    def parse_dump_v2(self, ram_dump):
        self.dump_type_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_type', 2)
        self.dump_table_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_table_ids', 0x110)
        self.dump_data_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_data_ids', 0x112)
        cpu_present_bits = ram_dump.read_word('cpu_present_bits')
        cpus = bin(cpu_present_bits).count('1')
        # per cpu entries
        for i in range(1, cpus):

                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_CPU_CTX + i] = 'MSM_DUMP_DATA_CPU_CTX'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_INST_CACHE + i] = 'MSM_DUMP_DATA_L1_INST_CACHE'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_DATA_CACHE + i] = 'MSM_DUMP_DATA_L1_DATA_CACHE'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_ETM_REG + i] = 'MSM_DUMP_DATA_ETM_REG'
        # 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'
        self.dump_data_id_lookup_table[
            client.MSM_DUMP_DATA_LOG_BUF] = 'MSM_DUMP_DATA_LOG_BUF'
        self.dump_data_id_lookup_table[
            client.MSM_DUMP_DATA_LOG_BUF_FIRST_IDX] = 'MSM_DUMP_DATA_LOG_BUF_FIRST_IDX'
        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.addr_lookup('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')
                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))

            for j in range(0, table_num_entries):
                print_out_str('--------')
                client_entry = entry_addr + dump_table_entry_offset + j * dump_entry_size
                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_id < 0 or client_id > len(self.dump_data_id_lookup_table):
                    print_out_str(
                        '!!! Invalid dump client id found {0:x}'.format(client_id))
                    continue

                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_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)

                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. The parser needs to be updated!'.format(client_name))
                else:
                    print_out_str('Parsing debug information for {0}. Version: {1} Magic: {2:x}'.format(
                       client_name, dump_data_version, dump_data_magic))

                    if dump_data_magic is None:
                        print_out_str(
                            "!!! Address {0:x} is bogus! Can't parse!".format(start))
                        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

                    func = client_table[client_name]
                    getattr(DebugImage_v2, func)(self, dump_data_addr, dump_data_addr + dump_data_len,
                                                 client_id, ram_dump)

            self.qdss.dump_all(ram_dump)
            if ram_dump.qtf:
                self.parse_qtf(ram_dump)
예제 #4
0
 def __init__(self, *args):
     super(DebugImage, self).__init__(*args)
     self.qdss = QDSSDump()
     self.name_lookup_table = []
예제 #5
0
class DebugImage_v2():

    def __init__(self, ramdump):
        self.qdss = QDSSDump()
        self.dump_type_lookup_table = []
        self.dump_table_id_lookup_table = []
        self.dump_data_id_lookup_table  = []
        version = re.findall(r'\d+', ramdump.version)
        if int(version[0]) > 3:
            self.event_call = 'struct trace_event_call'
            self.event_class = 'struct trace_event_class'
        else:
            self.event_call = 'struct ftrace_event_call'
            self.event_class = 'struct ftrace_event_class'

    def parse_scandump(self, version, start, end, client_id, ram_dump):
        scandump_file_prefix = "scandump_core"
        core_bin_prefix = "core"
        chipset = ram_dump.hw_id
        try:
            scan_wrapper_path = local_settings.scandump_parser_path
        except AttributeError:
            print_out_str('Could not find scandump_parser_path . Please define scandump_parser_path in local_settings')
            return
        if ram_dump.arm64:
            arch = "aarch64"
        else:
            arch = "aarch32"
        if client_id == client.MSM_DUMP_DATA_SCANDUMP:
            output = os.path.join(ram_dump.outdir, scandump_file_prefix)
            input = os.path.join(ram_dump.outdir, "core.bin")
            core_num = client_id & 0xF
        elif client_id >= client.MSM_DUMP_DATA_SCANDUMP_PER_CPU:
            core_num = client_id & 0xF
            output = '{0}_{1:x}'.format(scandump_file_prefix, core_num)
            output = os.path.join(ram_dump.outdir, output)

            input_filename = '{0}_{1:x}.bin'.format(core_bin_prefix, core_num)
            input = os.path.join(ram_dump.outdir, input_filename)
        print_out_str(
            'Parsing scandump context start {0:x} end {1:x} {2} {3}'.format(start, end, output, input))
        header_bin = ram_dump.open_file(input)

        it = range(start, end)
        for i in it:
            val = ram_dump.read_byte(i, False)
            header_bin.write(struct.pack("<B", val))
        header_bin.close()
        subprocess.call('python {0} -d {1} -o {2} -f {3} -c {4}'.format(scan_wrapper_path, input, output, arch, chipset))
        sv2 = Scandump_v2(core_num,ram_dump,version)
        reg_info = sv2.prepare_dict()
        if reg_info is not None:
            sv2.dump_core_pc(ram_dump)
            sv2.dump_all_regs(ram_dump)
        return

    def parse_fcmdump(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
                'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        fcmdumps = FCM_Dump(start, end)
        if fcmdumps.dump_fcm_img(ram_dump) is False:
            print_out_str('!!! Could not dump FCM')

        return

    def parse_cpu_ctx(self, version, start, end, client_id, ram_dump):
        core = client_id - client.MSM_DUMP_DATA_CPU_CTX

        print_out_str(
            'Parsing CPU{2} context start {0:x} end {1:x}'.format(start, end, core))

        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
        regs.dump_core_pc(ram_dump)
        regs.dump_all_regs(ram_dump)

    def parse_pmic(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        regs = PmicRegDump(start, end)
        if regs.parse_all_regs(ram_dump) is False:
            print_out_str('!!! Could not get registers from PMIC dump')
            return

        regs.dump_all_regs(ram_dump)

    def parse_dcc_reg(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        regs = DccRegDump(start, end)
        if regs.parse_all_regs(ram_dump) is False:
            print_out_str('!!! Could not get registers from DCC register dump')
            return

        regs.dump_all_regs(ram_dump)
        return

    def parse_dcc_sram(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        regs = DccSramDump(start, end, ram_dump)
        if regs.dump_sram_img(ram_dump) is False:
            print_out_str('!!! Could not dump SRAM')
        else:
            ram_dump.dcc = True
        return

    def parse_sysdbg_regs(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        sysregs = SysRegDump(start, end)
        if sysregs.dump_sysreg_img(ram_dump) is False:
            print_out_str('!!! Could not dump sysdbg_regs')
        else:
            ram_dump.sysreg = True
        return

    def parse_vsens(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        regs = VsensData()
        if regs.init_dump_regs(start, end, ram_dump) is False:
            print_out_str('!!! Could not get registers from Vsens Dump')
            return
        regs.print_vsens_regs(ram_dump)

    def parse_qdss_common(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        if client_id == client.MSM_DUMP_DATA_TMC_ETF_REG:
            setattr(self.qdss, 'tmc_etf_start', start)
        else:
            setattr(self.qdss, qdss_tag_to_field_name[client_name], start)

    def parse_cache_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_cache_type(ramdump.hw_id, client_id, version)
        try:
            cache_type.parse(start, end, ramdump, outfile)
        except NotImplementedError:
            print_out_str('Cache 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 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 %s'
                          % 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')
        filter_type_offset = ram_dump.field_offset('struct ftrace_event_field', 'filter_type')
        field_offset = ram_dump.field_offset('struct ftrace_event_field', 'offset')
        size_offset = ram_dump.field_offset('struct ftrace_event_field', 'size')
        signed_offset = ram_dump.field_offset('struct ftrace_event_field', 'is_signed')

        name = ram_dump.read_word(common_list + name_offset)
        field_name = ram_dump.read_cstring(name, 256)
        type_name = ram_dump.read_word(common_list + type_offset)
        type_str = ram_dump.read_cstring(type_name, 256)
        offset = ram_dump.read_u32(common_list + field_offset)
        size = ram_dump.read_u32(common_list + size_offset)
        signed = ram_dump.read_u32(common_list + signed_offset)

        if re.match('(.*)\[(.*)', type_str) and not(re.match('__data_loc', type_str)):
            s = re.split('\[', type_str)
            s[1] = '[' + s[1]
            self.formats_out.write("\tfield:{0} {1}{2};\toffset:{3};\tsize:{4};\tsigned:{5};\n".format(s[0], field_name, s[1], offset, size, signed))
        else:
            self.formats_out.write("\tfield:{0} {1};\toffset:{2};\tsize:{3};\tsigned:{4};\n".format(type_str, field_name, offset, size, signed))

    def ftrace_events_func(self, ftrace_list, ram_dump):
        event_offset = ram_dump.field_offset(self.event_call, 'event')
        fmt_offset = ram_dump.field_offset(self.event_call,'print_fmt')
        class_offset = ram_dump.field_offset(self.event_call, 'class')
        flags_offset = ram_dump.field_offset(self.event_call, 'flags')
        flags = ram_dump.read_word(ftrace_list + flags_offset)
        if ram_dump.kernel_version >= (4, 14):
            TRACE_EVENT_FL_TRACEPOINT = 0x10
        elif ram_dump.kernel_version >= (4, 9):
            TRACE_EVENT_FL_TRACEPOINT = 0x20
        else:
            TRACE_EVENT_FL_TRACEPOINT = 0x40
        if (ram_dump.kernel_version >= (3, 18) and (flags & TRACE_EVENT_FL_TRACEPOINT)):
            tp_offset = ram_dump.field_offset(self.event_call, 'tp')
            tp_name_offset = ram_dump.field_offset('struct tracepoint', 'name')
            tp = ram_dump.read_word(ftrace_list + tp_offset)
            name = ram_dump.read_word(tp + tp_name_offset)
        else:
            name_offset = ram_dump.field_offset(self.event_call, 'name')
            name = ram_dump.read_word(ftrace_list + name_offset)

        type_offset = ram_dump.field_offset('struct trace_event', 'type')
        fields_offset = ram_dump.field_offset(self.event_class, 'fields')
        common_field_list = ram_dump.address_of('ftrace_common_fields')
        field_next_offset = ram_dump.field_offset('struct ftrace_event_field', 'link')

        name_str = ram_dump.read_cstring(name, 512)
        event_id = ram_dump.read_word(ftrace_list + event_offset + type_offset)
        fmt = ram_dump.read_word(ftrace_list + fmt_offset)
        fmt_str = ram_dump.read_cstring(fmt, 2048)

        self.formats_out.write("name: {0}\n".format(name_str))
        self.formats_out.write("ID: {0}\n".format(event_id))
        self.formats_out.write("format:\n")

        list_walker = llist.ListWalker(ram_dump, common_field_list, field_next_offset)
        list_walker.walk_prev(common_field_list, self.ftrace_field_func, ram_dump)
        self.formats_out.write("\n")

        event_class = ram_dump.read_word(ftrace_list + class_offset)
        field_list =  event_class + fields_offset
        list_walker = llist.ListWalker(ram_dump, field_list, field_next_offset)
        list_walker.walk_prev(field_list, self.ftrace_field_func, ram_dump)
        self.formats_out.write("\n")
        self.formats_out.write("print fmt: {0}\n".format(fmt_str))

    def collect_ftrace_format(self, ram_dump):
        formats = os.path.join('qtf', 'map_files', 'formats.txt')
        formats_out = ram_dump.open_file(formats)
        self.formats_out = formats_out

        ftrace_events_list = ram_dump.address_of('ftrace_events')
        next_offset = ram_dump.field_offset(self.event_call, 'list')
        list_walker = llist.ListWalker(ram_dump, ftrace_events_list, next_offset)
        list_walker.walk_prev(ftrace_events_list, self.ftrace_events_func, ram_dump)

        self.formats_out.close

    def wait_for_completion_timeout(self, task, timeout):
        delay = 2.0
        #while the process is still executing and we haven't timed-out yet
        while task.poll() is None and timeout > 0:
            time.sleep(delay)
            timeout -= delay
        if timeout <= 0:
            print_out_str("QTF command timed out")
            task.kill()

    def parse_qtf(self, ram_dump):
        out_dir = ram_dump.outdir
        if platform.system() != 'Windows':
            return

        qtf_path = ram_dump.qtf_path
        if qtf_path is None:
            try:
                import local_settings
                try:
                    qtf_path = local_settings.qtf_path
                except AttributeError as e:
                    print_out_str("attribute qtf_path in local_settings.py looks bogus. Please see README.txt")
                    print_out_str("Full message: %s" % e.message)
                    return
            except ImportError:
                print_out_str("missing qtf_path local_settings.")
                print_out_str("Please see the README for instructions on setting up local_settings.py")
                return

        if qtf_path is None:
            print_out_str("!!! Incorrect path for qtf specified.")
            print_out_str("!!! Please see the README for instructions on setting up local_settings.py")
            return

        if not os.path.exists(qtf_path):
            print_out_str("!!! qtf_path {0} does not exist! Check your settings!".format(qtf_path))
            return

        if not os.access(qtf_path, os.X_OK):
            print_out_str("!!! No execute permissions on qtf path {0}".format(qtf_path))
            return

        if os.path.getsize(os.path.join(out_dir, 'tmc-etf.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etf.bin')
        elif os.path.getsize(os.path.join(out_dir, 'tmc-etr.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etr.bin')
        else:
            return

        port = None
        server_proc = None
        qtf_success = False
        max_tries = 3
        qtf_dir = os.path.join(out_dir, 'qtf')
        workspace = os.path.join(qtf_dir, 'qtf.workspace')
        qtf_out = os.path.join(out_dir, 'qtf.txt')
        chipset = ram_dump.hw_id
        if "sdm" not in ram_dump.hw_id.lower() and \
          "qcs" not in ram_dump.hw_id.lower():
            chipset = "msm" + ram_dump.hw_id
        hlos = 'LA'

        #Temp change to handle descripancy between tools usage
        if chipset == 'msmcobalt':
            chipset = 'msm8998'

        # Resolve any port collisions with other running qtf_server instances
        for tries in range(max_tries):
            port = random.randint(12000, 13000)
            server_proc = subprocess.Popen(
                [qtf_path, '-s', '{:d}'.format(port)], shell=True,stderr=subprocess.PIPE)
            time.sleep(15)
            server_proc.poll()
            if server_proc.returncode == 1:
                server_proc.terminate()
                continue
            else:
                qtf_success = True
                break
        if not qtf_success:
            server_proc.terminate()
            print_out_str('!!! Could not open a QTF server instance with a '
                          'unique port (last port tried: '
                          '{0})'.format(str(port)))
            print_out_str('!!! Please kill all currently running qtf_server '
                          'processes and try again')
            return
        #subprocess.call('{0} -c {1} new workspace {2} {3} {4}'.format(qtf_path, port, qtf_dir, chipset, hlos))
        server_proc1 = subprocess.Popen(
                   [qtf_path, '-c', '{:d}'.format(port),'new workspace {0} {1} {2}'.format(qtf_dir, chipset, hlos)], shell=True,stderr=subprocess.PIPE,stdout=subprocess.PIPE)
        server_proc1.communicate()
        self.collect_ftrace_format(ram_dump)

        p = subprocess.Popen('{0} -c {1} open workspace {2}'.format(qtf_path, port, workspace))
        self.wait_for_completion_timeout(p,60)
        p = subprocess.Popen('{0} -c {1} open bin {2}'.format(qtf_path, port, trace_file))
        self.wait_for_completion_timeout(p,90)
        p = subprocess.Popen('{0} -c {1} stream trace table {2}'.format(qtf_path, port, qtf_out))
        self.wait_for_completion_timeout(p,300)
        p = subprocess.Popen('{0} -c {1} close'.format(qtf_path, port))
        self.wait_for_completion_timeout(p,60)
        p = subprocess.Popen('{0} -c {1} exit'.format(qtf_path, port))
        self.wait_for_completion_timeout(p,60)
        server_proc.terminate()

    def parse_dcc(self, ram_dump):
        out_dir = ram_dump.outdir
        if ram_dump.ram_addr is None:
            bin_dir = ram_dump.autodump
        else:
            bin_dir = ram_dump.ram_addr
            bin_dir="\\".join(bin_dir[0][0].split('\\')[:-1])
        dcc_parser_path = os.path.join(os.path.dirname(__file__), '..', 'dcc_parser', 'dcc_parser.py')
        if dcc_parser_path is None:
            print_out_str("!!! Incorrect path for DCC specified.")
            return

        if not os.path.exists(dcc_parser_path):
            print_out_str("!!! dcc_parser_path {0} does not exist! Check your settings!".format(dcc_parser_path))
            return

        if (os.path.isfile(os.path.join(bin_dir, 'DCC_SRAM.BIN'))):
            sram_file = os.path.join(bin_dir, 'DCC_SRAM.BIN')
            cmd = ["-s ", sram_file, " --out-dir ", out_dir, " --config-offset ", "0x6000", " --v2"]
            p = subprocess.Popen([sys.executable, dcc_parser_path, cmd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            print_out_str('--------')
            print_out_str(p.communicate()[0])
        elif os.path.isfile(os.path.join(out_dir, 'sram.bin')):
            sram_file = os.path.join(out_dir, 'sram.bin')
            p = subprocess.Popen([sys.executable, dcc_parser_path, '-s', sram_file, '--out-dir', out_dir],
                    stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            print_out_str('--------')
            print_out_str(p.communicate()[0])
        else:
            print_out_str('DCC SRAM data is not populated!!')
            return

    def parse_sysreg(self,ram_dump):
        out_dir = ram_dump.outdir
        sysreg_parser_path_minidump = os.path.join(os.path.dirname(__file__), '..', 'dcc_parser',
                                                'sysregs_parser_minidump.py')
        if sysreg_parser_path_minidump is None:
            print_out_str("!!! Incorrect path for SYSREG specified.")
            return
        if not os.path.exists(sysreg_parser_path_minidump):
            print_out_str("!!! sysreg_parser_path_minidump {0} does not exist! "
                          "Check your settings!"
                          .format(sysreg_parser_path_minidump))
            return
        if os.path.getsize(os.path.join(out_dir, 'sysdbg_regs.bin')) > 0:
            sysdbg_file = os.path.join(out_dir, 'sysdbg_regs.bin')
        else:
            return
        p = subprocess.Popen([sys.executable, sysreg_parser_path_minidump, '-s', sysdbg_file, '--out-dir', out_dir],
                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

        print_out_str('--------')
        print_out_str(p.communicate()[0])

    def sorted_dump_data_clients(self, ram_dump, table, table_num_entries):
        """ Returns a sorted list of (client_name, func, client_address) where

        client_address --
            the (struct msm_dump_entry*) which contains a client_id mapping to
            client_name

        func --
            registered function in client_types to parse entries of
            this type

        the return value is sorted in the same order as the client names
        in client_types
        """

        dump_entry_id_offset = ram_dump.field_offset(
            'struct msm_dump_entry', 'id')
        dump_entry_size = ram_dump.sizeof('struct msm_dump_entry')
        results = list()

        client_table = dict(client_types)
        # get first column of client_types
        client_names = zip(*client_types)[0]

        for j in range(0, table_num_entries):
            client_entry = table + j * dump_entry_size
            client_id = ram_dump.read_u32(
                            client_entry + dump_entry_id_offset, False)

            if (client_id < 0 or
                    client_id >= len(self.dump_data_id_lookup_table)):
                print_out_str(
                    '!!! Invalid dump client id found {0:x}'.format(client_id))
                continue

            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))
                continue

            results.append((client_name, client_table[client_name], client_entry))

        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

    class MsmDumpTable(object):
        def __init__(self):
            self.name = "Anon"
            self.phys_addr = 0x0
            self.version = 0x0
            self.num_entries = 0x0

    """ Create an instance of MsmDumpTable, or None on error """
    def validateMsmDumpTable(self, ram_dump, name, table_phys):
        if table_phys is None:
            print_out_str('debug_image.py: Table {}: Unable to read dump table base address'.format(name))
            return None

        version = ram_dump.read_structure_field(
                    table_phys, 'struct msm_dump_table', 'version',
                    virtual = False)
        if version is None:
            print_out_str('Table {}: Version is bogus! Can\'t parse debug image'.format(name))
            return None

        num_entries = ram_dump.read_structure_field(
                        table_phys, 'struct msm_dump_table', 'num_entries',
                        virtual = False)
        if num_entries is None or num_entries > 100:
            print_out_str('Table {}: num_entries is bogus! Can\'t parse debug image'.format(name))
            return None

        table = self.MsmDumpTable()
        table.name = name
        table.phys_addr = table_phys
        table.version = version
        table.num_entries = num_entries
        return table

    def parse_dump_v2(self, ram_dump):
        self.dump_type_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_type', 2)
        self.dump_table_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_table_ids', MAX_NUM_ENTRIES)
        self.dump_data_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_data_ids', MAX_NUM_ENTRIES)
        cpus = ram_dump.get_num_cpus()
        # per cpu entries
        for i in range(1, cpus):

                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_CPU_CTX + i] = 'MSM_DUMP_DATA_CPU_CTX'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_INST_TLB + i] = 'MSM_DUMP_DATA_L1_INST_TLB'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_DATA_TLB + i] = 'MSM_DUMP_DATA_L1_DATA_TLB'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_INST_CACHE + i] = 'MSM_DUMP_DATA_L1_INST_CACHE'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_DATA_CACHE + i] = 'MSM_DUMP_DATA_L1_DATA_CACHE'
                self.dump_data_id_lookup_table[
                    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'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_SCANDUMP_PER_CPU + i] = 'MSM_DUMP_DATA_SCANDUMP_PER_CPU'

        for i in range(0, 4):
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_LLC_CACHE + i] = 'MSM_DUMP_DATA_LLC_CACHE'

        self.dump_data_id_lookup_table[
            client.MSM_DUMP_DATA_FCMDUMP] = 'MSM_DUMP_DATA_FCMDUMP'
        # 0x100 - tmc-etr registers and 0x101 - for tmc-etf registers
        self.dump_data_id_lookup_table[
            client.MSM_DUMP_DATA_TMC_ETR_REG + 1] = 'MSM_DUMP_DATA_TMC_ETR_REG'
        self.dump_data_id_lookup_table[
            client.MSM_DUMP_DATA_LOG_BUF] = 'MSM_DUMP_DATA_LOG_BUF'
        self.dump_data_id_lookup_table[
            client.MSM_DUMP_DATA_LOG_BUF_FIRST_IDX] = 'MSM_DUMP_DATA_LOG_BUF_FIRST_IDX'
	for i in range(0, cpus):
		self.dump_data_id_lookup_table[
		    client.MSM_DUMP_DATA_L2_TLB + i] = 'MSM_DUMP_DATA_L2_TLB'

        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')

            """
            Some multi-guest hypervisor systems override the imem location
            with a table for a crashed guest. So the value from IMEM may
            not match the value saved in the linux variable 'memdump'.
            """
            table_phys = ram_dump.read_word(
                ram_dump.board.imem_start + IMEM_OFFSET_MEM_DUMP_TABLE,
                virtual = False)
            root_table = self.validateMsmDumpTable(ram_dump, "IMEM", table_phys)

            if root_table is None:
                table_phys = ram_dump.read_structure_field(
                    'memdump', 'struct msm_memory_dump', 'table_phys')
                root_table = self.validateMsmDumpTable(ram_dump, "RAM", table_phys)

            if root_table is None:
                return

            print_out_str('\nDebug image version: {0}.{1} Number of table entries {2}'.format(
                root_table.version >> 20, root_table.version & 0xFFFFF, root_table.num_entries))
            print_out_str('--------')

            for i in range(0, root_table.num_entries):
                this_entry = root_table.phys_addr + dump_table_entry_offset + \
                    i * dump_entry_size
                entry_id = ram_dump.read_u32(this_entry + dump_entry_id_offset, virtual = False)
                entry_type = ram_dump.read_u32(this_entry + dump_entry_type_offset, virtual = False)
                entry_addr = ram_dump.read_word(this_entry + dump_entry_addr_offset, virtual = False)

                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')
                    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_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_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)

        self.parse_dcc(ram_dump)
        if ram_dump.sysreg:
            self.parse_sysreg(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)
예제 #6
0
 def __init__(self):
     self.qdss = QDSSDump()
     self.dump_type_lookup_table = []
     self.dump_table_id_lookup_table = []
     self.dump_data_id_lookup_table = []
예제 #7
0
class DebugImage(RamParser):
    def __init__(self, *args):
        super(DebugImage, self).__init__(*args)
        self.qdss = QDSSDump()
        self.name_lookup_table = []

    def parse_cpu_ctx(self, start, end, tag):
        print_out_str('Parsing CPU context start {0:x} end {1:x}'.format(
            start, end))
        # For historical reasons, we can't rely on the magic number to indicate if there
        # is context dumped. Check the magic number here instead
        magic = self.ramdump.read_word(start, False)
        if magic is None:
            print_out_str(
                "!!! Address {0:x} is bogus! Can't parse!".format(start))
            return

        if magic != 0x44434151:
            print_out_str(
                "!!! Magic {0:x} doesn't match! No context was dumped!".format(
                    magic))
            return

        regs = TZRegDump(self.ramdump)
        regs.init_regs(start)
        for i in range(regs.ncores):
            regs.dump_core_pc(i)
        regs.dump_all_regs()

    def parse_l2_cache(self, start, end, tag):
        print_out_str('Parsing L2 cache context start {0:x} end {1:x}'.format(
            start, end))
        magic = self.ramdump.read_word(start, False)
        if magic is None:
            print_out_str(
                "!!! Address {0:x} is bogus! Can't parse!".format(start))
            return

        if magic != 0xcac1ecac:
            print_out_str(
                "!!! Magic {0:x} doesn't match! No cache was dumped!".format(
                    magic))
            return

        parse_cache_dump(self.ramdump, start)

    def parse_l1_cache(self, start, end, tag):
        print_out_str('Parsing L1 cache context start {0:x} end {1:x}'.format(
            start, end))
        magic = self.ramdump.read_word(start, False)
        if magic is None:
            print_out_str(
                "!!! Address {0:x} is bogus! Can't parse!".format(start))
            return

        if magic != 0x314C4151:
            print_out_str(
                "!!! Magic {0:X} doesn't match! No cache was dumped!".format(
                    magic))
            return
        print_out_str('Saving L1 cache')
        save_l1_dump(self.ramdump, start, end - start)

    def parse_ocmem(self, start, end, tag):
        print_out_str(
            '[!!!] Parsing not implemented yet start {0:x} end {1:x}'.format(
                start, end))

    def parse_qdss_common(self, start, end, tag):
        print_out_str('Parsing {0} context start {1:x} end {2:x}'.format(
            tag, start, end))
        magic = self.ramdump.read_word(start, False)
        if magic is None:
            print_out_str(
                "!!! Address {0:x} is bogus! Can't parse!".format(start))
            return

        if magic != QDSS_MAGIC:
            print_out_str(
                "!!! Magic {0:X} doesn't match! Tracing was not dumped!".
                format(magic))
            return

        setattr(self.qdss, tag_to_field_name[tag], start + 4096)

    def parse_dump(self):
        out_dir = self.ramdump.outdir
        self.name_lookup_table = self.ramdump.gdbmi.get_enum_lookup_table(
            'dump_client_type', 32)
        dump_table_ptr_offset = self.ramdump.field_offset(
            'struct msm_memory_dump', 'dump_table_ptr')
        version_offset = self.ramdump.field_offset('struct msm_dump_table',
                                                   'version')
        num_entries_offset = self.ramdump.field_offset('struct msm_dump_table',
                                                       'num_entries')
        client_entries_offset = self.ramdump.field_offset(
            'struct msm_dump_table', 'client_entries')
        id_offset = self.ramdump.field_offset('struct msm_client_dump', 'id')
        start_addr_offset = self.ramdump.field_offset('struct msm_client_dump',
                                                      'start_addr')
        end_addr_offset = self.ramdump.field_offset('struct msm_client_dump',
                                                    'end_addr')
        client_dump_entry_size = self.ramdump.sizeof('struct msm_client_dump')

        mem_dump_data = self.ramdump.addr_lookup('mem_dump_data')

        dump_table = self.ramdump.read_word(mem_dump_data +
                                            dump_table_ptr_offset)

        version = self.ramdump.read_word(dump_table + version_offset)
        if version is None:
            print_out_str('Version is bogus! Can\'t parse debug image')
            return
        num_entries = self.ramdump.read_word(dump_table + num_entries_offset)
        if num_entries is None or num_entries > 100:
            print_out_str('num_entries is bogus! Can\'t parse debug image')
            return

        print_out_str(
            '\nDebug image version: {0}.{1} Number of entries {2}'.format(
                version >> 20, version & 0xFFFFF, num_entries))
        print_out_str('--------')

        for i in range(0, num_entries):
            this_client = dump_table + client_entries_offset + \
                i * client_dump_entry_size
            client_id = self.ramdump.read_word(this_client + id_offset)
            client_start = self.ramdump.read_word(this_client +
                                                  start_addr_offset)
            client_end = self.ramdump.read_word(this_client + end_addr_offset)

            if client_id < 0 or client_id > len(self.name_lookup_table):
                print_out_str(
                    '!!! Invalid client id found {0:x}'.format(client_id))
                continue

            client_name = self.name_lookup_table[client_id]

            if client_name not in print_table:
                print_out_str(
                    '!!! {0} Does not have an associated function. The parser needs to be updated!'
                    .format(client_name))
            else:
                print_out_str(
                    'Parsing debug information for {0}'.format(client_name))
                func = print_table[client_name]
                getattr(DebugImage, func)(self, client_start, client_end,
                                          client_name)
            print_out_str('--------')

        self.qdss.dump_all(self.ramdump)

    def parse(self):
        # use the mem_dump_data variable to detect if debug image feature was compiled in,
        # and memdump data variable for debug image v2 feature, rather than relying on
        # configuration option.
        if self.ramdump.addr_lookup('mem_dump_data'):
            self.parse_dump()
        elif self.ramdump.addr_lookup('memdump'):
            regs = DebugImage_v2()
            regs.parse_dump_v2(self.ramdump)
        else:
            print_out_str(
                '!!! Debug image was not enabled. No debug dump will be provided'
            )
            return
예제 #8
0
class DebugImage_v2():
    def __init__(self):
        self.qdss = QDSSDump()
        self.dump_type_lookup_table = []
        self.dump_table_id_lookup_table = []
        self.dump_data_id_lookup_table = []

    def parse_cpu_ctx(self, version, start, end, client_id, ram_dump):
        core = client_id - client.MSM_DUMP_DATA_CPU_CTX
        if ram_dump.Is_Dakota():
            core = 0

        print_out_str('Parsing CPU{2} context start {0:x} end {1:x}'.format(
            start, end, core))

        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
        regs.dump_core_pc(ram_dump)
        regs.dump_all_regs(ram_dump)

    def parse_qdss_common(self, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str('Parsing {0} context start {1:x} end {2:x}'.format(
            client_name, start, end))

        if client_id == client.MSM_DUMP_DATA_TMC_ETF_REG:
            setattr(self.qdss, 'tmc_etf_start', start)
        else:
            setattr(self.qdss, qdss_tag_to_field_name[client_name], start)

    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')
        filter_type_offset = ram_dump.field_offset('struct ftrace_event_field',
                                                   'filter_type')
        field_offset = ram_dump.field_offset('struct ftrace_event_field',
                                             'offset')
        size_offset = ram_dump.field_offset('struct ftrace_event_field',
                                            'size')
        signed_offset = ram_dump.field_offset('struct ftrace_event_field',
                                              'is_signed')

        name = ram_dump.read_word(common_list + name_offset)
        field_name = ram_dump.read_cstring(name, 256)
        type_name = ram_dump.read_word(common_list + type_offset)
        type_str = ram_dump.read_cstring(type_name, 256)
        offset = ram_dump.read_u32(common_list + field_offset)
        size = ram_dump.read_u32(common_list + size_offset)
        signed = ram_dump.read_u32(common_list + signed_offset)

        if re.match('(.*)\[(.*)',
                    type_str) and not (re.match('__data_loc', type_str)):
            s = re.split('\[', type_str)
            s[1] = '[' + s[1]
            self.formats_out.write(
                "\tfield:{0} {1}{2};\toffset:{3};\tsize:{4};\tsigned:{5};\n".
                format(s[0], field_name, s[1], offset, size, signed))
        else:
            self.formats_out.write(
                "\tfield:{0} {1};\toffset:{2};\tsize:{3};\tsigned:{4};\n".
                format(type_str, field_name, offset, size, signed))

    def ftrace_events_func(self, ftrace_list, ram_dump):
        name_offset = ram_dump.field_offset('struct ftrace_event_call', 'name')
        event_offset = ram_dump.field_offset('struct ftrace_event_call',
                                             'event')
        fmt_offset = ram_dump.field_offset('struct ftrace_event_call',
                                           'print_fmt')
        class_offset = ram_dump.field_offset('struct ftrace_event_call',
                                             'class')
        type_offset = ram_dump.field_offset('struct trace_event', 'type')
        fields_offset = ram_dump.field_offset('struct ftrace_event_class',
                                              'fields')
        common_field_list = ram_dump.addr_lookup('ftrace_common_fields')
        field_next_offset = ram_dump.field_offset('struct ftrace_event_field',
                                                  'link')

        name = ram_dump.read_word(ftrace_list + name_offset)
        name_str = ram_dump.read_cstring(name, 512)
        event_id = ram_dump.read_word(ftrace_list + event_offset + type_offset)
        fmt = ram_dump.read_word(ftrace_list + fmt_offset)
        fmt_str = ram_dump.read_cstring(fmt, 2048)

        self.formats_out.write("name: {0}\n".format(name_str))
        self.formats_out.write("ID: {0}\n".format(event_id))
        self.formats_out.write("format:\n")

        list_walker = llist.ListWalker(ram_dump, common_field_list,
                                       field_next_offset)
        list_walker.walk_prev(common_field_list, self.ftrace_field_func,
                              ram_dump)
        self.formats_out.write("\n")

        event_class = ram_dump.read_word(ftrace_list + class_offset)
        field_list = event_class + fields_offset
        list_walker = llist.ListWalker(ram_dump, field_list, field_next_offset)
        list_walker.walk_prev(field_list, self.ftrace_field_func, ram_dump)
        self.formats_out.write("\n")
        self.formats_out.write("print fmt: {0}\n".format(fmt_str))

    def collect_ftrace_format(self, ram_dump):
        formats = os.path.join('qtf', 'map_files', 'formats.txt')
        formats_out = ram_dump.open_file(formats)
        self.formats_out = formats_out

        ftrace_events_list = ram_dump.addr_lookup('ftrace_events')
        next_offset = ram_dump.field_offset('struct ftrace_event_call', 'list')
        list_walker = llist.ListWalker(ram_dump, ftrace_events_list,
                                       next_offset)
        list_walker.walk_prev(ftrace_events_list, self.ftrace_events_func,
                              ram_dump)

        self.formats_out.close

    def parse_qtf(self, ram_dump):
        out_dir = ram_dump.outdir
        if platform.system() != 'Windows':
            return

        qtf_path = ram_dump.qtf_path
        if qtf_path is None:
            try:
                import local_settings
                try:
                    qtf_path = local_settings.qtf_path
                except AttributeError as e:
                    print_out_str(
                        "attribute qtf_path in local_settings.py looks bogus. Please see README.txt"
                    )
                    print_out_str("Full message: %s" % e.message)
                    return
            except ImportError:
                print_out_str("missing qtf_path local_settings.")
                print_out_str(
                    "Please see the README for instructions on setting up local_settings.py"
                )
                return

        if qtf_path is None:
            print_out_str("!!! Incorrect path for qtf specified.")
            print_out_str(
                "!!! Please see the README for instructions on setting up local_settings.py"
            )
            return

        if not os.path.exists(qtf_path):
            print_out_str(
                "!!! qtf_path {0} does not exist! Check your settings!".format(
                    qtf_path))
            return

        if not os.access(qtf_path, os.X_OK):
            print_out_str(
                "!!! No execute permissions on qtf path {0}".format(qtf_path))
            return

        if os.path.getsize(os.path.join(out_dir, 'tmc-etf.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etf.bin')
        elif os.path.getsize(os.path.join(out_dir, 'tmc-etr.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etr.bin')
        else:
            return

        port = 12345
        qtf_dir = os.path.join(out_dir, 'qtf')
        workspace = os.path.join(qtf_dir, 'qtf.workspace')
        qtf_out = os.path.join(out_dir, 'qtf.txt')
        chipset = 'msm' + str(ram_dump.hw_id)
        hlos = 'LA'

        p = subprocess.Popen([qtf_path, '-s', '{0}'.format(port)])
        subprocess.call('{0} -c {1} new workspace {2} {3} {4}'.format(
            qtf_path, port, qtf_dir, chipset, hlos))

        self.collect_ftrace_format(ram_dump)

        subprocess.call('{0} -c {1} open workspace {2}'.format(
            qtf_path, port, workspace))
        subprocess.call('{0} -c {1} open bin {2}'.format(
            qtf_path, port, trace_file))
        subprocess.call('{0} -c {1} stream trace table {2}'.format(
            qtf_path, port, qtf_out))
        subprocess.call('{0} -c {1} exit'.format(qtf_path, port))
        p.communicate('quit')

    def parse_dump_v2(self, ram_dump):
        self.dump_type_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_type', 2)
        self.dump_table_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_table_ids', 0x110)
        self.dump_data_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_data_ids', 0x112)
        cpu_present_bits = ram_dump.read_word('cpu_present_bits')
        cpus = bin(cpu_present_bits).count('1')
        # per cpu entries
        for i in range(1, cpus):

            self.dump_data_id_lookup_table[client.MSM_DUMP_DATA_CPU_CTX +
                                           i] = 'MSM_DUMP_DATA_CPU_CTX'
            self.dump_data_id_lookup_table[client.MSM_DUMP_DATA_L1_INST_CACHE +
                                           i] = 'MSM_DUMP_DATA_L1_INST_CACHE'
            self.dump_data_id_lookup_table[client.MSM_DUMP_DATA_L1_DATA_CACHE +
                                           i] = 'MSM_DUMP_DATA_L1_DATA_CACHE'
            self.dump_data_id_lookup_table[client.MSM_DUMP_DATA_ETM_REG +
                                           i] = 'MSM_DUMP_DATA_ETM_REG'
        # 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'
        self.dump_data_id_lookup_table[
            client.MSM_DUMP_DATA_LOG_BUF] = 'MSM_DUMP_DATA_LOG_BUF'
        self.dump_data_id_lookup_table[
            client.
            MSM_DUMP_DATA_LOG_BUF_FIRST_IDX] = 'MSM_DUMP_DATA_LOG_BUF_FIRST_IDX'
        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.addr_lookup('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'
                )
                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))

            for j in range(0, table_num_entries):
                print_out_str('--------')
                client_entry = entry_addr + dump_table_entry_offset + j * dump_entry_size
                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_id < 0 or client_id > len(
                        self.dump_data_id_lookup_table):
                    print_out_str(
                        '!!! Invalid dump client id found {0:x}'.format(
                            client_id))
                    continue

                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_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)

                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. The parser needs to be updated!'
                        .format(client_name))
                else:
                    print_out_str(
                        'Parsing debug information for {0}. Version: {1} Magic: {2:x}'
                        .format(client_name, dump_data_version,
                                dump_data_magic))

                    if dump_data_magic is None:
                        print_out_str(
                            "!!! Address {0:x} is bogus! Can't parse!".format(
                                start))
                        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

                    func = client_table[client_name]
                    getattr(DebugImage_v2,
                            func)(self, dump_data_addr,
                                  dump_data_addr + dump_data_len, client_id,
                                  ram_dump)

            self.qdss.dump_all(ram_dump)
            if ram_dump.qtf:
                self.parse_qtf(ram_dump)
예제 #9
0
class DebugImage_v2():
    def __init__(self):
        self.qdss = QDSSDump()
        self.dump_type_lookup_table = []
        self.dump_table_id_lookup_table = []
        self.dump_data_id_lookup_table = []

    def parse_cpu_ctx(self, version, start, end, client_id, ram_dump):
        core = client_id - client.MSM_DUMP_DATA_CPU_CTX

        print_out_str('Parsing CPU{2} context start {0:x} end {1:x}'.format(
            start, end, core))

        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
        regs.dump_core_pc(ram_dump)
        regs.dump_all_regs(ram_dump)

    def parse_pmic(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str('Parsing {0} context start {1:x} end {2:x}'.format(
            client_name, start, end))

        regs = PmicRegDump(start, end)
        if regs.parse_all_regs(ram_dump) is False:
            print_out_str('!!! Could not get registers from PMIC dump')
            return

        regs.dump_all_regs(ram_dump)

    def parse_dcc_reg(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str('Parsing {0} context start {1:x} end {2:x}'.format(
            client_name, start, end))

        regs = DccRegDump(start, end)
        if regs.parse_all_regs(ram_dump) is False:
            print_out_str('!!! Could not get registers from DCC register dump')
            return

        regs.dump_all_regs(ram_dump)
        return

    def parse_dcc_sram(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str('Parsing {0} context start {1:x} end {2:x}'.format(
            client_name, start, end))

        regs = DccSramDump(start, end)
        if regs.dump_sram_img(ram_dump) is False:
            print_out_str('!!! Could not dump SRAM')
        else:
            ram_dump.dcc = True
        return

    def parse_vsens(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str('Parsing {0} context start {1:x} end {2:x}'.format(
            client_name, start, end))

        regs = VsensData()
        if regs.init_dump_regs(start, end, ram_dump) is False:
            print_out_str('!!! Could not get registers from Vsens Dump')
            return
        regs.print_vsens_regs(ram_dump)

    def parse_qdss_common(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str('Parsing {0} context start {1:x} end {2:x}'.format(
            client_name, start, end))

        if client_id == client.MSM_DUMP_DATA_TMC_ETF_REG:
            setattr(self.qdss, 'tmc_etf_start', start)
        else:
            setattr(self.qdss, qdss_tag_to_field_name[client_name], start)

    def parse_cache_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_cache_type(ramdump.hw_id, client_id, version)
        try:
            cache_type.parse(start, end, ramdump, outfile)
        except NotImplementedError:
            print_out_str('Cache 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')
        filter_type_offset = ram_dump.field_offset('struct ftrace_event_field',
                                                   'filter_type')
        field_offset = ram_dump.field_offset('struct ftrace_event_field',
                                             'offset')
        size_offset = ram_dump.field_offset('struct ftrace_event_field',
                                            'size')
        signed_offset = ram_dump.field_offset('struct ftrace_event_field',
                                              'is_signed')

        name = ram_dump.read_word(common_list + name_offset)
        field_name = ram_dump.read_cstring(name, 256)
        type_name = ram_dump.read_word(common_list + type_offset)
        type_str = ram_dump.read_cstring(type_name, 256)
        offset = ram_dump.read_u32(common_list + field_offset)
        size = ram_dump.read_u32(common_list + size_offset)
        signed = ram_dump.read_u32(common_list + signed_offset)

        if re.match('(.*)\[(.*)',
                    type_str) and not (re.match('__data_loc', type_str)):
            s = re.split('\[', type_str)
            s[1] = '[' + s[1]
            self.formats_out.write(
                "\tfield:{0} {1}{2};\toffset:{3};\tsize:{4};\tsigned:{5};\n".
                format(s[0], field_name, s[1], offset, size, signed))
        else:
            self.formats_out.write(
                "\tfield:{0} {1};\toffset:{2};\tsize:{3};\tsigned:{4};\n".
                format(type_str, field_name, offset, size, signed))

    def ftrace_events_func(self, ftrace_list, ram_dump):
        event_offset = ram_dump.field_offset('struct ftrace_event_call',
                                             'event')
        fmt_offset = ram_dump.field_offset('struct ftrace_event_call',
                                           'print_fmt')
        class_offset = ram_dump.field_offset('struct ftrace_event_call',
                                             'class')
        flags_offset = ram_dump.field_offset('struct ftrace_event_call',
                                             'flags')
        flags = ram_dump.read_word(ftrace_list + flags_offset)

        if (ram_dump.kernel_version >= (3, 18)
                and (flags & TRACE_EVENT_FL_TRACEPOINT)):
            tp_offset = ram_dump.field_offset('struct ftrace_event_call', 'tp')
            tp_name_offset = ram_dump.field_offset('struct tracepoint', 'name')
            tp = ram_dump.read_word(ftrace_list + tp_offset)
            name = ram_dump.read_word(tp + tp_name_offset)
        else:
            name_offset = ram_dump.field_offset('struct ftrace_event_call',
                                                'name')
            name = ram_dump.read_word(ftrace_list + name_offset)

        type_offset = ram_dump.field_offset('struct trace_event', 'type')
        fields_offset = ram_dump.field_offset('struct ftrace_event_class',
                                              'fields')
        common_field_list = ram_dump.address_of('ftrace_common_fields')
        field_next_offset = ram_dump.field_offset('struct ftrace_event_field',
                                                  'link')

        name_str = ram_dump.read_cstring(name, 512)
        event_id = ram_dump.read_word(ftrace_list + event_offset + type_offset)
        fmt = ram_dump.read_word(ftrace_list + fmt_offset)
        fmt_str = ram_dump.read_cstring(fmt, 2048)

        self.formats_out.write("name: {0}\n".format(name_str))
        self.formats_out.write("ID: {0}\n".format(event_id))
        self.formats_out.write("format:\n")

        list_walker = llist.ListWalker(ram_dump, common_field_list,
                                       field_next_offset)
        list_walker.walk_prev(common_field_list, self.ftrace_field_func,
                              ram_dump)
        self.formats_out.write("\n")

        event_class = ram_dump.read_word(ftrace_list + class_offset)
        field_list = event_class + fields_offset
        list_walker = llist.ListWalker(ram_dump, field_list, field_next_offset)
        list_walker.walk_prev(field_list, self.ftrace_field_func, ram_dump)
        self.formats_out.write("\n")
        self.formats_out.write("print fmt: {0}\n".format(fmt_str))

    def collect_ftrace_format(self, ram_dump):
        formats = os.path.join('qtf', 'map_files', 'formats.txt')
        formats_out = ram_dump.open_file(formats)
        self.formats_out = formats_out

        ftrace_events_list = ram_dump.address_of('ftrace_events')
        next_offset = ram_dump.field_offset('struct ftrace_event_call', 'list')
        list_walker = llist.ListWalker(ram_dump, ftrace_events_list,
                                       next_offset)
        list_walker.walk_prev(ftrace_events_list, self.ftrace_events_func,
                              ram_dump)

        self.formats_out.close

    def parse_qtf(self, ram_dump):
        out_dir = ram_dump.outdir
        if platform.system() != 'Windows':
            return

        qtf_path = ram_dump.qtf_path
        if qtf_path is None:
            try:
                import local_settings
                try:
                    qtf_path = local_settings.qtf_path
                except AttributeError as e:
                    print_out_str(
                        "attribute qtf_path in local_settings.py looks bogus. Please see README.txt"
                    )
                    print_out_str("Full message: %s" % e.message)
                    return
            except ImportError:
                print_out_str("missing qtf_path local_settings.")
                print_out_str(
                    "Please see the README for instructions on setting up local_settings.py"
                )
                return

        if qtf_path is None:
            print_out_str("!!! Incorrect path for qtf specified.")
            print_out_str(
                "!!! Please see the README for instructions on setting up local_settings.py"
            )
            return

        if not os.path.exists(qtf_path):
            print_out_str(
                "!!! qtf_path {0} does not exist! Check your settings!".format(
                    qtf_path))
            return

        if not os.access(qtf_path, os.X_OK):
            print_out_str(
                "!!! No execute permissions on qtf path {0}".format(qtf_path))
            return

        if os.path.getsize(os.path.join(out_dir, 'tmc-etf.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etf.bin')
        elif os.path.getsize(os.path.join(out_dir, 'tmc-etr.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etr.bin')
        else:
            return

        port = None
        server_proc = None
        qtf_success = False
        max_tries = 3
        qtf_dir = os.path.join(out_dir, 'qtf')
        workspace = os.path.join(qtf_dir, 'qtf.workspace')
        qtf_out = os.path.join(out_dir, 'qtf.txt')
        chipset = 'msm' + str(ram_dump.hw_id)
        hlos = 'LA'

        # Resolve any port collisions with other running qtf_server instances
        for tries in range(max_tries):
            port = random.randint(12000, 13000)
            server_proc = subprocess.Popen(
                [qtf_path, '-s', '{0}'.format(port)], stderr=subprocess.PIPE)
            time.sleep(1)
            server_proc.poll()
            if server_proc.returncode == 1:
                server_proc.terminate()
                continue
            else:
                qtf_success = True
                break
        if not qtf_success:
            server_proc.terminate()
            print_out_str('!!! Could not open a QTF server instance with a '
                          'unique port (last port tried: '
                          '{0})'.format(str(port)))
            print_out_str('!!! Please kill all currently running qtf_server '
                          'processes and try again')
            return

        subprocess.call('{0} -c {1} new workspace {2} {3} {4}'.format(
            qtf_path, port, qtf_dir, chipset, hlos))

        self.collect_ftrace_format(ram_dump)

        subprocess.call('{0} -c {1} open workspace {2}'.format(
            qtf_path, port, workspace))
        subprocess.call('{0} -c {1} open bin {2}'.format(
            qtf_path, port, trace_file))
        subprocess.call('{0} -c {1} stream trace table {2}'.format(
            qtf_path, port, qtf_out))
        subprocess.call('{0} -c {1} close'.format(qtf_path, port))
        subprocess.call('{0} -c {1} exit'.format(qtf_path, port))
        server_proc.communicate('quit')

    def parse_dcc(self, ram_dump):
        out_dir = ram_dump.outdir

        dcc_parser_path = os.path.join(os.path.dirname(__file__), '..',
                                       'dcc_parser', 'dcc_parser.py')

        if dcc_parser_path is None:
            print_out_str("!!! Incorrect path for DCC specified.")
            return

        if not os.path.exists(dcc_parser_path):
            print_out_str(
                "!!! dcc_parser_path {0} does not exist! Check your settings!".
                format(dcc_parser_path))
            return

        if os.path.getsize(os.path.join(out_dir, 'sram.bin')) > 0:
            sram_file = os.path.join(out_dir, 'sram.bin')
        else:
            return

        p = subprocess.Popen([
            sys.executable, dcc_parser_path, '-s', sram_file, '--out-dir',
            out_dir
        ],
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)

        print_out_str('--------')
        print_out_str(p.communicate()[0])

    def parse_dump_v2(self, ram_dump):
        self.dump_type_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_type', 2)
        self.dump_table_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_table_ids', MAX_NUM_ENTRIES)
        self.dump_data_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_data_ids', MAX_NUM_ENTRIES)
        cpu_present_bits = ram_dump.read_word('cpu_present_bits')
        cpus = bin(cpu_present_bits).count('1')
        # per cpu entries
        for i in range(1, cpus):

            self.dump_data_id_lookup_table[client.MSM_DUMP_DATA_CPU_CTX +
                                           i] = 'MSM_DUMP_DATA_CPU_CTX'
            self.dump_data_id_lookup_table[client.MSM_DUMP_DATA_L1_INST_TLB +
                                           i] = 'MSM_DUMP_DATA_L1_INST_TLB'
            self.dump_data_id_lookup_table[client.MSM_DUMP_DATA_L1_DATA_TLB +
                                           i] = 'MSM_DUMP_DATA_L1_DATA_TLB'
            self.dump_data_id_lookup_table[client.MSM_DUMP_DATA_L1_INST_CACHE +
                                           i] = 'MSM_DUMP_DATA_L1_INST_CACHE'
            self.dump_data_id_lookup_table[client.MSM_DUMP_DATA_L1_DATA_CACHE +
                                           i] = 'MSM_DUMP_DATA_L1_DATA_CACHE'
            self.dump_data_id_lookup_table[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'
        # 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'
        self.dump_data_id_lookup_table[
            client.MSM_DUMP_DATA_LOG_BUF] = 'MSM_DUMP_DATA_LOG_BUF'
        self.dump_data_id_lookup_table[
            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'
                )
                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))

            for j in range(0, table_num_entries):
                print_out_str('--------')
                client_entry = entry_addr + dump_table_entry_offset + j * dump_entry_size
                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_id < 0 or client_id > len(
                        self.dump_data_id_lookup_table):
                    print_out_str(
                        '!!! Invalid dump client id found {0:x}'.format(
                            client_id))
                    continue

                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)

                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. The parser needs to be updated!'
                        .format(client_name))
                else:
                    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(
                                start))
                        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

                    func = client_table[client_name]
                    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)
예제 #10
0
 def __init__(self, *args):
     super(DebugImage, self).__init__(*args)
     self.qdss = QDSSDump()
     self.name_lookup_table = []
예제 #11
0
class DebugImage(RamParser):

    def __init__(self, *args):
        super(DebugImage, self).__init__(*args)
        self.qdss = QDSSDump()
        self.name_lookup_table = []

    def parse_cpu_ctx(self, start, end, tag):
        print_out_str(
            'Parsing CPU context start {0:x} end {1:x}'.format(start, end))
        # For historical reasons, we can't rely on the magic number to indicate if there
        # is context dumped. Check the magic number here instead
        magic = self.ramdump.read_word(start, False)
        if magic is None:
            print_out_str(
                "!!! Address {0:x} is bogus! Can't parse!".format(start))
            return

        if magic != 0x44434151:
            print_out_str(
                "!!! Magic {0:x} doesn't match! No context was dumped!".format(magic))
            return

        regs = TZRegDump(self.ramdump)
        regs.init_regs(start)
        for i in range(regs.ncores):
            regs.dump_core_pc(i)
        regs.dump_all_regs()

    def parse_l2_cache(self, start, end, tag):
        print_out_str(
            'Parsing L2 cache context start {0:x} end {1:x}'.format(start, end))
        magic = self.ramdump.read_word(start, False)
        if magic is None:
            print_out_str(
                "!!! Address {0:x} is bogus! Can't parse!".format(start))
            return

        if magic != 0xcac1ecac:
            print_out_str(
                "!!! Magic {0:x} doesn't match! No cache was dumped!".format(magic))
            return

        parse_cache_dump(self.ramdump, start)

    def parse_l1_cache(self, start, end, tag):
        print_out_str(
            'Parsing L1 cache context start {0:x} end {1:x}'.format(start, end))
        magic = self.ramdump.read_word(start, False)
        if magic is None:
            print_out_str(
                "!!! Address {0:x} is bogus! Can't parse!".format(start))
            return

        if magic != 0x314C4151:
            print_out_str(
                "!!! Magic {0:X} doesn't match! No cache was dumped!".format(magic))
            return
        print_out_str('Saving L1 cache')
        save_l1_dump(self.ramdump, start, end - start)

    def parse_ocmem(self, start, end, tag):
        print_out_str(
            '[!!!] Parsing not implemented yet start {0:x} end {1:x}'.format(start, end))

    def parse_qdss_common(self, start, end, tag):
        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(tag, start, end))
        magic = self.ramdump.read_word(start, False)
        if magic is None:
            print_out_str(
                "!!! Address {0:x} is bogus! Can't parse!".format(start))
            return

        if magic != QDSS_MAGIC:
            print_out_str(
                "!!! Magic {0:X} doesn't match! Tracing was not dumped!".format(magic))
            return

        setattr(self.qdss, tag_to_field_name[tag], start + 4096)

    def parse_dump(self):
        out_dir = self.ramdump.outdir
        self.name_lookup_table = self.ramdump.gdbmi.get_enum_lookup_table(
            'dump_client_type', 32)
        dump_table_ptr_offset = self.ramdump.field_offset(
            'struct msm_memory_dump', 'dump_table_ptr')
        version_offset = self.ramdump.field_offset(
            'struct msm_dump_table', 'version')
        num_entries_offset = self.ramdump.field_offset(
            'struct msm_dump_table', 'num_entries')
        client_entries_offset = self.ramdump.field_offset(
            'struct msm_dump_table', 'client_entries')
        id_offset = self.ramdump.field_offset('struct msm_client_dump', 'id')
        start_addr_offset = self.ramdump.field_offset(
            'struct msm_client_dump', 'start_addr')
        end_addr_offset = self.ramdump.field_offset(
            'struct msm_client_dump', 'end_addr')
        client_dump_entry_size = self.ramdump.sizeof('struct msm_client_dump')

        mem_dump_data = self.ramdump.address_of('mem_dump_data')

        dump_table = self.ramdump.read_word(
            mem_dump_data + dump_table_ptr_offset)

        version = self.ramdump.read_word(dump_table + version_offset)
        if version is None:
            print_out_str('Version is bogus! Can\'t parse debug image')
            return
        num_entries = self.ramdump.read_word(dump_table + num_entries_offset)
        if num_entries is None or num_entries > 100:
            print_out_str('num_entries is bogus! Can\'t parse debug image')
            return

        print_out_str('\nDebug image version: {0}.{1} Number of entries {2}'.format(
            version >> 20, version & 0xFFFFF, num_entries))
        print_out_str('--------')

        for i in range(0, num_entries):
            this_client = dump_table + client_entries_offset + \
                i * client_dump_entry_size
            client_id = self.ramdump.read_word(this_client + id_offset)
            client_start = self.ramdump.read_word(
                this_client + start_addr_offset)
            client_end = self.ramdump.read_word(this_client + end_addr_offset)

            if client_id < 0 or client_id > len(self.name_lookup_table):
                print_out_str(
                    '!!! Invalid client id found {0:x}'.format(client_id))
                continue

            client_name = self.name_lookup_table[client_id]

            if client_name not in print_table:
                print_out_str(
                    '!!! {0} Does not have an associated function. The parser needs to be updated!'.format(client_name))
            else:
                print_out_str(
                    'Parsing debug information for {0}'.format(client_name))
                func = print_table[client_name]
                getattr(DebugImage, func)(self, client_start,
                                          client_end, client_name)
            print_out_str('--------')

        self.qdss.dump_all(self.ramdump)

    def parse(self):
        # use the mem_dump_data variable to detect if debug image feature was compiled in,
        # and memdump data variable for debug image v2 feature, rather than relying on
        # configuration option.
        if self.ramdump.address_of('mem_dump_data'):
            self.parse_dump()
        elif self.ramdump.address_of('memdump'):
            regs = DebugImage_v2()
            regs.parse_dump_v2(self.ramdump)
        else:
            print_out_str(
                '!!! Debug image was not enabled. No debug dump will be provided')
            return
예제 #12
0
class DebugImage_v2():

    def __init__(self):
        self.qdss = QDSSDump()
        self.dump_type_lookup_table = []
        self.dump_table_id_lookup_table = []
        self.dump_data_id_lookup_table  = []

    def parse_cpu_ctx(self, version, start, end, client_id, ram_dump):
        core = client_id - client.MSM_DUMP_DATA_CPU_CTX

        print_out_str(
            'Parsing CPU{2} context start {0:x} end {1:x}'.format(start, end, core))

        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
        regs.dump_core_pc(ram_dump)
        regs.dump_all_regs(ram_dump)

    def parse_pmic(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        regs = PmicRegDump(start, end)
        if regs.parse_all_regs(ram_dump) is False:
            print_out_str('!!! Could not get registers from PMIC dump')
            return

        regs.dump_all_regs(ram_dump)

    def parse_dcc_reg(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        regs = DccRegDump(start, end)
        if regs.parse_all_regs(ram_dump) is False:
            print_out_str('!!! Could not get registers from DCC register dump')
            return

        regs.dump_all_regs(ram_dump)
        return

    def parse_dcc_sram(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        regs = DccSramDump(start, end)
        if regs.dump_sram_img(ram_dump) is False:
            print_out_str('!!! Could not dump SRAM')
        else:
            ram_dump.dcc = True
        return

    def parse_vsens(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        regs = VsensData()
        if regs.init_dump_regs(start, end, ram_dump) is False:
            print_out_str('!!! Could not get registers from Vsens Dump')
            return
        regs.print_vsens_regs(ram_dump)

    def parse_qdss_common(self, version, start, end, client_id, ram_dump):
        client_name = self.dump_data_id_lookup_table[client_id]

        print_out_str(
            'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end))

        if client_id == client.MSM_DUMP_DATA_TMC_ETF_REG:
            setattr(self.qdss, 'tmc_etf_start', start)
        else:
            setattr(self.qdss, qdss_tag_to_field_name[client_name], start)

    def parse_cache_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_cache_type(ramdump.hw_id, client_id, version)
        try:
            cache_type.parse(start, end, ramdump, outfile)
        except NotImplementedError:
            print_out_str('Cache 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')
        filter_type_offset = ram_dump.field_offset('struct ftrace_event_field', 'filter_type')
        field_offset = ram_dump.field_offset('struct ftrace_event_field', 'offset')
        size_offset = ram_dump.field_offset('struct ftrace_event_field', 'size')
        signed_offset = ram_dump.field_offset('struct ftrace_event_field', 'is_signed')

        name = ram_dump.read_word(common_list + name_offset)
        field_name = ram_dump.read_cstring(name, 256)
        type_name = ram_dump.read_word(common_list + type_offset)
        type_str = ram_dump.read_cstring(type_name, 256)
        offset = ram_dump.read_u32(common_list + field_offset)
        size = ram_dump.read_u32(common_list + size_offset)
        signed = ram_dump.read_u32(common_list + signed_offset)

        if re.match('(.*)\[(.*)', type_str) and not(re.match('__data_loc', type_str)):
            s = re.split('\[', type_str)
            s[1] = '[' + s[1]
            self.formats_out.write("\tfield:{0} {1}{2};\toffset:{3};\tsize:{4};\tsigned:{5};\n".format(s[0], field_name, s[1], offset, size, signed))
        else:
            self.formats_out.write("\tfield:{0} {1};\toffset:{2};\tsize:{3};\tsigned:{4};\n".format(type_str, field_name, offset, size, signed))

    def ftrace_events_func(self, ftrace_list, ram_dump):
        event_offset = ram_dump.field_offset('struct ftrace_event_call', 'event')
        fmt_offset = ram_dump.field_offset('struct ftrace_event_call', 'print_fmt')
        class_offset = ram_dump.field_offset('struct ftrace_event_call', 'class')
        flags_offset = ram_dump.field_offset('struct ftrace_event_call', 'flags')
        flags = ram_dump.read_word(ftrace_list + flags_offset)

        if (ram_dump.kernel_version >= (3, 18) and (flags & TRACE_EVENT_FL_TRACEPOINT)):
            tp_offset = ram_dump.field_offset('struct ftrace_event_call', 'tp')
            tp_name_offset = ram_dump.field_offset('struct tracepoint', 'name')
            tp = ram_dump.read_word(ftrace_list + tp_offset)
            name = ram_dump.read_word(tp + tp_name_offset)
        else:
            name_offset = ram_dump.field_offset('struct ftrace_event_call', 'name')
            name = ram_dump.read_word(ftrace_list + name_offset)

        type_offset = ram_dump.field_offset('struct trace_event', 'type')
        fields_offset = ram_dump.field_offset('struct ftrace_event_class', 'fields')
        common_field_list = ram_dump.address_of('ftrace_common_fields')
        field_next_offset = ram_dump.field_offset('struct ftrace_event_field', 'link')

        name_str = ram_dump.read_cstring(name, 512)
        event_id = ram_dump.read_word(ftrace_list + event_offset + type_offset)
        fmt = ram_dump.read_word(ftrace_list + fmt_offset)
        fmt_str = ram_dump.read_cstring(fmt, 2048)

        self.formats_out.write("name: {0}\n".format(name_str))
        self.formats_out.write("ID: {0}\n".format(event_id))
        self.formats_out.write("format:\n")

        list_walker = llist.ListWalker(ram_dump, common_field_list, field_next_offset)
        list_walker.walk_prev(common_field_list, self.ftrace_field_func, ram_dump)
        self.formats_out.write("\n")

        event_class = ram_dump.read_word(ftrace_list + class_offset)
        field_list =  event_class + fields_offset
        list_walker = llist.ListWalker(ram_dump, field_list, field_next_offset)
        list_walker.walk_prev(field_list, self.ftrace_field_func, ram_dump)
        self.formats_out.write("\n")
        self.formats_out.write("print fmt: {0}\n".format(fmt_str))

    def collect_ftrace_format(self, ram_dump):
        formats = os.path.join('qtf', 'map_files', 'formats.txt')
        formats_out = ram_dump.open_file(formats)
        self.formats_out = formats_out

        ftrace_events_list = ram_dump.address_of('ftrace_events')
        next_offset = ram_dump.field_offset('struct ftrace_event_call', 'list')
        list_walker = llist.ListWalker(ram_dump, ftrace_events_list, next_offset)
        list_walker.walk_prev(ftrace_events_list, self.ftrace_events_func, ram_dump)

        self.formats_out.close

    def parse_qtf(self, ram_dump):
        out_dir = ram_dump.outdir
        if platform.system() != 'Windows':
            return

        qtf_path = ram_dump.qtf_path
        if qtf_path is None:
            try:
                import local_settings
                try:
                    qtf_path = local_settings.qtf_path
                except AttributeError as e:
                    print_out_str("attribute qtf_path in local_settings.py looks bogus. Please see README.txt")
                    print_out_str("Full message: %s" % e.message)
                    return
            except ImportError:
                print_out_str("missing qtf_path local_settings.")
                print_out_str("Please see the README for instructions on setting up local_settings.py")
                return

        if qtf_path is None:
            print_out_str("!!! Incorrect path for qtf specified.")
            print_out_str("!!! Please see the README for instructions on setting up local_settings.py")
            return

        if not os.path.exists(qtf_path):
            print_out_str("!!! qtf_path {0} does not exist! Check your settings!".format(qtf_path))
            return

        if not os.access(qtf_path, os.X_OK):
            print_out_str("!!! No execute permissions on qtf path {0}".format(qtf_path))
            return

        if os.path.getsize(os.path.join(out_dir, 'tmc-etf.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etf.bin')
        elif os.path.getsize(os.path.join(out_dir, 'tmc-etr.bin')) > 0:
            trace_file = os.path.join(out_dir, 'tmc-etr.bin')
        else:
            return

        port = None
        server_proc = None
        qtf_success = False
        max_tries = 3
        qtf_dir = os.path.join(out_dir, 'qtf')
        workspace = os.path.join(qtf_dir, 'qtf.workspace')
        qtf_out = os.path.join(out_dir, 'qtf.txt')
        chipset = 'msm' + str(ram_dump.hw_id)
        hlos = 'LA'

        # Resolve any port collisions with other running qtf_server instances
        for tries in range(max_tries):
            port = random.randint(12000, 13000)
            server_proc = subprocess.Popen(
                [qtf_path, '-s', '{0}'.format(port)], stderr=subprocess.PIPE)
            time.sleep(1)
            server_proc.poll()
            if server_proc.returncode == 1:
                server_proc.terminate()
                continue
            else:
                qtf_success = True
                break
        if not qtf_success:
            server_proc.terminate()
            print_out_str('!!! Could not open a QTF server instance with a '
                          'unique port (last port tried: '
                          '{0})'.format(str(port)))
            print_out_str('!!! Please kill all currently running qtf_server '
                          'processes and try again')
            return

        subprocess.call('{0} -c {1} new workspace {2} {3} {4}'.format(qtf_path, port, qtf_dir, chipset, hlos))

        self.collect_ftrace_format(ram_dump)

        subprocess.call('{0} -c {1} open workspace {2}'.format(qtf_path, port, workspace))
        subprocess.call('{0} -c {1} open bin {2}'.format(qtf_path, port, trace_file))
        subprocess.call('{0} -c {1} stream trace table {2}'.format(qtf_path, port, qtf_out))
        subprocess.call('{0} -c {1} close'.format(qtf_path, port))
        subprocess.call('{0} -c {1} exit'.format(qtf_path, port))
        server_proc.communicate('quit')

    def parse_dcc(self, ram_dump):
        out_dir = ram_dump.outdir

        dcc_parser_path = os.path.join(os.path.dirname(__file__), '..', 'dcc_parser', 'dcc_parser.py')

        if dcc_parser_path is None:
            print_out_str("!!! Incorrect path for DCC specified.")
            return

        if not os.path.exists(dcc_parser_path):
            print_out_str("!!! dcc_parser_path {0} does not exist! Check your settings!".format(dcc_parser_path))
            return

        if os.path.getsize(os.path.join(out_dir, 'sram.bin')) > 0:
            sram_file = os.path.join(out_dir, 'sram.bin')
        else:
            return

        p = subprocess.Popen([sys.executable, dcc_parser_path, '-s', sram_file, '--out-dir', out_dir],
                        stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

        print_out_str('--------')
        print_out_str(p.communicate()[0])

    def parse_dump_v2(self, ram_dump):
        self.dump_type_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_type', 2)
        self.dump_table_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_table_ids', MAX_NUM_ENTRIES)
        self.dump_data_id_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
            'msm_dump_data_ids', MAX_NUM_ENTRIES)
        cpu_present_bits = ram_dump.read_word('cpu_present_bits')
        cpus = bin(cpu_present_bits).count('1')
        # per cpu entries
        for i in range(1, cpus):

                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_CPU_CTX + i] = 'MSM_DUMP_DATA_CPU_CTX'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_INST_TLB + i] = 'MSM_DUMP_DATA_L1_INST_TLB'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_DATA_TLB + i] = 'MSM_DUMP_DATA_L1_DATA_TLB'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_INST_CACHE + i] = 'MSM_DUMP_DATA_L1_INST_CACHE'
                self.dump_data_id_lookup_table[
                    client.MSM_DUMP_DATA_L1_DATA_CACHE + i] = 'MSM_DUMP_DATA_L1_DATA_CACHE'
                self.dump_data_id_lookup_table[
                    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'
        # 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'
        self.dump_data_id_lookup_table[
            client.MSM_DUMP_DATA_LOG_BUF] = 'MSM_DUMP_DATA_LOG_BUF'
        self.dump_data_id_lookup_table[
            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')
                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))

            for j in range(0, table_num_entries):
                print_out_str('--------')
                client_entry = entry_addr + dump_table_entry_offset + j * dump_entry_size
                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_id < 0 or client_id > len(self.dump_data_id_lookup_table):
                    print_out_str(
                        '!!! Invalid dump client id found {0:x}'.format(client_id))
                    continue

                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)

                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. The parser needs to be updated!'.format(client_name))
                else:
                    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(start))
                        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

                    func = client_table[client_name]
                    getattr(DebugImage_v2, func)(self, dump_data_version, dump_data_addr, dump_data_addr + dump_data_len,
                                                 client_id, ram_dump)

            self.qdss.dump_all(ram_dump)
            if ram_dump.qtf:
                self.parse_qtf(ram_dump)
            if ram_dump.dcc:
                self.parse_dcc(ram_dump)