Skip to content
Snippets Groups Projects
ramdump.py 81.6 KiB
Newer Older
# Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 and
# only version 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

import sys
import re
import os
import struct
import gzip
import functools
import random
from boards import get_supported_boards, get_supported_ids
from tempfile import NamedTemporaryFile

import gdbmi
from print_out import print_out_str
from mmu import Armv7MMU, Armv7LPAEMMU, Armv8MMU
import parser_util
import minidump_util
from importlib import import_module
import module_table

FP = 11
SP = 13
LR = 14
PC = 15

# The smem code is very stable and unlikely to go away or be changed.
# Rather than go through the hassel of parsing the id through gdb,
# just hard code it

SMEM_HW_SW_BUILD_ID = 0x89
BUILD_ID_LENGTH = 32

def is_ramdump_file(val):
    ddr = re.compile(r'(DDR|EBI)[0-9_CS]+[.]BIN', re.IGNORECASE)
    imem = re.compile(r'.*IMEM.BIN', re.IGNORECASE)
    if ddr.match(val) or imem.match(val):
        return True
    return False

class AutoDumpInfo(object):
    priority = 0

    def __init__(self, autodumpdir):
        self.autodumpdir = autodumpdir
        self.ebi_files = []

    def parse(self):
        for (filename, base_addr) in self._parse():
            fullpath = os.path.join(self.autodumpdir, filename)
            if not os.path.exists(fullpath):
                continue
            end = base_addr + os.path.getsize(fullpath) - 1
            self.ebi_files.append((open(fullpath, 'rb'), base_addr, end, fullpath))
            # sort by addr, DDR files first. The goal is for
            # self.ebi_files[0] to be the DDR file with the lowest address.
            self.ebi_files.sort(key=lambda x: (x[1]))

    def _parse(self):
        # Implementations should return an interable of (filename, base_addr)
        raise NotImplementedError


class AutoDumpInfoCMM(AutoDumpInfo):
    # Parses CMM scripts (like load.cmm)
    def _parse(self):
        filename = 'load.cmm'
        if not os.path.exists(os.path.join(self.autodumpdir, filename)):
            print_out_str('!!! AutoParse could not find load.cmm!')
            return

        with open(os.path.join(self.autodumpdir, filename)) as f:
            for line in f.readlines():
                words = line.split()
                if len(words) == 4 and is_ramdump_file(words[1]):
                    fname = words[1]
                    start = int(words[2], 16)
                    yield fname, start


class AutoDumpInfoDumpInfoTXT(AutoDumpInfo):
    # Parses dump_info.txt
    priority = 1

    def _parse(self):
        filename = 'dump_info.txt'
        if not os.path.exists(os.path.join(self.autodumpdir, filename)):
            print_out_str('!!! AutoParse could not find dump_info.txt!')
            return

        with open(os.path.join(self.autodumpdir, filename)) as f:
            for line in f.readlines():
                words = line.split()
                if not words or not is_ramdump_file(words[-1]):
                    continue
                fname = words[-1]
                start = int(words[1], 16)
                size = int(words[2])
                filesize = os.path.getsize(
                    os.path.join(self.autodumpdir, fname))
                if size != filesize:
                    print_out_str(
                        ("!!! Size of %s on disk (%d) doesn't match size " +
                         "from dump_info.txt (%d). Skipping...")
                        % (fname, filesize, size))
                    continue
                yield fname, start

    """The main interface to the RAM dump"""

    class Unwinder ():

        class Stackframe ():

            def __init__(self, fp, sp, lr, pc):
                self.fp = fp
                self.sp = sp
                self.lr = lr
                self.pc = pc

        class UnwindCtrlBlock ():

            def __init__(self):
                self.vrs = 16 * [0]
                self.insn = 0
                self.entries = -1
                self.byte = -1
                self.index = 0

        def __init__(self, ramdump):
            start = ramdump.address_of('__start_unwind_idx')
            end = ramdump.address_of('__stop_unwind_idx')
            if (start is None) or (end is None):
                if ramdump.arm64:
                    self.unwind_frame = self.unwind_frame_generic64
                else:
                    self.unwind_frame = self.unwind_frame_generic
            self.unwind_frame = self.unwind_frame_tables
            self.start_idx = start
            self.stop_idx = end
            self.unwind_table = []
            i = 0
            for addr in range(start, end, 8):
                r = ramdump.read_string(addr, '<II')
                if r is None:
                    break
                (a, b) = r
                self.unwind_table.append((a, b, start + 8 * i))
                i += 1

            ver = ramdump.version
            if re.search('3.0.\d', ver) is not None:
                self.search_idx = self.search_idx_3_0
            else:
                self.search_idx = self.search_idx_3_4
                # index into the table
                self.origin = self.unwind_find_origin()

        def unwind_find_origin(self):
            start = 0
            stop = len(self.unwind_table)
            while (start < stop):
                mid = start + ((stop - start) >> 1)
                if (self.unwind_table[mid][0] >= 0x40000000):
                    start = mid + 1
                else:
                    stop = mid
            return stop

        def unwind_frame_generic64(self, frame):
            low = frame.sp
            mask = (self.ramdump.thread_size) - 1
            high = (low + mask) & (~mask)

            if (fp < low or fp > high or fp & 0xf):

            frame.sp = fp + 0x10
            frame.fp = self.ramdump.read_word(fp)
            frame.pc = self.ramdump.read_word(fp + 8)
            return 0

        def unwind_frame_generic(self, frame):
            mask = (self.ramdump.thread_size) - 1

            high = (low + mask) & (~mask)  # ALIGN(low, THREAD_SIZE)

            # /* check current frame pointer is within bounds */
            if (fp < (low + 12) or fp + 4 >= high):
                return -1

            fp_is_at = self.ramdump.read_word(frame.fp - 12)
            sp_is_at = self.ramdump.read_word(frame.fp - 8)
            pc_is_at = self.ramdump.read_word(frame.fp - 4)

            frame.fp = fp_is_at
            frame.sp = sp_is_at
            frame.pc = pc_is_at

            return 0

        def walk_stackframe_generic(self, frame):
            while True:
                symname = self.ramdump.addr_to_symbol(frame.pc)
                print_out_str(symname)

                ret = self.unwind_frame_generic(frame)
                if ret < 0:
                    break

        def unwind_backtrace_generic(self, sp, fp, pc):
            frame = self.Stackframe()
            frame.fp = fp
            frame.pc = pc
            frame.sp = sp
            walk_stackframe_generic(frame)

        def search_idx_3_4(self, addr):
            start = 0
            stop = len(self.unwind_table)
            orig = addr

            if (addr < self.start_idx):
                stop = self.origin
            else:
                start = self.origin

            if (start >= stop):
                return None

            addr = (addr - self.unwind_table[start][2]) & 0x7fffffff

            while (start < (stop - 1)):
                mid = start + ((stop - start) >> 1)

                dif = (self.unwind_table[mid][2]
                       - self.unwind_table[start][2])
                if ((addr - dif) < self.unwind_table[mid][0]):
                    stop = mid
                else:
                    addr = addr - dif
                    start = mid

            if self.unwind_table[start][0] <= addr:
                return self.unwind_table[start]
            else:
                return None

        def search_idx_3_0(self, addr):
            first = 0
            last = len(self.unwind_table)
            while (first < last - 1):
                mid = first + ((last - first + 1) >> 1)
                if (addr < self.unwind_table[mid][0]):
                    last = mid
                else:
                    first = mid

            return self.unwind_table[first]

        def unwind_get_byte(self, ctrl):

            if (ctrl.entries <= 0):
                print_out_str('unwind: Corrupt unwind table')
                return 0

            val = self.ramdump.read_word(ctrl.insn)

            ret = (val >> (ctrl.byte * 8)) & 0xff

            if (ctrl.byte == 0):
                ctrl.insn += 4
                ctrl.entries -= 1
                ctrl.byte = 3
            else:
                ctrl.byte -= 1

            return ret

        def unwind_exec_insn(self, ctrl):
            insn = self.unwind_get_byte(ctrl)

            if ((insn & 0xc0) == 0x00):
                ctrl.vrs[SP] += ((insn & 0x3f) << 2) + 4
            elif ((insn & 0xc0) == 0x40):
                ctrl.vrs[SP] -= ((insn & 0x3f) << 2) + 4
            elif ((insn & 0xf0) == 0x80):
                vsp = ctrl.vrs[SP]
                reg = 4

                insn = (insn << 8) | self.unwind_get_byte(ctrl)
                mask = insn & 0x0fff
                if (mask == 0):
                    print_out_str("unwind: 'Refuse to unwind' instruction")
                    return -1

                # pop R4-R15 according to mask */
                load_sp = mask & (1 << (13 - 4))
                while (mask):
                    if (mask & 1):
                        ctrl.vrs[reg] = self.ramdump.read_word(vsp)
                        if ctrl.vrs[reg] is None:
                            return -1
                        vsp += 4
                    mask >>= 1
                    reg += 1
                if not load_sp:
                    ctrl.vrs[SP] = vsp

            elif ((insn & 0xf0) == 0x90 and (insn & 0x0d) != 0x0d):
                ctrl.vrs[SP] = ctrl.vrs[insn & 0x0f]
            elif ((insn & 0xf0) == 0xa0):
                vsp = ctrl.vrs[SP]
                a = list(range(4, 4 + (insn & 7)))
                a.append(4 + (insn & 7))
                # pop R4-R[4+bbb] */
                for reg in (a):
                    ctrl.vrs[reg] = self.ramdump.read_word(vsp)
                    if ctrl.vrs[reg] is None:
                        return -1
                    vsp += 4
                if (insn & 0x80):
                    ctrl.vrs[14] = self.ramdump.read_word(vsp)
                    if ctrl.vrs[14] is None:
                        return -1
                    vsp += 4
                ctrl.vrs[SP] = vsp
            elif (insn == 0xb0):
                if (ctrl.vrs[PC] == 0):
                    ctrl.vrs[PC] = ctrl.vrs[LR]
                ctrl.entries = 0
            elif (insn == 0xb1):
                mask = self.unwind_get_byte(ctrl)
                vsp = ctrl.vrs[SP]
                reg = 0

                if (mask == 0 or mask & 0xf0):
                    print_out_str('unwind: Spare encoding')
                    return -1

                # pop R0-R3 according to mask
                while mask:
                    if (mask & 1):
                        ctrl.vrs[reg] = self.ramdump.read_word(vsp)
                        if ctrl.vrs[reg] is None:
                            return -1
                        vsp += 4
                    mask >>= 1
                    reg += 1
                ctrl.vrs[SP] = vsp
            elif (insn == 0xb2):
                uleb128 = self.unwind_get_byte(ctrl)
                ctrl.vrs[SP] += 0x204 + (uleb128 << 2)
            else:
                print_out_str('unwind: Unhandled instruction')
                return -1

            return 0

        def prel31_to_addr(self, addr):
            value = self.ramdump.read_word(addr)
            # offset = (value << 1) >> 1
            # C wants this sign extended. Python doesn't do that.
            # Sign extend manually.
            if (value & 0x40000000):
                offset = value | 0x80000000
            else:
                offset = value

            # This addition relies on integer overflow
            # Emulate this behavior
            temp = addr + offset
            return (temp & 0xffffffff) + ((temp >> 32) & 0xffffffff)

        def unwind_frame_tables(self, frame):
            high = ((low + (self.ramdump.thread_size - 1)) & \
                ~(self.ramdump.thread_size - 1)) + self.ramdump.thread_size
            idx = self.search_idx(frame.pc)

            if (idx is None):
                return -1

            ctrl = self.UnwindCtrlBlock()
            ctrl.vrs[FP] = frame.fp
            ctrl.vrs[SP] = frame.sp
            ctrl.vrs[LR] = frame.lr
            ctrl.vrs[PC] = 0

            if (idx[1] == 1):
                return -1

            elif ((idx[1] & 0x80000000) == 0):
                ctrl.insn = self.prel31_to_addr(idx[2] + 4)

            elif (idx[1] & 0xff000000) == 0x80000000:
                ctrl.insn = idx[2] + 4
            else:
                print_out_str('not supported')
                return -1

            val = self.ramdump.read_word(ctrl.insn)

            if ((val & 0xff000000) == 0x80000000):
                ctrl.byte = 2
                ctrl.entries = 1
            elif ((val & 0xff000000) == 0x81000000):
                ctrl.byte = 1
                ctrl.entries = 1 + ((val & 0x00ff0000) >> 16)
            else:
                return -1

            while (ctrl.entries > 0):
                urc = self.unwind_exec_insn(ctrl)
                if (urc < 0):
                    return urc
                if (ctrl.vrs[SP] < low or ctrl.vrs[SP] >= high):
                    return -1

            if (ctrl.vrs[PC] == 0):
                ctrl.vrs[PC] = ctrl.vrs[LR]

            # check for infinite loop */
            if (frame.pc == ctrl.vrs[PC]):
                return -1

            frame.fp = ctrl.vrs[FP]
            frame.sp = ctrl.vrs[SP]
            frame.lr = ctrl.vrs[LR]
            frame.pc = ctrl.vrs[PC]

            return 0

        def unwind_backtrace(self, sp, fp, pc, lr, extra_str='',
                             out_file=None):
            offset = 0
            frame = self.Stackframe(fp, sp, lr, pc)
            frame.fp = fp
            frame.sp = sp
            frame.lr = lr
            frame.pc = pc

            while True:
                where = frame.pc
                offset = 0

                r = self.ramdump.unwind_lookup(frame.pc)
                if r is None:
                    symname = 'UNKNOWN'
                    offset = 0x0
                else:
                    symname, offset = r
                pstring = (
                    extra_str + '[<{0:x}>] {1}+0x{2:x}'.format(frame.pc, symname, offset))
                if out_file:
                    out_file.write(pstring + '\n')
                else:
                    print_out_str(pstring)

                urc = self.unwind_frame(frame)
    def __init__(self, options, nm_path, gdb_path, objdump_path):
        self.ebi_files_minidump = []
        self.ebi_pa_name_map = {}
        self.kaslr_offset = options.kaslr_offset
        self.tz_start = 0
        self.ebi_start = 0
        self.cpu_type = None
        self.hw_id = options.force_hardware or None
        self.hw_version = options.force_hardware_version or None
        self.nm_path = nm_path
        self.gdb_path = gdb_path
        self.objdump_path = objdump_path
        self.gdbmi = gdbmi.GdbMI(self.gdb_path, self.vmlinux,
                                 self.kaslr_offset or 0)
        self.thread_size = 8192
        self.qtf_path = options.qtf_path
        self.qtf = options.qtf
        self.skip_qdss_bin = options.skip_qdss_bin
        self.sysreg = False
        self.t32_host_system = options.t32_host_system or None
        self.ipc_log_test = options.ipc_test
        self.ipc_log_skip = options.ipc_skip
        self.ipc_log_debug = options.ipc_debug
        self.ipc_log_help = options.ipc_help
        self.use_stdout = options.stdout
        self.kernel_version = (0, 0, 0)
        self.minidump = options.minidump
        self.elffile = None
        self.ram_elf_file = None
        self.ram_addr = options.ram_addr
        self.autodump = options.autodump
        self.module_table = module_table.module_table_class()
        self.module_table.setup_sym_path(options.sym_path)
        self.dump_module_symbol_table = options.dump_module_symbol_table
        self.dump_kernel_symbol_table = options.dump_kernel_symbol_table
        self.dump_module_kallsyms = options.dump_module_kallsyms
        self.dump_global_symbol_table = options.dump_global_symbol_table
        self.currentEL = options.currentEL or None
        if self.minidump:
            try:
                mod = import_module('elftools.elf.elffile')
                ELFFile = mod.ELFFile
                StringTableSection = mod.StringTableSection
                mod = import_module('elftools.common.py3compat')
                bytes2str = mod.bytes2str
            except ImportError:
                print "Oops, missing required library for minidump. Check README"
                sys.exit(1)
        if options.ram_addr is not None:
            # TODO sanity check to make sure the memory regions don't overlap
            for file_path, start, end in options.ram_addr:
                fd = open(file_path, 'rb')
                if not fd:
                    print_out_str(
                        'Could not open {0}. Will not be part of dump'.format(file_path))
                    continue
                self.ebi_files.append((fd, start, end, file_path))
        elif not options.minidump:
            if not self.auto_parse(options.autodump):
        if options.minidump:
            file_path = options.ram_elf_addr
            self.ram_elf_file = file_path
            fd = open(file_path, 'rb')
            self.elffile = ELFFile(fd)
            for idx, s in enumerate(self.elffile.iter_segments()):
                pa = int(s['p_paddr'])
                va = int(s['p_vaddr'])
                size = int(s['p_filesz'])
                end_addr = pa + size
                for section in self.elffile.iter_sections():
                    if (not section.is_null() and
                            s.section_in_segment(section)):
                        self.ebi_pa_name_map[pa] = section.name
                self.ebi_files_minidump.append((idx, pa, end_addr, va,size))

        if options.minidump:
            if self.ebi_start == 0:
                self.ebi_start = self.ebi_files_minidump[0][1]
        else:
            if self.ebi_start == 0:
                self.ebi_start = self.ebi_files[0][1]
        if self.phys_offset is None:
            self.get_hw_id()

        if self.kaslr_offset is None:
            self.determine_kaslr_offset()
            self.gdbmi.kaslr_offset = self.get_kaslr_offset()
        if options.phys_offset is not None:
                '[!!!] Phys offset was set to {0:x}'.format(\
                    options.phys_offset))
            self.phys_offset = options.phys_offset
        self.wlan = options.wlan
        self.lookup_table = []
        self.config = []
        if self.arm64:
            self.page_offset = 0xffffffc000000000
            self.thread_size = 16384
        if options.page_offset is not None:
            print_out_str(
                '[!!!] Page offset was set to {0:x}'.format(page_offset))
            self.page_offset = options.page_offset
        if self.get_kernel_version() > (4, 20, 0):
            va_bits = 39
            modules_vsize = 0x08000000
            bpf_jit_vsize = 0x08000000
            self.page_end = (0xffffffffffffffff << (va_bits - 1)) & 0xffffffffffffffff
            if self.address_of("kasan_init") is None:
                self.kasan_shadow_size = 0
            else:
                self.kasan_shadow_size = 1 << (va_bits - 3)

            self.kimage_vaddr = self.page_end + self.kasan_shadow_size + modules_vsize + \
                                bpf_jit_vsize
            va_bits = 39
            modules_vsize = 0x08000000
            self.va_start = (0xffffffffffffffff << va_bits) & 0xffffffffffffffff
            if self.address_of("kasan_init") is None:
                self.kasan_shadow_size = 0
            else:
                self.kasan_shadow_size = 1 << (va_bits - 3)

            self.kimage_vaddr = self.va_start + self.kasan_shadow_size + \
                                modules_vsize
        print_out_str("Kernel version vmlinux: {0}".format(self.kernel_version))
        self.kimage_vaddr = self.kimage_vaddr + self.get_kaslr_offset()
        self.modules_end = self.page_offset
        if self.arm64:
            self.kimage_voffset = self.address_of("kimage_voffset")
            if self.kimage_voffset is not None:
                self.kimage_voffset = self.kimage_vaddr - self.phys_offset
                self.modules_end = self.kimage_vaddr
                print_out_str("The kimage_voffset extracted is: {:x}".format(self.kimage_voffset))
        else:
            self.kimage_voffset = None
        # The address of swapper_pg_dir can be used to determine
        # whether or not we're running with LPAE enabled since an
        # extra 4k is needed for LPAE. If it's 0x5000 below
        # PAGE_OFFSET + TEXT_OFFSET then we know we're using LPAE. For
        # non-LPAE it should be 0x4000 below PAGE_OFFSET + TEXT_OFFSET
        self.swapper_pg_dir_addr = self.address_of('swapper_pg_dir')
        if self.swapper_pg_dir_addr is None:
            print_out_str('!!! Could not get the swapper page directory!')
            if not self.minidump:
                print_out_str(
                    '!!! Your vmlinux is probably wrong for these dumps')

                print_out_str('!!! Exiting now')
                sys.exit(1)

        stext = self.address_of('stext')
        if self.kimage_voffset is None:
            self.kernel_text_offset = stext - self.page_offset
        else:
            self.kernel_text_offset = stext - self.kimage_vaddr

        pg_dir_size = self.kernel_text_offset + self.page_offset \
            - self.swapper_pg_dir_addr

        if self.arm64:
            print_out_str('Using 64bit MMU')
            self.mmu = Armv8MMU(self)
        elif pg_dir_size == 0x4000:
            print_out_str('Using non-LPAE MMU')
            self.mmu = Armv7MMU(self)
        elif pg_dir_size == 0x5000:
            print_out_str('Using LPAE MMU')
            text_offset = 0x8000
            pg_dir_size = 0x5000    # 0x4000 for non-LPAE
            swapper_pg_dir_addr = self.phys_offset + text_offset - pg_dir_size

            # We deduce ttbr1 and ttbcr.t1sz based on the value of
            # PAGE_OFFSET. This is based on v7_ttb_setup in
            # arch/arm/mm/proc-v7-3level.S:

            # * TTBR0/TTBR1 split (PAGE_OFFSET):
            # *   0x40000000: T0SZ = 2, T1SZ = 0 (not used)
            # *   0x80000000: T0SZ = 0, T1SZ = 1
            # *   0xc0000000: T0SZ = 0, T1SZ = 2
            if self.page_offset == 0x40000000:
                t1sz = 0
            elif self.page_offset == 0x80000000:
                t1sz = 1
            elif self.page_offset == 0xc0000000:
                t1sz = 2
                # need to fixup ttbr1 since we'll be skipping the
                # first-level lookup (see v7_ttb_setup):
                # /* PAGE_OFFSET == 0xc0000000, T1SZ == 2 */
                # add      \ttbr1, \ttbr1, #4096 * (1 + 3) @ only L2 used, skip
                # pgd+3*pmd
                swapper_pg_dir_addr += (4096 * (1 + 3))
            else:
                raise Exception(
                    'Invalid phys_offset for page_table_walk: 0x%x'
                    % self.page_offset)
            self.mmu = Armv7LPAEMMU(self, swapper_pg_dir_addr, t1sz)
        else:
            print_out_str(
                "!!! Couldn't determine whether or not we're using LPAE!")
            print_out_str(
                '!!! This is a BUG in the parser and should be reported.')
            sys.exit(1)

        if not self.match_version():
            print_out_str('!!! Could not get the Linux version!')
            print_out_str(
                '!!! Your vmlinux is probably wrong for these dumps')
            print_out_str('!!! Exiting now')
            sys.exit(1)
        if not self.minidump:
            if not self.get_config():
                print_out_str('!!! Could not get saved configuration')
                print_out_str(
                    '!!! This is really bad and probably indicates RAM corruption')
                print_out_str('!!! Some features may be disabled!')
        self.unwind = self.Unwinder(self)
        if self.module_table.sym_path_exists():
            self.setup_module_symbols()
            self.gdbmi.setup_module_table(self.module_table)
            if self.dump_global_symbol_table:
                self.dump_global_symbol_lookup_table()

    def __del__(self):
        self.gdbmi.close()

    def open_file(self, file_name, mode='wb'):
        """Open a file in the out directory.

        Example:

        >>> with self.ramdump.open_file('pizza.txt') as p:
                p.write('Pizza is the best\\n')
        """
        file_path = os.path.join(self.outdir, file_name)
        f = None
        try:
            dir_path = os.path.dirname(file_path)
            if not os.path.exists(dir_path) and 'w' in mode:
                os.makedirs(dir_path)
            f = open(file_path, mode)
        except:
            print_out_str('Could not open path {0}'.format(file_path))
            print_out_str('Do you have write/read permissions on the path?')
            sys.exit(1)
        return f

    def remove_file(self, file_name):
	file_path = os.path.join(self.outdir, file_name)
	try:
	    if (os.path.exists(file_path)):
		os.remove(file_path)
	except:
	    print_out_str('Could not remove file {0}'.format(file_path))
	    print_out_str('Do you have write/read permissions on the path?')
	    sys.exit(1)

        kconfig_addr = self.address_of('kernel_config_data')
        if kconfig_addr is None:
            return
        kconfig_size = self.sizeof('kernel_config_data')
        # size includes magic, offset from it
        kconfig_size = kconfig_size - 16 - 1
        zconfig = NamedTemporaryFile(mode='wb', delete=False)
        # kconfig data starts with magic 8 byte string, go past that
        s = self.read_cstring(kconfig_addr, 8)
        if s != 'IKCFG_ST':
            return
        kconfig_addr = kconfig_addr + 8
        for i in range(0, kconfig_size):
            val = self.read_byte(kconfig_addr + i)
            zconfig.write(struct.pack('<B', val))

        zconfig.close()
        zconfig_in = gzip.open(zconfig.name, 'rb')
        try:
            t = zconfig_in.readlines()
        except:
            return False
        zconfig_in.close()
        os.remove(zconfig.name)
        for l in t:
            self.config.append(l.rstrip().decode('ascii', 'ignore'))
            if not l.startswith('#') and l.strip() != '':
                eql = l.find('=')
                cfg = l[:eql]
                val = l[eql+1:]
                self.config_dict[cfg] = val.strip()
    def get_config_val(self, config):
        """Gets the value of a kernel config option.

        Example:

        >>> va_bits = int(dump.get_config_val("CONFIG_ARM64_VA_BITS"))
        39
        """
        return self.config_dict.get(config)

    def is_config_defined(self, config):
        return config in self.config_dict
    def get_kernel_version(self):
        if self.kernel_version == (0, 0, 0):
            vm_v = self.gdbmi.get_value_of_string('linux_banner')
            if vm_v is None:
                print_out_str('!!! Could not read linux_banner from vmlinux!')
                sys.exit(1)
            v = re.search('Linux version (\d{0,2}\.\d{0,2}\.\d{0,2})', vm_v)
            if v is None:
                print_out_str('!!! Could not extract version info!')
                sys.exit(1)
            self.version = v.group(1)
            match = re.search('(\d+)\.(\d+)\.(\d+)', self.version)
            if match is not None:
                self.version = tuple(map(int, match.groups()))
                self.kernel_version = self.version
                self.linux_banner = vm_v
            else:
                print_out_str('!!! Could not extract version info! {0}'.format(self.version))
                sys.exit(1)

        return self.kernel_version

    def kernel_virt_to_phys(self, addr):
        if self.minidump:
            return minidump_util.minidump_virt_to_phys(self.ebi_files_minidump,addr)
            va_bits = 39
            if self.kimage_voffset is None:
                return addr - self.page_offset + self.phys_offset
            else:
                if self.kernel_version > (4, 20, 0):
                    if not (addr & (1 << (va_bits - 1))):
                        return addr - self.page_offset + self.phys_offset
                    else:
                        return addr - (self.kimage_voffset)
                    if addr & (1 << (va_bits - 1)):
                        return addr - self.page_offset + self.phys_offset
                    else:
                        return addr - (self.kimage_voffset)
        banner_addr = self.address_of('linux_banner')
        if banner_addr is not None:
            banner_addr = self.kernel_virt_to_phys(banner_addr)
            banner_len = len(self.linux_banner)
            b = self.read_cstring(banner_addr, banner_len, False)
                print_out_str('!!! Banner not found in dumps!')
                return False
            print_out_str('Linux Banner: ' + b.rstrip())
            if str(self.linux_banner) in str(b):
                print_out_str("Linux banner from vmlinux = %s" % self.linux_banner)
                print_out_str("Linux banner from dump = %s" % b)
                return True
            else:
                print_out_str("Expected Linux banner = %s" % self.linux_banner)
                print_out_str("Linux banner in Dumps = %s" % b)
            print_out_str('!!! linux_banner sym not found in vmlinux')
            return False

    def print_command_line(self):
        command_addr = self.address_of('saved_command_line')
        if command_addr is not None:
            command_addr = self.read_word(command_addr)
            b = self.read_cstring(command_addr, 2048)
            if b is None:
                print_out_str('!!! could not read saved command line address')
                return False
            print_out_str('Command Line: ' + b)
            return True
        else:
            print_out_str('!!! Could not lookup saved command line address')
            return False
        
    def print_socinfo_minidump(self):
        content_socinfo = None
        boards = get_supported_boards()
        for board in boards:
            if self.hw_id == board.board_num:
                content_socinfo = board.ram_start + board.smem_addr_buildinfo
                break
        sernum_offset = self.field_offset('struct socinfo_v10', 'serial_number')
        if sernum_offset is None:
            sernum_offset = self.field_offset('struct socinfo_v0_10', 'serial_number')
            if sernum_offset is None:
                print_out_str("No serial number information available")
                return False
        if content_socinfo:
            addr_of_sernum = content_socinfo + sernum_offset
            serial_number = self.read_u32(addr_of_sernum, False)
            if serial_number is not None:
                print_out_str('Serial number %s' % hex(serial_number))
                return True
            return False

        return False
    def print_socinfo(self):
        if self.read_pointer('socinfo') is None:
          return None
        content_socinfo = hex(self.read_pointer('socinfo'))
        content_socinfo = content_socinfo.strip('L')
        sernum_offset = self.field_offset('struct socinfo_v10', 'serial_number')
        if sernum_offset is None:
            sernum_offset = self.field_offset('struct socinfo_v0_10', 'serial_number')
            if sernum_offset is None:
                print_out_str("No serial number information available")
                return False
        addr_of_sernum = hex(int(content_socinfo, 16) + sernum_offset)
        addr_of_sernum = addr_of_sernum.strip('L')
        serial_number = self.read_u32(int(addr_of_sernum, 16))
        if serial_number is not None:
            print_out_str('Serial number %s' % hex(serial_number))
            return True
    def auto_parse(self, file_path):
        for cls in sorted(AutoDumpInfo.__subclasses__(),
                          key=lambda x: x.priority, reverse=True):
            info = cls(file_path)
            info.parse()
            if info is not None and len(info.ebi_files) > 0:
                self.ebi_files = info.ebi_files
                self.phys_offset = self.ebi_files[0][1]
                if self.get_hw_id():
                    for (f, start, end, filename) in self.ebi_files:
                        print_out_str('Adding {0} {1:x}--{2:x}'.format(
                            filename, start, end))
        self.ebi_files = None
        return False

    def create_t32_launcher(self):
        out_path = os.path.abspath(self.outdir)
        t32_host_system = self.t32_host_system or platform.system()

        launch_config = open(out_path + '/t32_config.t32', 'wb')
        launch_config.write('OS=\n')
        launch_config.write('ID=T32_1000002\n')
        if t32_host_system != 'Linux':
            launch_config.write('TMP=C:\\TEMP\n')
            launch_config.write('SYS=C:\\T32\n')
            launch_config.write('HELP=C:\\T32\\pdf\n')
        else:
            launch_config.write('TMP=/tmp\n')
            launch_config.write('SYS=/opt/t32\n')
            launch_config.write('HELP=/opt/t32/pdf\n')
        launch_config.write('\n')
        launch_config.write('PBI=SIM\n')
        launch_config.write('SCREEN=\n')
        if t32_host_system != 'Linux':
            launch_config.write('FONT=SMALL\n')
        else:
            launch_config.write('FONT=LARGE\n')
        launch_config.write('HEADER=Trace32-ScorpionSimulator\n')
        if t32_host_system != 'Linux':
            launch_config.write('PRINTER=WINDOWS\n')
        launch_config.write('\n')
        launch_config.write('RCL=NETASSIST\n')
        launch_config.write('PACKLEN=1024\n')
        launch_config.write('PORT=%d\n' % random.randint(20000, 30000))
        launch_config.close()

        startup_script = open(out_path + '/t32_startup_script.cmm', 'wb')

        startup_script.write(('title \"' + out_path + '\"\n').encode('ascii', 'ignore'))

        is_cortex_a53 = self.hw_id in ["8916", "8939", "8936"]
            startup_script.write('sys.cpu CORTEXA53\n'.encode('ascii', 'ignore'))
            startup_script.write('sys.cpu {0}\n'.format(self.cpu_type).encode('ascii', 'ignore'))
        startup_script.write('sys.up\n'.encode('ascii', 'ignore'))

        for ram in self.ebi_files:
            ebi_path = os.path.abspath(ram[3])