Skip to contentSkip to conversation

Uprobes Patches:

PATCH Superseded Srikar Dronamraju 7 participants 44 messages Jul 12, 2010 – Aug 4, 2010

Subsystems (11)

v9 of 11 Superseded Latest is v11 →

lore
Share & tools
lore
#0 lore raw

v9 cover Uprobes Patches:

Uprobes Patches

Ingo,

Would it be possible to pick these patches into -tip tree. This help me in getting more testing/feedback for uprobes/perf probes.

Changelog from V8:
- Fix build issues reported by Christoph.
- List available probes in a file without need to specify pid.

Changelog from V7:
- New feature: perf probe lists available probes.
- Fix perf probes for uprobes to exit with a error message on dwarf based probes.
- Merge changes to kprobes traceevent infrastructure.
- Merge changes to perf.

Changelog from V6:
- Remove perf adjust symbols patch.

Changelog from V5:
- Merged user_bkpt and user_bkpt_xol into uprobes.
- Addressed comments till now.

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/7/8/239
http://lkml.org/lkml/2010/6/29/299 http://lkml.org/lkml/2010/6/14/41
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 2010 (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.

- Perf automatically adds probes for high-overhead functions.
- Allow trace scripts to insert probes
- Syscall integration and TRACE_EVENT() universe. (Need clarity/discussion on API)
- Allow users to insert probes in their applications.
- 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 W with bits in inat table.

Please do provide your valuable comments.

Thanks in advance.
Srikar
Srikar Dronamraju(13)
0: Uprobes Patches
1: mm: Move replace_page() / write_protect_page() to mm/memory.c 2: uprobes: Breakpoint insertion/removal in user space applications. 3: uprobes: Slot allocation for Execution out of line(XOL) 4: uprobes: x86 specific functions for user space breakpointing. 5: uprobes: Uprobes (un)registration and exception handling. 6: uprobes: X86 support for Uprobes
7: uprobes: Uprobes Documentation
8: trace: Extract out common code for kprobes/uprobes traceevents. 9: trace: uprobes trace_event interface
10: perf: Re-Add make_absolute_path
11: perf: perf interface for uprobes
12: [RFC] perf: Show Potential probe points.
13: [RFC] perf: show functions in a file without using pid

 Documentation/uprobes.txt          |  193 +++++
 arch/Kconfig                       |    6 +
 arch/x86/Kconfig                   |    1 +
 arch/x86/include/asm/thread_info.h |    2 +
 arch/x86/include/asm/uprobes.h     |   43 ++
 arch/x86/kernel/Makefile           |    2 +
 arch/x86/kernel/signal.c           |   13 +
 arch/x86/kernel/uprobes.c          |  599 ++++++++++++++++
 fs/exec.c                          |    4 +
 include/linux/mm.h                 |    4 +
 include/linux/mm_types.h           |    4 +
 include/linux/sched.h              |    3 +
 include/linux/uprobes.h            |  334 +++++++++
 kernel/Makefile                    |    1 +
 kernel/fork.c                      |   21 +
 kernel/trace/Kconfig               |   20 +
 kernel/trace/Makefile              |    2 +
 kernel/trace/trace.h               |    5 +
 kernel/trace/trace_kprobe.c        |  742 +-------------------
 kernel/trace/trace_probe.c         |  654 +++++++++++++++++
 kernel/trace/trace_probe.h         |  157 ++++
 kernel/trace/trace_uprobe.c        |  739 +++++++++++++++++++
 kernel/uprobes.c                   | 1396 ++++++++++++++++++++++++++++++++++++
 mm/ksm.c                           |  112 ---
 mm/memory.c                        |  120 +++
 tools/perf/builtin-probe.c         |   53 ++-
 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/map.h              |    2 +
 tools/perf/util/probe-event.c      |  613 ++++++++++++----
 tools/perf/util/probe-event.h      |   38 +-
 tools/perf/util/probe-finder.c     |   34 +-
 tools/perf/util/probe-finder.h     |   10 +-
 tools/perf/util/symbol.c           |   47 ++
 tools/perf/util/symbol.h           |    2 +
 38 files changed, 5043 insertions(+), 1056 deletions(-)
#1 lore raw

PATCH v9 1/13 mm: Move replace_page() / write_protect_page() to mm/memory.c

mm: Move replace_page() / 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
index b969efb..206008e 100644
@@ -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

#2 lore raw

PATCH v9 2/13 uprobes: Breakpoint insertion/removal in user space applications.

In reply to Srikar Dronamraju

uprobes: Breakpoint insertion/removal in user space applications.

Changelog from V5: (Merge user_bkpt into uprobes)
* Merged user_bkpt into uprobes as suggested by Christoph Hellwig and Peter Zijlstra.

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.

Provides a mechanism in kernel to insert/remove breakpoints in user space applications including
- architecture independent mechanism to establish breakpoints in userspace applications.
- helper functions for reading/writing/validating data/opcodes from target process's address space.
- wrappers and default implementation(whereever possible) of architecture dependent functions(setting breakpoint)
- preprocessing and postprocessing of singlestep on breakpoint hit

Single stepping inline 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.

In execution out of line, threads single steps on a copy of the instruction. This method works well for both single-threaded and multithreaded applications.

Uprobes uses execution out of line method.

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 uprobes patch for your architecture to define architecture specific functionality for reading/writing/validating data/opcodes.

---

 arch/Kconfig            |   14 +
 include/linux/uprobes.h |  189 +++++++++++++++++++
 kernel/Makefile         |    1 
 kernel/uprobes.c        |  466 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 670 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/uprobes.h
 create mode 100644 kernel/uprobes.c
arch/Kconfig +14 -0
index 4877a8c..87bd26b 100644
@@ -47,6 +47,17 @@ config OPTPROBES
 	depends on !PREEMPT
 	select KALLSYMS_ALL
 
+config UPROBES
+	bool "User-space probes (EXPERIMENTAL)"
+	depends on ARCH_SUPPORTS_UPROBES
+	depends on MMU
+	help
+	  Uprobes enables kernel subsystems 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
@@ -80,6 +91,9 @@ config USER_RETURN_NOTIFIER
 	  Provide a kernel-internal notification when a cpu is about to
 	  switch to user mode.
 
+config ARCH_SUPPORTS_UPROBES
+	def_bool n
+
 config HAVE_IOREMAP_PROT
 	bool
 
include/linux/uprobes.h new file +189 -0

189 lines not on this page · raw message

kernel/Makefile +1 -0
index ce53fb2..ec70eab 100644
@@ -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_UPROBES) += uprobes.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
kernel/uprobes.c new file +466 -0

466 lines not on this page · raw message

#3 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 2/13] uprobes: Breakpoint insertion/removal in user space applications.

Quoted 11 lines
include/linux/uprobes.h new file +11 -0
+struct user_bkpt_arch_info {
+	void (*set_ip)(struct pt_regs *regs, unsigned long vaddr);
+	int (*validate_address)(struct task_struct *tsk, unsigned long vaddr);
+	int (*read_opcode)(struct task_struct *tsk, unsigned long vaddr,
+						user_bkpt_opcode_t *opcode);
+	int (*set_bkpt)(struct task_struct *tsk,
+				struct user_bkpt *user_bkpt);
+	int (*set_orig_insn)(struct task_struct *tsk,
+				struct user_bkpt *user_bkpt, bool check);
+	bool (*is_bkpt_insn)(struct user_bkpt *user_bkpt);
+	int (*analyze_insn)(struct task_struct *tsk,

include/linux/uprobes.h line 176

Quoted 10 lines
include/linux/uprobes.h new file +10 -0
+					struct user_bkpt *user_bkpt);
+	int (*pre_xol)(struct task_struct *tsk,
+				struct user_bkpt *user_bkpt,
+				struct user_bkpt_task_arch_info *tskinfo,
+				struct pt_regs *regs);
+	int (*post_xol)(struct task_struct *tsk,
+				struct user_bkpt *user_bkpt,
+				struct user_bkpt_task_arch_info *tskinfo,
+				struct pt_regs *regs);
+};

Just wondering why these are function pointers. Do we exepect an architecture to provide different versions of these for say 32 vs 64-bit binaries? If not just making these arch provided helpers might be a lot simpler. Especially in the current version where only very few of these are overriden by the architecture at all.

Quoted 14 lines
kernel/uprobes.c new file +14 -0
+unsigned long uprobes_read_vm(struct task_struct *tsk, void __user *vaddr,
+					void *kbuf, unsigned long nbytes)
+{
+	if (tsk == current) {
+		unsigned long nleft = copy_from_user(kbuf, vaddr, nbytes);
+		return nbytes - nleft;
+	} else
+		return access_process_vm(tsk, (unsigned long) vaddr, kbuf,
+							nbytes, 0);
+}
+
+unsigned long uprobes_write_data(struct task_struct *tsk,
+				void __user *vaddr, const void *kbuf,
+				unsigned long nbytes)

kernel/uprobes.c line 81

Quoted 10 lines
kernel/uprobes.c new file +10 -0
+{
+	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);
+}

Any reason for the naming mismatch between _read_vm and _write_data?

Also I wonder if the optimization for tsk == current should be folded directly into access_process_vm instead of adding these wrappers.

#4 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 2/13] uprobes: Breakpoint insertion/removal in user space applications.

Quoted 28 lines · Christoph Hellwig
Quoted 11 lines
include/linux/uprobes.h new file +11 -0
+struct user_bkpt_arch_info {
+	void (*set_ip)(struct pt_regs *regs, unsigned long vaddr);
+	int (*validate_address)(struct task_struct *tsk, unsigned long vaddr);
+	int (*read_opcode)(struct task_struct *tsk, unsigned long vaddr,
+						user_bkpt_opcode_t *opcode);
+	int (*set_bkpt)(struct task_struct *tsk,
+				struct user_bkpt *user_bkpt);
+	int (*set_orig_insn)(struct task_struct *tsk,
+				struct user_bkpt *user_bkpt, bool check);
+	bool (*is_bkpt_insn)(struct user_bkpt *user_bkpt);
+	int (*analyze_insn)(struct task_struct *tsk,

include/linux/uprobes.h line 176

Quoted 10 lines
include/linux/uprobes.h new file +10 -0
+					struct user_bkpt *user_bkpt);
+	int (*pre_xol)(struct task_struct *tsk,
+				struct user_bkpt *user_bkpt,
+				struct user_bkpt_task_arch_info *tskinfo,
+				struct pt_regs *regs);
+	int (*post_xol)(struct task_struct *tsk,
+				struct user_bkpt *user_bkpt,
+				struct user_bkpt_task_arch_info *tskinfo,
+				struct pt_regs *regs);
+};

Just wondering why these are function pointers. Do we exepect an architecture to provide different versions of these for say 32 vs 64-bit binaries? If not just making these arch provided helpers might be a lot simpler. Especially in the current version where only very few of these are overriden by the architecture at all.

Quoted 2 lines

kernel/uprobes.c line 47

Quoted 2 lines
kernel/uprobes.c new file +2 -0
+unsigned long uprobes_read_vm(struct task_struct *tsk, void __user *vaddr,
+					void *kbuf, unsigned long nbytes)

Some of these functions are purely optional example being validate_address.

Some of these functions need not be defined by the architecture in which case we default to the functions defined in common code. examples being: read_opcode, set_bkpt, and set_orig_insn.

Some of these functions are architecture mode specific, for example there is a architecture specific pre_xol needed for x86_64. However generic pre_xol for x86_32 would suffice for x86_32.

Some of these functions need to be mandatorily defined by the architecture. example being set_ip and analyze_insn.

Apart from the above flexibilities and enforcements that we can make when we use function pointers, its would be handy to incorporate more enhancements like return probes and booster.

Quoted 16 lines
Quoted 16 lines
kernel/uprobes.c new file +16 -0
+{
+	if (tsk == current) {
+		unsigned long nleft = copy_from_user(kbuf, vaddr, nbytes);
+		return nbytes - nleft;
+	} else
+		return access_process_vm(tsk, (unsigned long) vaddr, kbuf,
+							nbytes, 0);
+}
+
+unsigned long uprobes_write_data(struct task_struct *tsk,
+				void __user *vaddr, const void *kbuf,
+				unsigned long nbytes)
+{
+	unsigned long nleft;
+
+	if (tsk == current) {
Quoted 8 lines

kernel/uprobes.c line 81

Quoted 6 lines
kernel/uprobes.c new file +6 -0
+		nleft = copy_to_user(vaddr, kbuf, nbytes);
+		return nbytes - nleft;
+	} else
+		return access_process_vm(tsk, (unsigned long) vaddr,
+						(void *) kbuf, nbytes, 1);
+}

Any reason for the naming mismatch between _read_vm and _write_data?

The naming mismatch was on purpose, we wanted to mention that write_data cannot be used with code sections unlike read_vm which can be used to read code section.

Quoted 4 lines

Also I wonder if the optimization for tsk == current should be folded directly into access_process_vm instead of adding these wrappers.

One reason why we dont want to move this optimization as is into access_process_vm is we dont want to do a copy_to_user on a code section. So that would mean another check to determine if its a code section before we do the optimization. However there could other reasons why we shouldnt be doing this optimization. Do you still think we should still be pursuing with the optimization?

--
Thanks and Regards
Srikar

maintainer
#5 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 2/13] uprobes: Breakpoint insertion/removal in user space applications.

Quoted 21 lines · Srikar Dronamraju
Quoted 8 lines

Just wondering why these are function pointers. Do we exepect an architecture to provide different versions of these for say 32 vs 64-bit binaries? If not just making these arch provided helpers might be a lot simpler. Especially in the current version where only very few of these are overriden by the architecture at all.

Quoted 2 lines
kernel/uprobes.c new file +2 -0
+unsigned long uprobes_read_vm(struct task_struct *tsk, void __user *vaddr,
+                                   void *kbuf, unsigned long nbytes)

Some of these functions are purely optional example being validate_address.

Some of these functions need not be defined by the architecture in which case we default to the functions defined in common code. examples being: read_opcode, set_bkpt, and set_orig_insn.

Some of these functions are architecture mode specific, for example there is a architecture specific pre_xol needed for x86_64. However generic pre_xol for x86_32 would suffice for x86_32.

Quoted 6 lines

Some of these functions need to be mandatorily defined by the architecture. example being set_ip and analyze_insn.

Apart from the above flexibilities and enforcements that we can make when we use function pointers, its would be handy to incorporate more enhancements like return probes and booster.

Still not sure why you're using this vector though, why not use weak function for optionals and defaults and no implementation for mandatory functions (and if the implementations fails to provide it, that will result in a link error).

Are there likely to be multiple different versions of this method vector around on a running kernel?

#6 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 2/13] uprobes: Breakpoint insertion/removal in user space applications.

Quoted 22 lines · Peter Zijlstra
Quoted 21 lines · Srikar Dronamraju
Quoted 6 lines

Just wondering why these are function pointers. Do we exepect an architecture to provide different versions of these for say 32 vs 64-bit binaries? If not just making these arch provided helpers might be a lot simpler. Especially in the current version where only very few of these are overriden by the architecture at all.

Some of these functions are purely optional example being validate_address.

Some of these functions need not be defined by the architecture in which case we default to the functions defined in common code. examples being: read_opcode, set_bkpt, and set_orig_insn.

Some of these functions are architecture mode specific, for example there is a architecture specific pre_xol needed for x86_64. However generic pre_xol for x86_32 would suffice for x86_32.

Some of these functions need to be mandatorily defined by the architecture. example being set_ip and analyze_insn.

Quoted 8 lines
Quoted 3 lines

Apart from the above flexibilities and enforcements that we can make when we use function pointers, its would be handy to incorporate more enhancements like return probes and booster.

Still not sure why you're using this vector though, why not use weak function for optionals and defaults and no implementation for mandatory functions (and if the implementations fails to provide it, that will result in a link error).

Yes, we can certainly use weak functions instead of pointers. One another reason why we had these as function pointers in a structure was that it would easy be for a person porting uprobes to a new architecture. i.e person porting to a new architecture knows in one place(structure) which all functions need to be provided.

However I would go with your suggestion and make the changes to use weak functions in the next version of the patchset.

Quoted 3 lines

Are there likely to be multiple different versions of this method vector around on a running kernel?

No for a running kernel, there will be only one method vector.

Also wanted to check with if you had tried perf probes and had comments/suggestions on any of the other patches in the patchset.

--
Thanks and Regards
Srikar

maintainer
#7 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 2/13] uprobes: Breakpoint insertion/removal in user space applications.

Quoted 3 lines · Srikar Dronamraju

Also wanted to check with if you had tried perf probes and had comments/suggestions on any of the other patches in the patchset.

Just got back from holidays and am trying to make sense of the inbox, I'll hopefully get around to actually reading the patches 'soon' ;-)

#8 lore raw

PATCH v9 3/13 uprobes: Slot allocation for Execution out of line(XOL)

In reply to Srikar Dronamraju

uprobes: Slot allocation for Execution out of line(XOL)

Changelog from V5: Merged into uprobes.

Changelog form V3:
* Added a memory barrier after the slot gets initialized.

Changelog from V2: (addressing Oleg's comments)
* Removed code in !CONFIG_UPROBES_XOL
* Functions now pass pointer to uprobes_xol_area instead of pointer to void.

Provides slot allocation mechanism for execution out of line for use with user space breakpointing.

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.

---

 include/linux/uprobes.h |    2 
 kernel/uprobes.c        |  283 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 285 insertions(+), 0 deletions(-)
include/linux/uprobes.h +2 -0
index 44c23d6..f556b2d 100644
@@ -37,6 +37,8 @@ struct user_bkpt_task_arch_info {};
 struct user_bkpt_arch_info;
 #endif
 
+#define UINSNS_PER_PAGE	(PAGE_SIZE/UPROBES_XOL_SLOT_BYTES)
+#define MAX_UPROBES_XOL_SLOTS UINSNS_PER_PAGE
 
 struct task_struct;
 struct pt_regs;
kernel/uprobes.c +283 -0

295 lines not on this page · raw message

#9 lore raw

PATCH v9 4/13 uprobes: x86 specific functions for user space breakpointing.

In reply to Srikar Dronamraju

uprobes: x86 specific functions for user space breakpointing.

Changelog from V5: Merged into uprobes layer.

Changelog from V1:
set UPROBES_FIX_SLEEPY if post_xol might sleep.

Provides x86 specific functions for instruction analysis and instruction validation and x86 specific pre-processing and post-processing of singlestep especially for RIP relative instructions. Uses "x86: instruction decoder API" for validation and analysis of user space instructions. This analysis is used at the time of post-processing of breakpoint hit to do the necessary fix-ups. There is support for breakpointing RIP relative instructions. However there are still few instructions that cannot be singlestepped.

Also defines TIF_UPROBE flag for x86.

This patch requires "x86: instruction decoder API"
http://lkml.org/lkml/2009/6/1/459

---

 arch/x86/Kconfig                   |    1 
 arch/x86/include/asm/thread_info.h |    2 
 arch/x86/include/asm/uprobes.h     |   43 +++
 arch/x86/kernel/Makefile           |    2 
 arch/x86/kernel/uprobes.c          |  547 ++++++++++++++++++++++++++++++++++++
 5 files changed, 595 insertions(+), 0 deletions(-)
 create mode 100644 arch/x86/include/asm/uprobes.h
 create mode 100644 arch/x86/kernel/uprobes.c
arch/x86/Kconfig +1 -0
index 3069a6d..8f2bdbf 100644
@@ -54,6 +54,7 @@ config X86
 	select HAVE_KERNEL_LZO
 	select HAVE_HW_BREAKPOINT
 	select HAVE_MIXED_BREAKPOINTS_REGS
+	select ARCH_SUPPORTS_UPROBES
 	select PERF_EVENTS
 	select HAVE_PERF_EVENTS_NMI
 	select ANON_INODES
arch/x86/include/asm/thread_info.h +2 -0
index f0b6e5d..5b9c9f0 100644
@@ -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/include/asm/uprobes.h new file +43 -0

43 lines not on this page · raw message

arch/x86/kernel/Makefile +2 -0
index 0925676..f1da575 100644
@@ -116,6 +116,8 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
 
 obj-$(CONFIG_SWIOTLB)			+= pci-swiotlb.o
 
+obj-$(CONFIG_UPROBES)			+= uprobes.o
+
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
arch/x86/kernel/uprobes.c new file +547 -0

547 lines not on this page · raw message

#10 lore raw

PATCH v9 5/13 uprobes: Uprobes (un)registration and exception handling.

In reply to Srikar Dronamraju

uprobes: Uprobes (un)registration and exception handling.

Changelog from V5:
- Merged user_bkpt and user_bkpt_xol layers into uprobes.

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.
- find_probept() takes the spinlock; unlike previously when it was expected that the spinlock was taken before calling it.
- 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.)

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. Uprobes uses the execution out of line strategy and 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 only when the probe gets unregistered and there are no threads in the vicinity.

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. Allow multiple probes at a probepoint.
2. Booster probes.
3. Allow probes to be inherited across fork.
4. probing function returns.

---

 arch/Kconfig             |    1 
 fs/exec.c                |    4 
 include/linux/mm_types.h |    4 
 include/linux/sched.h    |    3 
 include/linux/uprobes.h  |  143 ++++++++++
 kernel/fork.c            |   21 +
 kernel/uprobes.c         |  653 ++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 826 insertions(+), 3 deletions(-)
arch/Kconfig +1 -0
index 87bd26b..c8c8e3f 100644
@@ -49,6 +49,7 @@ config OPTPROBES
 
 config UPROBES
 	bool "User-space probes (EXPERIMENTAL)"
+	default n
 	depends on ARCH_SUPPORTS_UPROBES
 	depends on MMU
 	help
fs/exec.c +4 -0
index 97d91a0..fe49384 100644
@@ -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
index b8bb9a6..200c659 100644
@@ -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
index 1f25798..26de836 100644
@@ -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 +143 -0

153 lines not on this page · raw message

kernel/fork.c +21 -0
index a82a65c..c932193 100644
@@ -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 +650 -3

696 lines not on this page · raw message

#11 lore raw

PATCH v9 6/13 uprobes: X86 support for Uprobes

In reply to Srikar Dronamraju

uprobes: X86 support for Uprobes

Changelog from V5: Using local_irq_enable() instead of
native_irq_enable and no more disabling irqs as suggested by Oleg Nesterov.

Provides x86 specific details for uprobes.
This includes interrupt notifier for uprobes, enabling/disabling singlestep.

---

 arch/x86/kernel/signal.c  |   13 +++++++++++
 arch/x86/kernel/uprobes.c |   52 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 0 deletions(-)
arch/x86/kernel/signal.c +13 -0
index 4fd173c..3657563 100644
@@ -848,6 +848,19 @@ 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);
+#ifdef CONFIG_X86_32
+		/*
+		 * On x86_32, do_notify_resume() gets called with
+		 * interrupts disabled. Hence enable interrupts if they
+		 * are still disabled.
+		 */
+		local_irq_enable();
+#endif
+		uprobe_notify_resume(regs);
+	}
+
 	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 		clear_thread_flag(TIF_NOTIFY_RESUME);
 		tracehook_notify_resume(regs);
arch/x86/kernel/uprobes.c +52 -0

61 lines not on this page · raw message

#12 lore raw

PATCH v9 7/13 uprobes: Uprobes Documentation

In reply to Srikar Dronamraju

uprobes: Uprobes Documentation

Changelog from V5: Removed references to Modules, Samples, and
probe Overhead.

Changelog from v3: Updated measurements.

Changelog from v2: Updated measurements.

Changelog from v1: Addressed comments from Randy Dunlap.
: Updated measurements.

---

 Documentation/uprobes.txt |  193 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 193 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/uprobes.txt
Documentation/uprobes.txt new file +193 -0
new file mode 100644
index 0000000..cf87136
@@ -0,0 +1,193 @@
+Title	: User-Space Probes (Uprobes)
+Authors	: Jim Keniston <[email protected]>
+	: Srikar Dronamraju <[email protected]>
+
+CONTENTS
+
+1. Concepts: Uprobes
+2. Architectures Supported
+3. API Reference
+4. Uprobes Features and Limitations
+5. TODO
+6. Uprobes Team
+
+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. 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.
+
+3.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.
+
+3.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.
+
+4. Uprobes Features and Limitations
+
+The user is expected to assign values to the following members
+of struct uprobe: pid, vaddr, handler.
+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.
+
+Uprobe clients may be used to probe a particular process
+simultaneously, or 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 background page
+replacement  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.
+
+5. TODO
+
+a. Support for other architectures.
+b. Support for multiple probes at the same address.
+c. Support for boosted probes.
+d. Support return probes.
+
+6. 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]
#13 lore raw

PATCH v9 8/13 trace: Extract out common code for kprobes/uprobes traceevents.

In reply to Srikar Dronamraju

trace: Extract out common code for kprobes/uprobes traceevents.

Changelog from v7: Merge changes due to string support in kprobes
traceevent.

Changelog from v5: Addressed comments from Masami Hiramatsu
and Steven Rostedt. Also shared lot more code from kprobes traceevents.

Move common parts of trace_kprobe.c and trace_uprobe.c Adjust kernel/trace/trace_kprobe.c after moving common code to kernel/trace/trace_probe.h and kernel/trace/trace_probe.c.

TODO: Merge both events to a single probe event.

---

 kernel/trace/Kconfig        |    4 
 kernel/trace/Makefile       |    1 
 kernel/trace/trace_kprobe.c |  742 +------------------------------------------
 kernel/trace/trace_probe.c  |  654 ++++++++++++++++++++++++++++++++++++++
 kernel/trace/trace_probe.h  |  155 +++++++++
 5 files changed, 823 insertions(+), 733 deletions(-)
 create mode 100644 kernel/trace/trace_probe.c
 create mode 100644 kernel/trace/trace_probe.h
kernel/trace/Kconfig +4 -0
index f669092..ab62d9a 100644
@@ -395,6 +395,7 @@ config KPROBE_EVENT
 	depends on HAVE_REGS_AND_STACK_ACCESS_API
 	bool "Enable kprobes-based dynamic events"
 	select TRACING
+	select PROBE_EVENTS
 	default y
 	help
 	  This allows the user to add tracing events (similar to tracepoints)
@@ -407,6 +408,9 @@ config KPROBE_EVENT
 	  This option is also required by perf-probe subcommand of perf tools.
 	  If you want to use perf tools, this option is strongly recommended.
 
+config PROBE_EVENTS
+	def_bool n
+
 config DYNAMIC_FTRACE
 	bool "enable/disable ftrace tracepoints dynamically"
 	depends on FUNCTION_TRACER
kernel/trace/Makefile +1 -0
index 469a1c7..5a45910 100644
@@ -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_PROBE_EVENTS) +=trace_probe.o
 
 libftrace-y := ftrace.o
kernel/trace/trace_kprobe.c +9 -733

812 lines not on this page · raw message

kernel/trace/trace_probe.c new file +654 -0

654 lines not on this page · raw message

kernel/trace/trace_probe.h new file +155 -0

155 lines not on this page · raw message

#14 lore raw

PATCH v9 9/13 trace: uprobes trace_event interface

In reply to Srikar Dronamraju

trace: uprobes trace_event interface

Changelog from v5: Addressed comments from Masami Hiramatsu and Steven
Rostedt. Some changes because of changes in common probe events.

Changelog from v4: (Merged to 2.6.35-rc3-tip)

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.

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.

TODO: Documentation/trace/uprobetrace.txt

---

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=79
 arch/Kconfig                |   11 -
 kernel/trace/Kconfig        |   16 +
 kernel/trace/Makefile       |    1 
 kernel/trace/trace.h        |    5 
 kernel/trace/trace_probe.h  |    2 
 kernel/trace/trace_uprobe.c |  739 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 764 insertions(+), 10 deletions(-)
 create mode 100644 kernel/trace/trace_uprobe.c
arch/Kconfig +1 -10
index c8c8e3f..af167f8 100644
@@ -48,16 +48,7 @@ config OPTPROBES
 	select KALLSYMS_ALL
 
 config UPROBES
-	bool "User-space probes (EXPERIMENTAL)"
-	default n
-	depends on ARCH_SUPPORTS_UPROBES
-	depends on MMU
-	help
-	  Uprobes enables kernel subsystems 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".
+	def_bool n
 
 config HAVE_EFFICIENT_UNALIGNED_ACCESS
 	bool
kernel/trace/Kconfig +16 -0
index ab62d9a..2f46188 100644
@@ -513,6 +513,22 @@ config RING_BUFFER_BENCHMARK
 
 	  If unsure, say N.
 
+config UPROBE_EVENT
+	bool "Enable uprobes-based dynamic events"
+	depends on ARCH_SUPPORTS_UPROBES
+	depends on MMU
+	select UPROBES
+	select PROBE_EVENTS
+	select TRACING
+	default n
+	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
index 5a45910..a386d12 100644
@@ -56,5 +56,6 @@ obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
 obj-$(CONFIG_KSYM_TRACER) += trace_ksym.o
 obj-$(CONFIG_EVENT_TRACING) += power-traces.o
 obj-$(CONFIG_PROBE_EVENTS) +=trace_probe.o
+obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o
 
 libftrace-y := ftrace.o
kernel/trace/trace.h +5 -0
index cc90ccd..8ef185f 100644
@@ -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
index 05da727..5b770e8 100644
@@ -48,6 +48,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"
 
 #undef DEFINE_FIELD
 #define DEFINE_FIELD(type, item, name, is_signed)			\
@@ -64,6 +65,7 @@
 /* Flags for trace_probe */
 #define TP_FLAG_TRACE	1
 #define TP_FLAG_PROFILE	2
+#define TP_FLAG_UPROBE	4
 
 
 /* data_rloc: data relative location, compatible with u32 */
kernel/trace/trace_uprobe.c new file +739 -0

739 lines not on this page · raw message

#15 lore raw

PATCH v9 10/13 perf: Re-Add make_absolute_path

In reply to Srikar Dronamraju

perf: Re-Add make_absolute_path

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
index 0e76aff..0a985fd 100644
@@ -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
index 27e9ebe..0dfed40 100644
@@ -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);
 
#16 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

Em Mon, Jul 12, 2010 at 04:04:12PM +0530, Srikar Dronamraju escreveu:

Quoted 7 lines

perf: Re-Add make_absolute_path

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]

Isn't this the other way around? I.e. "if the user specifies [email protected] it needs to be converted to malloc@/lib/libc.so.6"?

Also please remove the xstrdup and die calls from this function, we're trying to get rid of all such 'panic' like functions so that we can librarize as much code as possible.

Quoted 113 lines

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
index 0e76aff..0a985fd 100644
@@ -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
index 27e9ebe..0dfed40 100644
@@ -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);
 
maintainer
#17 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

Quoted 4 lines · Arnaldo Carvalho de Melo

Also please remove the xstrdup and die calls from this function, we're trying to get rid of all such 'panic' like functions so that we can librarize as much code as possible.

What I found useful with the "die" calls with trace-cmd is that I made them weak, and then they could be overwritten by apps. Thus, in kernelshark, the die and warning functions produce pop-ups and bug reports.

-- Steve

#18 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

Em Mon, Jul 12, 2010 at 10:30:36AM -0400, Steven Rostedt escreveu:

Quoted 9 lines · Arnaldo Carvalho de Melo
Quoted 3 lines

Also please remove the xstrdup and die calls from this function, we're trying to get rid of all such 'panic' like functions so that we can librarize as much code as possible.

What I found useful with the "die" calls with trace-cmd is that I made them weak, and then they could be overwritten by apps. Thus, in kernelshark, the die and warning functions produce pop-ups and bug reports.

Well, I prefer to follow the kernel way of doing things, i.e. to propagate as much as possible up the callchain the error return value, so that the apps can handle it in any way they prefer, i.e. die() calls in tools/perf/builtin-foo.c are okayish, but not on tools/perf/util/.

When I'm writing a tools/perf/builtin-.c file I also don't use die() calls, as some routines may end up moving to the library, so its nice to avoid them from the start.

The pr_{warning,err,info,etc} calls do something along the lines of what you do, but not by marking them weak, the routine that is ultimately called checks what kind of UI is being used and calls the appropriate one (TUI/NEWT of stdio).

- Arnaldo

maintainer
#19 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

Quoted 6 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 12, 2010 at 10:30:36AM -0400, Steven Rostedt escreveu:

Well, I prefer to follow the kernel way of doing things, i.e. to propagate as much as possible up the callchain the error return value, so that the apps can handle it in any way they prefer, i.e. die() calls in tools/perf/builtin-foo.c are okayish, but not on tools/perf/util/.

Ah, yes, die is a bit strong. And I have been starting to avoid them too. Although, when malloc fails, it's almost certain that the app will die soon anyway ;-)

-- Steve

#20 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

Em Tue, Jul 13, 2010 at 10:49:27PM -0400, Steven Rostedt escreveu:

Quoted 11 lines · Arnaldo Carvalho de Melo
Quoted 6 lines

Em Mon, Jul 12, 2010 at 10:30:36AM -0400, Steven Rostedt escreveu:

Well, I prefer to follow the kernel way of doing things, i.e. to propagate as much as possible up the callchain the error return value, so that the apps can handle it in any way they prefer, i.e. die() calls in tools/perf/builtin-foo.c are okayish, but not on tools/perf/util/.

Ah, yes, die is a bit strong. And I have been starting to avoid them too. Although, when malloc fails, it's almost certain that the app will die soon anyway ;-)

The interesting thing is that years ago, when modules were being introduced in the kernel and panic() calls for things like out of memory conditions were being removed, some people made the same comments, 'if that happens, you're doomed anyway!' :-)

I can see things like trying to load a huge perf.data file in the TUI interface failing and the user just being warned about it and going on with life loading some other file, etc.

Certainly it is interesting to try to apply as much as possible of the mindset (and fear of criticism) present when coding for the kernel when one codes for userland.

- Arnaldo

#21 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

Quoted 18 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 13, 2010 at 10:49:27PM -0400, Steven Rostedt escreveu:

Quoted 11 lines · Arnaldo Carvalho de Melo
Quoted 6 lines

Em Mon, Jul 12, 2010 at 10:30:36AM -0400, Steven Rostedt escreveu:

Well, I prefer to follow the kernel way of doing things, i.e. to propagate as much as possible up the callchain the error return value, so that the apps can handle it in any way they prefer, i.e. die() calls in tools/perf/builtin-foo.c are okayish, but not on tools/perf/util/.

Ah, yes, die is a bit strong. And I have been starting to avoid them too. Although, when malloc fails, it's almost certain that the app will die soon anyway ;-)

The interesting thing is that years ago, when modules were being introduced in the kernel and panic() calls for things like out of memory conditions were being removed, some people made the same comments, 'if that happens, you're doomed anyway!' :-)

Quoted 7 lines

I can see things like trying to load a huge perf.data file in the TUI interface failing and the user just being warned about it and going on with life loading some other file, etc.

Certainly it is interesting to try to apply as much as possible of the mindset (and fear of criticism) present when coding for the kernel when one codes for userland.

Yeah, and especially for perf the absolutely most important quality is reliability. It's not just an app - it's a measurement tool. People rely on it to reject or apply patches, on a daily basis.

perf must be very reliable and very dependable (and i'm happy that we managed to achieve that goal so far :), and if it fails it should be apparent that it failed and that results should not be relied on.

With other tools that are statistical i've sometimes seen a special type of dangerous attitude of: "hey, it's just a sample, no biggie if it's lost, it's just statistical anyway, lost in the noise" - but that's really a slippery slope leading to a sloppy tool we cannot depend on 110%.

Just like physicists or engineers want to be able to trust their measurement instruments, do we want kernel hackers to be able to trust the results of perf.

Thanks,

Ingo

#22 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

Quoted 37 lines · * Ingo Molnar ([email protected]) wrote:
Quoted 18 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 13, 2010 at 10:49:27PM -0400, Steven Rostedt escreveu:

Quoted 11 lines · Arnaldo Carvalho de Melo
Quoted 6 lines

Em Mon, Jul 12, 2010 at 10:30:36AM -0400, Steven Rostedt escreveu:

Well, I prefer to follow the kernel way of doing things, i.e. to propagate as much as possible up the callchain the error return value, so that the apps can handle it in any way they prefer, i.e. die() calls in tools/perf/builtin-foo.c are okayish, but not on tools/perf/util/.

Ah, yes, die is a bit strong. And I have been starting to avoid them too. Although, when malloc fails, it's almost certain that the app will die soon anyway ;-)

The interesting thing is that years ago, when modules were being introduced in the kernel and panic() calls for things like out of memory conditions were being removed, some people made the same comments, 'if that happens, you're doomed anyway!' :-)

Quoted 7 lines

I can see things like trying to load a huge perf.data file in the TUI interface failing and the user just being warned about it and going on with life loading some other file, etc.

Certainly it is interesting to try to apply as much as possible of the mindset (and fear of criticism) present when coding for the kernel when one codes for userland.

Yeah, and especially for perf the absolutely most important quality is reliability. It's not just an app - it's a measurement tool. People rely on it to reject or apply patches, on a daily basis.

perf must be very reliable and very dependable (and i'm happy that we managed to achieve that goal so far :), and if it fails it should be apparent that it failed and that results should not be relied on.

Quoted 8 lines

With other tools that are statistical i've sometimes seen a special type of dangerous attitude of: "hey, it's just a sample, no biggie if it's lost, it's just statistical anyway, lost in the noise" - but that's really a slippery slope leading to a sloppy tool we cannot depend on 110%.

Just like physicists or engineers want to be able to trust their measurement instruments, do we want kernel hackers to be able to trust the results of perf.

I'm glad to see we're on the exact same page here. :)

Having reliable trace analysis tools is crucially important for both kernel developers and end-users, especially when, as an example, someone try to use the results to find out which is the "one" odd-case longest/shortest interrupt handler during a day-long trace while trying to pinpoint a bug.

Thanks,

Mathieu

Quoted 4 lines

Thanks,

Ingo

Signature · 4 lines
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
#23 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

In reply to Arnaldo Carvalho de Melo
Quoted 12 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 12, 2010 at 04:04:12PM +0530, Srikar Dronamraju escreveu:

Quoted 7 lines

perf: Re-Add make_absolute_path

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]

Isn't this the other way around? I.e. "if the user specifies [email protected] it needs to be converted to malloc@/lib/libc.so.6"?

Actually we dont need to convert [email protected] to a malloc@/lib/libc.so.6. Because we can match the shortname of the dso.

Problem will occur when users specifies a full path of the file. Since the file can refer to a symbolic link and the dso will have just the short name or the target file name. Here I am using make_absolute_path to resolve to the target file.
Now we can then either check on dso full names or short names. I have chosen to use the short name.

Quoted 3 lines

Also please remove the xstrdup and die calls from this function, we're trying to get rid of all such 'panic' like functions so that we can librarize as much code as possible.

Okay, Can I do that in subsequent versions of the patchset?

--
Thanks and Regards
Srikar

#24 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

Em Mon, Jul 12, 2010 at 09:03:57PM +0530, Srikar Dronamraju escreveu:

Quoted 5 lines · Arnaldo Carvalho de Melo
Quoted 3 lines

Em Mon, Jul 12, 2010 at 04:04:12PM +0530, Srikar Dronamraju escreveu:

Quoted 2 lines

perf probe for uprobes would use make_absolute_path. make_absolute_path can be used to convert a file name to a dso name.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

so if user specifies the function to be traced as malloc@/lib/libc.so.6 it needs to be converted to [email protected]

Isn't this the other way around? I.e. "if the user specifies [email protected] it needs to be converted to malloc@/lib/libc.so.6"?

Actually we dont need to convert [email protected] to a malloc@/lib/libc.so.6. Because we can match the shortname of the dso.

Humm, I see, it is path based, so the first libc-2.5.so that appears in the LD_LIBRARY_PATH equivalent used in this code will be user, is that right?

I.e. if I'm testing some new libc-2.5.so that provides, say, private futexes while the one in my distro still doesn't have this feature, I'll have to specify the absolute name or make sure it is before the system's libc-2.5.so in the LD_LIBRARY_PATH, right?

Quoted 6 lines

Problem will occur when users specifies a full path of the file. Since the file can refer to a symbolic link and the dso will have just the short name or the target file name. Here I am using make_absolute_path to resolve to the target file.
Now we can then either check on dso full names or short names. I have chosen to use the short name.

Humm, so what you want is one of:

realpath - return the canonicalized absolute pathname canonicalize_file_name - return the canonicalized filename

Can you please check the man pages for both before we decide re-introducing make_absolute_path?

Quoted 5 lines
Quoted 3 lines

Also please remove the xstrdup and die calls from this function, we're trying to get rid of all such 'panic' like functions so that we can librarize as much code as possible.

Okay, Can I do that in subsequent versions of the patchset?

yeah, its ok if you don't end up using one of the suggested libc functions above :-)

- Arnaldo

#25 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 10/13] perf: Re-Add make_absolute_path

Quoted 7 lines
Quoted 3 lines

Actually we dont need to convert [email protected] to a malloc@/lib/libc.so.6. Because we can match the shortname of the dso.

Humm, I see, it is path based, so the first libc-2.5.so that appears in the LD_LIBRARY_PATH equivalent used in this code will be user, is that right?

No, As you might have got it by reading patch 11. I am trying to reuse the thread/session elements and walk thro the maps in the map_groups. So I dont need to bother on LD_LIBRARY_PATH.

Quoted 5 lines

I.e. if I'm testing some new libc-2.5.so that provides, say, private futexes while the one in my distro still doesn't have this feature, I'll have to specify the absolute name or make sure it is before the system's libc-2.5.so in the LD_LIBRARY_PATH, right?

We get to the right one, as we walk the list of dsos in the threadlist. But we have an option of either giving a correct full path or the shortname for the dso without any path. However right now the shortname has to be unique i.e I cant use malloc@libc instead of [email protected]. I would think specifying full path will be the most probable usage case. However if a person refers /proc/<pid>/maps, specifying shortnames should also be easy.

Quoted 8 lines
Quoted 7 lines

Problem will occur when users specifies a full path of the file. Since the file can refer to a symbolic link and the dso will have just the short name or the target file name. Here I am using make_absolute_path to resolve to the target file.
Now we can then either check on dso full names or short names. I have chosen to use the short name.

Quoted 7 lines

Humm, so what you want is one of:

realpath - return the canonicalized absolute pathname canonicalize_file_name - return the canonicalized filename

Can you please check the man pages for both before we decide re-introducing make_absolute_path?

right, realpath is right choice, I will use it instead of this patch.

--
Thanks and Regards
Srikar

#26 lore raw

PATCH v9 11/13 perf: perf interface for uprobes

In reply to Srikar Dronamraju

perf: perf interface for uprobes

Changelog from v8: Fixed a build break reported by Christoph Hellwig.

Changelog from v6: Changelog from v6: Fixed a bug reported by Masami.
i.e Throw an error message and exit if perf probe is for a dwarf based probes.

Changelog from v4: Merged to 2.6.35-rc3-tip.

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.

Enhances perf probe to accept pid and user vaddr.
Provides very basic support for uprobes.

TODO:
Update perf-probes.txt.
Global tracing.

---

Here is a terminal snapshot of placing, using and removing a probe on a process with pid 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  |  520 +++++++++++++++++++++++++++++-----------
 tools/perf/util/probe-event.h  |   37 +--
 tools/perf/util/probe-finder.c |   34 +--
 tools/perf/util/probe-finder.h |   10 -
 8 files changed, 445 insertions(+), 210 deletions(-)
tools/perf/builtin-probe.c +10 -3
index 5455186..cb915a5 100644
@@ -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;
 }
@@ -188,6 +190,8 @@ static const struct option options[] = {
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
 		 "Set how many probe points can be found for a probe."),
+	OPT_INTEGER('p', "pid", &params.upid,
+			"specify a pid for a uprobes based probe"),
 	OPT_END()
 };
 
@@ -225,6 +229,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",
@@ -233,7 +241,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");
@@ -248,7 +256,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);
@@ -267,4 +275,3 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 	}
 	return 0;
 }
-
tools/perf/builtin-top.c +0 -20
index 1e8e92e..b513e40 100644
@@ -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
index d7f21d7..d93e0bb 100644
@@ -552,6 +552,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
index 887ee63..8e790da 100644
@@ -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 +376 -144

932 lines not on this page · raw message

tools/perf/util/probe-event.h +16 -21
index bc06d3e..f69f98e 100644
@@ -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 */
@@ -68,6 +69,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 */
 };
 
@@ -92,25 +94,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);
@@ -118,7 +113,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 +17 -17
index 3e64e1f..f3a024a 100644
@@ -406,10 +406,10 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
  * Probe finder related functions
  */
 
-static struct kprobe_trace_arg_ref *alloc_trace_arg_ref(long offs)
+static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
 {
-	struct kprobe_trace_arg_ref *ref;
-	ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
+	struct probe_trace_arg_ref *ref;
+	ref = zalloc(sizeof(struct probe_trace_arg_ref));
 	if (ref != NULL)
 		ref->offset = offs;
 	return ref;
@@ -425,7 +425,7 @@ static int convert_variable_location(Dwarf_Die *vr_die, 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;
 	int ret;
 
 	/* TODO: handle more than 1 exprs */
@@ -499,10 +499,10 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 }
 
 static int convert_variable_type(Dwarf_Die *vr_die,
-				 struct kprobe_trace_arg *tvar,
+				 struct probe_trace_arg *tvar,
 				 const char *cast)
 {
-	struct kprobe_trace_arg_ref **ref_ptr = &tvar->ref;
+	struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
 	Dwarf_Die type;
 	char buf[16];
 	int ret;
@@ -540,7 +540,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
 			while (*ref_ptr)
 				ref_ptr = &(*ref_ptr)->next;
 			/* Add new reference with offset +0 */
-			*ref_ptr = zalloc(sizeof(struct kprobe_trace_arg_ref));
+			*ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
 			if (*ref_ptr == NULL) {
 				pr_warning("Out of memory error\n");
 				return -ENOMEM;
@@ -585,10 +585,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, tag;
@@ -614,7 +614,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
 		pr_debug2("Array real type: (%x)\n",
 			 (unsigned)dwarf_dieoffset(&type));
 		if (tag == DW_TAG_pointer_type) {
-			ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
+			ref = zalloc(sizeof(struct probe_trace_arg_ref));
 			if (ref == NULL)
 				return -ENOMEM;
 			if (*ref_ptr)
@@ -645,7 +645,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)
@@ -778,7 +778,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;
@@ -843,7 +843,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++) {
@@ -1100,9 +1100,9 @@ static int find_probe_point_by_func(struct probe_finder *pf)
 	return _param.retval;
 }
 
-/* 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)
+/* Find probe_trace_events specified by perf_probe_event from debuginfo */
+int find_probe_trace_events(int fd, struct perf_probe_event *pev,
+			     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;
@@ -1112,7 +1112,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 +5 -5
index e1f61dc..4507d51 100644
@@ -16,9 +16,9 @@ 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,
+/* Find probe_trace_events specified by perf_probe_event from debuginfo */
+extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
+				    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 {
#27 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 11/13] perf: perf interface for uprobes

Before some more comments: this is getting really nice! Kudos!

Em Mon, Jul 12, 2010 at 04:04:22PM +0530, Srikar Dronamraju escreveu:
<SNIP>

Quoted 2 lines
tools/perf/util/probe-event.c +0 -0
index 09cf546..ef7c2d5 100644

<SNIP>

Quoted 12 lines
tools/perf/util/probe-event.c +8 -0
@@ -403,6 +426,115 @@ static bool check_event_name(const char *name)
 	return true;
 }
 
+/*
+ * uprobe_events only accepts address:
+ * Convert function and any offset to address
+ */
+static int convert_name_to_addr(struct perf_probe_event *pev)
+{
+	struct perf_probe_point *pp = &pev->point;
+	struct perf_session *session;

tools/perf/util/probe-event.c static bool check_event_name(const char *name) · line 446

Quoted 10 lines
tools/perf/util/probe-event.c +10 -0
+	struct thread *thread;
+	struct symbol *sym;
+	struct map *map;
+	char *name;
+	int ret = -EINVAL;
+	unsigned long long vaddr;
+
+	/* check if user has specifed a virtual address */
+	vaddr = strtoul(pp->function, NULL, 0);
+	session = perf_session__new(NULL, O_WRONLY, false, false);

At first creating a session here looks too much, lets see below...

tools/perf/util/probe-event.c static bool check_event_name(const char *name) · line 458

Quoted 12 lines
tools/perf/util/probe-event.c +12 -0
+	if (!session) {
+		pr_warning("Cannot initialize perf session.\n");
+		return -ENOMEM;
+	}
+
+	symbol_conf.try_vmlinux_path = false;
+	if (!vaddr)
+		symbol_conf.sort_by_name = true;
+	if (symbol__init() < 0) {
+		pr_warning("Cannot initialize symbols.\n");
+		goto free_session;
+	}

Configuring the symbol lib on a library function is a no-go, this function (symbol__init()) should be marked with the equivalent of "module_init()" on tools that need the symbol library, i.e. be called from the cmd_{top,report,probe,etc} level.

tools/perf/util/probe-event.c static bool check_event_name(const char *name) · line 465

Quoted 6 lines
tools/perf/util/probe-event.c +6 -0
+	event__synthesize_thread(pev->upid, event__process, session);
+	thread = perf_session__findnew(session, pev->upid);
+	if (!thread) {
+		pr_warning("Cannot initialize perf session.\n");
+		goto free_session;
+	}

Got it, you want to read an existing thread, get it into the perf_session threads rb_tree to then use what was parsed from /proc.

I think you should change event__synthesize_thread somehow to achieve taht same goal instead of going in such a roundabout way, unless you need the session for some other need.

Probably we could change it to create a thread instance that then would be used to synthesize the MMAP and COMM events... but then for the existing use case we would be creating such events just to trow those objects away right after synthesizing the PERF_RECORD_{MMAP,COMM} events... perhaps duplicate them after all :-\

If I don't come with something for this quickly we can go on using what you coded and later refactor it to remove the fat.

<SNIP>

Quoted 9 lines
tools/perf/util/probe-event.c +3 -2
@@ -712,16 +858,17 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
 	return false;
 }
 
-/* Parse kprobe_events event into struct probe_point */
-int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
+/* Parse probe_events (uprobe_events) event into struct probe_point */
+static int parse_probe_trace_command(const char *cmd,
+					struct probe_trace_event *tev)

tools/perf/util/probe-event.c bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) · line 871

Quoted 10 lines
tools/perf/util/probe-event.c +2 -2
 {
-	struct kprobe_trace_point *tp = &tev->point;
+	struct probe_trace_point *tp = &tev->point;
 	char pr;
 	char *p;
 	int ret, i, argc;
 	char **argv;
 
-	pr_debug("Parsing kprobe_events: %s\n", cmd);
+	pr_debug("Parsing probe_events: %s\n", cmd);

I suggest you put these s/kprobe/probe/g parts in a separate patch for easing review :)

<SNIP>

- Arnaldo

#28 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 11/13] perf: perf interface for uprobes

Quoted 2 lines

Before some more comments: this is getting really nice! Kudos!

Thanks.

Quoted 6 lines

tools/perf/util/probe-event.c static bool check_event_name(const char *name) · line 446

Quoted 4 lines
tools/perf/util/probe-event.c +4 -0
+
+	/* check if user has specifed a virtual address */
+	vaddr = strtoul(pp->function, NULL, 0);
+	session = perf_session__new(NULL, O_WRONLY, false, false);

At first creating a session here looks too much, lets see below...

Okay.

Quoted 12 lines

tools/perf/util/probe-event.c static bool check_event_name(const char *name) · line 458

Quoted 7 lines
tools/perf/util/probe-event.c +6 -0
+	if (!vaddr)
+		symbol_conf.sort_by_name = true;
+	if (symbol__init() < 0) {
+		pr_warning("Cannot initialize symbols.\n");
+		goto free_session;
+	}

Configuring the symbol lib on a library function is a no-go, this function (symbol__init()) should be marked with the equivalent of "module_init()" on tools that need the symbol library, i.e. be called from the cmd_{top,report,probe,etc} level.

Oh okay, I then might be doing the same thing in patch 13/13. I will correct there too.

Quoted 11 lines

tools/perf/util/probe-event.c static bool check_event_name(const char *name) · line 465

Quoted 7 lines
tools/perf/util/probe-event.c +6 -0
+	event__synthesize_thread(pev->upid, event__process, session);
+	thread = perf_session__findnew(session, pev->upid);
+	if (!thread) {
+		pr_warning("Cannot initialize perf session.\n");
+		goto free_session;
+	}

Got it, you want to read an existing thread, get it into the perf_session threads rb_tree to then use what was parsed from /proc.

Quoted 3 lines

I think you should change event__synthesize_thread somehow to achieve taht same goal instead of going in such a roundabout way, unless you need the session for some other need.

Right, I need the session for the thread.

Quoted 9 lines

Probably we could change it to create a thread instance that then would be used to synthesize the MMAP and COMM events... but then for the existing use case we would be creating such events just to trow those objects away right after synthesizing the PERF_RECORD_{MMAP,COMM} events... perhaps duplicate them after all :-\

If I don't come with something for this quickly we can go on using what you coded and later refactor it to remove the fat.

Okay. I am fine either way.

Quoted 9 lines
Quoted 9 lines
tools/perf/util/probe-event.c +2 -1
+					struct probe_trace_event *tev)
 {
-	struct kprobe_trace_point *tp = &tev->point;
+	struct probe_trace_point *tp = &tev->point;
 	char pr;
 	char *p;
 	int ret, i, argc;
 	char **argv;
Quoted 6 lines

tools/perf/util/probe-event.c bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) · line 871

Quoted 2 lines
tools/perf/util/probe-event.c +1 -1
-	pr_debug("Parsing kprobe_events: %s\n", cmd);
+	pr_debug("Parsing probe_events: %s\n", cmd);

I suggest you put these s/kprobe/probe/g parts in a separate patch for easing review :)

Okay .

--
Thanks and Regards
Srikar

#29 lore raw

RFC PATCH v9 12/13 perf: Show Potential probe points.

In reply to Srikar Dronamraju

[RFC] perf: Show Potential probe points.

Introduces an option to list potential probes to probe using perf probe command. Also introduces an option to limit the dso to list the potential probes. Listing of potential probes is sorted by dso and alphabetical order.

---

Show all potential probes in the current running kernel and limit to the last 10 functions.

# perf probe -S | tail
zone_reclaimable_pages
zone_spanned_pages_in_node
zone_statistics
zone_wait_table_init
zone_watermark_ok
zoneinfo_open
zoneinfo_show
zoneinfo_show_print
zoneref_set_zone
zp_probe

Show all potential probes in a process by pid 21106 across all dsos and limit to the last 10 functions.

# perf probe -S -p 21106 | tail
_nss_files_gethostbyname2_r
_nss_files_gethostbyname_r
_nss_files_gethostent_r
_nss_files_gethostton_r
_nss_files_getnetbyaddr_r
_nss_files_getnetbyname_r
_nss_files_getnetent_r
_nss_files_getnetgrent_r
_nss_files_getntohost_r
_nss_files_getpr

Show all potentail probes in a process by pid 21106 limit to zsh dso and limit to the last 10 functions.

# perf probe -S -p 21106 -D zsh | tail
zstrtol
ztrcmp
ztrdup
ztrduppfx
ztrftime
ztrlen
ztrncpy
ztrsub
zwarn
zwarnnam
 tools/perf/builtin-probe.c    |   40 +++++++++++++++++++
 tools/perf/util/map.h         |    2 +
 tools/perf/util/probe-event.c |   85 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/probe-event.h |    1 
 tools/perf/util/symbol.c      |   38 ++++++++++++++++++
 tools/perf/util/symbol.h      |    1 
 6 files changed, 165 insertions(+), 2 deletions(-)
tools/perf/builtin-probe.c +39 -1
index cb915a5..5076e07 100644
@@ -50,9 +50,11 @@ static struct {
 	bool list_events;
 	bool force_add;
 	bool show_lines;
+	bool list_functions;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
+	struct strlist *limitlist;
 	struct line_range line_range;
 	int max_probe_points;
 	pid_t upid;
@@ -134,6 +136,17 @@ static int opt_show_lines(const struct option *opt __used,
 }
 #endif
 
+static int opt_limit_dsos(const struct option *opt __used,
+			       const char *str, int unset __used)
+{
+	if (str) {
+		if (!params.limitlist)
+			params.limitlist = strlist__new(true, NULL);
+		strlist__add(params.limitlist, str);
+	}
+	return 0;
+}
+
 static const char * const probe_usage[] = {
 	"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
 	"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
@@ -192,6 +205,10 @@ static const struct option options[] = {
 		 "Set how many probe points can be found for a probe."),
 	OPT_INTEGER('p', "pid", &params.upid,
 			"specify a pid for a uprobes based probe"),
+	OPT_BOOLEAN('S', "show_functions", &params.list_functions,
+				"Show potential probes."),
+	OPT_CALLBACK('D', "limit_dsos", NULL, "DSO",
+				"Limit Dsos.", opt_limit_dsos),
 	OPT_END()
 };
 
@@ -217,7 +234,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		params.max_probe_points = MAX_PROBES;
 
 	if ((!params.nevents && !params.dellist && !params.list_events &&
-	     !params.show_lines))
+	     !params.show_lines && !params.list_functions))
 		usage_with_options(probe_usage, options);
 
 	if (params.list_events) {
@@ -233,12 +250,33 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_warning("  Error: Don't use --list with --pid.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (params.list_functions) {
+			pr_warning("  Error: Don't use --list with --show_functions.\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",
 			       ret);
 		return ret;
 	}
+	if (params.list_functions) {
+		if (params.nevents != 0 || params.dellist) {
+			pr_err("  Error: Don't use --show_functions with"
+					"--add/--del.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.show_lines) {
+			pr_err("  Error: Don't use --show_functions with"
+					"--line.\n");
+			usage_with_options(probe_usage, options);
+		}
+		ret = show_possible_probes(params.limitlist, params.upid);
+		if (ret < 0)
+			pr_err("  Error: Failed to show possible"
+					"probes (%d).\n", ret);
+		return ret;
+	}
 
 #ifdef DWARF_SUPPORT
 	if (params.show_lines && !params.upid) {
tools/perf/util/map.h +2 -0
index f391345..b7dedcd 100644
@@ -210,6 +210,8 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
 
 struct map *map_groups__find_by_name(struct map_groups *self,
 				     enum map_type type, const char *name);
+int map_groups__iterate_maps(struct map_groups *self, enum map_type type,
+		const char *name, int (*fn)(struct map*, const char *));
 struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
 
 void map_groups__flush(struct map_groups *self);
tools/perf/util/probe-event.c +84 -1

94 lines not on this page · raw message

tools/perf/util/probe-event.h +1 -0
index f69f98e..a7a6a86 100644
@@ -116,6 +116,7 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 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);
+extern int show_possible_probes(struct strlist *availlist, pid_t pid);
 
 
 /* Maximum index number of event-name postfix */
tools/perf/util/symbol.c +38 -0
index 971d0a0..18bb1d8 100644
@@ -1448,6 +1448,28 @@ struct map *map_groups__find_by_name(struct map_groups *self,
 	return NULL;
 }
 
+int map_groups__iterate_maps(struct map_groups *self, enum map_type type,
+			const char *name, int (*fn)(struct map*, const char *))
+{
+	struct rb_node *nd;
+	struct map *map;
+	int ret;
+
+	if (!fn)
+		return -EINVAL;
+
+	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
+		map = rb_entry(nd, struct map, rb_node);
+		if (!map)
+			return -EINVAL;
+
+		ret = fn(map, name);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
 static int dso__kernel_module_get_build_id(struct dso *self,
 				const char *root_dir)
 {
@@ -2343,3 +2365,19 @@ int machine__load_vmlinux_path(struct machine *self, enum map_type type,
 
 	return ret;
 }
+
+void dso__list_available_symbols(struct dso *self, enum map_type type)
+{
+	struct rb_root *rb;
+	struct rb_node *nd;
+	struct symbol_name_rb_node *pos;
+
+	if (!self)
+		return;
+
+	rb = &self->symbol_names[type];
+	for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) {
+		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
+		printf("%s\n", pos->sym.name);
+	}
+}
tools/perf/util/symbol.h +1 -0
index 80e569b..04614b0 100644
@@ -195,6 +195,7 @@ char dso__symtab_origin(const struct dso *self);
 void dso__set_long_name(struct dso *self, char *name);
 void dso__set_build_id(struct dso *self, void *build_id);
 void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine);
+void dso__list_available_symbols(struct dso *self, enum map_type type);
 struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
 struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
 					const char *name);
#30 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 12/13] [RFC] perf: Show Potential probe points.

Em Mon, Jul 12, 2010 at 04:04:32PM +0530, Srikar Dronamraju escreveu:

Quoted 9 lines

Introduces an option to list potential probes to probe using perf probe command. Also introduces an option to limit the dso to list the potential probes. Listing of potential probes is sorted by dso and alphabetical order.

Show all potential probes in the kernel and limit to the last 10 functions.

# perf probe -S | tail
zone_reclaimable_pages
zone_spanned_pages_in_node

<SNIP>

tools/perf/builtin-probe.c static int opt_show_lines(const struct option *opt __used, · line 144

Quoted 11 lines
tools/perf/builtin-probe.c +6 -0
@@ -134,6 +136,17 @@ static int opt_show_lines(const struct option *opt __used,
 }
 #endif
 
+static int opt_limit_dsos(const struct option *opt __used,
+			       const char *str, int unset __used)
+{
+	if (str) {
+		if (!params.limitlist)
+			params.limitlist = strlist__new(true, NULL);

What if strlist__new() fails?

Quoted 13 lines
tools/perf/builtin-probe.c +5 -0
+		strlist__add(params.limitlist, str);
+	}
+	return 0;
+}
+
 static const char * const probe_usage[] = {
 	"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
 	"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
tools/perf/util/map.h +0 -0
index f391345..b7dedcd 100644

tools/perf/util/map.h int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, · line 214

Quoted 5 lines
tools/perf/util/map.h +2 -0
@@ -210,6 +210,8 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
 
 struct map *map_groups__find_by_name(struct map_groups *self,
 				     enum map_type type, const char *name);
+int map_groups__iterate_maps(struct map_groups *self, enum map_type type,
+		const char *name, int (*fn)(struct map*, const char *));

Humm, here I think perhaps we should try to do as the kernel and introduce some form of:

map_groups__for_each_map(self, pos)

Like we have for list_for_each_entry, strlist__for_each, for_each_lang, for_each_script, etc.

Matter of coding style, following the culture of the kernel is a goal for these tools, to encourage kernel hackers to contribute to these tools.

Quoted 157 lines
tools/perf/util/map.h +0 -0
 struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
 
 void map_groups__flush(struct map_groups *self);
tools/perf/util/probe-event.c +84 -1
index ef7c2d5..05b0748 100644
@@ -1842,7 +1842,6 @@ int del_perf_probe_events(struct strlist *dellist, pid_t pid)
 	struct str_node *ent;
 	struct strlist *namelist = NULL, *unamelist = NULL;
 
-
 	/* Get current event names */
 	if (!pid) {
 		kfd = open_kprobe_events(true);
@@ -1907,3 +1906,87 @@ error:
 	}
 	return ret;
 }
+
+static int print_list_available_symbols(struct map *map,
+					const char *name __unused)
+{
+	if (map__load(map, NULL) < 0)
+		return -EINVAL;
+	if (!dso__sorted_by_name(map->dso, map->type))
+		dso__sort_by_name(map->dso, map->type);
+
+	dso__list_available_symbols(map->dso, map->type);
+	return 0;
+}
+
+int show_possible_probes(struct strlist *limitlist, pid_t pid)
+{
+	struct perf_session *session;
+	struct thread *thread;
+	struct str_node *ent;
+	struct map *map = NULL;
+	char *name, *str;
+	int ret = -EINVAL;
+
+	if (!pid) {
+		ret = init_vmlinux();
+		if (ret < 0)
+			return ret;
+		return print_list_available_symbols(
+				machine.vmlinux_maps[MAP__FUNCTION], NULL);
+	}
+
+	session = perf_session__new(NULL, O_WRONLY, false, false);
+	if (!session) {
+		ret = -ENOMEM;
+		goto out_delete;
+	}
+
+	symbol_conf.sort_by_name = true;
+	symbol_conf.try_vmlinux_path = false;
+	if (symbol__init() < 0)
+		semantic_error("Cannot initialize symbols.");
+
+	event__synthesize_thread(pid, event__process, session);
+
+	thread = perf_session__findnew(session, pid);
+	if (!thread)
+		goto out_delete;
+
+	if (!limitlist)
+		ret = map_groups__iterate_maps(&thread->mg,
+				MAP__FUNCTION, NULL,
+				print_list_available_symbols);
+	strlist__for_each(ent, limitlist) {
+		str = strdup(ent->s);
+		if (!str) {
+			ret = -ENOMEM;
+			goto out_delete;
+		}
+
+		name = basename(make_absolute_path(str));
+		if (!name) {
+			pr_warning("Skip probe listing in %s DSO.", str);
+			free(str);
+			continue;
+		}
+		map = map_groups__find_by_name(&thread->mg,
+						MAP__FUNCTION, name);
+		if (!map) {
+			pr_warning("Skip probe listing in %s DSO.", str);
+			free(str);
+			continue;
+		}
+		ret = print_list_available_symbols(map, NULL);
+		if (ret)
+			pr_warning("Unknown dso %s .\n", str);
+		free(str);
+	}
+
+out_delete:
+	if (ret)
+		pr_warning("Failed to list available probes.\n");
+	if (session)
+		perf_session__delete(session);
+	return ret;
+}
tools/perf/util/probe-event.h +1 -0
index f69f98e..a7a6a86 100644
@@ -116,6 +116,7 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 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);
+extern int show_possible_probes(struct strlist *availlist, pid_t pid);
 
 
 /* Maximum index number of event-name postfix */
tools/perf/util/symbol.c +27 -0
index 971d0a0..18bb1d8 100644
@@ -1448,6 +1448,28 @@ struct map *map_groups__find_by_name(struct map_groups *self,
 	return NULL;
 }
 
+int map_groups__iterate_maps(struct map_groups *self, enum map_type type,
+			const char *name, int (*fn)(struct map*, const char *))
+{
+	struct rb_node *nd;
+	struct map *map;
+	int ret;
+
+	if (!fn)
+		return -EINVAL;
+
+	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
+		map = rb_entry(nd, struct map, rb_node);
+		if (!map)
+			return -EINVAL;
+
+		ret = fn(map, name);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
 static int dso__kernel_module_get_build_id(struct dso *self,
 				const char *root_dir)
 {
@@ -2343,3 +2365,19 @@ int machine__load_vmlinux_path(struct machine *self, enum map_type type,
 
 	return ret;
 }
+
+void dso__list_available_symbols(struct dso *self, enum map_type type)
+{
+	struct rb_root *rb;
+	struct rb_node *nd;

tools/perf/util/symbol.c int machine__load_vmlinux_path(struct machine *self, enum map_type type, · line 2382

Quoted 10 lines
tools/perf/util/symbol.c +10 -0
+	struct symbol_name_rb_node *pos;
+
+	if (!self)
+		return;
+
+	rb = &self->symbol_names[type];
+	for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) {
+		pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
+		printf("%s\n", pos->sym.name);
+	}

Also here please follow the style of the other routines that print entries, i.e.:

size_t dso__fprintf_symbols(self, type, fp)

like this:

tools/perf/util/symbol.c +14 -6
index 971d0a0..85fe580 100644
@@ -370,9 +370,21 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
 	return fprintf(fp, "%s", sbuild_id);
 }
 
-size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
+size_t dso__fprintf_symbols(struct dso *self, enum map_type type, FILE *fp)
 {
+	size_t ret = 0;
 	struct rb_node *nd;
+
+	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
+		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+		ret += symbol__fprintf(pos, fp);
+	}
+
+	return ret;
+}
+
+size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
+{
 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
 
 	if (self->short_name != self->long_name)
@@ -381,12 +393,8 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
 		       self->loaded ? "" : "NOT ");
 	ret += dso__fprintf_buildid(self, fp);
 	ret += fprintf(fp, ")\n");
-	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
-		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
-		ret += symbol__fprintf(pos, fp);
-	}
 
-	return ret;
+	return ret + dso__fprintf_symbols(self, type, fp);
 }
 
 int kallsyms__parse(const char *filename, void *arg,
tools/perf/util/symbol.h +1 -0
index 261a3e3..714d286 100644
@@ -177,6 +177,7 @@ size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp);
 size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits);
 
 size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
+size_t dso__fprintf_symbols(struct dso *self, enum map_type type, FILE *fp);
 size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
 
 enum dso_origin {

------------------------------------

This way we reduce the resulting code size while following the existing style.

- Arnaldo

#31 lore raw

Re: [PATCHv9 2.6.35-rc4-tip 12/13] [RFC] perf: Show Potential probe points.

Quoted 3 lines

What if strlist__new() fails?

Okay will add a check.

Quoted 5 lines

Humm, here I think perhaps we should try to do as the kernel and introduce some form of:

Quoted 8 lines

map_groups__for_each_map(self, pos)

Like we have for list_for_each_entry, strlist__for_each, for_each_lang, for_each_script, etc.

Matter of coding style, following the culture of the kernel is a goal for these tools, to encourage kernel hackers to contribute to these tools.

Okay.

Quoted 65 lines

Also here please follow the style of the other routines that print entries, i.e.:

size_t dso__fprintf_symbols(self, type, fp)

like this:

tools/perf/util/symbol.c +14 -6
index 971d0a0..85fe580 100644
@@ -370,9 +370,21 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
 	return fprintf(fp, "%s", sbuild_id);
 }
 
-size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
+size_t dso__fprintf_symbols(struct dso *self, enum map_type type, FILE *fp)
 {
+	size_t ret = 0;
 	struct rb_node *nd;
+
+	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
+		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+		ret += symbol__fprintf(pos, fp);
+	}
+
+	return ret;
+}
+
+size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
+{
 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
 
 	if (self->short_name != self->long_name)
@@ -381,12 +393,8 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
 		       self->loaded ? "" : "NOT ");
 	ret += dso__fprintf_buildid(self, fp);
 	ret += fprintf(fp, ")\n");
-	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
-		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
-		ret += symbol__fprintf(pos, fp);
-	}
 
-	return ret;
+	return ret + dso__fprintf_symbols(self, type, fp);
 }
 
 int kallsyms__parse(const char *filename, void *arg,
tools/perf/util/symbol.h +1 -1
index 261a3e3..714d286 100644
@@ -177,6 +177,7 @@ size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp);
 size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits);
 
 size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
+size_t dso__fprintf_symbols(struct dso *self, enum map_type type, FILE *fp);
 size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
 
 enum dso_origin {
 
------------------------------------
Quoted 2 lines

This way we reduce the resulting code size while following the existing style.

Okay.

#32 lore raw

RFC PATCH v9 13/13 perf: show functions in a file without using pid

In reply to Srikar Dronamraju

[RFC] perf: show functions in a file without using pid

Lists function names in a dso. Dso needs to a filename. However passing Dso short name will not work.

---

Show last 10 functions in /bin/zsh.

# perf probe -S -D /bin/zsh | tail
zstrtol
ztrcmp
ztrdup
ztrduppfx
ztrftime
ztrlen
ztrncpy
ztrsub
zwarn
zwarnnam
 tools/perf/util/probe-event.c |   56 ++++++++++++++++++++++++-----------------
 tools/perf/util/symbol.c      |    9 +++++++
 tools/perf/util/symbol.h      |    1 +
 3 files changed, 43 insertions(+), 23 deletions(-)
tools/perf/util/probe-event.c +33 -23
index 05b0748..df7cbe8 100644
@@ -1922,13 +1922,13 @@ static int print_list_available_symbols(struct map *map,
 int show_possible_probes(struct strlist *limitlist, pid_t pid)
 {
 	struct perf_session *session;
-	struct thread *thread;
+	struct thread *thread = NULL;
 	struct str_node *ent;
 	struct map *map = NULL;
 	char *name, *str;
 	int ret = -EINVAL;
 
-	if (!pid) {
+	if (!pid && !limitlist) { /* Show functions in kernel */
 		ret = init_vmlinux();
 		if (ret < 0)
 			return ret;
@@ -1947,16 +1947,20 @@ int show_possible_probes(struct strlist *limitlist, pid_t pid)
 	if (symbol__init() < 0)
 		semantic_error("Cannot initialize symbols.");
 
-	event__synthesize_thread(pid, event__process, session);
+	if (pid)  {
+		event__synthesize_thread(pid, event__process, session);
 
-	thread = perf_session__findnew(session, pid);
-	if (!thread)
-		goto out_delete;
+		thread = perf_session__findnew(session, pid);
+		if (!thread)
+			goto out_delete;
+		if (!limitlist) {
+			ret = map_groups__iterate_maps(&thread->mg,
+					MAP__FUNCTION, NULL,
+					print_list_available_symbols);
+			goto out_delete;
+		}
+	}
 
-	if (!limitlist)
-		ret = map_groups__iterate_maps(&thread->mg,
-				MAP__FUNCTION, NULL,
-				print_list_available_symbols);
 	strlist__for_each(ent, limitlist) {
 		str = strdup(ent->s);
 		if (!str) {
@@ -1964,19 +1968,25 @@ int show_possible_probes(struct strlist *limitlist, pid_t pid)
 			goto out_delete;
 		}
 
-		name = basename(make_absolute_path(str));
-		if (!name) {
-			pr_warning("Skip probe listing in %s DSO.", str);
-			free(str);
-			continue;
-		}
-		map = map_groups__find_by_name(&thread->mg,
-						MAP__FUNCTION, name);
-		if (!map) {
-			pr_warning("Skip probe listing in %s DSO.", str);
-			free(str);
-			continue;
-		}
+		if (pid) {
+			name = basename(make_absolute_path(str));
+			if (!name) {
+				pr_warning("Skip probe listing in %s DSO.",
+							str);
+				free(str);
+				continue;
+			}
+			map = map_groups__find_by_name(&thread->mg,
+							MAP__FUNCTION, name);
+			if (!map) {
+				pr_warning("Skip probe listing in %s DSO.",
+							str);
+				free(str);
+				continue;
+			}
+		} else
+			map = dso__new_map(str);
+
 		ret = print_list_available_symbols(map, NULL);
 		if (ret)
 			pr_warning("Unknown dso %s .\n", str);
tools/perf/util/symbol.c +9 -0
index 18bb1d8..d2e9123 100644
@@ -2381,3 +2381,12 @@ void dso__list_available_symbols(struct dso *self, enum map_type type)
 		printf("%s\n", pos->sym.name);
 	}
 }
+
+
+struct map *dso__new_map(char *name)
+{
+	struct dso *dso = dso__new(name);
+	struct map *map = map__new2(0, dso, MAP__FUNCTION);
+
+	return map;
+}
tools/perf/util/symbol.h +1 -0
index 04614b0..34e046c 100644
@@ -196,6 +196,7 @@ void dso__set_long_name(struct dso *self, char *name);
 void dso__set_build_id(struct dso *self, void *build_id);
 void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine);
 void dso__list_available_symbols(struct dso *self, enum map_type type);
+struct map *dso__new_map(char *name);
 struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
 struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
 					const char *name);
#33 lore raw
In reply to Srikar Dronamraju

I tried this again and it worked. That is kinda worked becuase I could use it to trace things in my running bash instance, but haven't really figured out how to trace something useful using the pid based interface. The processes I care about really don't run long enough for that.

So thanks for the good work so far, but we'll really need a way to define the trace points per-file and have a way to invoke a program with tracing that uses it enabled.

A minor note on perf probe -S output: This seems to include a lot of T.456 or similar labels, which from my recollection are gcc internal things. It would be good to filter those out as they aren't quite useful and just fill up the list.

And I really need to complain about the per-patch changelogs inside the visible commit message again. I know you disagree, but it's a real pain to read through it in git-log when you look for information about the patch (which for some of the patches is rather short anyway) and all you see is some rather useless patch versioning changelogs. This is what basically all patches to the kernel do, and what's also suggested in Documentation/SubmittingPatches.

While talking about changelogs: your patches duplicate the patch subject line inside the mail body, leading to rather funny git commit messages after a git-am:

commit c32a1b63db113bb1508dbf01af34d29f6cda747a

Author: Srikar Dronamraju <[email protected]>
Date:   Mon Jul 12 16:04:42 2010 +0530

perf: show functions in a file without using pid

[RFC] perf: show functions in a file without using pid

...

#34 lore raw
Quoted 2 lines

I tried this again and it worked. That is kinda worked becuase I could

Thanks for trying.

Quoted 3 lines

use it to trace things in my running bash instance, but haven't really figured out how to trace something useful using the pid based interface. The processes I care about really don't run long enough for that.

I am working/(continue to work) on file based probes. But currently spending some of my time merging the current patchset to latest tip. Once this patchset gets pushed to tip, I should be able to speed up the file based probing.

Quoted 9 lines

So thanks for the good work so far, but we'll really need a way to define the trace points per-file and have a way to invoke a program with tracing that uses it enabled.

A minor note on perf probe -S output: This seems to include a lot of T.456 or similar labels, which from my recollection are gcc internal things. It would be good to filter those out as they aren't quite useful and just fill up the list.

Okay .. will take a look. Offhand I dont know about the T.456 labels, so I will google and see if its possible for us to identify if its a t.456 label. However if you know how to identify a t456 label from normal functions, then it would be great.

Quoted 7 lines

And I really need to complain about the per-patch changelogs inside the visible commit message again. I know you disagree, but it's a real pain to read through it in git-log when you look for information about the patch (which for some of the patches is rather short anyway) and all you see is some rather useless patch versioning changelogs.

I am okay with dropping the Changelog or moving the Changelog under the --- section. However I had retained it because Stephen Rostedt replied to your post saying he found Changelog to be useful.

Assuming, he is fine dropping the changelog, I will move the Changelog to the --- section as suggested by you.

Quoted 2 lines

This is what basically all patches to the kernel do, and what's also suggested in Documentation/SubmittingPatches.

Agree.

Quoted 5 lines

While talking about changelogs: your patches duplicate the patch subject line inside the mail body, leading to rather funny git commit messages after a git-am:

Quoted 7 lines

commit c32a1b63db113bb1508dbf01af34d29f6cda747a

Author: Srikar Dronamraju <[email protected]>
Date:   Mon Jul 12 16:04:42 2010 +0530

perf: show functions in a file without using pid

[RFC] perf: show functions in a file without using pid

Okay, I shall drop the Subject from the body of the patch next time I send the patchset.

--
Thanks and Regards
Srikar

#35 lore raw

Em Tue, Jul 20, 2010 at 12:08:05PM +0530, Srikar Dronamraju escreveu:

Quoted 9 lines
Quoted 4 lines

A minor note on perf probe -S output: This seems to include a lot of T.456 or similar labels, which from my recollection are gcc internal things. It would be good to filter those out as they aren't quite useful and just fill up the list.

Okay .. will take a look. Offhand I dont know about the T.456 labels, so I will google and see if its possible for us to identify if its a t.456 label. However if you know how to identify a t456 label from normal functions, then it would be great.

We may have some hint on the symtab, having access to one of those files to look at its symtab will help.

- Arnaldo

#36 lore raw
Quoted 7 lines

Em Tue, Jul 20, 2010 at 12:08:05PM +0530, Srikar Dronamraju escreveu:

Quoted 5 lines
Quoted 4 lines

A minor note on perf probe -S output: This seems to include a lot of T.456 or similar labels, which from my recollection are gcc internal things. It would be good to filter those out as they aren't quite useful and just fill up the list.

Quoted 7 lines
Quoted 4 lines

Okay .. will take a look. Offhand I dont know about the T.456 labels, so I will google and see if its possible for us to identify if its a t.456 label. However if you know how to identify a t456 label from normal functions, then it would be great.

We may have some hint on the symtab, having access to one of those files to look at its symtab will help.

I tried searching for t.456 gcc labels in google. I dont think I found anything interesting. Are we looking at not listing symbols that end with @plt? Can you please list an example t.456 label. Also any pointers to where I can find more information on the same would be very useful.

-Srikar

maintainer
#37 lore raw
Quoted 4 lines · Srikar Dronamraju

I tried searching for t.456 gcc labels in google. I dont think I found anything interesting. Are we looking at not listing symbols that end with @plt? Can you please list an example t.456 label. Also any pointers to where I can find more information on the same would be very useful.

I'm not sure you'll find anything looking for "t.456" since that is just a random label that gcc created for its internal use. But I believe that all of these temp labels have a '.' in them. Thus, you can just ignore all labels with '.'.

-- Steve

#38 lore raw
Quoted 7 lines · Steven Rostedt
Quoted 4 lines · Srikar Dronamraju

I tried searching for t.456 gcc labels in google. I dont think I found anything interesting. Are we looking at not listing symbols that end with @plt? Can you please list an example t.456 label. Also any pointers to where I can find more information on the same would be very useful.

Quoted 6 lines

I'm not sure you'll find anything looking for "t.456" since that is just a random label that gcc created for its internal use. But I believe that all of these temp labels have a '.' in them. Thus, you can just ignore all labels with '.'.

Thanks a lot for confirming this. I did some digging and was thinking that may be .L<blah><blah> were the ones that Christoph was referring.

--
Thanks and Regards
Srikar

#39 lore raw
Quoted 2 lines · Srikar Dronamraju

Thanks a lot for confirming this. I did some digging and was thinking that may be .L<blah><blah> were the ones that Christoph was referring.

Well, for me it's T.<blah><blah>, but these seem to be either the same or similar.

maintainer
#40 lore raw
Quoted 6 lines · Christoph Hellwig
Quoted 2 lines · Srikar Dronamraju

Thanks a lot for confirming this. I did some digging and was thinking that may be .L<blah><blah> were the ones that Christoph was referring.

Well, for me it's T.<blah><blah>, but these seem to be either the same or similar.

I've seen both and more.

# nm vmlinux |grep '\.'
ffffffff824d0000 b .brk.dmi_alloc
ffffffff81602710 r ACPI_PSS_BIOS_BUG_MSG.30386
ffffffff81638340 r C.283.15204
ffffffff816382f0 r C.284.15205
ffffffff8164eab0 r C.415.26901
ffffffff81621530 r C.430.27428
ffffffff81606dc0 r C.519.31522
ffffffff81647e00 r C.541.33601
[...]
ffffffff81659590 r CSWTCH.952
ffffffff8135598c t T.1032
ffffffff81355955 t T.1034
ffffffff81051ffb t T.1065
ffffffff81335398 t T.1073

This dump does not have the .L labels, but I have seen them before.

-- Steve

#41 lore raw
In reply to Srikar Dronamraju

Em Wed, Jul 21, 2010 at 08:12:00AM +0530, Srikar Dronamraju escreveu:

Quoted 11 lines
Quoted 10 lines

Em Tue, Jul 20, 2010 at 12:08:05PM +0530, Srikar Dronamraju escreveu:

Quoted 9 lines
Quoted 4 lines

A minor note on perf probe -S output: This seems to include a lot of T.456 or similar labels, which from my recollection are gcc internal things. It would be good to filter those out as they aren't quite useful and just fill up the list.

Okay .. will take a look. Offhand I dont know about the T.456 labels, so I will google and see if its possible for us to identify if its a t.456 label. However if you know how to identify a t456 label from normal functions, then it would be great.

Quoted 7 lines
Quoted 2 lines

We may have some hint on the symtab, having access to one of those files to look at its symtab will help.

I tried searching for t.456 gcc labels in google. I dont think I found anything interesting. Are we looking at not listing symbols that end with @plt? Can you please list an example t.456 label. Also any pointers to where I can find more information on the same would be very useful.

I guess this is what he means:

[acme@doppio linux-2.6-tip]$ grep ' [TtWw] .\+\.' /proc/kallsyms | head -5 ffffffff81000646 t trace_kmalloc.clone.0
ffffffff810006ac t create_dev.clone.0
ffffffff81006ae4 t test_ti_thread_flag.clone.0
ffffffff8100a388 t trace_power_start.clone.0
ffffffff8100ad8d t user_regset_copyin.clone.0
[acme@doppio linux-2.6-tip]$ readelf -s ../build/v2.6.35-rc5-tip+/vmlinux | grep ' FUNC .\+\.' | head -5

   165: ffffffff81000646   101 FUNC    LOCAL  DEFAULT    1 trace_kmalloc.clone.0
   180: ffffffff810006ac    44 FUNC    LOCAL  DEFAULT    1 create_dev.clone.0
   438: ffffffff81006ae4    22 FUNC    LOCAL  DEFAULT    1 test_ti_thread_flag.clone
   510: ffffffff81ae5c40   136 FUNC    LOCAL  DEFAULT   22 e820_end_pfn.clone.0
   750: ffffffff8100a388    65 FUNC    LOCAL  DEFAULT    1 trace_power_start.clone.0

[acme@doppio linux-2.6-tip]$

Or at least those are the ones with dots here.

- Arnaldo

maintainer
#42 lore raw
Quoted 11 lines · Arnaldo Carvalho de Melo

Em Wed, Jul 21, 2010 at 08:12:00AM +0530, Srikar Dronamraju escreveu:

I guess this is what he means:

[acme@doppio linux-2.6-tip]$ grep ' [TtWw] .\+\.' /proc/kallsyms | head -5 ffffffff81000646 t trace_kmalloc.clone.0
ffffffff810006ac t create_dev.clone.0
ffffffff81006ae4 t test_ti_thread_flag.clone.0
ffffffff8100a388 t trace_power_start.clone.0
ffffffff8100ad8d t user_regset_copyin.clone.0
[acme@doppio linux-2.6-tip]$ readelf -s ../build/v2.6.35-rc5-tip+/vmlinux | grep ' FUNC .\+\.' | head -5

Quoted 8 lines
   165: ffffffff81000646   101 FUNC    LOCAL  DEFAULT    1 trace_kmalloc.clone.0
   180: ffffffff810006ac    44 FUNC    LOCAL  DEFAULT    1 create_dev.clone.0
   438: ffffffff81006ae4    22 FUNC    LOCAL  DEFAULT    1 test_ti_thread_flag.clone
   510: ffffffff81ae5c40   136 FUNC    LOCAL  DEFAULT   22 e820_end_pfn.clone.0
   750: ffffffff8100a388    65 FUNC    LOCAL  DEFAULT    1 trace_power_start.clone.0

[acme@doppio linux-2.6-tip]$

Or at least those are the ones with dots here.

Note, in PPC64 the function names all start with dots. That is, a function name is just a symbol look up to the actual function which is referenced by a '.'.

sys_read: points to .sys_read

.sys_read: actual address of start of function.

-- Steve

#43 lore raw
In reply to Arnaldo Carvalho de Melo
Quoted 6 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 20, 2010 at 12:08:05PM +0530, Srikar Dronamraju escreveu:

Quoted 5 lines
Quoted 4 lines

A minor note on perf probe -S output: This seems to include a lot of T.456 or similar labels, which from my recollection are gcc internal things. It would be good to filter those out as they aren't quite useful and just fill up the list.

Quoted 7 lines
Quoted 4 lines

Okay .. will take a look. Offhand I dont know about the T.456 labels, so I will google and see if its possible for us to identify if its a t.456 label. However if you know how to identify a t456 label from normal functions, then it would be great.

We may have some hint on the symtab, having access to one of those files to look at its symtab will help.

Based on inputs from Christoph and Arnaldo and Steven, I was trying to see what could be filtered out from the current listing.

For example current listing of libc would list labels like these (I think Christoph is refering to these as t.456 labels). (Thankfully Steven Rostedt also confirms this).

.L2
.L3
.L4
.L5
.L6
.L7
.L8
.L9

(Think we should exclude these labels from listing.)

However I now see more classifications and I am not sure if all of these classifications should be included. I am giving 8 listings each for each classification.

stty                                          GLOBAL binding DEFAULT visibility
swab                                          GLOBAL binding DEFAULT visibility
sync                                          GLOBAL binding DEFAULT visibility
time                                          GLOBAL binding DEFAULT visibility
verr                                          GLOBAL binding DEFAULT visibility
warn                                          GLOBAL binding DEFAULT visibility
abort                                         GLOBAL binding DEFAULT visibility
alarm                                         GLOBAL binding DEFAULT visibility

(Think we should include the above in listing.)

fini                                          LOCAL binding DEFAULT visibility
init                                          LOCAL binding DEFAULT visibility
pcmp                                          LOCAL binding DEFAULT visibility
__brk                                         LOCAL binding DEFAULT visibility
comma                                         LOCAL binding DEFAULT visibility
do_in                                         LOCAL binding DEFAULT visibility
__dup                                         LOCAL binding DEFAULT visibility
_help                                         LOCAL binding DEFAULT visibility
_itoa                                         LOCAL binding DEFAULT visibility
token                                         LOCAL binding DEFAULT visibility

(I am not sure if the above should be included in listing. This type of classification seem to be present in libc only. However I might be wrong here.)

_init                                         LOCAL binding HIDDEN visibility
_fitoa                                        LOCAL binding HIDDEN visibility
__GI_ffs                                      LOCAL binding HIDDEN visibility
__utimes                                      LOCAL binding HIDDEN visibility
__futimes                                     LOCAL binding HIDDEN visibility
__GI_exit                                     LOCAL binding HIDDEN visibility
__GI_glob                                     LOCAL binding HIDDEN visibility
__GI_time                                     LOCAL binding HIDDEN visibility
__GI_verr                                     LOCAL binding HIDDEN visibility
__GI_warn                                     LOCAL binding HIDDEN visibility
__readall                                     LOCAL binding HIDDEN visibility

(Guess functions listed under this classification shouldnt be listed. Again I have seen this classification only in libc.)

brk                                           WEAK binding DEFAULT visibility
dup                                           WEAK binding DEFAULT visibility
bcmp                                          WEAK binding DEFAULT visibility
dup2                                          WEAK binding DEFAULT visibility
feof                                          WEAK binding DEFAULT visibility
ffsl                                          WEAK binding DEFAULT visibility
fork                                          WEAK binding DEFAULT visibility
getc                                          WEAK binding DEFAULT visibility
gets                                          WEAK binding DEFAULT visibility
kill                                          WEAK binding DEFAULT visibility

(I see this classification in both libraries and executables. Generally these are plt enteries. Again I am not sure if these enteries need to be part of listing. In some of the DSO, these enteries have a symbol value of
0. i.e if somebody requests to probe a weak symbol in a particular dso, then chances are we fail to probe because we dont get the right address.)

The other way to look at it is seeing how fork and malloc are categorized.

__fork                                        GLOBAL binding DEFAULT visibility
__vfork                                       GLOBAL binding DEFAULT visibility
__libc_fork                                   GLOBAL binding DEFAULT visibility
__register_atfork                             GLOBAL binding DEFAULT visibility
free_atfork                                   LOCAL binding DEFAULT visibility
__GI___vfork                                  LOCAL binding DEFAULT visibility
malloc_atfork                                 LOCAL binding DEFAULT visibility
__GI___fork                                   LOCAL binding HIDDEN visibility
__unregister_atfork                           LOCAL binding HIDDEN visibility
__GI___register_atfork                        LOCAL binding HIDDEN visibility
fork                                          WEAK binding DEFAULT visibility
vfork                                         WEAK binding DEFAULT visibility
malloc                                        GLOBAL binding DEFAULT visibility
__libc_malloc                                 GLOBAL binding DEFAULT visibility
__malloc                                      LOCAL binding DEFAULT visibility
mallochook                                    LOCAL binding DEFAULT visibility
_int_malloc                                   LOCAL binding DEFAULT visibility
malloc_check                                  LOCAL binding DEFAULT visibility
malloc_atfork                                 LOCAL binding DEFAULT visibility
__malloc_trim                                 LOCAL binding DEFAULT visibility
ptmalloc_init                                 LOCAL binding DEFAULT visibility
tr_mallochook                                 LOCAL binding DEFAULT visibility
__malloc_stats                                LOCAL binding DEFAULT visibility
malloc_hook_ini                               LOCAL binding DEFAULT visibility
ptmalloc_lock_all                             LOCAL binding DEFAULT visibility
malloc_consolidate                            LOCAL binding DEFAULT visibility
__malloc_get_state                            LOCAL binding DEFAULT visibility
__malloc_set_state                            LOCAL binding DEFAULT visibility
__malloc_check_init                           LOCAL binding DEFAULT visibility
ptmalloc_unlock_all                           LOCAL binding DEFAULT visibility
__malloc_usable_size                          LOCAL binding DEFAULT visibility
ptmalloc_unlock_all2                          LOCAL binding DEFAULT visibility
__GI___libc_malloc                            LOCAL binding HIDDEN visibility
malloc_trim                                   WEAK binding DEFAULT visibility
malloc_stats                                  WEAK binding DEFAULT visibility
malloc_get_state                              WEAK binding DEFAULT visibility
malloc_set_state                              WEAK binding DEFAULT visibility
malloc_usable_size                            WEAK binding DEFAULT visibility

I think we should just list the symbols under classification GLOBAL binding, default visibility.

--
Thanks and Regards
Srikar