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