| 102 | |
| 103 | |
| 104 | def build_flow(code) -> list[Flow]: |
| 105 | flow_data = list() |
| 106 | |
| 107 | assert code[0].startswith("/*"), "Assembly is not in doldisasm format!" |
| 108 | assert len(code[0]) > 37, "Assembly is not in doldisasm format!" |
| 109 | |
| 110 | tokens = trim_inst(code[0]).split() |
| 111 | assert len(tokens) != 0, "Assembly is not in doldisasm format!" |
| 112 | assert tokens[0].startswith( |
| 113 | "cmp"), "Assembly does not begin with compare instruction!" |
| 114 | |
| 115 | branches = list() |
| 116 | cmp = CompareInst.NONE |
| 117 | imm = 0 |
| 118 | addr = 0 |
| 119 | for line in code: |
| 120 | if not line.startswith("/*"): |
| 121 | continue |
| 122 | |
| 123 | tokens = trim_inst(line).split() |
| 124 | |
| 125 | # Build flow |
| 126 | if tokens[0].startswith("cmp"): |
| 127 | # Existing flow |
| 128 | if cmp != CompareInst.NONE: |
| 129 | flow_data.append(Flow(addr, cmp, imm, branches.copy())) |
| 130 | cmp = CompareInst.NONE |
| 131 | imm = 0 |
| 132 | branches.clear() |
| 133 | if tokens[0] == "cmplwi": |
| 134 | addr = int(line.split()[1], 16) |
| 135 | imm = parse_imm(tokens[2]) + 2**32 |
| 136 | cmp = CompareInst.IMM_LOGICAL |
| 137 | elif tokens[0] == "cmpwi": |
| 138 | addr = int(line.split()[1], 16) |
| 139 | imm = parse_imm(tokens[2]) |
| 140 | cmp = CompareInst.IMM |
| 141 | else: |
| 142 | assert False, "Non-imm comparison not supported" |
| 143 | # Build branches |
| 144 | elif tokens[0].startswith("b"): |
| 145 | opcode = tokens[0].replace("-", "").replace("+", "") |
| 146 | if opcode in BRANCH_OPCODE_TO_ENUM: |
| 147 | tokens[1] = tokens[1].replace(".L_", "lbl_") |
| 148 | branches.append( |
| 149 | Branch(BRANCH_OPCODE_TO_ENUM[opcode], tokens[1])) |
| 150 | else: |
| 151 | assert False, f"Non supported branch instruction: {opcode}" |
| 152 | |
| 153 | # Append last flow |
| 154 | flow_data.append(Flow(addr, cmp, imm, branches.copy())) |
| 155 | return flow_data |
| 156 | |
| 157 | |
| 158 | def traverse_flow(flow_group, value) -> Case: |