Uprobes v3
Subsystems (9)
v3 cover Uprobes v3
intro.patch
From: Srikar Dronamraju <[email protected]>
Uprobes Patches
Changelog from v2:
- Addressed comments from Oleg, including removal of interrupt context handlers, reverting background page replacement in favour of access_process_vm().
- Provides perf interface for uprobes.
Changelog from v1:
- Added trace_event interface for uprobes.
- Addressed comments from Andrew Morton and Randy Dunlap.
For previous posting: please refer: http://lkml.org/lkml/2010/3/20/107
This patchset implements Uprobes which enables you to dynamically break into any routine in a user space application and collect information non-disruptively.
This patchset is a rework based on suggestions from discussions on lkml in January and March this year (http://lkml.org/lkml/2010/1/11/92,
http://lkml.org/lkml/2010/1/27/19, http://lkml.org/lkml/2010/3/20/107
and http://lkml.org/lkml/2010/3/31/199 ). This implementation of uprobes doesnt depend on utrace.
When a uprobe is registered, Uprobes makes a copy of the probed instruction, replaces the first byte(s) of the probed instruction with a breakpoint instruction. (Uprobes uses background page replacement mechanism and ensures that the breakpoint affects only that process.)
When a CPU hits the breakpoint instruction, Uprobes gets notified of trap and finds the associated uprobe. It then executes the associated handler. Uprobes single-steps its copy of the probed instruction and resumes execution of the probed process at the instruction following the probepoint. Instruction copies to be single-stepped are stored in a per-process "execution out of line (XOL) area". Currently XOL area is allocated as one page vma.
Advantages of uprobes over conventional debugging include:
1. Non-disruptive.
Unlike current ptrace based mechanisms, uprobes tracing wouldnt involve signals, stopping threads and context switching between the tracer and tracee.
2. Much better handling of multithreaded programs because of XOL. Current ptrace based mechanisms use single stepping inline, i.e they copy back the original instruction on hitting a breakpoint. In such mechanisms tracers have to stop all the threads on a breakpoint hit or tracers will not be able to handle all hits to the location of interest. Uprobes uses execution out of line, where the instruction to be traced is analysed at the time of breakpoint insertion and a copy of instruction is stored at a different location. On breakpoint hit, uprobes jumps to that copied location and singlesteps the same instruction and does the necessary fixups post singlestepping.
3. Multiple tracers for an application.
Multiple uprobes based tracer could work in unison to trace an application. There could one tracer that could be interested in generic events for a particular set of process. While there could be another tracer that is just interested in one specific event of a particular process thats part of the previous set of process.
4. Corelating events from kernels and userspace.
Uprobes could be used with other tools like kprobes, tracepoints or as part of higher level tools like perf to give a consolidated set of events from kernel and userspace. In future we could look at a single backtrace showing application, library and kernel calls.
Here is the list of TODO Items.
- Allowing probes across fork.
- Allowing probes per-executable/per dso.
- Allow multiple probes to share a probepoint.
- Return probes.
- Support for other architectures.
- Uprobes booster.
- Merge uprobes and kprobes trace_event.
- replace macro with bits in inat table.
The current patchset is based on 2.6.34-rc6.
Please do provide your valuable comments.
Thanks in advance.
Srikar
Srikar Dronamraju (10):
1. X86 instruction analysis: Move Macro W to insn.h 2. mm: Move replace_page() to mm/memory.c 3. mm: Enhance replace_page() to support pagecache 4. user_bkpt: User Space Breakpoint Assistance Layer 5. user_bkpt: X86 details for User space breakpoint assistance 6. user_bkpt: Slot allocation for Execution out of line 7. uprobes: Uprobes Implementation 8. uprobes: X86 details for Uprobes 9. uprobes: Uprobes Documentation patch
10. samples: Uprobes samples
11. trace: uprobes trace_event interface
12. perf: perf interface for uprobes.
Documentation/uprobes.txt | 236 +++++++++ arch/Kconfig | 30 ++ arch/x86/Kconfig | 2 + arch/x86/include/asm/insn.h | 7 + arch/x86/include/asm/thread_info.h | 2 + arch/x86/include/asm/user_bkpt.h | 43 ++ arch/x86/kernel/Makefile | 3 + arch/x86/kernel/kprobes.c | 7 - arch/x86/kernel/signal.c | 17 + arch/x86/kernel/uprobes.c | 77 +++ arch/x86/kernel/user_bkpt.c | 572 ++++++++++++++++++++++ fs/exec.c | 4 + include/linux/mm_types.h | 4 + include/linux/sched.h | 3 + include/linux/uprobes.h | 169 +++++++ include/linux/user_bkpt.h | 305 ++++++++++++ include/linux/user_bkpt_xol.h | 40 ++ kernel/Makefile | 3 + kernel/fork.c | 20 + kernel/trace/Kconfig | 8 + kernel/trace/Makefile | 1 + kernel/trace/trace.h | 12 + kernel/trace/trace_uprobe.c | 927 ++++++++++++++++++++++++++++++++++++ kernel/uprobes.c | 681 ++++++++++++++++++++++++++ kernel/user_bkpt.c | 536 +++++++++++++++++++++ kernel/user_bkpt_xol.c | 284 +++++++++++ samples/Kconfig | 7 + samples/Makefile | 2 +- samples/uprobes/Makefile | 17 + samples/uprobes/uprobe_example.c | 83 ++++ tools/perf/builtin-probe.c | 34 +- tools/perf/builtin-top.c | 20 - tools/perf/util/event.c | 20 + tools/perf/util/event.h | 1 + tools/perf/util/probe-event.c | 207 +++++++-- tools/perf/util/probe-event.h | 9 +- tools/perf/util/probe-finder.h | 1 + tools/perf/util/symbol.c | 6 +- 38 files changed, 4318 insertions(+), 82 deletions(-)
PATCH v3 1/10 X86 instruction analysis: Move Macro W to insn.h
move_W_to_insn.patch
From: Srikar Dronamraju <[email protected]>
Move Macro W to asm/insn.h
Macro W used to know if the instructions are valid for user-space/kernel space. This macro is used by kprobes and user_bkpt. (i.e user space breakpoint assistance layer.) So moving it to a common header file asm/insn.h.
TODO: replace macro W with bits in inat table. (suggested by Masami Hiramatsu)
---
arch/x86/include/asm/insn.h | 7 +++++++ arch/x86/kernel/kprobes.c | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/include/asm/insn.h +7 -0
@@ -23,6 +23,13 @@/* insn_attr_t is defined in inat.h */ #include <asm/inat.h> +#define W (row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\ + (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \ + (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) | \ + (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) | \ + (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf)) \ + << (row % 32)) + struct insn_field { union { insn_value_t value;
arch/x86/kernel/kprobes.c +0 -7
@@ -66,12 +66,6 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);#define stack_addr (regs) ((unsigned long *)kernel_stack_pointer(regs)) -#define W (row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\ - (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \ - (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) | \ - (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) | \ - (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf)) \ - << (row % 32))/* * Undefined/reserved opcodes, conditional jump, Opcode Extension * Groups, and some special opcodes can not boost.
@@ -98,7 +92,6 @@ static const u32 twobyte_is_boostable[256 / 32] = {/* ----------------------------------------------- */ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; -#undef Wstruct kretprobe_blackpoint kretprobe_blacklist[] = { {"__switch_to" , },/* This function switches only current task, but
PATCH v3 2/10 User Space Breakpoint Assistance Layer
In reply to Srikar Dronamrajuuser_bkpt_core.patch
From: Srikar Dronamraju <[email protected]>
User Space Breakpoint Assistance Layer (USER_BKPT) Changelog from v2: (addressing comments from Oleg)
* Use access_process_vm instead of replace_page based background page replacement.
Changelog from v1:
* Use k(un)map_atomic instead of k(un)map.
* Remove BUG_ON.
* Few parameter changes to be more consistent with sparse.
* Added kernel-doc comments whereever necessary.
* Introduce a check to detect if post_xol can sleep.
Currently there is no mechanism in kernel to insert/remove breakpoints.
This patch implements user space breakpoint assistance layer provides kernel subsystems with architecture independent interface to establish breakpoints in user applications. This patch provides core implementation of user_bkpt and also wrappers for architecture dependent methods.
USER_BKPT currently supports both single stepping inline and execution out of line strategies. Two different probepoints in the same process can have two different strategies. It handles pre-processing and post-processing of singlestep after a breakpoint hit.
Single stepping inline strategy is the traditional method where original instructions replace the breakpointed instructions on a breakpoint hit. This method works well with single threaded applications. However its racy with multithreaded applications.
Execution out of line strategy single steps on a copy of the instruction. This method works well for both single-threaded and multithreaded applications.
There could be other strategies like emulating an instruction. However they are currently not implemented.
Insertion and removal of breakpoints is by "Background page replacement". i.e make a copy of the page, modify its the contents, set the pagetable and flush the tlbs. This page uses enhanced replace_page to cow the page. Modified page is only reflected for the interested process. Others sharing the page will still see the old copy.
You need to follow this up with the USER_BKPT patch for your architecture.
Uprobes uses this facility to insert/remove breakpoint.
TODO: Merge user_bkpt layer with uprobes.
---
arch/Kconfig | 13 + include/linux/user_bkpt.h | 305 ++++++++++++++++++++++++++ kernel/Makefile | 1 kernel/user_bkpt.c | 536 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 855 insertions(+), 0 deletions(-) create mode 100644 include/linux/user_bkpt.h create mode 100644 kernel/user_bkpt.c
arch/Kconfig +13 -0
@@ -52,6 +52,16 @@ config OPTPROBES This option will allow kprobes to optimize breakpoint to a jump for reducing its overhead. +config USER_BKPT + bool "User-space breakpoint assistance (EXPERIMENTAL)" + depends on MODULES + depends on HAVE_USER_BKPT + help + User_bkpt (User-space breakpoint assistance layer) enables + kernel subsystems to establish breakpoints in user applications. + This service is used by components such as uprobes. + If in doubt, say "N". + config HAVE_EFFICIENT_UNALIGNED_ACCESS bool help
@@ -85,6 +95,9 @@ config USER_RETURN_NOTIFIER Provide a kernel-internal notification when a cpu is about to switch to user mode. +config HAVE_USER_BKPT + def_bool n + config HAVE_IOREMAP_PROT bool
include/linux/user_bkpt.h new file +305 -0
305 lines not on this page · raw message
kernel/Makefile +1 -0
@@ -105,6 +105,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o obj-$(CONFIG_PADATA) += padata.o +obj-$(CONFIG_USER_BKPT) += user_bkpt.o ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
kernel/user_bkpt.c new file +536 -0
536 lines not on this page · raw message
PATCH v3 3/10 x86 support for User space breakpoint assistance
In reply to Srikar Dronamrajux86_support_for_user_bkpt.patch
From: Srikar Dronamraju <[email protected]>
x86 support for user breakpoint Infrastructure
Changelog:
set USER_BKPT_FIX_SLEEPY if post_xol might sleep.
This patch provides x86 specific userspace breakpoint assistance implementation details. It uses the "x86: instruction decoder API" patch to do validate and analyze the instructions. This analysis is used at the time of post-processing of breakpoint hit to do the necessary fix-ups.
Almost all instructions are handled for traditional strategy and execution out of line strategy. Instruction handled include the RIP relative instructions.
This patch requires "x86: instruction decoder API" patch.
http://lkml.org/lkml/2009/6/1/459
---
arch/x86/Kconfig | 1 arch/x86/include/asm/user_bkpt.h | 43 +++ arch/x86/kernel/Makefile | 2 arch/x86/kernel/user_bkpt.c | 572 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 618 insertions(+), 0 deletions(-) create mode 100644 arch/x86/include/asm/user_bkpt.h create mode 100644 arch/x86/kernel/user_bkpt.c
arch/x86/Kconfig +1 -0
@@ -53,6 +53,7 @@ config X86 select HAVE_KERNEL_LZMA select HAVE_KERNEL_LZO select HAVE_HW_BREAKPOINT + select HAVE_USER_BKPT select PERF_EVENTS select ANON_INODES select HAVE_ARCH_KMEMCHECK
arch/x86/include/asm/user_bkpt.h new file +43 -0
43 lines not on this page · raw message
arch/x86/kernel/Makefile +2 -0
@@ -117,6 +117,8 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o +obj-$(CONFIG_USER_BKPT) += user_bkpt.o + ### # 64 bit specific files ifeq ($(CONFIG_X86_64),y)
arch/x86/kernel/user_bkpt.c new file +572 -0
572 lines not on this page · raw message
PATCH v3 4/10 Slot allocation for execution out of line (XOL)
In reply to Srikar Dronamrajuuser_bkpt_xol.patch
From: Srikar Dronamraju <[email protected]>
Changelog from v2: (addressing Oleg's comments)
* Removed code in !CONFIG_USER_BKPT_XOL
* Functions now pass pointer to user_bkpt_xol_area instead of pointer to void.
Slot allocation for Execution out of line strategy(XOL)
This patch provides slot allocation mechanism for execution out of line strategy for use with user space breakpoint infrastructure.
Traditional method of replacing the original instructions on breakpoint hit are racy when used on multithreaded applications.
Alternatives for the traditional method include:
- Emulating the breakpointed instruction.
- Execution out of line.
Emulating the instruction:
This approach would use a in-kernel instruction emulator to
emulate the breakpointed instruction. This approach could be looked in at a later point of time.
Execution out of line:
In execution out of line strategy, a new vma is injected into
the target process, a copy of the instructions which are breakpointed is stored in one of the slots. On breakpoint hit, the copy of the instruction is single-stepped leaving the breakpoint instruction as is. This method is architecture independent.
This method is useful while handling multithreaded processes.
This patch allocates one page per process for slots to be used to copy the breakpointed instructions.
Current slot allocation mechanism:
1. Allocate one dedicated slot per user breakpoint. Each slot is big enuf to accomodate the biggest instruction for that architecture. (16 bytes for x86).
2. We currently allocate only one page for slots. Hence the number of slots is limited to active breakpoint hits on that process.
3. Bitmap to track used slots.
---
arch/Kconfig | 4 + include/linux/user_bkpt_xol.h | 40 ++++++ kernel/Makefile | 1 kernel/user_bkpt_xol.c | 284 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 329 insertions(+), 0 deletions(-) create mode 100644 include/linux/user_bkpt_xol.h create mode 100644 kernel/user_bkpt_xol.c
arch/Kconfig +4 -0
@@ -98,6 +98,10 @@ config USER_RETURN_NOTIFIER config HAVE_USER_BKPT def_bool n +config USER_BKPT_XOL + def_bool y + depends on USER_BKPT + config HAVE_IOREMAP_PROT bool
include/linux/user_bkpt_xol.h new file +40 -0
@@ -0,0 +1,40 @@ +#ifndef _LINUX_XOL_H +#define _LINUX_XOL_H +/* +* User-space BreakPoint support (user_bkpt) -- Allocation of instruction +* slots for execution out of line (XOL) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* Copyright (C) IBM Corporation, 2009, 2010 +* Authors: +* Srikar Dronamraju +* Jim Keniston +*/ + +#define UINSNS_PER_PAGE (PAGE_SIZE/USER_BKPT_XOL_SLOT_BYTES) +#define MAX_USER_BKPT_XOL_SLOTS UINSNS_PER_PAGE +struct user_bkpt_xol_area ; + +extern unsigned long xol_get_insn_slot (struct user_bkpt *user_bkpt, +struct user_bkpt_xol_area *xol_area); +extern void xol_free_insn_slot (unsigned long , +struct user_bkpt_xol_area *xol_area); +extern int xol_validate_vaddr (struct pid *pid,unsigned long vaddr, +struct user_bkpt_xol_area *xol_area); +extern struct user_bkpt_xol_area *xol_alloc_area (void ); +extern void xol_free_area (struct user_bkpt_xol_area *xol_area); + +#endif /* _LINUX_XOL_H */
kernel/Makefile +1 -0
@@ -106,6 +106,7 @@ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o obj-$(CONFIG_PADATA) += padata.o obj-$(CONFIG_USER_BKPT) += user_bkpt.o +obj-$(CONFIG_USER_BKPT_XOL) += user_bkpt_xol.o ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
kernel/user_bkpt_xol.c new file +284 -0
284 lines not on this page · raw message
PATCH v3 5/10 Uprobes Implementation
In reply to Srikar Dronamrajuuprobes_core.patch
From: Srikar Dronamraju <[email protected]>
Uprobes Implementation
Changelog from v2:
- Introduce TIF_UPROBED flag.
- uprobes hooks now in fork/exec/exit paths instead of tracehooks.
- uprobe_process is now part of the mm struct and is shared between processes that share the mm.
- per thread information is now allocated on the fly.
* Hence allocation and freeing of this information is lockless.
- For now run the handler only in task context. The reasons for this change being:
* utask (per-task meta-data structure) is now allocated on the fly. Hence first request on the thread and first request for the breakpoint have to be anyway allocated in task context.
* Measurements showed task based handler had negligible overhead over interrupt based handlers.
* Feedback from Oleg and few others.
* Feedback at LFCS.
* Simplicity atleast till uprobes stabilizes.
( However we may introduce interrupt based handlers at a later time.) Here are sample overhead figures (in usec) for x86 architecture.
i686: Intel(R) Xeon(TM) CPU 2.40GHz
Without probe module.
100000 interations in 0.000650 sec i.e 0.006500 usec per iteration
With probes and handler run in interrupt context. 100000 interations in 0.340774 sec i.e 3.407740 usec per iteration probe overhead is 3.401240 usec per probe hit.
With probes and handler run in task context.
100000 interations in 0.365589 sec i.e 3.655890 usec per iteration probe overhead is 3.649390 usec per probe hit.
x86_64: Intel(R) Xeon(R) CPU X7350 @ 2.93GHz
Without probe module.
100000 interations in 0.000468 sec i.e 0.004680 usec per iteration
With probes and handler run in interrupt context. 100000 interations in 0.120369 sec i.e 1.203690 usec per iteration Probe overhead is 1.199010 usec per probe hit.
With probes and handler run in task context.
100000 interations in 0.130685 sec i.e 1.306850 usec per iteration Probe overhead is 1.302170 usec per probe hit.
- find_probept() takes the spinlock; unlike previously when it was expected that the spinlock was taken before calling it.
Changelog from v1:
- If fixup might sleep; then do the post singlestep processing in task context.
The uprobes infrastructure enables a user to dynamically establish probepoints in user applications and collect information by executing a handler function when a probepoint is hit.
The user specifies the virtual address and the pid of the process of interest along with the action to be performed (handler). The handle Uprobes is implemented on the user-space breakpoint assistance layer and uses the execution out of line strategy. Uprobes follows lazy slot allocation. I.e, on the first probe hit for that process, a new vma (to hold the probed instructions for execution out of line) is allocated. Once allocated, this vma remains for the life of the process, and is reused as needed for subsequent probes. A slot in the vma is allocated for a probepoint when it is first hit.
A slot is marked for reuse when the probe gets unregistered and no threads are using that slot.
In a multithreaded process, a probepoint once registered is active for all threads of a process. If a thread specific action for a probepoint is required then the handler should be implemented to do the same.
If a breakpoint already exists at a particular address (irrespective of who inserted the breakpoint including uprobes), uprobes will refuse to register any more probes at that address.
You need to follow this up with the uprobes patch for your architecture.
For more information: please refer to Documentation/uprobes.txt
TODO:
1. Perf/trace events interface for uprobes.
2. Allow multiple probes at a probepoint.
3. Booster probes.
4. Allow probes to be inherited across fork.
5. probing function returns.
---
arch/Kconfig | 13 + arch/x86/include/asm/thread_info.h | 2 arch/x86/kernel/signal.c | 5 fs/exec.c | 4 include/linux/mm_types.h | 4 include/linux/sched.h | 3 include/linux/uprobes.h | 169 +++++++++ kernel/Makefile | 1 kernel/fork.c | 20 + kernel/uprobes.c | 681 ++++++++++++++++++++++++++++++++++++ 10 files changed, 902 insertions(+), 0 deletions(-) create mode 100644 include/linux/uprobes.h create mode 100644 kernel/uprobes.c
arch/Kconfig +13 -0
@@ -62,6 +62,16 @@ config USER_BKPT This service is used by components such as uprobes. If in doubt, say "N". +config UPROBES + bool "User-space probes (EXPERIMENTAL)" + depends on MODULES && USER_BKPT_XOL + depends on HAVE_UPROBES + help + Uprobes enables kernel modules to establish probepoints + in user applications and execute handler functions when + the probepoints are hit. For more information, refer to + Documentation/uprobes.txt. If in doubt, say "N". + config HAVE_EFFICIENT_UNALIGNED_ACCESS bool help
@@ -113,6 +123,9 @@ config HAVE_KRETPROBES config HAVE_OPTPROBES bool + +config HAVE_UPROBES + def_bool n # # An arch should select this if it provides all these things: #
arch/x86/include/asm/thread_info.h +2 -0
@@ -84,6 +84,7 @@ struct thread_info {#define TIF_SECCOMP 8/* secure computing */ #define TIF_MCE_NOTIFY 10/* notify userspace of an MCE */ #define TIF_USER_RETURN_NOTIFY 11/* notify kernel of userspace return */ +#define TIF_UPROBE 12/* breakpointed or singlestepping */ #define TIF_NOTSC 16/* TSC is not accessible in userland */ #define TIF_IA32 17/* 32bit process */ #define TIF_FORK 18/* ret_from_fork */
@@ -108,6 +109,7 @@ struct thread_info {#define _TIF_SECCOMP (1 << TIF_SECCOMP)#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY) +#define _TIF_UPROBE (1 << TIF_UPROBE)#define _TIF_NOTSC (1 << TIF_NOTSC)#define _TIF_IA32 (1 << TIF_IA32)#define _TIF_FORK (1 << TIF_FORK)
arch/x86/kernel/signal.c +5 -0
@@ -848,6 +848,11 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)if (thread_info_flags & _TIF_SIGPENDING)do_signal (regs); +if (thread_info_flags & _TIF_UPROBE) { +clear_thread_flag (TIF_UPROBE ); +uprobe_notify_resume (regs); + } +if (thread_info_flags & _TIF_NOTIFY_RESUME) {clear_thread_flag (TIF_NOTIFY_RESUME );tracehook_notify_resume (regs);
fs/exec.c +4 -0
@@ -1048,6 +1048,10 @@ void setup_new_exec(struct linux_binprm * bprm)flush_signal_handlers (current,0 );flush_old_files (current->files); +#ifdef CONFIG_UPROBES +if (unlikely (current->utask)) +uprobe_free_utask (current); +#endif }EXPORT_SYMBOL (setup_new_exec);
include/linux/mm_types.h +4 -0
@@ -14,6 +14,7 @@#include <linux/page-debug-flags.h> #include <asm/page.h> #include <asm/mmu.h> +#include <linux/uprobes.h> #ifndef AT_VECTOR_SIZE_ARCH #define AT_VECTOR_SIZE_ARCH 0
@@ -310,6 +311,9 @@ struct mm_struct {#ifdef CONFIG_MMU_NOTIFIER struct mmu_notifier_mm *mmu_notifier_mm;#endif +#ifdef CONFIG_UPROBES +struct uprobe_process *uproc;/* per mm uprobes meta-data */ +#endif };/* Future-safe accessor for struct mm_struct's cpu_vm_mask. */
include/linux/sched.h +3 -0
@@ -1506,6 +1506,9 @@ struct task_struct { unsigned long memsw_bytes; /* uncharged mem+swap usage */ } memcg_batch;#endif +#ifdef CONFIG_UPROBES +struct uprobe_task *utask;/* per-thread uprobes meta-data */ +#endif };/* Future-safe accessor for struct task_struct's cpus_allowed. */
include/linux/uprobes.h new file +169 -0
169 lines not on this page · raw message
kernel/Makefile +1 -0
@@ -107,6 +107,7 @@ obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o obj-$(CONFIG_PADATA) += padata.o obj-$(CONFIG_USER_BKPT) += user_bkpt.o obj-$(CONFIG_USER_BKPT_XOL) += user_bkpt_xol.o +obj-$(CONFIG_UPROBES) += uprobes.o ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
kernel/fork.c +20 -0
@@ -173,6 +173,10 @@ void __put_task_struct(struct task_struct *tsk)exit_creds (tsk);delayacct_tsk_free (tsk); +#ifdef CONFIG_UPROBES +if (unlikely (tsk->utask)) +uprobe_free_utask (tsk); +#endif if (!profile_handoff_task (tsk))free_task (tsk);
@@ -509,6 +513,10 @@ void __mmdrop(struct mm_struct *mm)mm_free_pgd (mm);destroy_context (mm);mmu_notifier_mm_destroy (mm); +#ifdef CONFIG_UPROBES +if (unlikely (mm->uproc)) +uprobe_put_uprocess (mm); +#endif free_mm (mm); }EXPORT_SYMBOL_GPL (__mmdrop);
@@ -667,6 +675,9 @@ struct mm_struct *dup_mm(struct task_struct *tsk)if (mm->binfmt && !try_module_get (mm->binfmt->module)) goto free_pt; +#ifdef CONFIG_UPROBES + mm->uproc =NULL ; +#endif return mm; free_pt:
@@ -1183,6 +1194,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,INIT_LIST_HEAD (&p->pi_state_list); p->pi_state_cache =NULL ;#endif +#ifdef CONFIG_UPROBES + p->utask =NULL ; +#endif /* * sigaltstack should be cleared when sharing the same VM */
@@ -1281,6 +1295,12 @@ static struct task_struct *copy_process(unsigned long clone_flags,proc_fork_connector (p);cgroup_post_fork (p);perf_event_fork (p); +#ifdef CONFIG_UPROBES +if ((current->mm) && !(clone_flags &CLONE_VM )) { +if (unlikely (current->mm->uproc)) +uprobe_handle_fork (p); + } +#endif return p; bad_fork_free_pid:
kernel/uprobes.c new file +681 -0
681 lines not on this page · raw message
PATCH v3 6/10 x86 support for Uprobes
In reply to Srikar Dronamrajuuprobes_x86.patch
From: Srikar Dronamraju <[email protected]>
X86 support for Uprobes
This patch provides x86 specific details for uprobes. This includes interrupt notifier for uprobes, enabling/disabling singlestep.
---
arch/x86/Kconfig | 1 + arch/x86/kernel/Makefile | 1 + arch/x86/kernel/signal.c | 12 +++++++ arch/x86/kernel/uprobes.c | 77 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 0 deletions(-) create mode 100644 arch/x86/kernel/uprobes.c
arch/x86/Kconfig +1 -0
@@ -54,6 +54,7 @@ config X86 select HAVE_KERNEL_LZO select HAVE_HW_BREAKPOINT select HAVE_USER_BKPT + select HAVE_UPROBES select PERF_EVENTS select ANON_INODES select HAVE_ARCH_KMEMCHECK
arch/x86/kernel/Makefile +1 -0
@@ -118,6 +118,7 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o obj-$(CONFIG_USER_BKPT) += user_bkpt.o +obj-$(CONFIG_UPROBES) += uprobes.o ### # 64 bit specific files
arch/x86/kernel/signal.c +12 -0
@@ -850,7 +850,19 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)if (thread_info_flags & _TIF_UPROBE) {clear_thread_flag (TIF_UPROBE ); +#ifdef CONFIG_X86_32 +/* +* On x86_32, do_notify_resume() gets called with +* interrupts disabled. Hence enable interrupts if they +* are still disabled. +*/ +native_irq_enable (); +#endif uprobe_notify_resume (regs); + +#ifdef CONFIG_X86_32 +native_irq_disable (); +#endif }if (thread_info_flags & _TIF_NOTIFY_RESUME) {
arch/x86/kernel/uprobes.c new file +77 -0
77 lines not on this page · raw message
PATCH v3 7/10 samples: Uprobes samples
In reply to Srikar Dronamrajusamples.patch
From: Srikar Dronamraju <[email protected]>
Uprobes Samples
This provides an example uprobes module in the samples directory.
To run this module run (as root)
insmod uprobe_example.ko vaddr=<vaddr> pid=<pid>
Where <vaddr> is the address where we want to place the probe.
<pid> is the pid of the process we are interested to probe.
example: -
# cd samples/uprobes
[get the virtual address to place the probe.]
# vaddr=0x$(objdump -T /bin/bash |awk '/echo_builtin/ {print $1}')
[Run a bash shell in the background; have it echo 4 lines.] # (sleep 10; echo 1; echo 2; echo 3; echo 4) & [Probe calls echo_builtin() in the background bash process.]
# insmod uprobe_example.ko vaddr=$vaddr pid=$! # sleep 10 # rmmod uprobe_example # dmesg | tail -n 3 Registering uprobe on pid 10875, vaddr 0x45aa30 Unregistering uprobe on pid 10875, vaddr 0x45aa30 Probepoint was hit 4 times # [ Output shows that echo_builtin function was hit 4 times. ]
---
samples/Kconfig | 7 +++ samples/Makefile | 2 - samples/uprobes/Makefile | 17 ++++++++ samples/uprobes/uprobe_example.c | 83 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 1 deletions(-) create mode 100644 samples/uprobes/Makefile create mode 100644 samples/uprobes/uprobe_example.c
samples/Kconfig +7 -0
@@ -44,4 +44,11 @@ config SAMPLE_HW_BREAKPOINT help This builds kernel hardware breakpoint example modules. +config SAMPLE_UPROBES + tristate "Build uprobes example -- loadable module only" + depends on UPROBES && m + help + This builds uprobes example module. + + endif # SAMPLES
samples/Makefile +1 -1
@@ -1,4 +1,4 @@ # Makefile for Linux samples code obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ tracepoints/ trace_events/ \ - hw_breakpoint/ + hw_breakpoint/ uprobes/
samples/uprobes/Makefile new file +17 -0
@@ -0,0 +1,17 @@ +# builds the uprobes example kernel modules; +# then to use one (as root): +# insmod <module_name.ko> vaddr=<vaddr> pid=<pid> +# +# +# example: - +# vaddr=0x$(objdump -T /bin/bash |awk '/echo_builtin/ print $1}') +# (sleep 10; echo 1; echo 2; echo 3; echo 4) & +# insmod uprobe_example.ko vaddr=$vaddr pid=$! +# sleep 10 +# rmmod uprobe_example +# dmesg | tail -n 3 +# Registering uprobe on pid 3920, vaddr 0x45aa30 +# Unregistering uprobe on pid 3920, vaddr 0x45aa30 +# Probepoint was hit 4 times + +obj-$(CONFIG_SAMPLE_UPROBES) += uprobe_example.o
samples/uprobes/uprobe_example.c new file +83 -0
83 lines not on this page · raw message
PATCH v3 8/10 Uprobes documentation.
In reply to Srikar Dronamrajuuprobes-documentation.patch
From: Srikar Dronamraju <[email protected]>
Uprobes documentation.
---
Documentation/uprobes.txt | 236 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 236 insertions(+), 0 deletions(-) create mode 100644 Documentation/uprobes.txt
Documentation/uprobes.txt new file +236 -0
@@ -0,0 +1,236 @@ +Title : User-Space Probes (Uprobes) +Authors : Jim Keniston <[email protected]> + : Srikar Dronamraju <[email protected]> + +CONTENTS + +1. Concepts: Uprobes +2. Architectures Supported +3. Configuring Uprobes +4. API Reference +5. Uprobes Features and Limitations +6. Probe Overhead +7. TODO +8. Uprobes Team +9. Uprobes Example + +1. Concepts: Uprobes + +Uprobes enables you to dynamically break into any routine in a +user application and collect debugging and performance information +non-disruptively. You can trap at any code address, specifying a +kernel handler routine to be invoked when the breakpoint is hit. + +A uprobe can be inserted on any instruction in the application's +virtual address space. The registration function register_uprobe() +specifies which process is to be probed, where the probe is to be +inserted, and what handler is to be called when the probe is hit. + +Uprobes-based instrumentation can be packaged as a kernel +module. In the simplest case, the module's init function installs +("registers") one or more probes, and the exit function unregisters +them. + +1.1 How Does a Uprobe Work? + +When a uprobe is registered, Uprobes makes a copy of the probed +instruction, stops the probed application, replaces the first byte(s) +of the probed instruction with a breakpoint instruction (e.g., int3 +on i386 and x86_64), and allows the probed application to continue. +(When inserting the breakpoint, Uprobes uses background page +replacement mechanism, so that the breakpoint affects only that +process, and not any other process running that program. This is +true even if the probed instruction is in a shared library.) + +When a CPU hits the breakpoint instruction, a trap occurs, the CPU's +user-mode registers are saved, and uprobes notifier code finds the +associated uprobe. It then executes the handler associated with the +uprobe, passing the handler the addresses of the uprobe struct and the +saved registers. The handler can run either in interrupt context or in +task context; this is specified by the user at the time of registration. +When run in task context, the handler may block, but keep in mind that +the probed thread remains stopped while your handler runs. + +Next, Uprobes single-steps its copy of the probed instruction and +resumes execution of the probed process at the instruction following +the probepoint. (It would be simpler to single-step the actual +instruction in place, but then Uprobes would have to temporarily +remove the breakpoint instruction. This would create problems in a +multithreaded application. For example, it would open a time window +when another thread could sail right past the probepoint.) + +Instruction copies to be single-stepped are stored in a per-process +"execution out of line (XOL) area," which is a little VM area +created by Uprobes in each probed process's address space. + +Uprobes handles interesting events in the lifetime of the probed +process, such as fork, clone, exec, and exit. + +1.2 Multithreaded Applications + +Uprobes supports the probing of multithreaded applications. Uprobes +imposes no limit on the number of threads in a probed application. +All threads in a process use the same text pages, so every probe +in a process affects all threads; of course, each thread hits the +probepoint (and runs the handler) independently. Multiple threads +may run the same handler simultaneously. If you want a particular +thread or set of threads to run a particular handler, your handler +should check current or current->pid to determine which thread has +hit the probepoint. + +When a process clones a new thread, that thread automatically shares +all current and future probes established for that process. + +2. Architectures Supported + +This user_bkpt based version of Uprobes is implemented on the following +architectures: + +- x86 + +3. Configuring Uprobes + +When configuring the kernel using make menuconfig/xconfig/oldconfig, +ensure that CONFIG_UPROBES is set to "y". Under "General setup" select +"User-space breakpoint assistance" then select "User-space probes". + +So that you can load and unload Uprobes-based instrumentation modules, +make sure "Loadable module support" (CONFIG_MODULES) and "Module +unloading" (CONFIG_MODULE_UNLOAD) are set to "y". + +4. API Reference + +The Uprobes API includes a "register" function and an "unregister" +function for uprobes. Here are terse, mini-man-page specifications for +these functions and the associated probe handlers that you'll write. +See the latter half of this document for examples. + +4.1 register_uprobe + +#include <linux/uprobes.h> +int register_uprobe(struct uprobe *u); + +Sets a breakpoint at virtual address u->vaddr in the process whose +pid is u->pid. When the breakpoint is hit, Uprobes calls u->handler. +If u->handler_in_interrupt is set, the handler runs in interrupt +context. Otherwise it runs in task context. + +register_uprobe() returns 0 on success, or a negative errno +otherwise. + +User's handler (u->handler): +#include <linux/uprobes.h> +#include <linux/ptrace.h> +void handler(struct uprobe *u, struct pt_regs *regs); + +Called with u pointing to the uprobe associated with the breakpoint, +and regs pointing to the struct containing the registers saved when +the breakpoint was hit. + +4.2 unregister_uprobe + +#include <linux/uprobes.h> +void unregister_uprobe(struct uprobe *u); + +Removes the specified probe. The unregister function can be called +at any time after the probe has been registered, and can be called +from a uprobe handler. + +5. Uprobes Features and Limitations + +The user is expected to assign values to the following members +of struct uprobe: pid, vaddr, handler, and handler_in_interrupt. +Uprobes may produce unexpected results if you: +- change the contents of a uprobe object while it is registered; or +- attempt to register a uprobe that is already registered. + +In this implementation, Uprobes allows only one uprobe at a particular +address. + +Any number of kernel modules may probe a particular process +simultaneously, and a particular module may probe any number of +processes simultaneously. + +Probes are shared by all threads in a process (including newly +created threads). + +If a probed process exits or execs, Uprobes automatically +unregisters all uprobes associated with that process. Subsequent +attempts to unregister these probes will be treated as no-ops. + +On the other hand, if a probed memory area is removed from the +process's virtual memory map (e.g., via dlclose(3) or munmap(2)), +it's currently up to you to unregister the probes first. + +There is no way to specify that probes should be inherited across fork; +Uprobes removes all probepoints in the newly created child process. + +To avoid interfering with interactive debuggers, Uprobes will refuse +to insert a probepoint where a breakpoint instruction already exists. +Some architectures may refuse to insert probes on other types of +instructions. + +If you install a probe in an inline-able function, Uprobes makes +no attempt to chase down all inline instances of the function and +install probes there. gcc may inline a function without being asked, +so keep this in mind if you're not seeing the probe hits you expect. + +A probe handler can modify the environment of the probed function +-- e.g., by modifying data structures, or by modifying the +contents of the pt_regs struct (which are restored to the registers +upon return from the breakpoint). So Uprobes can be used, for example, +to install a bug fix or to inject faults for testing. Uprobes, of +course, has no way to distinguish the deliberately injected faults +from the accidental ones. Don't drink and probe. + +When Uprobes establishes a probepoint on a previous unprobed page +of text, Linux creates a new copy of the page via its copy-on-write +mechanism. When probepoints are removed, Uprobes makes no attempt +to consolidate identical copies of the same page. This could affect +memory availability if you probe many, many pages in many, many +long-running processes. + +6. Probe Overhead + +Probe overhead is measured on a benchmark that hits the same probepoint +repeatedly, firing a simple handler each time. Probe overhead +changes with different cpus/archs/probe handlers and the number of +iterations. + +Here are sample overhead figures (in usec) for x86 architecture. + +i686: Intel(R) Xeon(TM) CPU 2.40GHz +Without probe module. +100000 interations in 0.000650 sec i.e 0.006500 usec per iteration + +With probes +100000 interations in 0.365589 sec i.e 3.655890 usec per iteration +probe overhead is 3.649390 usec per probe hit. + +x86_64: Intel(R) Xeon(R) CPU X7350 @ 2.93GHz +Without probe module. +100000 interations in 0.000468 sec i.e 0.004680 usec per iteration + +With probes +100000 interations in 0.130685 sec i.e 1.306850 usec per iteration +Probe overhead is 1.302170 usec per probe hit. + +7. TODO + +a. Support for other architectures. +b. Support for multiple probes at the same address. +c. Support for boosted probes. +d. Support return probes. + +8. Uprobes Team + +The following people have made major contributions to Uprobes: +Jim Keniston - [email protected] +Srikar Dronamraju - [email protected] +Ananth Mavinakayanahalli - [email protected] +Prasanna Panchamukhi - [email protected] +Dave Wilder - [email protected] + +9. Uprobes Example + +samples/uprobes/uprobe_example.c
PATCH v3 9/10 trace: uprobes trace_event interface
In reply to Srikar Dronamrajuuprobes_trace_events.patch
From: Srikar Dronamraju <[email protected]>
The following patch implements trace_event support for uprobes. In its current form it can be used to put probes at a specified text address in a process and dump the required registers when the code flow reaches the probed address.
This is based on trace_events for kprobes to the extent that it may resemble that file on 2.6.34-rc3.
The following example shows how to dump the instruction pointer and %ax a register at the probed text address.
Start a process to trace. Get the address to trace.
[Here pid is asssumed as 3548]
[Address to trace is 0x0000000000446420] [Registers to be dumped are %ip and %ax]
# cd /sys/kernel/debug/tracing/
# echo 'p 3548:0x0000000000446420 %ip %ax' > uprobe_events
# cat uprobe_events
p:uprobes/p_3548_0x0000000000446420 3548:0x0000000000446420 %ip=%ip %ax=%ax
# cat events/uprobes/p_3548_0x0000000000446420/enable
0
[enable the event]
# echo 1 > events/uprobes/p_3548_0x0000000000446420/enable
# cat events/uprobes/p_3548_0x0000000000446420/enable
1
# #### do some activity on the program so that it hits the breakpoint
# cat uprobe_profile
3548 p_3548_0x0000000000446420 234
# tracer: nop
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
<...>-3548 [001] 294.285812: p_3548_0x0000000000446420: (0x446420) %ip=446421 %ax=1
<...>-3548 [001] 294.285884: p_3548_0x0000000000446420: (0x446420) %ip=446421 %ax=1
<...>-3548 [001] 294.285894: p_3548_0x0000000000446420: (0x446420) %ip=446421 %ax=1
<...>-3548 [001] 294.285903: p_3548_0x0000000000446420: (0x446420) %ip=446421 %ax=1
<...>-3548 [001] 294.285912: p_3548_0x0000000000446420: (0x446420) %ip=446421 %ax=1
<...>-3548 [001] 294.285922: p_3548_0x0000000000446420: (0x446420) %ip=446421 %ax=1TODO: Documentation/trace/uprobetrace.txt
---
kernel/trace/Kconfig | 8 kernel/trace/Makefile | 1 kernel/trace/trace.h | 12 + kernel/trace/trace_uprobe.c | 927 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 948 insertions(+), 0 deletions(-) create mode 100644 kernel/trace/trace_uprobe.c
kernel/trace/Kconfig +8 -0
@@ -557,6 +557,14 @@ config RING_BUFFER_BENCHMARK If unsure, say N. +config UPROBE_EVENT + depends on UPROBES + bool "Enable uprobes-based dynamic events" + select TRACING + default y + help + This allows the user to add tracing events (similar to tracepoints) + on the fly via the traceevents interface. endif # FTRACE endif # TRACING_SUPPORT
kernel/trace/Makefile +1 -0
@@ -58,5 +58,6 @@ obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o obj-$(CONFIG_KSYM_TRACER) += trace_ksym.o obj-$(CONFIG_EVENT_TRACING) += power-traces.o +obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o libftrace-y := ftrace.o
kernel/trace/trace.h +12 -0
@@ -126,6 +126,18 @@ struct kretprobe_trace_entry { (offsetof(struct kretprobe_trace_entry , args) + \ (sizeof(unsigned long) * (n))) +struct uprobe_trace_entry { +struct trace_entry ent; +pid_t pid; +unsigned long ip; +int nargs; +unsigned long args[]; +}; + +#define SIZEOF_UPROBE_TRACE_ENTRY (n) \ + (offsetof(struct uprobe_trace_entry, args) + \ + (sizeof(unsigned long) * (n))) +/* * trace_flag_type is an enumeration that holds different * states when a trace occurs. These are:
kernel/trace/trace_uprobe.c new file +927 -0
927 lines not on this page · raw message
PATCH v3 10/10 perf: perf interface for uprobes.
In reply to Srikar Dronamrajuperf-events.patch
From: Srikar Dronamraju <[email protected]>
This patch enhances perf probe to accept pid and user vaddr. This patch provides very basic support for uprobes.
TODO:
Update perf-probes.txt.
Global tracing.
Here is a terminal snapshot of placing, using and removing a probe on a process with pid 3329 (corresponding to zsh)
[ Probing a function in the executable using function name ]
-------------------------------------------------------------
[root@ABCD]# perf probe -p 3329 zfree@zsh Added new event: probe:p_3329_zfree (on 0x446420)
You can now use it on all perf tools, such as:
perf record -e probe:p_3329_zfree -a sleep 1
[root@ABCD]# perf probe --list probe:p_3329_zfree (on 3329:0x0000000000446420) [root@ABCD]# cat /sys/kernel/debug/tracing/uprobe_events p:probe/p_3329_zfree 3329:0x0000000000446420 [root@ABCD]# perf record -f -e probe:p_3329_zfree -a sleep 10 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.039 MB perf.data (~1716 samples) ] [root@ABCD]# perf probe -p 3329 --del probe:p_3329_zfree Remove event: probe:p_3329_zfree [root@ABCD]# perf report # Samples: 447 # # Overhead Command Shared Object Symbol # ........ ............... ............. ...... # 100.00% zsh zsh [.] zfree
#
# (For a higher level overview, try: perf report --sort comm,dso) #
[ Probing a function + offset ]
-------------------------------
[root@ABCD]# perf probe -p 3329 zfree@zsh+5 Added new event: probe:p_3329_zfree (on 0x446425)
You can now use it on all perf tools, such as:
perf record -e probe:p_3329_zfree -a sleep 1
[root@ABCD]# perf probe --list probe:p_3329_zfree (on 3329:0x0000000000446425) [root@ABCD]# cat /sys/kernel/debug/tracing/uprobe_events p:probe/p_3329_zfree 3329:0x0000000000446425 [root@ABCD]# perf record -f -e probe:p_3329_zfree -a sleep 10 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.036 MB perf.data (~1590 samples) ] [root@ABCD]# perf probe -p 3329 --del probe:p_3329_zfree Remove event: probe:p_3329_zfree [root@ABCD]# perf report # Samples: 18 # # Overhead Command Shared Object Symbol # ........ ............... ............. ...... # 100.00% zsh zsh [.] zfree
#
# (For a higher level overview, try: perf report --sort comm,dso) #
[ Probing a library function using function name ]
--------------------------------------------------
[root@ABCD]# perf probe -p 3329 [email protected] Added new event: probe:p_3329_write (on 0x36010c6060)
You can now use it on all perf tools, such as:
perf record -e probe:p_3329_write -a sleep 1
[root@ABCD]# perf probe --list probe:p_3329_write (on 3329:0x00000036010c6060) [root@ABCD]# cat /sys/kernel/debug/tracing/uprobe_events p:probe/p_3329_write 3329:0x00000036010c6060 [root@ABCD]# perf record -f -e probe:p_3329_write -a sleep 10 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.040 MB perf.data (~1738 samples) ] [root@ABCD]# perf probe -p 3329 --del probe:p_3329_write Remove event: probe:p_3329_write [root@ABCD]# perf report # Samples: 11 # # Overhead Command Shared Object Symbol # ........ ............... .................. ...... # 100.00% zsh libc-2.5.so [.] __GI___libc_write
#
# (For a higher level overview, try: perf report --sort comm,dso) #
Adding a probe for a process
[ Probing using vaddr 0x0000000000446420 (corresponding to zfree)]
-------------------------------------------------------------------
[root@ABCD]# perf probe -p 3329 0x0000000000446420 Added new event: probe:p_3329_0x0000000000446420 (on 0x0000000000446420)
You can now use it on all perf tools, such as:
perf record -e probe:p_3329_0x0000000000446420 -a sleep 1
[root@ABCD]# perf record -e probe:p_3329_0x0000000000446420 -a sleep 10 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.041 MB perf.data (~1797 samples) ] [root@ABCD]# perf report # # Samples: 628 # # Overhead Command Shared Object Symbol # ........ ............... ............. ...... # 100.00% zsh zsh [.] zfree
#
# (For a higher level overview, try: perf report --sort comm,dso) #
[root@ABCD]# perf report --sort comm,dso # Samples: 628 # # Overhead Command Shared Object # ........ ............... ............. # 100.00% zsh zsh
[root@ABCD]# perf probe --list probe:p_3329_0x0000000000446420 (on 3329:0x0000000000446420) [root@ABCD]# perf list | grep probe probe:p_3329_0x0000000000446420 [Tracepoint event] [root@ABCD]# perf probe -p 3329 --del probe:p_3329_0x0000000000446420 Remove event: probe:p_3329_0x0000000000446420 [root@ABCD]#
Another example for a shared library: write stub in libc. (corresponds to 0x00000036010c6060)
on a vaddr
[ Probing a libc vaddr 0x00000036010c6060 (corresponding to write) ]
[root@ABCD]# perf probe -p 3329 0x00000036010c6060 dded new event: probe:p_3329_0x00000036010c6060 (on 0x00000036010c6060)
You can now use it on all perf tools, such as:
perf record -e probe:p_3329_0x00000036010c6060 -a sleep 1
[root@ABCD]# perf record -f -e probe:p_3329_0x00000036010c6060 -a sleep 10 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.040 MB perf.data (~1748 samples) ] [root@ABCD]# perf report # Samples: 24 # # Overhead Command Shared Object Symbol # ........ ............... .................. ...... # 100.00% zsh libc-2.5.so [.] __GI___libc_write
#
# (For a higher level overview, try: perf report --sort comm,dso) #
[root@ABCD]#
---
tools/perf/builtin-probe.c | 34 +++++-- tools/perf/builtin-top.c | 20 ---- tools/perf/util/event.c | 20 ++++ tools/perf/util/event.h | 1 tools/perf/util/probe-event.c | 207 ++++++++++++++++++++++++++++++++-------- tools/perf/util/probe-event.h | 9 +- tools/perf/util/probe-finder.h | 1 tools/perf/util/symbol.c | 6 + 8 files changed, 224 insertions(+), 74 deletions(-)
tools/perf/builtin-probe.c +24 -10
@@ -55,6 +55,7 @@ static struct {bool force_add;bool show_lines;int nr_probe; +pid_t pid;struct probe_point probes[MAX_PROBES ];struct strlist *dellist;struct map_groups kmap_groups;
@@ -73,7 +74,7 @@ static void parse_probe_event(const char *str)die ("Too many probes (> %d) are specified." ,MAX_PROBES );/* Parse perf-probe event into probe_point */ -parse_perf_probe_event (str, pp, &session.need_dwarf); +parse_perf_probe_event (str, pp, &session.need_dwarf, session.pid);pr_debug ("%d arguments\n" , pp->nr_args); }
@@ -203,6 +204,8 @@ static const struct option options[] = { "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", "Show source code lines.", opt_show_lines),#endif +OPT_INTEGER ('p' ,"pid" , &session.pid, +"specify a pid for a uprobes based probe" ), OPT_END() };
@@ -263,7 +266,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) }#ifndef NO_DWARF_SUPPORT -if (session.show_lines) { +if (session.show_lines && !session.pid) {if (session.nr_probe !=0 || session.dellist) {pr_warning (" Error: Don't use --line with" " --add/--del.\n" );
@@ -283,12 +286,19 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)#endif if (session.dellist) { -del_trace_kprobe_events (session.dellist); +if (session.pid) +del_trace_uprobe_events (session.dellist); +else +del_trace_kprobe_events (session.dellist); +strlist__delete (session.dellist);if (session.nr_probe ==0 )return 0 ; } +if (session.pid) + goto end_dwarf; +/* Add probes */ init_vmlinux ();
@@ -334,18 +344,19 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) break; }close (fd); - -end_dwarf:#endif /* !NO_DWARF_SUPPORT */ +end_dwarf:/* Synthesize probes without dwarf */ for (i =0 ; i < session.nr_probe; i++) { pp = &session.probes[i];if (pp->found)/* This probe is already found. */ continue ; -evaluate_probe_point (pp); - ret =synthesize_trace_kprobe_event (pp); +if (!session.pid) +evaluate_probe_point (pp); + + ret =synthesize_trace_probe_event (pp);if (ret == -E2BIG )die ("probe point definition becomes too long." );else if (ret <0 )
@@ -353,8 +364,11 @@ end_dwarf: }/* Settng up probe points */ -add_trace_kprobe_events (session.probes, session.nr_probe, - session.force_add); +if (session.pid) +add_trace_uprobe_events (session.probes, session.nr_probe, + session.force_add, session.pid); +else +add_trace_kprobe_events (session.probes, session.nr_probe, + session.force_add);return 0 ; } -
tools/perf/builtin-top.c +0 -20
@@ -1005,26 +1005,6 @@ static void event__process_sample(const event_t *self, } } -static int event__process (event_t *event,struct perf_session *session) -{ -switch (event->header.type) { -case PERF_RECORD_COMM : -event__process_comm (event, session); -break ; -case PERF_RECORD_MMAP : -event__process_mmap (event, session); -break ; -case PERF_RECORD_FORK : -case PERF_RECORD_EXIT : -event__process_task (event, session); -break ; -default : -break ; - } - -return 0 ; -} -struct mmap_data {int counter;void *base;
tools/perf/util/event.c +20 -0
@@ -432,6 +432,26 @@ int event__process_task(event_t *self, struct perf_session *session)return 0 ; } +int event__process (event_t *event,struct perf_session *session) +{ +switch (event->header.type) { +case PERF_RECORD_COMM : +event__process_comm (event, session); +break ; +case PERF_RECORD_MMAP : +event__process_mmap (event, session); +break ; +case PERF_RECORD_FORK : +case PERF_RECORD_EXIT : +event__process_task (event, session); +break ; +default : +break ; + } + +return 0 ; +} + void thread__find_addr_map(struct thread *self, struct perf_session *session, u8 cpumode, enum map_type type, u64 addr,
tools/perf/util/event.h +1 -0
@@ -128,6 +128,7 @@ int event__process_comm(event_t *self, struct perf_session *session);int event__process_lost (event_t *self,struct perf_session *session);int event__process_mmap (event_t *self,struct perf_session *session);int event__process_task (event_t *self,struct perf_session *session); +int event__process (event_t *event,struct perf_session *session);struct addr_location ; int event__preprocess_sample(const event_t *self, struct perf_session *session,
tools/perf/util/probe-event.c +168 -39
409 lines not on this page · raw message
tools/perf/util/probe-event.h +6 -3
@@ -7,14 +7,17 @@extern void parse_line_range_desc (const char *arg,struct line_range *lr);extern void parse_perf_probe_event (const char *str,struct probe_point *pp, -bool *need_dwarf); +bool *need_dwarf,pid_t pid);extern int synthesize_perf_probe_point (struct probe_point *pp);extern int synthesize_perf_probe_event (struct probe_point *pp); -extern void parse_trace_kprobe_event (const char *str,struct probe_point *pp); -extern int synthesize_trace_kprobe_event (struct probe_point *pp); +extern int synthesize_trace_probe_event (struct probe_point *pp); +extern void parse_trace_probe_event (const char *str,struct probe_point *pp);extern void add_trace_kprobe_events (struct probe_point *probes,int nr_probes,bool force_add);extern void del_trace_kprobe_events (struct strlist *dellist); +extern void add_trace_uprobe_events (struct probe_point *probes,int nr_probes, +bool force_add,pid_t pid); +extern void del_trace_uprobe_events (struct strlist *dellist);extern void show_perf_probe_events (void );extern void show_line_range (struct line_range *lr);
tools/perf/util/probe-finder.h +1 -0
@@ -33,6 +33,7 @@ struct probe_point {/* Output */ int found;/* Number of found probe points */ +pid_t upid;/* uprobes only */ char *probes[MAX_PROBES ];/* Output buffers (will be allocated)*/ };
tools/perf/util/symbol.c +4 -2
@@ -958,12 +958,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, nr_syms = shdr.sh_size / shdr.sh_entsize;memset (&sym,0 ,sizeof (sym)); -if (!self->kernel) { +if (self->kernel || symbol_conf.sort_by_name) + self->adjust_symbols =0 ; +else { self->adjust_symbols = (ehdr.e_type ==ET_EXEC ||elf_section_by_name (elf, &ehdr, &shdr,".gnu.prelink_undo" ,NULL ) !=NULL ); - }else self->adjust_symbols =0 ; + }elf_symtab__for_each_symbol (syms, nr_syms, idx, sym) {struct symbol *f;
Re: [PATCH v3 10/10] perf: perf interface for uprobes.
Quoted 6 lines · Srikar Dronamraju
perf-events.patch
From: Srikar Dronamraju <[email protected]>
This patch enhances perf probe to accept pid and user vaddr. This patch provides very basic support for uprobes.
Good work! Thank you!
Quoted 3 lines
TODO:
Update perf-probes.txt.
Global tracing.
Could you also rebase your patch on the latest tip tree? :) (and remove die() too)
Quoted 6 lines
Here is a terminal snapshot of placing, using and removing a probe on a process with pid 3329 (corresponding to zsh)
[ Probing a function in the executable using function name ]
-------------------------------------------------------------[root@ABCD]# perf probe -p 3329 zfree@zsh
Hmm, I'm not sure why we have to specify both of PID and exec name. Is that possible to give a symbol as below? (omit exec name)
# perf probe -p 3329 zfree
Quoted 2 lines
Added new event:
probe:p_3329_zfree (on0x446420)
Hmm, the event name should be simpler, as like as zfree_3329. or, we might better make a new event group for each process, as like as 'probe_3329:zfree'
Quoted 21 lines
You can now use it on all perf tools, such as:
perf record -e probe:p_3329_zfree -a sleep 1
[root@ABCD]# perf probe --list probe:p_3329_zfree (on 3329:0x0000000000446420) [root@ABCD]# cat /sys/kernel/debug/tracing/uprobe_events p:probe/p_3329_zfree 3329:0x0000000000446420 [root@ABCD]# perf record -f -e probe:p_3329_zfree -a sleep 10 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.039 MB perf.data (~1716 samples) ] [root@ABCD]# perf probe -p 3329 --del probe:p_3329_zfree Remove event: probe:p_3329_zfree [root@ABCD]# perf report # Samples: 447 # # Overhead Command Shared Object Symbol # ........ ............... ............. ...... # 100.00% zsh zsh [.] zfree
Quoted 6 lines
#
# (For a higher level overview, try: perf report --sort comm,dso) #[ Probing a function + offset ]
-------------------------------
Looks great! :D
[...]
Quoted 4 lines
Signed-off-by Srikar Dronamraju <[email protected]>---
Quoted 9 lines
tools/perf/builtin-probe.c | 34 +++++-- tools/perf/builtin-top.c | 20 ---- tools/perf/util/event.c | 20 ++++ tools/perf/util/event.h | 1 tools/perf/util/probe-event.c | 207 ++++++++++++++++++++++++++++++++-------- tools/perf/util/probe-event.h | 9 +- tools/perf/util/probe-finder.h | 1 tools/perf/util/symbol.c | 6 + 8 files changed, 224 insertions(+), 74 deletions(-)
Some comments on the patch.
[...]
Quoted 32 lines
tools/perf/builtin-probe.c +4
-1@@ -55,6 +55,7 @@ static struct {bool force_add;bool show_lines;int nr_probe; +pid_t pid;struct probe_point probes[MAX_PROBES ];struct strlist *dellist;struct map_groups kmap_groups;@@ -73,7 +74,7 @@ static void parse_probe_event(const char *str)die ("Too many probes (> %d) are specified." ,MAX_PROBES );/* Parse perf-probe event into probe_point */ -parse_perf_probe_event (str, pp, &session.need_dwarf); +parse_perf_probe_event (str, pp, &session.need_dwarf, session.pid);pr_debug ("%d arguments\n" , pp->nr_args); }@@ -203,6 +204,8 @@ static const struct option options[] = { "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", "Show source code lines.", opt_show_lines),#endif +OPT_INTEGER ('p' ,"pid" , &session.pid, +"specify a pid for a uprobes based probe" ), OPT_END() };
tools/perf/builtin-probe.c int cmd_probe(int argc, const char **argv, const char *prefix __used) · line 272
Quoted 8 lines
tools/perf/builtin-probe.c +1
-1@@ -263,7 +266,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) }#ifndef NO_DWARF_SUPPORT -if (session.show_lines) { +if (session.show_lines && !session.pid) {if (session.nr_probe !=0 || session.dellist) {pr_warning (" Error: Don't use --line with" " --add/--del.\n" );
Hmm, if user gave --list with -p, what happened?
We need to check a bad combination and warn it.
Quoted 8 lines
tools/perf/builtin-probe.c +3
-1@@ -283,12 +286,19 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)#endif if (session.dellist) { -del_trace_kprobe_events (session.dellist); +if (session.pid) +del_trace_uprobe_events (session.dellist); +else
tools/perf/builtin-probe.c int cmd_probe(int argc, const char **argv, const char *prefix __used) · line 301
Quoted 10 lines
tools/perf/builtin-probe.c +5
-0+del_trace_kprobe_events (session.dellist); +strlist__delete (session.dellist);if (session.nr_probe ==0 )return 0 ; } +if (session.pid) + goto end_dwarf; +
Again, it must be checked that the combination of -p option and dwarf requirement. The latest code has perf_probe_event_need_dwarf(), so you can check it easier.
[...]
Quoted 51 lines
tools/perf/builtin-probe.c +47
-0@@ -112,6 +113,64 @@ static bool check_event_name(const char *name)return true; } +/* +* uprobe_events only accepts address: +* Convert function and any offset to address +*/ +static void convert_name_to_addr (struct probe_point *pp) +{ +struct perf_session *session; +struct thread *thread; +struct symbol *sym; +struct map *map; +char *name = pp->file; +unsigned long long vaddr; + +/* check if user has specifed a virtual address */ + vaddr =strtoul (pp->function,NULL ,0 ); +if (vaddr) +return ; + + session =perf_session__new (NULL ,O_WRONLY , false); +DIE_IF (session ==NULL ); + symbol_conf.sort_by_name = true; + symbol_conf.try_vmlinux_path = false; +if (symbol__init () <0 ) +semantic_error ("Cannot initialize symbols." ); + +event__synthesize_thread (pp->upid, event__process, session); + + thread =perf_session__findnew (session, pp->upid); +DIE_IF (thread ==NULL ); + +if (!name) +/* Lets find the function in the executable. */ + name = thread->comm; +DIE_IF (name ==NULL ); + + map =map_groups__find_by_name (&thread->mg,MAP__FUNCTION , name); +if (!map) +semantic_error ("Cannot find appropriate DSO." ); + + sym =map__find_symbol_by_name (map, pp->function,NULL ); +if (!sym) +semantic_error ("Cannot find appropriate Symbol." ); + +if (map->start > sym->start) + vaddr = map->start; + vaddr += sym->start + pp->offset + map->pgoff; + pp->offset =0 ;
tools/perf/builtin-probe.c static bool check_event_name(const char *name) · line 172
Quoted 10 lines
tools/perf/builtin-probe.c +10
-0+ +if (!pp->event) + pp->event = pp->function; +else +free (pp->function); + pp->function =zalloc (sizeof (char *) *20 ); +if (!pp->function) +die ("Failed to allocate memory by zalloc." ); +e_snprintf (pp->function,20 ,"0x%llx" , vaddr); +}
Well, after rebasing, you'll need to remove die()s from here and make it returns errors.
[...]
tools/perf/builtin-probe.c int synthesize_trace_kprobe_event(struct probe_point *pp) · line 460
Quoted 13 lines
tools/perf/builtin-probe.c +5
-1@@ -383,7 +450,11 @@ int synthesize_trace_kprobe_event(struct probe_point *pp) pp->probes[0 ] = buf =zalloc (MAX_CMDLEN );if (!buf)die ("Failed to allocate memory by zalloc." ); - ret =e_snprintf (buf,MAX_CMDLEN ,"%s+%d" , pp->function, pp->offset); +if (pp->offset) + ret =e_snprintf (buf,MAX_CMDLEN ,"%s+%d" , pp->function, + pp->offset); +else + ret =e_snprintf (buf,MAX_CMDLEN ,"%s" , pp->function);if (ret <=0 ) goto error; len = ret;
Isn't it a cleanup ?
[...]
Quoted 55 lines
tools/perf/builtin-probe.c +14
-8@@ -595,22 +697,25 @@ static void get_new_event_name(char *buf, size_t len, const char *base,die ("Too many events are on the same function." ); } -void add_trace_kprobe_events (struct probe_point *probes,int nr_probes, -bool force_add) +static void add_trace_probe_events (int fd,struct probe_point *probes, +int nr_probes,bool force_add,pid_t pid) { -int i, j, fd; +int i, j;struct probe_point *pp;char buf[MAX_CMDLEN ]; +char tempbuf[MAX_CMDLEN ];char event[64 ];struct strlist *namelist;bool allow_suffix; - fd =open_kprobe_events (O_RDWR ,O_APPEND );/* Get current event names */ namelist =get_perf_event_names (fd, false);for (j =0 ; j < nr_probes; j++) { pp = probes + j; + pp->upid = pid; +if (pid) +snprintf (tempbuf,MAX_CMDLEN ,"%d:" , pid);if (!pp->event) pp->event =strdup (pp->function);if (!pp->group)@@ -621,12 +726,13 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,for (i =0 ; i < pp->found; i++) {/* Get an unused new event name */ get_new_event_name (event,64 , pp->event, namelist, - allow_suffix); -snprintf (buf,MAX_CMDLEN ,"%c:%s/%s %s\n" , + allow_suffix, pid); +snprintf (buf,MAX_CMDLEN ,"%c:%s/%s %s%s\n" , pp->retprobe ?'r' :'p' , pp->group, event, + pp->upid ? tempbuf :" " , pp->probes[i]); -write_trace_kprobe_event (fd, buf); +write_trace_probe_event (fd, buf);printf ("Added new event:\n" );/* Get the first parameter (probe-point) */ sscanf (pp->probes[i],"%s" , buf);@@ -650,7 +756,21 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,close (fd); } -static void __del_trace_kprobe_event (int fd,struct str_node *ent) +void add_trace_kprobe_events (struct probe_point *probes,int nr_probes, +bool force_add) +{
tools/perf/builtin-probe.c void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, · line 771
Quoted 10 lines
tools/perf/builtin-probe.c +10
-0+int fd =open_kprobe_events (O_RDWR ,O_APPEND ); +add_trace_probe_events (fd, probes, nr_probes, force_add,0 ); +} + +void add_trace_uprobe_events (struct probe_point *probes,int nr_probes, +bool force_add,pid_t pid) +{ +int fd =open_uprobe_events (O_RDWR ,O_APPEND ); +add_trace_probe_events (fd, probes, nr_probes, force_add, pid); +}
Please close fd in the function which opened it.
Quoted 31 lines
tools/perf/builtin-probe.c +3
-5@@ -696,16 +816,13 @@ static void del_trace_kprobe_event(int fd, const char *group,pr_info ("Info: event \"%s\" does not exist, could not remove it.\n" , buf); } -void del_trace_kprobe_events (struct strlist *dellist) +static void del_trace_probe_events (int fd,struct strlist *dellist) { -int fd;const char *group, *event;char *p, *str;struct str_node *ent;struct strlist *namelist; - fd =open_kprobe_events (O_RDWR ,O_APPEND ); -/* Get current event names */ namelist =get_perf_event_names (fd, true);strlist__for_each (ent, dellist) {@@ -723,13 +840,25 @@ void del_trace_kprobe_events(struct strlist *dellist) event = str; }pr_debug ("Group: %s, Event: %s\n" , group, event); -del_trace_kprobe_event (fd, group, event, namelist); +del_trace_probe_event (fd, group, event, namelist);free (str); }strlist__delete (namelist);close (fd); } +void del_trace_kprobe_events (struct strlist *dellist)
tools/perf/builtin-probe.c void del_trace_kprobe_events(struct strlist *dellist) · line 860
Quoted 10 lines
tools/perf/builtin-probe.c +10
-0+{ +int fd =open_kprobe_events (O_RDWR ,O_APPEND ); +del_trace_probe_events (fd, dellist); +} + +void del_trace_uprobe_events (struct strlist *dellist) +{ +int fd =open_uprobe_events (O_RDWR ,O_APPEND ); +del_trace_probe_events (fd, dellist); +}
Ditto.
[...]
Quoted 11 lines
tools/perf/util/symbol.c +2
-1@@ -958,12 +958,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, nr_syms = shdr.sh_size / shdr.sh_entsize;memset (&sym,0 ,sizeof (sym)); -if (!self->kernel) { +if (self->kernel || symbol_conf.sort_by_name) + self->adjust_symbols =0 ;
tools/perf/util/symbol.c static int dso__load_sym(struct dso *self, struct map *map, const char *name, · line 971
Quoted 10 lines
tools/perf/util/symbol.c +2
-1+else { self->adjust_symbols = (ehdr.e_type ==ET_EXEC ||elf_section_by_name (elf, &ehdr, &shdr,".gnu.prelink_undo" ,NULL ) !=NULL ); - }else self->adjust_symbols =0 ; + }elf_symtab__for_each_symbol (syms, nr_syms, idx, sym) {struct symbol *f;
This one changes the symbol.c, so I think you'd better make a separate patch for this change.
Thank you,
Signature · 2 lines
Masami Hiramatsu e-mail: [email protected]
Re: [PATCH v3 10/10] perf: perf interface for uprobes.
Quoted 3 lines
Could you also rebase your patch on the latest tip tree? :) (and remove
die()too)
I was aware that I have to rebase the patch to the latest tip. However I wanted to get a working set out.
Please expect the rebased version in the next version of the posting.
Quoted 4 lines
Quoted 4 lines
Here is a terminal snapshot of placing, using and removing a probe on a process with pid 3329 (corresponding to zsh)
Quoted 8 lines
Quoted 3 lines
[ Probing a function in the executable using function name ]
-------------------------------------------------------------[root@ABCD]# perf probe -p 3329 zfree@zshHmm, I'm not sure why we have to specify both of PID and exec name. Is that possible to give a symbol as below? (omit exec name)
# perf probe -p 3329 zfree
Yes, If the symbol name belongs to th execfile then we can omit the execfile part. However for symbols outside the execname, the execfile(library file) is a must(atleast for now).
Quoted 8 lines
Quoted 3 lines
Added new event:
probe:p_3329_zfree (on0x446420)Hmm, the event name should be simpler, as like as
zfree_3329. or, we might better make a new event group for each process, as like as 'probe_3329:zfree'
Either zfree_3329 or having a new event group for each process is possible.
Quoted 5 lines
Hmm, if user gave --list with -p, what happened?
We need to check a bad combination and warn it.
Currently it would ignore -p option. i.e --list overrides. We could either warn, or error out. What do you suggest?
Quoted 8 lines
tools/perf/builtin-probe.c int cmd_probe(int argc, const char **argv, const char *prefix __used) · line 301
Quoted 4 lines
tools/perf/builtin-probe.c +3
-0+if (session.pid) + goto end_dwarf; +Again, it must be checked that the combination of -p option and dwarf requirement. The latest code has
perf_probe_event_need_dwarf(), so you can check it easier.
Okay,
Quoted 12 lines
[...]
tools/perf/util/probe-event.c static bool check_event_name(const char *name) · line 172
Quoted 7 lines
tools/perf/util/probe-event.c +7
-0+else +free (pp->function); + pp->function =zalloc (sizeof (char *) *20 ); +if (!pp->function) +die ("Failed to allocate memory by zalloc." ); +e_snprintf (pp->function,20 ,"0x%llx" , vaddr); +}Well, after rebasing, you'll need to remove die()s from here and make it returns errors.
Okay.
Quoted 16 lines
[...]
tools/perf/util/probe-event.c int synthesize_trace_kprobe_event(struct probe_point *pp) · line 460
Quoted 13 lines
tools/perf/util/probe-event.c +5
-1@@ -383,7 +450,11 @@ int synthesize_trace_kprobe_event(struct probe_point *pp) pp->probes[0 ] = buf =zalloc (MAX_CMDLEN );if (!buf)die ("Failed to allocate memory by zalloc." ); - ret =e_snprintf (buf,MAX_CMDLEN ,"%s+%d" , pp->function, pp->offset); +if (pp->offset) + ret =e_snprintf (buf,MAX_CMDLEN ,"%s+%d" , pp->function, + pp->offset); +else + ret =e_snprintf (buf,MAX_CMDLEN ,"%s" , pp->function);if (ret <=0 ) goto error; len = ret;Isn't it a cleanup ?
Can you please elaborate?
Quoted 10 lines
tools/perf/util/probe-event.c void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, · line 771
Quoted 7 lines
tools/perf/util/probe-event.c +6
-0+void add_trace_uprobe_events (struct probe_point *probes,int nr_probes, +bool force_add,pid_t pid) +{ +int fd =open_uprobe_events (O_RDWR ,O_APPEND ); +add_trace_probe_events (fd, probes, nr_probes, force_add, pid); +}Please close fd in the function which opened it.
Okay.
Quoted 13 lines
Quoted 13 lines
tools/perf/util/symbol.c +4
-2memset (&sym,0 ,sizeof (sym)); -if (!self->kernel) { +if (self->kernel || symbol_conf.sort_by_name) + self->adjust_symbols =0 ; +else { self->adjust_symbols = (ehdr.e_type ==ET_EXEC ||elf_section_by_name (elf, &ehdr, &shdr,".gnu.prelink_undo" ,NULL ) !=NULL ); - }else self->adjust_symbols =0 ; + }
Quoted 5 lines
tools/perf/util/symbol.c static int dso__load_sym(struct dso *self, struct map *map, const char *name, · line 971
Quoted 2 lines
tools/perf/util/symbol.c +0
-0elf_symtab__for_each_symbol (syms, nr_syms, idx, sym) {struct symbol *f;This one changes the
symbol.c, so I think you'd better make a separate patch for this change.
Okay, I will separate it in the next version.
Thanks Masami for the review.
--
Thanks and Regards
Srikar
Re: [PATCH v3 10/10] perf: perf interface for uprobes.
Quoted 16 lines · Srikar Dronamraju
Quoted 3 lines
Could you also rebase your patch on the latest tip tree? :) (and remove
die()too)I was aware that I have to rebase the patch to the latest tip. However I wanted to get a working set out.
Please expect the rebased version in the next version of the posting.Quoted 8 lines
Quoted 7 lines
Here is a terminal snapshot of placing, using and removing a probe on a process with pid 3329 (corresponding to zsh)
[ Probing a function in the executable using function name ]
-------------------------------------------------------------[root@ABCD]# perf probe -p 3329 zfree@zsh
Quoted 8 lines
Quoted 4 lines
Hmm, I'm not sure why we have to specify both of PID and exec name. Is that possible to give a symbol as below? (omit exec name)
# perf probe -p 3329 zfreeYes, If the symbol name belongs to th execfile then we can omit the execfile part. However for symbols outside the execname, the execfile(library file) is a must(atleast for now).
Good!:)
Quoted 10 lines
Quoted 7 lines
Quoted 2 lines
Added new event:
probe:p_3329_zfree (on0x446420)Hmm, the event name should be simpler, as like as
zfree_3329. or, we might better make a new event group for each process, as like as 'probe_3329:zfree'Either
zfree_3329or having a new event group for each process is possible.
I think adding new groups make controlling those event easier. (e.g. deleting all probes on exited process)
Quoted 51 lines
Quoted 3 lines
Hmm, if user gave --list with -p, what happened?
We need to check a bad combination and warn it.Currently it would ignore -p option. i.e --list overrides. We could either warn, or error out. What do you suggest?
Quoted 8 lines
tools/perf/builtin-probe.c int cmd_probe(int argc, const char **argv, const char *prefix __used) · line 301
Quoted 4 lines
tools/perf/builtin-probe.c +3
-0+if (session.pid) + goto end_dwarf; +Again, it must be checked that the combination of -p option and dwarf requirement. The latest code has
perf_probe_event_need_dwarf(), so you can check it easier.Okay,
Quoted 12 lines
[...]
tools/perf/util/probe-event.c static bool check_event_name(const char *name) · line 172
Quoted 7 lines
tools/perf/util/probe-event.c +7
-0+else +free (pp->function); + pp->function =zalloc (sizeof (char *) *20 ); +if (!pp->function) +die ("Failed to allocate memory by zalloc." ); +e_snprintf (pp->function,20 ,"0x%llx" , vaddr); +}Well, after rebasing, you'll need to remove die()s from here and make it returns errors.
Okay.
Quoted 16 lines
[...]
tools/perf/util/probe-event.c int synthesize_trace_kprobe_event(struct probe_point *pp) · line 460
Quoted 13 lines
tools/perf/util/probe-event.c +5
-1@@ -383,7 +450,11 @@ int synthesize_trace_kprobe_event(struct probe_point *pp) pp->probes[0 ] = buf =zalloc (MAX_CMDLEN );if (!buf)die ("Failed to allocate memory by zalloc." ); - ret =e_snprintf (buf,MAX_CMDLEN ,"%s+%d" , pp->function, pp->offset); +if (pp->offset) + ret =e_snprintf (buf,MAX_CMDLEN ,"%s+%d" , pp->function, + pp->offset); +else + ret =e_snprintf (buf,MAX_CMDLEN ,"%s" , pp->function);if (ret <=0 ) goto error; len = ret;Isn't it a cleanup ?
Quoted 1 line
Can you please elaborate?
symbol+offset is always allowed even if offset == 0,
so I think this change isn't needed. I guessed it is just for cleanup.
Quoted 25 lines
Quoted 9 lines
tools/perf/util/probe-event.c void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, · line 771
Quoted 6 lines
tools/perf/util/probe-event.c +6
-0+void add_trace_uprobe_events (struct probe_point *probes,int nr_probes, +bool force_add,pid_t pid) +{ +int fd =open_uprobe_events (O_RDWR ,O_APPEND ); +add_trace_probe_events (fd, probes, nr_probes, force_add, pid); +}Please close fd in the function which opened it.
Okay.
Quoted 13 lines
Quoted 13 lines
tools/perf/util/symbol.c +4
-2memset (&sym,0 ,sizeof (sym)); -if (!self->kernel) { +if (self->kernel || symbol_conf.sort_by_name) + self->adjust_symbols =0 ; +else { self->adjust_symbols = (ehdr.e_type ==ET_EXEC ||elf_section_by_name (elf, &ehdr, &shdr,".gnu.prelink_undo" ,NULL ) !=NULL ); - }else self->adjust_symbols =0 ; + }
Quoted 8 lines
Quoted 5 lines
tools/perf/util/symbol.c static int dso__load_sym(struct dso *self, struct map *map, const char *name, · line 971
Quoted 2 lines
tools/perf/util/symbol.c +0
-0elf_symtab__for_each_symbol (syms, nr_syms, idx, sym) {struct symbol *f;This one changes the
symbol.c, so I think you'd better make a separate patch for this change.Okay, I will separate it in the next version.
Thanks Masami for the review.
Thank you!
Signature · 2 lines
Masami Hiramatsu e-mail: [email protected]
Re: [PATCH v3 10/10] perf: perf interface for uprobes.
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
Either
zfree_3329or having a new event group for each process is possible.I think adding new groups make controlling those event easier. (e.g. deleting all probes on exited process)
Okay..
Quoted 18 lines
Quoted 18 lines
Quoted 17 lines
[...]
tools/perf/util/probe-event.c int synthesize_trace_kprobe_event(struct probe_point *pp) · line 460
Quoted 13 lines
tools/perf/util/probe-event.c +5
-1@@ -383,7 +450,11 @@ int synthesize_trace_kprobe_event(struct probe_point *pp) pp->probes[0 ] = buf =zalloc (MAX_CMDLEN );if (!buf)die ("Failed to allocate memory by zalloc." ); - ret =e_snprintf (buf,MAX_CMDLEN ,"%s+%d" , pp->function, pp->offset); +if (pp->offset) + ret =e_snprintf (buf,MAX_CMDLEN ,"%s+%d" , pp->function, + pp->offset); +else + ret =e_snprintf (buf,MAX_CMDLEN ,"%s" , pp->function);if (ret <=0 ) goto error; len = ret;Isn't it a cleanup ?
Quoted 5 lines
Quoted 1 line
Can you please elaborate?
symbol+offset is always allowed even if offset == 0,
so I think this change isn't needed. I guessed it is just for cleanup.
kprobes has an advantage that it can make sense of kernel symbols. However uprobes doesnt have the advantage. It cannot make any sense of user space symbols. Hence unlike kprobes, uprobes doesnt have symbol_name and offset fields. To overcome this the perf probe for uprobes resolves the symbol_name, offset and pass the plain vaddr to uprobes.
--
Thanks and Regards
Srikar Dronamraju
Peter Zijlstra
maintainerQuoted 6 lines · Srikar Dronamraju
- Addressed comments from Oleg, including removal of interrupt context handlers, reverting background page replacement in favour of
access_process_vm().(quoted diff) +1
-0+static int write_opcode(struct task_struct *tsk, unsigned long vaddr,
Review
Quoted 10 lines
(quoted diff) +10
-0+ user_bkpt_opcode_t opcode) +{ + int ret; + + if (!tsk) + return -EINVAL; + + ret = access_process_vm(tsk, vaddr, &opcode, user_bkpt_opcode_sz, 1); + return (ret == user_bkpt_opcode_sz ? 0 : -EFAULT); +}
Why!
That's not not the atomic sequence outlined.
Quoted 20 lines · Peter Zijlstra
Quoted 6 lines · Srikar Dronamraju
- Addressed comments from Oleg, including removal of interrupt context handlers, reverting background page replacement in favour of
access_process_vm().(quoted diff) +1
-0+static int write_opcode(struct task_struct *tsk, unsigned long vaddr,Review
Quoted 10 lines
(quoted diff) +10
-0+ user_bkpt_opcode_t opcode) +{ + int ret; + + if (!tsk) + return -EINVAL; + + ret = access_process_vm(tsk, vaddr, &opcode, user_bkpt_opcode_sz, 1); + return (ret == user_bkpt_opcode_sz ? 0 : -EFAULT); +}Why!
Quoted 2 lines
That's not not the atomic sequence outlined.
Yes, we had moved away from access_process_vm to background page replacement in Version 1 and Version 2.
One of the reasons being Mathieu suggesting to Jim in LFCS that for almost all architectures insertion of a breakpoint instruction on a user page is an atomic operation, as far as the CPU is concerned.
Can you and other VM experts tell me if access_process_vm isnt going to be atomic with respect to inserting/deleting a breakpoint instruction?
Oleg had few questions which I didnt have answers. (Most of which you have already answered yesterday). One thing that's still missing is
[ snipping from Oleg's mail: ]
-----
But suppose that the application does mprotect(PROT_WRITE) after register_uprobe() installs the bp, now unregister_uprobe/etc can't restore the original insn?
---
Also I tried a write_opcode that uses background page replacement which addressed some of Oleg's comments. The pseudo-code is here:write_opcode()
{
down_read(mmap_sem);
get_user_pages(tsk, mm, vaddr, .. &old_page, &vma);
anon_vma_prepare(vma);
new_page=alloc_page_vma(.., vma, vaddr);
copy_user_page(new_page, old_page);
kmap_atomic(new_page,...);
memcpy(vaddr,..);
kunmap_atomic(..);
lock_page(new_page);
old_pte = get_pte(mm,vaddr);
replace_page(vma, new_page, old_page, old_pte);
unlock_page(new_page);
put_page(new_page);
put_page(old_page);
up_read(mmap);
} Will this work?
The Other VM quieries that I had were:
Is there any thing else needed for the parent process to pass on the anon_vma to the child process. (I inserted a breakpoint in the parent and tried removing the breakpoint in the child.
However page_address_in_vma() (called by replace_page() returned EFAULT because "vma->anon_vma != page_anon_vma(page)"
Do we need to take care of mem_cgroups?
Do we need to update mm counters?
--
Thanks and Regards
Srikar
Peter Zijlstra
maintainerQuoted 26 lines · Srikar Dronamraju
Quoted 20 lines · Peter Zijlstra
Quoted 6 lines · Srikar Dronamraju
- Addressed comments from Oleg, including removal of interrupt context handlers, reverting background page replacement in favour of
access_process_vm().(quoted diff) +1
-0+static int write_opcode(struct task_struct *tsk, unsigned long vaddr,Review
Quoted 10 lines
(quoted diff) +10
-0+ user_bkpt_opcode_t opcode) +{ + int ret; + + if (!tsk) + return -EINVAL; + + ret = access_process_vm(tsk, vaddr, &opcode, user_bkpt_opcode_sz, 1); + return (ret == user_bkpt_opcode_sz ? 0 : -EFAULT); +}Why!
Quoted 2 lines
That's not not the atomic sequence outlined.
Quoted 6 lines
Yes, we had moved away from
access_process_vmto background page replacement in Version 1 and Version 2.One of the reasons being Mathieu suggesting to Jim in LFCS that for almost all architectures insertion of a breakpoint instruction on a user page is an atomic operation, as far as the CPU is concerned.
That is true, however when restoring the old instruction you do need to take care, so your usage from set_orig_insn() is dubious.
Quoted 2 lines
Can you and other VM experts tell me if
access_process_vmisnt going to be atomic with respect to inserting/deleting a breakpoint instruction?
Well, clearly not, since it simply does a gup(.force=1), if whatever page is there is writable it will simply poke at it.
Now writing the INT3 is special, but restoring the old insn is not and might confuse another CPU that is currently trying to execute code near there.
All in all, doing the page flip thing isn't hard at all and does avoid any and all potential CPU decoder/i$ races.
Quoted 9 lines
Oleg had few questions which I didnt have answers. (Most of which you have already answered yesterday). One thing that's still missing is
[ snipping from Oleg's mail: ]
-----
But suppose that the application doesmprotect(PROT_WRITE)afterregister_uprobe()installs the bp, now unregister_uprobe/etc can't restore the original insn?
I wouldn't see why not. The mprotect() will only allow the application to poke at its own private copy of the page (the one you COWed for it).
Of course the app, a ptrace-client and uprobes could go fighting over who owns what INT3 (all 3 poking an INT3 at the same place, and one of them removing it will confuse matters, but that's unavoidable).
But a nicely written flip will be atomic wrt concurrent writes (the below is not).
Quoted 23 lines
Also I tried a
write_opcodethat uses background page replacement which addressed some of Oleg's comments. The pseudo-code is here:
write_opcode(){ down_read(mmap_sem); get_user_pages(tsk, mm, vaddr, .. &old_page, &vma); anon_vma_prepare(vma); new_page=alloc_page_vma(.., vma, vaddr); copy_user_page(new_page, old_page); kmap_atomic(new_page,...); memcpy(vaddr,..); kunmap_atomic(..); lock_page(new_page); old_pte = get_pte(mm,vaddr); replace_page(vma, new_page, old_page, old_pte); unlock_page(new_page); put_page(new_page); put_page(old_page); up_read(mmap); }
Quoted 1 line
Will this work?
No, that's full of races. you need to copy and modify the original page while holding the pte-lock and after you cleared the original pte.
You could possible skip the whole COW break logic by cheating and making gup() do that, it would be a little extra overhead, but a lot less to worry about.
Hrmm, you could do something like the above and use write_protect_page() along with that lock_page() you do to sync against concurrent faults. It won't be the fastest code around but it should work I guess.
Something like try_to_merge_one_page() in the KSM code:
write_opcode(struct mm_struct *mm, unsigned long address, void *insn, int len)
{
down_read(mm->mmap_sem);
/* let gup() deal with COW and VM accounting */
nr = get_user_pages(tsk, mm, address, 1, 1, 1, &old_page, &vma);
if (!nr) goto fail;
/* get ourselves a new page */
new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
if (!new_page) goto fail;
/* lock page will serialize against do_wp_page()'s PageAnon() handling */
lock_page(old_page);
/* mark the page RO so any concurrent access will end up in do_wp_page() */
if (write_protect_page(vma, old_page, &orig_pte)) goto fail_locked;
/* copy the page now that we've got it stable */
vaddr_old = kmap_atomic(old_page);
vaddr_new = kmap_atomic(new_page);
memcpy(vaddr_new, vaddr_old, PAGE_SIZE);
/* poke the new insn in, ASSUMES we don't cross page boundary */
memcpy(vaddr_new + (address & PAGE_MASK), insn, len);
kunmap_atomic(vaddr_new);
kunmap_atomic(vaddr_old);
/* XXX: frob mlock state */
/* flip pages, do_wp_page() will fail pte_same() and bail */
err = replace_page(vma, new_page, old_page, orig_pte)
if (err) goto fail_more;
/* we're done, let 'em rip */
unlock_page(old_page);
put_page(old_page);
return;fail:
/* XXX: fixup stuff */ }
Note that this can fail for fun reasons like O_DIRECT IO, but that should be very rare indeed on text pages.
Quoted 7 lines
The Other VM quieries that I had were:
Is there any thing else needed for the parent process to pass on the
anon_vmato the child process. (I inserted a breakpoint in the parent and tried removing the breakpoint in the child.
Howeverpage_address_in_vma()(called byreplace_page()returned EFAULT because "vma->anon_vma!=page_anon_vma(page)"
Yeah, anon_vma is a bit of a pain after Rik changed it, you need to compare the oldest entries on the list or something.
Quoted 1 line
Do we need to take care of
mem_cgroups?
Dunno, I've so far successfully avoided looking at them, but yeah, I think you need to do like the regular COW path does when breaking COW.
Quoted 1 line
Do we need to update mm counters?
When breaking COW, yes, but the above code cheats and lets gup() worry about that.
Quoted 40 lines · Peter Zijlstra
Quoted 26 lines · Srikar Dronamraju
Quoted 20 lines · Peter Zijlstra
Quoted 6 lines · Srikar Dronamraju
- Addressed comments from Oleg, including removal of interrupt context handlers, reverting background page replacement in favour of
access_process_vm().(quoted diff) +1
-0+static int write_opcode(struct task_struct *tsk, unsigned long vaddr,Review
Quoted 10 lines
(quoted diff) +10
-0+ user_bkpt_opcode_t opcode) +{ + int ret; + + if (!tsk) + return -EINVAL; + + ret = access_process_vm(tsk, vaddr, &opcode, user_bkpt_opcode_sz, 1); + return (ret == user_bkpt_opcode_sz ? 0 : -EFAULT); +}Why!
Quoted 2 lines
That's not not the atomic sequence outlined.
Quoted 6 lines
Yes, we had moved away from
access_process_vmto background page replacement in Version 1 and Version 2.One of the reasons being Mathieu suggesting to Jim in LFCS that for almost all architectures insertion of a breakpoint instruction on a user page is an atomic operation, as far as the CPU is concerned.
That is true, however when restoring the old instruction you do need to take care, so your usage from
set_orig_insn()is dubious.Quoted 2 lines
Can you and other VM experts tell me if
access_process_vmisnt going to be atomic with respect to inserting/deleting a breakpoint instruction?
Quoted 6 lines
Well, clearly not, since it simply does a gup(.force=1), if whatever page is there is writable it will simply poke at it.
Now writing the INT3 is special, but restoring the old insn is not and might confuse another CPU that is currently trying to execute code near there.
Yes, this helps for breakpoint insertion, but...
The question is whether only INT3 special or single-byte changes are also guaranteed to be atomic. In http://lkml.org/lkml/2010/1/27/275
Peter Anvin states 'specific case of a more generic rule'.
For restoring the old instruction, we technically need to put back just one byte, irrespective of the actual length of the underlying instruction. Now, as long as we have the housekeeping code to handle the possibility of a thread hitting the said breakpoint when its being removed, is it safe to assume atomicity for replacing one byte of possibly a longer instruction?
Ananth
Peter Zijlstra
maintainerQuoted 4 lines · Ananth N Mavinakayanahalli
Now, as long as we have the housekeeping code to handle the possibility of a thread hitting the said breakpoint when its being removed, is it safe to assume atomicity for replacing one byte of possibly a longer instruction?
Dunno I'm not a hardware guy, but the issue is so simple to side-step I'm not sure why you're arguing for relying on these special semantics.
Quoted 8 lines · Peter Zijlstra
Quoted 4 lines · Ananth N Mavinakayanahalli
Now, as long as we have the housekeeping code to handle the possibility of a thread hitting the said breakpoint when its being removed, is it safe to assume atomicity for replacing one byte of possibly a longer instruction?
Dunno I'm not a hardware guy, but the issue is so simple to side-step I'm not sure why you're arguing for relying on these special semantics.
Yes we know what to do, but I am just trying to get clarity if its possible at all, since Mathieu was pretty sure that the hoops aren't necessary...
Ananth
Mathieu Desnoyers
reviewerQuoted 7 lines · * Ananth N Mavinakayanahalli ([email protected]) wrote:
Quoted 6 lines · Peter Zijlstra
Quoted 4 lines · Ananth N Mavinakayanahalli
Now, as long as we have the housekeeping code to handle the possibility of a thread hitting the said breakpoint when its being removed, is it safe to assume atomicity for replacing one byte of possibly a longer instruction?
Quoted 8 lines
Quoted 2 lines
Dunno I'm not a hardware guy, but the issue is so simple to side-step I'm not sure why you're arguing for relying on these special semantics.
Yes we know what to do, but I am just trying to get clarity if its possible at all, since Mathieu was pretty sure that the hoops aren't necessary...
From what I gathered in the Intel code modification documentation, setting a
breakpoint instruction is both atomic and OK with respect to concurrent CPUs executing the code. The breakpoint instruction itself deals with serialization of remote cores when it is hit.
Placing back _the original instruction_ is considered as safe too, as it is both atomic and brings back the remote cores to the original code state. Basically, these cores either observe the int3, or the original code. If they observe the int3, they perform core serialization. If they observe the original code, they either have never observed the int3 version (which is fine, it is as if the code had never changed), or if they did observe the int3, they executed the serialization instruction at the int3, so it's OK to put back the original instruction.
Now the tricky case is the sequence: instruction A -> int3 -> instruction B, because a core can only see "instruction A -> instruction B" without any core synchronization whatsoever, and may not see the int3. That's where the djprobes logic (with IPIs to all cores) comes into play. But as long as we stick to "insn A -> int3 -> insn A", things can be done very simply.
By the way, kprobes rely on the assumption that it is OK to put a breakpoint atomically and to put back the original instruction afterward.
Thanks,
Mathieu
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
H. Peter Anvin
reviewerQuoted 10 lines · Mathieu Desnoyers
Now the tricky case is the sequence: instruction A -> int3 -> instruction B, because a core can only see "instruction A -> instruction B" without any core synchronization whatsoever, and may not see the int3. That's where the djprobes logic (with IPIs to all cores) comes into play. But as long as we stick to "insn A -> int3 -> insn A", things can be done very simply.
By the way, kprobes rely on the assumption that it is OK to put a breakpoint atomically and to put back the original instruction afterward.
Keep in mind the following corner case, though:
insnA -> int3@A -> insnA
insnB -> int3@B -> insnB
It is now possible for the core to hit int3@A, without the int3@B being there. The int3 handler *has* to be able to handle any of the int3's put in place, quite possibly out of order, until a core serialization is performed.
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Mathieu Desnoyers
reviewerQuoted 14 lines · * H. Peter Anvin ([email protected]) wrote:
Quoted 10 lines · Mathieu Desnoyers
Now the tricky case is the sequence: instruction A -> int3 -> instruction B, because a core can only see "instruction A -> instruction B" without any core synchronization whatsoever, and may not see the int3. That's where the djprobes logic (with IPIs to all cores) comes into play. But as long as we stick to "insn A -> int3 -> insn A", things can be done very simply.
By the way, kprobes rely on the assumption that it is OK to put a breakpoint atomically and to put back the original instruction afterward.
Keep in mind the following corner case, though:
Quoted 7 lines
insnA -> int3@A -> insnA
insnB -> int3@B -> insnBIt is now possible for the core to hit int3@A, without the int3@B being there. The int3 handler *has* to be able to handle any of the int3's put in place, quite possibly out of order, until a core serialization is performed.
Indeed. I would add that this out-of-order observation of breakpoint modification is already expected, because other cores may be executing arbitrary code when we add the two breakpoints (either insnA, B, or somewhere in between, or somewhere else entirely).
Basically, we can make no assumption about the order in which the two stores will be seen by other CPUs. But I can't imagine a debugger expecting these two stores to be observed in order.
If we ever want to provide a _guarantee_ that starting from a certain point all CPUs will see a set of breakpoint, then we need to issue a core serializing instruction on all CPUs. This would determine the "quiescent state" of the CPUs, starting from which all of them see the breakpoints.
Thanks,
Mathieu
Quoted 7 lines
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Quoted 4 lines
Hrmm, you could do something like the above and use
write_protect_page()along with thatlock_page()you do to sync against concurrent faults. It won't be the fastest code around but it should work I guess.
Okay, thanks for the code.
Quoted 7 lines
Something like
try_to_merge_one_page()in the KSM code:
write_opcode(struct mm_struct *mm, unsigned long address, void *insn, int len){ down_read(mm->mmap_sem);
[ snipped]
Quoted 5 lines
kunmap_atomic(vaddr_new); kunmap_atomic(vaddr_old); /* XXX: frob mlock state */
I think you are referring to mlock_vma_page() and munlock_vma_page that we have in try_to_merge_one_page(). However mlock_vma_page and munlock_vma_page are not exposed outside mm as they are declared inside mm/internal.h. So do you suggest moving the declarations out of mm/internal.h or have a wrapper function defined in mm/ that could be used by both KSM and uprobes.
Quoted 18 lines
/* flip pages, do_wp_page() will fail pte_same() and bail */ err = replace_page(vma, new_page, old_page, orig_pte) if (err) goto fail_more; /* we're done, let 'em rip */ unlock_page(old_page); put_page(old_page); return;fail:
/* XXX: fixup stuff */ }Note that this can fail for fun reasons like
O_DIRECTIO, but that should be very rare indeed on text pages.
Quoted 5 lines · Srikar Dronamraju
intro.patch
From: Srikar Dronamraju <[email protected]>
Uprobes Patches
I can't find the trace event patch inside this set. May be you missed it somehow? (or I did).
Thanks.
Quoted 5 lines · Frederic Weisbecker
Quoted 4 lines · Srikar Dronamraju
intro.patch
From: Srikar Dronamraju <[email protected]>
Quoted 9 lines
Quoted 1 line
Uprobes Patches
I can't find the trace event patch inside this set. May be you missed it somehow? (or I did).
Thanks.
http://lkml.org/lkml/2010/5/6/284
However there were no changes from the patchset in version 2. So your comments hold good for this version too.
--
Thanks and Regards
Srikar
Quoted 11 lines · Srikar Dronamraju
Quoted 9 lines · Frederic Weisbecker
Quoted 5 lines · Srikar Dronamraju
intro.patch
From: Srikar Dronamraju <[email protected]>
Uprobes Patches
Quoted 7 lines
Quoted 5 lines
I can't find the trace event patch inside this set. May be you missed it somehow? (or I did).
Thanks.
I missed it somehow.
Nevermind.
Thanks.