[REFACTOR] remove 'OVERHEAD_DEBUG'
[kernel/swap-modules.git] / kprobe / arch / asm-arm / dbi_kprobes.c
1 /*
2  *  Dynamic Binary Instrumentation Module based on KProbes
3  *  modules/kprobe/arch/asm-arm/dbi_kprobes.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Copyright (C) Samsung Electronics, 2006-2010
20  *
21  * 2006-2007    Ekaterina Gorelkina <e.gorelkina@samsung.com>: initial implementation for ARM/MIPS
22  * 2008-2009    Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
23  *              Probes initial implementation; Support x86.
24  * 2010         Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
25  * 2010-2011    Alexander Shirshikov <a.shirshikov@samsung.com>: initial implementation for Thumb
26  * 2012         Stanislav Andreev <s.andreev@samsung.com>: added time debug profiling support; BUG() message fix
27  * 2012         Stanislav Andreev <s.andreev@samsung.com>: redesign of kprobe functionality -
28  *              kprobe_handler() now called via undefined instruction hooks
29  * 2012         Stanislav Andreev <s.andreev@samsung.com>: hash tables search implemented for uprobes
30  */
31
32 #include <linux/module.h>
33 #include <linux/mm.h>
34
35 #include "dbi_kprobes.h"
36 #include "trampoline_arm.h"
37 #include "../dbi_kprobes.h"
38 #include "../../dbi_kprobes.h"
39
40 #include "../../dbi_kdebug.h"
41 #include "../../dbi_insn_slots.h"
42 #include "../../dbi_kprobes_deps.h"
43 #include <ksyms.h>
44
45 #include <asm/cacheflush.h>
46 #include <asm/traps.h>
47 #include <asm/ptrace.h>
48 #include <linux/list.h>
49 #include <linux/hash.h>
50
51 #define SUPRESS_BUG_MESSAGES
52
53 extern struct kprobe * per_cpu__current_kprobe;
54 extern struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
55
56 static void (*__swap_register_undef_hook)(struct undef_hook *hook);
57 static void (*__swap_unregister_undef_hook)(struct undef_hook *hook);
58
59 static struct kprobe trampoline_p =
60 {
61         .addr = (kprobe_opcode_t *) & kretprobe_trampoline,
62         .pre_handler = trampoline_probe_handler
63 };
64
65 int prep_pc_dep_insn_execbuf(kprobe_opcode_t *insns, kprobe_opcode_t insn, int uregs)
66 {
67         int i;
68
69         if (uregs & 0x10)
70         {
71                 int reg_mask = 0x1;
72                 //search in reg list
73                 for (i = 0; i < 13; i++, reg_mask <<= 1)
74                 {
75                         if (!(insn & reg_mask))
76                                 break;
77                 }
78         }
79         else
80         {
81                 for (i = 0; i < 13; i++)
82                 {
83                         if ((uregs & 0x1) && (ARM_INSN_REG_RN (insn) == i))
84                                 continue;
85                         if ((uregs & 0x2) && (ARM_INSN_REG_RD (insn) == i))
86                                 continue;
87                         if ((uregs & 0x4) && (ARM_INSN_REG_RS (insn) == i))
88                                 continue;
89                         if ((uregs & 0x8) && (ARM_INSN_REG_RM (insn) == i))
90                                 continue;
91                         break;
92                 }
93         }
94         if (i == 13)
95         {
96                 DBPRINTF ("there are no free register %x in insn %lx!", uregs, insn);
97                 return -EINVAL;
98         }
99         DBPRINTF ("prep_pc_dep_insn_execbuf: using R%d, changing regs %x", i, uregs);
100
101         // set register to save
102         ARM_INSN_REG_SET_RD (insns[0], i);
103         // set register to load address to
104         ARM_INSN_REG_SET_RD (insns[1], i);
105         // set instruction to execute and patch it
106         if (uregs & 0x10)
107         {
108                 ARM_INSN_REG_CLEAR_MR (insn, 15);
109                 ARM_INSN_REG_SET_MR (insn, i);
110         }
111         else
112         {
113                 if ((uregs & 0x1) && (ARM_INSN_REG_RN (insn) == 15))
114                         ARM_INSN_REG_SET_RN (insn, i);
115                 if ((uregs & 0x2) && (ARM_INSN_REG_RD (insn) == 15))
116                         ARM_INSN_REG_SET_RD (insn, i);
117                 if ((uregs & 0x4) && (ARM_INSN_REG_RS (insn) == 15))
118                         ARM_INSN_REG_SET_RS (insn, i);
119                 if ((uregs & 0x8) && (ARM_INSN_REG_RM (insn) == 15))
120                         ARM_INSN_REG_SET_RM (insn, i);
121         }
122         insns[UPROBES_TRAMP_INSN_IDX] = insn;
123         // set register to restore
124         ARM_INSN_REG_SET_RD (insns[3], i);
125         return 0;
126 }
127 EXPORT_SYMBOL_GPL(prep_pc_dep_insn_execbuf);
128
129 int arch_check_insn_arm(struct arch_specific_insn *ainsn)
130 {
131         int ret = 0;
132
133         // check instructions that can change PC by nature
134         if (
135 //              ARM_INSN_MATCH (UNDEF, ainsn->insn_arm[0]) ||
136                 ARM_INSN_MATCH (AUNDEF, ainsn->insn_arm[0]) ||
137                 ARM_INSN_MATCH (SWI, ainsn->insn_arm[0]) ||
138                 ARM_INSN_MATCH (BREAK, ainsn->insn_arm[0]) ||
139                 ARM_INSN_MATCH (BL, ainsn->insn_arm[0]) ||
140                 ARM_INSN_MATCH (BLX1, ainsn->insn_arm[0]) ||
141                 ARM_INSN_MATCH (BLX2, ainsn->insn_arm[0]) ||
142                 ARM_INSN_MATCH (BX, ainsn->insn_arm[0]) ||
143                 ARM_INSN_MATCH (BXJ, ainsn->insn_arm[0]))
144         {
145                 DBPRINTF ("Bad insn arch_check_insn_arm: %lx\n", ainsn->insn_arm[0]);
146                 ret = -EFAULT;
147         }
148 #ifndef CONFIG_CPU_V7
149         // check instructions that can write result to PC
150         else if ((ARM_INSN_MATCH (DPIS, ainsn->insn_arm[0]) ||
151                                 ARM_INSN_MATCH (DPRS, ainsn->insn_arm[0]) ||
152                                 ARM_INSN_MATCH (DPI, ainsn->insn_arm[0]) ||
153                                 ARM_INSN_MATCH (LIO, ainsn->insn_arm[0]) ||
154                                 ARM_INSN_MATCH (LRO, ainsn->insn_arm[0])) &&
155                         (ARM_INSN_REG_RD (ainsn->insn_arm[0]) == 15))
156         {
157                 DBPRINTF ("Bad arch_check_insn_arm: %lx\n", ainsn->insn_arm[0]);
158                 ret = -EFAULT;
159         }
160 #endif // CONFIG_CPU_V7
161         // check special instruction loads store multiple registers
162         else if ((ARM_INSN_MATCH (LM, ainsn->insn_arm[0]) || ARM_INSN_MATCH (SM, ainsn->insn_arm[0])) &&
163                         // store pc or load to pc
164                         (ARM_INSN_REG_MR (ainsn->insn_arm[0], 15) ||
165                          // store/load with pc update
166                          ((ARM_INSN_REG_RN (ainsn->insn_arm[0]) == 15) && (ainsn->insn_arm[0] & 0x200000))))
167         {
168                 DBPRINTF ("Bad insn arch_check_insn_arm: %lx\n", ainsn->insn_arm[0]);
169                 ret = -EFAULT;
170         }
171         return ret;
172 }
173 EXPORT_SYMBOL_GPL(arch_check_insn_arm);
174
175 int arch_prepare_kprobe (struct kprobe *p)
176 {
177         kprobe_opcode_t insns[KPROBES_TRAMP_LEN];
178         int uregs, pc_dep, ret = 0;
179     kprobe_opcode_t insn[MAX_INSN_SIZE];
180     struct arch_specific_insn ainsn;
181
182     /* insn: must be on special executable page on i386. */
183     p->ainsn.insn = get_insn_slot(NULL, &kprobe_insn_pages, 0);
184     if (!p->ainsn.insn)
185         return -ENOMEM;
186
187     memcpy (insn, p->addr, MAX_INSN_SIZE * sizeof (kprobe_opcode_t));
188     ainsn.insn_arm = ainsn.insn = insn;
189     ret = arch_check_insn_arm (&ainsn);
190     if (!ret)
191     {
192         p->opcode = *p->addr;
193         uregs = pc_dep = 0;
194
195         // Rn, Rm ,Rd
196         if(ARM_INSN_MATCH (DPIS, insn[0]) || ARM_INSN_MATCH (LRO, insn[0]) ||
197            ARM_INSN_MATCH (SRO, insn[0]))
198         {
199             uregs = 0xb;
200             if( (ARM_INSN_REG_RN (insn[0]) == 15) || (ARM_INSN_REG_RM (insn[0]) == 15) ||
201                 (ARM_INSN_MATCH (SRO, insn[0]) && (ARM_INSN_REG_RD (insn[0]) == 15)) )
202             {
203                 DBPRINTF ("Unboostable insn %lx, DPIS/LRO/SRO\n", insn[0]);
204                 pc_dep = 1;
205             }
206         }
207         // Rn ,Rd
208         else if(ARM_INSN_MATCH (DPI, insn[0]) || ARM_INSN_MATCH (LIO, insn[0]) ||
209                 ARM_INSN_MATCH (SIO, insn[0]))
210         {
211             uregs = 0x3;
212             if ((ARM_INSN_REG_RN (insn[0]) == 15) || (ARM_INSN_MATCH (SIO, insn[0]) &&
213                         (ARM_INSN_REG_RD (insn[0]) == 15)))
214             {
215                 pc_dep = 1;
216                 DBPRINTF ("Unboostable insn %lx/%p, DPI/LIO/SIO\n", insn[0], p);
217             }
218         }
219         // Rn, Rm, Rs
220         else if(ARM_INSN_MATCH (DPRS, insn[0]))
221         {
222             uregs = 0xd;
223             if ((ARM_INSN_REG_RN (insn[0]) == 15) || (ARM_INSN_REG_RM (insn[0]) == 15) ||
224                 (ARM_INSN_REG_RS (insn[0]) == 15))
225             {
226                 pc_dep = 1;
227                 DBPRINTF ("Unboostable insn %lx, DPRS\n", insn[0]);
228             }
229         }
230         // register list
231         else if(ARM_INSN_MATCH (SM, insn[0]))
232         {
233             uregs = 0x10;
234             if (ARM_INSN_REG_MR (insn[0], 15))
235             {
236                 DBPRINTF ("Unboostable insn %lx, SM\n", insn[0]);
237                 pc_dep = 1;
238             }
239         }
240         // check instructions that can write result to SP andu uses PC
241         if (pc_dep  && (ARM_INSN_REG_RD (ainsn.insn[0]) == 13))
242         {
243             free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
244             ret = -EFAULT;
245         }
246         else
247         {
248             if (uregs && pc_dep)
249             {
250                 memcpy (insns, pc_dep_insn_execbuf, sizeof (insns));
251                 if (prep_pc_dep_insn_execbuf (insns, insn[0], uregs) != 0)
252                 {
253                     DBPRINTF ("failed to prepare exec buffer for insn %lx!", insn[0]);
254                     free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
255                     return -EINVAL;
256                 }
257                 insns[6] = (kprobe_opcode_t) (p->addr + 2);
258             }
259             else
260             {
261                 memcpy (insns, gen_insn_execbuf, sizeof (insns));
262                 insns[KPROBES_TRAMP_INSN_IDX] = insn[0];
263             }
264             insns[7] = (kprobe_opcode_t) (p->addr + 1);
265             DBPRINTF ("arch_prepare_kprobe: insn %lx", insn[0]);
266             DBPRINTF ("arch_prepare_kprobe: to %p - %lx %lx %lx %lx %lx %lx %lx %lx %lx",
267                     p->ainsn.insn, insns[0], insns[1], insns[2], insns[3], insns[4],
268                     insns[5], insns[6], insns[7], insns[8]);
269             memcpy (p->ainsn.insn, insns, sizeof(insns));
270             flush_icache_range((long unsigned)p->ainsn.insn, (long unsigned)(p->ainsn.insn) + sizeof(insns));
271 #ifdef BOARD_tegra
272             flush_cache_all();
273 #endif
274         }
275     }
276     else
277     {
278         free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
279         printk("arch_prepare_kprobe: instruction 0x%lx not instrumentation, addr=0x%p\n", insn[0], p->addr);
280     }
281
282     return ret;
283 }
284
285 void prepare_singlestep (struct kprobe *p, struct pt_regs *regs)
286 {
287         if (p->ss_addr) {
288                 regs->ARM_pc = (unsigned long)p->ss_addr;
289                 p->ss_addr = NULL;
290         } else {
291                 regs->ARM_pc = (unsigned long)p->ainsn.insn;
292         }
293 }
294 EXPORT_SYMBOL_GPL(prepare_singlestep);
295
296 void save_previous_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p_run)
297 {
298         kcb->prev_kprobe.kp = kprobe_running();
299         kcb->prev_kprobe.status = kcb->kprobe_status;
300 }
301
302 void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
303 {
304         __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
305         kcb->kprobe_status = kcb->prev_kprobe.status;
306 }
307
308 void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
309 {
310         __get_cpu_var(current_kprobe) = p;
311         DBPRINTF ("set_current_kprobe: p=%p addr=%p\n", p, p->addr);
312 }
313
314 static int kprobe_handler(struct pt_regs *regs)
315 {
316         struct kprobe *p, *cur;
317         struct kprobe_ctlblk *kcb;
318
319         kcb = get_kprobe_ctlblk();
320         cur = kprobe_running();
321         p = get_kprobe((void *)regs->ARM_pc);
322
323         if (p) {
324                 if (cur) {
325                         /* Kprobe is pending, so we're recursing. */
326                         switch (kcb->kprobe_status) {
327                         case KPROBE_HIT_ACTIVE:
328                         case KPROBE_HIT_SSDONE:
329                                 /* A pre- or post-handler probe got us here. */
330                                 kprobes_inc_nmissed_count(p);
331                                 save_previous_kprobe(kcb, NULL);
332                                 set_current_kprobe(p, 0, 0);
333                                 kcb->kprobe_status = KPROBE_REENTER;
334                                 prepare_singlestep(p, regs);
335                                 restore_previous_kprobe(kcb);
336                                 break;
337                         default:
338                                 /* impossible cases */
339                                 BUG();
340                         }
341                 } else {
342                         set_current_kprobe(p, 0, 0);
343                         kcb->kprobe_status = KPROBE_HIT_ACTIVE;
344
345                         if (!p->pre_handler || !p->pre_handler(p, regs)) {
346                                 kcb->kprobe_status = KPROBE_HIT_SS;
347                                 prepare_singlestep(p, regs);
348                                 reset_current_kprobe();
349                         }
350                 }
351         } else {
352                 goto no_kprobe;
353         }
354
355         return 0;
356
357 no_kprobe:
358         printk("no_kprobe\n");
359         return 1;
360 }
361
362 int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
363 {
364         int ret;
365         unsigned long flags;
366
367 #ifdef SUPRESS_BUG_MESSAGES
368         int swap_oops_in_progress;
369         /* oops_in_progress used to avoid BUG() messages
370          * that slow down kprobe_handler() execution */
371         swap_oops_in_progress = oops_in_progress;
372         oops_in_progress = 1;
373 #endif
374
375         local_irq_save(flags);
376         preempt_disable();
377         ret = kprobe_handler(regs);
378         preempt_enable_no_resched();
379         local_irq_restore(flags);
380
381 #ifdef SUPRESS_BUG_MESSAGES
382         oops_in_progress = swap_oops_in_progress;
383 #endif
384
385         return ret;
386 }
387
388 int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
389 {
390         struct jprobe *jp = container_of(p, struct jprobe, kp);
391         kprobe_pre_entry_handler_t pre_entry = (kprobe_pre_entry_handler_t)jp->pre_entry;
392         entry_point_t entry = (entry_point_t)jp->entry;
393         pre_entry = (kprobe_pre_entry_handler_t)jp->pre_entry;
394
395         if (((unsigned long)p->addr == sched_addr) && sched_rp) {
396                 struct thread_info *tinfo = (struct thread_info *)regs->ARM_r2;
397                 patch_suspended_task(sched_rp, tinfo->task);
398         }
399
400         if (pre_entry) {
401                 p->ss_addr = (void *)pre_entry (jp->priv_arg, regs);
402         }
403
404         if (entry) {
405                 entry(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
406                       regs->ARM_r3, regs->ARM_r4, regs->ARM_r5);
407         } else {
408                 dbi_jprobe_return();
409         }
410
411         return 0;
412 }
413
414 void dbi_jprobe_return (void)
415 {
416 }
417
418 int longjmp_break_handler (struct kprobe *p, struct pt_regs *regs)
419 {
420         return 0;
421 }
422 EXPORT_SYMBOL_GPL(longjmp_break_handler);
423
424 void arch_arm_kprobe (struct kprobe *p)
425 {
426         *p->addr = BREAKPOINT_INSTRUCTION;
427         flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t));
428 }
429
430 void arch_disarm_kprobe (struct kprobe *p)
431 {
432         *p->addr = p->opcode;
433         flush_icache_range ((unsigned long) p->addr, (unsigned long) p->addr + sizeof (kprobe_opcode_t));
434 }
435
436
437 int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs)
438 {
439         struct kretprobe_instance *ri = NULL;
440         struct hlist_head *head;
441         struct hlist_node *node, *tmp;
442         unsigned long flags, orig_ret_address = 0;
443         unsigned long trampoline_address = (unsigned long) &kretprobe_trampoline;
444
445         struct kretprobe *crp = NULL;
446         struct kprobe_ctlblk *kcb = get_kprobe_ctlblk ();
447
448         DBPRINTF ("start");
449
450         spin_lock_irqsave (&kretprobe_lock, flags);
451
452         /*
453          * We are using different hash keys (current and mm) for finding kernel
454          * space and user space probes.  Kernel space probes can change mm field in
455          * task_struct.  User space probes can be shared between threads of one
456          * process so they have different current but same mm.
457          */
458         head = kretprobe_inst_table_head(current);
459
460         /*
461          * It is possible to have multiple instances associated with a given
462          * task either because an multiple functions in the call path
463          * have a return probe installed on them, and/or more then one
464          * return probe was registered for a target function.
465          *
466          * We can handle this because:
467          *     - instances are always inserted at the head of the list
468          *     - when multiple return probes are registered for the same
469          *       function, the first instance's ret_addr will point to the
470          *       real return address, and all the rest will point to
471          *       kretprobe_trampoline
472          */
473         hlist_for_each_entry_safe (ri, node, tmp, head, hlist)
474         {
475                 if (ri->task != current)
476                         /* another task is sharing our hash bucket */
477                         continue;
478                 if (ri->rp && ri->rp->handler){
479                         ri->rp->handler (ri, regs, ri->rp->priv_arg);
480                 }
481
482                 orig_ret_address = (unsigned long) ri->ret_addr;
483                 recycle_rp_inst (ri);
484                 if (orig_ret_address != trampoline_address)
485                         /*
486                          * This is the real return address. Any other
487                          * instances associated with this task are for
488                          * other calls deeper on the call stack
489                          */
490                         break;
491         }
492         kretprobe_assert (ri, orig_ret_address, trampoline_address);
493
494         regs->uregs[14] = orig_ret_address;
495         DBPRINTF ("regs->uregs[14] = 0x%lx\n", regs->uregs[14]);
496         DBPRINTF ("regs->uregs[15] = 0x%lx\n", regs->uregs[15]);
497
498         if (trampoline_address != (unsigned long) &kretprobe_trampoline)
499         {
500                 regs->uregs[15] = orig_ret_address;
501         }else{
502                 if (!thumb_mode( regs )) regs->uregs[15] += 4;
503                 else regs->uregs[15] += 2;
504         }
505
506         DBPRINTF ("regs->uregs[15] = 0x%lx\n", regs->uregs[15]);
507
508         if(p){ // ARM, MIPS, X86 user space
509                 if (thumb_mode( regs ) && !(regs->uregs[14] & 0x01))
510                 {
511                         regs->ARM_cpsr &= 0xFFFFFFDF;
512                 }else{
513                         if (user_mode( regs ) && (regs->uregs[14] & 0x01))
514                         {
515                                 regs->ARM_cpsr |= 0x20;
516                         }
517                 }
518
519                 if (kcb->kprobe_status == KPROBE_REENTER) {
520                         restore_previous_kprobe(kcb);
521                 } else {
522                         reset_current_kprobe();
523                 }
524         }
525
526         spin_unlock_irqrestore (&kretprobe_lock, flags);
527
528         /*
529          * By returning a non-zero value, we are telling
530          * kprobe_handler() that we don't want the post_handler
531          * to run (and have re-enabled preemption)
532          */
533
534         return 1;
535 }
536 EXPORT_SYMBOL_GPL(trampoline_probe_handler);
537
538 void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
539 {
540         struct kretprobe_instance *ri;
541
542         DBPRINTF ("start\n");
543         //TODO: test - remove retprobe after func entry but before its exit
544         if ((ri = get_free_rp_inst (rp)) != NULL)
545         {
546                 ri->rp = rp;
547                 ri->task = current;
548                 ri->ret_addr = (kprobe_opcode_t *) regs->uregs[14];
549                 ri->sp = (kprobe_opcode_t *)regs->ARM_sp; //uregs[13];
550
551                 /* Set flag of current mode */
552                 ri->sp = (kprobe_opcode_t *)((long)ri->sp | !!thumb_mode(regs));
553
554                 /* Replace the return addr with trampoline addr */
555                 regs->uregs[14] = (unsigned long) &kretprobe_trampoline;
556
557 //              DBPRINTF ("ret addr set to %p->%lx\n", ri->ret_addr, regs->uregs[14]);
558                 add_rp_inst (ri);
559         }
560         else {
561                 DBPRINTF ("WARNING: missed retprobe %p\n", rp->kp.addr);
562                 rp->nmissed++;
563         }
564 }
565
566 void swap_register_undef_hook(struct undef_hook *hook)
567 {
568         __swap_register_undef_hook(hook);
569 }
570 EXPORT_SYMBOL_GPL(swap_register_undef_hook);
571
572 void swap_unregister_undef_hook(struct undef_hook *hook)
573 {
574         __swap_unregister_undef_hook(hook);
575 }
576 EXPORT_SYMBOL_GPL(swap_unregister_undef_hook);
577
578 // kernel probes hook
579 static struct undef_hook undef_ho_k = {
580     .instr_mask = 0xffffffff,
581     .instr_val  = BREAKPOINT_INSTRUCTION,
582     .cpsr_mask  = MODE_MASK,
583     .cpsr_val   = SVC_MODE,
584     .fn         = kprobe_trap_handler
585 };
586
587 int arch_init_kprobes(void)
588 {
589         int ret = 0;
590
591         // Register hooks (kprobe_handler)
592         __swap_register_undef_hook = swap_ksyms("register_undef_hook");
593         if (__swap_register_undef_hook == NULL) {
594                 printk("no register_undef_hook symbol found!\n");
595                 return -1;
596         }
597
598         // Unregister hooks (kprobe_handler)
599         __swap_unregister_undef_hook = swap_ksyms("unregister_undef_hook");
600         if (__swap_unregister_undef_hook == NULL) {
601                 printk("no unregister_undef_hook symbol found!\n");
602                 return -1;
603         }
604
605         swap_register_undef_hook(&undef_ho_k);
606         if ((ret = dbi_register_kprobe (&trampoline_p)) != 0) {
607                 //dbi_unregister_jprobe(&do_exit_p, 0);
608                 return ret;
609         }
610         return ret;
611 }
612
613 void arch_exit_kprobes(void)
614 {
615         swap_unregister_undef_hook(&undef_ho_k);
616 }
617
618 /* export symbol for trampoline_arm.h */
619 EXPORT_SYMBOL_GPL(gen_insn_execbuf);
620 EXPORT_SYMBOL_GPL(pc_dep_insn_execbuf);