aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRusty Lynch <rusty.lynch@intel.com>2005-06-23 03:09:30 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:23 -0400
commit8bc76772ad653bcaad1b0af72aafb6072ef0fa87 (patch)
treed778f0cc2640e078338d84cdc67cda403cc47d7b /arch
parentcd2675bf65455a45b54228b7acc0c6a26a164cb6 (diff)
[PATCH] Kprobes ia64 cleanup
A cleanup of the ia64 kprobes implementation such that all of the bundle manipulation logic is concentrated in arch_prepare_kprobe(). With the current design for kprobes, the arch specific code only has a chance to return failure inside the arch_prepare_kprobe() function. This patch moves all of the work that was happening in arch_copy_kprobe() and most of the work that was happening in arch_arm_kprobe() into arch_prepare_kprobe(). By doing this we can add further robustness checks in arch_arm_kprobe() and refuse to insert kprobes that will cause problems. Signed-off-by: Rusty Lynch <Rusty.lynch@intel.com> Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/ia64/kernel/kprobes.c178
1 files changed, 77 insertions, 101 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 20a250e2e9b2..b7a204137fbb 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -84,121 +84,97 @@ static enum instruction_type bundle_encoding[32][3] = {
84int arch_prepare_kprobe(struct kprobe *p) 84int arch_prepare_kprobe(struct kprobe *p)
85{ 85{
86 unsigned long addr = (unsigned long) p->addr; 86 unsigned long addr = (unsigned long) p->addr;
87 unsigned long bundle_addr = addr & ~0xFULL; 87 unsigned long *bundle_addr = (unsigned long *)(addr & ~0xFULL);
88 unsigned long slot = addr & 0xf; 88 unsigned long slot = addr & 0xf;
89 bundle_t bundle;
90 unsigned long template; 89 unsigned long template;
90 unsigned long major_opcode = 0;
91 unsigned long lx_type_inst = 0;
92 unsigned long kprobe_inst = 0;
93 bundle_t *bundle = &p->ainsn.insn.bundle;
91 94
92 /* 95 memcpy(&p->opcode.bundle, bundle_addr, sizeof(bundle_t));
93 * TODO: Verify that a probe is not being inserted 96 memcpy(&p->ainsn.insn.bundle, bundle_addr, sizeof(bundle_t));
94 * in sensitive regions of code
95 * TODO: Verify that the memory holding the probe is rwx
96 * TODO: verify this is a kernel address
97 */
98 memcpy(&bundle, (unsigned long *)bundle_addr, sizeof(bundle_t));
99 template = bundle.quad0.template;
100 if (((bundle_encoding[template][1] == L) && slot > 1) || (slot > 2)) {
101 printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n", addr);
102 return -EINVAL;
103 }
104 return 0;
105}
106 97
107void arch_copy_kprobe(struct kprobe *p) 98 p->ainsn.inst_flag = 0;
108{ 99 p->ainsn.target_br_reg = 0;
109 unsigned long addr = (unsigned long)p->addr;
110 unsigned long bundle_addr = addr & ~0xFULL;
111 100
112 memcpy(&p->ainsn.insn.bundle, (unsigned long *)bundle_addr, 101 template = bundle->quad0.template;
113 sizeof(bundle_t));
114 memcpy(&p->opcode.bundle, &p->ainsn.insn.bundle, sizeof(bundle_t));
115}
116 102
117void arch_arm_kprobe(struct kprobe *p) 103 if (((bundle_encoding[template][1] == L) && slot > 1) || (slot > 2)) {
118{ 104 printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n",
119 unsigned long addr = (unsigned long)p->addr; 105 addr);
120 unsigned long arm_addr = addr & ~0xFULL; 106 return -EINVAL;
121 unsigned long slot = addr & 0xf; 107 }
122 unsigned long template;
123 unsigned long major_opcode = 0;
124 unsigned long lx_type_inst = 0;
125 unsigned long kprobe_inst = 0;
126 bundle_t bundle;
127
128 p->ainsn.inst_flag = 0;
129 p->ainsn.target_br_reg = 0;
130
131 memcpy(&bundle, &p->ainsn.insn.bundle, sizeof(bundle_t));
132 template = bundle.quad0.template;
133 if (slot == 1 && bundle_encoding[template][1] == L) {
134 lx_type_inst = 1;
135 slot = 2;
136 }
137 108
109 if (slot == 1 && bundle_encoding[template][1] == L) {
110 lx_type_inst = 1;
111 slot = 2;
112 }
138 113
139 switch (slot) { 114 switch (slot) {
140 case 0: 115 case 0:
141 major_opcode = (bundle.quad0.slot0 >> SLOT0_OPCODE_SHIFT); 116 major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT);
142 kprobe_inst = bundle.quad0.slot0; 117 kprobe_inst = bundle->quad0.slot0;
143 bundle.quad0.slot0 = BREAK_INST; 118 bundle->quad0.slot0 = BREAK_INST;
144 break; 119 break;
145 case 1: 120 case 1:
146 major_opcode = (bundle.quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT); 121 major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT);
147 kprobe_inst = (bundle.quad0.slot1_p0 | 122 kprobe_inst = (bundle->quad0.slot1_p0 |
148 (bundle.quad1.slot1_p1 << (64-46))); 123 (bundle->quad1.slot1_p1 << (64-46)));
149 bundle.quad0.slot1_p0 = BREAK_INST; 124 bundle->quad0.slot1_p0 = BREAK_INST;
150 bundle.quad1.slot1_p1 = (BREAK_INST >> (64-46)); 125 bundle->quad1.slot1_p1 = (BREAK_INST >> (64-46));
151 break; 126 break;
152 case 2: 127 case 2:
153 major_opcode = (bundle.quad1.slot2 >> SLOT2_OPCODE_SHIFT); 128 major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT);
154 kprobe_inst = bundle.quad1.slot2; 129 kprobe_inst = bundle->quad1.slot2;
155 bundle.quad1.slot2 = BREAK_INST; 130 bundle->quad1.slot2 = BREAK_INST;
156 break; 131 break;
157 } 132 }
158 /* 133
159 * Look for IP relative Branches, IP relative call or 134 /*
160 * IP relative predicate instructions 135 * Look for IP relative Branches, IP relative call or
161 */ 136 * IP relative predicate instructions
162 if (bundle_encoding[template][slot] == B) { 137 */
163 switch (major_opcode) { 138 if (bundle_encoding[template][slot] == B) {
164 case INDIRECT_CALL_OPCODE: 139 switch (major_opcode) {
165 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG; 140 case INDIRECT_CALL_OPCODE:
166 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7); 141 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
167 break; 142 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
168 case IP_RELATIVE_PREDICT_OPCODE: 143 break;
169 case IP_RELATIVE_BRANCH_OPCODE: 144 case IP_RELATIVE_PREDICT_OPCODE:
170 p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR; 145 case IP_RELATIVE_BRANCH_OPCODE:
171 break; 146 p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
172 case IP_RELATIVE_CALL_OPCODE: 147 break;
173 p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR; 148 case IP_RELATIVE_CALL_OPCODE:
174 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG; 149 p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
175 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7); 150 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
176 break; 151 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
177 default: 152 break;
178 /* Do nothing */ 153 default:
179 break; 154 /* Do nothing */
180 } 155 break;
181 } else if (lx_type_inst) { 156 }
182 switch (major_opcode) { 157 } else if (lx_type_inst) {
183 case LONG_CALL_OPCODE: 158 switch (major_opcode) {
184 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG; 159 case LONG_CALL_OPCODE:
185 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7); 160 p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
186 break; 161 p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
187 default: 162 break;
188 /* Do nothing */ 163 default:
189 break; 164 /* Do nothing */
190 } 165 break;
191 } 166 }
192 167 }
193 /* Flush icache for the instruction at the emulated address */ 168
194 flush_icache_range((unsigned long)&p->ainsn.insn.bundle, 169 return 0;
195 (unsigned long)&p->ainsn.insn.bundle + 170}
196 sizeof(bundle_t)); 171
197 /* 172void arch_arm_kprobe(struct kprobe *p)
198 * Patch the original instruction with the probe instruction 173{
199 * and flush the instruction cache 174 unsigned long addr = (unsigned long)p->addr;
200 */ 175 unsigned long arm_addr = addr & ~0xFULL;
201 memcpy((char *) arm_addr, (char *) &bundle, sizeof(bundle_t)); 176
177 memcpy((char *)arm_addr, &p->ainsn.insn.bundle, sizeof(bundle_t));
202 flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); 178 flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
203} 179}
204 180
@@ -226,7 +202,7 @@ void arch_remove_kprobe(struct kprobe *p)
226 */ 202 */
227static void resume_execution(struct kprobe *p, struct pt_regs *regs) 203static void resume_execution(struct kprobe *p, struct pt_regs *regs)
228{ 204{
229 unsigned long bundle_addr = ((unsigned long) (&p->ainsn.insn.bundle)) & ~0xFULL; 205 unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL;
230 unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL; 206 unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
231 unsigned long template; 207 unsigned long template;
232 int slot = ((unsigned long)p->addr & 0xf); 208 int slot = ((unsigned long)p->addr & 0xf);
@@ -293,7 +269,7 @@ turn_ss_off:
293 269
294static void prepare_ss(struct kprobe *p, struct pt_regs *regs) 270static void prepare_ss(struct kprobe *p, struct pt_regs *regs)
295{ 271{
296 unsigned long bundle_addr = (unsigned long) &p->ainsn.insn.bundle; 272 unsigned long bundle_addr = (unsigned long) &p->opcode.bundle;
297 unsigned long slot = (unsigned long)p->addr & 0xf; 273 unsigned long slot = (unsigned long)p->addr & 0xf;
298 274
299 /* Update instruction pointer (IIP) and slot number (IPSR.ri) */ 275 /* Update instruction pointer (IIP) and slot number (IPSR.ri) */