예제 #1
0
    def _run_analysis(self, analysis):
        try:
            is_html_formatter = isinstance(self.formatter, HtmlFormatter)
            if not IS_PYTHON2 and is_html_formatter:
                # ACAT includes buffers graphs generated by `matplotlib'
                # library to generate HTML output. Matplotlib isn't thread
                # safe under Python3 and crashes.
                analysis.run_all()
            else:
                self.__run_analysis_with_timeout(analysis, 120)

        except FatalAnalysisError as fae:
            # Fatal errors should exit immediately.
            self.formatter.alert('Analysis ' + analysis.__class__.__name__ +
                                 ' failed to complete!' + '\n' +
                                 traceback.format_exc() + '\n')
            self.formatter.flush()
            raise FatalAnalysisError(str(fae))

        except (SystemExit, KeyboardInterrupt, GeneratorExit):
            raise

        except Exception:  # pylint: disable=broad-except
            # Need to catch all error so I have to disable pylint's
            # broad-except error. In automatic mode, we want to catch any
            # other exceptions and try to carry on, so that we can try all
            # the other analyses.
            self.formatter.alert('Analysis ' + analysis.__class__.__name__ +
                                 ' failed to complete!')
            if not cu.global_options.under_test:
                self.formatter.output(traceback.format_exc() + '\n')
            self.formatter.section_reset()
예제 #2
0
    def _get_heap_and_magic_offset(self, heap_address, heap_size, memory_type):
        """Get heap and magic offset.

            Args:
                heap_address
                heap_size
                memory_type

            Returns:
                tuple: Heap Data and the value which shows the distance
                    between two 32-bit words.

            Raises:
                FatalAnalysisError: Memory type not recognized.
        """
        # Get the address we will be working with from the start of heap_pm
        address = heap_address
        if memory_type == "dm":
            heap_data = self.chipdata.get_data(heap_address, heap_size)
            testblock = self.chipdata.cast(address, 'mem_node')
            testblock_magic = testblock.get_member('u').get_member('magic')
        elif memory_type == "pm":
            heap_data = self.chipdata.get_data_pm(heap_address, heap_size)
            testblock = self.chipdata.cast(address, 'mem_node_pm', False, 'PM')
            testblock_magic = testblock.get_member(
                'struct_mem_node').get_member('u').get_member('magic')
        else:
            raise FatalAnalysisError("Memory type %s not recognised." %
                                     memory_type)

        testblock_address = testblock_magic.address
        # magic_offset here shows the distance between two 32-bit words, first
        # being start of the test block and second being magic value
        magic_offset = (testblock_address - address) // Arch.addr_per_word
        return heap_data, magic_offset
예제 #3
0
    def analyse_firmware_id(self, id_mismatch_allowed=None):
        """Check the firmware id for mismatch.

        Compare the firmware ID reported in the chipdata with the one in
        the debug information (checks we have got the correct build
        output) id_mismatch_allowed is a boolean. If supplied, it
        overrides any command-line setting.

        Args:
            id_mismatch_allowed (int)
        """
        if Arch.chip_arch == "KAS":
            self.formatter.section_start('Firmware')
            self.formatter.alert("KAS.. ID not currently supported")
            self.formatter.section_end()
            return

        if id_mismatch_allowed is not None:
            permit_mismatch = id_mismatch_allowed
        else:
            permit_mismatch = cu.global_options.build_mismatch_allowed

        if self.chipdata.processor == 1:
            permit_mismatch = True
        # Perform the ID check even if there is no formatter supplied.
        # If we fail this test then we won't need one anyway.
        debug_id = self.get_debug_firmware_id()
        chipdata_id = self.chipdata.get_firmware_id()

        # The build ID check does not work for old style
        # Bluecore coredumps because the firmware
        # ID did not use to be recorded and the ID returned was 0.
        # The Coredump tool was modified to do
        # this in B-204537.
        # For this particular case, the check is being skipped.
        if (not self.chipdata.is_volatile() and Arch.chip_arch == "Bluecore"
                and chipdata_id == 0):
            permit_mismatch = True
            self.formatter.alert(
                "Might be dealing with an old Bluecore coredump when "
                "ID check was not supported as build ID is 0.")

        if debug_id != chipdata_id:
            grave_warning = 'Chip does not match supplied build output! '
            # (Firmware IDs are stored in decimal, so output them in decimal.)
            grave_warning += 'Chip ID is %d, build output is ID %d' % (
                chipdata_id, debug_id)
            if not permit_mismatch:
                self.formatter.error(grave_warning)
                raise FatalAnalysisError(grave_warning)
            else:
                self.formatter.alert(grave_warning)

        debug_id_string = self.get_debug_firmware_id_string()
        chipdata_id_string = self.chipdata.get_firmware_id_string()

        # Whitespace is already stripped, should be able to just check for
        # equality.
        if debug_id_string != chipdata_id_string:
            grave_warning = 'Chip does not match supplied build output! '
            grave_warning += (
                "Chip ID string is '%s', build output is ID '%s'" %
                (chipdata_id_string, debug_id_string))
            if not permit_mismatch:
                self.formatter.error(grave_warning)
                raise FatalAnalysisError(grave_warning)
            else:
                self.formatter.alert(grave_warning)

        # Now we can raise an exception if necessary.
        self.formatter.section_start('Firmware')
        self.formatter.output('Firmware ID: ' + str(debug_id))
        self.formatter.output('Firmware ID String: ' + debug_id_string)
        self.formatter.section_end()
예제 #4
0
    def _free_blocks(self, address, heap_start, heap_size, memory_type="dm"):
        """Checks the free blocks.

        Args:
            address: Address to start with.
            heap_start
            heap_size
            memory_type (str, optional)

        Returns:
            A list describing the free memory allocations.
        """
        free_blocks_info = []
        address_history = []
        total_size = 0
        while address != 0:
            # Avoid infinite loop by checking if the node was already checked.
            if address not in address_history:
                address_history.append(address)
            else:
                self.formatter.error("Repeating nodes with address 0x%x. "
                                     "Probably memory corruption" % address)
                return FreeBlocks(total_size, free_blocks_info)
            if memory_type == "dm":
                try:
                    freeblock = self.chipdata.cast(address, 'mem_node')
                    freeblock_size = freeblock.get_member('length').value
                except InvalidDmAddressError:
                    self.formatter.error(
                        "Address 0x%x in %s cannot be access. "
                        "Heap cannot be analysed." %
                        (address, str(Arch.get_dm_region(address, False))))

                    return FreeBlocks(total_size, free_blocks_info)

            elif memory_type == "pm":
                freeblock = self.chipdata.cast(address, 'mem_node_pm', False,
                                               'PM')
                freeblock_size = freeblock.get_member(
                    'struct_mem_node').get_member(
                        'length_32').value * Arch.addr_per_word
            else:
                raise FatalAnalysisError("Memory type %s not recognised." %
                                         memory_type)

            # verify if the address is valid
            if self.is_address_valid(address):
                # If the list node belongs to the current analysed heap
                # display info
                end_of_heap = heap_start + heap_size
                if (address >= heap_start) and (address <= end_of_heap):
                    desc_str = ("Free block size : " +
                                cu.mem_size_to_string(freeblock_size, "o") +
                                " at address: 0x{0:0>8x}".format(address))
                    free_blocks_info.append(desc_str)
                    total_size += freeblock_size
            else:
                raise FatalAnalysisError(" 0x%x is out of %s heap memory !" %
                                         (address, memory_type))

            if memory_type == "dm":
                address = freeblock.get_member('u').get_member('next').value
            elif memory_type == "pm":
                address = freeblock.get_member('struct_mem_node').get_member(
                    'u').get_member('next').value

        free_blocks_info.append("Total heap free : " +
                                cu.mem_size_to_string(total_size, "ow"))
        return FreeBlocks(total_size, free_blocks_info)