@ -5,7 +5,7 @@ from typing import Callable
from typing import Dict
from capstone import * # noqa: F403
from capstone . a rm 64 import * # noqa: F403
from capstone . a arch 64 import * # noqa: F403
from typing_extensions import override
import pwndbg . aglib . arch
@ -28,105 +28,126 @@ if TYPE_CHECKING:
# Negative size indicates signed read
# None indicates the read size depends on the target register
AARCH64_SINGLE_LOAD_INSTRUCTIONS : Dict [ int , int | None ] = {
ARM64_INS_LDRB : 1 ,
ARM64_INS_LDURB : 1 ,
ARM64_INS_LDRSB : - 1 ,
ARM64_INS_LDURSB : - 1 ,
ARM64_INS_LDRH : 2 ,
ARM64_INS_LDURH : 2 ,
ARM64_INS_LDRSH : - 2 ,
ARM64_INS_LDURSH : - 2 ,
ARM64_INS_LDURSW : - 4 ,
ARM64_INS_LDRSW : - 4 ,
ARM64_INS_LDUR : None ,
ARM64_INS_LDR : None ,
ARM64_INS_LDTRB : 1 ,
ARM64_INS_LDTRSB : - 1 ,
ARM64_INS_LDTRH : 2 ,
ARM64_INS_LDTRSH : - 2 ,
ARM64_INS_LDTRSW : - 4 ,
ARM64_INS_LDTR : None ,
ARM64_INS_LDXRB : 1 ,
ARM64_INS_LDXRH : 2 ,
ARM64_INS_LDXR : None ,
ARM64_INS_LDARB : 1 ,
ARM64_INS_LDARH : 2 ,
ARM64_INS_LDAR : None ,
AARCH64_INS_LDRB : 1 ,
AARCH64_INS_ALIAS_LDRB : 1 ,
AARCH64_INS_LDURB : 1 ,
AARCH64_INS_ALIAS_LDURB : 1 ,
AARCH64_INS_LDRSB : - 1 ,
AARCH64_INS_ALIAS_LDRSB : - 1 ,
AARCH64_INS_LDURSB : - 1 ,
AARCH64_INS_ALIAS_LDURSB : - 1 ,
AARCH64_INS_LDRH : 2 ,
AARCH64_INS_ALIAS_LDRH : 2 ,
AARCH64_INS_LDURH : 2 ,
AARCH64_INS_ALIAS_LDURH : 2 ,
AARCH64_INS_LDRSH : - 2 ,
AARCH64_INS_ALIAS_LDRSH : - 2 ,
AARCH64_INS_LDURSH : - 2 ,
AARCH64_INS_ALIAS_LDURSH : - 2 ,
AARCH64_INS_LDURSW : - 4 ,
AARCH64_INS_ALIAS_LDURSW : - 4 ,
AARCH64_INS_LDRSW : - 4 ,
AARCH64_INS_ALIAS_LDRSW : - 4 ,
AARCH64_INS_LDUR : None ,
AARCH64_INS_ALIAS_LDUR : None ,
AARCH64_INS_LDR : None ,
AARCH64_INS_ALIAS_LDR : None ,
AARCH64_INS_LDTRB : 1 ,
AARCH64_INS_LDTRSB : - 1 ,
AARCH64_INS_LDTRH : 2 ,
AARCH64_INS_LDTRSH : - 2 ,
AARCH64_INS_LDTRSW : - 4 ,
AARCH64_INS_LDTR : None ,
AARCH64_INS_ALIAS_LDTR : None ,
AARCH64_INS_LDXRB : 1 ,
AARCH64_INS_LDXRH : 2 ,
AARCH64_INS_LDXR : None ,
AARCH64_INS_LDARB : 1 ,
AARCH64_INS_LDARH : 2 ,
AARCH64_INS_LDAR : None ,
}
# None indicates that the write size depends on the source register
AARCH64_SINGLE_STORE_INSTRUCTIONS : Dict [ int , int | None ] = {
ARM64_INS_STRB : 1 ,
ARM64_INS_STURB : 1 ,
ARM64_INS_STRH : 2 ,
ARM64_INS_STURH : 2 ,
ARM64_INS_STUR : None ,
ARM64_INS_STR : None ,
AARCH64_INS_STRB : 1 ,
AARCH64_INS_ALIAS_STRB : 1 ,
AARCH64_INS_STURB : 1 ,
AARCH64_INS_ALIAS_STURB : 1 ,
AARCH64_INS_STRH : 2 ,
AARCH64_INS_ALIAS_STRH : 2 ,
AARCH64_INS_STURH : 2 ,
AARCH64_INS_ALIAS_STURH : 2 ,
AARCH64_INS_STUR : None ,
AARCH64_INS_ALIAS_STUR : None ,
AARCH64_INS_STR : None ,
AARCH64_INS_ALIAS_STR : None ,
# Store Register (unprivileged)
ARM64_INS_STTRB : 1 ,
ARM64_INS_STTRH : 2 ,
ARM64_INS_STTR : None ,
A ARCH 64_INS_STTRB: 1 ,
A ARCH 64_INS_STTRH: 2 ,
A ARCH 64_INS_STTR: None ,
# Store-Release
ARM64_INS_STLRB : 1 ,
A RM 64_INS_STLRH: 2 ,
A RM 64_INS_STLR: None ,
A ARCH 64_INS_STLRB: 1 ,
A ARCH 64_INS_STLRH: 2 ,
A ARCH 64_INS_STLR: None ,
}
# The first operand of these instructions gets the status result of the operation
AARCH64_EXCLUSIVE_STORE_INSTRUCTIONS = {
# Store Exclusive
A RM 64_INS_STXRB: 1 ,
A RM 64_INS_STXRH: 2 ,
A RM 64_INS_STXR: None ,
A ARCH 64_INS_STXRB: 1 ,
A ARCH 64_INS_STXRH: 2 ,
A ARCH 64_INS_STXR: None ,
# Store-Release Exclusive
A RM 64_INS_STLXRB: 1 ,
A RM 64_INS_STLXRH: 2 ,
A RM 64_INS_STLXR: None ,
A ARCH 64_INS_STLXRB: 1 ,
A ARCH 64_INS_STLXRH: 2 ,
A ARCH 64_INS_STLXR: None ,
}
CONDITIONAL_SELECT_INSTRUCTIONS = {
A RM 64_INS_CSEL,
A RM 64_INS_CSINC,
A RM 64_INS_CSINV,
A RM 64_INS_CSNEG,
A RM64_IN S_CSET,
A RM64_IN S_CSETM,
A RM64_IN S_CINC,
A RM64_IN S_CINV,
A RM64_IN S_CNEG,
A ARCH 64_INS_CSEL,
A ARCH 64_INS_CSINC,
A ARCH 64_INS_CSINV,
A ARCH 64_INS_CSNEG,
A ARCH64_INS_ALIA S_CSET,
A ARCH64_INS_ALIA S_CSETM,
A ARCH64_INS_ALIA S_CINC,
A ARCH64_INS_ALIA S_CINV,
A ARCH64_INS_ALIA S_CNEG,
}
AARCH64_EMULATED_ANNOTATIONS = CONDITIONAL_SELECT_INSTRUCTIONS | {
A RM 64_INS_SXTB,
A RM 64_INS_SXTH,
A RM 64_INS_SXTW,
A RM 64_INS_UXTB,
A RM 64_INS_UXTH,
A RM 64_INS_UXTW,
A RM 64_INS_RBIT,
A RM 64_INS_CLS,
A RM 64_INS_CLZ,
A RM64_IN S_BFXIL,
A RM64_IN S_UBFIZ,
A RM 64_INS_UBFM,
A RM64_IN S_UBFX,
A RM64_IN S_SBFIZ,
A RM 64_INS_SBFM,
A RM64_IN S_SBFX,
A RM64_IN S_BFI,
A RM 64_INS_NEG,
A RM64_IN S_NEGS,
A RM 64_INS_REV,
A RM 64_INS_BIC,
A RM 64_INS_BICS,
A ARCH 64_INS_SXTB,
A ARCH 64_INS_SXTH,
A ARCH 64_INS_SXTW,
A ARCH 64_INS_UXTB,
A ARCH 64_INS_UXTH,
A ARCH 64_INS_UXTW,
A ARCH 64_INS_RBIT,
A ARCH 64_INS_CLS,
A ARCH 64_INS_CLZ,
A ARCH64_INS_ALIA S_BFXIL,
A ARCH64_INS_ALIA S_UBFIZ,
A ARCH 64_INS_UBFM,
A ARCH64_INS_ALIA S_UBFX,
A ARCH64_INS_ALIA S_SBFIZ,
A ARCH 64_INS_SBFM,
A ARCH64_INS_ALIA S_SBFX,
A ARCH64_INS_ALIA S_BFI,
A ARCH 64_INS_NEG,
A ARCH64_INS_ALIA S_NEGS,
A ARCH 64_INS_REV,
A ARCH 64_INS_BIC,
A ARCH 64_INS_BICS,
}
AARCH64_CONSTANT_SHIFTS = { AARCH64_SFT_LSL , AARCH64_SFT_LSR , AARCH64_SFT_ASR , AARCH64_SFT_ROR }
# Parameters to each function: (value, shift_amt, bit_width)
AARCH64_BIT_SHIFT_MAP : Dict [ int , Callable [ [ int , int , int ] , int ] ] = {
A RM 64_SFT_LSL: bit_math . logical_shift_left ,
A RM 64_SFT_LSR: bit_math . logical_shift_right ,
A RM 64_SFT_ASR: bit_math . arithmetic_shift_right ,
A RM 64_SFT_ROR: bit_math . rotate_right ,
A ARCH 64_SFT_LSL: bit_math . logical_shift_left ,
A ARCH 64_SFT_LSR: bit_math . logical_shift_right ,
A ARCH 64_SFT_ASR: bit_math . arithmetic_shift_right ,
A ARCH 64_SFT_ROR: bit_math . rotate_right ,
}
@ -134,38 +155,54 @@ AARCH64_BIT_SHIFT_MAP: Dict[int, Callable[[int, int, int], int]] = {
# They take in a number, extract a byte, halfword, or word,
# and perform a zero- or sign-extend operation.
AARCH64_EXTEND_MAP : Dict [ int , Callable [ [ int ] , int ] ] = {
A RM 64_EXT_UXTB: lambda x : x & ( ( 1 << 8 ) - 1 ) ,
A RM 64_EXT_UXTH: lambda x : x & ( ( 1 << 16 ) - 1 ) ,
A RM 64_EXT_UXTW: lambda x : x & ( ( 1 << 32 ) - 1 ) ,
A RM 64_EXT_UXTX: lambda x : x , # UXTX has no effect. It extracts 64-bits from a 64-bit register.
A RM 64_EXT_SXTB: lambda x : bit_math . to_signed ( x , 8 ) ,
A RM 64_EXT_SXTH: lambda x : bit_math . to_signed ( x , 16 ) ,
A RM 64_EXT_SXTW: lambda x : bit_math . to_signed ( x , 32 ) ,
A RM 64_EXT_SXTX: lambda x : bit_math . to_signed ( x , 64 ) ,
A ARCH 64_EXT_UXTB: lambda x : x & ( ( 1 << 8 ) - 1 ) ,
A ARCH 64_EXT_UXTH: lambda x : x & ( ( 1 << 16 ) - 1 ) ,
A ARCH 64_EXT_UXTW: lambda x : x & ( ( 1 << 32 ) - 1 ) ,
A ARCH 64_EXT_UXTX: lambda x : x , # UXTX has no effect. It extracts 64-bits from a 64-bit register.
A ARCH 64_EXT_SXTB: lambda x : bit_math . to_signed ( x , 8 ) ,
A ARCH 64_EXT_SXTH: lambda x : bit_math . to_signed ( x , 16 ) ,
A ARCH 64_EXT_SXTW: lambda x : bit_math . to_signed ( x , 32 ) ,
A ARCH 64_EXT_SXTX: lambda x : bit_math . to_signed ( x , 64 ) ,
}
AARCH64_MATH_INSTRUCTIONS = {
ARM64_INS_ADD : " + " ,
ARM64_INS_ADDS : " + " ,
ARM64_INS_SUB : " - " ,
ARM64_INS_SUBS : " - " ,
ARM64_INS_AND : " & " ,
ARM64_INS_ANDS : " & " ,
ARM64_INS_ORR : " & " ,
ARM64_INS_ASR : " >>s " ,
ARM64_INS_ASRV : " >>s " ,
ARM64_INS_EOR : " ^ " ,
ARM64_INS_LSL : " << " ,
ARM64_INS_LSLV : " << " ,
ARM64_INS_LSR : " >> " ,
ARM64_INS_LSRV : " >> " ,
ARM64_INS_UDIV : " / " ,
ARM64_INS_SDIV : " / " ,
ARM64_INS_SMULH : " * " ,
ARM64_INS_SMULL : " * " ,
ARM64_INS_UMULH : " * " ,
ARM64_INS_UMULL : " * " ,
ARM64_INS_MUL : " * " ,
AARCH64_INS_ADD : " + " ,
AARCH64_INS_ALIAS_ADD : " + " ,
AARCH64_INS_ADDS : " + " ,
AARCH64_INS_ALIAS_ADDS : " + " ,
AARCH64_INS_SUB : " - " ,
AARCH64_INS_ALIAS_SUB : " - " ,
AARCH64_INS_SUBS : " - " ,
AARCH64_INS_ALIAS_SUBS : " - " ,
AARCH64_INS_AND : " & " ,
AARCH64_INS_ALIAS_AND : " & " ,
AARCH64_INS_ANDS : " & " ,
AARCH64_INS_ALIAS_ANDS : " & " ,
AARCH64_INS_ORR : " | " ,
AARCH64_INS_ALIAS_ORR : " | " ,
AARCH64_INS_EOR : " ^ " ,
AARCH64_INS_ALIAS_EOR : " ^ " ,
AARCH64_INS_UDIV : " / " ,
AARCH64_INS_SDIV : " / " ,
AARCH64_INS_SMULH : " * " ,
AARCH64_INS_SMULL : " * " ,
AARCH64_INS_ALIAS_SMULL : " * " ,
AARCH64_INS_UMULH : " * " ,
AARCH64_INS_UMULL : " * " ,
AARCH64_INS_ALIAS_UMULL : " * " ,
AARCH64_INS_MUL : " * " ,
AARCH64_INS_ALIAS_MUL : " * " ,
}
AARCH64_SHIFT_INSTRUCTIONS = {
AARCH64_INS_LSL : " << " ,
AARCH64_INS_ALIAS_LSL : " << " ,
AARCH64_INS_LSR : " >> " ,
AARCH64_INS_ALIAS_LSR : " >> " ,
AARCH64_INS_ASR : " >>s " ,
AARCH64_INS_ALIAS_ASR : " >>s " ,
AARCH64_INS_ROR : " >>r " ,
AARCH64_INS_ALIAS_ROR : " >>r " ,
}
@ -182,23 +219,23 @@ def resolve_condition(condition: int, cpsr: int) -> InstructionCondition:
v = ( cpsr >> 28 ) & 1
condition = {
A RM64_CC_INVALID: True , # Capstone uses this code for the 'B' instruction, the unconditional branch
A RM64_CC_EQ: z == 1 ,
A RM64_CC_NE: z == 0 ,
A RM64_CC_HS: c == 1 ,
A RM64_CC_LO: c == 0 ,
A RM64_CC_MI: n == 1 ,
A RM64_CC_PL: n == 0 ,
A RM64_CC_VS: v == 1 ,
A RM64_CC_VC: v == 0 ,
A RM64_CC_HI: c == 1 and z == 0 ,
A RM64_CC_LS: not ( c == 1 and z == 0 ) ,
A RM64_CC_GE: n = = v ,
A RM64_CC_LT: n ! = v ,
A RM64_CC_GT: z == 0 and n == v ,
A RM64_CC_LE: not ( z == 0 and n == v ) ,
A RM64_CC_AL : True ,
A RM64_CC_NV : True ,
A Arch64CC_EQ: z == 1 ,
A Arch64CC_NE: z == 0 ,
A Arch64CC_HS: c == 1 ,
A Arch64CC_LO: c == 0 ,
A Arch64CC_MI: n == 1 ,
A Arch64CC_PL: n == 0 ,
A Arch64CC_VS: v == 1 ,
A Arch64CC_VC: v == 0 ,
A Arch64CC_HI: c == 1 and z == 0 ,
A Arch64CC_LS: not ( c == 1 and z == 0 ) ,
A Arch64CC_GE: n == v ,
A Arch64CC_LT: n ! = v ,
A Arch64CC_GT: z == 0 and n = = v ,
A Arch64CC_LE: not ( z == 0 and n == v ) ,
A Arch64CC_AL: True ,
A Arch64CC_NV : True ,
A Arch64CC_Invalid : True ,
} . get ( condition , False )
return InstructionCondition . TRUE if condition else InstructionCondition . FALSE
@ -210,23 +247,26 @@ class DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
self . annotation_handlers : Dict [ int , Callable [ [ PwndbgInstruction , Emulator ] , None ] ] = {
# MOV
ARM64_INS_MOV : self . _common_move_annotator ,
AARCH64_INS_MOV : self . _common_move_annotator ,
AARCH64_INS_ALIAS_MOV : self . _common_move_annotator ,
# MOVZ
AARCH64_INS_MOVZ : self . _common_move_annotator ,
# MOV WITH KEEP
ARM64_INS_MOVK : self . _common_generic_register_destination ,
A ARCH 64_INS_MOVK: self . _common_generic_register_destination ,
# ADR
A RM 64_INS_ADR: self . _common_generic_register_destination ,
A ARCH 64_INS_ADR: self . _common_generic_register_destination ,
# ADRP
A RM 64_INS_ADRP: self . _handle_adrp ,
A ARCH 64_INS_ADRP: self . _handle_adrp ,
# CMP
A RM64_IN S_CMP: self . _common_cmp_annotator_builder ( " cpsr " , " - " ) ,
A ARCH64_INS_ALIA S_CMP: self . _common_cmp_annotator_builder ( " cpsr " , " - " ) ,
# CMN
A RM64_IN S_CMN: self . _common_cmp_annotator_builder ( " cpsr " , " + " ) ,
A ARCH64_INS_ALIA S_CMN: self . _common_cmp_annotator_builder ( " cpsr " , " + " ) ,
# TST (bitwise "and")
A RM64_IN S_TST: self . _common_cmp_annotator_builder ( " cpsr " , " & " ) ,
A ARCH64_INS_ALIA S_TST: self . _common_cmp_annotator_builder ( " cpsr " , " & " ) ,
# CCMP (conditional compare)
A RM 64_INS_CCMP: self . _common_cmp_annotator_builder ( " cpsr " , " " ) ,
A ARCH 64_INS_CCMP: self . _common_cmp_annotator_builder ( " cpsr " , " " ) ,
# CCMN
A RM 64_INS_CCMN: self . _common_cmp_annotator_builder ( " cpsr " , " " ) ,
A ARCH 64_INS_CCMN: self . _common_cmp_annotator_builder ( " cpsr " , " " ) ,
}
@override
@ -273,6 +313,20 @@ class DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
instruction . operands [ - 1 ] . before_value ,
AARCH64_MATH_INSTRUCTIONS [ instruction . id ] ,
)
elif instruction . id in AARCH64_SHIFT_INSTRUCTIONS :
# AArch64 encoding of shifts forces special attention: https://github.com/capstone-engine/capstone/issues/2631
if len ( instruction . operands ) == 2 :
if instruction . operands [ 1 ] . cs_op . shift . type in AARCH64_CONSTANT_SHIFTS :
self . _common_binary_op_annotator (
instruction ,
emu ,
instruction . operands [ 0 ] ,
instruction . operands [ 1 ] . before_value_no_modifiers ,
instruction . operands [ 1 ] . cs_op . shift . value ,
AARCH64_SHIFT_INSTRUCTIONS [ instruction . id ] ,
)
else :
self . _common_generic_register_destination ( instruction , emu )
elif instruction . id in AARCH64_EMULATED_ANNOTATIONS :
self . _common_generic_register_destination ( instruction , emu )
else :
@ -291,30 +345,38 @@ class DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
instruction . annotation = register_assign ( result_operand . str , telescope )
@override
def _prepare (
self , instruction : PwndbgInstruction , emu : pwndbg . aglib . disasm . arch . Emulator
) - > None :
if CS_GRP_INT in instruction . groups :
# https://github.com/capstone-engine/capstone/issues/2630
instruction . groups . remove ( CS_GRP_CALL )
@override
def _condition (
self , instruction : PwndbgInstruction , emu : Emulator
) - > pwndbg . aglib . disasm . arch . InstructionCondition :
# In ARM64, only branches have the conditional code in the instruction,
# as opposed to ARM32 which allows most instructions to be conditional
if instruction . id == ARM64_INS_B :
if instruction . id == A ARCH 64_INS_B:
# The B instruction can be made conditional by the condition codes
if instruction . cs_insn . cc in ( A RM64_CC_INVALID, ARM64_ CC_AL) :
if instruction . cs_insn . cc in ( A Arch64CC_Invalid, AArch64 CC_AL) :
instruction . declare_conditional = False
else :
flags = super ( ) . _read_register_name ( instruction , " cpsr " , emu )
if flags is not None :
return resolve_condition ( instruction . cs_insn . cc , flags )
elif instruction . id == A RM 64_INS_CBNZ:
elif instruction . id == A ARCH 64_INS_CBNZ:
op_val = instruction . operands [ 0 ] . before_value
return boolean_to_instruction_condition ( op_val is not None and op_val != 0 )
elif instruction . id == A RM 64_INS_CBZ:
elif instruction . id == A ARCH 64_INS_CBZ:
op_val = instruction . operands [ 0 ] . before_value
return boolean_to_instruction_condition ( op_val is not None and op_val == 0 )
elif instruction . id == A RM 64_INS_TBNZ:
elif instruction . id == A ARCH 64_INS_TBNZ:
op_val , bit = (
instruction . operands [ 0 ] . before_value ,
instruction . operands [ 1 ] . before_value ,
@ -323,7 +385,7 @@ class DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
if op_val is not None and bit is not None :
return boolean_to_instruction_condition ( bool ( ( op_val >> bit ) & 1 ) )
elif instruction . id == A RM 64_INS_TBZ:
elif instruction . id == A ARCH 64_INS_TBZ:
op_val , bit = (
instruction . operands [ 0 ] . before_value ,
instruction . operands [ 1 ] . before_value ,
@ -351,7 +413,7 @@ class DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
if ( val := instruction . operands [ - 1 ] . before_value ) is not None :
return val & pwndbg . aglib . arch . ptrmask
return None
elif instruction . id == ARM64_INS_RET :
elif instruction . id in ( AARCH64_INS_RET , AARCH64_INS_ALIAS_RET ) :
# If this is a ret WITHOUT an operand, it means we should read from the LR/x30 register
return super ( ) . _read_register_name ( instruction , " lr " , emu )
@ -383,11 +445,20 @@ class DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
target = 0
# All memory operands have `base` defined
# Handle case of LDR instructions memory operands that uses immediate as memory location
# Example: ldr x1, 0x30
if op . mem . base == 0 :
return op . mem . disp
base = self . _read_register ( instruction , op . mem . base , emu )
if base is None :
return None
target = base + op . mem . disp
target = base
if not instruction . cs_insn . post_index :
# Unlike in arm32, the sign of `disp` is encoded in the number already.
# There is no separate ".subtracted" value in Capstone
target + = op . mem . disp
# If there is an index register
if op . mem . index != 0 :
@ -448,6 +519,9 @@ class DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
if target is None :
return None
# We need this to retain the value of the un-shifted register in some annotations, such as shifts
op . before_value_no_modifiers = target
# The shift and sign-extend operations depend on the target bit width.
# This is sometimes implicit in the target register size, which is always
# the first operand.
@ -461,10 +535,12 @@ class DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
target = AARCH64_EXTEND_MAP [ op . cs_op . ext ] ( target ) & ( ( 1 << target_bit_width ) - 1 )
if op . cs_op . shift . type != 0 :
print ( target , op . cs_op . shift . type , op . cs_op . shift . value )
target = AARCH64_BIT_SHIFT_MAP [ op . cs_op . shift . type ] (
target = AARCH64_BIT_SHIFT_MAP . get ( op . cs_op . shift . type , lambda * a : None ) (
target , op . cs_op . shift . value , target_bit_width
) & ( ( 1 << target_bit_width ) - 1 )
)
if target is not None :
target = target & ( ( 1 << target_bit_width ) - 1 )
return target