diff options
author | Dave Kleikamp <shaggy@linux.vnet.ibm.com> | 2010-02-08 06:51:05 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-02-16 22:03:17 -0500 |
commit | 3162d92dfb79a0b5fc03380b8819fa5f870ebf1e (patch) | |
tree | 490c54c78630be6052200432d249596bf2f3ae62 /arch/powerpc/kernel/ptrace.c | |
parent | 172ae2e7f8ff9053905a36672453a6d2ff95b182 (diff) |
powerpc: Extended ptrace interface
powerpc: Extended ptrace interface
From: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Based on patches originally written by Torez Smith.
Add a new extended ptrace interface so that user-space has a single
interface for powerpc, without having to know the specific layout
of the debug registers.
Implement:
PPC_PTRACE_GETHWDEBUGINFO
PPC_PTRACE_SETHWDEBUG
PPC_PTRACE_DELHWDEBUG
Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Acked-by: David Gibson <dwg@au1.ibm.com>
Cc: Torez Smith <lnxtorez@linux.vnet.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Sergio Durigan Junior <sergiodj@br.ibm.com>
Cc: Thiago Jung Bauermann <bauerman@br.ibm.com>
Cc: linuxppc-dev list <Linuxppc-dev@ozlabs.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 292c81432014..8847bd618cec 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -835,6 +835,52 @@ void ptrace_disable(struct task_struct *child) | |||
835 | user_disable_single_step(child); | 835 | user_disable_single_step(child); |
836 | } | 836 | } |
837 | 837 | ||
838 | static long ppc_set_hwdebug(struct task_struct *child, | ||
839 | struct ppc_hw_breakpoint *bp_info) | ||
840 | { | ||
841 | /* | ||
842 | * We currently support one data breakpoint | ||
843 | */ | ||
844 | if (((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0) || | ||
845 | ((bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0) || | ||
846 | (bp_info->trigger_type != PPC_BREAKPOINT_TRIGGER_WRITE) || | ||
847 | (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) || | ||
848 | (bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)) | ||
849 | return -EINVAL; | ||
850 | |||
851 | if (child->thread.dabr) | ||
852 | return -ENOSPC; | ||
853 | |||
854 | if ((unsigned long)bp_info->addr >= TASK_SIZE) | ||
855 | return -EIO; | ||
856 | |||
857 | child->thread.dabr = (unsigned long)bp_info->addr; | ||
858 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | ||
859 | child->thread.dbcr0 = DBCR0_IDM; | ||
860 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ) | ||
861 | child->thread.dbcr0 |= DBSR_DAC1R; | ||
862 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE) | ||
863 | child->thread.dbcr0 |= DBSR_DAC1W; | ||
864 | child->thread.regs->msr |= MSR_DE; | ||
865 | #endif | ||
866 | return 1; | ||
867 | } | ||
868 | |||
869 | static long ppc_del_hwdebug(struct task_struct *child, long addr, long data) | ||
870 | { | ||
871 | if (data != 1) | ||
872 | return -EINVAL; | ||
873 | if (child->thread.dabr == 0) | ||
874 | return -ENOENT; | ||
875 | |||
876 | child->thread.dabr = 0; | ||
877 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | ||
878 | child->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | DBCR0_IDM); | ||
879 | child->thread.regs->msr &= ~MSR_DE; | ||
880 | #endif | ||
881 | return 0; | ||
882 | } | ||
883 | |||
838 | /* | 884 | /* |
839 | * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls, | 885 | * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls, |
840 | * we mark them as obsolete now, they will be removed in a future version | 886 | * we mark them as obsolete now, they will be removed in a future version |
@@ -928,6 +974,50 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
928 | break; | 974 | break; |
929 | } | 975 | } |
930 | 976 | ||
977 | case PPC_PTRACE_GETHWDBGINFO: { | ||
978 | struct ppc_debug_info dbginfo; | ||
979 | |||
980 | dbginfo.version = 1; | ||
981 | dbginfo.num_instruction_bps = 0; | ||
982 | dbginfo.num_data_bps = 1; | ||
983 | dbginfo.num_condition_regs = 0; | ||
984 | #ifdef CONFIG_PPC64 | ||
985 | dbginfo.data_bp_alignment = 8; | ||
986 | #else | ||
987 | dbginfo.data_bp_alignment = 4; | ||
988 | #endif | ||
989 | dbginfo.sizeof_condition = 0; | ||
990 | dbginfo.features = 0; | ||
991 | |||
992 | if (!access_ok(VERIFY_WRITE, data, | ||
993 | sizeof(struct ppc_debug_info))) | ||
994 | return -EFAULT; | ||
995 | ret = __copy_to_user((struct ppc_debug_info __user *)data, | ||
996 | &dbginfo, sizeof(struct ppc_debug_info)) ? | ||
997 | -EFAULT : 0; | ||
998 | break; | ||
999 | } | ||
1000 | |||
1001 | case PPC_PTRACE_SETHWDEBUG: { | ||
1002 | struct ppc_hw_breakpoint bp_info; | ||
1003 | |||
1004 | if (!access_ok(VERIFY_READ, data, | ||
1005 | sizeof(struct ppc_hw_breakpoint))) | ||
1006 | return -EFAULT; | ||
1007 | ret = __copy_from_user(&bp_info, | ||
1008 | (struct ppc_hw_breakpoint __user *)data, | ||
1009 | sizeof(struct ppc_hw_breakpoint)) ? | ||
1010 | -EFAULT : 0; | ||
1011 | if (!ret) | ||
1012 | ret = ppc_set_hwdebug(child, &bp_info); | ||
1013 | break; | ||
1014 | } | ||
1015 | |||
1016 | case PPC_PTRACE_DELHWDEBUG: { | ||
1017 | ret = ppc_del_hwdebug(child, addr, data); | ||
1018 | break; | ||
1019 | } | ||
1020 | |||
931 | case PTRACE_GET_DEBUGREG: { | 1021 | case PTRACE_GET_DEBUGREG: { |
932 | ret = -EINVAL; | 1022 | ret = -EINVAL; |
933 | /* We only support one DABR and no IABRS at the moment */ | 1023 | /* We only support one DABR and no IABRS at the moment */ |