xref: /linux/arch/arm/probes/uprobes/actions-arm.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8 
9 #include <linux/kernel.h>
10 #include <linux/types.h>
11 #include <linux/stddef.h>
12 #include <linux/wait.h>
13 #include <linux/uprobes.h>
14 #include <linux/module.h>
15 
16 #include "../decode.h"
17 #include "../decode-arm.h"
18 #include "core.h"
19 
20 static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
21 {
22 	probes_opcode_t insn = __mem_to_opcode_arm(*pinsn);
23 	probes_opcode_t temp;
24 	probes_opcode_t mask;
25 	int freereg;
26 	u32 free = 0xffff;
27 	u32 regs;
28 
29 	for (regs = oregs; regs; regs >>= 4, insn >>= 4) {
30 		if ((regs & 0xf) == REG_TYPE_NONE)
31 			continue;
32 
33 		free &= ~(1 << (insn & 0xf));
34 	}
35 
36 	/* No PC, no problem */
37 	if (free & (1 << 15))
38 		return 15;
39 
40 	if (!free)
41 		return -1;
42 
43 	/*
44 	 * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would
45 	 * pick LR instead of R1.
46 	 */
47 	freereg = free = fls(free) - 1;
48 
49 	temp = __mem_to_opcode_arm(*pinsn);
50 	insn = temp;
51 	regs = oregs;
52 	mask = 0xf;
53 
54 	for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) {
55 		if ((regs & 0xf) == REG_TYPE_NONE)
56 			continue;
57 
58 		if ((temp & 0xf) != 15)
59 			continue;
60 
61 		insn &= ~mask;
62 		insn |= free & mask;
63 	}
64 
65 	*pinsn = __opcode_to_mem_arm(insn);
66 	return freereg;
67 }
68 
69 static void uprobe_set_pc(struct arch_uprobe *auprobe,
70 			  struct arch_uprobe_task *autask,
71 			  struct pt_regs *regs)
72 {
73 	u32 pcreg = auprobe->pcreg;
74 
75 	autask->backup = regs->uregs[pcreg];
76 	regs->uregs[pcreg] = regs->ARM_pc + 8;
77 }
78 
79 static void uprobe_unset_pc(struct arch_uprobe *auprobe,
80 			    struct arch_uprobe_task *autask,
81 			    struct pt_regs *regs)
82 {
83 	/* PC will be taken care of by common code */
84 	regs->uregs[auprobe->pcreg] = autask->backup;
85 }
86 
87 static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe,
88 			       struct arch_uprobe_task *autask,
89 			       struct pt_regs *regs)
90 {
91 	u32 pcreg = auprobe->pcreg;
92 
93 	alu_write_pc(regs->uregs[pcreg], regs);
94 	regs->uregs[pcreg] = autask->backup;
95 }
96 
97 static void uprobe_write_pc(struct arch_uprobe *auprobe,
98 			    struct arch_uprobe_task *autask,
99 			    struct pt_regs *regs)
100 {
101 	u32 pcreg = auprobe->pcreg;
102 
103 	load_write_pc(regs->uregs[pcreg], regs);
104 	regs->uregs[pcreg] = autask->backup;
105 }
106 
107 enum probes_insn
108 decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi,
109 	     const struct decode_header *d)
110 {
111 	struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
112 						   asi);
113 	struct decode_emulate *decode = (struct decode_emulate *) d;
114 	u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS;
115 	int reg;
116 
117 	reg = uprobes_substitute_pc(&auprobe->ixol[0], regs);
118 	if (reg == 15)
119 		return INSN_GOOD;
120 
121 	if (reg == -1)
122 		return INSN_REJECTED;
123 
124 	auprobe->pcreg = reg;
125 	auprobe->prehandler = uprobe_set_pc;
126 	auprobe->posthandler = uprobe_unset_pc;
127 
128 	return INSN_GOOD;
129 }
130 
131 enum probes_insn
132 decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi,
133 	     const struct decode_header *d, bool alu)
134 {
135 	struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
136 						   asi);
137 	enum probes_insn ret = decode_pc_ro(insn, asi, d);
138 
139 	if (((insn >> 12) & 0xf) == 15)
140 		auprobe->posthandler = alu ? uprobe_aluwrite_pc
141 					   : uprobe_write_pc;
142 
143 	return ret;
144 }
145 
146 enum probes_insn
147 decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
148 			      struct arch_probes_insn *asi,
149 			      const struct decode_header *d)
150 {
151 	return decode_wb_pc(insn, asi, d, true);
152 }
153 
154 enum probes_insn
155 decode_ldr(probes_opcode_t insn, struct arch_probes_insn *asi,
156 	   const struct decode_header *d)
157 {
158 	return decode_wb_pc(insn, asi, d, false);
159 }
160 
161 enum probes_insn
162 uprobe_decode_ldmstm(probes_opcode_t insn,
163 		     struct arch_probes_insn *asi,
164 		     const struct decode_header *d)
165 {
166 	struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
167 						   asi);
168 	unsigned reglist = insn & 0xffff;
169 	int rn = (insn >> 16) & 0xf;
170 	int lbit = insn & (1 << 20);
171 	unsigned used = reglist | (1 << rn);
172 
173 	if (rn == 15)
174 		return INSN_REJECTED;
175 
176 	if (!(used & (1 << 15)))
177 		return INSN_GOOD;
178 
179 	if (used & (1 << 14))
180 		return INSN_REJECTED;
181 
182 	/* Use LR instead of PC */
183 	insn ^= 0xc000;
184 
185 	auprobe->pcreg = 14;
186 	auprobe->ixol[0] = __opcode_to_mem_arm(insn);
187 
188 	auprobe->prehandler = uprobe_set_pc;
189 	if (lbit)
190 		auprobe->posthandler = uprobe_write_pc;
191 	else
192 		auprobe->posthandler = uprobe_unset_pc;
193 
194 	return INSN_GOOD;
195 }
196 
197 const union decode_action uprobes_probes_actions[] = {
198 	[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
199 	[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
200 	[PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
201 	[PROBES_MRS] = {.handler = simulate_mrs},
202 	[PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
203 	[PROBES_CLZ] = {.handler = probes_simulate_nop},
204 	[PROBES_SATURATING_ARITHMETIC] = {.handler = probes_simulate_nop},
205 	[PROBES_MUL1] = {.handler = probes_simulate_nop},
206 	[PROBES_MUL2] = {.handler = probes_simulate_nop},
207 	[PROBES_SWP] = {.handler = probes_simulate_nop},
208 	[PROBES_LDRSTRD] = {.decoder = decode_pc_ro},
209 	[PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro},
210 	[PROBES_LOAD] = {.decoder = decode_ldr},
211 	[PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro},
212 	[PROBES_STORE] = {.decoder = decode_pc_ro},
213 	[PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
214 	[PROBES_DATA_PROCESSING_REG] = {
215 		.decoder = decode_rd12rn16rm0rs8_rwflags},
216 	[PROBES_DATA_PROCESSING_IMM] = {
217 		.decoder = decode_rd12rn16rm0rs8_rwflags},
218 	[PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop},
219 	[PROBES_SEV] = {.handler = probes_simulate_nop},
220 	[PROBES_WFE] = {.handler = probes_simulate_nop},
221 	[PROBES_SATURATE] = {.handler = probes_simulate_nop},
222 	[PROBES_REV] = {.handler = probes_simulate_nop},
223 	[PROBES_MMI] = {.handler = probes_simulate_nop},
224 	[PROBES_PACK] = {.handler = probes_simulate_nop},
225 	[PROBES_EXTEND] = {.handler = probes_simulate_nop},
226 	[PROBES_EXTEND_ADD] = {.handler = probes_simulate_nop},
227 	[PROBES_MUL_ADD_LONG] = {.handler = probes_simulate_nop},
228 	[PROBES_MUL_ADD] = {.handler = probes_simulate_nop},
229 	[PROBES_BITFIELD] = {.handler = probes_simulate_nop},
230 	[PROBES_BRANCH] = {.handler = simulate_bbl},
231 	[PROBES_LDMSTM] = {.decoder = uprobe_decode_ldmstm}
232 };
233