[IMPROVE] remove links to build modules
[kernel/swap-modules.git] / kprobe / arch / x86 / swap-asm / swap_kprobes.h
1 /**
2  * @file kprobe/arch/asm-x86/swap_kprobes.h
3  * @author Alexey Gerenkov <a.gerenkov@samsung.com> User-Space Probes initial implementation;
4  * Support x86/ARM/MIPS for both user and kernel spaces.
5  * @author Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
6  *
7  * @section LICENSE
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * @section COPYRIGHT
24  *
25  * Copyright (C) IBM Corporation, 2002, 2004
26  * Copyright (C) Samsung Electronics, 2006-2010
27  *
28  * @section DESCRIPTION
29  *
30  * Arch-dependent kprobes interface for x86 arch.
31  */
32
33 #ifndef _SWAP_ASM_X86_KPROBES_H
34 #define _SWAP_ASM_X86_KPROBES_H
35
36
37 #include <linux/version.h>
38 #include <kprobe/swap_kprobes_deps.h>
39
40 /**
41  * @brief Opcode type.
42  */
43 typedef u8 kprobe_opcode_t;
44
45 #define BREAKPOINT_INSTRUCTION          0xcc
46 #define RELATIVEJUMP_INSTRUCTION        0xe9
47
48 #define BP_INSN_SIZE                    1
49 #define MAX_INSN_SIZE                   16
50 #define MAX_STACK_SIZE                  64
51
52 #define MIN_STACK_SIZE(ADDR)   (((MAX_STACK_SIZE) <                       \
53                         (((unsigned long)current_thread_info())  \
54                          + THREAD_SIZE - (ADDR)))                 \
55                 ? (MAX_STACK_SIZE)                        \
56                 : (((unsigned long)current_thread_info()) \
57                         + THREAD_SIZE - (ADDR)))
58
59 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
60
61 #define EREG(rg)                e##rg
62 #define XREG(rg)                x##rg
63 #define ORIG_EAX_REG            orig_eax
64
65 #else
66
67 #define EREG(rg)                rg
68 #define XREG(rg)                rg
69 #define ORIG_EAX_REG            orig_ax
70
71 #endif /*  LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) */
72
73 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
74 #define TF_MASK                         X86_EFLAGS_TF
75 #define IF_MASK                         X86_EFLAGS_IF
76 #endif
77 #define UPROBES_TRAMP_LEN               (MAX_INSN_SIZE+sizeof(kprobe_opcode_t))
78 #define UPROBES_TRAMP_INSN_IDX          0
79 #define UPROBES_TRAMP_RET_BREAK_IDX     MAX_INSN_SIZE
80 #define KPROBES_TRAMP_LEN               MAX_INSN_SIZE
81 #define KPROBES_TRAMP_INSN_IDX          0
82
83 static inline unsigned long arch_get_task_pc(struct task_struct *p)
84 {
85         /* FIXME: Not implemented yet */
86         return 0;
87 }
88
89 static inline void arch_set_task_pc(struct task_struct *p, unsigned long val)
90 {
91         /* FIXME: Not implemented yet */
92 }
93
94 static inline struct pt_regs *swap_get_syscall_uregs(unsigned long sp)
95 {
96         return NULL; //FIXME currently not implemented for x86
97 }
98
99 static inline unsigned long swap_get_stack_ptr(struct pt_regs *regs)
100 {
101         return regs->EREG(sp);
102 }
103
104 static inline unsigned long swap_get_instr_ptr(struct pt_regs *regs)
105 {
106         return regs->EREG(ip);
107 }
108
109 static inline void swap_set_instr_ptr(struct pt_regs *regs, unsigned long val)
110 {
111         regs->EREG(ip) = val;
112 }
113
114 static inline unsigned long swap_get_ret_addr(struct pt_regs *regs)
115 {
116         unsigned long addr = 0;
117         read_proc_vm_atomic(current, regs->EREG(sp), &addr, sizeof(addr));
118         return addr;
119 }
120
121 static inline void swap_set_ret_addr(struct pt_regs *regs, unsigned long val)
122 {
123         write_proc_vm_atomic(current, regs->EREG(sp), &val, sizeof(val));
124 }
125
126 static inline unsigned long swap_get_arg(struct pt_regs *regs, int num)
127 {
128         unsigned long arg = 0;
129         read_proc_vm_atomic(current, regs->EREG(sp) + (1 + num) * 4,
130                         &arg, sizeof(arg));
131         return arg;
132 }
133
134 static inline void swap_set_arg(struct pt_regs *regs, int num,
135                                 unsigned long val)
136 {
137         write_proc_vm_atomic(current, regs->EREG(sp) + (1 + num) * 4,
138                         &val, sizeof(val));
139 }
140
141 static inline int swap_fp_backtrace(struct task_struct *task,
142                                     unsigned long *buf, int max_cnt)
143 {
144         int i = 0;
145         struct pt_regs *regs;
146
147         struct {
148                 unsigned long next;
149                 unsigned long raddr;
150         } frame;
151
152
153         regs = task_pt_regs(task);
154         frame.next = regs->EREG(bp);
155         frame.raddr = swap_get_ret_addr(regs);
156
157         while (frame.next && i < max_cnt) {
158                 if (read_proc_vm_atomic(task, frame.next, &frame, sizeof(frame))
159                                 == sizeof(frame))
160                         buf[i++] = frame.raddr;
161                 else
162                         break;
163         }
164
165         return i;
166 }
167
168 /**
169  * @struct prev_kprobe
170  * @brief Stores previous kprobe.
171  * @var prev_kprobe::kp
172  * Pointer to kprobe struct.
173  * @var prev_kprobe::status
174  * Kprobe status.
175  */
176 struct prev_kprobe {
177         struct kprobe *kp;
178         unsigned long status;
179 };
180
181 /**
182  * @struct kprobe_ctlblk
183  * @brief Per-cpu kprobe control block.
184  * @var kprobe_ctlblk::kprobe_status
185  * Kprobe status.
186  * @var kprobe_ctlblk::prev_kprobe
187  * Previous kprobe.
188  */
189 struct kprobe_ctlblk {
190         unsigned long kprobe_status;
191         struct prev_kprobe prev_kprobe;
192         struct pt_regs jprobe_saved_regs;
193         unsigned long kprobe_old_eflags;
194         unsigned long kprobe_saved_eflags;
195         unsigned long *jprobe_saved_esp;
196         kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
197 };
198
199
200 /**
201  * @struct arch_specific_insn
202  * @brief Architecture specific copy of original instruction.
203  * @var arch_specific_insn::insn
204  * Copy of the original instruction.
205  * @var arch_specific_insn::boostable
206  * If this flag is not 0, this kprobe can be boost when its
207  * post_handler and break_handler is not set.
208  */
209 struct arch_specific_insn {
210         kprobe_opcode_t *insn;
211         int boostable;
212 };
213
214 /**
215  * @brief Entry point.
216  */
217 typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
218
219 int arch_init_module_deps(void);
220
221 struct slot_manager;
222 struct kretprobe_instance;
223
224 int swap_arch_prepare_kprobe(struct kprobe *p, struct slot_manager *sm);
225 void swap_arch_arm_kprobe(struct kprobe *p);
226 void swap_arch_disarm_kprobe(struct kprobe *p);
227 void swap_arch_prepare_kretprobe(struct kretprobe_instance *ri,
228                                  struct pt_regs *regs);
229 void swap_kretprobe_trampoline(void);
230
231 void restore_previous_kprobe(struct kprobe_ctlblk *kcb);
232 int swap_can_boost(kprobe_opcode_t *opcodes);
233 static inline int arch_check_insn(struct arch_specific_insn *ainsn)
234 {
235         return 0;
236 }
237
238 static inline unsigned long swap_get_karg(struct pt_regs *regs, unsigned long n)
239 {
240         switch (n) {
241         case 0:
242                 return regs->ax;
243         case 1:
244                 return regs->dx;
245         case 2:
246                 return regs->cx;
247         }
248
249         /*
250          * 2 = 3 - 1
251          * 3 - arguments from registers
252          * 1 - return address saved on top of the stack
253          */
254         return *((unsigned long *)kernel_stack_pointer(regs) + n - 2);
255 }
256
257 static inline unsigned long swap_get_sarg(struct pt_regs *regs, unsigned long n)
258 {
259         /* 1 - return address saved on top of the stack */
260         return *((unsigned long *)kernel_stack_pointer(regs) + n + 1);
261 }
262
263 /* jumper */
264 typedef unsigned long (*jumper_cb_t)(void *);
265
266 int set_kjump_cb(struct pt_regs *regs, jumper_cb_t cb,
267                  void *data, size_t size);
268
269 unsigned long get_jump_addr(void);
270 int set_jump_cb(unsigned long ret_addr, struct pt_regs *regs,
271                 jumper_cb_t cb, void *data, size_t size);
272
273 int swap_arch_init_kprobes(void);
274 void swap_arch_exit_kprobes(void);
275
276 #endif /* _SWAP_ASM_X86_KPROBES_H */