This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/2][RFC] user space instruction tracing tapset


This patch is the tapset usr_itrace.stp that I propose putting into runtimes/tapset to support user space instruction tracing.
diff -paurN ../null/tapset/usr_itrace.stp ./tapset/usr_itrace.stp
--- ../null/tapset/usr_itrace.stp	1969-12-31 16:00:00.000000000 -0800
+++ ./tapset/usr_itrace.stp	2007-10-17 13:12:20.000000000 -0700
@@ -0,0 +1,271 @@
+%{
+/*
+ * user space instruction tracing tapset
+ * Copyright (C) 2005, 2006, 2007 IBM Corp.
+ *
+ * This file is part of systemtap, and is free software.  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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/rcupdate.h>
+#include <linux/utrace.h>
+#include <linux/uprobes.h>
+#include <asm/string.h>
+#include <asm/tracehook.h>
+
+#ifndef put_task_struct
+#define put_task_struct(t)	\
+	BUG_ON(atomic_dec_and_test(&tsk->usage))
+#endif
+
+struct itrace_info {
+	pid_t tid;
+	int itrace_on;
+	struct task_struct *tsk;
+	struct utrace_attached_engine *engine;
+	struct list_head link;
+};
+
+
+static LIST_HEAD(usr_itrace_info);
+static DEFINE_MUTEX(itrace_mutex);
+
+
+typedef void (*USR_ITRACE_HANDLER) (struct task_struct *, struct pt_regs *);
+static USR_ITRACE_HANDLER usr_itrace_handler = NULL;
+static u32 step_flag = 0;
+
+static struct task_struct *get_task_by_pid(pid_t pid)
+{
+	struct task_struct *tsk;
+
+	rcu_read_lock();
+	tsk = find_task_by_pid(pid);
+	if (tsk)
+		get_task_struct(tsk);
+	return tsk;
+}
+
+static struct itrace_info *create_itrace_info(pid_t tid)
+{
+	struct task_struct *tsk;
+	struct itrace_info *ui;
+
+	tsk = get_task_by_pid(tid);
+	if (!tsk) {
+		printk(KERN_ERR "Cannot find process %d\n", tid);
+		return NULL;
+	}
+
+	/* initialize ui */
+	ui = kzalloc(sizeof(struct itrace_info), GFP_USER);
+	ui->tsk = tsk;
+	ui->tid = tid;
+	INIT_LIST_HEAD(&ui->link);
+
+	/* push ui onto usr_itrace_info */
+	mutex_lock(&itrace_mutex);
+	rcu_read_lock();
+	list_add_rcu(&ui->link, &usr_itrace_info);
+	mutex_unlock(&itrace_mutex);
+	rcu_read_unlock();
+
+	put_task_struct(tsk);
+
+	return ui;
+}
+
+static struct itrace_info *find_itrace_info(pid_t tid)
+{
+	struct itrace_info *ui = NULL;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ui, &usr_itrace_info, link) {
+		if (ui->tid == tid)
+			goto done;
+	}
+	ui = NULL;
+done:
+	rcu_read_unlock();
+	return ui;
+}
+
+static struct itrace_info *get_itrace_info(pid_t tid)
+{
+	struct itrace_info *ui = find_itrace_info(tid);
+
+	if (!ui) {
+		/* none found, so create one and push onto usr_itrace_info */
+		ui = create_itrace_info(tid);
+	}
+	return ui;
+}
+
+void static cleanup_usr_itrace(void)
+{
+	struct itrace_info *tmp;
+	struct itrace_info *ui;
+
+	list_for_each_entry_safe(ui, tmp, &usr_itrace_info, link) {
+		mutex_lock(&itrace_mutex);
+		if (ui->tsk && ui->engine) {
+			(void) utrace_detach(ui->tsk, ui->engine);
+		}
+		list_del_rcu(&ui->link);
+		mutex_unlock(&itrace_mutex);
+		synchronize_rcu();
+		kfree(ui);
+	}
+}
+
+static u32 usr_itrace_report_signal(struct utrace_attached_engine *engine,
+			     struct task_struct *tsk,
+			     struct pt_regs *regs,
+			     u32 action, siginfo_t *info,
+			     const struct k_sigaction *orig_ka,
+			     struct k_sigaction *return_ka)
+{
+	struct itrace_info *ui = engine->data;
+	
+	if (info->si_signo != SIGTRAP || !ui)
+		return UTRACE_ACTION_RESUME;
+
+	if (!ui->itrace_on) {
+		printk(KERN_INFO "usr_itrace_off: stop tracing tid %d\n", ui->tid);
+		return UTRACE_ACTION_NEWSTATE | UTRACE_SIGNAL_IGN;
+	}
+	
+
+	usr_itrace_handler(tsk, regs);
+
+	/* continue stepping, don't let any other engines see this trap */
+	return step_flag | UTRACE_ACTION_HIDE | UTRACE_SIGNAL_IGN |
+			   UTRACE_ACTION_NEWSTATE;
+}
+
+static u32 usr_itrace_report_death(struct utrace_attached_engine *e,
+	struct task_struct *tsk)
+{
+	cleanup_usr_itrace();
+	return (UTRACE_ACTION_NEWSTATE | UTRACE_ACTION_DETACH);
+}
+
+static const struct utrace_engine_ops utrace_ops =
+{
+	.report_signal = usr_itrace_report_signal,
+	.report_death = usr_itrace_report_death
+};
+
+static int attach_utrace_engine(struct itrace_info *ui)
+{
+	struct utrace_attached_engine *engine;
+
+	if (!ui || !ui->tsk) {
+		return 0;
+	}
+
+	/* if engine doesn't already exist create one */
+	if (ui->engine)
+		return 1;
+
+	ui->engine = utrace_attach(ui->tsk, UTRACE_ATTACH_CREATE, &utrace_ops, ui);
+
+	if (IS_ERR(ui->engine)) {
+		printk(KERN_ERR "utrace_attach returns %ld\n",
+			PTR_ERR(ui->engine));
+		return 0;
+	}
+	printk(KERN_INFO "attach_utrace_engine: created engine. flags=%lx\n",
+		ui->engine->flags);
+	return 1;
+}
+
+%}
+
+
+function usr_itrace_on:long (tid:long)
+%{
+	int ret;
+	pid_t tid = (pid_t)THIS->tid;
+	struct itrace_info *ui;
+
+	THIS->__retvalue = 0;
+	if (!usr_itrace_handler) {
+		printk(KERN_ERR "usr_itrace_on:usr_itrace_init() not called\n");
+		return;
+	}
+
+	if (!(ui = get_itrace_info(tid))) {
+		return;
+	}
+
+	/* attach a single stepping engine */
+	if (!attach_utrace_engine(ui))
+		return;
+
+	/* success */
+	THIS->__retvalue = 1;
+	printk(KERN_INFO "usr_itrace_on: start tracing tid %d\n", ui->tid);
+
+	/* start single-stepping engine */
+	utrace_set_flags(ui->tsk, ui->engine, ui->engine->flags | step_flag |
+		UTRACE_EVENT_SIGNAL_ALL | UTRACE_EVENT(DEATH));
+	ui->itrace_on = 1;
+%}
+
+function usr_itrace_off (tid:long)
+%{
+	int ret;
+	pid_t tid = (pid_t)THIS->tid;
+	struct itrace_info *ui = find_itrace_info(tid);
+	
+	if (!ui) {
+		printk(KERN_ERR "usr_itrace_off: cannot find engine for tid %d\n",
+			tid);
+		return;
+	}
+
+	/* turn off tracing on next single step trap */
+	ui->itrace_on = 0;
+
+%}
+
+function usr_itrace_init:long (step_mode:string, handler:long)
+%{
+	step_flag = 0;
+	if (strcmp(THIS->step_mode, "single_step") == 0)
+#if defined(ARCH_HAS_SINGLE_STEP) && (ARCH_HAS_SINGLE_STEP != 0)
+		step_flag = UTRACE_ACTION_SINGLESTEP;
+#else
+		_stp_printf("SINGLESTEP not allowed in <asm/tracehook.h> for this architecture\n");
+#endif
+	else if (strcmp(THIS->step_mode, "block_step") == 0)
+#if defined( ARCH_HAS_BLOCK_STEP) && (ARCH_HAS_BLOCK_STEP != 0)
+		step_flag = UTRACE_ACTION_BLOCKSTEP;
+#else
+		_stp_printf("BLOCKSTEP not allowed in <asm/tracehook.h> for this architecture\n");
+#endif
+	else
+		_stp_printf("unknown stepping mode: %s\n", THIS->step_mode);
+
+	if (step_flag == 0) {
+		THIS->__retvalue = 0;
+		return;
+	}
+
+	usr_itrace_handler = (USR_ITRACE_HANDLER)(long)THIS->handler;
+	THIS->__retvalue = 1;
+%}
+
+function cleanup_usr_itrace()
+%{
+	cleanup_usr_itrace();
+%}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]