[RFC] [PATCH] Breakpoint assistance(SSOL) using utrace infrastructure.

Srinivasa D S srinivasa at in.ibm.com
Wed Apr 16 06:29:39 UTC 2008


Hi 

I have been working on providing breakpoint assistance(with SSOL) to 
multithreaded applications using utrace infrastructure. To start with, I have 
developed a small snippet of code which inserts/removes breakpoint at given 
address and copies the original instruction to a separate vma. Whenever the 
breakpoint is hit at the user specified address, user defined handler is 
executed and single stepping is done on the original instruction present in 
the separate vma(Single Step Out of Line, SSOL). After single stepping, we 
fixup ip to get back to the instruction after the breakpoint.

Breakpoint assistance feature can be exploited by clients of utrace like
uprobes.

I have gone through Roland's mail(written last year) and subsequent 
discussions on breakpoint assistance in systemtap mailinglist and found that 
there are some concerns in using SSOL, like

1) Where to store out of line copies.

SSOL copies are stored in a per-process SSOL area, which is a little VM area 
created on each probed process's address space. Here in code, setup_ssol_vma() 
mmaps "n" bytes and then sets vmflags of the vma, so that ssol area is not 
copied over fork and not resized with mremap.

2)Arch issues with instruction semantics.

Once we single step on the original instruction, we need to fixup ip and other 
registers to allow it to proceed from next instruction after user specified 
virtual address.
Since I have developed a minimal prototype which works on ppc, I have not
dealt with all types of instructions.(ofcourse, Iam not yet exposed to
instructions of x86/x86_64 instructions also).
post_ssol() verifies the single stepped instruction and updates the new ip
relative to the original instruction for a non-branch instruction.
For branch instruction(like b,bc) we update the nip, if the branch uses 
relative addressing and update the link register to the instruction following 
the original instruction address.
	

Implementation

register_ssol() collects pid of the process, virtual address at which
breakpoint has to be inserted and handler to be executed before single
stepping on the original instruction.

unregister_ssol() collects pid of the process, virtual address at which
breakpoint has to be removed.

prerequisite

All threads are quiesced and one of the thread makes a call to 
ssol_register().

Iam posting this small piece of code with minimal feature to collect feedback 
from the community before I develop a fully featured code.
So Please let me know your comments/views on my design and approach on 
providing breakpoint assistance.


---
 arch/powerpc/kernel/Makefile    |    1 
 arch/powerpc/kernel/ssol_bkpt.c |   79 ++++++++
 include/linux/ssol_bkpt.h       |   99 ++++++++++
 init/Kconfig                    |    9 
 kernel/Makefile                 |    1 
 kernel/ssol_bkpt.c              |  386 
++++++++++++++++++++++++++++++++++++++++
 kernel/utrace.c                 |    2 
 7 files changed, 576 insertions(+), 1 deletion(-)

Index: linux-2.6.25-rc6/kernel/utrace.c
===================================================================
--- linux-2.6.25-rc6.orig/kernel/utrace.c
+++ linux-2.6.25-rc6/kernel/utrace.c
@@ -439,7 +439,7 @@ dead:
 }
 
 
-static struct utrace_attached_engine *
+struct utrace_attached_engine *
 matching_engine(struct utrace *utrace, int flags,
 		const struct utrace_engine_ops *ops, void *data)
 {
Index: linux-2.6.25-rc6/kernel/ssol_bkpt.c
===================================================================
--- /dev/null
+++ linux-2.6.25-rc6/kernel/ssol_bkpt.c
@@ -0,0 +1,386 @@
+/*
+ *  Insetion/Removal of breakpoint
+ *  kernel/ssol_bkpt.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2008
+ */
+#include <linux/ssol_bkpt.h>
+
+static noinline unsigned long setup_ssol_vma(unsigned long nbytes)
+{
+	unsigned long addr;
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+
+	BUG_ON(nbytes & ~PAGE_MASK);
+
+	down_write(&mm->mmap_sem);
+	/*
+	* Find the end of the top mapping and skip a page.
+	* If there is no space for PAGE_SIZE above
+	* that, mmap will ignore our address hint.
+	*/
+	vma = rb_entry(rb_last(&mm->mm_rb), struct vm_area_struct, vm_rb);
+	addr = vma->vm_end + PAGE_SIZE;
+	addr = do_mmap_pgoff(NULL, addr, nbytes, PROT_EXEC,
+				 MAP_PRIVATE|MAP_ANONYMOUS, 0);
+	if (addr & ~PAGE_MASK) {
+		up_write(&mm->mmap_sem);
+		printk(KERN_ERR "Breakpoint failed to allocate a vma for"
+				"pid/tgid %d/%d for SSOL.\n",
+				current->pid, current->tgid);
+		return addr;
+	}
+
+	vma = find_vma(mm, addr);
+	BUG_ON(!vma);
+	/* avoid vma copy on fork() and don't expand when mremap() */
+	vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
+
+	up_write(&mm->mmap_sem);
+	return addr;
+}
+
+static noinline struct ssol_area *init_ssol(struct ssol_process *sproc)
+{
+	struct ssol_area *area = &sproc->sarea;
+	struct ssol_slot *slot;
+	int i;
+	char *slot_addr;
+
+	if (!sproc->sarea.initialized) {
+		sproc->sarea.initialized = 1;
+		area = (struct ssol_area *)kzalloc(sizeof(struct ssol_area),
+								 GFP_USER);
+		area->insn_area = (opcode_t *) setup_ssol_vma(PAGE_SIZE);
+		if (IS_ERR(area->insn_area))
+			return NULL;
+		area->nfree = area->nslots = PAGE_SIZE / MAX_UINSN_BYTES;
+		if (area->nslots > MAX_SSOL_SLOTS)
+		area->nfree = area->nslots = MAX_SSOL_SLOTS;
+		area->slots = (struct ssol_slot *)
+			kzalloc(sizeof(struct ssol_slot) * area->nslots,
+								 GFP_USER);
+		if (!area->slots) {
+			area->insn_area = ERR_PTR(-ENOMEM);
+			return NULL;
+		}
+		spin_lock_init(&area->lock);
+		area->next_slot = 0;
+		slot_addr = (char *) area->insn_area;
+		for (i = 0; i < area->nslots; i++) {
+			slot = &area->slots[i];
+			init_rwsem(&slot->rwsem);
+			slot->owner = NULL;
+			slot->last_used = 0;
+			slot->insn = (__user opcode_t *) slot_addr;
+			slot_addr += MAX_UINSN_BYTES;
+		}
+		return area;
+	} else
+		return &sproc->sarea;
+}
+
+static noinline int take_slot(struct ssol_area *area, struct probept *ppt)
+{
+	struct ssol_slot *s;
+	struct ssol_slot *slot;
+	int i, len;
+
+	for (i = 0; i < area->nslots; i++) {
+		slot = &area->slots[i];
+		if (slot->owner == NULL)
+			break;
+	}
+	s = &area->slots[i];
+	ppt->slot = s;
+	s->owner = ppt;
+	len = access_process_vm(current, (unsigned long)s->insn,
+				ppt->insn, MAX_UINSN_BYTES, 1);
+	if (unlikely(len < MAX_UINSN_BYTES)) {
+		printk(KERN_ERR "Failed to copy instruction at %#lx"
+			" to SSOL area (%#lx)\n", ppt->u->vaddr,
+				(unsigned long) area->slots);
+		return -1;
+	}
+	return 0;
+}
+
+static struct probept *find_ppt(unsigned long vaddr, struct ssol_process 
*sproc)
+{
+	struct hlist_node *node;
+	struct hlist_head *head;
+	struct probept *ppt;
+	int i;
+
+	for (i = 0; i < UPROBE_TABLE_SIZE; i++) {
+		head = &sproc->ppt_table[i];
+		hlist_for_each_entry(ppt, node, head, ut_node) {
+		if (ppt->u->vaddr == vaddr)
+			return ppt;
+		}
+	}
+	return NULL;
+}
+
+static u32 probe_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 ssol_area *area;
+	struct probept *ppt;
+	struct ssol_process *sproc;
+	unsigned long vaddr;
+	u32 ret;
+
+	sproc = (struct ssol_process *)rcu_dereference(engine->data);
+	vaddr = arch_get_probept(regs);
+
+	if (info->si_signo == BREAKPOINT_SIGNAL) {
+		switch (sproc->state) {
+		case UPTASK_RUNNING:
+			ppt = find_ppt(vaddr, sproc);
+			if (!ppt)
+				return UTRACE_ACTION_RESUME;
+			area = init_ssol(sproc);
+			if (!area) {
+				printk(KERN_INFO
+				  "Failed to set the ssol area \n");
+				return UTRACE_ACTION_RESUME;
+			}
+			ret = take_slot(area, ppt);
+			if (!ret) {
+				ppt->u->handler(ppt->u, regs);
+				pre_ssol(ppt, regs);
+				sproc->state = UPTASK_SSTEP;
+				sproc->active_probe = ppt;
+				ret = UTRACE_ACTION_HIDE | UTRACE_SIGNAL_IGN
+					| UTRACE_ACTION_SINGLESTEP
+					| UTRACE_ACTION_NEWSTATE;
+			}
+		break;
+		case UPTASK_SSTEP:
+			ppt = sproc->active_probe;
+			post_ssol(ppt, regs);
+			sproc->state = UPTASK_RUNNING;
+			sproc->active_probe = NULL;
+			ret = UTRACE_ACTION_HIDE | UTRACE_SIGNAL_IGN
+				| UTRACE_ACTION_NEWSTATE
+				| UTRACE_ACTION_RESUME;
+			break;
+		default :
+			ret = UTRACE_ACTION_RESUME;
+			break;
+		}
+		return ret;
+	}
+		return UTRACE_ACTION_RESUME;
+}
+
+static const struct utrace_engine_ops bpt_utrace_ops = {
+	.report_signal = probe_report_signal,
+};
+
+static int validate_vaddr(struct task_struct *p, unsigned long vaddr)
+{
+	struct vm_area_struct *vma;
+	struct mm_struct *mm = p->mm;
+	if (!mm)
+		return -EINVAL;
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, vaddr);
+	if (!vma || vaddr < vma->vm_start || !(vma->vm_flags & VM_EXEC)) {
+		up_read(&mm->mmap_sem);
+		return -EINVAL;
+	}
+	up_read(&mm->mmap_sem);
+	return 0;
+}
+
+static struct ssol_process *ssol_find_task(struct task_struct *tsk)
+{
+	struct hlist_head *head;
+	struct hlist_node *node;
+	struct ssol_process *sproc;
+
+	head = &sproc_table[hash_ptr(tsk, UPROBE_HASH_BITS)];
+	hlist_for_each_entry(sproc, node, head, hlist) {
+		if (sproc->tsk == tsk)
+			return sproc;
+	}
+	return NULL;
+}
+
+static struct ssol_process *ssol_mk_process(struct task_struct *p)
+{
+	struct ssol_process *sproc;
+	int i;
+
+	sproc = (struct ssol_process *)kzalloc(sizeof *sproc, GFP_USER);
+	if (unlikely(sproc == NULL))
+		return ERR_PTR(-ENOMEM);
+	/* Initialize fields */
+	for (i = 0; i < UPROBE_TABLE_SIZE; i++)
+		INIT_HLIST_HEAD(&sproc->ppt_table[i]);
+	INIT_HLIST_NODE(&sproc->hlist);
+	sproc->tgid = p->tgid;
+	sproc->tsk = p;
+	sproc->sarea.insn_area = NULL;
+	sproc->sarea.initialized = 0;
+	sproc->state = UPTASK_RUNNING;
+	hlist_add_head(&sproc->hlist,
+		&sproc_table[hash_long(p, UPROBE_HASH_BITS)]);
+	return sproc;
+}
+
+static struct probept *ssol_mk_ppt(struct ssol_user *u,
+				struct ssol_process *sproc)
+{
+	struct probept *ppt;
+
+	ppt = (struct probept *)kzalloc(sizeof *ppt, GFP_USER);
+	if (unlikely(ppt == NULL))
+		return ERR_PTR(-ENOMEM);
+
+	ppt->slot = NULL;
+	ppt->u = u;
+	INIT_HLIST_NODE(&ppt->ut_node);
+	hlist_add_head(&ppt->ut_node,
+		&sproc->ppt_table[hash_long(ppt->u->vaddr, UPROBE_HASH_BITS)]);
+	return ppt;
+}
+
+static int set_bp(struct probept *ppt, struct task_struct *tsk)
+{
+	opcode_t bp_insn = BREAKPOINT_INSTRUCTION;
+	return access_process_vm(tsk, ppt->u->vaddr, &bp_insn, BP_INSN_SIZE, 1);
+}
+
+void insert_bkpt(struct ssol_user *u, struct task_struct *p)
+{
+	struct utrace_attached_engine *engine = NULL;
+	unsigned long newflags;
+	int len;
+	struct probept *ppt;
+	struct ssol_process *sproc;
+
+	sproc = ssol_find_task(p);
+	if (!sproc)
+		sproc = ssol_mk_process(p);
+	ppt = find_ppt(u->vaddr, sproc);
+	if (!ppt)
+		ppt = ssol_mk_ppt(u, sproc);
+
+	engine = utrace_attach(p, UTRACE_ATTACH_CREATE,
+				&bpt_utrace_ops, sproc);
+	if (IS_ERR(engine)) {
+		long err = PTR_ERR(engine);
+		printk(KERN_ERR "utrace_attach failed, returned %ld\n",
+							err);
+		return ;
+	}
+	newflags = engine->flags;
+	newflags |= (UTRACE_EVENT(SIGNAL) | UTRACE_EVENT(SIGNAL_IGN) |
+					 UTRACE_EVENT(SIGNAL_CORE));
+
+	utrace_set_flags(p, engine, newflags);
+	len = access_process_vm(p, ppt->u->vaddr, ppt->insn, MAX_UINSN_BYTES,
+								 0);
+	if (len < BP_INSN_SIZE) {
+		printk(KERN_ERR "error reading original instruction %d\n",
+								 len);
+		return;
+	}
+	memcpy(&ppt->opcode, ppt->insn, BP_INSN_SIZE);
+	if (ppt->opcode == BREAKPOINT_INSTRUCTION) {
+		printk(KERN_ERR "bkpt already exists at that addr\n");
+		return;
+	}
+	len = set_bp(ppt, p);
+	if (len < BP_INSN_SIZE) {
+		printk(KERN_ERR "failed to insert bkpt instruction\n");
+		return;
+	}
+	return;
+}
+
+int register_ssol(struct ssol_user *u)
+{
+	int ret;
+	struct task_struct *p;
+
+	if (!u || !u->handler)
+		return -EINVAL;
+
+	rcu_read_lock();
+	p = find_task_by_pid(u->pid);
+	rcu_read_unlock();
+	if (!p)
+		return -EINVAL;
+	ret = validate_vaddr(p, u->vaddr);
+	if (ret < 0)
+		return -EINVAL;
+	insert_bkpt(u, p);
+	return 0;
+}
+EXPORT_SYMBOL(register_ssol);
+
+static int set_orig_insn(struct probept *ppt, struct task_struct *tsk)
+{
+	return access_process_vm(tsk, ppt->u->vaddr, &ppt->opcode, BP_INSN_SIZE,
+		1);
+}
+
+static void remove_bkpt(struct probept *ppt, struct task_struct *tsk)
+{
+	int len;
+
+	if (tsk) {
+		len = set_orig_insn(ppt, tsk);
+		if (len < BP_INSN_SIZE) {
+			printk(KERN_ERR
+				"Failed to remove breakpoint at %#lx:",
+				 ppt->u->vaddr);
+		}
+	}
+	hlist_del(&ppt->ut_node);
+}
+
+int unregister_ssol(struct ssol_user *u)
+{
+	struct task_struct *p;
+	struct probept *ppt;
+	struct ssol_process *sproc;
+
+	if (!u)
+		return -EINVAL;
+	rcu_read_lock();
+	p = find_task_by_pid(u->pid);
+	rcu_read_unlock();
+	if (!p)
+		return -EINVAL;
+	sproc = ssol_find_task(p);
+	ppt = find_ppt(u->vaddr, sproc);
+	if (!ppt)
+		return -EINVAL;
+	remove_bkpt(ppt, p);
+	return 0;
+}
+EXPORT_SYMBOL(unregister_ssol);
+
+MODULE_LICENSE("GPL");
Index: linux-2.6.25-rc6/include/linux/ssol_bkpt.h
===================================================================
--- /dev/null
+++ linux-2.6.25-rc6/include/linux/ssol_bkpt.h
@@ -0,0 +1,99 @@
+/*
+ * Insertion/Removal of breakpoint
+ * inlcude/linux/ssol_bkpt.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
+#include <linux/utrace.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <linux/hash.h>
+#include <linux/pagemap.h>
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include <asm/mman.h>
+
+typedef unsigned int opcode_t;
+#define BREAKPOINT_INSTRUCTION  0x7fe00008
+#define BP_INSN_SIZE 4
+#define MAX_UINSN_BYTES 4
+#define BREAKPOINT_SIGNAL SIGTRAP
+
+#define UPROBE_HASH_BITS 5
+#define UPROBE_TABLE_SIZE (1 << UPROBE_HASH_BITS)
+#define MAX_SSOL_SLOTS          1024
+
+struct ssol_area {
+	__user opcode_t *insn_area;
+	int nslots;
+	int nfree;
+	struct ssol_slot *slots;
+	spinlock_t lock;
+	int next_slot;
+	int initialized;
+};
+
+struct ssol_slot {
+	__user opcode_t  *insn;
+	struct probept *owner;
+	struct rw_semaphore rwsem;
+	unsigned long last_used;
+};
+
+struct ssol_user {
+	pid_t pid;
+	unsigned long vaddr;
+	void (*handler) (struct ssol_user*, struct pt_regs*);
+	void *kdata;
+};
+
+enum ssol_task_state {
+	UPTASK_RUNNING,
+	UPTASK_SSTEP,
+};
+
+struct probept {
+	opcode_t opcode;
+	enum ssol_task_state state;
+	struct hlist_node ut_node;
+	struct ssol_user *u;
+	opcode_t insn[MAX_UINSN_BYTES / sizeof(opcode_t)];
+	struct ssol_slot *slot;
+};
+
+struct ssol_process {
+	struct hlist_head ppt_table[UPROBE_TABLE_SIZE];
+	struct hlist_node hlist;
+	struct task_struct *tsk;
+	struct ssol_area sarea;
+	enum ssol_task_state state;
+	pid_t tgid;
+	struct probept *active_probe;
+	struct ssol_area ssol_bkpt_area;
+};
+
+void pre_ssol(struct probept *ppt, struct pt_regs *regs);
+void post_ssol(struct probept *ppt, struct pt_regs *regs);
+unsigned long arch_get_probept(struct pt_regs *regs);
+void calc_offset(struct probept *ppt, struct pt_regs *regs);
+static struct hlist_head sproc_table[UPROBE_TABLE_SIZE];
Index: linux-2.6.25-rc6/arch/powerpc/kernel/ssol_bkpt.c
===================================================================
--- /dev/null
+++ linux-2.6.25-rc6/arch/powerpc/kernel/ssol_bkpt.c
@@ -0,0 +1,79 @@
+/*
+ *  Insetion/Removal of breakpoint
+ *  kernel/ssol_bkpt.h  powerpc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2008
+ */
+#include <linux/ssol_bkpt.h>
+
+void pre_ssol(struct probept *ppt, struct pt_regs *regs)
+{
+	struct ssol_slot *slot;
+	regs->nip = (long)ppt->slot->insn;
+}
+
+void calc_offset(struct probept *ppt, struct pt_regs *regs)
+{
+	int offset = 0;
+	unsigned int opcode = 0;
+	unsigned int insn = *ppt->insn;
+
+	opcode = insn >> 26;
+	switch (opcode) {
+	case 16:        /* bc */
+		if ((insn & 2) == 0) {
+			offset = (signed short)(insn & 0xfffc);
+			regs->nip = ppt->u->vaddr + offset;
+		}
+		if (insn & 1)
+			regs->link = ppt->u->vaddr + MAX_UINSN_BYTES;
+		break;
+	case 18:        /* b */
+		if ((insn & 2) == 0) {
+			offset = insn & 0x03fffffc;
+			if (offset & 0x02000000)
+				offset -= 0x04000000;
+			regs->nip = ppt->u->vaddr + offset;
+		}
+	if (insn & 1)
+		regs->link = ppt->u->vaddr + MAX_UINSN_BYTES;
+	break;
+	}
+
+	return;
+}
+
+void post_ssol(struct probept *ppt, struct pt_regs *regs)
+{
+	unsigned long copy_nip;
+
+	copy_nip = (unsigned long) ppt->slot->insn;
+
+	/*
+	* If the single stepped instruction is non-branch instruction
+	* then update the IP to be relative to probepoint.
+	*/
+	if (regs->nip == copy_nip + MAX_UINSN_BYTES)
+		regs->nip = ppt->u->vaddr + MAX_UINSN_BYTES;
+	else
+		calc_offset(ppt, regs);
+}
+
+unsigned long arch_get_probept(struct pt_regs *regs)
+{
+	return (unsigned long)(regs->nip);
+}
Index: linux-2.6.25-rc6/arch/powerpc/kernel/Makefile
===================================================================
--- linux-2.6.25-rc6.orig/arch/powerpc/kernel/Makefile
+++ linux-2.6.25-rc6/arch/powerpc/kernel/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
 obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
+obj-$(CONFIG_SSOL)		+= ssol_bkpt.o
 obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_serial.o udbg_16550.o
 
 pci64-$(CONFIG_PPC64)		+= pci_dn.o isa-bridge.o
Index: linux-2.6.25-rc6/init/Kconfig
===================================================================
--- linux-2.6.25-rc6.orig/init/Kconfig
+++ linux-2.6.25-rc6/init/Kconfig
@@ -887,6 +887,15 @@ config UTRACE
 	  applications.  Unless you are making a specially stripped-down
 	  kernel and are very sure you don't need these facilitiies,
 	  say Y.
+
+config SSOL
+	bool "Single stepping the virtual address of a process out of line"
+	default y
+	depends on  UTRACE
+	help
+	  This option provides single stepping the process's virtual address out of
+	  line using utrace. It has interface for insertion and removal of 
breakpoint.
+	  say Y/N here if you want to enable SSOL.
 endmenu
 
 source "block/Kconfig"
Index: linux-2.6.25-rc6/kernel/Makefile
===================================================================
--- linux-2.6.25-rc6.orig/kernel/Makefile
+++ linux-2.6.25-rc6/kernel/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilt
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
 obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_SSOL) += ssol_bkpt.o
 obj-$(CONFIG_UTRACE) += utrace.o
 obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/




More information about the utrace-devel mailing list