def _set_register_long_name(self, reg, reg_node):
     long_name_node = reg_node.find("./reg_long_name")
     if long_name_node is not None:
         reg.long_name = long_name_node.text
         logger.debug("long_name = " + reg.long_name)
     else:
         logger.warn(str(reg.name) + " long_name attribute not found")
Example #2
0
    def _generate_register_set(self, outfile, reg):
        """
        Generate a C function that writes the given register
        """

        if not reg.is_writeable():
            return

        rname = reg.name.lower()
        prefix = self._register_function_prefix(reg)
        suffix = config.register_write_function
        size_type = self._register_size_type(reg)

        gadget = self.gadgets["shoulder.c.function_definition"]
        gadget.name = prefix + "_" + rname + "_" + suffix
        gadget.return_type = "void"
        gadget.args = [(size_type, "val")]

        if reg.access_mechanisms["msr_register"]:
            am = reg.access_mechanisms["msr_register"][0]
            if config.encoded_functions:
                self._generate_aarch64_encoded_set(outfile, reg, am)
            else:
                self._generate_msr_register_set(outfile, reg, am)

        elif reg.access_mechanisms["mcr"]:
            am = reg.access_mechanisms["mcr"][0]
            self._generate_mcr_set(outfile, reg, am)

        elif reg.access_mechanisms["mcrr"]:
            gadget.args = [("uint64_t", "val")]

            am = reg.access_mechanisms["mcrr"][0]
            self._generate_mcrr_set(outfile, reg, am)

        elif reg.access_mechanisms["msr_banked"]:
            am = reg.access_mechanisms["msr_banked"][0]
            self._generate_msr_banked_set(outfile, reg, am)

        elif reg.access_mechanisms["vmsr"]:
            am = reg.access_mechanisms["vmsr"][0]
            self._generate_vmsr_set(outfile, reg, am)

        elif reg.access_mechanisms["str"]:
            am = reg.access_mechanisms["str"][0]
            if not reg.is_readable():
                self._generate_external_constants(outfile, reg, am)
            self._generate_str_set(outfile, reg, am)

        elif reg.access_mechanisms["msr_immediate"]:
            msg = "MSRimmediate access mechanism not supported for register {r}"
            logger.warn(msg.format(r=reg.name.lower()))

        else:
            msg = "Failed to generate {f} function for writeable register {r}"
            msg = msg.format(f=config.register_write_function,
                             r=reg.name.lower())
            logger.error(msg)
Example #3
0
    def generate(self, regs, outpath):
        try:
            outfile_path = os.path.abspath(os.path.join(outpath, "shoulder.h"))
            logger.info("Generating C Header: " + str(outfile_path))

            regs = transforms["remove_reserved_0"].transform(regs)
            regs = transforms["remove_reserved_1"].transform(regs)
            regs = transforms["remove_reserved_sign_extended"].transform(regs)
            regs = transforms["remove_implementation_defined"].transform(regs)
            regs = transforms["special_to_underscore"].transform(regs)
            regs = transforms["remove_redundant_am"].transform(regs)
            regs = transforms["remove_redundant_fields"].transform(regs)
            regs = transforms["unique_fieldset_names"].transform(regs)

            regs = filters["no_access_mechanism"].filter_exclusive(regs)

            if config.encoded_functions:
                msg = "Encoded accessors are only supported for aarch64 "
                msg += "registers (aarch32 and external not supported)"
                logger.warn(msg)
                regs = filters["aarch64"].filter_inclusive(regs)

            self.gadgets["shoulder.header_depends"].includes = [
                "<stdint.h>", "aarch32_gcc_accessor_macros.h",
                "aarch64_gcc_accessor_macros.h"
            ]

            unique = []
            for reg in regs:
                external_mechs = reg.access_mechanisms["ldr"] + \
                                 reg.access_mechanisms["str"]
                for mech in external_mechs:
                    if mech.component not in unique:
                        unique.append(mech.component)
            self.gadgets["shoulder.external_component"].components = unique

            with open(outfile_path, "w") as outfile:
                self._generate(outfile, regs)

        except Exception as e:
            msg = "{g} failed to generate output {out}: {exception}".format(
                g=str(type(self).__name__), out=outpath, exception=e)
            raise ShoulderGeneratorException(msg)
Example #4
0
    def _set_register_purpose(self, reg, reg_node):
        purpose_text_nodes = reg_node.findall("./reg_purpose/purpose_text")
        if len(purpose_text_nodes) == 1:
            purpose_node = reg_node.find("./reg_purpose/purpose_text/para")
            if purpose_node is not None:
                ET.strip_tags(purpose_node, "arm-defined-word",
                              "register_link")
                reg.purpose = purpose_node.text
                reg.purpose = reg.purpose.replace("\n", " ")
        elif len(purpose_text_nodes) > 1:
            text = "See the ARMv8 architecture reference manual for a "
            text += "description of this register"
            reg.purpose = text
            reg.purpose = reg.purpose.replace("\n", " ")

        if reg.purpose is not None:
            logger.debug("purpose = " + reg.purpose)
        else:
            logger.warn(str(reg.name) + " purpose attribute not found")
    def _set_register_access_attributes(self, reg, reg_node):
        access_mechanism_nodes = reg_node.findall(
            "./access_mechanisms/access_mechanism")
        for mechanism in access_mechanism_nodes:
            if mechanism is not None:
                accessor = str(mechanism.attrib["accessor"])
                operation = accessor.split(' ', 1)[0]
                if operation == "MSR" or operation == "MSRregister":
                    reg.is_writable = True
                if reg.access_attributes is None:
                    access_attributes = AccessAttributes()
                    if operation.startswith("MR"):
                        access_attributes.mnemonic = accessor.split(' ', 1)[1]

                    encoding_nodes = mechanism.findall("encoding/enc")
                    for enc in encoding_nodes:
                        name = str(enc.attrib["n"])
                        try:
                            val = int(enc.attrib["v"], 2)
                        except:
                            logger.warn(
                                "Could not parse access attribute value " +
                                str(enc.attrib["v"]) + " for register " +
                                reg.name)
                            continue

                        if name == "op0":
                            access_attributes.op0 = val
                        elif name == "op1":
                            access_attributes.op1 = val
                        elif name == "op2":
                            access_attributes.op2 = val
                        elif name == "CRn":
                            access_attributes.crn = val
                        elif name == "CRm":
                            access_attributes.crm = val

                    if access_attributes.is_valid():
                        reg.access_attributes = access_attributes
            else:
                logger.warn(
                    str(reg.name) + " access_mechanism attribute not found")

        if reg.access_attributes is None:
            logger.warn(str(reg.name) + " access attributes not found")
Example #6
0
    def parse_file(self, path):
        registers = []

        try:
            etree = ET.parse(path)
            root_node = etree.getroot()
            registers_node = root_node.findall("./registers/register")
            reg_count = len(registers_node)
            msg = type(self).__name__ + ": processing " + str(reg_count)
            msg += " register " if reg_count == 1 else " registers "
            msg += "from " + str(path)
            logger.debug(msg)

            for reg_node in registers_node:
                if (str(reg_node.attrib["is_register"]) == "True"):
                    logger.debug("Register Attributes:")

                    reg = shoulder.model.armv8a.ARMv8ARegister()
                    self._set_register_name(reg, reg_node)

                    if "<n>" in reg.name:
                        array_start_node = reg_node.find(
                            "./reg_array/reg_array_start")
                        array_end_node = reg_node.find(
                            "./reg_array/reg_array_end")

                        if array_start_node is None or array_end_node is None:
                            logger.warn("Unbounded n-index register " +
                                        str(reg.name))
                            continue

                        array_start = int(array_start_node.text)
                        array_end = int(array_end_node.text)

                        # TODO: Figure out better way to identify long
                        # memory-mapped registers and access them with an
                        # offset
                        if ((array_end - array_start) > 32):
                            logger.warn("Excessively large n-index register " +
                                        str(reg.name))
                            continue

                        for n in range(array_start, array_end + 1):
                            n_reg = shoulder.model.armv8a.ARMv8ARegister()
                            self._set_register_name(n_reg, reg_node)
                            self._set_register_long_name(n_reg, reg_node)
                            self._set_register_execution_state(n_reg, reg_node)
                            self._set_register_attributes(n_reg, reg_node)
                            self._set_register_access_mechanisms(
                                n_reg, reg_node, n)
                            self._set_register_purpose(n_reg, reg_node)
                            self._set_register_size(n_reg, reg_node)
                            self._set_register_fields(n_reg, reg_node)

                            n_reg.name = n_reg.name.replace("<n>", str(n))
                            for fs in n_reg.fieldsets:
                                for f in fs.fields:
                                    f.name = f.name.replace("<n>", str(n))

                            registers.append(n_reg)
                    else:
                        self._set_register_long_name(reg, reg_node)
                        self._set_register_execution_state(reg, reg_node)
                        self._set_register_attributes(reg, reg_node)
                        self._set_register_access_mechanisms(reg, reg_node)
                        self._set_register_purpose(reg, reg_node)
                        self._set_register_size(reg, reg_node)
                        self._set_register_fields(reg, reg_node)
                        registers.append(reg)

        except Exception as e:
            msg = "Failed to parse register file " + str(path)
            msg += ": " + str(e)
            raise ShoulderParserException(msg)

        return registers
Example #7
0
    def _set_register_access_mechanisms(self, reg, reg_node, n=0):
        # Memory mapped access mechanisms
        reg_address_nodes = reg_node.findall("./reg_address")
        offsets = set()
        for node in reg_address_nodes:
            component_node = node.find("./reg_component")
            component = str(component_node.text).lower()
            component = component.replace(" ", "_")
            component = component.replace(".", "_")

            offset_node = node.find("./reg_offset/hexnumber")
            offset = int(offset_node.text, 0)
            offsets.add(offset)

            access_type_nodes = node.findall(
                "./reg_access/reg_access_state/reg_access_type")
            access_types = set()
            for access_type_node in access_type_nodes:
                access_type = access_type_node.text
                access_types.add(access_type)

            readable_types = set(
                ["RO", "RW", "WI", "IMPDEF", "RO or RW", "RAZ/WI"])
            writable_types = set(["RW", "WO", "RO or RW", "IMPDEF"])

            if access_types & readable_types:
                am = shoulder.model.armv8a.access_mechanism.LDR(
                    component, offset)
                reg.access_mechanisms["ldr"].append(am)

            if access_types & writable_types:
                am = shoulder.model.armv8a.access_mechanism.STR(
                    component, offset)
                reg.access_mechanisms["str"].append(am)

        # Instruction based access mechanisms
        access_mechanism_nodes = reg_node.findall(
            "./access_mechanisms/access_mechanism")
        for access_mechanism_node in access_mechanism_nodes:
            try:
                accessor = str(access_mechanism_node.attrib["accessor"])
                operation = accessor.split(' ', 1)[0]
                operand = accessor.split(' ', 1)[1]

                encoding_nodes = access_mechanism_node.findall("encoding/enc")
                encoding = {}
                for enc in encoding_nodes:
                    name = str(enc.attrib["n"]).lower()
                    try:
                        val = int(enc.attrib["v"], 2)
                    except ValueError:
                        strval = str(enc.attrib["v"])
                        n_field_strings = re.findall("\[n:\d+:\d+]", strval)
                        for n_string in n_field_strings:
                            n_trim = n_string[1:-1]
                            msb = int(n_trim.split(":")[1])
                            lsb = int(n_trim.split(":")[2])
                            replacement = ""
                            for i in range(lsb, msb + 1):
                                if ((1 << i) & n):
                                    replacement = "1" + replacement
                                else:
                                    replacement = "0" + replacement
                            strval = strval.replace(n_string, replacement)

                        n_bit_strings = re.findall("\[n:\d+]", strval)
                        for n_string in n_bit_strings:
                            n_trim = n_string[1:-1]
                            bit = int(n_trim.split(":")[1])
                            n_bit = bin(((1 << bit) & n) >> bit)
                            strval = strval.replace(n_string, str(n_bit)[2:])

                        n_strings = re.findall("n+", strval)
                        for n_string in n_strings:
                            num_bits = len(n_string)
                            replacement = ""
                            for i in range(num_bits):
                                if ((1 << i) & n):
                                    replacement = "1" + replacement
                                else:
                                    replacement = "0" + replacement
                            strval = strval.replace(n_string, replacement)

                        val = int(strval, 2)
                        operand = operand.replace("<n>", str(n))
                    encoding[name] = val

                if operation == "MSRregister":
                    am = shoulder.model.armv8a.access_mechanism.MSRRegister(
                        encoding["op0"],
                        encoding["op1"],
                        encoding["op2"],
                        encoding["crn"],
                        encoding["crm"],
                        operand,
                        rt=0b0)
                    reg.access_mechanisms["msr_register"].append(am)

                elif operation == "MSRbanked":
                    am = shoulder.model.armv8a.access_mechanism.MSRBanked(
                        encoding["m"], encoding["r"], encoding["m1"], operand)
                    reg.access_mechanisms["msr_banked"].append(am)

                elif operation == "MSRimmediate":
                    am = shoulder.model.armv8a.access_mechanism.MSRImmediate(
                        encoding["crn"], encoding["op0"], encoding["op1"],
                        encoding["op2"], operand)
                    reg.access_mechanisms["msr_immediate"].append(am)

                elif operation == "MRS":
                    am = shoulder.model.armv8a.access_mechanism.MRSRegister(
                        encoding["op0"],
                        encoding["op1"],
                        encoding["op2"],
                        encoding["crn"],
                        encoding["crm"],
                        operand,
                        rt=0b0)
                    reg.access_mechanisms["mrs_register"].append(am)

                elif operation == "MRSbanked":
                    am = shoulder.model.armv8a.access_mechanism.MRSBanked(
                        encoding["m"], encoding["r"], encoding["m1"], operand)
                    reg.access_mechanisms["mrs_banked"].append(am)

                elif operation == "MCR":
                    am = shoulder.model.armv8a.access_mechanism.MCR(
                        encoding["coproc"], encoding["opc1"], encoding["opc2"],
                        encoding["crn"], encoding["crm"])
                    reg.access_mechanisms["mcr"].append(am)

                elif operation == "MCRR":
                    am = shoulder.model.armv8a.access_mechanism.MCRR(
                        encoding["coproc"], encoding["opc1"], encoding["crm"])
                    reg.access_mechanisms["mcrr"].append(am)

                elif operation == "MRC":
                    am = shoulder.model.armv8a.access_mechanism.MRC(
                        encoding["coproc"], encoding["opc1"], encoding["opc2"],
                        encoding["crn"], encoding["crm"])
                    reg.access_mechanisms["mrc"].append(am)

                elif operation == "MRRC":
                    am = shoulder.model.armv8a.access_mechanism.MRRC(
                        encoding["coproc"], encoding["opc1"], encoding["crm"])
                    reg.access_mechanisms["mrrc"].append(am)

                elif operation == "VMRS":
                    am = shoulder.model.armv8a.access_mechanism.VMRS(
                        encoding["reg"], operand)
                    reg.access_mechanisms["vmrs"].append(am)

                elif operation == "VMSR":
                    am = shoulder.model.armv8a.access_mechanism.VMSR(
                        encoding["reg"], operand)
                    reg.access_mechanisms["vmsr"].append(am)

                else:
                    msg = "Invalid operation " + operation
                    msg += " in register " + reg.name
                    raise ShoulderParserException(msg)

                logger.debug(str(am))

            except Exception as e:
                msg = "Could not parse " + str(operation) + " access mechanism"
                msg += " in register " + reg.name + ":"
                logger.warn(msg)
                logger.warn("\t" + str(e))
                continue