Esempio n. 1
0
    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)
Esempio n. 3
0
    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)