aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/kprobes.c
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2011-01-05 06:47:19 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2011-01-05 06:47:23 -0500
commitba640a591574036ab22cd32b47897340b0605342 (patch)
tree271783643d438caa0c41a5dbc68e712a7a4c5484 /arch/s390/kernel/kprobes.c
parent5a8b589f8a35b2c69d1819e3365825e4385a844c (diff)
[S390] kprobes: instruction fixup
Determine instruction fixup details in resume_execution, no need to do it beforehand. Remove fixup, ilen and reg from arch_specific_insn. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/kprobes.c')
-rw-r--r--arch/s390/kernel/kprobes.c130
1 files changed, 57 insertions, 73 deletions
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 1e75ec523577..fcbc25836879 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -37,29 +37,9 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
37 37
38struct kretprobe_blackpoint kretprobe_blacklist[] = {{NULL, NULL}}; 38struct kretprobe_blackpoint kretprobe_blacklist[] = {{NULL, NULL}};
39 39
40int __kprobes arch_prepare_kprobe(struct kprobe *p) 40static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
41{ 41{
42 /* Make sure the probe isn't going on a difficult instruction */ 42 switch (insn[0] >> 8) {
43 if (is_prohibited_opcode((kprobe_opcode_t *) p->addr))
44 return -EINVAL;
45
46 if ((unsigned long)p->addr & 0x01)
47 return -EINVAL;
48
49 /* Use the get_insn_slot() facility for correctness */
50 if (!(p->ainsn.insn = get_insn_slot()))
51 return -ENOMEM;
52
53 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
54
55 get_instruction_type(&p->ainsn);
56 p->opcode = *p->addr;
57 return 0;
58}
59
60int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
61{
62 switch (*(__u8 *) instruction) {
63 case 0x0c: /* bassm */ 43 case 0x0c: /* bassm */
64 case 0x0b: /* bsm */ 44 case 0x0b: /* bsm */
65 case 0x83: /* diag */ 45 case 0x83: /* diag */
@@ -68,7 +48,7 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
68 case 0xad: /* stosm */ 48 case 0xad: /* stosm */
69 return -EINVAL; 49 return -EINVAL;
70 } 50 }
71 switch (*(__u16 *) instruction) { 51 switch (insn[0]) {
72 case 0x0101: /* pr */ 52 case 0x0101: /* pr */
73 case 0xb25a: /* bsa */ 53 case 0xb25a: /* bsa */
74 case 0xb240: /* bakr */ 54 case 0xb240: /* bakr */
@@ -81,80 +61,79 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
81 return 0; 61 return 0;
82} 62}
83 63
84void __kprobes get_instruction_type(struct arch_specific_insn *ainsn) 64static int __kprobes get_fixup_type(kprobe_opcode_t *insn)
85{ 65{
86 /* default fixup method */ 66 /* default fixup method */
87 ainsn->fixup = FIXUP_PSW_NORMAL; 67 int fixup = FIXUP_PSW_NORMAL;
88
89 /* save r1 operand */
90 ainsn->reg = (*ainsn->insn & 0xf0) >> 4;
91
92 /* save the instruction length (pop 5-5) in bytes */
93 switch (*(__u8 *) (ainsn->insn) >> 6) {
94 case 0:
95 ainsn->ilen = 2;
96 break;
97 case 1:
98 case 2:
99 ainsn->ilen = 4;
100 break;
101 case 3:
102 ainsn->ilen = 6;
103 break;
104 }
105 68
106 switch (*(__u8 *) ainsn->insn) { 69 switch (insn[0] >> 8) {
107 case 0x05: /* balr */ 70 case 0x05: /* balr */
108 case 0x0d: /* basr */ 71 case 0x0d: /* basr */
109 ainsn->fixup = FIXUP_RETURN_REGISTER; 72 fixup = FIXUP_RETURN_REGISTER;
110 /* if r2 = 0, no branch will be taken */ 73 /* if r2 = 0, no branch will be taken */
111 if ((*ainsn->insn & 0x0f) == 0) 74 if ((insn[0] & 0x0f) == 0)
112 ainsn->fixup |= FIXUP_BRANCH_NOT_TAKEN; 75 fixup |= FIXUP_BRANCH_NOT_TAKEN;
113 break; 76 break;
114 case 0x06: /* bctr */ 77 case 0x06: /* bctr */
115 case 0x07: /* bcr */ 78 case 0x07: /* bcr */
116 ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN; 79 fixup = FIXUP_BRANCH_NOT_TAKEN;
117 break; 80 break;
118 case 0x45: /* bal */ 81 case 0x45: /* bal */
119 case 0x4d: /* bas */ 82 case 0x4d: /* bas */
120 ainsn->fixup = FIXUP_RETURN_REGISTER; 83 fixup = FIXUP_RETURN_REGISTER;
121 break; 84 break;
122 case 0x47: /* bc */ 85 case 0x47: /* bc */
123 case 0x46: /* bct */ 86 case 0x46: /* bct */
124 case 0x86: /* bxh */ 87 case 0x86: /* bxh */
125 case 0x87: /* bxle */ 88 case 0x87: /* bxle */
126 ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN; 89 fixup = FIXUP_BRANCH_NOT_TAKEN;
127 break; 90 break;
128 case 0x82: /* lpsw */ 91 case 0x82: /* lpsw */
129 ainsn->fixup = FIXUP_NOT_REQUIRED; 92 fixup = FIXUP_NOT_REQUIRED;
130 break; 93 break;
131 case 0xb2: /* lpswe */ 94 case 0xb2: /* lpswe */
132 if (*(((__u8 *) ainsn->insn) + 1) == 0xb2) { 95 if ((insn[0] & 0xff) == 0xb2)
133 ainsn->fixup = FIXUP_NOT_REQUIRED; 96 fixup = FIXUP_NOT_REQUIRED;
134 }
135 break; 97 break;
136 case 0xa7: /* bras */ 98 case 0xa7: /* bras */
137 if ((*ainsn->insn & 0x0f) == 0x05) { 99 if ((insn[0] & 0x0f) == 0x05)
138 ainsn->fixup |= FIXUP_RETURN_REGISTER; 100 fixup |= FIXUP_RETURN_REGISTER;
139 }
140 break; 101 break;
141 case 0xc0: 102 case 0xc0:
142 if ((*ainsn->insn & 0x0f) == 0x00 /* larl */ 103 if ((insn[0] & 0x0f) == 0x00 || /* larl */
143 || (*ainsn->insn & 0x0f) == 0x05) /* brasl */ 104 (insn[0] & 0x0f) == 0x05) /* brasl */
144 ainsn->fixup |= FIXUP_RETURN_REGISTER; 105 fixup |= FIXUP_RETURN_REGISTER;
145 break; 106 break;
146 case 0xeb: 107 case 0xeb:
147 if (*(((__u8 *) ainsn->insn) + 5 ) == 0x44 || /* bxhg */ 108 if ((insn[2] & 0xff) == 0x44 || /* bxhg */
148 *(((__u8 *) ainsn->insn) + 5) == 0x45) {/* bxleg */ 109 (insn[2] & 0xff) == 0x45) /* bxleg */
149 ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN; 110 fixup = FIXUP_BRANCH_NOT_TAKEN;
150 }
151 break; 111 break;
152 case 0xe3: /* bctg */ 112 case 0xe3: /* bctg */
153 if (*(((__u8 *) ainsn->insn) + 5) == 0x46) { 113 if ((insn[2] & 0xff) == 0x46)
154 ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN; 114 fixup = FIXUP_BRANCH_NOT_TAKEN;
155 }
156 break; 115 break;
157 } 116 }
117 return fixup;
118}
119
120int __kprobes arch_prepare_kprobe(struct kprobe *p)
121{
122 if ((unsigned long) p->addr & 0x01)
123 return -EINVAL;
124
125 /* Make sure the probe isn't going on a difficult instruction */
126 if (is_prohibited_opcode((kprobe_opcode_t *) p->addr))
127 return -EINVAL;
128
129 /* Use the get_insn_slot() facility for correctness */
130 if (!(p->ainsn.insn = get_insn_slot()))
131 return -ENOMEM;
132
133 p->opcode = *p->addr;
134 memcpy(p->ainsn.insn, p->addr, ((p->opcode >> 14) + 3) & -2);
135
136 return 0;
158} 137}
159 138
160struct ins_replace_args { 139struct ins_replace_args {
@@ -444,17 +423,22 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
444{ 423{
445 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 424 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
446 unsigned long ip = regs->psw.addr & PSW_ADDR_INSN; 425 unsigned long ip = regs->psw.addr & PSW_ADDR_INSN;
426 int fixup = get_fixup_type(p->ainsn.insn);
447 427
448 if (p->ainsn.fixup & FIXUP_PSW_NORMAL) 428 if (fixup & FIXUP_PSW_NORMAL)
449 ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; 429 ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn;
450 430
451 if (p->ainsn.fixup & FIXUP_BRANCH_NOT_TAKEN) 431 if (fixup & FIXUP_BRANCH_NOT_TAKEN) {
452 if (ip - (unsigned long) p->ainsn.insn == p->ainsn.ilen) 432 int ilen = ((p->ainsn.insn[0] >> 14) + 3) & -2;
453 ip = (unsigned long) p->addr + p->ainsn.ilen; 433 if (ip - (unsigned long) p->ainsn.insn == ilen)
434 ip = (unsigned long) p->addr + ilen;
435 }
454 436
455 if (p->ainsn.fixup & FIXUP_RETURN_REGISTER) 437 if (fixup & FIXUP_RETURN_REGISTER) {
456 regs->gprs[p->ainsn.reg] += (unsigned long) p->addr - 438 int reg = (p->ainsn.insn[0] & 0xf0) >> 4;
457 (unsigned long) p->ainsn.insn; 439 regs->gprs[reg] += (unsigned long) p->addr -
440 (unsigned long) p->ainsn.insn;
441 }
458 442
459 disable_singlestep(kcb, regs, ip); 443 disable_singlestep(kcb, regs, ip);
460} 444}