1
linux/include/asm-i386
Masami Hiramatsu 311ac88fd2 [PATCH] x86: kprobes-booster
Current kprobe copies the original instruction at the probe point and replaces
it with a breakpoint instruction (int3).  When the kernel hits the probe
point, kprobe handler is invoked.  And the copied instruction is single-step
executed on the copied buffer (not on the original address) by kprobe.  After
that, the kprobe checks registers and modify it (if need) as if the
instructions was executed on the original address.

My proposal is based on the fact there are many instructions which do NOT
require the register modification after the single-step execution.  When the
copied instruction is a kind of them, kprobe just jumps back to the next
instruction after single-step execution.  If so, why don't we execute those
instructions directly?

With kprobe-booster patch, kprobes will execute a copied instruction directly
and (if need) jump back to original code.  This direct execution is executed
when the kprobe don't have both post_handler and break_handler, and the copied
instruction can be executed directly.

I sorted instructions which can be executed directly or not;

- Call instructions are NG(can not be executed directly).
  We should correct the return address pushed into top of stack.
- Indirect instructions except for absolute indirect-jumps
  are NG. Those instructions changes EIP randomly. We should
  check EIP and correct it.
- Instructions that change EIP beyond the range of the
  instruction buffer are NG.
- Instructions that change EIP to tail 5 bytes of the
  instruction buffer (it is the size of a jump instruction).
  We must write a jump instruction which backs to original
  kernel code in the instruction buffer.
- Break point instruction is NG. We should not touch EIP and
  pass to other handlers.
- Absolute direct/indirect jumps are OK.- Conditional Jumps are NG.
- Halt and software-interruptions are NG. Because it will stay on
  the instruction buffer of kprobes.
- Prefixes are NG.
- Unknown/reserved opcode is NG.
- Other 1 byte instructions are OK. But those instructions need a
  jump back code.
- 2 bytes instructions are mapped sparsely. So, in this release,
  this patch don't boost those instructions.

>From Intel's IA-32 opcode map described in IA-32 Intel Architecture Software
Developer's Manual Vol.2 B, I determined that following opcodes are not
boostable.

- 0FH (2byte escape)
- 70H - 7FH (Jump on condition)
- 9AH (Call) and 9CH (Pushf)
- C0H-C1H (Grp 2: includes reserved opcode)
- C6H-C7H (Grp11: includes reserved opcode)
- CCH-CEH (Software-interrupt)
- D0H-D3H (Grp2: includes reserved opcode)
- D6H (Reserved)
- D8H-DFH (Coprocessor)
- E0H-E3H (loop/conditional jump)
- E8H (Call)
- F0H-F3H (Prefixes and reserved)
- F4H (Halt)
- F6H-F7H (Grp3: includes reserved opcode)
- FEH-FFH(Grp4,5: includes reserved opcode)

Kprobe-booster checks whether target instruction can be boosted (can be
executed directly) at arch_copy_kprobe() function.  If the target instruction
can be boosted, it clears "boostable" flag.  If not, it sets "boostable" flag
-1.  This is disabled status.  In resume_execution() function, If "boostable"
flag is cleared, kprobe-booster measures the size of the target instruction
and sets "boostable" flag 1.

In kprobe_handler(), kprobe checks the "boostable" flag.  If the flag is 1, it
resets current kprobe and executes instruction buffer directly instead of
single stepping.

When unregistering a boosted kprobe, it calls synchronize_sched()
after "int3" is removed. So we can ensure followings after
the synchronize_sched() called.
- interrupt handlers are finished on all CPUs.
- instruction buffer is not executed on all CPUs.
And we can release the boosted kprobe safely.

And also, on preemptible kernel, the booster is not enabled where the kernel
preemption is enabled.  So, there are no preempted threads on the instruction
buffer.

The description of kretprobe-booster:
====================================

In the normal operation, kretprobe make a target function return to trampoline
code.  And a kprobe (called trampoline_probe) have been inserted at the
trampoline code.  When the kernel hits this kprobe, it calls kretprobe's
handler and it returns to original return address.

Kretprobe-booster patch removes the trampoline_probe.  It allows the
trampoline code to call kretprobe's handler directly instead of invoking
kprobe.  And tranpoline code returns to original return address.

This new trampoline code stores and restores registers, so the kretprobe
handler is still able to access those registers.

Current kprobe has about 1.3 usec/probe(*) overhead, and kprobe-booster patch
reduces it to 0.6 usec/probe(*).  Also current kretprobe has about 2.0
usec/probe(*) overhead.  Kprobe-booster patch reduces it to 1.3 usec/probe(*),
and the combination of both kprobe-booster patch and kretprobe-booster patch
reduces it to 0.9 usec/probe(*).

I expect the combination of both patches can reduce half of a probing
overhead.

Performance numbers strongly depend on the processor model.

Andrew Morton wrote:
> These preempt tricks look rather nasty.  Can you please describe what the
> problem is, precisely?  And how this code avoids it?  Perhaps we can find
> something cleaner.

The problem is how to remove the copied instructions of the
kprobe *safely* on the preemptable kernel (CONFIG_PREEMPT=y).

Kprobes basically executes the following actions;

(1)int3
(2)preempt_disable()
(3)kprobe_prehandler()
(4)copied instructioin(single step)
(5)kprobe_posthandler()
(6)preempt_enable()
(7)return to the original code

During the execution of copied instruction, preemption is
disabled (from step (2) to (6)).
When unregistering the probes, Kprobe waits for RCU
quiescent state by using synchronize_sched() after removing
int3 instruction.
Thus we can ensure the copied instruction is not executed.

On the other hand, kprobe-booster executes the following actions;

(1)int3
(2)preempt_disable()
(3)kprobe_prehandler()
(4)preempt_enable()             <-- this one is added by my patch
(5)copied instruction(direct execution)
(6)jmp back to the original code

The problem is that we have no way to prevent preemption on
step (5) or (6). We cannot call preempt_disable() after step (6),
because there are no rooms to do that. Thus, some other
processes may be preempted at step(5) or (6) on preemptable kernel.
And I couldn't find the easy way to ensure that other processes'
stack do *not* have the address of them. (I thought some way
to do that, but those are very costly.)

So currently, I simply boost the kprobe only when the probe
point is already preemption disabled.

> Also, the patch adds a preempt_enable() but I don't see a corresponding
> preempt_disable().  Am I missing something?

It is corresponding to the preempt_disable() in the top of
kprobe_handler().
I copied the code of kprobe_handler() here:

static int __kprobes kprobe_handler(struct pt_regs *regs)
{
        struct kprobe *p;
        int ret = 0;
        kprobe_opcode_t *addr = NULL;
        unsigned long *lp;
        struct kprobe_ctlblk *kcb;

        /*
         * We don't want to be preempted for the entire
         * duration of kprobe processing
         */
        preempt_disable();             <-- HERE
        kcb = get_kprobe_ctlblk();

Signed-off-by: Masami Hiramatsu <hiramatu@sdl.hitachi.co.jp>
Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-26 08:57:04 -08:00
..
mach-bigsmp [PATCH] x86: convert bigsmp to use flat physical mode 2006-01-06 08:33:37 -08:00
mach-default [PATCH] i386: fix uses of user_mode() vs. user_mode_vm() 2006-03-23 07:38:05 -08:00
mach-es7000 [PATCH] Compilation fix for ES7000 when no ACPI is specified in config (i386) 2006-03-23 07:38:04 -08:00
mach-generic [PATCH] x86: sutomatically enable bigsmp when we have more than 8 CPUs 2005-09-05 00:06:10 -07:00
mach-numaq [PATCH] Do not enforce unique IO_APIC_ID check for xAPIC systems (i386) 2005-06-23 09:45:09 -07:00
mach-summit [PATCH] USB: Always do usb-handoff 2005-10-28 16:47:49 -07:00
mach-visws [PATCH] i386: fix uses of user_mode() vs. user_mode_vm() 2006-03-23 07:38:05 -08:00
mach-voyager [PATCH] i386: fix uses of user_mode() vs. user_mode_vm() 2006-03-23 07:38:05 -08:00
8253pit.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
a.out.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
acpi.h [PATCH] don't call check_acpi_pci() on x86 with ACPI disabled 2006-03-22 07:53:54 -08:00
agp.h [PATCH] i386: inline asm cleanup 2005-09-05 00:06:11 -07:00
alternative.h [PATCH] x86: SMP alternatives 2006-03-23 07:38:04 -08:00
apic.h [PATCH] i386: port ATI timer fix from x86_64 to i386 II 2006-03-08 18:10:31 -08:00
apicdef.h [PATCH] x86: sutomatically enable bigsmp when we have more than 8 CPUs 2005-09-05 00:06:10 -07:00
arch_hooks.h [PATCH] x86: early printk handling fixes 2006-03-23 07:38:05 -08:00
atomic.h [PATCH] atomic: add_unless cmpxchg optimise 2006-03-23 07:38:17 -08:00
auxvec.h [PATCH] auxiliary vector cleanups 2005-09-07 16:57:21 -07:00
bitops.h [PATCH] x86: SMP alternatives 2006-03-23 07:38:04 -08:00
boot.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
bug.h [PATCH] remove all kernel BUGs 2005-05-01 08:59:01 -07:00
bugs.h [PATCH] i386: move SIMD initialization 2006-01-06 08:33:34 -08:00
byteorder.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
cache.h [PATCH] Move read_mostly definition to asm/cache.h 2006-03-23 07:38:10 -08:00
cacheflush.h [PATCH] x86/x86_64: mark rodata section read only: x86 parts 2006-01-06 08:33:36 -08:00
checksum.h [NET]: Fix ipl=>ihl typo in ip_fast_csum 2005-08-29 16:02:48 -07:00
cpu.h [PATCH] i386 CPU hotplug 2005-06-25 16:24:29 -07:00
cpufeature.h [PATCH] x86: SMP alternatives 2006-03-23 07:38:04 -08:00
cputime.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
current.h [PATCH] mark several functions __always_inline 2006-01-14 18:27:15 -08:00
debugreg.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
delay.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
desc.h [PATCH] x86: fix broken SMP boot sequence 2006-02-24 14:31:38 -08:00
div64.h [PATCH] include/asm-i386/: "extern inline" -> "static inline" 2005-09-10 10:06:34 -07:00
dma-mapping.h [PATCH] i386: make pci_map_single/pci_map_sg warn for zero length. 2006-01-11 19:04:56 -08:00
dma.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
dmi.h [PATCH] x86_64: Implement early DMI scanning 2006-03-25 09:10:55 -08:00
e820.h [PATCH] Increase number of e820 entries hard limit from 32 to 128 2005-05-01 08:58:51 -07:00
edac.h [PATCH] EDAC: core EDAC support code 2006-01-18 19:20:31 -08:00
elf.h [PATCH] fix remaining missing includes 2005-11-07 07:53:41 -08:00
emergency-restart.h [PATCH] i386: Implement machine_emergency_reboot 2005-07-26 14:35:42 -07:00
errno.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
fcntl.h [PATCH] Clean up struct flock64 definitions 2005-09-07 16:57:38 -07:00
fixmap.h [ACPI] delete CONFIG_ACPI_BOOT 2005-08-24 12:08:54 -04:00
floppy.h [PATCH] make some things static 2005-05-05 16:36:47 -07:00
futex.h [PATCH] uml: remove leftover from patch revertal 2006-01-18 19:20:20 -08:00
genapic.h [PATCH] Do not enforce unique IO_APIC_ID check for xAPIC systems (i386) 2005-06-23 09:45:09 -07:00
hardirq.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
highmem.h [PATCH] kdump: Routines for copying dump pages 2005-06-25 16:24:53 -07:00
hpet.h [PATCH] i386: fix hpet for systems that don't support legacy replacement 2005-05-01 08:58:50 -07:00
hw_irq.h Revert "i386: move apic init in init_IRQs" 2005-10-31 19:16:17 -08:00
i387.h [PATCH] i386: task_thread_info() 2006-01-12 09:08:51 -08:00
i8253.h [PATCH] x86: i8253/i8259A lock cleanup 2005-06-30 08:45:10 -07:00
i8259.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
ide.h [PATCH] ide: explain the PCI bus test we do in <asm-i386/ide.h> 2005-11-10 00:10:37 +01:00
io_apic.h [ACPI] delete CONFIG_ACPI_BOOT 2005-08-24 12:08:54 -04:00
io.h [PATCH] remove ISA legacy functions: remove the helpers 2006-03-24 07:33:19 -08:00
ioctl.h [PATCH] Generic ioctl.h 2006-01-10 08:01:34 -08:00
ioctls.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
ipc.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
ipcbuf.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
irq.h [PATCH] Make vm86 support optional 2006-01-08 20:14:11 -08:00
ist.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
kdebug.h [PATCH] x86 NMI: better support for debuggers 2005-09-05 00:06:13 -07:00
kexec.h [PATCH] Kdump: i386 compiler warning fix 2006-01-10 08:01:27 -08:00
kmap_types.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
kprobes.h [PATCH] x86: kprobes-booster 2006-03-26 08:57:04 -08:00
ldt.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
linkage.h [PATCH] i386: fix prevent_tail_call 2005-05-26 16:16:16 -07:00
local.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
math_emu.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
mc146818rtc.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
mca_dma.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
mca.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
mman.h [PATCH] add asm-generic/mman.h 2006-02-15 15:32:22 -08:00
mmu_context.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
mmu.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
mmx.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
mmzone.h [PATCH] mm: kvaddr_to_nid not used in common code 2006-01-06 08:33:23 -08:00
module.h [PATCH] Base support for AMD Geode GX/LX processors 2006-01-06 08:33:38 -08:00
mpspec_def.h [PATCH] mpspec: remove unneeded packed attribute 2006-01-06 08:33:39 -08:00
mpspec.h [PATCH] i386: remove duplicate declaration of mp_bus_id_to_pci_bus 2006-03-23 07:38:04 -08:00
msgbuf.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
msi.h [PATCH] PCI: Change MSI to use physical delivery mode always 2005-11-10 16:09:18 -08:00
msr.h [PATCH] x86: more asm cleanups 2005-09-05 00:06:12 -07:00
mtrr.h [PATCH] Fix the imlicit declaration of mtrr_centaur_report_mcr in arch/i386/kernel/cpu/centaur.c 2006-03-23 07:38:06 -08:00
mutex.h [PATCH] x86: SMP alternatives 2006-03-23 07:38:04 -08:00
namei.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
nmi.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
node.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
numa.h [PATCH] x86-64: Use ACPI PXM to parse PCI<->node assignments 2005-09-12 10:49:57 -07:00
numaq.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
numnodes.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
page.h [PATCH] VMSPLIT config options 2006-02-01 08:53:21 -08:00
param.h [PATCH] Avoid namespace pollution in <asm/param.h> 2006-01-02 08:38:38 -08:00
parport.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
pci-direct.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
pci.h Revert PCIBIOS_MIN_IO changes for 2.6.13 2005-08-14 18:21:30 -07:00
percpu.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
pgalloc.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
pgtable-2level-defs.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
pgtable-2level.h [PATCH] i386: actively synchronize vmalloc area when registering certain callbacks 2006-03-23 07:38:05 -08:00
pgtable-3level-defs.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
pgtable-3level.h [PATCH] i386: actively synchronize vmalloc area when registering certain callbacks 2006-03-23 07:38:05 -08:00
pgtable.h [PATCH] Enable mprotect on huge pages 2006-03-22 07:54:03 -08:00
poll.h [PATCH] POLLRDHUP/EPOLLRDHUP handling for half-closed devices notifications 2006-03-25 08:22:56 -08:00
posix_types.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
processor.h [PATCH] i386: task_stack_page() 2006-01-12 09:08:52 -08:00
ptrace.h [PATCH] PTRACE_SYSEMU is only for i386 and clashes with other ptrace codes of other archs 2006-01-08 20:14:04 -08:00
resource.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
rtc.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
rwlock.h [PATCH] x86: SMP alternatives 2006-03-23 07:38:04 -08:00
rwsem.h [PATCH] add sem_is_read/write_locked() 2005-10-29 21:40:35 -07:00
scatterlist.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
seccomp.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
sections.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
segment.h [PATCH] x86: Pnp segments in segment h 2006-01-06 08:33:34 -08:00
semaphore.h [PATCH] x86: SMP alternatives 2006-03-23 07:38:04 -08:00
sembuf.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
serial.h [PATCH] Serial: Split 8250 port table (part 2) 2005-06-29 18:45:19 +01:00
setup.h [PATCH] x86: fix EFI memory map parsing 2005-09-05 00:06:09 -07:00
shmbuf.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
shmparam.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
sigcontext.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
siginfo.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
signal.h [PATCH] Handle TIF_RESTORE_SIGMASK for i386 2006-01-18 19:20:29 -08:00
smp.h [PATCH] PCI: Change MSI to use physical delivery mode always 2005-11-10 16:09:18 -08:00
socket.h [NET]: Introduce SO_{SND,RCV}BUFFORCE socket options 2005-08-29 15:31:35 -07:00
sockios.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
sparsemem.h [PATCH] sparsemem memory model for i386 2005-06-23 09:45:05 -07:00
spinlock_types.h [PATCH] spinlock consolidation 2005-09-10 10:06:21 -07:00
spinlock.h [PATCH] i386 spinlocks: disable interrupts only if we enabled them 2006-03-23 07:38:06 -08:00
srat.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
stat.h [PATCH] 2TB files: st_blocks is invalid when calling stat64 2006-03-26 08:57:00 -08:00
statfs.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
string.h [PATCH] mark several functions __always_inline 2006-01-14 18:27:15 -08:00
suspend.h [PATCH] i386: Use loaddebug macro consistently 2005-04-16 15:24:46 -07:00
system.h [PATCH] kill include/linux/platform.h, default_idle() cleanup 2006-03-24 07:33:21 -08:00
termbits.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
termios.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
thread_info.h [PATCH] i386: fix singlestepping though a syscall 2006-02-17 08:55:21 -08:00
timer.h [PATCH] add suspend/resume for timer 2005-09-05 00:06:18 -07:00
timex.h [PATCH] x86: cpu_khz type fix 2005-06-23 09:45:11 -07:00
tlb.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
tlbflush.h [PATCH] seccomp: tsc disable 2005-06-27 15:11:44 -07:00
topology.h [PATCH] fix x86 topology export in sysfs for subarchitectures 2006-02-14 16:09:34 -08:00
types.h [PATCH] 2TB files: add blkcnt_t 2006-03-26 08:57:00 -08:00
uaccess.h [PATCH] i386: Add a temporary to make put_user more type safe 2006-03-23 07:38:04 -08:00
ucontext.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
unaligned.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
unistd.h [PATCH] x86: Make _syscallX() macros compile in PIC mode 2006-03-23 07:38:07 -08:00
user.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
vga.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
vic.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
vm86.h [PATCH] Make vm86 support optional 2006-01-08 20:14:11 -08:00
voyager.h Linux-2.6.12-rc2 2005-04-16 15:20:36 -07:00
xor.h [PATCH] i386: inline asm cleanup 2005-09-05 00:06:11 -07:00