(self, b, stmt_loc)
return load_stmt_loc, load_stmt, load_size, stmts_to_remove, stmts_adding_base_addr, all_addr_holders
Find the location of the final Load statement that loads indirect jump targets from the jump table.
Find the location of the final Load statement that loads indirect jump targets from the jump table.
Find the location of the final Load statement that loads indirect jump targets from the jump table .
def _find_load_statement(self, b, stmt_loc):
        """
        Find the location of the final Load statement that loads indirect jump targets from the jump table.
        """

        # pylint:disable=no-else-continue

        # shorthand
        project = self.project

        # initialization
        load_stmt_loc, load_stmt, load_size = None, None, None
        stmts_to_remove = [stmt_loc]
        stmts_adding_base_addr = []  # type: list[JumpTargetBaseAddr]
        # All temporary variables that hold indirect addresses loaded out of the memory
        # Obviously, load_stmt.tmp must be here
        # if there are additional data transferring statements between the Load statement and the base-address-adding
        # statement, all_addr_holders will have more than one temporary variables
        #
        # Here is an example:
        #
        # IRSB 0x4c64c4
        #  + 06 | t12 = LDle:I32(t7)
        #  + 07 | t11 = 32Sto64(t12)
        #  + 10 | t2 = Add64(0x0000000000571df0,t11)
        #
        # all_addr_holders will be {(0x4c64c4, 11): (AddressTransferringTypes.SignedExtension, 32, 64,),
        #           (0x4c64c4, 12); (AddressTransferringTypes.Assignment,),
        #           }
        all_addr_holders = OrderedDict()

        while True:
            preds = list(b.slice.predecessors(stmt_loc))
            if len(preds) != 1:
                break
            block_addr, stmt_idx = stmt_loc = preds[0]
            block = project.factory.block(block_addr, cross_insn_opt=True, backup_state=self.base_state).vex
            if stmt_idx == DEFAULT_STATEMENT:
                # it's the default exit. continue
                continue
            stmt = block.statements[stmt_idx]
            if isinstance(stmt, (pyvex.IRStmt.WrTmp, pyvex.IRStmt.Put)):
                if isinstance(stmt.data, (pyvex.IRExpr.Get, pyvex.IRExpr.RdTmp)):
                    # data transferring
                    stmts_to_remove.append(stmt_loc)
                    if isinstance(stmt, pyvex.IRStmt.WrTmp):
                        all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Assignment,)
                    continue
                elif isinstance(stmt.data, pyvex.IRExpr.ITE):
                    # data transferring
                    #   t16 = if (t43) ILGop_Ident32(LDle(t29)) else 0x0000c844
                    # > t44 = ITE(t43,t16,0x0000c844)
                    stmts_to_remove.append(stmt_loc)
                    if isinstance(stmt, pyvex.IRStmt.WrTmp):
                        all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Assignment,)
                    continue
                elif isinstance(stmt.data, pyvex.IRExpr.Unop):
                    if stmt.data.op == 'Iop_32Sto64':
                        # data transferring with conversion
                        # t11 = 32Sto64(t12)
                        stmts_to_remove.append(stmt_loc)
                        if isinstance(stmt, pyvex.IRStmt.WrTmp):
                            all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.SignedExtension,
                                                                         32, 64)
                        continue
                    elif stmt.data.op == 'Iop_64to32':
                        # data transferring with conversion
                        # t24 = 64to32(t21)
                        stmts_to_remove.append(stmt_loc)
                        if isinstance(stmt, pyvex.IRStmt.WrTmp):
                            all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Truncation,
                                                                         64, 32)
                        continue
                    elif stmt.data.op == 'Iop_32Uto64':
                        # data transferring with conversion
                        # t21 = 32Uto64(t22)
                        stmts_to_remove.append(stmt_loc)
                        if isinstance(stmt, pyvex.IRStmt.WrTmp):
                            all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.UnsignedExtension,
                                                                         32, 64)
                        continue
                    elif stmt.data.op == 'Iop_16Uto32':
                        # data transferring wth conversion
                        stmts_to_remove.append(stmt_loc)
                        if isinstance(stmt, pyvex.IRStmt.WrTmp):
                            all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.UnsignedExtension,
                                                                         16, 32)
                        continue
                    elif stmt.data.op == 'Iop_8Uto32':
                        # data transferring wth conversion
                        stmts_to_remove.append(stmt_loc)
                        if isinstance(stmt, pyvex.IRStmt.WrTmp):
                            all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.UnsignedExtension,
                                                                         8, 32)
                        continue
                elif isinstance(stmt.data, pyvex.IRExpr.Binop):
                    if stmt.data.op.startswith('Iop_Add'):
                        # GitHub issue #1289, an S390X binary
                        # jump_label = &jump_table + *(jump_table[index])
                        #       IRSB 0x4007c0
                        #   00 | ------ IMark(0x4007c0, 4, 0) ------
                        # + 01 | t0 = GET:I32(212)
                        # + 02 | t1 = Add32(t0,0xffffffff)
                        #   03 | PUT(352) = 0x0000000000000003
                        #   04 | t13 = 32Sto64(t0)
                        #   05 | t6 = t13
                        #   06 | PUT(360) = t6
                        #   07 | PUT(368) = 0xffffffffffffffff
                        #   08 | PUT(376) = 0x0000000000000000
                        #   09 | PUT(212) = t1
                        #   10 | PUT(ia) = 0x00000000004007c4
                        #   11 | ------ IMark(0x4007c4, 6, 0) ------
                        # + 12 | t14 = 32Uto64(t1)
                        # + 13 | t8 = t14
                        # + 14 | t16 = CmpLE64U(t8,0x000000000000000b)
                        # + 15 | t15 = 1Uto32(t16)
                        # + 16 | t10 = t15
                        # + 17 | t11 = CmpNE32(t10,0x00000000)
                        # + 18 | if (t11) { PUT(offset=336) = 0x4007d4; Ijk_Boring }
                        #   Next: 0x4007ca
                        #
                        #       IRSB 0x4007d4
                        #   00 | ------ IMark(0x4007d4, 6, 0) ------
                        # + 01 | t8 = GET:I64(r2)
                        # + 02 | t7 = Shr64(t8,0x3d)
                        # + 03 | t9 = Shl64(t8,0x03)
                        # + 04 | t6 = Or64(t9,t7)
                        # + 05 | t11 = And64(t6,0x00000007fffffff8)
                        #   06 | ------ IMark(0x4007da, 6, 0) ------
                        #   07 | PUT(r1) = 0x0000000000400a50
                        #   08 | PUT(ia) = 0x00000000004007e0
                        #   09 | ------ IMark(0x4007e0, 6, 0) ------
                        # + 10 | t12 = Add64(0x0000000000400a50,t11)
                        # + 11 | t16 = LDbe:I64(t12)
                        #   12 | PUT(r2) = t16
                        #   13 | ------ IMark(0x4007e6, 4, 0) ------
                        # + 14 | t17 = Add64(0x0000000000400a50,t16)
                        # + Next: t17
                        #
                        # Special case: a base address is added to the loaded offset before jumping to it.
                        if isinstance(stmt.data.args[0], pyvex.IRExpr.Const) and \
                                isinstance(stmt.data.args[1], pyvex.IRExpr.RdTmp):
                            stmts_adding_base_addr.append(JumpTargetBaseAddr(stmt_loc, stmt,
                                                                             stmt.data.args[1].tmp,
                                                                             base_addr=stmt.data.args[0].con.value)
                                                          )
                            stmts_to_remove.append(stmt_loc)
                        elif isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp) and \
                                isinstance(stmt.data.args[1], pyvex.IRExpr.Const):
                            stmts_adding_base_addr.append(JumpTargetBaseAddr(stmt_loc, stmt,
                                                                             stmt.data.args[0].tmp,
                                                                             base_addr=stmt.data.args[1].con.value)
                                                          )
                            stmts_to_remove.append(stmt_loc)
                        elif isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp) and \
                                isinstance(stmt.data.args[1], pyvex.IRExpr.RdTmp):
                            # one of the tmps must be holding a concrete value at this point
                            stmts_adding_base_addr.append(JumpTargetBaseAddr(stmt_loc, stmt,
                                                                             stmt.data.args[0].tmp,
                                                                             tmp_1=stmt.data.args[1].tmp)
                                                          )
                            stmts_to_remove.append(stmt_loc)
                        else:
                            # not supported
                            pass
                        continue
                    elif stmt.data.op.startswith('Iop_Or'):
                        # this is sometimes used in VEX statements in THUMB mode code to adjust the address to an odd
                        # number
                        # e.g.
                        #        IRSB 0x4b63
                        #    00 | ------ IMark(0x4b62, 4, 1) ------
                        #    01 | PUT(itstate) = 0x00000000
                        #  + 02 | t11 = GET:I32(r2)
                        #  + 03 | t10 = Shl32(t11,0x01)
                        #  + 04 | t9 = Add32(0x00004b66,t10)
                        #  + 05 | t8 = LDle:I16(t9)
                        #  + 06 | t7 = 16Uto32(t8)
                        #  + 07 | t14 = Shl32(t7,0x01)
                        #  + 08 | t13 = Add32(0x00004b66,t14)
                        #  + 09 | t12 = Or32(t13,0x00000001)
                        #  + Next: t12
                        if isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp) and \
                                isinstance(stmt.data.args[1], pyvex.IRExpr.Const) and stmt.data.args[1].con.value == 1:
                            # great. here it is
                            stmts_to_remove.append(stmt_loc)
                            all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Or1, )
                            continue
                    elif stmt.data.op.startswith('Iop_Shl'):
                        # this is sometimes used when dealing with TBx instructions in ARM code.
                        # e.g.
                        #        IRSB 0x4b63
                        #    00 | ------ IMark(0x4b62, 4, 1) ------
                        #    01 | PUT(itstate) = 0x00000000
                        #  + 02 | t11 = GET:I32(r2)
                        #  + 03 | t10 = Shl32(t11,0x01)
                        #  + 04 | t9 = Add32(0x00004b66,t10)
                        #  + 05 | t8 = LDle:I16(t9)
                        #  + 06 | t7 = 16Uto32(t8)
                        #  + 07 | t14 = Shl32(t7,0x01)
                        #  + 08 | t13 = Add32(0x00004b66,t14)
                        #  + 09 | t12 = Or32(t13,0x00000001)
                        #  + Next: t12
                        if isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp) and \
                                isinstance(stmt.data.args[1], pyvex.IRExpr.Const):
                            # found it
                            stmts_to_remove.append(stmt_loc)
                            all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.ShiftLeft,
                                                                         stmt.data.args[1].con.value)
                            continue
                elif isinstance(stmt.data, pyvex.IRExpr.Load):
                    # Got it!
                    load_stmt, load_stmt_loc, load_size = stmt, stmt_loc, \
                                                          block.tyenv.sizeof(stmt.tmp) // self.project.arch.byte_width
                    stmts_to_remove.append(stmt_loc)
                    all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Assignment, )
            elif isinstance(stmt, pyvex.IRStmt.LoadG):
                # Got it!
                #
                # this is how an ARM jump table is translated to VEX
                # > t16 = if (t43) ILGop_Ident32(LDle(t29)) else 0x0000c844
                load_stmt, load_stmt_loc, load_size = stmt, stmt_loc, \
                                                      block.tyenv.sizeof(stmt.dst) // self.project.arch.byte_width
                stmts_to_remove.append(stmt_loc)

            break

        return load_stmt_loc, load_stmt, load_size, stmts_to_remove, stmts_adding_base_addr, all_addr_holders
def _find_load_statement ( self , b , stmt_loc ) : # pylint:disable=no-else-continue # shorthand project = self . project # initialization load_stmt_loc , load_stmt , load_size = None , None , None stmts_to_remove = [ stmt_loc ] stmts_adding_base_addr = [ ] # type: list[JumpTargetBaseAddr] # All temporary variables that hold indirect addresses loaded out of the memory # Obviously, load_stmt.tmp must be here # if there are additional data transferring statements between the Load statement and the base-address-adding # statement, all_addr_holders will have more than one temporary variables # # Here is an example: # # IRSB 0x4c64c4 #  + 06 | t12 = LDle:I32(t7) #  + 07 | t11 = 32Sto64(t12) #  + 10 | t2 = Add64(0x0000000000571df0,t11) # # all_addr_holders will be {(0x4c64c4, 11): (AddressTransferringTypes.SignedExtension, 32, 64,), #           (0x4c64c4, 12); (AddressTransferringTypes.Assignment,), #           } all_addr_holders = OrderedDict ( ) while True : preds = list ( b . slice . predecessors ( stmt_loc ) ) if len ( preds ) != 1 : break block_addr , stmt_idx = stmt_loc = preds [ 0 ] block = project . factory . block ( block_addr , cross_insn_opt = True , backup_state = self . base_state ) . vex if stmt_idx == DEFAULT_STATEMENT : # it's the default exit. continue continue stmt = block . statements [ stmt_idx ] if isinstance ( stmt , ( pyvex . IRStmt . WrTmp , pyvex . IRStmt . Put ) ) : if isinstance ( stmt . data , ( pyvex . IRExpr . Get , pyvex . IRExpr . RdTmp ) ) : # data transferring stmts_to_remove . append ( stmt_loc ) if isinstance ( stmt , pyvex . IRStmt . WrTmp ) : all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . Assignment , ) continue elif isinstance ( stmt . data , pyvex . IRExpr . ITE ) : # data transferring #   t16 = if (t43) ILGop_Ident32(LDle(t29)) else 0x0000c844 # > t44 = ITE(t43,t16,0x0000c844) stmts_to_remove . append ( stmt_loc ) if isinstance ( stmt , pyvex . IRStmt . WrTmp ) : all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . Assignment , ) continue elif isinstance ( stmt . data , pyvex . IRExpr . Unop ) : if stmt . data . op == 'Iop_32Sto64' : # data transferring with conversion # t11 = 32Sto64(t12) stmts_to_remove . append ( stmt_loc ) if isinstance ( stmt , pyvex . IRStmt . WrTmp ) : all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . SignedExtension , 32 , 64 ) continue elif stmt . data . op == 'Iop_64to32' : # data transferring with conversion # t24 = 64to32(t21) stmts_to_remove . append ( stmt_loc ) if isinstance ( stmt , pyvex . IRStmt . WrTmp ) : all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . Truncation , 64 , 32 ) continue elif stmt . data . op == 'Iop_32Uto64' : # data transferring with conversion # t21 = 32Uto64(t22) stmts_to_remove . append ( stmt_loc ) if isinstance ( stmt , pyvex . IRStmt . WrTmp ) : all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . UnsignedExtension , 32 , 64 ) continue elif stmt . data . op == 'Iop_16Uto32' : # data transferring wth conversion stmts_to_remove . append ( stmt_loc ) if isinstance ( stmt , pyvex . IRStmt . WrTmp ) : all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . UnsignedExtension , 16 , 32 ) continue elif stmt . data . op == 'Iop_8Uto32' : # data transferring wth conversion stmts_to_remove . append ( stmt_loc ) if isinstance ( stmt , pyvex . IRStmt . WrTmp ) : all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . UnsignedExtension , 8 , 32 ) continue elif isinstance ( stmt . data , pyvex . IRExpr . Binop ) : if stmt . data . op . startswith ( 'Iop_Add' ) : # GitHub issue #1289, an S390X binary # jump_label = &jump_table + *(jump_table[index]) #       IRSB 0x4007c0 #   00 | ------ IMark(0x4007c0, 4, 0) ------ # + 01 | t0 = GET:I32(212) # + 02 | t1 = Add32(t0,0xffffffff) #   03 | PUT(352) = 0x0000000000000003 #   04 | t13 = 32Sto64(t0) #   05 | t6 = t13 #   06 | PUT(360) = t6 #   07 | PUT(368) = 0xffffffffffffffff #   08 | PUT(376) = 0x0000000000000000 #   09 | PUT(212) = t1 #   10 | PUT(ia) = 0x00000000004007c4 #   11 | ------ IMark(0x4007c4, 6, 0) ------ # + 12 | t14 = 32Uto64(t1) # + 13 | t8 = t14 # + 14 | t16 = CmpLE64U(t8,0x000000000000000b) # + 15 | t15 = 1Uto32(t16) # + 16 | t10 = t15 # + 17 | t11 = CmpNE32(t10,0x00000000) # + 18 | if (t11) { PUT(offset=336) = 0x4007d4; Ijk_Boring } #   Next: 0x4007ca # #       IRSB 0x4007d4 #   00 | ------ IMark(0x4007d4, 6, 0) ------ # + 01 | t8 = GET:I64(r2) # + 02 | t7 = Shr64(t8,0x3d) # + 03 | t9 = Shl64(t8,0x03) # + 04 | t6 = Or64(t9,t7) # + 05 | t11 = And64(t6,0x00000007fffffff8) #   06 | ------ IMark(0x4007da, 6, 0) ------ #   07 | PUT(r1) = 0x0000000000400a50 #   08 | PUT(ia) = 0x00000000004007e0 #   09 | ------ IMark(0x4007e0, 6, 0) ------ # + 10 | t12 = Add64(0x0000000000400a50,t11) # + 11 | t16 = LDbe:I64(t12) #   12 | PUT(r2) = t16 #   13 | ------ IMark(0x4007e6, 4, 0) ------ # + 14 | t17 = Add64(0x0000000000400a50,t16) # + Next: t17 # # Special case: a base address is added to the loaded offset before jumping to it. if isinstance ( stmt . data . args [ 0 ] , pyvex . IRExpr . Const ) and isinstance ( stmt . data . args [ 1 ] , pyvex . IRExpr . RdTmp ) : stmts_adding_base_addr . append ( JumpTargetBaseAddr ( stmt_loc , stmt , stmt . data . args [ 1 ] . tmp , base_addr = stmt . data . args [ 0 ] . con . value ) ) stmts_to_remove . append ( stmt_loc ) elif isinstance ( stmt . data . args [ 0 ] , pyvex . IRExpr . RdTmp ) and isinstance ( stmt . data . args [ 1 ] , pyvex . IRExpr . Const ) : stmts_adding_base_addr . append ( JumpTargetBaseAddr ( stmt_loc , stmt , stmt . data . args [ 0 ] . tmp , base_addr = stmt . data . args [ 1 ] . con . value ) ) stmts_to_remove . append ( stmt_loc ) elif isinstance ( stmt . data . args [ 0 ] , pyvex . IRExpr . RdTmp ) and isinstance ( stmt . data . args [ 1 ] , pyvex . IRExpr . RdTmp ) : # one of the tmps must be holding a concrete value at this point stmts_adding_base_addr . append ( JumpTargetBaseAddr ( stmt_loc , stmt , stmt . data . args [ 0 ] . tmp , tmp_1 = stmt . data . args [ 1 ] . tmp ) ) stmts_to_remove . append ( stmt_loc ) else : # not supported pass continue elif stmt . data . op . startswith ( 'Iop_Or' ) : # this is sometimes used in VEX statements in THUMB mode code to adjust the address to an odd # number # e.g. #        IRSB 0x4b63 #    00 | ------ IMark(0x4b62, 4, 1) ------ #    01 | PUT(itstate) = 0x00000000 #  + 02 | t11 = GET:I32(r2) #  + 03 | t10 = Shl32(t11,0x01) #  + 04 | t9 = Add32(0x00004b66,t10) #  + 05 | t8 = LDle:I16(t9) #  + 06 | t7 = 16Uto32(t8) #  + 07 | t14 = Shl32(t7,0x01) #  + 08 | t13 = Add32(0x00004b66,t14) #  + 09 | t12 = Or32(t13,0x00000001) #  + Next: t12 if isinstance ( stmt . data . args [ 0 ] , pyvex . IRExpr . RdTmp ) and isinstance ( stmt . data . args [ 1 ] , pyvex . IRExpr . Const ) and stmt . data . args [ 1 ] . con . value == 1 : # great. here it is stmts_to_remove . append ( stmt_loc ) all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . Or1 , ) continue elif stmt . data . op . startswith ( 'Iop_Shl' ) : # this is sometimes used when dealing with TBx instructions in ARM code. # e.g. #        IRSB 0x4b63 #    00 | ------ IMark(0x4b62, 4, 1) ------ #    01 | PUT(itstate) = 0x00000000 #  + 02 | t11 = GET:I32(r2) #  + 03 | t10 = Shl32(t11,0x01) #  + 04 | t9 = Add32(0x00004b66,t10) #  + 05 | t8 = LDle:I16(t9) #  + 06 | t7 = 16Uto32(t8) #  + 07 | t14 = Shl32(t7,0x01) #  + 08 | t13 = Add32(0x00004b66,t14) #  + 09 | t12 = Or32(t13,0x00000001) #  + Next: t12 if isinstance ( stmt . data . args [ 0 ] , pyvex . IRExpr . RdTmp ) and isinstance ( stmt . data . args [ 1 ] , pyvex . IRExpr . Const ) : # found it stmts_to_remove . append ( stmt_loc ) all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . ShiftLeft , stmt . data . args [ 1 ] . con . value ) continue elif isinstance ( stmt . data , pyvex . IRExpr . Load ) : # Got it! load_stmt , load_stmt_loc , load_size = stmt , stmt_loc , block . tyenv . sizeof ( stmt . tmp ) // self . project . arch . byte_width stmts_to_remove . append ( stmt_loc ) all_addr_holders [ ( stmt_loc [ 0 ] , stmt . tmp ) ] = ( AddressTransferringTypes . Assignment , ) elif isinstance ( stmt , pyvex . IRStmt . LoadG ) : # Got it! # # this is how an ARM jump table is translated to VEX # > t16 = if (t43) ILGop_Ident32(LDle(t29)) else 0x0000c844 load_stmt , load_stmt_loc , load_size = stmt , stmt_loc , block . tyenv . sizeof ( stmt . dst ) // self . project . arch . byte_width stmts_to_remove . append ( stmt_loc ) break return load_stmt_loc , load_stmt , load_size , stmts_to_remove , stmts_adding_base_addr , all_addr_holders