/* * Called after single-stepping. To avoid the SMP problems that can * occur when we temporarily put back the original opcode to * single-step, we single-stepped a copy of the instruction. * * This function prepares to resume execution after the single-step. * We have to fix things up as follows: * * Typically, the new ip is relative to the copied instruction. We need * to make it relative to the original instruction (FIX_IP). Exceptions * are return instructions and absolute or indirect jump or call instructions. * * If the single-stepped instruction was a call, the return address that * is atop the stack is the address following the copied instruction. We * need to make it the address following the original instruction (FIX_CALL). * * If the original instruction was a rip-relative instruction such as * "movl %edx,0xnnnn(%rip)", we have instead executed an equivalent * instruction using a scratch register -- e.g., "movl %edx,(%rax)". * We need to restore the contents of the scratch register and adjust * the ip, keeping in mind that the instruction we executed is 4 bytes * shorter than the original instruction (since we squeezed out the offset * field). (FIX_RIP_AX or FIX_RIP_CX) */ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) { struct uprobe_task *utask; long correction; int result = 0; WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); utask = current->utask; current->thread.trap_nr = utask->autask.saved_trap_nr; correction = (long)(utask->vaddr - utask->xol_vaddr); handle_riprel_post_xol(auprobe, regs, &correction); if (auprobe->fixups & UPROBE_FIX_IP) regs->ip += correction; if (auprobe->fixups & UPROBE_FIX_CALL) result = adjust_ret_addr(regs->sp, correction); /* * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP * so we can get an extra SIGTRAP if we do not clear TF. We need * to examine the opcode to make it right. */ if (utask->autask.saved_tf) send_sig(SIGTRAP, current, 0); else if (!(auprobe->fixups & UPROBE_FIX_SETF)) regs->flags &= ~X86_EFLAGS_TF; return result; }
/* * Called after single-stepping. ppt->vaddr is the address of the * instruction whose first byte has been replaced by the "int3" * instruction. To avoid the SMP problems that can occur when we * temporarily put back the original opcode to single-step, we * single-stepped a copy of the instruction. The address of this * copy is utask->singlestep_addr. * * This function prepares to return from the post-single-step * interrupt. We have to fix up the stack as follows: * * 0) Typically, the new eip is relative to the copied instruction. We * need to make it relative to the original instruction. Exceptions are * return instructions and absolute or indirect jump or call instructions. * * 1) If the single-stepped instruction was a call, the return address * that is atop the stack is the address following the copied instruction. * We need to make it the address following the original instruction. */ static void uprobe_post_ssout(struct uprobe_task *utask, struct uprobe_probept *ppt, struct pt_regs *regs) { long copy_eip = utask->singlestep_addr; long orig_eip = ppt->vaddr; unsigned long flags = ppt->arch_info.flags; up_read(&ppt->slot->rwsem); if (flags & UPFIX_RETURN) adjust_ret_addr(regs->esp, (orig_eip - copy_eip), utask); if (!(flags & UPFIX_ABS_IP)) regs->eip = orig_eip + (regs->eip - copy_eip); }
/* * Called after single-stepping. To avoid the SMP problems that can * occur when we temporarily put back the original opcode to * single-step, we single-stepped a copy of the instruction. * * This function prepares to resume execution after the single-step. * We have to fix things up as follows: * * Typically, the new ip is relative to the copied instruction. We need * to make it relative to the original instruction (FIX_IP). Exceptions * are return instructions and absolute or indirect jump or call instructions. * * If the single-stepped instruction was a call, the return address that * is atop the stack is the address following the copied instruction. We * need to make it the address following the original instruction (FIX_CALL). * * If the original instruction was a rip-relative instruction such as * "movl %edx,0xnnnn(%rip)", we have instead executed an equivalent * instruction using a scratch register -- e.g., "movl %edx,(%rax)". * We need to restore the contents of the scratch register and adjust * the ip, keeping in mind that the instruction we executed is 4 bytes * shorter than the original instruction (since we squeezed out the offset * field). (FIX_RIP_AX or FIX_RIP_CX) */ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) { struct uprobe_task *utask; long correction; int result = 0; WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); utask = current->utask; current->thread.trap_nr = utask->autask.saved_trap_nr; correction = (long)(utask->vaddr - utask->xol_vaddr); handle_riprel_post_xol(auprobe, regs, &correction); if (auprobe->fixups & UPROBE_FIX_IP) regs->ip += correction; if (auprobe->fixups & UPROBE_FIX_CALL) result = adjust_ret_addr(regs->sp, correction); return result; }