This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[PATCH 2/2][RFC] user space instruction tracing example
- From: Dave Nomura <dcnltc at us dot ibm dot com>
- To: systemtap at sourceware dot org
- Cc: Maynard Johnson <mpjohn at us dot ibm dot com>
- Date: Wed, 17 Oct 2007 13:59:28 -0700
- Subject: [PATCH 2/2][RFC] user space instruction tracing example
- Organization: Linux Power Toolchain
- Reply-to: dcnltc at us dot ibm dot com
This patch is an example of how to use the usr_itrace.stp tapset for
doing user space instruction tracing on x86.
diff -paurN ../null/Makefile ./Makefile
--- ../null/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ ./Makefile 2007-10-08 13:48:58.000000000 -0700
@@ -0,0 +1,10 @@
+PWD := $(shell pwd)
+
+PROGS=probeme4
+
+default: progs
+
+progs: $(PROGS)
+
+probeme4: probeme4.o
+ cc -g probeme4.c -o probeme4
diff -paurN ../null/README ./README
--- ../null/README 1969-12-31 16:00:00.000000000 -0800
+++ ./README 2007-10-17 13:19:23.000000000 -0700
@@ -0,0 +1,62 @@
+The current support for uprobes in SystemTap requires you to provide the pid
+of the user program and the vaddr of the probe address. This example tapset
+takes command line arguments pid ($1) and proc_vaddr($2) to set up uprobe
+points to turn on and off user space instruction tracing of a subprogram
+using the usr_itrace.stp tapset interface. The user program must start up
+(so that it's pid is known) before starting the tapscript, and it must be
+delayed so that it doesn't get past the call to the subprogram being traced.
+
+The simple_usr_itrace_handler() routine in this example simply prints out the ip
+and opcode of each traced instruction. More elaborate trace data gathering
+routines need to be developed as well as post processing programs to get usable
+results.
+
+To run this example:
+1) build user code
+mkdir usr_itrace
+mv usr_itrace.stp usr_itrace/
+make
+2) find the vaddr of a subprogram to trace
+nm probeme4 | awk '$3=="doit" {print "0x" $1}' > vaddr
+=========== window 1 ===================
+% ./probeme4 1
+I am process 12228
+:
+=========== window 2 ===================
+% stap -g sstep.stp -I usr_itrace 12228 `cat vaddr`
+sstep:usr_itrace_init completed; continue user program
+=========== window 1 ===================
+<hit ENTER to let user program run>
+1 interations in 0.000318 sec
+318.000000 usec per iteration
+sum = 1
+=========== window 2 ===================
+usr_itrace_on(12228)
+sstep:usr_itrace_on(804855e) completed for pid=12228
+ip=8048560 opcode=0x83
+ip=8048563 opcode=0xc7
+ip=804856a opcode=0xc7
+ip=8048571 opcode=0xeb
+ip=8048585 opcode=0x8b
+ip=8048588 opcode=0x3b
+ip=804858b opcode=0x7e
+ip=8048573 opcode=0x8b
+ip=8048576 opcode=0x8b
+ip=8048579 opcode=0xe8
+ip=8048544 opcode=0x55
+ip=8048545 opcode=0x89
+ip=8048547 opcode=0x83
+ip=804854a opcode=0x89
+ip=804854d opcode=0x89
+ip=8048550 opcode=0x8b
+ip=8048553 opcode=0x03
+ip=8048556 opcode=0xc9
+ip=8048557 opcode=0xc3
+ip=804857e opcode=0x89
+ip=8048581 opcode=0x83
+ip=8048585 opcode=0x8b
+ip=8048588 opcode=0x3b
+ip=804858b opcode=0x7e
+ip=804858d opcode=0xe8
+ip=8048558 opcode=0xcc
+sstep:usr_itrace_off(8048592) completed for pid=12228
diff -paurN ../null/probeme4.c ./probeme4.c
--- ../null/probeme4.c 1969-12-31 16:00:00.000000000 -0800
+++ ./probeme4.c 2007-10-12 21:45:22.000000000 -0700
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ucontext.h>
+
+#define noinline __attribute__((noinline))
+#define fastcall __attribute__((regparm(3)))
+
+noinline fastcall static int add(int n1, int n2)
+{
+ return n1 + n2;
+}
+
+noinline int doit(int n)
+{
+ int sum = 0;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ sum = add(sum, i);
+ }
+ return sum;
+}
+
+main(int argc, char **argv)
+{
+ int n, sum;
+ char line[100];
+ struct timeval start, finish;
+ long usec;
+
+ if (argc != 2 || (n = atoi(argv[1])) <= 0) {
+ fprintf(stderr, "Usage: %s niter\n", argv[0]);
+ exit(1);
+ }
+
+
+ fprintf(stderr, "I am process %d\n:", getpid());
+ fgets(line, 100, stdin);
+
+ (void) gettimeofday(&start, NULL);
+ sum = doit(n);
+ (void) gettimeofday(&finish, NULL);
+ usec = 1000*1000*(finish.tv_sec - start.tv_sec)
+ + (finish.tv_usec - start.tv_usec);
+ printf("%d interations in %.6f sec\n", n, ((double)usec) / (1000*1000));
+ printf("%.6f usec per iteration\n", ((double)usec) / n);
+ printf("sum = %d\n", sum);
+ exit(0);
+}
diff -paurN ../null/sstep.stp ./sstep.stp
--- ../null/sstep.stp 1969-12-31 16:00:00.000000000 -0800
+++ ./sstep.stp 2007-10-17 13:14:00.000000000 -0700
@@ -0,0 +1,61 @@
+%{
+/* example script that uses user space instruction tracing
+ * Copyright (C) 2005, 2006, 2007 IBM Corp.
+ *
+ * You can redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+/*
+ * This sample script for doing user space instruction tracing takes 2 command
+ * line arguments to the stap invocation:
+ * stap -g sstep.stp <pid> <proc_vaddr>
+ * where
+ * <pid> is the pid of the user program you are tracing
+ * <proc_vaddr> is the vaddr of the subprogram you want to trace
+ *
+ * It requires you to manually determine the vaddr range to tracing and some
+ * way of suspending your user program before you get to the subprogram that
+ * you are tracing, so that you can invoke the stap command.
+ * Unfortunately I couldn't find any way of setting the uprobe using the
+ * tap function target() when using the -c option. This problem will probably
+ * be solved when full support for uprobes is added to SystemTap.
+ */
+
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+
+static void
+simple_usr_itrace_handler(struct task_struct *tsk, struct pt_regs *regs)
+{
+ unsigned char opcode = *((unsigned char *)instruction_pointer(regs));
+ _stp_printf("ip=%lx opcode=%#2.2x\n",
+ instruction_pointer(regs), opcode);
+}
+%}
+
+function simple_usr_itrace_handler_address:long ()
+%{
+ THIS->__retvalue = (long)&simple_usr_itrace_handler;
+%}
+
+probe process($1).statement($2).absolute
+{
+ if (usr_itrace_on($1))
+ printf("sstep:usr_itrace_on(%x) completed for tid=%d\n", $2, $1)
+}
+
+probe process($1).statement($2).absolute.return
+{
+ usr_itrace_off($1)
+ printf("sstep:usr_itrace_off(%x) completed for tid=%d\n", $2, $1)
+}
+
+probe begin
+{
+ if (usr_itrace_init("single_step", simple_usr_itrace_handler_address()))
+ printf("sstep:usr_itrace_init completed; continue user program\n")
+ else
+ exit()
+}