diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/uprobes.c | 30 |
1 files changed, 14 insertions, 16 deletions
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 5df1bca7c2bc..2ebadb252093 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -326,22 +326,24 @@ static void riprel_analyze(struct arch_uprobe *auprobe, struct insn *insn) | |||
326 | } | 326 | } |
327 | } | 327 | } |
328 | 328 | ||
329 | static inline unsigned long * | ||
330 | scratch_reg(struct arch_uprobe *auprobe, struct pt_regs *regs) | ||
331 | { | ||
332 | return (auprobe->def.fixups & UPROBE_FIX_RIP_AX) ? ®s->ax : ®s->cx; | ||
333 | } | ||
334 | |||
329 | /* | 335 | /* |
330 | * If we're emulating a rip-relative instruction, save the contents | 336 | * If we're emulating a rip-relative instruction, save the contents |
331 | * of the scratch register and store the target address in that register. | 337 | * of the scratch register and store the target address in that register. |
332 | */ | 338 | */ |
333 | static void riprel_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | 339 | static void riprel_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) |
334 | { | 340 | { |
335 | struct uprobe_task *utask = current->utask; | 341 | if (auprobe->def.fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { |
342 | struct uprobe_task *utask = current->utask; | ||
343 | unsigned long *sr = scratch_reg(auprobe, regs); | ||
336 | 344 | ||
337 | if (auprobe->def.fixups & UPROBE_FIX_RIP_AX) { | 345 | utask->autask.saved_scratch_register = *sr; |
338 | utask->autask.saved_scratch_register = regs->ax; | 346 | *sr = utask->vaddr + auprobe->def.riprel_target; |
339 | regs->ax = utask->vaddr; | ||
340 | regs->ax += auprobe->def.riprel_target; | ||
341 | } else if (auprobe->def.fixups & UPROBE_FIX_RIP_CX) { | ||
342 | utask->autask.saved_scratch_register = regs->cx; | ||
343 | regs->cx = utask->vaddr; | ||
344 | regs->cx += auprobe->def.riprel_target; | ||
345 | } | 347 | } |
346 | } | 348 | } |
347 | 349 | ||
@@ -349,14 +351,10 @@ static void riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, | |||
349 | long *correction) | 351 | long *correction) |
350 | { | 352 | { |
351 | if (auprobe->def.fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { | 353 | if (auprobe->def.fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { |
352 | struct arch_uprobe_task *autask; | 354 | struct uprobe_task *utask = current->utask; |
353 | 355 | unsigned long *sr = scratch_reg(auprobe, regs); | |
354 | autask = ¤t->utask->autask; | ||
355 | if (auprobe->def.fixups & UPROBE_FIX_RIP_AX) | ||
356 | regs->ax = autask->saved_scratch_register; | ||
357 | else | ||
358 | regs->cx = autask->saved_scratch_register; | ||
359 | 356 | ||
357 | *sr = utask->autask.saved_scratch_register; | ||
360 | /* | 358 | /* |
361 | * The original instruction includes a displacement, and so | 359 | * The original instruction includes a displacement, and so |
362 | * is 4 bytes longer than what we've just single-stepped. | 360 | * is 4 bytes longer than what we've just single-stepped. |