Uprobes v5
Subsystems (11)
v5 cover Uprobes v5
intro.patch
From: Srikar Dronamraju <[email protected]>
Uprobes Patches
Changelog from v4:
- Rebased to tip tree. (2.6.35-rc3-tip)
Changelog from v3:
- Reverted to background page replacement as suggested by Peter Zijlstra.
- Dso in 'perf probe' can be either be a short name or a absolute path.
- Addressed comments from Masami, Frederic, Steven on traceevents and perf
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
and http://lkml.org/lkml/2010/5/18/307
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.35-rc3-tip.
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. user_bkpt: User Space Breakpoint Assistance Layer 4. user_bkpt: X86 details for User space breakpoint assistance 5. user_bkpt: Slot allocation for Execution out of line 6. uprobes: Uprobes Implementation 7. uprobes: X86 details for Uprobes 8. samples: Uprobes samples 9. uprobes: Uprobes Documentation patch
10. trace: Share common code for uprobes/kprobes traceevents
11. trace: uprobes trace_event interface
12. perf: Dont adjust symbols if lookup is by name.
13. perf: Re-add make_absolute_path().
14. perf: perf interface for uprobes.
Documentation/uprobes.txt | 236 +++++++++ arch/Kconfig | 31 ++ 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.h | 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 | 21 + kernel/trace/Kconfig | 13 + kernel/trace/Makefile | 1 + kernel/trace/trace.h | 5 + kernel/trace/trace_kprobe.c | 141 +------ kernel/trace/trace_probe.h | 159 +++++++ kernel/trace/trace_uprobe.c | 921 ++++++++++++++++++++++++++++++++++++ kernel/uprobes.c | 681 ++++++++++++++++++++++++++ kernel/user_bkpt.c | 589 +++++++++++++++++++++++ kernel/user_bkpt_xol.c | 302 ++++++++++++ mm/ksm.c | 112 ----- mm/memory.c | 120 +++++ samples/Kconfig | 7 + samples/Makefile | 2 +- samples/uprobes/Makefile | 17 + samples/uprobes/uprobe_example.c | 83 ++++ tools/perf/builtin-probe.c | 13 +- tools/perf/builtin-top.c | 20 - tools/perf/util/abspath.c | 81 ++++ tools/perf/util/cache.h | 1 + tools/perf/util/event.c | 20 + tools/perf/util/event.h | 1 + tools/perf/util/probe-event.c | 466 +++++++++++++------ tools/perf/util/probe-event.h | 37 +- tools/perf/util/probe-finder.c | 20 +- tools/perf/util/probe-finder.h | 6 +- tools/perf/util/symbol.c | 6 +- 46 files changed, 4917 insertions(+), 457 deletions(-)
---
0 files changed, 0 insertions(+), 0 deletions(-)
PATCH v5 1/14 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
Re: [PATCH v5 1/14] X86 instruction analysis: Move Macro W to insn.h
Quoted 10 lines · Srikar Dronamraju
move_W_to_insn.patch
From: Srikar Dronamraju <[email protected]>
Move Macro W to
asm/insn.hMacro 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 fileasm/insn.h.
I don't think W is a good name for a macro in a header file.
Re: [PATCH v5 1/14] X86 instruction analysis: Move Macro W to insn.h
Quoted 5 lines · Christoph Hellwig
Quoted 4 lines · Srikar Dronamraju
move_W_to_insn.patch
From: Srikar Dronamraju <[email protected]>
Quoted 8 lines
Quoted 6 lines
Move Macro W to
asm/insn.hMacro 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 fileasm/insn.h.I don't think W is a good name for a macro in a header file.
Agree, Masami has also given the same comment earlier, I plan to move to using inat tables instead of this macro.
--
Thanks and Regards
Srikar
PATCH v5 2/14 mm: Move replace_page to mm/memory.c
In reply to Srikar Dronamrajumove_replace_page.patch
From: Srikar Dronamraju <[email protected]>
Move replace_page() and write_protect_page() to mm/memory.c
User bkpt will use background page replacement approach to insert/delete breakpoints. Background page replacement approach will be based on replace_page and write_protect_page.
Now replace_page() loses its static attribute.
---
include/linux/mm.h | 4 ++ mm/ksm.c | 112 ------------------------------------------------- mm/memory.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 112 deletions(-)
include/linux/mm.h +4 -0
@@ -858,6 +858,10 @@ void account_page_dirtied(struct page *page, struct address_space *mapping);int set_page_dirty (struct page *page);int set_page_dirty_lock (struct page *page);int clear_page_dirty_for_io (struct page *page); +int replace_page (struct vm_area_struct *vma,struct page *page, +struct page *kpage,pte_t orig_pte); +int write_protect_page (struct vm_area_struct *vma,struct page *page, +pte_t *orig_pte); extern unsigned long move_page_tables(struct vm_area_struct *vma, unsigned long old_addr, struct vm_area_struct *new_vma,
mm/ksm.c +0 -112
118 lines not on this page · raw message
mm/memory.c +120 -0
126 lines not on this page · raw message
Re: [PATCH v5 2/14] mm: Move replace_page to mm/memory.c
Quoted 10 lines · Srikar Dronamraju
move_replace_page.patch
From: Srikar Dronamraju <[email protected]>
Move
replace_page()andwrite_protect_page()tomm/memory.cUser bkpt will use background page replacement approach to insert/delete breakpoints. Background page replacement approach will be based on
replace_pageandwrite_protect_page.
Nowreplace_page()loses its static attribute.
Neither of these actually gets used in this series. So you can drop the patch for now.
Re: [PATCH v5 2/14] mm: Move replace_page to mm/memory.c
Quoted 7 lines · Srikar Dronamraju
Quoted 6 lines
move_replace_page.patch
From: Srikar Dronamraju <[email protected]>
Move
replace_page()andwrite_protect_page()tomm/memory.c
Quoted 7 lines
Quoted 4 lines
User bkpt will use background page replacement approach to insert/delete breakpoints. Background page replacement approach will be based on
replace_pageandwrite_protect_page.
Nowreplace_page()loses its static attribute.Neither of these actually gets used in this series. So you can drop the patch for now.
replace_page() and write_protect_page() are used in write_opcode() to insert/remove a breakpoint in the user-space breakpoint insertion layer. i.e "[PATCH v5 3/14] User Space Breakpoint Assistance Layer"
Even if we merge uprobes and user_bkpt layers, we would still need write_opcode function while inserting/deleting a breakpoint.
--
Thanks and Regards
Srikar
Re: [PATCH v5 2/14] mm: Move replace_page to mm/memory.c
Quoted 3 lines · Srikar Dronamraju
replace_page()andwrite_protect_page()are used inwrite_opcode()to insert/remove a breakpoint in the user-space breakpoint insertion layer. i.e "[PATCH v5 3/14] User Space Breakpoint Assistance Layer"
You're right. I did a git-grep, but that didn't find the newly added files..
PATCH v5 3/14 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 V3: (reimplement background page replacement)
* Replemented background page replacement based on inputs from Peter Zijlstra.
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 | 14 + include/linux/user_bkpt.h | 305 +++++++++++++++++++++++ kernel/Makefile | 1 kernel/user_bkpt.c | 589 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 909 insertions(+), 0 deletions(-) create mode 100644 include/linux/user_bkpt.h create mode 100644 kernel/user_bkpt.c
arch/Kconfig +14 -0
@@ -47,6 +47,17 @@ config OPTPROBES depends on !PREEMPT select KALLSYMS_ALL +config USER_BKPT + bool "User-space breakpoint assistance (EXPERIMENTAL)" + depends on MODULES + depends on HAVE_USER_BKPT + depends on MMU + 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
@@ -80,6 +91,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 +589 -0
589 lines not on this page · raw message
Re: [PATCH v5 3/14] User Space Breakpoint Assistance Layer
Quoted 6 lines · Srikar Dronamraju
User Space Breakpoint Assistance Layer (
USER_BKPT) Changelog from V3: (reimplement background page replacement)
* Replemented background page replacement based on inputs from Peter Zijlstra.Changelog from v2: (addressing comments from Oleg)
FYI the changelog should be under the --- marker so that it doesn't get included into the final commit message.
Steven Rostedt
maintainerRe: [PATCH v5 3/14] User Space Breakpoint Assistance Layer
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Srikar Dronamraju
User Space Breakpoint Assistance Layer (
USER_BKPT) Changelog from V3: (reimplement background page replacement)
* Replemented background page replacement based on inputs from Peter Zijlstra.Changelog from v2: (addressing comments from Oleg)
FYI the changelog should be under the --- marker so that it doesn't get included into the final commit message.
Actually, I find the version'ing of a patch in the changelog useful. It gives a bit of history to how the patch was created.
-- Steve
Re: [PATCH v5 3/14] User Space Breakpoint Assistance Layer
In reply to Srikar DronamrajuQuoted 1 line · Srikar Dronamraju
TODO: Merge
user_bkptlayer with uprobes.
Yes, I don't think there's any point in that split. What's the timeframe for you to finish that merge?
arch/Kconfig config OPTPROBES · line 52
Quoted 1 line
arch/Kconfig +1
-0+ depends on MODULES
This doesn't make too much sense - the only real user of this is not modular at all.
arch/Kconfig config OPTPROBES · line 53
Quoted 1 line
arch/Kconfig +1
-0+ depends on HAVE_USER_BKPT
Should this be ARCH_HAVE_USER_BKPT or similar?
Re: [PATCH v5 3/14] User Space Breakpoint Assistance Layer
Quoted 5 lines · Christoph Hellwig
Quoted 1 line · Srikar Dronamraju
TODO: Merge
user_bkptlayer with uprobes.Yes, I don't think there's any point in that split. What's the timeframe for you to finish that merge?
I will take this up in v6.
Quoted 5 lines
arch/Kconfig config OPTPROBES · line 52
Quoted 2 lines
arch/Kconfig +1
-0+ depends on MODULESThis doesn't make too much sense - the only real user of this is not modular at all.
Okay.
Quoted 4 lines
arch/Kconfig config OPTPROBES · line 53
Quoted 2 lines
arch/Kconfig +1
-0+ depends on HAVE_USER_BKPTShould this be
ARCH_HAVE_USER_BKPTor similar?
Okay I shall change from HAVE_USER_BKPT to ARCH_HAVE_USER_BKPT.
--
Thanks and Regards
Srikar
Steven Rostedt
maintainerRe: [PATCH v5 3/14] User Space Breakpoint Assistance Layer
In reply to Srikar DronamrajuQuoted 5 lines · Srikar Dronamraju
user_bkpt_core.patch
From: Srikar Dronamraju <[email protected]>
Quoted 7 lines
+/**
+ *user_bkpt_write_data- Write @nbytes from @kbuf at @vaddr in @tsk.
+ * Can be used to write to stack or data VM areas, but not instructions.
+ * Not exported, but available for use by arch-specificuser_bkptcode.
+ * @tsk: The probed task
+ * @vaddr: Destination address, in user space.
+ * @kbuf: Source address, in kernel space to be read.
I'm curious. Anything prevent this from being called on instructions, or is this just "Don't do that?".
Quoted 72 lines
+ *
+ * Context: This function may sleep.
+ *
+ * Return number of bytes written.
+ */kernel/user_bkpt.c new file +67
-0+unsigned long user_bkpt_write_data (struct task_struct *tsk, +void __user *vaddr,const void *kbuf, +unsigned long nbytes) +{ +unsigned long nleft; + +if (tsk == current) { + nleft =copy_to_user (vaddr, kbuf, nbytes); +return nbytes - nleft; + }else +return access_process_vm (tsk, (unsigned long ) vaddr, + (void *) kbuf, nbytes,1 ); +} + +static int write_opcode (struct task_struct *tsk,unsigned long vaddr, +user_bkpt_opcode_t opcode) +{ +struct mm_struct *mm; +struct vm_area_struct *vma; +struct page *old_page, *new_page; +void *vaddr_old, *vaddr_new; +pte_t orig_pte; +int ret = -EINVAL ; + +if (!tsk) +return ret; + + mm =get_task_mm (tsk); +if (!mm) +return ret; + +down_read (&mm->mmap_sem); + +/* Read the page with vaddr into memory */ + ret =get_user_pages (tsk, mm, vaddr,1 ,1 ,1 , &old_page, &vma); +if (ret <=0 ) + goto mmput_out; + +/* +* check if the page we are interested is read-only mapped +* Since we are interested in text pages, Our pages of interest +* should be mapped read-only. +*/ +if ((vma->vm_flags && (VM_READ |VM_WRITE )) !=VM_READ ) { + ret = -EINVAL ; + goto put_out; + } + +/* If its VM_SHARED vma, lets not write to such vma's. */ +if (vma->vm_flags &VM_SHARED ) { + ret = -EINVAL ; + goto put_out; + } + +/* Allocate a page */ + new_page =alloc_page_vma (GFP_HIGHUSER_MOVABLE , vma, vaddr); +if (!new_page) { + ret = -ENOMEM ; + goto put_out; + } + +/* +* lock page will serialize against do_wp_page()'s +* PageAnon() handling +*/ +lock_page (old_page); +/* mark page RO so any concurrent access will end up in do_wp_page() */
kernel/user_bkpt.c line 197
Quoted 10 lines
kernel/user_bkpt.c new file +10
-0+if (write_protect_page (vma, old_page, &orig_pte)) + goto unlock_out; + +/* copy the page now that we've got it stable */ + vaddr_old =kmap_atomic (old_page,KM_USER0 ); + vaddr_new =kmap_atomic (new_page,KM_USER1 ); + +memcpy (vaddr_new, vaddr_old,PAGE_SIZE ); +/* poke the new insn in, ASSUMES we don't cross page boundary */ + vaddr = vaddr & (PAGE_SIZE -1 );
This should probably be vaddr = vaddr & ~PAGE_MASK;
-- Steve
Quoted 24 lines
kernel/user_bkpt.c new file +24
-0+memcpy (vaddr_new + vaddr, &opcode, user_bkpt_opcode_sz); + +kunmap_atomic (vaddr_new,KM_USER1 ); +kunmap_atomic (vaddr_old,KM_USER0 ); + +lock_page (new_page); +/* flip pages, do_wp_page() will fail pte_same() and bail */ + ret =replace_page (vma, old_page, new_page, orig_pte); + +unlock_out: +unlock_page (new_page); +unlock_page (old_page); +if (ret !=0 ) +page_cache_release (new_page); + +put_out: +put_page (old_page);/* we did a get_page in the beginning */ + +mmput_out: +up_read (&mm->mmap_sem); +mmput (mm); +return ret; +} +
Re: [PATCH v5 3/14] User Space Breakpoint Assistance Layer
Quoted 11 lines
Quoted 7 lines
+/**
+ *user_bkpt_write_data- Write @nbytes from @kbuf at @vaddr in @tsk.
+ * Can be used to write to stack or data VM areas, but not instructions.
+ * Not exported, but available for use by arch-specificuser_bkptcode.
+ * @tsk: The probed task
+ * @vaddr: Destination address, in user space.
+ * @kbuf: Source address, in kernel space to be read.I'm curious. Anything prevent this from being called on instructions, or is this just "Don't do that?".
Both,copy_to_user doesnt work on writes to text.
And if I am right, copy_to_user isnt preferred while writing to text pages too.
Quoted 6 lines
kernel/user_bkpt.c line 197
Quoted 4 lines
kernel/user_bkpt.c new file +4
-0+ +memcpy (vaddr_new, vaddr_old,PAGE_SIZE ); +/* poke the new insn in, ASSUMES we don't cross page boundary */ + vaddr = vaddr & (PAGE_SIZE -1 );This should probably be vaddr = vaddr & ~PAGE_MASK;
Okay, I will make the corresponding change.
Quoted 2 lines
PATCH v5 4/14 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 from v1:
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
@@ -54,6 +54,7 @@ config X86 select HAVE_KERNEL_LZO select HAVE_HW_BREAKPOINT select HAVE_MIXED_BREAKPOINTS_REGS + select HAVE_USER_BKPT select PERF_EVENTS select HAVE_PERF_EVENTS_NMI select ANON_INODES
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
@@ -115,6 +115,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 v5 5/14 Slot allocation for execution out of line (XOL)
In reply to Srikar Dronamrajuubp_xol.patch
From: Srikar Dronamraju <[email protected]>
Changelog form v3:
* Added a memory barrier after the slot gets initialized.
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 | 302 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 347 insertions(+), 0 deletions(-) create mode 100644 include/linux/user_bkpt_xol.h create mode 100644 kernel/user_bkpt_xol.c
arch/Kconfig +4 -0
@@ -94,6 +94,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 +302 -0
302 lines not on this page · raw message
Re: [PATCH v5 5/14] Slot allocation for execution out of line (XOL)
What's the point of adding another header for a few prototypes when all users include user_bkpt.h anyway?
Re: [PATCH v5 5/14] Slot allocation for execution out of line (XOL)
Quoted 3 lines · Christoph Hellwig
What's the point of adding another header for a few prototypes when all users include
user_bkpt.hanyway?
Okay,
Should we be moving the user_bkpt_xol also into uprobes when we move the user_bkpt layer into uprobes?
--
Thanks and Regards
Srikar
PATCH v5 6/14 Uprobes Implementation
In reply to Srikar Dronamrajuuprobes_core.patch
From: Srikar Dronamraju <[email protected]>
Uprobes Implementation
Changelog from v2:
- Introduce TIF_UPROBE 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 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 introduce interrupt based handlers at a later time.)
- 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 | 21 + kernel/uprobes.c | 681 ++++++++++++++++++++++++++++++++++++ 10 files changed, 903 insertions(+), 0 deletions(-) create mode 100644 include/linux/uprobes.h create mode 100644 kernel/uprobes.c
arch/Kconfig +13 -0
@@ -58,6 +58,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
@@ -109,6 +119,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 */
@@ -107,6 +108,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
@@ -1053,6 +1053,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
@@ -12,6 +12,7 @@#include <linux/completion.h> #include <linux/cpumask.h> #include <linux/page-debug-flags.h> +#include <linux/uprobes.h> #include <asm/page.h> #include <asm/mmu.h>
@@ -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 info */ +#endif };/* Future-safe accessor for struct mm_struct's cpu_vm_mask. */
include/linux/sched.h +3 -0
@@ -1498,6 +1498,9 @@ struct task_struct { unsigned long memsw_bytes; /* uncharged mem+swap usage */ } memcg_batch;#endif +#ifdef CONFIG_UPROBES +struct uprobe_task *utask; +#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 +21 -0
@@ -187,6 +187,11 @@ void __put_task_struct(struct task_struct *tsk)delayacct_tsk_free (tsk);put_signal_struct (tsk->signal); +#ifdef CONFIG_UPROBES +if (unlikely (tsk->utask)) +uprobe_free_utask (tsk); +#endif +if (!profile_handoff_task (tsk))free_task (tsk); }
@@ -522,6 +527,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);
@@ -680,6 +689,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:
@@ -1186,6 +1198,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 */
@@ -1284,6 +1299,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
Re: [PATCH v5 6/14] Uprobes Implementation
arch/Kconfig config USER_BKPT · line 63
Quoted 11 lines · On Mon, 14 Jun 2010 13:59:03 +0530 Srikar Dronamraju wrote:
arch/Kconfig +3
-0@@ -58,6 +58,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 having CONFIG_MODULES enabled. Please explain.
arch/Kconfig config USER_BKPT · line 73
Quoted 10 lines
arch/Kconfig +7
-0+ 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
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
Re: [PATCH v5 6/14] Uprobes Implementation
Quoted 10 lines · Randy Dunlap
Quoted 8 lines · On Mon, 14 Jun 2010 13:59:03 +0530 Srikar Dronamraju wrote:
arch/Kconfig +0
-0@@ -58,6 +58,16 @@ config USER_BKPT This service is used by components such as uprobes. If in doubt, say "N".
Quoted 6 lines
arch/Kconfig config USER_BKPT · line 63
Quoted 3 lines
arch/Kconfig +3
-0+config UPROBES + bool "User-space probes (EXPERIMENTAL)" + depends on MODULES && USER_BKPT_XOLdepends on having
CONFIG_MODULESenabled. Please explain.
As Christoph suggested, I will remove the samples and hence the dependency on CONFIG_MODULES.
PATCH v5 7/14 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
@@ -55,6 +55,7 @@ config X86 select HAVE_HW_BREAKPOINT select HAVE_MIXED_BREAKPOINTS_REGS select HAVE_USER_BKPT + select HAVE_UPROBES select PERF_EVENTS select HAVE_PERF_EVENTS_NMI select ANON_INODES
arch/x86/kernel/Makefile +1 -0
@@ -116,6 +116,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
Re: [PATCH v5 7/14] x86 support for Uprobes
Quoted 7 lines · Srikar Dronamraju
arch/x86/kernel/signal.c +3
-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
arch/x86/kernel/signal.c do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) · line 865
Quoted 10 lines
arch/x86/kernel/signal.c +9
-0+* 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
I'm no x86 port guru, but this looks rather worriesome to me. Why does do_notify_resume have different calling conventions on 32 vs 64-bit? And if there is a good reason that 32-bit has them disabled, why is enabling them in the middle of do_notify_resume okay?
arch/x86/kernel/uprobes.c line 77
Quoted 7 lines
arch/x86/kernel/uprobes.c new file +7
-0+void arch_uprobe_disable_sstep (struct pt_regs *regs) +{ +/* Disable single-stepping by clearing what we set */ +clear_thread_flag (TIF_SINGLESTEP ); +clear_thread_flag (TIF_FORCED_TF ); + regs->flags &= ~X86_EFLAGS_TF ; +}
This seems to have one layer of indentation too much.
Re: [PATCH v5 7/14] x86 support for Uprobes
Quoted 15 lines · Christoph Hellwig
Quoted 14 lines · Srikar Dronamraju
arch/x86/kernel/signal.c +9
-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); +
Quoted 8 lines
arch/x86/kernel/signal.c do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) · line 865
Quoted 3 lines
arch/x86/kernel/signal.c +3
-0+#ifdef CONFIG_X86_32 +native_irq_disable (); +#endif I'm no x86 port guru, but this looks rather worriesome to me. Why does
do_notify_resumehave different calling conventions on 32 vs 64-bit? And if there is a good reason that 32-bit has them disabled, why is enabling them in the middle ofdo_notify_resumeokay?
Thanks for bringing this up. I have no idea about why do_notify_resume() gets called with interrupts disabled in 32 bit. I would be happy to know the reason and rework based on inputs. I did query a few people about this but I havent got an answer on why we they are disabled on 32 bit and if its Okay to enable at this place.
Ingo, Is there any person whom I could check with to get to know why the interrupts are disabled on x86_32?
Quoted 10 lines
arch/x86/kernel/uprobes.c line 77
Quoted 8 lines
arch/x86/kernel/uprobes.c new file +7
-0+void arch_uprobe_disable_sstep (struct pt_regs *regs) +{ +/* Disable single-stepping by clearing what we set */ +clear_thread_flag (TIF_SINGLESTEP ); +clear_thread_flag (TIF_FORCED_TF ); + regs->flags &= ~X86_EFLAGS_TF ; +}This seems to have one layer of indentation too much.
Okay, I shall fix this in the next iteration.
--
Thanks and Regards
Srikar
Oleg Nesterov
maintainerRe: [PATCH v5 7/14] x86 support for Uprobes
Quoted 27 lines · Srikar Dronamraju
Quoted 15 lines · Christoph Hellwig
Quoted 14 lines · Srikar Dronamraju
arch/x86/kernel/signal.c +9
-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); +Quoted 8 lines
arch/x86/kernel/signal.c do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) · line 865
Quoted 3 lines
arch/x86/kernel/signal.c +3
-0+#ifdef CONFIG_X86_32 +native_irq_disable (); +#endif I'm no x86 port guru, but this looks rather worriesome to me. Why does
do_notify_resumehave different calling conventions on 32 vs 64-bit? And if there is a good reason that 32-bit has them disabled, why is enabling them in the middle ofdo_notify_resumeokay?
Quoted 2 lines
Thanks for bringing this up. I have no idea about why
do_notify_resume()gets called with interrupts disabled in 32 bit.
Perhaps just because there is no reason to explicitly enable irqs?
Quoted 4 lines
I would be happy to know
the reason and rework based on inputs. I did query a few people about this but I havent got an answer on why we they are disabled on 32 bit and if its Okay to enable at this place.
I think it is OK to enable interrupts. do_notify_resume() calls do_signal() which enables them anyway.
But there is another question I already asked. Why the code uses native_irq_enable()? IIRC, you explained that local_irq_enable() doesn't work for unkown reason. This is strange, and imho should be explained.
And I do not see a need to disable irqs again.
Oleg.
Re: [PATCH v5 7/14] x86 support for Uprobes
Quoted 16 lines
Quoted 8 lines
Quoted 5 lines
I'm no x86 port guru, but this looks rather worriesome to me. Why does
do_notify_resumehave different calling conventions on 32 vs 64-bit? And if there is a good reason that 32-bit has them disabled, why is enabling them in the middle ofdo_notify_resumeokay?Thanks for bringing this up. I have no idea about why
do_notify_resume()gets called with interrupts disabled in 32 bit.Perhaps just because there is no reason to explicitly enable irqs?
Quoted 4 lines
I would be happy to know
the reason and rework based on inputs. I did query a few people about this but I havent got an answer on why we they are disabled on 32 bit and if its Okay to enable at this place.
Quoted 7 lines
I think it is OK to enable interrupts.
do_notify_resume()callsdo_signal()which enables them anyway.But there is another question I already asked. Why the code uses
native_irq_enable()? IIRC, you explained thatlocal_irq_enable()doesn't work for unkown reason. This is strange, and imho should be explained.
local_irq_enable() translates to raw_local_irq_enable(). However raw_local_irq_enable on x86 seems to depend on CONFIG_PARAVIRT. On a machine, where CONFIG_PARAVIRT was defined, local_irq_enable translates to something other than native_irq_enable.
It translates to PVOP_VCALLEE0(pv_irq_ops.irq_enable);
Is it okay to use local_irq_enable() and then make CONFIG_UPROBES depend on !CONFIG_PARAVIRT?
Quoted 4 lines
And I do not see a need to disable irqs again.
Oleg.
Oleg Nesterov
maintainerRe: [PATCH v5 7/14] x86 support for Uprobes
Quoted 8 lines · Srikar Dronamraju
Quoted 7 lines
I think it is OK to enable interrupts.
do_notify_resume()callsdo_signal()which enables them anyway.But there is another question I already asked. Why the code uses
native_irq_enable()? IIRC, you explained thatlocal_irq_enable()doesn't work for unkown reason. This is strange, and imho should be explained.
Quoted 5 lines
local_irq_enable()translates toraw_local_irq_enable(). Howeverraw_local_irq_enableon x86 seems to depend onCONFIG_PARAVIRT. On a machine, whereCONFIG_PARAVIRTwas defined,local_irq_enabletranslates to something other thannative_irq_enable.
It translates toPVOP_VCALLEE0(pv_irq_ops.irq_enable);
I see, and my question is why PVOP_VCALLEE0(pv_irq_ops.irq_enable) doesn't work ? If it doesn't here, why it works for other callers of local_irq_enable?
I think we should ask paravirt developers.
Quoted 2 lines
Is it okay to use
local_irq_enable()and then makeCONFIG_UPROBESdepend on !CONFIG_PARAVIRT?
I dunno, and I know nothing about paravirt.
But please note that currently native_irq_enable has the only caller, raw_local_irq_enable(). It is really strange that do_notify_resume() has to use it, and it uses it to bypass the paravirt layer which perhaps can introduce other problems.
Oleg.
Steven Rostedt
maintainerRe: [PATCH v5 7/14] x86 support for Uprobes
In reply to Srikar DronamrajuQuoted 9 lines · Srikar Dronamraju
local_irq_enable()translates toraw_local_irq_enable(). Howeverraw_local_irq_enableon x86 seems to depend onCONFIG_PARAVIRT. On a machine, whereCONFIG_PARAVIRTwas defined,local_irq_enabletranslates to something other thannative_irq_enable.
It translates toPVOP_VCALLEE0(pv_irq_ops.irq_enable);Is it okay to use
local_irq_enable()and then makeCONFIG_UPROBESdepend on !CONFIG_PARAVIRT?
It should still work under paravirt. If it does not, we need to figurure out why.
On boot up, when CONFIG_PARAVIRT is set but the kernel is running on bare metal, a lot of the calls to things like "pv_irq_ops.irq_enabled" are converted to the native caller anyway. Perhaps the conversion messed up?
-- Steve
PATCH v5 8/14 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
Re: [PATCH v5 8/14] samples: Uprobes samples
Quoted 4 lines · Srikar Dronamraju
samples.patch
From: Srikar Dronamraju <[email protected]>
Quoted 8 lines
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.
What's the point of this sample? It's a sub-set of what the perf uprobes inteface supports, and writing kernel modules to probe userspace code is braindead to start with. So if you remove this example of what people should not do we can also get rid of all the exports.
PATCH v5 9/14 Uprobes documentation.
In reply to Srikar Dronamrajuuprobes-documentation.patch
From: Srikar Dronamraju <[email protected]>
Changelog from v3: Updated measurements.
Changelog from v2: Updated measurements.
Changelog from v1: Addressed comments from Randy Dunlap.
: Updated measurements.
---
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.000687 sec i.e 0.006870 usec per iteration + +With probes +100000 interations in 0.314938 sec i.e 3.149380 usec per iteration +probe overhead is 3.142510 usec per probe hit. + +x86_64: Intel(R) Xeon(R) CPU X7350 @ 2.93GHz +Without probe module. +100000 interations in 0.000432 sec i.e 0.004320 usec per iteration + +With probes +100000 interations in 0.101276 sec i.e 1.012760 usec per iteration +Probe overhead is 1.301738 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 v5 10/14 trace: Common code for kprobes/uprobes traceevents
In reply to Srikar Dronamrajushare_traceevents.patch.
From: Srikar Dronamraju <[email protected]>
Changelog from v5: Addressed comments from Masami.
Also shared lot more code from kprobes traceevents.
Move common parts of trace_kprobe.c and trace_uprobec. Adjust kernel/trace/trace_kprobe.c after moving common code to kernel/trace/trace_probe.h. However they still have few duplicate functions.
TODO: Merge both events to a single probe event.
---
kernel/trace/trace_kprobe.c | 141 +-------------------------------------- kernel/trace/trace_probe.h | 157 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+), 137 deletions(-) create mode 100644 kernel/trace/trace_probe.h
kernel/trace/trace_kprobe.c +4 -137
@@ -20,32 +20,12 @@#include <linux/module.h> #include <linux/uaccess.h> #include <linux/kprobes.h> -#include <linux/seq_file.h> -#include <linux/slab.h> -#include <linux/smp.h> -#include <linux/debugfs.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/ctype.h> -#include <linux/ptrace.h> -#include <linux/perf_event.h> -#include <linux/stringify.h> -#include <asm/bitsperlong.h> - -#include "trace.h" -#include "trace_output.h" - -#define MAX_TRACE_ARGS 128 -#define MAX_ARGSTR_LEN 63 -#define MAX_EVENT_NAME_LEN 64 -#define KPROBE_EVENT_SYSTEM "kprobes" -/* Reserved field names */ -#define FIELD_STRING_IP "__probe_ip" -#define FIELD_STRING_RETIP "__probe_ret_ip" -#define FIELD_STRING_FUNC "__probe_func" +#include "trace_probe.h" + +#define KPROBE_EVENT_SYSTEM "kprobes" -const char *reserved_field_names[] = { +static const char *reserved_field_names[] = {"common_type" ,"common_flags" ,"common_preempt_count" ,
@@ -57,70 +37,9 @@ const char *reserved_field_names[] = {FIELD_STRING_FUNC , }; -/* Printing function type */ -typedef int (*print_type_func_t )(struct trace_seq *,const char *,void *); -#define PRINT_TYPE_FUNC_NAME (type) print_type_##type -#define PRINT_TYPE_FMT_NAME (type) print_type_format_##type - -/* Printing in basic type function template */ -#define DEFINE_BASIC_PRINT_TYPE_FUNC (type, fmt, cast) \ -static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ - const char *name, void *data)\ -{ \ - return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\ -} \ -static const char PRINT_TYPE_FMT_NAME(type)[] = fmt; - -DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int) -DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int) -DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long) -DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long) -DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int) -DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int) DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long) DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long) -/* Data fetch function type */ -typedef void (*fetch_func_t )(struct pt_regs *,void *,void *); - -struct fetch_param { -fetch_func_t fn; -void *data; -}; - -static __kprobes void call_fetch (struct fetch_param *fprm, -struct pt_regs *regs,void *dest) -{ -return fprm->fn (regs, fprm->data, dest); -} - -#define FETCH_FUNC_NAME (kind, type) fetch_##kind##_##type -/* -* Define macro for basic types - we don't need to define s* types, because -* we have to care only about bitwidth at recording time. -*/ -#define DEFINE_BASIC_FETCH_FUNCS (kind) \ -DEFINE_FETCH_##kind(u8) \ -DEFINE_FETCH_##kind(u16) \ -DEFINE_FETCH_##kind(u32) \ -DEFINE_FETCH_##kind(u64) - -#define CHECK_BASIC_FETCH_FUNCS (kind, fn) \ - ((FETCH_FUNC_NAME(kind, u8) == fn) || \ - (FETCH_FUNC_NAME(kind, u16) == fn) || \ - (FETCH_FUNC_NAME(kind, u32) == fn) || \ - (FETCH_FUNC_NAME(kind, u64) == fn)) - -/* Data fetch function templates */ -#define DEFINE_FETCH_reg (type) \ -static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \ - void *offset, void *dest) \ -{ \ - *(type *)dest = (type)regs_get_register(regs, \ - (unsigned int)((unsigned long)offset)); \ -} -DEFINE_BASIC_FETCH_FUNCS (reg) -#define DEFINE_FETCH_stack (type) \ static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ void *offset, void *dest) \
@@ -234,15 +153,6 @@ static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data)kfree (data); } -/* Default (unsigned long) fetch type */ -#define __DEFAULT_FETCH_TYPE (t) u##t -#define _DEFAULT_FETCH_TYPE (t) __DEFAULT_FETCH_TYPE(t) -#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG) -#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) - -#define ASSIGN_FETCH_FUNC (kind, type) \ - .kind = FETCH_FUNC_NAME(kind, type) -#define ASSIGN_FETCH_TYPE (ptype, ftype, sign) \ {.name = #ptype, \ .size = sizeof(ftype), \
@@ -306,18 +216,6 @@ static __kprobes void fetch_stack_address(struct pt_regs *regs,* Kprobe event core functions */ -struct probe_arg { -struct fetch_param fetch; -unsigned int offset;/* Offset from argument entry */ -const char *name;/* Name of this argument */ -const char *comm;/* Command of this argument */ -const struct fetch_type *type;/* Type of this argument */ -}; - -/* Flags for trace_probe */ -#define TP_FLAG_TRACE 1 -#define TP_FLAG_PROFILE 2 -struct trace_probe {struct list_head list;struct kretprobe rp;/* Use rp.kp for kprobe use */
@@ -355,19 +253,6 @@ static LIST_HEAD(probe_list);static int kprobe_dispatcher (struct kprobe *kp,struct pt_regs *regs);static int kretprobe_dispatcher (struct kretprobe_instance *ri,struct pt_regs *regs); - -/* Check the name is good for event/group */ -static int check_event_name (const char *name) -{ -if (!isalpha (*name) && *name !='_' ) -return 0 ; -while (*++name !='\0' ) { -if (!isalpha (*name) && !isdigit (*name) && *name !='_' ) -return 0 ; - } -return 1 ; -} -/* * Allocate new trace_probe and initialize it (including kprobes). */
@@ -537,8 +422,6 @@ static int split_symbol_offset(char *symbol, unsigned long *offset)return 0 ; } -#define PARAM_MAX_ARGS 16 -#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))static int parse_probe_vars (char *arg,const struct fetch_type *t,struct fetch_param *f,int is_return)
@@ -1214,22 +1097,6 @@ static void probe_event_disable(struct ftrace_event_call *call) } } -static int probe_event_raw_init (struct ftrace_event_call *event_call) -{ -return 0 ; -} - -#undef DEFINE_FIELD -#define DEFINE_FIELD (type, item, name, is_signed) \ - do { \ - ret = trace_define_field(event_call, #type, name, \ - offsetof(typeof(field), item), \ - sizeof(field.item), is_signed, \ - FILTER_OTHER); \ - if (ret) \ - return ret; \ - } while (0) -static int kprobe_event_define_fields (struct ftrace_event_call *event_call) {int ret, i;
kernel/trace/trace_probe.h new file +157 -0
157 lines not on this page · raw message
Re: [PATCH v5 10/14] trace: Common code for kprobes/uprobes traceevents
Quoted 11 lines · Srikar Dronamraju
share_traceevents.patch.
From: Srikar Dronamraju <[email protected]>
Changelog from v5: Addressed comments from Masami.
Also shared lot more code from kprobes traceevents.Move common parts of
trace_kprobe.candtrace_uprobec. Adjustkernel/trace/trace_kprobe.cafter moving common code tokernel/trace/trace_probe.h. However they still have few duplicate functions.
Hi Shriker,
OK, sharing fetch codes between them is acceptable.
Quoted 5 lines
kernel/trace/trace_probe.h new file +0
-0
[...]
Quoted 5 lines
kernel/trace/trace_probe.h new file +5
-0+/* Printing in basic type function template */ +#define DEFINE_BASIC_PRINT_TYPE_FUNC (type, fmt, cast) \ +static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ + const char *name, void *data)\ +{ \
kernel/trace/trace_probe.h line 75
Quoted 10 lines
kernel/trace/trace_probe.h new file +10
-0+return trace_seq_printf (s," %s=" fmt, name, (cast)*(type *)data);\ +} \ +static const char PRINT_TYPE_FMT_NAME (type )[] = fmt; + +DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int) +DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int) +DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long) +DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long) +DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int) +DEFINE_BASIC_PRINT_TYPE_FUNC (s16,"%d" , int)
Please do NOT define static variables in header file... It should be in trace_probe_common.c.
Quoted 34 lines
kernel/trace/trace_probe.h new file +34
-0+ +/* Data fetch function type */ +typedef void (*fetch_func_t )(struct pt_regs *,void *,void *); + +struct fetch_param { +fetch_func_t fn; +void *data; +}; + +#define FETCH_FUNC_NAME (kind, type) fetch_##kind##_##type +/* +* Define macro for basic types - we don't need to define s* types, because +* we have to care only about bitwidth at recording time. +*/ +#define DEFINE_BASIC_FETCH_FUNCS (kind) \ +DEFINE_FETCH_##kind(u8) \ +DEFINE_FETCH_##kind(u16) \ +DEFINE_FETCH_##kind(u32) \ +DEFINE_FETCH_##kind(u64) + +#define CHECK_BASIC_FETCH_FUNCS (kind, fn) \ + ((FETCH_FUNC_NAME(kind, u8) == fn) || \ + (FETCH_FUNC_NAME(kind, u16) == fn) || \ + (FETCH_FUNC_NAME(kind, u32) == fn) || \ + (FETCH_FUNC_NAME(kind, u64) == fn)) + +/* Data fetch function templates */ +#define DEFINE_FETCH_reg (type) \ +static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \ + void *offset, void *dest) \ +{ \ + *(type *)dest = (type)regs_get_register(regs, \ + (unsigned int)((unsigned long)offset)); \ +}
kernel/trace/trace_probe.h line 119
Quoted 10 lines
kernel/trace/trace_probe.h new file +10
-0+DEFINE_BASIC_FETCH_FUNCS (reg) + +/* Default (unsigned long) fetch type */ +#define __DEFAULT_FETCH_TYPE (t) u##t +#define _DEFAULT_FETCH_TYPE (t) __DEFAULT_FETCH_TYPE(t) +#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG) +#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) + +#define ASSIGN_FETCH_FUNC (kind, type) \ + .kind = FETCH_FUNC_NAME(kind, type)
And, please do not split these macros and function bodies. I think we should make a new .c and put them into there. Maybe, we need a new interface for generating new fetch_arg according to its type (and access region, user/kernel).
Quoted 28 lines
kernel/trace/trace_probe.h new file +28
-0+ +/* Flags for trace_probe */ +#define TP_FLAG_TRACE 1 +#define TP_FLAG_PROFILE 2 + +#define PARAM_MAX_ARGS 16 +#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) + +struct probe_arg { +struct fetch_param fetch; +unsigned int offset;/* Offset from argument entry */ +const char *name;/* Name of this argument */ +const char *comm;/* Command of this argument */ +const struct fetch_type *type;/* Type of this argument */ +}; + +static __kprobes void call_fetch (struct fetch_param *fprm, +struct pt_regs *regs,void *dest) +{ +return fprm->fn (regs, fprm->data, dest); +} + +/* Check the name is good for event/group */ +static inline int check_event_name (const char *name) +{ +if (!isalpha (*name) && *name !='_' ) +return 0 ; +while (*++name !='\0' ) {
kernel/trace/trace_probe.h line 157
Quoted 10 lines
kernel/trace/trace_probe.h new file +10
-0+if (!isalpha (*name) && !isdigit (*name) && *name !='_' ) +return 0 ; + } +return 1 ; +} + +static int probe_event_raw_init (struct ftrace_event_call *event_call) +{ +return 0 ; +}
Exporting these interfaces are OK.
Thank you,
Steven Rostedt
maintainerRe: [PATCH v5 10/14] trace: Common code for kprobes/uprobes traceevents
In reply to Srikar DronamrajuQuoted 37 lines · Srikar Dronamraju
share_traceevents.patch.
From: Srikar Dronamraju <[email protected]>
Changelog from v5: Addressed comments from Masami.
Also shared lot more code from kprobes traceevents.Move common parts of
trace_kprobe.candtrace_uprobec. Adjustkernel/trace/trace_kprobe.cafter moving common code tokernel/trace/trace_probe.h. However they still have few duplicate functions.TODO: Merge both events to a single probe event.
Signed-off-by Srikar Dronamraju <[email protected]>---
kernel/trace/trace_kprobe.c | 141 +-------------------------------------- kernel/trace/trace_probe.h | 157 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+), 137 deletions(-) create mode 100644 kernel/trace/trace_probe.hkernel/trace/trace_probe.h new file +8
-0@@ -0,0 +1,157 @@ +/* +* Common header file for probe-based Dynamic events. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful,
kernel/trace/trace_probe.h line 18
Quoted 10 lines
kernel/trace/trace_probe.h new file +10
-0+* 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, 2010 +* Author: Srikar Dronamraju
Note, when moving stuff from one file to another, you still need to keep the copyright and author of the original file. You can add your name and copyright as well, when you add your stuff to it.
-- Steve
Re: [PATCH v5 10/14] trace: Common code for kprobes/uprobes traceevents
Quoted 44 lines · Steven Rostedt
Quoted 43 lines · Srikar Dronamraju
share_traceevents.patch.
From: Srikar Dronamraju <[email protected]>
Changelog from v5: Addressed comments from Masami.
Also shared lot more code from kprobes traceevents.Move common parts of
trace_kprobe.candtrace_uprobec. Adjustkernel/trace/trace_kprobe.cafter moving common code tokernel/trace/trace_probe.h. However they still have few duplicate functions.TODO: Merge both events to a single probe event.
Signed-off-by Srikar Dronamraju <[email protected]>---
kernel/trace/trace_kprobe.c | 141 +-------------------------------------- kernel/trace/trace_probe.h | 157 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+), 137 deletions(-) create mode 100644 kernel/trace/trace_probe.hkernel/trace/trace_probe.h new file +14
-0@@ -0,0 +1,157 @@ +/* +* Common header file for probe-based Dynamic events. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* 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
Quoted 8 lines
kernel/trace/trace_probe.h line 18
Quoted 4 lines
kernel/trace/trace_probe.h new file +4
-0+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* Copyright (C) IBM Corporation, 2010 +* Author: Srikar Dronamraju Note, when moving stuff from one file to another, you still need to keep the copyright and author of the original file. You can add your name and copyright as well, when you add your stuff to it.
Okay .. will modify as suggested by you.
--
Thanks and Regards
Srikar
Quoted 4 lines
-- Steve
PATCH v5 11/14 trace: uprobes trace_event interface
In reply to Srikar DronamrajuChangelog from v4: (Merged to 2.6.35-rc3-tip)
From: Srikar Dronamraju <[email protected]>
Changelog from v2/v3: (Addressing comments from Steven Rostedt
and Frederic Weisbecker)
* removed pit field from uprobe_trace_entry.
* share common parts with kprobe trace events.
* use trace_create_file instead of debugfs_create_file.
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.
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 6016]
[Address to trace is 0x0000000000446420] [Registers to be dumped are %ip and %ax]
# cd /sys/kernel/debug/tracing/
# echo 'p 6016:0x0000000000446420 %ip %ax' > uprobe_events
# cat uprobe_events
p:uprobes/p_6016_0x0000000000446420 6016:0x0000000000446420 %ip=%ip %ax=%ax
# cat events/uprobes/p_6016_0x0000000000446420/enable
0
[enable the event]
# echo 1 > events/uprobes/p_6016_0x0000000000446420/enable
# cat events/uprobes/p_6016_0x0000000000446420/enable
1
# #### do some activity on the program so that it hits the breakpoint
# cat uprobe_profile
6016 p_6016_0x0000000000446420 234
# tracer: nop
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
zsh-6016 [004] 227931.093579: p_6016_0x0000000000446420: (0x446420) %ip=446421 %ax=79
zsh-6016 [005] 227931.097541: p_6016_0x0000000000446420: (0x446420) %ip=446421 %ax=79
zsh-6016 [000] 227931.124909: p_6016_0x0000000000446420: (0x446420) %ip=446421 %ax=79
zsh-6016 [001] 227933.128565: p_6016_0x0000000000446420: (0x446420) %ip=446421 %ax=79
zsh-6016 [004] 227933.132756: p_6016_0x0000000000446420: (0x446420) %ip=446421 %ax=79
zsh-6016 [000] 227933.158802: p_6016_0x0000000000446420: (0x446420) %ip=446421 %ax=79
zsh-6016 [001] 227935.161602: p_6016_0x0000000000446420: (0x446420) %ip=446421 %ax=79
zsh-6016 [004] 227935.165229: p_6016_0x0000000000446420: (0x446420) %ip=446421 %ax=79TODO: Documentation/trace/uprobetrace.txt
---
kernel/trace/Kconfig | 13 + kernel/trace/Makefile | 1 kernel/trace/trace.h | 5 kernel/trace/trace_probe.h | 2 kernel/trace/trace_uprobe.c | 921 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 942 insertions(+), 0 deletions(-) create mode 100644 kernel/trace/trace_uprobe.c
kernel/trace/Kconfig +13 -0
@@ -509,6 +509,19 @@ 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 on top of userspace dynamic + events (similar to tracepoints) on the fly via the traceevents interface. + Those events can be inserted wherever uprobes can probe, and record + various registers. + This option is required if you plan to use perf-probe subcommand of perf + tools on user space applications. + endif # FTRACE endif # TRACING_SUPPORT
kernel/trace/Makefile +1 -0
@@ -55,5 +55,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 +5 -0
@@ -99,6 +99,11 @@ struct kretprobe_trace_entry_head {unsigned long ret_ip; }; +struct uprobe_trace_entry_head { +struct trace_entry ent; +unsigned long ip; +}; +/* * trace_flag_type is an enumeration that holds different * states when a trace occurs. These are:
kernel/trace/trace_probe.h +2 -0
@@ -39,6 +39,7 @@#define FIELD_STRING_IP "__probe_ip"#define FIELD_STRING_RETIP "__probe_ret_ip"#define FIELD_STRING_FUNC "__probe_func" +#define FIELD_STRING_PID "__probe_pid"#define WRITE_BUFSIZE 128
@@ -121,6 +122,7 @@ DEFINE_BASIC_FETCH_FUNCS(reg)/* Flags for trace_probe */ #define TP_FLAG_TRACE 1#define TP_FLAG_PROFILE 2 +#define TP_FLAG_UPROBE 4#define PARAM_MAX_ARGS 16#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
kernel/trace/trace_uprobe.c new file +921 -0
921 lines not on this page · raw message
Steven Rostedt
maintainerRe: [PATCH v5 11/14] trace: uprobes trace_event interface
kernel/trace/Kconfig config RING_BUFFER_BENCHMARK · line 516
Quoted 5 lines · Srikar Dronamraju
kernel/trace/Kconfig +5
-0+config UPROBE_EVENT + depends on UPROBES + bool "Enable uprobes-based dynamic events" + select TRACING + default y
Why is this default y?
-- Steve
Quoted 11 lines
kernel/trace/Kconfig +8
-0+ help + This allows the user to add tracing events on top of userspace dynamic + events (similar to tracepoints) on the fly via the traceevents interface. + Those events can be inserted wherever uprobes can probe, and record + various registers. + This option is required if you plan to use perf-probe subcommand of perf + tools on user space applications. + endif # FTRACE
Re: [PATCH v5 11/14] trace: uprobes trace_event interface
Quoted 8 lines
kernel/trace/Kconfig config RING_BUFFER_BENCHMARK · line 516
Quoted 6 lines
kernel/trace/Kconfig +5
-0+config UPROBE_EVENT + depends on UPROBES + bool "Enable uprobes-based dynamic events" + select TRACING + default yWhy is this default y?
As you see UPROBE_EVENT is gated on UPROBES. I think if UPROBES is enabled, then UPROBE_EVENT should be enabled. Esp with Christoph suggesting for module support to be removed, I think it becomes all the more reason for UPROBE_EVENT to be enabled by default. Otherwise there is no point in having uprobes code and having no enabled users. I was even looking at "select UPROBE_EVENT" on enabling UPROBES.
Do you have any specific reason why UPROBE_EVENT should not be enabled by default?
--
Thanks and Regards
Srikar
Re: [PATCH v5 11/14] trace: uprobes trace_event interface
Quoted 9 lines · Srikar Dronamraju
As you see
UPROBE_EVENTis gated on UPROBES. I think if UPROBES is enabled, thenUPROBE_EVENTshould be enabled. Esp with Christoph suggesting for module support to be removed, I think it becomes all the more reason forUPROBE_EVENTto be enabled by default. Otherwise there is no point in having uprobes code and having no enabled users. I was even looking at "selectUPROBE_EVENT" on enabling UPROBES.Do you have any specific reason why
UPROBE_EVENTshould not be enabled by default?
default y generally is a big hammer. But given that it depends on UPROBES it might be fine here. Then again the big question is why we even bother with separate config options? At least in this form UPROBES just is supported for UPROBE_EVENT. So it makes sense either to remove the UPROBES option entirely, or at least make it invisible to the user and let UPROBE_EVENT select it.
PATCH v5 12/14 perf: Dont adjust symbols on name lookup
In reply to Srikar Dronamrajuperf_adjust_symbol_name.patch
From: Srikar Dronamraju <[email protected]>
Adjusting symbols is not needed if we are searching by name even if the symbols correspond to user space objects. Infact if we adjust and search symbols by name, we get incorrect results.
---
tools/perf/util/symbol.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
tools/perf/util/symbol.c +4 -2
@@ -992,12 +992,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 ==DSO_TYPE_USER ) { +if (self->kernel !=DSO_TYPE_USER || 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;
PATCH v5 13/14 perf: Re-Add make_absolute_path
In reply to Srikar Dronamrajurevert_make_absolute_path.patch
From: Srikar Dronamraju <[email protected]>
perf probe for uprobes would use make_absolute_path. make_absolute_path can be used to convert a file name to a dso name.
so if user specifies the function to be traced as malloc@/lib/libc.so.6 it needs to be converted to [email protected]
This patch reverts a part of a41794cdd7ee94a5199e14f642c26d649d383fa5
---
tools/perf/util/abspath.c | 81 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/cache.h | 1 + 2 files changed, 82 insertions(+), 0 deletions(-)
tools/perf/util/abspath.c +81 -0
@@ -1,5 +1,86 @@#include "cache.h" +/* +* Do not use this for inspecting *tracked* content. When path is a +* symlink to a directory, we do not want to say it is a directory when +* dealing with tracked content in the working tree. +*/ +static int is_directory (const char *path) +{ +struct stat st; +return (!stat (path, &st) &&S_ISDIR (st.st_mode)); +} + +/* We allow "recursive" symbolic links. Only within reason, though. */ +#define MAXDEPTH 5 + +const char *make_absolute_path (const char *path) +{ +static char bufs[2 ][PATH_MAX +1 ], *buf = bufs[0 ], *next_buf = bufs[1 ]; +char cwd[1024 ] ="" ; +int buf_index =1 , len; + +int depth =MAXDEPTH ; +char *last_elem =NULL ; +struct stat st; + +if (strlcpy (buf, path,PATH_MAX ) >=PATH_MAX ) +die ("Too long path: %.*s" ,60 , path); + +while (depth--) { +if (!is_directory (buf)) { +char *last_slash =strrchr (buf,'/' ); +if (last_slash) { + *last_slash ='\0' ; + last_elem =xstrdup (last_slash +1 ); + }else { + last_elem =xstrdup (buf); + *buf ='\0' ; + } + } + +if (*buf) { +if (!*cwd && !getcwd (cwd,sizeof (cwd))) +die ("Could not get current working directory" ); + +if (chdir (buf)) +die ("Could not switch to '%s'" , buf); + } +if (!getcwd (buf,PATH_MAX )) +die ("Could not get current working directory" ); + +if (last_elem) { + len =strlen (buf); + +if (len +strlen (last_elem) +2 >PATH_MAX ) +die ("Too long path name: '%s/%s'" , + buf, last_elem); + buf[len] ='/' ; +strcpy (buf + len +1 , last_elem); +free (last_elem); + last_elem =NULL ; + } + +if (!lstat (buf, &st) &&S_ISLNK (st.st_mode)) { + len =readlink (buf, next_buf,PATH_MAX ); +if (len <0 ) +die ("Invalid symlink: %s" , buf); +if (PATH_MAX <= len) +die ("symbolic link too long: %s" , buf); + next_buf[len] ='\0' ; + buf = next_buf; + buf_index =1 - buf_index; + next_buf = bufs[buf_index]; + }else +break ; + } + +if (*cwd &&chdir (cwd)) +die ("Could not change back to '%s'" , cwd); + +return buf; +} +static const char *get_pwd_cwd (void ) {static char cwd[PATH_MAX +1 ];
tools/perf/util/cache.h +1 -0
@@ -73,6 +73,7 @@ static inline int is_absolute_path(const char *path)return path[0 ] =='/' ; } +const char *make_absolute_path (const char *path);const char *make_nonrelative_path (const char *path);char *strip_path_suffix (const char *path,const char *suffix);
PATCH v5 14/14 perf: perf interface for uprobes.
In reply to Srikar Dronamrajuperf-events.patch
From: Srikar Dronamraju <[email protected]>
Changelog from v4: Merged to 2.6.35-rc3-tip.
This patch enhances perf probe to accept pid and user vaddr. This patch provides very basic support for uprobes.
Changelog from v3: (addressed comments from Masami Hiramatsu)
* Every process id has a different group name.
* event name starts with function name.
* If vaddr is specified, event name has vaddr appended along with function name, (this is to avoid subsequent probes using same event name.)
* warning if -p and --list options are used together.
Also dso can either be a short name or absolute path.
TODO:
Update perf-probes.txt.
Global tracing.
Here is a terminal snapshot of placing, using and removing a probe on a process with pid 3591 (corresponding to zsh)
[ Probing a function in the executable using function name ]
-------------------------------------------------------------
[root@ABCD]# perf probe -p 3591 zfree@zsh Added new event: probe_3591:zfree (on 0x446420)
You can now use it on all perf tools, such as:
perf record -e probe_3591:zfree -a sleep 1
[root@ABCD]# perf probe --list probe_3591:zfree (on 3591:0x0000000000446420) [root@ABCD]# cat /sys/kernel/debug/tracing/uprobe_events p:probe_3591/zfree 3591:0x0000000000446420 [root@ABCD]# perf record -f -e probe_3591: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 3591 --del probe_3591:zfree Remove event: probe_3591: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 3591 zfree@zsh+5 Added new event: probe_3591:zfree (on 0x446425)
You can now use it on all perf tools, such as:
perf record -e probe_3591:zfree -a sleep 1
[root@ABCD]# perf probe --list probe_3591:zfree (on 3591:0x0000000000446425) [root@ABCD]# cat /sys/kernel/debug/tracing/uprobe_events p:probe_3591/zfree 3591:0x0000000000446425 [root@ABCD]# perf record -f -e probe_3591: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 3591 --del probe_3591:zfree Remove event: probe_3591: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 3591 [email protected] Added new event: probe_3591:write (on 0x36010c6060)
You can now use it on all perf tools, such as:
perf record -e probe_3591:write -a sleep 1
[root@ABCD]# perf probe --list probe_3591:write (on 3591:0x00000036010c6060) [root@ABCD]# cat /sys/kernel/debug/tracing/uprobe_events p:probe_3591/write 3591:0x00000036010c6060 [root@ABCD]# perf record -f -e probe_3591: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 3591 --del probe_3591:write Remove event: probe_3591: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) #
[ Probing a library function using function name and absolute path ]
---------------------------------------------------------------------
[root@ABCD]# perf probe -p 3591 write@/lib64/libc-2.5.so Added new event: probe_3591:write (on 0x36010c6060)
You can now use it on all perf tools, such as:
perf record -e probe_3591:write -a sleep 1
[root@ABCD]# perf probe --list probe_3591:write (on 3591:0x00000036010c6060) [root@ABCD]# cat /sys/kernel/debug/tracing/uprobe_events p:probe_3591/write 3591:0x00000036010c6060 [root@ABCD]# perf record -f -e probe_3591: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 3591 --del probe_3591:write Remove event: probe_3591: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) #
[ Probing using vaddr 0x0000000000446420 (corresponding to zfree)]
-------------------------------------------------------------------
[root@ABCD]# perf probe -p 3591 0x0000000000446420 Added new event: probe_3591:zfree_446420 (on 0x0000000000446420)
You can now use it on all perf tools, such as:
perf record -e probe_3591:zfree_446420 -a sleep 1
[root@ABCD]# perf record -e probe_3591:zfree_446420 -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_3591:zfree_446420 (on 3591:0x0000000000446420) [root@ABCD]# perf list | grep probe probe_3591:zfree_446420 [Tracepoint event] [root@ABCD]# perf probe -p 3591 --del probe_3591:zfree_446420 Remove event: probe_3591:zfree_446420 [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 3591 0x00000036010c6060 dded new event: probe_3591:__GI___libc_write_36010c6060 (on 0x00000036010c6060)
You can now use it on all perf tools, such as:
perf record -e probe_3591:__GI___libc_write_36010c6060 -a sleep 1
[root@ABCD]# perf record -f -e probe_3591:__GI___libc_write_36010c6060 -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]#
[ Probing using a function without specifying a dso (corresponding to zfree)]
-------------------------------------------------------------------
[root@ABCD]# perf probe -p 3591 zfree Added new event: probe_3591:zfree (on 0x0000000000446420)
You can now use it on all perf tools, such as:
perf record -e probe_3591:zfree -a sleep 1
[root@ABCD]# perf record -e probe_3591:zfree -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]#
---
tools/perf/builtin-probe.c | 13 + tools/perf/builtin-top.c | 20 -- tools/perf/util/event.c | 20 ++ tools/perf/util/event.h | 1 tools/perf/util/probe-event.c | 466 ++++++++++++++++++++++++++++------------ tools/perf/util/probe-event.h | 37 +-- tools/perf/util/probe-finder.c | 20 +- tools/perf/util/probe-finder.h | 6 - 8 files changed, 385 insertions(+), 198 deletions(-)
tools/perf/builtin-probe.c +10 -3
@@ -55,6 +55,7 @@ static struct {struct strlist *dellist;struct line_range line_range;int max_probe_points; +pid_t upid; } params;
@@ -73,6 +74,7 @@ static int parse_probe_event(const char *str)/* Parse a perf-probe command into event */ ret =parse_perf_probe_command (str, pev);pr_debug ("%d arguments\n" , pev->nargs); + pev->upid = params.upid;return ret; }
@@ -186,6 +188,8 @@ static const struct option options[] = {OPT__DRY_RUN (&probe_event_dry_run),OPT_INTEGER ('\0' ,"max-probes" , ¶ms.max_probe_points,"Set how many probe points can be found for a probe." ), +OPT_INTEGER ('p' ,"pid" , ¶ms.upid, +"specify a pid for a uprobes based probe" ), OPT_END() };
@@ -223,6 +227,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)pr_err (" Error: Don't use --list with --line.\n" );usage_with_options (probe_usage, options); } +if (params.upid) { +pr_warning (" Error: Don't use --list with --pid.\n" ); +usage_with_options (probe_usage, options); + } ret =show_perf_probe_events ();if (ret <0 ) pr_err(" Error: Failed to show event list. (%d)\n",
@@ -231,7 +239,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) }#ifdef DWARF_SUPPORT -if (params.show_lines) { +if (params.show_lines && !params.upid) {if (params.nevents !=0 || params.dellist) {pr_warning (" Error: Don't use --line with" " --add/--del.\n" );
@@ -246,7 +254,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)#endif if (params.dellist) { - ret =del_perf_probe_events (params.dellist); + ret =del_perf_probe_events (params.dellist, params.upid);strlist__delete (params.dellist);if (ret <0 ) {pr_err (" Error: Failed to delete events. (%d)\n" , ret);
@@ -265,4 +273,3 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) }return 0 ; } -
tools/perf/builtin-top.c +0 -20
@@ -1082,26 +1082,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
@@ -550,6 +550,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, pid_t pid, u64 addr,
tools/perf/util/event.h +1 -0
@@ -154,6 +154,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 +325 -141
842 lines not on this page · raw message
tools/perf/util/probe-event.h +16 -21
@@ -6,34 +6,35 @@extern bool probe_event_dry_run; -/* kprobe-tracer tracing point */ -struct kprobe_trace_point { +/* kprobe-tracer and uprobe-tracer tracing point */ +struct probe_trace_point {char *symbol;/* Base symbol */ unsigned long offset;/* Offset from symbol */ bool retprobe;/* Return probe flag */ }; -/* kprobe-tracer tracing argument referencing offset */ -struct kprobe_trace_arg_ref { -struct kprobe_trace_arg_ref *next;/* Next reference */ +/* probe-tracer tracing argument referencing offset */ +struct probe_trace_arg_ref { +struct probe_trace_arg_ref *next;/* Next reference */ long offset;/* Offset value */ }; -/* kprobe-tracer tracing argument */ -struct kprobe_trace_arg { +/* kprobe-tracer and uprobe-tracer tracing argument */ +struct probe_trace_arg {char *name;/* Argument name */ char *value;/* Base value */ char *type;/* Type name */ -struct kprobe_trace_arg_ref *ref;/* Referencing offset */ +struct probe_trace_arg_ref *ref;/* Referencing offset */ }; -/* kprobe-tracer tracing event (point + arg) */ -struct kprobe_trace_event { +/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */ +struct probe_trace_event {char *event;/* Event name */ char *group;/* Group name */ -struct kprobe_trace_point point;/* Trace point */ +struct probe_trace_point point;/* Trace point */ int nargs;/* Number of args */ -struct kprobe_trace_arg *args;/* Arguments */ +pid_t upid;/* uprobes only */ +struct probe_trace_arg *args;/* Arguments */ };/* Perf probe probing point */
@@ -67,6 +68,7 @@ struct perf_probe_event {char *group;/* Group name */ struct perf_probe_point point;/* Probe point */ int nargs;/* Number of arguments */ +pid_t upid;struct perf_probe_arg *args;/* Arguments */ };
@@ -91,25 +93,18 @@ struct line_range {/* Command string to events */ extern int parse_perf_probe_command (const char *cmd,struct perf_probe_event *pev); -extern int parse_kprobe_trace_command (const char *cmd, -struct kprobe_trace_event *tev);/* Events to command string */ extern char *synthesize_perf_probe_command (struct perf_probe_event *pev); -extern char *synthesize_kprobe_trace_command (struct kprobe_trace_event *tev); +extern char *synthesize_probe_trace_command (struct probe_trace_event *tev);extern int synthesize_perf_probe_arg (struct perf_probe_arg *pa,char *buf,size_t len);/* Check the perf_probe_event needs debuginfo */ extern bool perf_probe_event_need_dwarf (struct perf_probe_event *pev); -/* Convert from kprobe_trace_event to perf_probe_event */ -extern int convert_to_perf_probe_event (struct kprobe_trace_event *tev, -struct perf_probe_event *pev); -/* Release event contents */ extern void clear_perf_probe_event (struct perf_probe_event *pev); -extern void clear_kprobe_trace_event (struct kprobe_trace_event *tev);/* Command string to line-range */ extern int parse_line_range_desc (const char *cmd,struct line_range *lr);
@@ -117,7 +112,7 @@ extern int parse_line_range_desc(const char *cmd, struct line_range *lr);extern int add_perf_probe_events (struct perf_probe_event *pevs,int npevs,bool force_add,int max_probe_points); -extern int del_perf_probe_events (struct strlist *dellist); +extern int del_perf_probe_events (struct strlist *dellist,pid_t pid);extern int show_perf_probe_events (void );extern int show_line_range (struct line_range *lr);
tools/perf/util/probe-finder.c +10 -10
@@ -363,7 +363,7 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf)Dwarf_Word offs =0 ;bool ref = false;const char *regs; -struct kprobe_trace_arg *tvar = pf->tvar; +struct probe_trace_arg *tvar = pf->tvar;/* If this is based on frame buffer, set the offset */ if (op->atom == DW_OP_fbreg) {
@@ -405,7 +405,7 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf)return -ENOMEM ;if (ref) { - tvar->ref =zalloc (sizeof (struct kprobe_trace_arg_ref )); + tvar->ref =zalloc (sizeof (struct probe_trace_arg_ref ));if (tvar->ref ==NULL )return -ENOMEM ; tvar->ref->offset = (long )offs;
@@ -414,7 +414,7 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf) }static int convert_variable_type (Dwarf_Die *vr_die, -struct kprobe_trace_arg *targ) +struct probe_trace_arg *targ) {Dwarf_Die type;char buf[16 ];
@@ -454,10 +454,10 @@ static int convert_variable_type(Dwarf_Die *vr_die,static int convert_variable_fields (Dwarf_Die *vr_die,const char *varname,struct perf_probe_arg_field *field, -struct kprobe_trace_arg_ref **ref_ptr, +struct probe_trace_arg_ref **ref_ptr,Dwarf_Die *die_mem) { -struct kprobe_trace_arg_ref *ref = *ref_ptr; +struct probe_trace_arg_ref *ref = *ref_ptr;Dwarf_Die type;Dwarf_Word offs;int ret;
@@ -486,7 +486,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,return -EINVAL ; } - ref =zalloc (sizeof (struct kprobe_trace_arg_ref )); + ref =zalloc (sizeof (struct probe_trace_arg_ref ));if (ref ==NULL )return -ENOMEM ;if (*ref_ptr)
@@ -618,7 +618,7 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)/* Show a probe point to output buffer */ static int convert_probe_point (Dwarf_Die *sp_die,struct probe_finder *pf) { -struct kprobe_trace_event *tev; +struct probe_trace_event *tev;Dwarf_Addr eaddr;Dwarf_Die die_mem;const char *name;
@@ -683,7 +683,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)/* Find each argument */ tev->nargs = pf->pev->nargs; - tev->args =zalloc (sizeof (struct kprobe_trace_arg ) * tev->nargs); + tev->args =zalloc (sizeof (struct probe_trace_arg ) * tev->nargs);if (tev->args ==NULL )return -ENOMEM ;for (i =0 ; i < pf->pev->nargs; i++) {
@@ -942,7 +942,7 @@ static int find_probe_point_by_func(struct probe_finder *pf)/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ int find_kprobe_trace_events (int fd,struct perf_probe_event *pev, -struct kprobe_trace_event **tevs,int max_tevs) +struct probe_trace_event **tevs,int max_tevs) {struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};struct perf_probe_point *pp = &pev->point;
@@ -952,7 +952,7 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,Dwarf *dbg;int ret =0 ; - pf.tevs =zalloc (sizeof (struct kprobe_trace_event ) * max_tevs); + pf.tevs =zalloc (sizeof (struct probe_trace_event ) * max_tevs);if (pf.tevs ==NULL )return -ENOMEM ; *tevs = pf.tevs;
tools/perf/util/probe-finder.h +3 -3
@@ -18,7 +18,7 @@ static inline int is_c_varname(const char *name)#ifdef DWARF_SUPPORT /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ extern int find_kprobe_trace_events (int fd,struct perf_probe_event *pev, -struct kprobe_trace_event **tevs, +struct probe_trace_event **tevs,int max_tevs);/* Find a perf_probe_point from debuginfo */
@@ -33,7 +33,7 @@ extern int find_line_range(int fd, struct line_range *lr);struct probe_finder {struct perf_probe_event *pev;/* Target probe event */ -struct kprobe_trace_event *tevs;/* Result trace events */ +struct probe_trace_event *tevs;/* Result trace events */ int ntevs;/* Number of trace events */ int max_tevs;/* Max number of trace events */
@@ -50,7 +50,7 @@ struct probe_finder {#endif Dwarf_Op *fb_ops;/* Frame base attribute */ struct perf_probe_arg *pvar;/* Current target variable */ -struct kprobe_trace_arg *tvar;/* Current result variable */ +struct probe_trace_arg *tvar;/* Current result variable */ };struct line_finder {