* Srinivasa D S <[EMAIL PROTECTED]> [2008-04-16 11:59:39]:

Hi Srinivasa, 

Can you please break this patch into 
- The actual breakpoint assistance code.
- single stepping out of line (ssol). 
- How to use breakpoint assistance + ssol. 

--
Thanks and Regards
Srikar 

> 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/
> 

Reply via email to