Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
408133e9
Commit
408133e9
authored
Apr 29, 2011
by
Russell King
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'kprobes' of
git://git.linaro.org/people/nico/linux
into fixes
parents
ef267500
cdc25361
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
462 additions
and
321 deletions
+462
-321
arch/arm/include/asm/kprobes.h
arch/arm/include/asm/kprobes.h
+3
-0
arch/arm/kernel/kprobes-decode.c
arch/arm/kernel/kprobes-decode.c
+457
-320
arch/arm/kernel/kprobes.c
arch/arm/kernel/kprobes.c
+2
-1
No files found.
arch/arm/include/asm/kprobes.h
View file @
408133e9
...
...
@@ -39,10 +39,13 @@ typedef u32 kprobe_opcode_t;
struct
kprobe
;
typedef
void
(
kprobe_insn_handler_t
)(
struct
kprobe
*
,
struct
pt_regs
*
);
typedef
unsigned
long
(
kprobe_check_cc
)(
unsigned
long
);
/* Architecture specific copy of original instruction. */
struct
arch_specific_insn
{
kprobe_opcode_t
*
insn
;
kprobe_insn_handler_t
*
insn_handler
;
kprobe_check_cc
*
insn_check_cc
;
};
struct
prev_kprobe
{
...
...
arch/arm/kernel/kprobes-decode.c
View file @
408133e9
...
...
@@ -34,9 +34,6 @@
*
* *) If the PC is written to by the instruction, the
* instruction must be fully simulated in software.
* If it is a conditional instruction, the handler
* will use insn[0] to copy its condition code to
* set r0 to 1 and insn[1] to "mov pc, lr" to return.
*
* *) Otherwise, a modified form of the instruction is
* directly executed. Its handler calls the
...
...
@@ -68,13 +65,17 @@
#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
#define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos))
/*
* Test if load/store instructions writeback the address register.
* if P (bit 24) == 0 or W (bit 21) == 1
*/
#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000)
#define PSR_fs (PSR_f|PSR_s)
#define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e
/* mov pc, lr */
#define SET_R0_TRUE_INSTRUCTION 0xe3a00001
/* mov r0, #1 */
#define truecc_insn(insn) (((insn) & 0xf0000000) | \
(SET_R0_TRUE_INSTRUCTION & 0x0fffffff))
typedef
long
(
insn_0arg_fn_t
)(
void
);
typedef
long
(
insn_1arg_fn_t
)(
long
);
...
...
@@ -419,14 +420,10 @@ insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr,
static
void
__kprobes
simulate_bbl
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_1arg_fn_t
*
i_fn
=
(
insn_1arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
long
iaddr
=
(
long
)
p
->
addr
;
int
disp
=
branch_displacement
(
insn
);
if
(
!
insnslot_1arg_rflags
(
0
,
regs
->
ARM_cpsr
,
i_fn
))
return
;
if
(
insn
&
(
1
<<
24
))
regs
->
ARM_lr
=
iaddr
+
4
;
...
...
@@ -446,14 +443,10 @@ static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs)
static
void
__kprobes
simulate_blx2bx
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_1arg_fn_t
*
i_fn
=
(
insn_1arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
int
rm
=
insn
&
0xf
;
long
rmv
=
regs
->
uregs
[
rm
];
if
(
!
insnslot_1arg_rflags
(
0
,
regs
->
ARM_cpsr
,
i_fn
))
return
;
if
(
insn
&
(
1
<<
5
))
regs
->
ARM_lr
=
(
long
)
p
->
addr
+
4
;
...
...
@@ -463,9 +456,16 @@ static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs)
regs
->
ARM_cpsr
|=
PSR_T_BIT
;
}
static
void
__kprobes
simulate_mrs
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
kprobe_opcode_t
insn
=
p
->
opcode
;
int
rd
=
(
insn
>>
12
)
&
0xf
;
unsigned
long
mask
=
0xf8ff03df
;
/* Mask out execution state */
regs
->
uregs
[
rd
]
=
regs
->
ARM_cpsr
&
mask
;
}
static
void
__kprobes
simulate_ldm1stm1
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_1arg_fn_t
*
i_fn
=
(
insn_1arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
int
rn
=
(
insn
>>
16
)
&
0xf
;
int
lbit
=
insn
&
(
1
<<
20
);
...
...
@@ -476,9 +476,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
int
reg_bit_vector
;
int
reg_count
;
if
(
!
insnslot_1arg_rflags
(
0
,
regs
->
ARM_cpsr
,
i_fn
))
return
;
reg_count
=
0
;
reg_bit_vector
=
insn
&
0xffff
;
while
(
reg_bit_vector
)
{
...
...
@@ -510,11 +507,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
static
void
__kprobes
simulate_stm1_pc
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_1arg_fn_t
*
i_fn
=
(
insn_1arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
if
(
!
insnslot_1arg_rflags
(
0
,
regs
->
ARM_cpsr
,
i_fn
))
return
;
regs
->
ARM_pc
=
(
long
)
p
->
addr
+
str_pc_offset
;
simulate_ldm1stm1
(
p
,
regs
);
regs
->
ARM_pc
=
(
long
)
p
->
addr
+
4
;
...
...
@@ -525,24 +517,16 @@ static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs)
regs
->
uregs
[
12
]
=
regs
->
uregs
[
13
];
}
static
void
__kprobes
emulate_ldcstc
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_1arg_fn_t
*
i_fn
=
(
insn_1arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
int
rn
=
(
insn
>>
16
)
&
0xf
;
long
rnv
=
regs
->
uregs
[
rn
];
/* Save Rn in case of writeback. */
regs
->
uregs
[
rn
]
=
insnslot_1arg_rflags
(
rnv
,
regs
->
ARM_cpsr
,
i_fn
);
}
static
void
__kprobes
emulate_ldrd
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_2arg_fn_t
*
i_fn
=
(
insn_2arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
long
ppc
=
(
long
)
p
->
addr
+
8
;
int
rd
=
(
insn
>>
12
)
&
0xf
;
int
rn
=
(
insn
>>
16
)
&
0xf
;
int
rm
=
insn
&
0xf
;
/* rm may be invalid, don't care. */
long
rmv
=
(
rm
==
15
)
?
ppc
:
regs
->
uregs
[
rm
];
long
rnv
=
(
rn
==
15
)
?
ppc
:
regs
->
uregs
[
rn
];
/* Not following the C calling convention here, so need asm(). */
__asm__
__volatile__
(
...
...
@@ -554,29 +538,36 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs)
"str r0, %[rn]
\n\t
"
/* in case of writeback */
"str r2, %[rd0]
\n\t
"
"str r3, %[rd1]
\n\t
"
:
[
rn
]
"+m"
(
r
egs
->
uregs
[
rn
]
),
:
[
rn
]
"+m"
(
r
nv
),
[
rd0
]
"=m"
(
regs
->
uregs
[
rd
]),
[
rd1
]
"=m"
(
regs
->
uregs
[
rd
+
1
])
:
[
rm
]
"m"
(
r
egs
->
uregs
[
rm
]
),
:
[
rm
]
"m"
(
r
mv
),
[
cpsr
]
"r"
(
regs
->
ARM_cpsr
),
[
i_fn
]
"r"
(
i_fn
)
:
"r0"
,
"r1"
,
"r2"
,
"r3"
,
"lr"
,
"cc"
);
if
(
is_writeback
(
insn
))
regs
->
uregs
[
rn
]
=
rnv
;
}
static
void
__kprobes
emulate_strd
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_4arg_fn_t
*
i_fn
=
(
insn_4arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
long
ppc
=
(
long
)
p
->
addr
+
8
;
int
rd
=
(
insn
>>
12
)
&
0xf
;
int
rn
=
(
insn
>>
16
)
&
0xf
;
int
rm
=
insn
&
0xf
;
long
rnv
=
regs
->
uregs
[
rn
];
long
rmv
=
regs
->
uregs
[
rm
];
/* rm/rmv may be invalid, don't care. */
long
rnv
=
(
rn
==
15
)
?
ppc
:
regs
->
uregs
[
rn
];
/* rm/rmv may be invalid, don't care. */
long
rmv
=
(
rm
==
15
)
?
ppc
:
regs
->
uregs
[
rm
];
long
rnv_wb
;
r
egs
->
uregs
[
rn
]
=
insnslot_4arg_rflags
(
rnv
,
rmv
,
regs
->
uregs
[
rd
],
r
nv_wb
=
insnslot_4arg_rflags
(
rnv
,
rmv
,
regs
->
uregs
[
rd
],
regs
->
uregs
[
rd
+
1
],
regs
->
ARM_cpsr
,
i_fn
);
if
(
is_writeback
(
insn
))
regs
->
uregs
[
rn
]
=
rnv_wb
;
}
static
void
__kprobes
emulate_ldr
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
...
...
@@ -630,31 +621,6 @@ static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs)
regs
->
uregs
[
rn
]
=
rnv_wb
;
/* Save Rn in case of writeback. */
}
static
void
__kprobes
emulate_mrrc
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_llret_0arg_fn_t
*
i_fn
=
(
insn_llret_0arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
union
reg_pair
fnr
;
int
rd
=
(
insn
>>
12
)
&
0xf
;
int
rn
=
(
insn
>>
16
)
&
0xf
;
fnr
.
dr
=
insnslot_llret_0arg_rflags
(
regs
->
ARM_cpsr
,
i_fn
);
regs
->
uregs
[
rn
]
=
fnr
.
r0
;
regs
->
uregs
[
rd
]
=
fnr
.
r1
;
}
static
void
__kprobes
emulate_mcrr
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_2arg_fn_t
*
i_fn
=
(
insn_2arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
int
rd
=
(
insn
>>
12
)
&
0xf
;
int
rn
=
(
insn
>>
16
)
&
0xf
;
long
rnv
=
regs
->
uregs
[
rn
];
long
rdv
=
regs
->
uregs
[
rd
];
insnslot_2arg_rflags
(
rnv
,
rdv
,
regs
->
ARM_cpsr
,
i_fn
);
}
static
void
__kprobes
emulate_sat
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_1arg_fn_t
*
i_fn
=
(
insn_1arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
...
...
@@ -688,32 +654,32 @@ static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs)
insnslot_0arg_rflags
(
regs
->
ARM_cpsr
,
i_fn
);
}
static
void
__kprobes
emulate_
rd12
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
static
void
__kprobes
emulate_
nop
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_0arg_fn_t
*
i_fn
=
(
insn_0arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
int
rd
=
(
insn
>>
12
)
&
0xf
;
regs
->
uregs
[
rd
]
=
insnslot_0arg_rflags
(
regs
->
ARM_cpsr
,
i_fn
);
}
static
void
__kprobes
emulate_ird12
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
static
void
__kprobes
emulate_rd12_modify
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_1arg_fn_t
*
i_fn
=
(
insn_1arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
int
ird
=
(
insn
>>
12
)
&
0xf
;
int
rd
=
(
insn
>>
12
)
&
0xf
;
long
rdv
=
regs
->
uregs
[
rd
];
insnslot_1arg_rflags
(
regs
->
uregs
[
ird
]
,
regs
->
ARM_cpsr
,
i_fn
);
regs
->
uregs
[
rd
]
=
insnslot_1arg_rflags
(
rdv
,
regs
->
ARM_cpsr
,
i_fn
);
}
static
void
__kprobes
emulate_rn16
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
static
void
__kprobes
emulate_rd12rn0_modify
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_
1arg_fn_t
*
i_fn
=
(
insn_1
arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
insn_
2arg_fn_t
*
i_fn
=
(
insn_2
arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
int
rn
=
(
insn
>>
16
)
&
0xf
;
int
rd
=
(
insn
>>
12
)
&
0xf
;
int
rn
=
insn
&
0xf
;
long
rdv
=
regs
->
uregs
[
rd
];
long
rnv
=
regs
->
uregs
[
rn
];
insnslot_1arg_rflags
(
rnv
,
regs
->
ARM_cpsr
,
i_fn
);
regs
->
uregs
[
rd
]
=
insnslot_2arg_rflags
(
rdv
,
rnv
,
regs
->
ARM_cpsr
,
i_fn
);
}
static
void
__kprobes
emulate_rd12rm0
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
...
...
@@ -818,6 +784,17 @@ emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs)
regs
->
uregs
[
rd
]
=
insnslot_1arg_rwflags
(
rnv
,
&
regs
->
ARM_cpsr
,
i_fn
);
}
static
void
__kprobes
emulate_alu_tests_imm
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_1arg_fn_t
*
i_fn
=
(
insn_1arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
int
rn
=
(
insn
>>
16
)
&
0xf
;
long
rnv
=
(
rn
==
15
)
?
(
long
)
p
->
addr
+
8
:
regs
->
uregs
[
rn
];
insnslot_1arg_rwflags
(
rnv
,
&
regs
->
ARM_cpsr
,
i_fn
);
}
static
void
__kprobes
emulate_alu_rflags
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
...
...
@@ -854,14 +831,34 @@ emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs)
insnslot_3arg_rwflags
(
rnv
,
rmv
,
rsv
,
&
regs
->
ARM_cpsr
,
i_fn
);
}
static
void
__kprobes
emulate_alu_tests
(
struct
kprobe
*
p
,
struct
pt_regs
*
regs
)
{
insn_3arg_fn_t
*
i_fn
=
(
insn_3arg_fn_t
*
)
&
p
->
ainsn
.
insn
[
0
];
kprobe_opcode_t
insn
=
p
->
opcode
;
long
ppc
=
(
long
)
p
->
addr
+
8
;
int
rn
=
(
insn
>>
16
)
&
0xf
;
int
rs
=
(
insn
>>
8
)
&
0xf
;
/* rs/rsv may be invalid, don't care. */
int
rm
=
insn
&
0xf
;
long
rnv
=
(
rn
==
15
)
?
ppc
:
regs
->
uregs
[
rn
];
long
rmv
=
(
rm
==
15
)
?
ppc
:
regs
->
uregs
[
rm
];
long
rsv
=
regs
->
uregs
[
rs
];
insnslot_3arg_rwflags
(
rnv
,
rmv
,
rsv
,
&
regs
->
ARM_cpsr
,
i_fn
);
}
static
enum
kprobe_insn
__kprobes
prep_emulate_ldr_str
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
int
ibit
=
(
insn
&
(
1
<<
26
))
?
25
:
22
;
int
not_imm
=
(
insn
&
(
1
<<
26
))
?
(
insn
&
(
1
<<
25
))
:
(
~
insn
&
(
1
<<
22
));
if
(
is_writeback
(
insn
)
&&
is_r15
(
insn
,
16
))
return
INSN_REJECTED
;
/* Writeback to PC */
insn
&=
0xfff00fff
;
insn
|=
0x00001000
;
/* Rn = r0, Rd = r1 */
if
(
insn
&
(
1
<<
ibit
)
)
{
if
(
not_imm
)
{
insn
&=
~
0xf
;
insn
|=
2
;
/* Rm = r2 */
}
...
...
@@ -871,20 +868,40 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi)
}
static
enum
kprobe_insn
__kprobes
prep_emulate_rd12
rm0
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
prep_emulate_rd12
_modify
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
insn
&=
0xffff0ff0
;
/* Rd = r0, Rm = r0 */
if
(
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* Rd is PC */
insn
&=
0xffff0fff
;
/* Rd = r0 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_rd12
rm0
;
asi
->
insn_handler
=
emulate_rd12
_modify
;
return
INSN_GOOD
;
}
static
enum
kprobe_insn
__kprobes
prep_emulate_rd12
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
prep_emulate_rd12rn0_modify
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
insn
&=
0xffff0fff
;
/* Rd = r0 */
if
(
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* Rd is PC */
insn
&=
0xffff0ff0
;
/* Rd = r0 */
insn
|=
0x00000001
;
/* Rn = r1 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_rd12rn0_modify
;
return
INSN_GOOD
;
}
static
enum
kprobe_insn
__kprobes
prep_emulate_rd12rm0
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
if
(
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* Rd is PC */
insn
&=
0xffff0ff0
;
/* Rd = r0, Rm = r0 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_rd12
;
asi
->
insn_handler
=
emulate_rd12
rm0
;
return
INSN_GOOD
;
}
...
...
@@ -892,6 +909,9 @@ static enum kprobe_insn __kprobes
prep_emulate_rd12rn16rm0_wflags
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
if
(
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* Rd is PC */
insn
&=
0xfff00ff0
;
/* Rd = r0, Rn = r0 */
insn
|=
0x00000001
;
/* Rm = r1 */
asi
->
insn
[
0
]
=
insn
;
...
...
@@ -903,6 +923,9 @@ static enum kprobe_insn __kprobes
prep_emulate_rd16rs8rm0_wflags
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
if
(
is_r15
(
insn
,
16
))
return
INSN_REJECTED
;
/* Rd is PC */
insn
&=
0xfff0f0f0
;
/* Rd = r0, Rs = r0 */
insn
|=
0x00000001
;
/* Rm = r1 */
asi
->
insn
[
0
]
=
insn
;
...
...
@@ -914,6 +937,9 @@ static enum kprobe_insn __kprobes
prep_emulate_rd16rn12rs8rm0_wflags
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
if
(
is_r15
(
insn
,
16
))
return
INSN_REJECTED
;
/* Rd is PC */
insn
&=
0xfff000f0
;
/* Rd = r0, Rn = r0 */
insn
|=
0x00000102
;
/* Rs = r1, Rm = r2 */
asi
->
insn
[
0
]
=
insn
;
...
...
@@ -925,6 +951,9 @@ static enum kprobe_insn __kprobes
prep_emulate_rdhi16rdlo12rs8rm0_wflags
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
if
(
is_r15
(
insn
,
16
)
||
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* RdHi or RdLo is PC */
insn
&=
0xfff000f0
;
/* RdHi = r0, RdLo = r1 */
insn
|=
0x00001203
;
/* Rs = r2, Rm = r3 */
asi
->
insn
[
0
]
=
insn
;
...
...
@@ -945,20 +974,13 @@ prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn,
static
enum
kprobe_insn
__kprobes
space_1111
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
/* CPS mmod == 1 : 1111 0001 0000 xx10 xxxx xxxx xx0x xxxx */
/* RFE : 1111 100x x0x1 xxxx xxxx 1010 xxxx xxxx */
/* SRS : 1111 100x x1x0 1101 xxxx 0101 xxxx xxxx */
if
((
insn
&
0xfff30020
)
==
0xf1020000
||
(
insn
&
0xfe500f00
)
==
0xf8100a00
||
(
insn
&
0xfe5f0f00
)
==
0xf84d0500
)
return
INSN_REJECTED
;
/* PLD : 1111 01x1 x101 xxxx xxxx xxxx xxxx xxxx : */
if
((
insn
&
0xfd700000
)
==
0xf4500000
)
{
insn
&=
0xfff0ffff
;
/* Rn = r0 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_rn16
;
return
INSN_GOOD
;
/* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */
/* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */
/* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */
/* PLD : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */
if
((
insn
&
0xfe300000
)
==
0xf4100000
)
{
asi
->
insn_handler
=
emulate_nop
;
return
INSN_GOOD_NO_SLOT
;
}
/* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */
...
...
@@ -967,41 +989,22 @@ space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi)
return
INSN_GOOD_NO_SLOT
;
}
/* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
/* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
if
((
insn
&
0xffff00f0
)
==
0xf1010000
||
(
insn
&
0xff000010
)
==
0xfe000000
)
{
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_none
;
return
INSN_GOOD
;
}
/* CPS : 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */
/* SETEND: 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
/* SRS : 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
/* RFE : 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* Coprocessor instructions... */
/* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
/* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
if
((
insn
&
0xffe00000
)
==
0xfc400000
)
{
insn
&=
0xfff00fff
;
/* Rn = r0 */
insn
|=
0x00001000
;
/* Rd = r1 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
(
insn
&
(
1
<<
20
))
?
emulate_mrrc
:
emulate_mcrr
;
return
INSN_GOOD
;
}
/* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
/* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
if
((
insn
&
0xfe000000
)
==
0xfc000000
)
{
insn
&=
0xfff0ffff
;
/* Rn = r0 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_ldcstc
;
return
INSN_GOOD
;
}
/* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
/* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
/* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
insn
&=
0xffff0fff
;
/* Rd = r0 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
(
insn
&
(
1
<<
20
))
?
emulate_rd12
:
emulate_ird12
;
return
INSN_GOOD
;
return
INSN_REJECTED
;
}
static
enum
kprobe_insn
__kprobes
...
...
@@ -1010,19 +1013,18 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
/* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */
if
((
insn
&
0x0f900010
)
==
0x01000000
)
{
/* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
/* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
if
((
insn
&
0x0ff000f0
)
==
0x01200020
||
(
insn
&
0x0fb000f0
)
==
0x01200000
)
return
INSN_REJECTED
;
/* MRS : cccc 0001 0x00 xxxx xxxx xxxx 0000 xxxx */
if
((
insn
&
0x0fb00010
)
==
0x01000000
)
return
prep_emulate_rd12
(
insn
,
asi
);
/* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */
if
((
insn
&
0x0ff000f0
)
==
0x01000000
)
{
if
(
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* Rd is PC */
asi
->
insn_handler
=
simulate_mrs
;
return
INSN_GOOD_NO_SLOT
;
}
/* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
if
((
insn
&
0x0ff00090
)
==
0x01400080
)
return
prep_emulate_rdhi16rdlo12rs8rm0_wflags
(
insn
,
asi
);
return
prep_emulate_rdhi16rdlo12rs8rm0_wflags
(
insn
,
asi
);
/* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
/* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
...
...
@@ -1031,24 +1033,29 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
return
prep_emulate_rd16rs8rm0_wflags
(
insn
,
asi
);
/* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */
/* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 0x00 xxxx : Q */
/* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */
if
((
insn
&
0x0ff00090
)
==
0x01000080
||
(
insn
&
0x0ff000b0
)
==
0x01200080
)
return
prep_emulate_rd16rn12rs8rm0_wflags
(
insn
,
asi
);
/* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
/* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
/* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */
/* Other instruction encodings aren't yet defined */
return
INSN_REJECTED
;
}
/* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */
else
if
((
insn
&
0x0f900090
)
==
0x01000010
)
{
/* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
if
((
insn
&
0xfff000f0
)
==
0xe1200070
)
return
INSN_REJECTED
;
/* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
/* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
if
((
insn
&
0x0ff000d0
)
==
0x01200010
)
{
asi
->
insn
[
0
]
=
truecc_insn
(
insn
);
if
((
insn
&
0x0ff000ff
)
==
0x0120003f
)
return
INSN_REJECTED
;
/* BLX pc */
asi
->
insn_handler
=
simulate_blx2bx
;
return
INSN_GOOD
;
return
INSN_GOOD
_NO_SLOT
;
}
/* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
...
...
@@ -1059,17 +1066,27 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
/* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */
/* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */
/* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */
if
((
insn
&
0x0f9000f0
)
==
0x01000050
)
return
prep_emulate_rd12rn16rm0_wflags
(
insn
,
asi
);
/* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
/* SMC : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */
/* Other instruction encodings aren't yet defined */
return
INSN_REJECTED
;
}
/* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */
else
if
((
insn
&
0x0f0000
9
0
)
==
0x00000090
)
{
else
if
((
insn
&
0x0f0000
f
0
)
==
0x00000090
)
{
/* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */
/* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */
/* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */
/* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */
/* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */
/* undef : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx : */
/* MLS : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx : */
/* undef : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx : */
/* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */
/* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */
/* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */
...
...
@@ -1078,13 +1095,15 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
/* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */
/* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */
/* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */
if
((
insn
&
0x0fe000f0
)
==
0x00000090
)
{
if
((
insn
&
0x00d00000
)
==
0x00500000
)
return
INSN_REJECTED
;
else
if
((
insn
&
0x00e00000
)
==
0x00000000
)
return
prep_emulate_rd16rs8rm0_wflags
(
insn
,
asi
);
}
else
if
((
insn
&
0x0fe000f0
)
==
0x00200090
)
{
else
if
((
insn
&
0x00a00000
)
==
0x00200000
)
return
prep_emulate_rd16rn12rs8rm0_wflags
(
insn
,
asi
);
}
else
{
return
prep_emulate_rdhi16rdlo12rs8rm0_wflags
(
insn
,
asi
);
}
else
return
prep_emulate_rdhi16rdlo12rs8rm0_wflags
(
insn
,
asi
);
}
/* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */
...
...
@@ -1092,23 +1111,45 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
/* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */
/* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */
/* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */
/* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */
/* ??? : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */
/* ??? : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */
/* ??? : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */
/* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */
/* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */
/* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */
/* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */
/* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */
/* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */
/* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */
/* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */
/* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */
/* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */
/* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */
/* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */
/* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */
/* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */
if
((
insn
&
0x0f0000f0
)
==
0x01000090
)
{
if
((
insn
&
0x0fb000f0
)
==
0x01000090
)
{
/* SWP/SWPB */
return
prep_emulate_rd12rn16rm0_wflags
(
insn
,
asi
);
return
prep_emulate_rd12rn16rm0_wflags
(
insn
,
asi
);
}
else
{
/* STREX/LDREX variants and unallocaed space */
return
INSN_REJECTED
;
}
}
else
if
((
insn
&
0x0e1000d0
)
==
0x00000d0
)
{
/* STRD/LDRD */
if
((
insn
&
0x0000e000
)
==
0x0000e000
)
return
INSN_REJECTED
;
/* Rd is LR or PC */
if
(
is_writeback
(
insn
)
&&
is_r15
(
insn
,
16
))
return
INSN_REJECTED
;
/* Writeback to PC */
insn
&=
0xfff00fff
;
insn
|=
0x00002000
;
/* Rn = r0, Rd = r2 */
if
(
insn
&
(
1
<<
22
))
{
/*
I bit
*/
if
(
!
(
insn
&
(
1
<<
22
)
))
{
/*
Register index
*/
insn
&=
~
0xf
;
insn
|=
1
;
/* Rm = r1 */
}
...
...
@@ -1118,6 +1159,9 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
return
INSN_GOOD
;
}
/* LDRH/STRH/LDRSB/LDRSH */
if
(
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* Rd is PC */
return
prep_emulate_ldr_str
(
insn
,
asi
);
}
...
...
@@ -1154,22 +1198,61 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
insn
|=
0x00000200
;
/* Rs = r2 */
}
asi
->
insn
[
0
]
=
insn
;
if
((
insn
&
0x0f900000
)
==
0x01100000
)
{
/*
* TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx
* TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx
* CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx
* CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx
*/
asi
->
insn_handler
=
emulate_alu_tests
;
}
else
{
/* ALU ops which write to Rd */
asi
->
insn_handler
=
(
insn
&
(
1
<<
20
))
?
/* S-bit */
emulate_alu_rwflags
:
emulate_alu_rflags
;
}
return
INSN_GOOD
;
}
static
enum
kprobe_insn
__kprobes
space_cccc_001x
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
/* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
/* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
if
((
insn
&
0x0fb00000
)
==
0x03000000
)
return
prep_emulate_rd12_modify
(
insn
,
asi
);
/* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
if
((
insn
&
0x0fff0000
)
==
0x03200000
)
{
unsigned
op2
=
insn
&
0x000000ff
;
if
(
op2
==
0x01
||
op2
==
0x04
)
{
/* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
/* SEV : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_none
;
return
INSN_GOOD
;
}
else
if
(
op2
<=
0x03
)
{
/* NOP : cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
/* WFE : cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
/* WFI : cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
/*
* We make WFE and WFI true NOPs to avoid stalls due
* to missing events whilst processing the probe.
*/
asi
->
insn_handler
=
emulate_nop
;
return
INSN_GOOD_NO_SLOT
;
}
/* For DBG and unallocated hints it's safest to reject them */
return
INSN_REJECTED
;
}
/*
* MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx
* Undef : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx
* ALU op with S bit and Rd == 15 :
* cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx
*/
if
((
insn
&
0x0fb00000
)
==
0x03200000
||
/* MSR */
(
insn
&
0x0ff00000
)
==
0x03400000
||
/* Undef */
(
insn
&
0x0e10f000
)
==
0x0210f000
)
/* ALU s-bit, R15 */
return
INSN_REJECTED
;
...
...
@@ -1180,10 +1263,22 @@ space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
* *S (bit 20) updates condition codes
* ADC/SBC/RSC reads the C flag
*/
insn
&=
0xfff
f0fff
;
/*
Rd = r0 */
insn
&=
0xfff
00fff
;
/* Rn = r0 and
Rd = r0 */
asi
->
insn
[
0
]
=
insn
;
if
((
insn
&
0x0f900000
)
==
0x03100000
)
{
/*
* TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx
* TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx
* CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx
* CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx
*/
asi
->
insn_handler
=
emulate_alu_tests_imm
;
}
else
{
/* ALU ops which write to Rd */
asi
->
insn_handler
=
(
insn
&
(
1
<<
20
))
?
/* S-bit */
emulate_alu_imm_rwflags
:
emulate_alu_imm_rflags
;
}
return
INSN_GOOD
;
}
...
...
@@ -1192,6 +1287,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
{
/* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */
if
((
insn
&
0x0ff000f0
)
==
0x068000b0
)
{
if
(
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* Rd is PC */
insn
&=
0xfff00ff0
;
/* Rd = r0, Rn = r0 */
insn
|=
0x00000001
;
/* Rm = r1 */
asi
->
insn
[
0
]
=
insn
;
...
...
@@ -1205,6 +1302,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
/* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */
if
((
insn
&
0x0fa00030
)
==
0x06a00010
||
(
insn
&
0x0fb000f0
)
==
0x06a00030
)
{
if
(
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* Rd is PC */
insn
&=
0xffff0ff0
;
/* Rd = r0, Rm = r0 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_sat
;
...
...
@@ -1213,57 +1312,101 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
/* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
/* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
/* RBIT : cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */
/* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
if
((
insn
&
0x0ff00070
)
==
0x06b00030
||
(
insn
&
0x0ff000
f0
)
==
0x06f000b
0
)
(
insn
&
0x0ff000
70
)
==
0x06f0003
0
)
return
prep_emulate_rd12rm0
(
insn
,
asi
);
/* ??? : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx : */
/* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */
/* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */
/* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */
/* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */
/* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */
/* ??? : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx : */
/* ??? : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx : */
/* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */
/* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */
/* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */
/* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */
/* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */
/* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */
/* ??? : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx : */
/* ??? : cccc 0110 0010 xxxx xxxx xxxx 1101 xxxx : */
/* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */
/* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */
/* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */
/* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */
/* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */
/* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */
/* ??? : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx : */
/* ??? : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx : */
/* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */
/* ??? : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx : */
/* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */
/* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */
/* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */
/* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */
/* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */
/* ??? : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx : */
/* ??? : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx : */
/* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */
/* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */
/* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */
/* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */
/* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */
/* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */
/* ??? : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx : */
/* ??? : cccc 0110 0110 xxxx xxxx xxxx 1101 xxxx : */
/* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */
/* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */
/* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */
/* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */
/* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */
/* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */
/* ??? : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx : */
/* ??? : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx : */
/* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */
if
((
insn
&
0x0f800010
)
==
0x06000010
)
{
if
((
insn
&
0x00300000
)
==
0x00000000
||
(
insn
&
0x000000e0
)
==
0x000000a0
||
(
insn
&
0x000000e0
)
==
0x000000c0
)
return
INSN_REJECTED
;
/* Unallocated space */
return
prep_emulate_rd12rn16rm0_wflags
(
insn
,
asi
);
}
/* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */
/* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */
if
((
insn
&
0x0ff00030
)
==
0x06800010
)
return
prep_emulate_rd12rn16rm0_wflags
(
insn
,
asi
);
/* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */
/* SXTB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */
/* SXTB16 : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx : */
/* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */
/* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */
/* SXTB : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx : */
/* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */
/* SXTH : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx : */
/* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */
/* UXTB16 : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx : */
/* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */
/* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */
/* UXTB : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx : */
/* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */
/* UXTH : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx : */
if
((
insn
&
0x0f8000f0
)
==
0x06800070
)
{
if
((
insn
&
0x00300000
)
==
0x00100000
)
return
INSN_REJECTED
;
/* Unallocated space */
if
((
insn
&
0x000f0000
)
==
0x000f0000
)
return
prep_emulate_rd12rm0
(
insn
,
asi
);
else
return
prep_emulate_rd12rn16rm0_wflags
(
insn
,
asi
);
}
/* Other instruction encodings aren't yet defined */
return
INSN_REJECTED
;
}
static
enum
kprobe_insn
__kprobes
...
...
@@ -1273,29 +1416,49 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
if
((
insn
&
0x0ff000f0
)
==
0x03f000f0
)
return
INSN_REJECTED
;
/* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */
/* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */
if
((
insn
&
0x0ff000f0
)
==
0x07800010
)
return
prep_emulate_rd16rn12rs8rm0_wflags
(
insn
,
asi
);
/* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
/* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
if
((
insn
&
0x0ff00090
)
==
0x07400010
)
return
prep_emulate_rdhi16rdlo12rs8rm0_wflags
(
insn
,
asi
);
/* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */
/* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */
/* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */
/* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */
/* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */
/* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */
/* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */
/* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx : */
/* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx : */
if
((
insn
&
0x0ff00090
)
==
0x07000010
||
(
insn
&
0x0ff000d0
)
==
0x07500010
||
(
insn
&
0x0ff000d0
)
==
0x075000d0
)
return
prep_emulate_rd16rn12rs8rm0_wflags
(
insn
,
asi
);
(
insn
&
0x0ff000f0
)
==
0x07800010
)
{
/* SMUSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx : */
/* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */
/* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */
if
((
insn
&
0x0000f000
)
==
0x0000f000
)
return
prep_emulate_rd16rs8rm0_wflags
(
insn
,
asi
);
else
return
prep_emulate_rd16rn12rs8rm0_wflags
(
insn
,
asi
);
}
/* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */
if
((
insn
&
0x0ff000d0
)
==
0x075000d0
)
return
prep_emulate_rd16rn12rs8rm0_wflags
(
insn
,
asi
);
/* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */
/* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */
if
((
insn
&
0x0fa00070
)
==
0x07a00050
)
return
prep_emulate_rd12rm0
(
insn
,
asi
);
/* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */
/* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */
if
((
insn
&
0x0fe00070
)
==
0x07c00010
)
{
if
((
insn
&
0x0000000f
)
==
0x0000000f
)
return
prep_emulate_rd12_modify
(
insn
,
asi
);
else
return
prep_emulate_rd12rn0_modify
(
insn
,
asi
);
}
return
INSN_REJECTED
;
}
static
enum
kprobe_insn
__kprobes
...
...
@@ -1309,6 +1472,10 @@ space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi)
/* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */
/* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
/* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
if
((
insn
&
0x00500000
)
==
0x00500000
&&
is_r15
(
insn
,
12
))
return
INSN_REJECTED
;
/* LDRB into PC */
return
prep_emulate_ldr_str
(
insn
,
asi
);
}
...
...
@@ -1323,10 +1490,9 @@ space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
/* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
asi
->
insn
[
0
]
=
truecc_insn
(
insn
);
asi
->
insn_handler
=
((
insn
&
0x108000
)
==
0x008000
)
?
/* STM & R15 */
simulate_stm1_pc
:
simulate_ldm1stm1
;
return
INSN_GOOD
;
return
INSN_GOOD
_NO_SLOT
;
}
static
enum
kprobe_insn
__kprobes
...
...
@@ -1334,58 +1500,117 @@ space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
{
/* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
/* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
asi
->
insn
[
0
]
=
truecc_insn
(
insn
);
asi
->
insn_handler
=
simulate_bbl
;
return
INSN_GOOD
;
return
INSN_GOOD
_NO_SLOT
;
}
static
enum
kprobe_insn
__kprobes
space_cccc_11
00_010
x
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
space_cccc_11
x
x
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
/* Coprocessor instructions... */
/* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
/* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
insn
&=
0xfff00fff
;
insn
|=
0x00001000
;
/* Rn = r0, Rd = r1 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
(
insn
&
(
1
<<
20
))
?
emulate_mrrc
:
emulate_mcrr
;
return
INSN_GOOD
;
/* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
/* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
/* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
/* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
/* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
/* SVC : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
return
INSN_REJECTED
;
}
static
enum
kprobe_insn
__kprobes
space_cccc_110x
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
static
unsigned
long
__kprobes
__check_eq
(
unsigned
long
cpsr
)
{
/* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
/* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
insn
&=
0xfff0ffff
;
/* Rn = r0 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_ldcstc
;
return
INSN_GOOD
;
return
cpsr
&
PSR_Z_BIT
;
}
static
enum
kprobe_insn
__kprobes
space_cccc_111x
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
static
unsigned
long
__kprobes
__check_ne
(
unsigned
long
cpsr
)
{
/* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
/* SWI : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
if
((
insn
&
0xfff000f0
)
==
0xe1200070
||
(
insn
&
0x0f000000
)
==
0x0f000000
)
return
INSN_REJECTED
;
return
(
~
cpsr
)
&
PSR_Z_BIT
;
}
/* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
if
((
insn
&
0x0f000010
)
==
0x0e000000
)
{
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
emulate_none
;
return
INSN_GOOD
;
}
static
unsigned
long
__kprobes
__check_cs
(
unsigned
long
cpsr
)
{
return
cpsr
&
PSR_C_BIT
;
}
/* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
/* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
insn
&=
0xffff0fff
;
/* Rd = r0 */
asi
->
insn
[
0
]
=
insn
;
asi
->
insn_handler
=
(
insn
&
(
1
<<
20
))
?
emulate_rd12
:
emulate_ird12
;
return
INSN_GOOD
;
static
unsigned
long
__kprobes
__check_cc
(
unsigned
long
cpsr
)
{
return
(
~
cpsr
)
&
PSR_C_BIT
;
}
static
unsigned
long
__kprobes
__check_mi
(
unsigned
long
cpsr
)
{
return
cpsr
&
PSR_N_BIT
;
}
static
unsigned
long
__kprobes
__check_pl
(
unsigned
long
cpsr
)
{
return
(
~
cpsr
)
&
PSR_N_BIT
;
}
static
unsigned
long
__kprobes
__check_vs
(
unsigned
long
cpsr
)
{
return
cpsr
&
PSR_V_BIT
;
}
static
unsigned
long
__kprobes
__check_vc
(
unsigned
long
cpsr
)
{
return
(
~
cpsr
)
&
PSR_V_BIT
;
}
static
unsigned
long
__kprobes
__check_hi
(
unsigned
long
cpsr
)
{
cpsr
&=
~
(
cpsr
>>
1
);
/* PSR_C_BIT &= ~PSR_Z_BIT */
return
cpsr
&
PSR_C_BIT
;
}
static
unsigned
long
__kprobes
__check_ls
(
unsigned
long
cpsr
)
{
cpsr
&=
~
(
cpsr
>>
1
);
/* PSR_C_BIT &= ~PSR_Z_BIT */
return
(
~
cpsr
)
&
PSR_C_BIT
;
}
static
unsigned
long
__kprobes
__check_ge
(
unsigned
long
cpsr
)
{
cpsr
^=
(
cpsr
<<
3
);
/* PSR_N_BIT ^= PSR_V_BIT */
return
(
~
cpsr
)
&
PSR_N_BIT
;
}
static
unsigned
long
__kprobes
__check_lt
(
unsigned
long
cpsr
)
{
cpsr
^=
(
cpsr
<<
3
);
/* PSR_N_BIT ^= PSR_V_BIT */
return
cpsr
&
PSR_N_BIT
;
}
static
unsigned
long
__kprobes
__check_gt
(
unsigned
long
cpsr
)
{
unsigned
long
temp
=
cpsr
^
(
cpsr
<<
3
);
/* PSR_N_BIT ^= PSR_V_BIT */
temp
|=
(
cpsr
<<
1
);
/* PSR_N_BIT |= PSR_Z_BIT */
return
(
~
temp
)
&
PSR_N_BIT
;
}
static
unsigned
long
__kprobes
__check_le
(
unsigned
long
cpsr
)
{
unsigned
long
temp
=
cpsr
^
(
cpsr
<<
3
);
/* PSR_N_BIT ^= PSR_V_BIT */
temp
|=
(
cpsr
<<
1
);
/* PSR_N_BIT |= PSR_Z_BIT */
return
temp
&
PSR_N_BIT
;
}
static
unsigned
long
__kprobes
__check_al
(
unsigned
long
cpsr
)
{
return
true
;
}
static
kprobe_check_cc
*
const
condition_checks
[
16
]
=
{
&
__check_eq
,
&
__check_ne
,
&
__check_cs
,
&
__check_cc
,
&
__check_mi
,
&
__check_pl
,
&
__check_vs
,
&
__check_vc
,
&
__check_hi
,
&
__check_ls
,
&
__check_ge
,
&
__check_lt
,
&
__check_gt
,
&
__check_le
,
&
__check_al
,
&
__check_al
};
/* Return:
* INSN_REJECTED If instruction is one not allowed to kprobe,
* INSN_GOOD If instruction is supported and uses instruction slot,
...
...
@@ -1401,133 +1626,45 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
enum
kprobe_insn
__kprobes
arm_kprobe_decode_insn
(
kprobe_opcode_t
insn
,
struct
arch_specific_insn
*
asi
)
{
asi
->
insn_check_cc
=
condition_checks
[
insn
>>
28
];
asi
->
insn
[
1
]
=
KPROBE_RETURN_INSTRUCTION
;
if
((
insn
&
0xf0000000
)
==
0xf0000000
)
{
if
((
insn
&
0xf0000000
)
==
0xf0000000
)
return
space_1111
(
insn
,
asi
);
}
else
if
((
insn
&
0x0e000000
)
==
0x00000000
)
{
else
if
((
insn
&
0x0e000000
)
==
0x00000000
)
return
space_cccc_000x
(
insn
,
asi
);
}
else
if
((
insn
&
0x0e000000
)
==
0x02000000
)
{
else
if
((
insn
&
0x0e000000
)
==
0x02000000
)
return
space_cccc_001x
(
insn
,
asi
);
}
else
if
((
insn
&
0x0f000010
)
==
0x06000010
)
{
else
if
((
insn
&
0x0f000010
)
==
0x06000010
)
return
space_cccc_0110__1
(
insn
,
asi
);
}
else
if
((
insn
&
0x0f000010
)
==
0x07000010
)
{
else
if
((
insn
&
0x0f000010
)
==
0x07000010
)
return
space_cccc_0111__1
(
insn
,
asi
);
}
else
if
((
insn
&
0x0c000000
)
==
0x04000000
)
{
else
if
((
insn
&
0x0c000000
)
==
0x04000000
)
return
space_cccc_01xx
(
insn
,
asi
);
}
else
if
((
insn
&
0x0e000000
)
==
0x08000000
)
{
else
if
((
insn
&
0x0e000000
)
==
0x08000000
)
return
space_cccc_100x
(
insn
,
asi
);
}
else
if
((
insn
&
0x0e000000
)
==
0x0a000000
)
{
else
if
((
insn
&
0x0e000000
)
==
0x0a000000
)
return
space_cccc_101x
(
insn
,
asi
);
}
else
if
((
insn
&
0x0fe00000
)
==
0x0c400000
)
{
return
space_cccc_1100_010x
(
insn
,
asi
);
}
else
if
((
insn
&
0x0e000000
)
==
0x0c000000
)
{
return
space_cccc_110x
(
insn
,
asi
);
}
return
space_cccc_111x
(
insn
,
asi
);
return
space_cccc_11xx
(
insn
,
asi
);
}
void
__init
arm_kprobe_decode_init
(
void
)
{
find_str_pc_offset
();
}
/*
* All ARM instructions listed below.
*
* Instructions and their general purpose registers are given.
* If a particular register may not use R15, it is prefixed with a "!".
* If marked with a "*" means the value returned by reading R15
* is implementation defined.
*
* ADC/ADD/AND/BIC/CMN/CMP/EOR/MOV/MVN/ORR/RSB/RSC/SBC/SUB/TEQ
* TST: Rd, Rn, Rm, !Rs
* BX: Rm
* BLX(2): !Rm
* BX: Rm (R15 legal, but discouraged)
* BXJ: !Rm,
* CLZ: !Rd, !Rm
* CPY: Rd, Rm
* LDC/2,STC/2 immediate offset & unindex: Rn
* LDC/2,STC/2 immediate pre/post-indexed: !Rn
* LDM(1/3): !Rn, register_list
* LDM(2): !Rn, !register_list
* LDR,STR,PLD immediate offset: Rd, Rn
* LDR,STR,PLD register offset: Rd, Rn, !Rm
* LDR,STR,PLD scaled register offset: Rd, !Rn, !Rm
* LDR,STR immediate pre/post-indexed: Rd, !Rn
* LDR,STR register pre/post-indexed: Rd, !Rn, !Rm
* LDR,STR scaled register pre/post-indexed: Rd, !Rn, !Rm
* LDRB,STRB immediate offset: !Rd, Rn
* LDRB,STRB register offset: !Rd, Rn, !Rm
* LDRB,STRB scaled register offset: !Rd, !Rn, !Rm
* LDRB,STRB immediate pre/post-indexed: !Rd, !Rn
* LDRB,STRB register pre/post-indexed: !Rd, !Rn, !Rm
* LDRB,STRB scaled register pre/post-indexed: !Rd, !Rn, !Rm
* LDRT,LDRBT,STRBT immediate pre/post-indexed: !Rd, !Rn
* LDRT,LDRBT,STRBT register pre/post-indexed: !Rd, !Rn, !Rm
* LDRT,LDRBT,STRBT scaled register pre/post-indexed: !Rd, !Rn, !Rm
* LDRH/SH/SB/D,STRH/SH/SB/D immediate offset: !Rd, Rn
* LDRH/SH/SB/D,STRH/SH/SB/D register offset: !Rd, Rn, !Rm
* LDRH/SH/SB/D,STRH/SH/SB/D immediate pre/post-indexed: !Rd, !Rn
* LDRH/SH/SB/D,STRH/SH/SB/D register pre/post-indexed: !Rd, !Rn, !Rm
* LDREX: !Rd, !Rn
* MCR/2: !Rd
* MCRR/2,MRRC/2: !Rd, !Rn
* MLA: !Rd, !Rn, !Rm, !Rs
* MOV: Rd
* MRC/2: !Rd (if Rd==15, only changes cond codes, not the register)
* MRS,MSR: !Rd
* MUL: !Rd, !Rm, !Rs
* PKH{BT,TB}: !Rd, !Rn, !Rm
* QDADD,[U]QADD/16/8/SUBX: !Rd, !Rm, !Rn
* QDSUB,[U]QSUB/16/8/ADDX: !Rd, !Rm, !Rn
* REV/16/SH: !Rd, !Rm
* RFE: !Rn
* {S,U}[H]ADD{16,8,SUBX},{S,U}[H]SUB{16,8,ADDX}: !Rd, !Rn, !Rm
* SEL: !Rd, !Rn, !Rm
* SMLA<x><y>,SMLA{D,W<y>},SMLSD,SMML{A,S}: !Rd, !Rn, !Rm, !Rs
* SMLAL<x><y>,SMLA{D,LD},SMLSLD,SMMULL,SMULW<y>: !RdHi, !RdLo, !Rm, !Rs
* SMMUL,SMUAD,SMUL<x><y>,SMUSD: !Rd, !Rm, !Rs
* SSAT/16: !Rd, !Rm
* STM(1/2): !Rn, register_list* (R15 in reg list not recommended)
* STRT immediate pre/post-indexed: Rd*, !Rn
* STRT register pre/post-indexed: Rd*, !Rn, !Rm
* STRT scaled register pre/post-indexed: Rd*, !Rn, !Rm
* STREX: !Rd, !Rn, !Rm
* SWP/B: !Rd, !Rn, !Rm
* {S,U}XTA{B,B16,H}: !Rd, !Rn, !Rm
* {S,U}XT{B,B16,H}: !Rd, !Rm
* UM{AA,LA,UL}L: !RdHi, !RdLo, !Rm, !Rs
* USA{D8,A8,T,T16}: !Rd, !Rm, !Rs
*
* May transfer control by writing R15 (possible mode changes or alternate
* mode accesses marked by "*"):
* ALU op (* with s-bit), B, BL, BKPT, BLX(1/2), BX, BXJ, CPS*, CPY,
* LDM(1), LDM(2/3)*, LDR, MOV, RFE*, SWI*
*
* Instructions that do not take general registers, nor transfer control:
* CDP/2, SETEND, SRS*
*/
arch/arm/kernel/kprobes.c
View file @
408133e9
...
...
@@ -134,6 +134,7 @@ static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs,
struct
kprobe_ctlblk
*
kcb
)
{
regs
->
ARM_pc
+=
4
;
if
(
p
->
ainsn
.
insn_check_cc
(
regs
->
ARM_cpsr
))
p
->
ainsn
.
insn_handler
(
p
,
regs
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment