def _update_table(self): """ @brief Internal method used for updatign the capability table. """ if not self.ptr_table_address: return new_table_address = self.chipdata.get_data(self.ptr_table_address) if new_table_address != 0: self.table_address = new_table_address new_identify_field = self.chipdata.get_data(self.table_address) if new_identify_field != 0: new_num_of_entries = self.chipdata.get_data( self.table_address + Arch.addr_per_word) else: new_num_of_entries = 0 else: new_identify_field = self.identify_field new_num_of_entries = self.num_of_entries if (self.table_address != new_table_address) or \ (self.identify_field != new_identify_field) or \ (self.num_of_entries != new_num_of_entries): self.identify_field = new_identify_field self.num_of_entries = new_num_of_entries self.entries = [] self.file_id_dict = {} curr_address = self.table_address + 2 * Arch.addr_per_word # Start of the entries to the table for _ in range(self.num_of_entries): data_vals = list( self.chipdata.get_data(curr_address, 4 * Arch.addr_per_word)) # Read 4 words # When pointing in the PM region, bit 31 is a flag that always # set. However after kerelfreader reads downloaded capability # data, this flag is removed, thus we mask it here # before adding new entry to a table try: Arch.get_pm_region(data_vals[0]) data_vals[2] &= 0x7FFFFFFF except Arch.NotPmRegion: # StandardError occurred thus it means that we are not in # PM region and masking is not required pass entry = MappedTableEntry(data_vals[0], data_vals[1], data_vals[2], data_vals[3]) # For each elf_id (data_vals[3]) try to load the elf by searching # the path for the elf id in the file "elf_id_mapped_to_elf_path.json" self.load_bundle_from_internal_builds(data_vals[3]) if entry.file_id not in list(self.file_id_dict.keys()): self.file_id_dict[entry.file_id] = [] self.file_id_dict[entry.file_id].append(entry) self.entries.append(entry) curr_address += 4 * Arch.addr_per_word self.checksum = self.chipdata.get_data(curr_address)
def get(self, identifier, elf_id=None, datalen=None): """ Get a variable, register or range of addresses. 'identifier' can be an address, or the name of a register or variable (note constant names are not handled). If it's a name, we attempt to find the closest match in our lists of registers and variables. However, please note that there is a 'search' function to conduct searches, i.e. search('*[IDENTIFIER]*'), and it's advised to use that instead of 'get'. If the identifier is ambiguous, an AmbiguousSymbolError exception may be thrown. Like `get_var`, it's also possible to pass in a data length to request a slice of data (this only makes sense for things in DM). Obviously there are things that could go wrong here, especially if the user passes in a random number and we try to guess what it points to. That's why we only provide this function in Interactive mode! Args: identifier: Could be name or address elf_id: The bundle elf id if the variable is in a downloadable capability. datalen: If the identifier is an address the data length is specified by this input. Returns: a DataSym (which may be a Variable) or a SourceInfo (if a code address was supplied). """ pm_addr = None reg = None var = None apology = "" hit_flag = False # For Crescendo, data can only be fetched as words. Since it is # octet-addressed, the addresses must be divisible by the number of # addresses per word (32 bit words - 4 octets, therefore addresses must # be divisible by 4). if isinstance(identifier, numbers.Integral): identifier = cu.get_correct_addr(identifier, Arch.addr_per_word) # Same as above. The lengths are measured in addressable units. if datalen is not None: datalen = cu.convert_byte_len_word(datalen, Arch.addr_per_word) # Look to see whether it's an address in PM. # Since the PM range can be huge (and may overlap with DM), perform a # sanity check to avoid false positives. if (isinstance(identifier, numbers.Integral) and Arch.get_pm_region(identifier, False) in ("PMROM", "PMRAM") and datalen is None): # Is it the address of a valid instruction? try: self.debuginfo.get_instruction(identifier) except KeyError: pass else: pm_addr = self.debuginfo.get_source_info(identifier) # Look to see whether it's the name of a module in PM. This needs to # include all the fluff at the start, (i.e. '$M.foo.bar' rather than # just 'foo.bar' or 'bar') so as to avoid clashes with names in DM # space (which are more likely to be what's wanted). if isinstance(identifier, numbers.Integral): try: pm_addr = self.debuginfo.get_source_info(identifier) hit_flag = True except KeyError: pass except AmbiguousSymbolError as amb_pm: apology += str(amb_pm) + "\n" # Look to see whether it's a register. try: reg = self.get_reg(identifier) hit_flag = True except AmbiguousSymbolError as amb_reg: logger.warning( "Multiple registers found for {}. Use `search('*{}*')` to see " "the results clearer.\n".format(str(identifier), str(identifier))) apology += str(amb_reg) + "\n" # Also look to see whether it's a variable name/address. try: var = self.get_var(identifier, elf_id, datalen) hit_flag = True except AmbiguousSymbolError as amb_var: logger.warning( "Multiple variables found for {}. Use `search('*{}*')` to see " "the results clearer.\n".format(str(identifier), str(identifier))) apology += str(amb_var) + "\n" # We got at least one hit if hit_flag: if not pm_addr and not reg and not var: # We didn't find anything at all logger.warning( "Nothing was found! You can also use `search('*%s*')`.", identifier) return None elif pm_addr and not reg and not var: return pm_addr elif reg and not var and not pm_addr: return reg elif var and not reg and not pm_addr: return var else: # We got unique, valid hits for one or more of the above. apology = ( "Multiple matches found for {}. Use `search('*{}*')` to " "see the results clearer.\n".format( str(identifier), str(identifier))) # If we get here then we couldn't resolve ambiguous symbols in one or # more cases. Note any genuine match of the other types as well. if pm_addr: apology += " code address in module " + pm_addr.module_name + "\n" if var: apology += " variable " + var.name + "\n" if reg: apology += " register " + reg.name + "\n" raise AmbiguousSymbolError(apology)
def get(self, identifier, elf_id=None, datalen=None): """ @brief A 'smart' lookup funtion. 'identifier' can be an address, or the name of a register or variable (note constant names are not handled). If it's a name, we attempt to find the closest match in our lists of registers and variables. If the identifier is ambiguous, an AmbiguousSymbol exception may be thrown. Like get_var, it's also possible to pass in a data length to request a slice of data (this only makes sense for things in DM). Returns a DataSym (which may be a Variable) or a SourceInfo (if a code address was supplied). Obviously there are things that could go wrong here, especially if the user passes in a random number and we try to guess what it points to. That's why we only provide this function in Interactive mode! @param[in] self Pointer to the current object @param[in] identifier Could be name or address @param[in] elf_id The bundle elf id if the variable is in a downloadable capability. @param[in] datalen If the identifier is an address the data length is specified by this input. """ pm_addr = None reg = None var = None apology = "" hit_flag = False # For Crescendo, data can only be fetched as words. Since it is # octet-addressed, the addresses must be divisible with the number of # addresses per word (32 bit words - 4 octets, therefore addresses must # be divisble with 4). if isinstance(identifier, cu.INTEGERS): identifier = cu.get_correct_addr(identifier, Arch.addr_per_word) # Same as above. The lengths are measured in addressable units. if datalen is not None: datalen = cu.convert_byte_len_word(datalen, Arch.addr_per_word) # Look to see whether it's an address in PM. # Since the PM range can be huge (and may overlap with DM), perform a # sanity check to avoid false positives. if isinstance(identifier, cu.INTEGERS) and \ (Arch.get_pm_region(identifier, False) == "PMROM" or \ Arch.get_pm_region(identifier, False) == "PMRAM") and \ datalen is None: # Is it the address of a valid instruction? try: _ = self.debuginfo.get_instruction(identifier) except KeyError: pass else: pm_addr = self.debuginfo.get_source_info(identifier) # Look to see whether it's the name of a module in PM. This needs to # include all the fluff at the start, (i.e. '$M.foo.bar' rather than # just 'foo.bar' or 'bar') so as to avoid clashes with names in DM # space (which are more likely to be what's wanted). if isinstance(identifier, cu.INTEGERS): try: pm_addr = self.debuginfo.get_source_info(identifier) hit_flag = True except KeyError: pass except ct.AmbiguousSymbol as amb_pm: apology += str(amb_pm) + "\n" # Look to see whether it's a register. try: reg = self.get_reg(identifier) hit_flag = True except ct.AmbiguousSymbol as amb_reg: apology += str(amb_reg) + "\n" # Also look to see whether it's a variable name/address. try: var = self.get_var(identifier, elf_id, datalen) hit_flag = True except ct.AmbiguousSymbol as amb_var: apology += str(amb_var) + "\n" # We got at least one hit if hit_flag: if not pm_addr and not reg and not var: # We didn't find anything at all return None elif pm_addr and not reg and not var: return pm_addr elif reg and not var and not pm_addr: return reg elif var and not reg and not pm_addr: return var else: # We got unique, valid hits for one or more of the above. apology = "Multiple potential matches found for identifier '" + \ str(identifier) + "': \n" # If we get here then we couldn't resolve ambiguous symbols in one or more cases. # Note any genuine match of the other types as well. if pm_addr: apology += " code address in module " + pm_addr.module_name + "\n" if var: apology += " variable " + var.name + "\n" if reg: apology += " register " + reg.name + "\n" raise ct.AmbiguousSymbol(apology)