def _get_heap_config_str(self, processor_number): """ @brief Returns the string representation of the heap configuration . In other words is the to string function for processor configuration. @param[in] self Pointer to the current object @param[in] processor_number @param[out] processor configuration string. """ return_str = "" total_size = 0 for heap_num in range(self.max_num_heaps): (available, heap_size, heap_start, heap_end) = \ self._get_heap_config(processor_number, heap_num) if available: return_str += "%-15s : " % self.heap_names[heap_num] return_str += "%s at 0x%08x - 0x%08x\n" % ( cu.mem_size_to_string(heap_size), heap_start, heap_end ) total_size += heap_size return_str += "%-15s : " % "Total size" + cu.mem_size_to_string(total_size) return return_str
def get_watermarks(self): """Displays the memory statistics. Shows the minimum available memory for the total, the free and the minimum free memories. """ total_size, current_free, min_free, pools_statistic = \ self.ret_get_watermarks() output_str = "" for pool_statistic in pools_statistic: output_str += ( "pools with size %2d words, total size, %3d blocks\n" % (pool_statistic[0], pool_statistic[1][0])) output_str += ( "pools with size %2d words, current free, %3d blocks\n" % (pool_statistic[0], pool_statistic[1][1])) output_str += ( "pools with size %2d words, minimum free, %3d blocks\n" % (pool_statistic[0], pool_statistic[1][2])) output_str += "\n" output_str += ("entire pool memory, total size, " + cu.mem_size_to_string(total_size * Arch.addr_per_word) + "\n") output_str += ( "entire pool memory, current free, " + cu.mem_size_to_string(current_free * Arch.addr_per_word) + "\n") output_str += ("entire pool memory, minimum free, " + cu.mem_size_to_string(min_free * Arch.addr_per_word) + "\n") # use output_raw to keep the spaces. self.formatter.output_raw(output_str)
def _get_free_space(self): """Get total size of free blocks. This method reads the free blocks for all heaps and returns a string which contains a list with the total size of those free blocks. """ # Look up the debug information. self._lookup_debuginfo() output_str = "" total_size = 0 for heap_num in range(self.max_num_heaps): (available, heap_size, heap_start, _, heap_free_start) = \ self._get_heap_property(heap_num) if available: free_blocks = self._free_blocks(heap_free_start, heap_start, heap_size, memory_type=self.memory_type) # display the heap name output_str += "%-15s : " % self.heap_names[heap_num] free_block_size = free_blocks.total_size if self.pmalloc_debug_enabled: # Two words are used for guard. free_block_size -= 2 * Arch.addr_per_word output_str += cu.mem_size_to_string(free_block_size) total_size += free_block_size output_str += "\n" output_str += "%-15s : %s\n" % ("Total size", cu.mem_size_to_string(total_size)) return output_str
def _get_heap_config_str(self, processor_number): """Get string representation of the heap configurations. In other words is the to string function for processor configuration. Args: processor_number Returns: processor configuration string. """ return_str = "" total_size = 0 for heap_num in range(self.max_num_heaps): (available, heap_size, heap_start, heap_end) = \ self._get_heap_config(processor_number, heap_num) if available: return_str += "%-15s : " % self.heap_names[heap_num] return_str += "%s at 0x%08x - 0x%08x\n" % ( cu.mem_size_to_string(heap_size), heap_start, heap_end) total_size += heap_size return_str += "%-15s : %s" % ("Total size", cu.mem_size_to_string(total_size)) return return_str
def overview(self): """ @brief This method displays an overview of the available heaps. @param[in] self Pointer to the current object """ output_str = self._get_overview_str(detailed=True) self.formatter.section_start( 'Heap %s memory usage' % (self.memory_type.upper()) ) # use output_raw to keep the spaces. # display memory used by patches for PM Heap if self.memory_type.upper() == "PM": try: patch_analysis = self.interpreter.get_analysis("patches", self.chipdata.processor) if patch_analysis.get_patch_level() > 0: patch_address_start = self.debuginfo.get_constant_strict( '$PM_RAM_P0_CODE_START' ).value self.formatter.output_raw( "\nPatch size : " + cu.mem_size_to_string(patch_analysis.get_patch_size(), "o") + " at address: 0x{0:0>8x}".format(patch_address_start) + "\n" ) except KeyError: # Patch analysis is not released to customers. pass self.formatter.output_raw(output_str) self.formatter.section_end()
def _get_overview_str(self, detailed=True): """ @brief This method returns an overview string of the available heaps. This is a helper method. @param[in] self Pointer to the current object @param[in] detailed If set to True, a detailed view is provided. """ total_heap, free_heap, min_free_heap = self.ret_get_watermarks() output_str = "" output_str += ( "%s heap total size :\n" % (self.memory_type.upper()) ) if detailed: config_str = self._get_heap_config_str(self.chipdata.processor) # add indentation for a nicer view. output_str += cu.add_indentation(config_str, 2) + "\n" else: watermark_str = "%-15s : " % "from config" watermark_str += cu.mem_size_to_string(total_heap) output_str += cu.add_indentation(watermark_str, 2) + "\n" output_str += ( "%s heap current free:\n" % (self.memory_type.upper()) ) if detailed: free_space_str = self._get_free_space() output_str += cu.add_indentation(free_space_str, 2) if free_heap != -1: watermark_str = "%-15s : " % "from watermarks" watermark_str += cu.mem_size_to_string(free_heap) else: watermark_str = "Watermarks not available for this heap!" output_str += cu.add_indentation(watermark_str, 2) + "\n" output_str += ( "%s heap minimum free:\n" % (self.memory_type.upper()) ) if min_free_heap != -1: watermark_str = "%-15s : " % "from watermarks" watermark_str += cu.mem_size_to_string(min_free_heap) else: watermark_str = "Watermarks not available for this heap!" output_str += cu.add_indentation(watermark_str, 2) + "\n" return output_str
def get_watermarks(self): """ @brief Returns the minimum available memory for the total, the free and the minimum free memories. @param[in] self Pointer to the current object """ total_heap, free_heap, min_free_heap = self.ret_get_watermarks() output_str = "" output_str += ("entire heap memory, total size, " + cu.mem_size_to_string(total_heap) + "\n") output_str += ("entire heap memory, current free, " + cu.mem_size_to_string(free_heap) + "\n") output_str += ("entire heap memory, minimum free, " + cu.mem_size_to_string(min_free_heap) + "\n") # use output_raw to keep the spaces. self.formatter.output_raw(output_str)
def analyse_patch_size(self): """Display the memory used by patches.""" patch_address_start = self.debuginfo.get_constant_strict( '$PM_RAM_P0_CODE_START').value self.formatter.output( "Patch size : " + cu.mem_size_to_string(self.get_patch_size(), "o") + " at address: 0x{0:0>8x}".format(patch_address_start))
def get_watermarks(self): """ @brief Same as get_watermarks, but it will return values rather than print outs. @param[in] self Pointer to the current object @param[out] List with the heap usage + pools statistic. """ total_heap, free_heap, min_free_heap = self.ret_get_watermarks() output_str = "" output_str += ("entire heap memory, total size, " + cu.mem_size_to_string(total_heap) + "\n") output_str += ("entire heap memory, current free, " + cu.mem_size_to_string(free_heap) + "\n") output_str += ("entire heap memory, minimum free, " + cu.mem_size_to_string(min_free_heap) + "\n") # use output_raw to keep the spaces. self.formatter.output_raw(output_str)
def _get_overview_str(self, detailed=True): """Gets Overview string of the available heaps. Args: detailed (bool, optional): If set to True, a detailed view is provided. """ total_heap, free_heap, min_free_heap = self.ret_get_watermarks() output_str = "" output_str += ("%s heap total size :\n" % (self.memory_type.upper())) if detailed: config_str = self._get_heap_config_str(self.chipdata.processor) # add indentation for a nicer view. output_str += cu.add_indentation(config_str, 2) + "\n" else: watermark_str = "%-15s : " % "from config" watermark_str += cu.mem_size_to_string(total_heap) output_str += cu.add_indentation(watermark_str, 2) + "\n" output_str += ("%s heap current free:\n" % (self.memory_type.upper())) if detailed: free_space_str = self._get_free_space() output_str += cu.add_indentation(free_space_str, 2) if free_heap != -1: watermark_str = "%-15s : " % "from watermarks" watermark_str += cu.mem_size_to_string(free_heap) else: watermark_str = "Watermarks not available for this heap!" output_str += cu.add_indentation(watermark_str, 2) + "\n" output_str += ("%s heap minimum free:\n" % (self.memory_type.upper())) if min_free_heap != -1: watermark_str = "%-15s : " % "from watermarks" watermark_str += cu.mem_size_to_string(min_free_heap) else: watermark_str = "Watermarks not available for this heap!" output_str += cu.add_indentation(watermark_str, 2) + "\n" return output_str
def _alloc_blocks(self, heap_address, heap_size, memory_type="dm"): """ @brief Reads and checks the allocated blocks. @param[in] self Pointer to the current object @param[in] heap_address The heap start address @param[in] heap_size The heap size. @param[out] Returns two lists. One for the heap allocations the other for debug information. """ magic_val = 0xabcd01 alloc_info = [] debug_info = [] (heap_data, magic_offset) = self._get_heap_and_magic_offset( heap_address, heap_size, memory_type ) total = 0 # here index is the index of the magic word in heap_data. Since in # heap_pm we are working with 32-bit words and not strictly addresses, # for start, index should actually be # -Arch.addr_per_word/Arch.arrd_per_word, which is -1 index = -1 # Search through the entire heap block, looking for allocated blocks # based on the presence of the magic word while True: try: index = index + heap_data[index + 1:].index(magic_val) + 1 address = heap_address + \ (index - magic_offset) * Arch.addr_per_word (length, magic, owner_hint) = \ self._read_alloc_block(address, memory_type) if magic != magic_val: raise ct.AnalysisError( "Magic word not found at expected offset." ) # Check if we are still in valid region if (length > 0) and \ (address + length < heap_address + heap_size): alloc_info.append( "Allocated block size : " + cu.mem_size_to_string(length, "o") + " at address: 0x{0:0>8x}".format(address) ) index = index + length // Arch.addr_per_word total = total + length if self.pmalloc_debug_enabled: debug_info.append( "Ptr: 0x{0:0>8x} size: ".format(address) + cu.mem_size_to_string(length, "o") + " allocated by: {0:s}".format(owner_hint) ) except ValueError: break alloc_info.append( "Total heap allocation : " + cu.mem_size_to_string(total, "ow") ) return alloc_info, debug_info
def _free_blocks(self, address, heap_start, heap_size, memory_type="dm"): """ @brief Checks the free blocks. @param[in] self Pointer to the current object @param[in] address Address to start with. @param[out] 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": freeblock = self.chipdata.cast(address, 'mem_node') freeblock_size = freeblock.get_member('length').value 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 ct.FatalAnalysisError( "Memory type %s not recognised." % memory_type ) # verify if the address is valid if self.is_address_valid(address): # and if the list node belongs to the current analysed heap display info if (address >= heap_start) and \ (address <= (heap_start + heap_size)): 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 ct.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)
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)