Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.14.15.
  1/*
  2 * arch/arm/kernel/kprobes-decode.c
  3 *
  4 * Copyright (C) 2006, 2007 Motorola Inc.
  5 *
  6 * This program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License version 2 as
  8 * published by the Free Software Foundation.
  9 *
 10 * This program is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13 * General Public License for more details.
 14 */
 15
 16/*
 17 * We do not have hardware single-stepping on ARM, This
 18 * effort is further complicated by the ARM not having a
 19 * "next PC" register.  Instructions that change the PC
 20 * can't be safely single-stepped in a MP environment, so
 21 * we have a lot of work to do:
 22 *
 23 * In the prepare phase:
 24 *   *) If it is an instruction that does anything
 25 *      with the CPU mode, we reject it for a kprobe.
 26 *      (This is out of laziness rather than need.  The
 27 *      instructions could be simulated.)
 28 *
 29 *   *) Otherwise, decode the instruction rewriting its
 30 *      registers to take fixed, ordered registers and
 31 *      setting a handler for it to run the instruction.
 32 *
 33 * In the execution phase by an instruction's handler:
 34 *
 35 *   *) If the PC is written to by the instruction, the
 36 *      instruction must be fully simulated in software.
 37 *
 38 *   *) Otherwise, a modified form of the instruction is
 39 *      directly executed.  Its handler calls the
 40 *      instruction in insn[0].  In insn[1] is a
 41 *      "mov pc, lr" to return.
 42 *
 43 *      Before calling, load up the reordered registers
 44 *      from the original instruction's registers.  If one
 45 *      of the original input registers is the PC, compute
 46 *      and adjust the appropriate input register.
 47 *
 48 *	After call completes, copy the output registers to
 49 *      the original instruction's original registers.
 50 *
 51 * We don't use a real breakpoint instruction since that
 52 * would have us in the kernel go from SVC mode to SVC
 53 * mode losing the link register.  Instead we use an
 54 * undefined instruction.  To simplify processing, the
 55 * undefined instruction used for kprobes must be reserved
 56 * exclusively for kprobes use.
 57 *
 58 * TODO: ifdef out some instruction decoding based on architecture.
 59 */
 60
 61#include <linux/kernel.h>
 62#include <linux/kprobes.h>
 63#include <linux/ptrace.h>
 64
 65#include "kprobes.h"
 66#include "probes-arm.h"
 67
 68#if  __LINUX_ARM_ARCH__ >= 6
 69#define BLX(reg)	"blx	"reg"		\n\t"
 70#else
 71#define BLX(reg)	"mov	lr, pc		\n\t"	\
 72			"mov	pc, "reg"	\n\t"
 73#endif
 74
 75static void __kprobes
 76emulate_ldrdstrd(probes_opcode_t insn,
 77	struct arch_probes_insn *asi, struct pt_regs *regs)
 78{
 79	unsigned long pc = regs->ARM_pc + 4;
 80	int rt = (insn >> 12) & 0xf;
 81	int rn = (insn >> 16) & 0xf;
 82	int rm = insn & 0xf;
 83
 84	register unsigned long rtv asm("r0") = regs->uregs[rt];
 85	register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
 86	register unsigned long rnv asm("r2") = (rn == 15) ? pc
 87							  : regs->uregs[rn];
 88	register unsigned long rmv asm("r3") = regs->uregs[rm];
 89
 90	__asm__ __volatile__ (
 91		BLX("%[fn]")
 92		: "=r" (rtv), "=r" (rt2v), "=r" (rnv)
 93		: "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
 94		  [fn] "r" (asi->insn_fn)
 95		: "lr", "memory", "cc"
 96	);
 97
 98	regs->uregs[rt] = rtv;
 99	regs->uregs[rt+1] = rt2v;
100	if (is_writeback(insn))
101		regs->uregs[rn] = rnv;
102}
103
104static void __kprobes
105emulate_ldr(probes_opcode_t insn,
106	struct arch_probes_insn *asi, struct pt_regs *regs)
107{
108	unsigned long pc = regs->ARM_pc + 4;
109	int rt = (insn >> 12) & 0xf;
110	int rn = (insn >> 16) & 0xf;
111	int rm = insn & 0xf;
112
113	register unsigned long rtv asm("r0");
114	register unsigned long rnv asm("r2") = (rn == 15) ? pc
115							  : regs->uregs[rn];
116	register unsigned long rmv asm("r3") = regs->uregs[rm];
117
118	__asm__ __volatile__ (
119		BLX("%[fn]")
120		: "=r" (rtv), "=r" (rnv)
121		: "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
122		: "lr", "memory", "cc"
123	);
124
125	if (rt == 15)
126		load_write_pc(rtv, regs);
127	else
128		regs->uregs[rt] = rtv;
129
130	if (is_writeback(insn))
131		regs->uregs[rn] = rnv;
132}
133
134static void __kprobes
135emulate_str(probes_opcode_t insn,
136	struct arch_probes_insn *asi, struct pt_regs *regs)
137{
138	unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
139	unsigned long rnpc = regs->ARM_pc + 4;
140	int rt = (insn >> 12) & 0xf;
141	int rn = (insn >> 16) & 0xf;
142	int rm = insn & 0xf;
143
144	register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
145							  : regs->uregs[rt];
146	register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
147							  : regs->uregs[rn];
148	register unsigned long rmv asm("r3") = regs->uregs[rm];
149
150	__asm__ __volatile__ (
151		BLX("%[fn]")
152		: "=r" (rnv)
153		: "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
154		: "lr", "memory", "cc"
155	);
156
157	if (is_writeback(insn))
158		regs->uregs[rn] = rnv;
159}
160
161static void __kprobes
162emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
163	struct arch_probes_insn *asi, struct pt_regs *regs)
164{
165	unsigned long pc = regs->ARM_pc + 4;
166	int rd = (insn >> 12) & 0xf;
167	int rn = (insn >> 16) & 0xf;
168	int rm = insn & 0xf;
169	int rs = (insn >> 8) & 0xf;
170
171	register unsigned long rdv asm("r0") = regs->uregs[rd];
172	register unsigned long rnv asm("r2") = (rn == 15) ? pc
173							  : regs->uregs[rn];
174	register unsigned long rmv asm("r3") = (rm == 15) ? pc
175							  : regs->uregs[rm];
176	register unsigned long rsv asm("r1") = regs->uregs[rs];
177	unsigned long cpsr = regs->ARM_cpsr;
178
179	__asm__ __volatile__ (
180		"msr	cpsr_fs, %[cpsr]	\n\t"
181		BLX("%[fn]")
182		"mrs	%[cpsr], cpsr		\n\t"
183		: "=r" (rdv), [cpsr] "=r" (cpsr)
184		: "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
185		  "1" (cpsr), [fn] "r" (asi->insn_fn)
186		: "lr", "memory", "cc"
187	);
188
189	if (rd == 15)
190		alu_write_pc(rdv, regs);
191	else
192		regs->uregs[rd] = rdv;
193	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
194}
195
196static void __kprobes
197emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
198	struct arch_probes_insn *asi, struct pt_regs *regs)
199{
200	int rd = (insn >> 12) & 0xf;
201	int rn = (insn >> 16) & 0xf;
202	int rm = insn & 0xf;
203
204	register unsigned long rdv asm("r0") = regs->uregs[rd];
205	register unsigned long rnv asm("r2") = regs->uregs[rn];
206	register unsigned long rmv asm("r3") = regs->uregs[rm];
207	unsigned long cpsr = regs->ARM_cpsr;
208
209	__asm__ __volatile__ (
210		"msr	cpsr_fs, %[cpsr]	\n\t"
211		BLX("%[fn]")
212		"mrs	%[cpsr], cpsr		\n\t"
213		: "=r" (rdv), [cpsr] "=r" (cpsr)
214		: "0" (rdv), "r" (rnv), "r" (rmv),
215		  "1" (cpsr), [fn] "r" (asi->insn_fn)
216		: "lr", "memory", "cc"
217	);
218
219	regs->uregs[rd] = rdv;
220	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
221}
222
223static void __kprobes
224emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
225	struct arch_probes_insn *asi,
226	struct pt_regs *regs)
227{
228	int rd = (insn >> 16) & 0xf;
229	int rn = (insn >> 12) & 0xf;
230	int rm = insn & 0xf;
231	int rs = (insn >> 8) & 0xf;
232
233	register unsigned long rdv asm("r2") = regs->uregs[rd];
234	register unsigned long rnv asm("r0") = regs->uregs[rn];
235	register unsigned long rmv asm("r3") = regs->uregs[rm];
236	register unsigned long rsv asm("r1") = regs->uregs[rs];
237	unsigned long cpsr = regs->ARM_cpsr;
238
239	__asm__ __volatile__ (
240		"msr	cpsr_fs, %[cpsr]	\n\t"
241		BLX("%[fn]")
242		"mrs	%[cpsr], cpsr		\n\t"
243		: "=r" (rdv), [cpsr] "=r" (cpsr)
244		: "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
245		  "1" (cpsr), [fn] "r" (asi->insn_fn)
246		: "lr", "memory", "cc"
247	);
248
249	regs->uregs[rd] = rdv;
250	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
251}
252
253static void __kprobes
254emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
255	struct arch_probes_insn *asi, struct pt_regs *regs)
256{
257	int rd = (insn >> 12) & 0xf;
258	int rm = insn & 0xf;
259
260	register unsigned long rdv asm("r0") = regs->uregs[rd];
261	register unsigned long rmv asm("r3") = regs->uregs[rm];
262
263	__asm__ __volatile__ (
264		BLX("%[fn]")
265		: "=r" (rdv)
266		: "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
267		: "lr", "memory", "cc"
268	);
269
270	regs->uregs[rd] = rdv;
271}
272
273static void __kprobes
274emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
275	struct arch_probes_insn *asi,
276	struct pt_regs *regs)
277{
278	int rdlo = (insn >> 12) & 0xf;
279	int rdhi = (insn >> 16) & 0xf;
280	int rn = insn & 0xf;
281	int rm = (insn >> 8) & 0xf;
282
283	register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
284	register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
285	register unsigned long rnv asm("r3") = regs->uregs[rn];
286	register unsigned long rmv asm("r1") = regs->uregs[rm];
287	unsigned long cpsr = regs->ARM_cpsr;
288
289	__asm__ __volatile__ (
290		"msr	cpsr_fs, %[cpsr]	\n\t"
291		BLX("%[fn]")
292		"mrs	%[cpsr], cpsr		\n\t"
293		: "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
294		: "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
295		  "2" (cpsr), [fn] "r" (asi->insn_fn)
296		: "lr", "memory", "cc"
297	);
298
299	regs->uregs[rdlo] = rdlov;
300	regs->uregs[rdhi] = rdhiv;
301	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
302}
303
304const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
305	[PROBES_EMULATE_NONE] = {.handler = probes_emulate_none},
306	[PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
307	[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
308	[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
309	[PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
310	[PROBES_MRS] = {.handler = simulate_mrs},
311	[PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
312	[PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc},
313	[PROBES_SATURATING_ARITHMETIC] = {
314		.handler = emulate_rd12rn16rm0_rwflags_nopc},
315	[PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
316	[PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
317	[PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
318	[PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd},
319	[PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
320	[PROBES_LOAD] = {.handler = emulate_ldr},
321	[PROBES_STORE_EXTRA] = {.handler = emulate_str},
322	[PROBES_STORE] = {.handler = emulate_str},
323	[PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
324	[PROBES_DATA_PROCESSING_REG] = {
325		.handler = emulate_rd12rn16rm0rs8_rwflags},
326	[PROBES_DATA_PROCESSING_IMM] = {
327		.handler = emulate_rd12rn16rm0rs8_rwflags},
328	[PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
329	[PROBES_SEV] = {.handler = probes_emulate_none},
330	[PROBES_WFE] = {.handler = probes_simulate_nop},
331	[PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
332	[PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
333	[PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
334	[PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
335	[PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc},
336	[PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
337	[PROBES_MUL_ADD_LONG] = {
338		.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
339	[PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
340	[PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
341	[PROBES_BRANCH] = {.handler = simulate_bbl},
342	[PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
343};