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-repost] 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.

--
Dave Nomura
LTC Linux Power Toolchain

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-11-01 09:29:04.000000000 -0700
@@ -0,0 +1,303 @@
+%{
+/*
+ * 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/spinlock.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>
+#include <asm/ptrace.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 spinlock_t itrace_lock;
+
+
+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 u32 debug = 1;
+
+static struct itrace_info *create_itrace_info(struct task_struct *tsk);
+void static cleanup_usr_itrace(void);
+void static remove_usr_itrace_info(struct itrace_info *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;
+	u32 return_flags;
+
+	ui = rcu_dereference((struct itrace_info *)engine->data);
+	WARN_ON(!ui);
+	
+	if (info->si_signo != SIGTRAP || !ui)
+		return UTRACE_ACTION_RESUME;
+
+	/* normal case: continue stepping, hide this trap from other engines */
+	return_flags =  step_flag | UTRACE_ACTION_HIDE | UTRACE_SIGNAL_IGN |
+			   UTRACE_ACTION_NEWSTATE;
+
+	if (!ui->itrace_on) {
+		if (debug)
+			printk(KERN_INFO "usr_itrace_off: stop tracing tid %d\n", ui->tid);
+		return_flags = UTRACE_ACTION_NEWSTATE | UTRACE_SIGNAL_IGN;
+	}
+	
+
+	usr_itrace_handler(tsk, regs);
+
+	return return_flags;
+}
+
+static u32 usr_itrace_report_clone(struct utrace_attached_engine *engine,
+		struct task_struct *parent, unsigned long clone_flags,
+		struct task_struct *child)
+{
+	struct itrace_info *child_ui;
+	struct itrace_info *parent_ui;
+
+	if (debug)
+		printk(KERN_INFO "report_clone: parent=parent=%d, child=%d\n",
+			parent->pid, child->pid);
+	/* propagate itrace_on flag from parent to child */
+	parent_ui = rcu_dereference((struct itrace_info *)engine->data);
+	WARN_ON(!parent_ui);
+
+	get_task_struct(child);
+	child_ui = create_itrace_info(child);
+	WARN_ON(!child_ui);
+	spin_lock(&itrace_lock);
+	child_ui->itrace_on = parent_ui->itrace_on;
+	spin_unlock(&itrace_lock);
+	return UTRACE_ACTION_RESUME;
+}
+
+static u32 usr_itrace_report_death(struct utrace_attached_engine *e,
+	struct task_struct *tsk)
+{
+	struct itrace_info *ui = rcu_dereference((struct itrace_info *)e->data);
+	WARN_ON(!ui);
+	remove_usr_itrace_info(ui);
+
+	return (UTRACE_ACTION_NEWSTATE | UTRACE_ACTION_DETACH);
+}
+
+static const struct utrace_engine_ops utrace_ops =
+{
+	.report_signal = usr_itrace_report_signal,
+	.report_clone = usr_itrace_report_clone,
+	.report_death = usr_itrace_report_death
+};
+
+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);
+	rcu_read_unlock();
+
+	if (!tsk)
+		printk(KERN_ERR "Cannot find process %d\n", pid);
+	return tsk;
+}
+
+static struct itrace_info *create_itrace_info(struct task_struct *tsk)
+{
+	struct itrace_info *ui;
+
+	if (debug)
+		printk(KERN_INFO "create_itrace_info: tid=%d\n", tsk->pid);
+	/* initialize ui */
+	ui = kzalloc(sizeof(struct itrace_info), GFP_USER);
+	ui->tsk = tsk;
+	ui->tid = tsk->pid;
+	INIT_LIST_HEAD(&ui->link);
+
+	/* push ui onto usr_itrace_info */
+	spin_lock(&itrace_lock);
+	list_add(&ui->link, &usr_itrace_info);
+	spin_unlock(&itrace_lock);
+
+	/* attach a single stepping engine */
+	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));
+		ui = NULL;
+	} else {
+		utrace_set_flags(tsk, ui->engine, ui->engine->flags | step_flag |
+			UTRACE_EVENT(CLONE) | UTRACE_EVENT_SIGNAL_ALL |
+			UTRACE_EVENT(DEATH));
+	}
+
+	return ui;
+}
+
+static struct itrace_info *find_itrace_info(pid_t tid)
+{
+	struct itrace_info *ui = NULL;
+
+	spin_lock(&itrace_lock);
+	list_for_each_entry(ui, &usr_itrace_info, link) {
+		if (ui->tid == tid)
+			goto done;
+	}
+	ui = NULL;
+done:
+	spin_unlock(&itrace_lock);
+	return ui;
+}
+
+void static remove_usr_itrace_info(struct itrace_info *ui)
+{
+	struct itrace_info *tmp;
+
+	if (debug)
+		printk(KERN_INFO "remove_usr_itrace_info called\n");
+
+	WARN_ON(!ui);
+	spin_lock(&itrace_lock);
+	if (ui->tsk && ui->engine) {
+		(void) utrace_detach(ui->tsk, ui->engine);
+	}
+	list_del(&ui->link);
+	spin_unlock(&itrace_lock);
+	kfree(ui);
+}
+
+void static cleanup_usr_itrace(void)
+{
+	struct itrace_info *tmp;
+	struct itrace_info *ui;
+
+	if (debug)
+		printk(KERN_INFO "cleanup_usr_itrace called\n");
+
+	list_for_each_entry_safe(ui, tmp, &usr_itrace_info, link)
+		remove_usr_itrace_info(ui);
+}
+
+%}
+
+
+function usr_itrace_on:long (tid:long)
+%{
+	int ret;
+	pid_t tid = (pid_t)THIS->tid;
+	struct itrace_info *ui = find_itrace_info(tid);
+
+	THIS->__retvalue = -1;
+	if (!usr_itrace_handler) {
+		printk(KERN_ERR "usr_itrace_on:usr_itrace_init() not called\n");
+		return;
+	}
+
+	if (debug)
+		printk(KERN_INFO "usr_itrace_on called %d\n", tid);
+		
+	if (!ui) {
+		struct task_struct *tsk = get_task_by_pid(tid);
+		WARN_ON(!tsk);
+
+		/* none found, so create one and push onto usr_itrace_info */
+		ui = create_itrace_info(tsk);
+		WARN_ON(!ui);
+		put_task_struct(tsk);
+	}
+
+
+	/* start single-stepping engine */
+	spin_lock(&itrace_lock);
+	ui->itrace_on = 1;
+	spin_unlock(&itrace_lock);
+
+	THIS->__retvalue = 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 */
+	spin_lock(&itrace_lock);
+	ui->itrace_on = 0;
+	spin_unlock(&itrace_lock);
+%}
+
+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;
+	}
+
+	spin_lock_init(&itrace_lock);
+	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]