aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/kprobes-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/kprobes-common.c')
-rw-r--r--arch/arm/kernel/kprobes-common.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c
index 86fdc4c4c2ce..43d663cafdd1 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/kernel/kprobes-common.c
@@ -166,6 +166,76 @@ void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs)
166 p->ainsn.insn_fn(); 166 p->ainsn.insn_fn();
167} 167}
168 168
169static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
170{
171 kprobe_opcode_t insn = p->opcode;
172 int rn = (insn >> 16) & 0xf;
173 int lbit = insn & (1 << 20);
174 int wbit = insn & (1 << 21);
175 int ubit = insn & (1 << 23);
176 int pbit = insn & (1 << 24);
177 long *addr = (long *)regs->uregs[rn];
178 int reg_bit_vector;
179 int reg_count;
180
181 reg_count = 0;
182 reg_bit_vector = insn & 0xffff;
183 while (reg_bit_vector) {
184 reg_bit_vector &= (reg_bit_vector - 1);
185 ++reg_count;
186 }
187
188 if (!ubit)
189 addr -= reg_count;
190 addr += (!pbit == !ubit);
191
192 reg_bit_vector = insn & 0xffff;
193 while (reg_bit_vector) {
194 int reg = __ffs(reg_bit_vector);
195 reg_bit_vector &= (reg_bit_vector - 1);
196 if (lbit)
197 regs->uregs[reg] = *addr++;
198 else
199 *addr++ = regs->uregs[reg];
200 }
201
202 if (wbit) {
203 if (!ubit)
204 addr -= reg_count;
205 addr -= (!pbit == !ubit);
206 regs->uregs[rn] = (long)addr;
207 }
208}
209
210static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
211{
212 regs->ARM_pc = (long)p->addr + str_pc_offset;
213 simulate_ldm1stm1(p, regs);
214 regs->ARM_pc = (long)p->addr + 4;
215}
216
217static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs)
218{
219 simulate_ldm1stm1(p, regs);
220 load_write_pc(regs->ARM_pc, regs);
221}
222
223enum kprobe_insn __kprobes
224kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
225{
226 kprobe_insn_handler_t *handler = 0;
227 unsigned reglist = insn & 0xffff;
228 int is_ldm = insn & 0x100000;
229
230 if (reglist & 0x8000)
231 handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
232 else
233 handler = simulate_ldm1stm1;
234 asi->insn_handler = handler;
235 return INSN_GOOD_NO_SLOT;
236}
237
238
169/* 239/*
170 * Prepare an instruction slot to receive an instruction for emulating. 240 * Prepare an instruction slot to receive an instruction for emulating.
171 * This is done by placing a subroutine return after the location where the 241 * This is done by placing a subroutine return after the location where the