def reg_field_index(self, line: Line) -> RegisterFieldIndex: operand1, operand2 = line.split_operands() reg = Register(operand1) if not reg.is_valid(): raise RegisterInvalidError field = self.field_index(operand2) return RegisterFieldIndex(line, reg, field)
def reg_branch(self, line: Line) -> RegisterBranch: operand1, operand2 = line.split_operands() reg = Register(operand1) if not reg.is_valid(): raise RegisterInvalidError branch = self.get_branch(operand2) return RegisterBranch(line, reg, branch)
def aaget(self, node: KeyValue) -> str: address = self.vm.allocate() ecb_address = self.get_ecb_address("D1", "CE1CR") self.vm.set_value(address, ecb_address) reg = Register(node.get_value("BASEREG")) if reg.is_valid(): self.regs.set_value(address, reg) return node.fall_down
def using(self, line: Line) -> None: operands = line.split_operands() if len(operands) != 2: raise UsingInvalidError base = Register(operands[1]) if not base.is_valid(): raise UsingInvalidError dsect_name = self.name if operands[0] == '*' else operands[0] self.set_using(dsect_name, base)
def branch_condition_reg(self, line: Line) -> BranchConditionRegister: operand1, operand2 = line.split_operands() mask = self.get_value(operand1) if not 0 <= mask <= BranchGeneric.MAX_VALUE: raise ConditionMaskError reg = Register(operand2) if not reg.is_valid(): raise RegisterInvalidError return BranchConditionRegister(line, mask, reg)
def globz(self, line: Line) -> RegisterData: globc = self.key_value(line) reg = globc.get_value("REGR") or globc.get_value("REGS") or globc.get_value("REGC") base = Register(reg) if not base.is_valid(): raise RegisterInvalidError(line) self.load_macro("GLOBAL", base=reg) line.command = "LHI" return RegisterData(line, base, config.GLOBAL)
def dbred(self, node: KeyValue) -> str: self._base_sw00sr() # Setup KEY1 Primary key pky = node.get_sub_value("KEY1", "PKY") if pky is not None: key = f"{self.seg.evaluate(pky):02X}" else: key = f"{self.seg.evaluate(node.get_sub_value('KEY1', 'S')):02X}" # Set up KEY2 to KEY6 other_keys = dict() for key_number in range(2, 7): key_n = f"KEY{key_number}" if node.get_value(key_n) is None: break df_field_name = node.get_sub_value(key_n, "R") condition = node.get_sub_value(key_n, "C") sign = self.C[condition] if condition is not None else "==" field: FieldBaseDsp = node.get_sub_value(key_n, "S") if field is None: # TODO For M, D, L types raise DbredError base_address = self.regs.get_value(field.base) length = self.seg.lookup(df_field_name).length byte_array = self.vm.get_bytes(base_address + field.dsp, length) other_keys[df_field_name] = (f"{sign} {byte_array}", length) # Get the lrec ref_name = node.get_value("REF") item_number = 0 if node.get_value( "BEGIN") else self.tpfdf_ref[ref_name] item_number += 1 lrec, item_number = Tpfdf.get_lrec(ref_name, key, item_number, other_keys) self.tpfdf_ref[ref_name] = item_number # Update error_code and REG= if lrec is None or self.is_error(node.label): error_code = self.seg.evaluate("#TPFDBER") else: error_code = self.seg.evaluate("#TPFDBOK") data_address = self.regs.R3 + self.seg.evaluate("SW00KL1") self.vm.set_bytes(lrec, data_address, len(lrec)) reg = Register(node.get_value("REG")) if reg.is_valid(): self.regs.set_value(data_address, reg) self.vm.set_byte(error_code, self.regs.R3 + self.seg.evaluate("SW00RTN")) # ERROR= error_label = node.get_value("ERRORA") if error_label and self.is_error(node.label): return error_label return node.fall_down
def reg_data_field(self, line: Line) -> RegisterDataField: operand1, operand2, operand3 = line.split_operands() reg = Register(operand1) if not reg.is_valid(): raise RegisterInvalidError data = self.get_value(operand2) if not 0 <= data <= RegisterDataField.MAX_VALUE: raise DataInvalidError field = self.field_base_dsp(operand3) return RegisterDataField(line, reg, data, field)
def _get_field_by_name(self, name: str) -> FieldBaseDsp: dsp = self.get_value(name) if self.is_based(name): possible_name = next(iter(re.split(r"[+*/-]", name))) # Field type of NAME+L'NAME or NAME base = self.get_base(self.lookup( possible_name).name) if name[0] != '*' else Register('R8') name = possible_name if name[0] != '*' else 'R8_AREA' else: base = Register('R0') return FieldBaseDsp(name, base, dsp)
def mhinf(self, node: KeyValue) -> str: if node.keys[0] != "ECB": raise MhinfExecutionError reg = Register(node.get_value("REG")) if not reg.is_valid(): raise MhinfExecutionError option = node.get_value("INPTR") if option == "NAME": airline_code = self.vm.get_bytes(self.regs.get_value(reg), 2) self.set_partition(DataType("X", bytes=airline_code).decode) else: raise MhinfExecutionError return node.fall_down
def reg_data(self, line: Line) -> RegisterData: operand1, operand2 = line.split_operands() reg = Register(operand1) if not reg.is_valid(): raise RegisterInvalidError data = self.get_value(operand2) max_unsigned_value = (1 << RegisterData.DATA_LENGTH) - 1 min_signed_value = -1 << RegisterData.DATA_LENGTH - 1 max_signed_value = (1 << RegisterData.DATA_LENGTH - 1) - 1 if not min_signed_value <= data <= max_unsigned_value: raise DataInvalidError((line, data)) if data > max_signed_value: data -= max_unsigned_value + 1 # Two"s complement negative number return RegisterData(line, reg, data)
def field_index(self, operand: str) -> FieldIndex: index = Register('R0') if operand.startswith('='): label_ref = self._literal(operand[1:]) field = FieldBaseDsp(label_ref.label, self.get_base(self.name), label_ref.dsp) return FieldIndex(field, index) operand1, operand2, operand3 = self.split_operand(operand) if not operand2 and not operand3: # Single label like EBW000 field: FieldBaseDsp = self._get_field_by_name(name=operand1) elif not operand3: # Note: In TPF these types are with no base but with index register set. # In our tool we have flipped this. So there would be no index but the base would be present. if operand1.isdigit() or set("+-*").intersection(operand1): # Base_dsp 34(R5) or expression with base EBW008-EBW000(R9) field: FieldBaseDsp = self._get_field_by_base_dsp( base=operand2, dsp=operand1) else: # Label with index EBW000(R14) or EBW000(R14,) field: FieldBaseDsp = self._get_field_by_name(name=operand1) index = Register(operand2) if not index.is_valid(): raise RegisterIndexInvalidError elif not operand2: # Base_dsp with no index 10(,R5) field: FieldBaseDsp = self._get_field_by_base_dsp(base=operand3, dsp=operand1) else: # Base_dsp with index 10(R3,R5) field = self._get_field_by_base_dsp(base=operand3, dsp=operand1) index = Register(operand2) if not index.is_valid(): raise RegisterIndexInvalidError return FieldIndex(field, index)
def _capture_output(self, output: Output, last_node: InstructionType) -> None: output.messages = self.messages.copy() output.dumps.extend(self.dumps) output.last_line = last_node.label output.last_node = str(last_node) if output.debug: output.debug = self.debug.get_traces(hit=True) output.debug_missed = self.debug.get_traces(hit=False) for core in output.cores: macro_name = core.macro_name.upper() if macro_name in config.DEFAULT_MACROS: self._capture_core(core.field_data, macro_name, config.DEFAULT_MACROS[macro_name]) elif macro_name in macros: if not Register(core.base_reg).is_valid(): raise InvalidBaseRegError self._capture_core(core.field_data, macro_name, self.regs.get_unsigned_value(core.base_reg)) for reg in output.regs: output.regs[reg] = self.regs.get_value(reg) for reg in output.reg_pointers: try: output.reg_pointers[reg] = self.vm.get_bytes( self.regs.get_unsigned_value(reg), output.reg_pointers[reg]).hex().upper() except BaseAddressError: continue return
def index_to_label(self, field: FieldIndex) -> str: if field.index.reg == "R0": return field.name dsp = self.regs.get_address(field.index, field.dsp) label = self.seg.get_field_name(Register("R8"), dsp, config.INSTRUCTION_LEN_DEFAULT) return label
def branch_return(self, node: BranchConditionRegister) -> str: if node.mask & (1 << 3 - self.cc) != 0: value = self.regs.get_address(node.reg) - self.regs.R8 label = self.seg.get_field_name(Register('R8'), value, 4) else: label = node.fall_down return label
def delete_reg(self, reg: str) -> bool: if not Register(reg).is_valid(): return False if reg not in self.regs: return False del self.regs[reg] self.save() return True
def reg_label(self, line: Line) -> RegisterFieldIndex: reg_index: RegisterFieldIndex = self.reg_field_index(line) _, operand2 = line.split_operands() if operand2.startswith("*"): expression = line.label + operand2[1:] reg_index.field.dsp = self.get_value(expression) reg_index.field.base = Register("R8") reg_index.field.name = self.get_field_name(reg_index.field.base, reg_index.field.dsp, 4) return reg_index
def error_check(self, node: KeyValue) -> str: if self.is_error(node.label): field_name = node.get_value("FIELD") reg = Register(node.get_value("BASE")) address = self.regs.get_unsigned_value(reg) + self.seg.evaluate( field_name) byte_array = DataType("X", input=node.get_value("XVALUE")).to_bytes() self.vm.set_bytes(byte_array, address, len(byte_array)) return node.fall_down
def get_value(self, operand: str) -> int: if operand.isdigit(): return int(operand) updated_operand = operand.upper() data_list = re.findall(r"[CXHFDBZPAY]D?'[^']+'", updated_operand) value_list = list() if data_list: updated_operand = re.sub(r"[CXHFDBZPAY]D?'[^']+'", "~", updated_operand) for data in data_list: value = DataType(data[0], input=data[2:-1]).value value_list.insert(0, value) exp_list = re.split(r"([+*()/-])", updated_operand) if len(exp_list) == 1: if exp_list[0] == "~": return value_list.pop() return self._location_counter if exp_list[0] == "*" else self.evaluate(exp_list[0]) exp_list = [expression for expression in exp_list if expression] if len(exp_list) >= 2 and exp_list[0] == "-" and exp_list[1].isdigit(): exp_list.pop(0) exp_list[0] = f"-{exp_list[0]}" exp_list = [(index, expression) for index, expression in enumerate(exp_list)] parenthesis = [indexed_expression for indexed_expression in exp_list if indexed_expression[1] in "()"] exp_list = [indexed_expression for indexed_expression in exp_list if indexed_expression[1] not in "()"] eval_list = list() for index, (position, expression) in enumerate(exp_list): if expression in ("-", "+", "/") or (expression == "*" and index % 2 == 1): eval_list.append((position, expression)) else: if expression == "~": value = value_list.pop() elif expression == "*": value = self._location_counter elif expression.isdigit() or (expression[0] == "-" and expression[1:].isdigit()): value = expression elif Register(expression).is_valid(): value = Register(expression).value else: value = self.evaluate(expression) eval_list.append((position, str(value))) eval_list.extend(parenthesis) eval_list.sort(key=lambda item: item[0]) eval_list = [expression for _, expression in eval_list] return int(eval("".join(eval_list)))
def create_regs(self, reg_dict: dict) -> bool: if 'regs' not in reg_dict: return False self.regs = dict() for reg in reg_dict['regs']: if not Register(reg).is_valid(): return False self.regs[reg] = 0 self.save() return True
def branch_on_count_register(self, node: RegisterRegister) -> str: dsp = self.regs.get_address(node.reg2) if dsp > 0: dsp -= self.regs.R8 value = self.regs.get_value(node.reg1) - 1 self.regs.set_value(value, node.reg1) if dsp == 0 or value == 0: label = node.fall_down else: label = self.seg.get_field_name(Register('R8'), dsp, 4) return label
def drop(self, line: Line) -> None: operands = line.split_operands() registers = [Register(operand) for operand in operands] if any(not register.is_valid() for register in registers): raise DropInvalidError(line) for drop_register in registers: self._using = { macro_name: register for macro_name, register in self._using.items() if register.reg != drop_register.reg }
def add_reg(self, reg_dict: dict) -> bool: if 'reg' not in reg_dict or not Register(reg_dict['reg']).is_valid(): return False if 'value' not in reg_dict or not isinstance(reg_dict['value'], int): return False if len(reg_dict) != 2: return False if reg_dict['value'] < -0x80000000 or reg_dict['value'] > 0x7FFFFFFF: return False self.regs[reg_dict['reg']] = reg_dict['value'] self.save() return True
def reg_reg(line: Line) -> RegisterRegister: operand1, operand2 = line.split_operands() reg1 = Register(operand1) reg2 = Register(operand2) if not reg1.is_valid() or not reg2.is_valid(): raise RegisterInvalidError return RegisterRegister(line, reg1, reg2)
def _pd0_base(self, node: KeyValue) -> Optional[int]: workarea = node.get_value("WORKAREA") if workarea is None: raise Pd0BaseError if workarea[0] == "LEV": lev_parameter = workarea[1] level = lev_parameter[1] if len( lev_parameter ) == 2 and lev_parameter[0] == "D" else lev_parameter if not self._is_level_present(level): self._core_block(self.vm.allocate(), level) level = f"D{level}" level_address = self.get_ecb_address(level, "CE1CR") pd0_base = self.vm.get_value(level_address) elif workarea[0] == "REG": reg = Register(workarea[1]) if not reg.is_valid(): raise RegisterInvalidError pd0_base = self.regs.get_value(reg) else: raise Pd0BaseError return pd0_base
def pnrcc(self, node: KeyValue) -> str: action = node.get_value("ACTION") reg = Register(node.get_value("REG")) if not reg.is_valid(): raise RegisterInvalidError pnrcm_base = self.regs.get_value(reg) self.seg.load_macro("PNRCM") if self.is_error(node.label): error_code = self.seg.evaluate("#PM1ER5") self.vm.set_value(error_code, pnrcm_base + self.seg.evaluate("PM1ERR"), 1) return node.fall_down if action in ["CRLON"]: pnr_locator_bytes = self.vm.get_bytes( pnrcm_base + self.seg.evaluate("PM1LOC"), 6) pnr_locator = DataType("X", bytes=pnr_locator_bytes).decode ordinal = PnrLocator.to_ordinal(pnr_locator) self.vm.set_value(ordinal, pnrcm_base + self.seg.evaluate("PM1ORN")) self.vm.set_value(ordinal, pnrcm_base + self.seg.evaluate("PM1FAD")) return node.fall_down
def reg_reg_field(self, line: Line) -> RegisterRegisterField: operand1, operand2, operand3 = line.split_operands() reg1 = Register(operand1) reg2 = Register(operand2) if not reg1.is_valid() or not reg2.is_valid(): raise RegisterInvalidError field = self.field_base_dsp(operand3) return RegisterRegisterField(line, reg1, reg2, field)
def reg_reg_branch(self, line: Line) -> RegisterRegisterBranch: operand1, operand2, operand3 = line.split_operands() reg1 = Register(operand1) reg2 = Register(operand2) if not reg1.is_valid() or not reg2.is_valid(): raise RegisterInvalidError branch = self.get_branch(operand3) return RegisterRegisterBranch(line, reg1, reg2, branch)
def heapa(self, node: KeyValue) -> str: # REG, REF and SREF reg = Register(node.get_value("REG")) ref = node.get_value("REF") if ref is None: sref = node.get_value("SREF") if sref is None: raise HeapaExecutionError ref_bytes = self.seg.get_constant_bytes(sref, 8) ref = DataType("X", bytes=ref_bytes).decode # ERROR= for forced errors error_label = node.get_value("ERROR") if error_label and self.is_error(node.label): if reg.is_valid(): self.regs.set_value(0, reg) return error_label # HEAPA / CFCMA / EHEAPA command types command = node.keys[0] heap = self.heap["new"] if node.command == "EHEAPA" else self.heap[ "old"] if command == "ALLOCATE": address = self.vm.allocate() heap[ref] = address if reg.is_valid(): self.regs.set_value(address, reg) elif command == "LOADADD": address = heap[ref] if ref in heap else 0 if reg.is_valid(): self.regs.set_value(address, reg) if address == 0 and error_label: return error_label elif command == "FREE": heap.pop(ref, None) else: raise HeapaExecutionError return node.fall_down
def _get_field_by_base_dsp(self, base: str, dsp: str, length: Optional[int] = None) -> FieldBaseDsp: # Set base register base = Register(base) if not base.is_valid(): raise RegisterInvalidError # Set displacement dsp = self.get_value(dsp) if not 0 <= dsp <= 4095: raise FieldDspInvalidError # Set name name = base.reg + '_AREA' return FieldBaseDsp(name, base, dsp)