diff options
author | Jan Willeke <willeke@de.ibm.com> | 2014-09-22 10:37:27 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-09-25 04:52:14 -0400 |
commit | 975fab17399a2b29985166181ad80e5f50fa42e9 (patch) | |
tree | 385dac7c1384947e5b3a520d40b60cb77d5797b1 /arch/s390/kernel/kprobes.c | |
parent | bbae71bf9c2fe90dc5642d4cddbbc1994861fd92 (diff) |
s390/uprobes: common library for kprobes and uprobes
This patch moves common functions from kprobes.c to probes.c.
Thus its possible for uprobes to use them without enabling kprobes.
Signed-off-by: Jan Willeke <willeke@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/kprobes.c')
-rw-r--r-- | arch/s390/kernel/kprobes.c | 154 |
1 files changed, 3 insertions, 151 deletions
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index c48a00c9f351..27ae5433fe4d 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
@@ -58,161 +58,13 @@ struct kprobe_insn_cache kprobe_dmainsn_slots = { | |||
58 | .insn_size = MAX_INSN_SIZE, | 58 | .insn_size = MAX_INSN_SIZE, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn) | ||
62 | { | ||
63 | if (!is_known_insn((unsigned char *)insn)) | ||
64 | return -EINVAL; | ||
65 | switch (insn[0] >> 8) { | ||
66 | case 0x0c: /* bassm */ | ||
67 | case 0x0b: /* bsm */ | ||
68 | case 0x83: /* diag */ | ||
69 | case 0x44: /* ex */ | ||
70 | case 0xac: /* stnsm */ | ||
71 | case 0xad: /* stosm */ | ||
72 | return -EINVAL; | ||
73 | case 0xc6: | ||
74 | switch (insn[0] & 0x0f) { | ||
75 | case 0x00: /* exrl */ | ||
76 | return -EINVAL; | ||
77 | } | ||
78 | } | ||
79 | switch (insn[0]) { | ||
80 | case 0x0101: /* pr */ | ||
81 | case 0xb25a: /* bsa */ | ||
82 | case 0xb240: /* bakr */ | ||
83 | case 0xb258: /* bsg */ | ||
84 | case 0xb218: /* pc */ | ||
85 | case 0xb228: /* pt */ | ||
86 | case 0xb98d: /* epsw */ | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int __kprobes get_fixup_type(kprobe_opcode_t *insn) | ||
93 | { | ||
94 | /* default fixup method */ | ||
95 | int fixup = FIXUP_PSW_NORMAL; | ||
96 | |||
97 | switch (insn[0] >> 8) { | ||
98 | case 0x05: /* balr */ | ||
99 | case 0x0d: /* basr */ | ||
100 | fixup = FIXUP_RETURN_REGISTER; | ||
101 | /* if r2 = 0, no branch will be taken */ | ||
102 | if ((insn[0] & 0x0f) == 0) | ||
103 | fixup |= FIXUP_BRANCH_NOT_TAKEN; | ||
104 | break; | ||
105 | case 0x06: /* bctr */ | ||
106 | case 0x07: /* bcr */ | ||
107 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
108 | break; | ||
109 | case 0x45: /* bal */ | ||
110 | case 0x4d: /* bas */ | ||
111 | fixup = FIXUP_RETURN_REGISTER; | ||
112 | break; | ||
113 | case 0x47: /* bc */ | ||
114 | case 0x46: /* bct */ | ||
115 | case 0x86: /* bxh */ | ||
116 | case 0x87: /* bxle */ | ||
117 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
118 | break; | ||
119 | case 0x82: /* lpsw */ | ||
120 | fixup = FIXUP_NOT_REQUIRED; | ||
121 | break; | ||
122 | case 0xb2: /* lpswe */ | ||
123 | if ((insn[0] & 0xff) == 0xb2) | ||
124 | fixup = FIXUP_NOT_REQUIRED; | ||
125 | break; | ||
126 | case 0xa7: /* bras */ | ||
127 | if ((insn[0] & 0x0f) == 0x05) | ||
128 | fixup |= FIXUP_RETURN_REGISTER; | ||
129 | break; | ||
130 | case 0xc0: | ||
131 | if ((insn[0] & 0x0f) == 0x05) /* brasl */ | ||
132 | fixup |= FIXUP_RETURN_REGISTER; | ||
133 | break; | ||
134 | case 0xeb: | ||
135 | switch (insn[2] & 0xff) { | ||
136 | case 0x44: /* bxhg */ | ||
137 | case 0x45: /* bxleg */ | ||
138 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
139 | break; | ||
140 | } | ||
141 | break; | ||
142 | case 0xe3: /* bctg */ | ||
143 | if ((insn[2] & 0xff) == 0x46) | ||
144 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
145 | break; | ||
146 | case 0xec: | ||
147 | switch (insn[2] & 0xff) { | ||
148 | case 0xe5: /* clgrb */ | ||
149 | case 0xe6: /* cgrb */ | ||
150 | case 0xf6: /* crb */ | ||
151 | case 0xf7: /* clrb */ | ||
152 | case 0xfc: /* cgib */ | ||
153 | case 0xfd: /* cglib */ | ||
154 | case 0xfe: /* cib */ | ||
155 | case 0xff: /* clib */ | ||
156 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
157 | break; | ||
158 | } | ||
159 | break; | ||
160 | } | ||
161 | return fixup; | ||
162 | } | ||
163 | |||
164 | static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn) | ||
165 | { | ||
166 | /* Check if we have a RIL-b or RIL-c format instruction which | ||
167 | * we need to modify in order to avoid instruction emulation. */ | ||
168 | switch (insn[0] >> 8) { | ||
169 | case 0xc0: | ||
170 | if ((insn[0] & 0x0f) == 0x00) /* larl */ | ||
171 | return true; | ||
172 | break; | ||
173 | case 0xc4: | ||
174 | switch (insn[0] & 0x0f) { | ||
175 | case 0x02: /* llhrl */ | ||
176 | case 0x04: /* lghrl */ | ||
177 | case 0x05: /* lhrl */ | ||
178 | case 0x06: /* llghrl */ | ||
179 | case 0x07: /* sthrl */ | ||
180 | case 0x08: /* lgrl */ | ||
181 | case 0x0b: /* stgrl */ | ||
182 | case 0x0c: /* lgfrl */ | ||
183 | case 0x0d: /* lrl */ | ||
184 | case 0x0e: /* llgfrl */ | ||
185 | case 0x0f: /* strl */ | ||
186 | return true; | ||
187 | } | ||
188 | break; | ||
189 | case 0xc6: | ||
190 | switch (insn[0] & 0x0f) { | ||
191 | case 0x02: /* pfdrl */ | ||
192 | case 0x04: /* cghrl */ | ||
193 | case 0x05: /* chrl */ | ||
194 | case 0x06: /* clghrl */ | ||
195 | case 0x07: /* clhrl */ | ||
196 | case 0x08: /* cgrl */ | ||
197 | case 0x0a: /* clgrl */ | ||
198 | case 0x0c: /* cgfrl */ | ||
199 | case 0x0d: /* crl */ | ||
200 | case 0x0e: /* clgfrl */ | ||
201 | case 0x0f: /* clrl */ | ||
202 | return true; | ||
203 | } | ||
204 | break; | ||
205 | } | ||
206 | return false; | ||
207 | } | ||
208 | |||
209 | static void __kprobes copy_instruction(struct kprobe *p) | 61 | static void __kprobes copy_instruction(struct kprobe *p) |
210 | { | 62 | { |
211 | s64 disp, new_disp; | 63 | s64 disp, new_disp; |
212 | u64 addr, new_addr; | 64 | u64 addr, new_addr; |
213 | 65 | ||
214 | memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8)); | 66 | memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8)); |
215 | if (!is_insn_relative_long(p->ainsn.insn)) | 67 | if (!probe_is_insn_relative_long(p->ainsn.insn)) |
216 | return; | 68 | return; |
217 | /* | 69 | /* |
218 | * For pc-relative instructions in RIL-b or RIL-c format patch the | 70 | * For pc-relative instructions in RIL-b or RIL-c format patch the |
@@ -276,7 +128,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
276 | if ((unsigned long) p->addr & 0x01) | 128 | if ((unsigned long) p->addr & 0x01) |
277 | return -EINVAL; | 129 | return -EINVAL; |
278 | /* Make sure the probe isn't going on a difficult instruction */ | 130 | /* Make sure the probe isn't going on a difficult instruction */ |
279 | if (is_prohibited_opcode(p->addr)) | 131 | if (probe_is_prohibited_opcode(p->addr)) |
280 | return -EINVAL; | 132 | return -EINVAL; |
281 | if (s390_get_insn_slot(p)) | 133 | if (s390_get_insn_slot(p)) |
282 | return -ENOMEM; | 134 | return -ENOMEM; |
@@ -605,7 +457,7 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | |||
605 | { | 457 | { |
606 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 458 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
607 | unsigned long ip = regs->psw.addr & PSW_ADDR_INSN; | 459 | unsigned long ip = regs->psw.addr & PSW_ADDR_INSN; |
608 | int fixup = get_fixup_type(p->ainsn.insn); | 460 | int fixup = probe_get_fixup_type(p->ainsn.insn); |
609 | 461 | ||
610 | if (fixup & FIXUP_PSW_NORMAL) | 462 | if (fixup & FIXUP_PSW_NORMAL) |
611 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; | 463 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; |