aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-09-23 15:10:18 -0400
committerOleg Nesterov <oleg@redhat.com>2012-09-29 15:21:54 -0400
commitcceb55aab73d2aea8f4d6f7414d2e1b647a3dacb (patch)
tree3da300ea711b72be0d5dc846d65f94695c5a7ed5 /kernel
parente97f65a17deafacc360a4cb75ae944897ecea6d7 (diff)
uprobes: Introduce copy_opcode(), kill read_opcode()
No functional changes, preparations. 1. Extract the kmap-and-memcpy code from read_opcode() into the new trivial helper, copy_opcode(). The next patch will add another user. 2. read_opcode() becomes really trivial, fold it into its single caller, is_swbp_at_addr(). 3. Remove "auprobe" argument from write_opcode(), it is not used since f403072c6. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/events/uprobes.c63
1 files changed, 19 insertions, 44 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index a4453d1c8199..b6f0f716a884 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -183,19 +183,25 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn)
183 return *insn == UPROBE_SWBP_INSN; 183 return *insn == UPROBE_SWBP_INSN;
184} 184}
185 185
186static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode)
187{
188 void *kaddr = kmap_atomic(page);
189 memcpy(opcode, kaddr + (vaddr & ~PAGE_MASK), UPROBE_SWBP_INSN_SIZE);
190 kunmap_atomic(kaddr);
191}
192
186/* 193/*
187 * NOTE: 194 * NOTE:
188 * Expect the breakpoint instruction to be the smallest size instruction for 195 * Expect the breakpoint instruction to be the smallest size instruction for
189 * the architecture. If an arch has variable length instruction and the 196 * the architecture. If an arch has variable length instruction and the
190 * breakpoint instruction is not of the smallest length instruction 197 * breakpoint instruction is not of the smallest length instruction
191 * supported by that architecture then we need to modify read_opcode / 198 * supported by that architecture then we need to modify is_swbp_at_addr and
192 * write_opcode accordingly. This would never be a problem for archs that 199 * write_opcode accordingly. This would never be a problem for archs that
193 * have fixed length instructions. 200 * have fixed length instructions.
194 */ 201 */
195 202
196/* 203/*
197 * write_opcode - write the opcode at a given virtual address. 204 * write_opcode - write the opcode at a given virtual address.
198 * @auprobe: arch breakpointing information.
199 * @mm: the probed process address space. 205 * @mm: the probed process address space.
200 * @vaddr: the virtual address to store the opcode. 206 * @vaddr: the virtual address to store the opcode.
201 * @opcode: opcode to be written at @vaddr. 207 * @opcode: opcode to be written at @vaddr.
@@ -206,8 +212,8 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn)
206 * For mm @mm, write the opcode at @vaddr. 212 * For mm @mm, write the opcode at @vaddr.
207 * Return 0 (success) or a negative errno. 213 * Return 0 (success) or a negative errno.
208 */ 214 */
209static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, 215static int write_opcode(struct mm_struct *mm, unsigned long vaddr,
210 unsigned long vaddr, uprobe_opcode_t opcode) 216 uprobe_opcode_t opcode)
211{ 217{
212 struct page *old_page, *new_page; 218 struct page *old_page, *new_page;
213 void *vaddr_old, *vaddr_new; 219 void *vaddr_old, *vaddr_new;
@@ -253,40 +259,9 @@ put_old:
253 return ret; 259 return ret;
254} 260}
255 261
256/**
257 * read_opcode - read the opcode at a given virtual address.
258 * @mm: the probed process address space.
259 * @vaddr: the virtual address to read the opcode.
260 * @opcode: location to store the read opcode.
261 *
262 * Called with mm->mmap_sem held (for read and with a reference to
263 * mm.
264 *
265 * For mm @mm, read the opcode at @vaddr and store it in @opcode.
266 * Return 0 (success) or a negative errno.
267 */
268static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t *opcode)
269{
270 struct page *page;
271 void *vaddr_new;
272 int ret;
273
274 ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
275 if (ret <= 0)
276 return ret;
277
278 vaddr_new = kmap_atomic(page);
279 vaddr &= ~PAGE_MASK;
280 memcpy(opcode, vaddr_new + vaddr, UPROBE_SWBP_INSN_SIZE);
281 kunmap_atomic(vaddr_new);
282
283 put_page(page);
284
285 return 0;
286}
287
288static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) 262static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
289{ 263{
264 struct page *page;
290 uprobe_opcode_t opcode; 265 uprobe_opcode_t opcode;
291 int result; 266 int result;
292 267
@@ -300,14 +275,14 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
300 goto out; 275 goto out;
301 } 276 }
302 277
303 result = read_opcode(mm, vaddr, &opcode); 278 result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
304 if (result) 279 if (result < 0)
305 return result; 280 return result;
306out:
307 if (is_swbp_insn(&opcode))
308 return 1;
309 281
310 return 0; 282 copy_opcode(page, vaddr, &opcode);
283 put_page(page);
284 out:
285 return is_swbp_insn(&opcode);
311} 286}
312 287
313/** 288/**
@@ -321,7 +296,7 @@ out:
321 */ 296 */
322int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) 297int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
323{ 298{
324 return write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN); 299 return write_opcode(mm, vaddr, UPROBE_SWBP_INSN);
325} 300}
326 301
327/** 302/**
@@ -345,7 +320,7 @@ set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long v
345 if (result != 1) 320 if (result != 1)
346 return result; 321 return result;
347 322
348 return write_opcode(auprobe, mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); 323 return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
349} 324}
350 325
351static int match_uprobe(struct uprobe *l, struct uprobe *r) 326static int match_uprobe(struct uprobe *l, struct uprobe *r)