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