[PATCH] arm64 ptrace.c
Aaron Liu
liucy214 at gmail.com
Wed Dec 11 23:47:44 EST 2013
Hi Will,
Your patch works without errors.
Thanks
Aaron
2013/12/12 Will Deacon <will.deacon at arm.com>:
> On Wed, Dec 11, 2013 at 07:16:11AM +0000, Aaron Liu wrote:
>> Hi Will,
>
> Hi Aaron,
>
>> gdb calls ptrace twice to set watch points and break points as
>> following. After first ptrace call is completed, second ptrace call
>> fails with no space error. The first ptrace will reserve 16 watch
>> points in static LIST_HEAD(bp_task_head)@kernel/events/hw_breakpoint.c
>> and each entry, ie. struct perf_event, has a member called
>> attr.bp_type. The bp_type in the entry should be used as indicator for
>> watch points or break points. You could see
>> __reserve_bp_slot at kernel/events/hw_breakpoint.c and find it does a
>> basic check bp_type should be not HW_BREAKPOINT_EMPTY and
>> HW_BREAKPOINT_INVALID. After the __reserve_bp_slot call, the reserved
>> slot's bp_type is HW_BREAKPOINT_RW or HW_BREAKPOINT_X. However,
>> ptrace_hbp_fill_attr_ctrl at arch/arm64/kernel/ptrace.c set the bp_type
>> to HW_BREAKPOINT_EMPTY if it's disabled. This causes the
>> find_slot_idx at kernel/event/hw_breakpoint.c to judge the existing
>> entries as TYPE_INST. So, after first 16 watch points are reserved in
>> list, the following break points determine no space to reserve, ie.
>> max 16 break points. The patch only set disable bit even user zeroing
>> control bits and it could still pass
>> modify_user_hw_breakpoint at kernel/events/hw_breakpoint.c.
>
> Ok, thanks for the explanation. This used to work, but I suspect something
> changed in the core code which caused this to start breaking with
> HW_BREAKPOINT_EMPTY.
>
> Lucky for us, our ptrace_hbp_create function will infer the type/len for us
> using values that are known to pass validation. In that case, the use of
> HW_BREAKPOINT_EMPTY is redundant -- we just need to make sure we avoid
> populating anything other than the disabled field in the perf_event_attr.
>
> A curious behaviour here (which also exists in the current code) is that the
> breakpoint register effectively becomes read-only apart from the enable bit
> if you are disabling it. That shouldn't effect gdb, though, and is required
> to allow nuking of the breakpoint without changing its type.
>
> Can you test the following patch please?
>
> Thanks,
>
> Will
>
> --->8
>
> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> index 6777a2192b83..6a8928bba03c 100644
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -214,31 +214,29 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
> {
> int err, len, type, disabled = !ctrl.enabled;
>
> - if (disabled) {
> - len = 0;
> - type = HW_BREAKPOINT_EMPTY;
> - } else {
> - err = arch_bp_generic_fields(ctrl, &len, &type);
> - if (err)
> - return err;
> -
> - switch (note_type) {
> - case NT_ARM_HW_BREAK:
> - if ((type & HW_BREAKPOINT_X) != type)
> - return -EINVAL;
> - break;
> - case NT_ARM_HW_WATCH:
> - if ((type & HW_BREAKPOINT_RW) != type)
> - return -EINVAL;
> - break;
> - default:
> + attr->disabled = disabled;
> + if (disabled)
> + return 0;
> +
> + err = arch_bp_generic_fields(ctrl, &len, &type);
> + if (err)
> + return err;
> +
> + switch (note_type) {
> + case NT_ARM_HW_BREAK:
> + if ((type & HW_BREAKPOINT_X) != type)
> return -EINVAL;
> - }
> + break;
> + case NT_ARM_HW_WATCH:
> + if ((type & HW_BREAKPOINT_RW) != type)
> + return -EINVAL;
> + break;
> + default:
> + return -EINVAL;
> }
>
> attr->bp_len = len;
> attr->bp_type = type;
> - attr->disabled = disabled;
>
> return 0;
> }
More information about the linux-arm-kernel
mailing list