On Fri, Sep 16, 2011 at 12:57:10PM +0530, K.Prasad wrote:
> On Fri, Aug 26, 2011 at 03:05:52PM +0530, K.Prasad wrote:
> > On Wed, Aug 24, 2011 at 01:59:39PM +1000, David Gibson wrote:
> > > On Tue, Aug 23, 2011 at 02:55:13PM +0530, K.Prasad wrote:
> > > > On Tue, Aug 23, 2011 at 03:08:50PM +1000, David Gibson wrote:
> > > > > On Fri, Aug 19, 2011 at 01:21:36PM +0530, K.Prasad wrote:
> > > > > > PPC_PTRACE_GETHWDBGINFO, PPC_PTRACE_SETHWDEBUG and 
> > > > > > PPC_PTRACE_DELHWDEBUG are
> > > > > > PowerPC specific ptrace flags that use the watchpoint register. 
> > > > > > While they are
> > > > > > targeted primarily towards BookE users, user-space applications 
> > > > > > such as GDB
> > > > > > have started using them for BookS too.
> > > > > > 
> > > > > > This patch enables the use of generic hardware breakpoint 
> > > > > > interfaces for these
> > > > > > new flags. The version number of the associated data structures
> > > > > > "ppc_hw_breakpoint" and "ppc_debug_info" is incremented to denote 
> > > > > > new semantics.
> > > > > 
> > > > > So, the structure itself doesn't seem to have been extended.  I don't
> > > > > understand what the semantic difference is - your patch comment needs
> > > > > to explain this clearly.
> > > > >
> > > > 
> > > > We had a request to extend the structure but thought it was dangerous to
> > > > do so. For instance if the user-space used version1 of the structure,
> > > > while kernel did a copy_to_user() pertaining to version2, then we'd run
> > > > into problems. Unfortunately the ptrace flags weren't designed to accept
> > > > a version number as input from the user through the
> > > > PPC_PTRACE_GETHWDBGINFO flag (which would have solved this issue).
> > > 
> > > I still don't follow you.
> > > 
> > 
> > Two things here.
> > 
> > One, the change of semantics warranted an increment of the version
> > number. The new semantics accepts PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE on
> > BookS, while the old version number did not. I've added a small comment
> > in the code to this effect.
> > 
> > Two, regarding changes in the "ppc_hw_breakpoint" and "ppc_debug_info"
> > structures - we would like to add more members to it if we can (GDB has a
> > pending request to add more members to it). However the problem foreseen
> > is that there could be a mismatch between the versions of the structure
> > used by the user vs kernel-space i.e. if a new version of the structure,
> > known to the kernel, had an extra member while the user-space still had
> > the old version, then it becomes dangerous because the __copy_to_user
> > function would overflow the buffer size in user-space.
> > 
> > This could have been avoided if PPC_PTRACE_GETHWDBGINFO was originally
> > designed to accept a version number (and provide corresponding
> > "struct ppc_debug_info") rather than send a populated "ppc_debug_info"
> > structure along with the version number.
> >
> 
> Based on further discussions with the code-reviewer (David Gibson
> <d...@au1.ibm.com>), it was decided that incrementing the version number
> for the proposed changes is unnecessary as the patch only introduces new
> features but not a change in semantics.
> 
> Please find a new version of the patch where the version number is
> retained as 1, along with the other planned changes.
> 
> Thanks,
> K.Prasad
> 
>  
>     [hw-breakpoint] Use generic hw-breakpoint interfaces for new PPC ptrace 
> flags
>     
>     PPC_PTRACE_GETHWDBGINFO, PPC_PTRACE_SETHWDEBUG and PPC_PTRACE_DELHWDEBUG 
> are
>     PowerPC specific ptrace flags that use the watchpoint register. While 
> they are
>     targeted primarily towards BookE users, user-space applications such as 
> GDB
>     have started using them for BookS too.
>     
>     This patch enables the use of generic hardware breakpoint interfaces for 
> these
>     new flags. The version number of the associated data structures
>     "ppc_hw_breakpoint" and "ppc_debug_info" is incremented to denote new 
> semantics.

Above pargraph needs revision.


>     Apart from the usual benefits of using generic hw-breakpoint interfaces, 
> these
>     changes allow debuggers (such as GDB) to use a common set of ptrace flags 
> for
>     their watchpoint needs and allow more precise breakpoint specification 
> (length
>     of the variable can be specified).
>     
>     [Edjunior: Identified an issue in the patch with the sanity check for 
> version
>     numbers]
>     
>     Tested-by: Edjunior Barbosa Machado <emach...@linux.vnet.ibm.com>
>     Signed-off-by: K.Prasad <pra...@linux.vnet.ibm.com>
> 
> diff --git a/Documentation/powerpc/ptrace.txt 
> b/Documentation/powerpc/ptrace.txt
> index f4a5499..04656ec 100644
> --- a/Documentation/powerpc/ptrace.txt
> +++ b/Documentation/powerpc/ptrace.txt
> @@ -127,6 +127,22 @@ Some examples of using the structure to:
>    p.addr2           = (uint64_t) end_range;
>    p.condition_value = 0;
>  
> +- set a watchpoint in server processors (BookS)
> +
> +  p.version         = 1;
> +  p.trigger_type    = PPC_BREAKPOINT_TRIGGER_RW;
> +  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
> +  or
> +  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_EXACT;

MODE_RANGE_EXACT?  Shouldn't that just be MODE_EXACT?

> +
> +  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
> +  p.addr            = (uint64_t) begin_range;
> +  /* For PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE addr2 needs to be specified, 
> where
> +   * addr2 - addr <= 8 Bytes.
> +   */
> +  p.addr2           = (uint64_t) end_range;
> +  p.condition_value = 0;
> +
>  3. PTRACE_DELHWDEBUG
>  
>  Takes an integer which identifies an existing breakpoint or watchpoint
> diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
> index 05b7dd2..2449495 100644
> --- a/arch/powerpc/kernel/ptrace.c
> +++ b/arch/powerpc/kernel/ptrace.c
> @@ -1339,6 +1339,12 @@ static int set_dac_range(struct task_struct *child,
>  static long ppc_set_hwdebug(struct task_struct *child,
>                    struct ppc_hw_breakpoint *bp_info)
>  {
> +#ifdef CONFIG_HAVE_HW_BREAKPOINT
> +     int ret, len = 0;
> +     struct thread_struct *thread = &(child->thread);
> +     struct perf_event *bp;
> +     struct perf_event_attr attr;
> +#endif /* CONFIG_HAVE_HW_BREAKPOINT */
>  #ifndef CONFIG_PPC_ADV_DEBUG_REGS
>       unsigned long dabr;
>  #endif
> @@ -1382,13 +1388,9 @@ static long ppc_set_hwdebug(struct task_struct *child,
>        */
>       if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 ||
>           (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 ||
> -         bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT ||
>           bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
>               return -EINVAL;
>  
> -     if (child->thread.dabr)
> -             return -ENOSPC;
> -
>       if ((unsigned long)bp_info->addr >= TASK_SIZE)
>               return -EIO;
>  
> @@ -1398,15 +1400,83 @@ static long ppc_set_hwdebug(struct task_struct *child,
>               dabr |= DABR_DATA_READ;
>       if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
>               dabr |= DABR_DATA_WRITE;
> +#ifdef CONFIG_HAVE_HW_BREAKPOINT
> +     if (ptrace_get_breakpoints(child) < 0)
> +             return -ESRCH;
>  
> -     child->thread.dabr = dabr;
> +     bp = thread->ptrace_bps[0];
> +     if (!bp_info->addr) {

I think this is treating a hardware breakpoint at address 0 as if it
didn't exist.  That seems wrong.

> +             if (bp) {
> +                     unregister_hw_breakpoint(bp);
> +                     thread->ptrace_bps[0] = NULL;
> +             }
> +             ptrace_put_breakpoints(child);
> +             return 0;
> +     }
> +     /*
> +      * Check if the request is for 'range' breakpoints. We can
> +      * support it if range < 8 bytes.
> +      */
> +     if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE)
> +             len = bp_info->addr2 - bp_info->addr;
> +     else if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) {
> +                     ptrace_put_breakpoints(child);
> +                     return -EINVAL;
> +             }

Misindent here.  This statement would be clearer if you had {} on all
of the if branches.

> +     if (bp) {
> +             attr = bp->attr;
> +             attr.bp_addr = (unsigned long)bp_info->addr & 
> ~HW_BREAKPOINT_ALIGN;
> +             arch_bp_generic_fields(dabr &
> +                                     (DABR_DATA_WRITE | DABR_DATA_READ),
> +                                                     &attr.bp_type);
> +             attr.bp_len = len;

If gdb is using the new breakpoint interface, surely it should just
use it, rather than doing this bit frobbing as in the old SET_DABR
call.

> +             ret =  modify_user_hw_breakpoint(bp, &attr);
> +             if (ret) {
> +                     ptrace_put_breakpoints(child);
> +                     return ret;
> +             }
> +             thread->ptrace_bps[0] = bp;
> +             ptrace_put_breakpoints(child);
> +             thread->dabr = dabr;
> +             return 0;
> +     }
>  
> +     /* Create a new breakpoint request if one doesn't exist already */
> +     hw_breakpoint_init(&attr);
> +     attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN;
> +     attr.bp_len = len;
> +     arch_bp_generic_fields(dabr & (DABR_DATA_WRITE | DABR_DATA_READ),
> +                                                             &attr.bp_type);
> +
> +     thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
> +                                            ptrace_triggered, NULL, child);
> +     if (IS_ERR(bp)) {
> +             thread->ptrace_bps[0] = NULL;
> +             ptrace_put_breakpoints(child);
> +             return PTR_ERR(bp);
> +     }
> +
> +     ptrace_put_breakpoints(child);
> +     return 1;
> +#endif /* CONFIG_HAVE_HW_BREAKPOINT */
> +
> +     if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
> +             return -EINVAL;
> +
> +     if (child->thread.dabr)
> +             return -ENOSPC;
> +
> +     child->thread.dabr = dabr;
>       return 1;
>  #endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
>  }
>  
>  static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
>  {
> +#ifdef CONFIG_HAVE_HW_BREAKPOINT
> +     struct thread_struct *thread = &(child->thread);
> +     struct perf_event *bp;
> +#endif /* CONFIG_HAVE_HW_BREAKPOINT */
>  #ifdef CONFIG_PPC_ADV_DEBUG_REGS
>       int rc;
>  
> @@ -1426,10 +1496,24 @@ static long ppc_del_hwdebug(struct task_struct 
> *child, long addr, long data)
>  #else
>       if (data != 1)
>               return -EINVAL;
> +
> +#ifdef CONFIG_HAVE_HW_BREAKPOINT
> +     if (ptrace_get_breakpoints(child) < 0)
> +             return -ESRCH;
> +
> +     bp = thread->ptrace_bps[0];
> +     if (bp) {
> +             unregister_hw_breakpoint(bp);
> +             thread->ptrace_bps[0] = NULL;
> +     }
> +     ptrace_put_breakpoints(child);
> +     return 0;
> +#else /* CONFIG_HAVE_HW_BREAKPOINT */
>       if (child->thread.dabr == 0)
>               return -ENOENT;
>  
>       child->thread.dabr = 0;
> +#endif /* CONFIG_HAVE_HW_BREAKPOINT */
>  
>       return 0;
>  #endif
> @@ -1560,7 +1644,7 @@ long arch_ptrace(struct task_struct *child, long 
> request,
>               dbginfo.data_bp_alignment = 4;
>  #endif
>               dbginfo.sizeof_condition = 0;
> -             dbginfo.features = 0;
> +             dbginfo.features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
>  #endif /* CONFIG_PPC_ADV_DEBUG_REGS */
>  
>               if (!access_ok(VERIFY_WRITE, datavp,
> 

-- 
David Gibson                    | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
                                | _way_ _around_!
http://www.ozlabs.org/~dgibson
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to