[REFACTOR] extract arch specific code from kprobe to uprobe
[kernel/swap-modules.git] / uprobe / arch / asm-arm / swap_uprobes.c
1 #include <dbi_kprobes.h>
2 #include <asm/dbi_kprobes.h>
3
4 // FIXME:
5 #include <dbi_kdebug.h>
6 extern struct hlist_head uprobe_insn_pages;
7 kprobe_opcode_t *get_insn_slot(struct task_struct *task, int atomic);
8 int arch_check_insn_arm(struct arch_specific_insn *ainsn);
9 int prep_pc_dep_insn_execbuf(kprobe_opcode_t *insns, kprobe_opcode_t insn, int uregs);
10 void free_insn_slot(struct hlist_head *page_list, struct task_struct *task, kprobe_opcode_t *slot);
11 int isThumb2(kprobe_opcode_t insn);
12 void pc_dep_insn_execbuf(void);
13 void gen_insn_execbuf(void);
14 void gen_insn_execbuf_thumb(void);
15 void pc_dep_insn_execbuf_thumb(void);
16
17
18 #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
19 #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
20
21 static kprobe_opcode_t get_addr_b(kprobe_opcode_t insn, kprobe_opcode_t *addr)
22 {
23         // real position less then PC by 8
24         return (kprobe_opcode_t)((long)addr + 8 + branch_displacement(insn));
25 }
26
27 static int arch_copy_trampoline_arm_uprobe(struct kprobe *p, struct task_struct *task, int atomic)
28 {
29         kprobe_opcode_t insns[UPROBES_TRAMP_LEN];
30         int uregs, pc_dep;
31         kprobe_opcode_t insn[MAX_INSN_SIZE];
32         struct arch_specific_insn ainsn;
33
34         p->safe_arm = -1;
35         if ((unsigned long)p->addr & 0x01) {
36                 printk("Error in %s at %d: attempt to register kprobe at an unaligned address\n", __FILE__, __LINE__);
37                 return -EINVAL;
38         }
39
40         insn[0] = p->opcode;
41         ainsn.insn_arm = insn;
42         if (!arch_check_insn_arm(&ainsn)) {
43                 p->safe_arm = 0;
44         }
45
46         uregs = pc_dep = 0;
47         // Rn, Rm ,Rd
48         if (ARM_INSN_MATCH(DPIS, insn[0]) || ARM_INSN_MATCH(LRO, insn[0]) ||
49             ARM_INSN_MATCH(SRO, insn[0])) {
50                 uregs = 0xb;
51                 if ((ARM_INSN_REG_RN(insn[0]) == 15) || (ARM_INSN_REG_RM(insn[0]) == 15) ||
52                     (ARM_INSN_MATCH(SRO, insn[0]) && (ARM_INSN_REG_RD(insn[0]) == 15))) {
53                         DBPRINTF("Unboostable insn %lx, DPIS/LRO/SRO\n", insn[0]);
54                         pc_dep = 1;
55                 }
56
57         // Rn ,Rd
58         } else if (ARM_INSN_MATCH(DPI, insn[0]) || ARM_INSN_MATCH(LIO, insn[0]) ||
59                    ARM_INSN_MATCH (SIO, insn[0])) {
60                 uregs = 0x3;
61                 if ((ARM_INSN_REG_RN(insn[0]) == 15) || (ARM_INSN_MATCH(SIO, insn[0]) &&
62                     (ARM_INSN_REG_RD(insn[0]) == 15))) {
63                         pc_dep = 1;
64                         DBPRINTF("Unboostable insn %lx/%p, DPI/LIO/SIO\n", insn[0], p);
65                 }
66
67         // Rn, Rm, Rs
68         } else if (ARM_INSN_MATCH(DPRS, insn[0])) {
69                 uregs = 0xd;
70                 if ((ARM_INSN_REG_RN(insn[0]) == 15) || (ARM_INSN_REG_RM(insn[0]) == 15) ||
71                     (ARM_INSN_REG_RS(insn[0]) == 15)) {
72                         pc_dep = 1;
73                         DBPRINTF("Unboostable insn %lx, DPRS\n", insn[0]);
74                 }
75
76         // register list
77         } else if (ARM_INSN_MATCH(SM, insn[0])) {
78                 uregs = 0x10;
79                 if (ARM_INSN_REG_MR (insn[0], 15))
80                 {
81                         DBPRINTF ("Unboostable insn %lx, SM\n", insn[0]);
82                         pc_dep = 1;
83                 }
84         }
85
86         // check instructions that can write result to SP andu uses PC
87         if (pc_dep  && (ARM_INSN_REG_RD (ainsn.insn_arm[0]) == 13)) {
88                 printk("Error in %s at %d: instruction check failed (arm)\n", __FILE__, __LINE__);
89                 p->safe_arm = -1;
90                 // TODO: move free to later phase
91                 //free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_arm, 0);
92                 //ret = -EFAULT;
93         }
94
95         if (unlikely(uregs && pc_dep)) {
96                 memcpy(insns, pc_dep_insn_execbuf, sizeof(insns));
97                 if (prep_pc_dep_insn_execbuf(insns, insn[0], uregs) != 0) {
98                         printk("Error in %s at %d: failed to prepare exec buffer for insn %lx!",
99                                __FILE__, __LINE__, insn[0]);
100                         p->safe_arm = -1;
101                         // TODO: move free to later phase
102                         //free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_arm, 0);
103                         //return -EINVAL;
104                 }
105
106                 insns[6] = (kprobe_opcode_t) (p->addr + 2);
107         } else {
108                 memcpy(insns, gen_insn_execbuf, sizeof(insns));
109                 insns[UPROBES_TRAMP_INSN_IDX] = insn[0];
110         }
111
112         insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
113         insns[7] = (kprobe_opcode_t) (p->addr + 1);
114
115         // B
116         if(ARM_INSN_MATCH(B, ainsn.insn_arm[0])) {
117                 memcpy(insns, pc_dep_insn_execbuf, sizeof(insns));
118                 insns[UPROBES_TRAMP_RET_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
119                 insns[6] = (kprobe_opcode_t)(p->addr + 2);
120                 insns[7] = get_addr_b(p->opcode, p->addr);
121         }
122
123         DBPRINTF("arch_prepare_uprobe: to %p - %lx %lx %lx %lx %lx %lx %lx %lx %lx",
124                  p->ainsn.insn_arm, insns[0], insns[1], insns[2], insns[3], insns[4],
125                  insns[5], insns[6], insns[7], insns[8]);
126         if (!write_proc_vm_atomic(task, (unsigned long)p->ainsn.insn_arm, insns, sizeof(insns))) {
127                 panic("failed to write memory %p!\n", p->ainsn.insn_arm);
128                 // Mr_Nobody: we have to panic, really??...
129                 //free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_arm, 0);
130                 //return -EINVAL;
131         }
132
133         return 0;
134 }
135
136 static int arch_check_insn_thumb(struct arch_specific_insn *ainsn)
137 {
138         int ret = 0;
139
140         // check instructions that can change PC
141         if (THUMB_INSN_MATCH(UNDEF, ainsn->insn_thumb[0]) ||
142             THUMB_INSN_MATCH(SWI, ainsn->insn_thumb[0]) ||
143             THUMB_INSN_MATCH(BREAK, ainsn->insn_thumb[0]) ||
144             THUMB2_INSN_MATCH(BL, ainsn->insn_thumb[0]) ||
145             THUMB_INSN_MATCH(B1, ainsn->insn_thumb[0]) ||
146             THUMB_INSN_MATCH(B2, ainsn->insn_thumb[0]) ||
147             THUMB_INSN_MATCH(CBZ, ainsn->insn_thumb[0]) ||
148             THUMB2_INSN_MATCH(B1, ainsn->insn_thumb[0]) ||
149             THUMB2_INSN_MATCH(B2, ainsn->insn_thumb[0]) ||
150             THUMB2_INSN_MATCH(BLX1, ainsn->insn_thumb[0]) ||
151             THUMB_INSN_MATCH(BLX2, ainsn->insn_thumb[0]) ||
152             THUMB_INSN_MATCH(BX, ainsn->insn_thumb[0]) ||
153             THUMB2_INSN_MATCH(BXJ, ainsn->insn_thumb[0]) ||
154             (THUMB2_INSN_MATCH(ADR, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RD(ainsn->insn_thumb[0]) == 15) ||
155             (THUMB2_INSN_MATCH(LDRW, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RT(ainsn->insn_thumb[0]) == 15) ||
156             (THUMB2_INSN_MATCH(LDRW1, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RT(ainsn->insn_thumb[0]) == 15) ||
157             (THUMB2_INSN_MATCH(LDRHW, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RT(ainsn->insn_thumb[0]) == 15) ||
158             (THUMB2_INSN_MATCH(LDRHW1, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RT(ainsn->insn_thumb[0]) == 15) ||
159             (THUMB2_INSN_MATCH(LDRWL, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RT(ainsn->insn_thumb[0]) == 15) ||
160             THUMB2_INSN_MATCH(LDMIA, ainsn->insn_thumb[0]) ||
161             THUMB2_INSN_MATCH(LDMDB, ainsn->insn_thumb[0]) ||
162             (THUMB2_INSN_MATCH(DP, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RD(ainsn->insn_thumb[0]) == 15) ||
163             (THUMB2_INSN_MATCH(RSBW, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RD(ainsn->insn_thumb[0]) == 15) ||
164             (THUMB2_INSN_MATCH(RORW, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RD(ainsn->insn_thumb[0]) == 15) ||
165             (THUMB2_INSN_MATCH(ROR, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RD(ainsn->insn_thumb[0]) == 15) ||
166             (THUMB2_INSN_MATCH(LSLW1, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RD(ainsn->insn_thumb[0]) == 15) ||
167             (THUMB2_INSN_MATCH(LSLW2, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RD(ainsn->insn_thumb[0]) == 15) ||
168             (THUMB2_INSN_MATCH(LSRW1, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RD(ainsn->insn_thumb[0]) == 15) ||
169             (THUMB2_INSN_MATCH(LSRW2, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RD(ainsn->insn_thumb[0]) == 15) ||
170             /* skip PC, #-imm12 -> SP, #-imm8 and Tegra-hanging instructions */
171             (THUMB2_INSN_MATCH(STRW1, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RN(ainsn->insn_thumb[0]) == 15) ||
172             (THUMB2_INSN_MATCH(STRBW1, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RN(ainsn->insn_thumb[0]) == 15) ||
173             (THUMB2_INSN_MATCH(STRHW1, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RN(ainsn->insn_thumb[0]) == 15) ||
174             (THUMB2_INSN_MATCH(STRW, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RN(ainsn->insn_thumb[0]) == 15) ||
175             (THUMB2_INSN_MATCH(STRHW, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RN(ainsn->insn_thumb[0]) == 15) ||
176             (THUMB2_INSN_MATCH(LDRW, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RN(ainsn->insn_thumb[0]) == 15) ||
177             (THUMB2_INSN_MATCH(LDRBW, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RN(ainsn->insn_thumb[0]) == 15) ||
178             (THUMB2_INSN_MATCH(LDRHW, ainsn->insn_thumb[0]) && THUMB2_INSN_REG_RN(ainsn->insn_thumb[0]) == 15) ||
179             /* skip STRDx/LDRDx Rt, Rt2, [Rd, ...] */
180             (THUMB2_INSN_MATCH(LDRD, ainsn->insn_thumb[0]) || THUMB2_INSN_MATCH(LDRD1, ainsn->insn_thumb[0]) || THUMB2_INSN_MATCH(STRD, ainsn->insn_thumb[0])) ) {
181                 DBPRINTF("Bad insn arch_check_insn_thumb: %lx\n", ainsn->insn_thumb[0]);
182                 ret = -EFAULT;
183         }
184
185         return ret;
186 }
187
188 static int prep_pc_dep_insn_execbuf_thumb(kprobe_opcode_t * insns, kprobe_opcode_t insn, int uregs)
189 {
190         unsigned char mreg = 0;
191         unsigned char reg = 0;
192
193         if (THUMB_INSN_MATCH(APC, insn) || THUMB_INSN_MATCH(LRO3, insn)) {
194                 reg = ((insn & 0xffff) & uregs) >> 8;
195         } else {
196                 if (THUMB_INSN_MATCH(MOV3, insn)) {
197                         if (((((unsigned char) insn) & 0xff) >> 3) == 15) {
198                                 reg = (insn & 0xffff) & uregs;
199                         } else {
200                                 return 0;
201                         }
202                 } else {
203                         if (THUMB2_INSN_MATCH(ADR, insn)) {
204                                 reg = ((insn >> 16) & uregs) >> 8;
205                                 if (reg == 15) {
206                                         return 0;
207                                 }
208                         } else {
209                                 if (THUMB2_INSN_MATCH(LDRW, insn) || THUMB2_INSN_MATCH(LDRW1, insn) ||
210                                     THUMB2_INSN_MATCH(LDRHW, insn) || THUMB2_INSN_MATCH(LDRHW1, insn) ||
211                                     THUMB2_INSN_MATCH(LDRWL, insn)) {
212                                         reg = ((insn >> 16) & uregs) >> 12;
213                                         if (reg == 15) {
214                                                 return 0;
215                                         }
216                                 } else {
217                                         // LDRB.W PC, [PC, #immed] => PLD [PC, #immed], so Rt == PC is skipped
218                                         if (THUMB2_INSN_MATCH(LDRBW, insn) || THUMB2_INSN_MATCH(LDRBW1, insn) ||
219                                             THUMB2_INSN_MATCH(LDREX, insn)) {
220                                                 reg = ((insn >> 16) & uregs) >> 12;
221                                         } else {
222                                                 if (THUMB2_INSN_MATCH(DP, insn)) {
223                                                         reg = ((insn >> 16) & uregs) >> 12;
224                                                         if (reg == 15) {
225                                                                 return 0;
226                                                         }
227                                                 } else {
228                                                         if (THUMB2_INSN_MATCH(RSBW, insn)) {
229                                                                 reg = ((insn >> 12) & uregs) >> 8;
230                                                                 if (reg == 15){
231                                                                         return 0;
232                                                                 }
233                                                         } else {
234                                                                 if (THUMB2_INSN_MATCH(RORW, insn)) {
235                                                                         reg = ((insn >> 12) & uregs) >> 8;
236                                                                         if (reg == 15) {
237                                                                                 return 0;
238                                                                         }
239                                                                 } else {
240                                                                         if (THUMB2_INSN_MATCH(ROR, insn) || THUMB2_INSN_MATCH(LSLW1, insn) ||
241                                                                             THUMB2_INSN_MATCH(LSLW2, insn) || THUMB2_INSN_MATCH(LSRW1, insn) ||
242                                                                             THUMB2_INSN_MATCH(LSRW2, insn)) {
243                                                                                 reg = ((insn >> 12) & uregs) >> 8;
244                                                                                 if (reg == 15) {
245                                                                                         return 0;
246                                                                                 }
247                                                                         } else {
248                                                                                 if (THUMB2_INSN_MATCH(TEQ1, insn) || THUMB2_INSN_MATCH(TST1, insn)) {
249                                                                                         reg = 15;
250                                                                                 } else {
251                                                                                         if (THUMB2_INSN_MATCH(TEQ2, insn) || THUMB2_INSN_MATCH(TST2, insn)) {
252                                                                                                 reg = THUMB2_INSN_REG_RM(insn);
253                                                                                         }
254                                                                                 }
255                                                                         }
256                                                                 }
257                                                         }
258                                                 }
259                                         }
260                                 }
261                         }
262                 }
263         }
264
265         if ((THUMB2_INSN_MATCH(STRW, insn) || THUMB2_INSN_MATCH(STRBW, insn) ||
266              THUMB2_INSN_MATCH(STRD, insn) || THUMB2_INSN_MATCH(STRHT, insn) ||
267              THUMB2_INSN_MATCH(STRT, insn) || THUMB2_INSN_MATCH(STRHW1, insn) ||
268              THUMB2_INSN_MATCH(STRHW, insn)) && THUMB2_INSN_REG_RT(insn) == 15) {
269                 reg = THUMB2_INSN_REG_RT(insn);
270         }
271
272         if (reg == 6 || reg == 7) {
273                 *((unsigned short*)insns + 0) = (*((unsigned short*)insns + 0) & 0x00ff) | ((1 << mreg) | (1 << (mreg + 1)));
274                 *((unsigned short*)insns + 1) = (*((unsigned short*)insns + 1) & 0xf8ff) | (mreg << 8);
275                 *((unsigned short*)insns + 2) = (*((unsigned short*)insns + 2) & 0xfff8) | (mreg + 1);
276                 *((unsigned short*)insns + 3) = (*((unsigned short*)insns + 3) & 0xffc7) | (mreg << 3);
277                 *((unsigned short*)insns + 7) = (*((unsigned short*)insns + 7) & 0xf8ff) | (mreg << 8);
278                 *((unsigned short*)insns + 8) = (*((unsigned short*)insns + 8) & 0xffc7) | (mreg << 3);
279                 *((unsigned short*)insns + 9) = (*((unsigned short*)insns + 9) & 0xffc7) | ((mreg + 1) << 3);
280                 *((unsigned short*)insns + 10) = (*((unsigned short*)insns + 10) & 0x00ff) | (( 1 << mreg) | (1 << (mreg + 1)));
281         }
282
283         if (THUMB_INSN_MATCH(APC, insn)) {
284                 // ADD Rd, PC, #immed_8*4 -> ADD Rd, SP, #immed_8*4
285                 *((unsigned short*)insns + 4) = ((insn & 0xffff) | 0x800);                              // ADD Rd, SP, #immed_8*4
286         } else {
287                 if (THUMB_INSN_MATCH(LRO3, insn)) {
288                         // LDR Rd, [PC, #immed_8*4] -> LDR Rd, [SP, #immed_8*4]
289                         *((unsigned short*)insns + 4) = ((insn & 0xffff) + 0x5000);                     // LDR Rd, [SP, #immed_8*4]
290                 } else {
291                         if (THUMB_INSN_MATCH(MOV3, insn)) {
292                                 // MOV Rd, PC -> MOV Rd, SP
293                                 *((unsigned short*)insns + 4) = ((insn & 0xffff) ^ 0x10);               // MOV Rd, SP
294                         } else {
295                                 if (THUMB2_INSN_MATCH(ADR, insn)) {
296                                         // ADDW Rd, PC, #imm -> ADDW Rd, SP, #imm
297                                         insns[2] = (insn & 0xfffffff0) | 0x0d;                          // ADDW Rd, SP, #imm
298                                 } else {
299                                         if (THUMB2_INSN_MATCH(LDRW, insn) || THUMB2_INSN_MATCH(LDRBW, insn) ||
300                                             THUMB2_INSN_MATCH(LDRHW, insn)) {
301                                                 // LDR.W Rt, [PC, #-<imm_12>] -> LDR.W Rt, [SP, #-<imm_8>]
302                                                 // !!!!!!!!!!!!!!!!!!!!!!!!
303                                                 // !!! imm_12 vs. imm_8 !!!
304                                                 // !!!!!!!!!!!!!!!!!!!!!!!!
305                                                 insns[2] = (insn & 0xf0fffff0) | 0x0c00000d;            // LDR.W Rt, [SP, #-<imm_8>]
306                                         } else {
307                                                 if (THUMB2_INSN_MATCH(LDRW1, insn) || THUMB2_INSN_MATCH(LDRBW1, insn) ||
308                                                     THUMB2_INSN_MATCH(LDRHW1, insn) || THUMB2_INSN_MATCH(LDRD, insn) ||
309                                                     THUMB2_INSN_MATCH(LDRD1, insn) || THUMB2_INSN_MATCH(LDREX, insn)) {
310                                                         // LDRx.W Rt, [PC, #+<imm_12>] -> LDRx.W Rt, [SP, #+<imm_12>] (+/-imm_8 for LDRD Rt, Rt2, [PC, #<imm_8>]
311                                                         insns[2] = (insn & 0xfffffff0) | 0xd;                                                                                                   // LDRx.W Rt, [SP, #+<imm_12>]
312                                                 } else {
313                                                         if (THUMB2_INSN_MATCH(MUL, insn)) {
314                                                                 insns[2] = (insn & 0xfff0ffff) | 0x000d0000;                                                                                    // MUL Rd, Rn, SP
315                                                         } else {
316                                                                 if (THUMB2_INSN_MATCH(DP, insn)) {
317                                                                         if (THUMB2_INSN_REG_RM(insn) == 15) {
318                                                                                 insns[2] = (insn & 0xfff0ffff) | 0x000d0000;                                                                    // DP Rd, Rn, PC
319                                                                         } else if (THUMB2_INSN_REG_RN(insn) == 15) {
320                                                                                 insns[2] = (insn & 0xfffffff0) | 0xd;                                                                           // DP Rd, PC, Rm
321                                                                         }
322                                                                 } else {
323                                                                         if (THUMB2_INSN_MATCH(LDRWL, insn)) {
324                                                                                 // LDRx.W Rt, [PC, #<imm_12>] -> LDRx.W Rt, [SP, #+<imm_12>] (+/-imm_8 for LDRD Rt, Rt2, [PC, #<imm_8>]
325                                                                                 insns[2] = (insn & 0xfffffff0) | 0xd;                                                                           // LDRx.W Rt, [SP, #+<imm_12>]
326                                                                         } else {
327                                                                                 if (THUMB2_INSN_MATCH(RSBW, insn)) {
328                                                                                         insns[2] = (insn & 0xfffffff0) | 0xd;                                                                   // RSB{S}.W Rd, PC, #<const> -> RSB{S}.W Rd, SP, #<const>
329                                                                                 } else {
330                                                                                         if (THUMB2_INSN_MATCH(RORW, insn) || THUMB2_INSN_MATCH(LSLW1, insn) || THUMB2_INSN_MATCH(LSRW1, insn)) {
331                                                                                                 if ((THUMB2_INSN_REG_RM(insn) == 15) && (THUMB2_INSN_REG_RN(insn) == 15)) {
332                                                                                                         insns[2] = (insn & 0xfffdfffd);                                                         // ROR.W Rd, PC, PC
333                                                                                                 } else if (THUMB2_INSN_REG_RM(insn) == 15) {
334                                                                                                         insns[2] = (insn & 0xfff0ffff) | 0xd0000;                                               // ROR.W Rd, Rn, PC
335                                                                                                 } else if (THUMB2_INSN_REG_RN(insn) == 15) {
336                                                                                                         insns[2] = (insn & 0xfffffff0) | 0xd;                                                   // ROR.W Rd, PC, Rm
337                                                                                                 }
338                                                                                         } else {
339                                                                                                 if (THUMB2_INSN_MATCH(ROR, insn) || THUMB2_INSN_MATCH(LSLW2, insn) || THUMB2_INSN_MATCH(LSRW2, insn)) {
340                                                                                                         insns[2] = (insn & 0xfff0ffff) | 0xd0000;                                               // ROR{S} Rd, PC, #<const> -> ROR{S} Rd, SP, #<const>
341                                                                                                 }
342                                                                                         }
343                                                                                 }
344                                                                         }
345                                                                 }
346                                                         }
347                                                 }
348                                         }
349                                 }
350                         }
351                 }
352         }
353
354         if (THUMB2_INSN_MATCH(STRW, insn) || THUMB2_INSN_MATCH(STRBW, insn)) {
355                 insns[2] = (insn & 0xfff0ffff) | 0x000d0000;                                                            // STRx.W Rt, [Rn, SP]
356         } else {
357                 if (THUMB2_INSN_MATCH(STRD, insn) || THUMB2_INSN_MATCH(STRHT, insn) ||
358                     THUMB2_INSN_MATCH(STRT, insn) || THUMB2_INSN_MATCH(STRHW1, insn)) {
359                         if (THUMB2_INSN_REG_RN(insn) == 15) {
360                                 insns[2] = (insn & 0xfffffff0) | 0xd;                                                   // STRD/T/HT{.W} Rt, [SP, ...]
361                         } else {
362                                 insns[2] = insn;
363                         }
364                 } else {
365                         if (THUMB2_INSN_MATCH(STRHW, insn) && (THUMB2_INSN_REG_RN(insn) == 15)) {
366                                 if (THUMB2_INSN_REG_RN(insn) == 15) {
367                                         insns[2] = (insn & 0xf0fffff0) | 0x0c00000d;                                    // STRH.W Rt, [SP, #-<imm_8>]
368                                 } else {
369                                         insns[2] = insn;
370                                 }
371                         }
372                 }
373         }
374
375         // STRx PC, xxx
376         if ((reg == 15) && (THUMB2_INSN_MATCH(STRW, insn)   ||
377                             THUMB2_INSN_MATCH(STRBW, insn)  ||
378                             THUMB2_INSN_MATCH(STRD, insn)   ||
379                             THUMB2_INSN_MATCH(STRHT, insn)  ||
380                             THUMB2_INSN_MATCH(STRT, insn)   ||
381                             THUMB2_INSN_MATCH(STRHW1, insn) ||
382                             THUMB2_INSN_MATCH(STRHW, insn) )) {
383                 insns[2] = (insns[2] & 0x0fffffff) | 0xd0000000;
384         }
385
386         if (THUMB2_INSN_MATCH(TEQ1, insn) || THUMB2_INSN_MATCH(TST1, insn)) {
387                 insns[2] = (insn & 0xfffffff0) | 0xd;                                                                   // TEQ SP, #<const>
388         } else {
389                 if (THUMB2_INSN_MATCH(TEQ2, insn) || THUMB2_INSN_MATCH(TST2, insn)) {
390                         if ((THUMB2_INSN_REG_RN(insn) == 15) && (THUMB2_INSN_REG_RM(insn) == 15)) {
391                                 insns[2] = (insn & 0xfffdfffd);                                                         // TEQ/TST PC, PC
392                         } else if (THUMB2_INSN_REG_RM(insn) == 15) {
393                                 insns[2] = (insn & 0xfff0ffff) | 0xd0000;                                               // TEQ/TST Rn, PC
394                         } else if (THUMB2_INSN_REG_RN(insn) == 15) {
395                                 insns[2] = (insn & 0xfffffff0) | 0xd;                                                   // TEQ/TST PC, Rm
396                         }
397                 }
398         }
399
400         return 0;
401 }
402
403 static int arch_copy_trampoline_thumb_uprobe(struct kprobe *p, struct task_struct *task, int atomic)
404 {
405         int uregs, pc_dep;
406         unsigned int addr;
407         kprobe_opcode_t insn[MAX_INSN_SIZE];
408         struct arch_specific_insn ainsn;
409         kprobe_opcode_t insns[UPROBES_TRAMP_LEN * 2];
410
411         p->safe_thumb = -1;
412         if ((unsigned long)p->addr & 0x01) {
413                 printk("Error in %s at %d: attempt to register kprobe at an unaligned address\n", __FILE__, __LINE__);
414                 return -EINVAL;
415         }
416
417         insn[0] = p->opcode;
418         ainsn.insn_thumb = insn;
419         if (!arch_check_insn_thumb(&ainsn)) {
420                 p->safe_thumb = 0;
421         }
422
423         uregs = 0;
424         pc_dep = 0;
425
426         if (THUMB_INSN_MATCH(APC, insn[0]) || THUMB_INSN_MATCH(LRO3, insn[0])) {
427                 uregs = 0x0700;         // 8-10
428                 pc_dep = 1;
429         } else if (THUMB_INSN_MATCH(MOV3, insn[0]) && (((((unsigned char)insn[0]) & 0xff) >> 3) == 15)) {
430                 // MOV Rd, PC
431                 uregs = 0x07;
432                 pc_dep = 1;
433         } else if THUMB2_INSN_MATCH(ADR, insn[0]) {
434                 uregs = 0x0f00;         // Rd 8-11
435                 pc_dep = 1;
436         } else if (((THUMB2_INSN_MATCH(LDRW, insn[0]) || THUMB2_INSN_MATCH(LDRW1, insn[0]) ||
437                      THUMB2_INSN_MATCH(LDRBW, insn[0]) || THUMB2_INSN_MATCH(LDRBW1, insn[0]) ||
438                      THUMB2_INSN_MATCH(LDRHW, insn[0]) || THUMB2_INSN_MATCH(LDRHW1, insn[0]) ||
439                      THUMB2_INSN_MATCH(LDRWL, insn[0])) && THUMB2_INSN_REG_RN(insn[0]) == 15) ||
440                      THUMB2_INSN_MATCH(LDREX, insn[0]) ||
441                      ((THUMB2_INSN_MATCH(STRW, insn[0]) || THUMB2_INSN_MATCH(STRBW, insn[0]) ||
442                        THUMB2_INSN_MATCH(STRHW, insn[0]) || THUMB2_INSN_MATCH(STRHW1, insn[0])) &&
443                       (THUMB2_INSN_REG_RN(insn[0]) == 15 || THUMB2_INSN_REG_RT(insn[0]) == 15)) ||
444                      ((THUMB2_INSN_MATCH(STRT, insn[0]) || THUMB2_INSN_MATCH(STRHT, insn[0])) &&
445                        (THUMB2_INSN_REG_RN(insn[0]) == 15 || THUMB2_INSN_REG_RT(insn[0]) == 15))) {
446                 uregs = 0xf000;         // Rt 12-15
447                 pc_dep = 1;
448         } else if ((THUMB2_INSN_MATCH(LDRD, insn[0]) || THUMB2_INSN_MATCH(LDRD1, insn[0])) && (THUMB2_INSN_REG_RN(insn[0]) == 15)) {
449                 uregs = 0xff00;         // Rt 12-15, Rt2 8-11
450                 pc_dep = 1;
451         } else if (THUMB2_INSN_MATCH(MUL, insn[0]) && THUMB2_INSN_REG_RM(insn[0]) == 15) {
452                 uregs = 0xf;
453                 pc_dep = 1;
454         } else if (THUMB2_INSN_MATCH(DP, insn[0]) && (THUMB2_INSN_REG_RN(insn[0]) == 15 || THUMB2_INSN_REG_RM(insn[0]) == 15)) {
455                 uregs = 0xf000;         // Rd 12-15
456                 pc_dep = 1;
457         } else if (THUMB2_INSN_MATCH(STRD, insn[0]) && ((THUMB2_INSN_REG_RN(insn[0]) == 15) || (THUMB2_INSN_REG_RT(insn[0]) == 15) || THUMB2_INSN_REG_RT2(insn[0]) == 15)) {
458                 uregs = 0xff00;         // Rt 12-15, Rt2 8-11
459                 pc_dep = 1;
460         } else if (THUMB2_INSN_MATCH(RSBW, insn[0]) && THUMB2_INSN_REG_RN(insn[0]) == 15) {
461                 uregs = 0x0f00;         // Rd 8-11
462                 pc_dep = 1;
463         } else if (THUMB2_INSN_MATCH (RORW, insn[0]) && (THUMB2_INSN_REG_RN(insn[0]) == 15 || THUMB2_INSN_REG_RM(insn[0]) == 15)) {
464                 uregs = 0x0f00;
465                 pc_dep = 1;
466         } else if ((THUMB2_INSN_MATCH(ROR, insn[0]) || THUMB2_INSN_MATCH(LSLW2, insn[0]) || THUMB2_INSN_MATCH(LSRW2, insn[0])) && THUMB2_INSN_REG_RM(insn[0]) == 15) {
467                 uregs = 0x0f00;         // Rd 8-11
468                 pc_dep = 1;
469         } else if ((THUMB2_INSN_MATCH(LSLW1, insn[0]) || THUMB2_INSN_MATCH(LSRW1, insn[0])) && (THUMB2_INSN_REG_RN(insn[0]) == 15 || THUMB2_INSN_REG_RM(insn[0]) == 15)) {
470                 uregs = 0x0f00;         // Rd 8-11
471                 pc_dep = 1;
472         } else if ((THUMB2_INSN_MATCH(TEQ1, insn[0]) || THUMB2_INSN_MATCH(TST1, insn[0])) && THUMB2_INSN_REG_RN(insn[0]) == 15) {
473                 uregs = 0xf0000;        //Rn 0-3 (16-19)
474                 pc_dep = 1;
475         } else if ((THUMB2_INSN_MATCH(TEQ2, insn[0]) || THUMB2_INSN_MATCH(TST2, insn[0])) &&
476                    (THUMB2_INSN_REG_RN(insn[0]) == 15 || THUMB2_INSN_REG_RM(insn[0]) == 15)) {
477                 uregs = 0xf0000;        //Rn 0-3 (16-19)
478                 pc_dep = 1;
479         }
480
481         if (unlikely(uregs && pc_dep)) {
482                 memcpy(insns, pc_dep_insn_execbuf_thumb, 18 * 2);
483                 if (prep_pc_dep_insn_execbuf_thumb(insns, insn[0], uregs) != 0) {
484                         printk("Error in %s at %d: failed to prepare exec buffer for insn %lx!",
485                                __FILE__, __LINE__, insn[0]);
486                         p->safe_thumb = -1;
487                         //free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_thumb, 0);
488                         //return -EINVAL;
489                 }
490
491                 addr = ((unsigned int)p->addr) + 4;
492                 *((unsigned short*)insns + 13) = 0xdeff;
493                 *((unsigned short*)insns + 14) = addr & 0x0000ffff;
494                 *((unsigned short*)insns + 15) = addr >> 16;
495                 if (!isThumb2(insn[0])) {
496                         addr = ((unsigned int)p->addr) + 2;
497                         *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
498                         *((unsigned short*)insns + 17) = addr >> 16;
499                 } else {
500                         addr = ((unsigned int)p->addr) + 4;
501                         *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
502                         *((unsigned short*)insns + 17) = addr >> 16;
503                 }
504         } else {
505                 memcpy(insns, gen_insn_execbuf_thumb, 18 * 2);
506                 *((unsigned short*)insns + 13) = 0xdeff;
507                 if (!isThumb2(insn[0])) {
508                         addr = ((unsigned int)p->addr) + 2;
509                         *((unsigned short*)insns + 2) = insn[0];
510                         *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
511                         *((unsigned short*)insns + 17) = addr >> 16;
512                 } else {
513                         addr = ((unsigned int)p->addr) + 4;
514                         insns[1] = insn[0];
515                         *((unsigned short*)insns + 16) = (addr & 0x0000ffff) | 0x1;
516                         *((unsigned short*)insns + 17) = addr >> 16;
517                 }
518         }
519
520         if (!write_proc_vm_atomic (task, (unsigned long)p->ainsn.insn_thumb, insns, 18 * 2)) {
521                 panic("failed to write memory %p!\n", p->ainsn.insn_thumb);
522                 // Mr_Nobody: we have to panic, really??...
523                 //free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_thumb, 0);
524                 //return -EINVAL;
525         }
526
527         return 0;
528 }
529
530 int arch_prepare_uprobe(struct kprobe *p, struct task_struct *task, int atomic)
531 {
532         int ret = 0;
533         kprobe_opcode_t insn[MAX_INSN_SIZE];
534
535         if ((unsigned long)p->addr & 0x01) {
536                 printk("Error in %s at %d: attempt to register kprobe at an unaligned address\n", __FILE__, __LINE__);
537                 return -EINVAL;
538         }
539
540         if (!read_proc_vm_atomic(task, (unsigned long)p->addr, &insn, MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) {
541                 panic("Failed to read memory task[tgid=%u, comm=%s] %p!\n", task->tgid, task->comm, p->addr);
542         }
543
544         p->opcode = insn[0];
545         p->ainsn.insn_arm = get_insn_slot(task, atomic);
546         if (!p->ainsn.insn_arm) {
547                 printk("Error in %s at %d: kprobe slot allocation error (arm)\n", __FILE__, __LINE__);
548                 return -ENOMEM;
549         }
550
551         ret = arch_copy_trampoline_arm_uprobe(p, task, 1);
552         if (ret) {
553                 free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
554                 return -EFAULT;
555         }
556
557         p->ainsn.insn_thumb = get_insn_slot(task, atomic);
558         if (!p->ainsn.insn_thumb) {
559                 printk("Error in %s at %d: kprobe slot allocation error (thumb)\n", __FILE__, __LINE__);
560                 return -ENOMEM;
561         }
562
563         ret = arch_copy_trampoline_thumb_uprobe(p, task, 1);
564         if (ret) {
565                 free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
566                 free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_thumb);
567                 return -EFAULT;
568         }
569
570         if ((p->safe_arm == -1) && (p->safe_thumb == -1)) {
571                 printk("Error in %s at %d: failed arch_copy_trampoline_*_uprobe() (both) [tgid=%u, addr=%lx, data=%lx]\n",
572                        __FILE__, __LINE__, task->tgid, (unsigned long)p->addr, (unsigned long)p->opcode);
573                 if (!write_proc_vm_atomic(task, (unsigned long)p->addr, &p->opcode, sizeof(p->opcode))) {
574                         panic("Failed to write memory %p!\n", p->addr);
575                 }
576
577                 free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
578                 free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_thumb);
579
580                 return -EFAULT;
581         }
582
583         return ret;
584 }