Skip to contentSkip to conversation

powerpc: Cleanup ptrace bits

PATCH In review Benjamin Herrenschmidt 4 participants 10 messages May 29, 2007 – Jun 1, 2007

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 2/5 powerpc: Cleanup ptrace bits

The powerpc ptrace code has some weirdness, like a ptrace-common.h file that is actually ppc64 only and some of the 32 bits code ifdef'ed inside ptrace.c.

There are also separate implementations for things like get/set_vrregs for 32 and 64 bits which is totally unnecessary.

This patch cleans that up a bit by having a ptrace-common.h which contains really common code (and makes a lot more code common), and ptrace-ppc32.h and ptrace-ppc64.h files that contain the few remaining different bits.

 arch/powerpc/kernel/ptrace-common.h |   89 +++++++---------
 arch/powerpc/kernel/ptrace-ppc32.h  |  100 ++++++++++++++++++
 arch/powerpc/kernel/ptrace-ppc64.h  |   51 +++++++++
 arch/powerpc/kernel/ptrace.c        |  198 ------------------------------------
 arch/powerpc/kernel/ptrace32.c      |    1 
 5 files changed, 197 insertions(+), 242 deletions(-)
arch/powerpc/kernel/ptrace-common.h +41 -48
Index: linux-cell/arch/powerpc/kernel/ptrace-common.h
===================================================================
@@ -1,5 +1,6 @@
 /*
  *    Copyright (c) 2002 Stephen Rothwell, IBM Coproration
+ *    Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
  *    Extracted from ptrace.c and ptrace32.c
  *
  * This file is subject to the terms and conditions of the GNU General
@@ -7,15 +8,8 @@
  * this archive for more details.
  */
 
-#ifndef _PPC64_PTRACE_COMMON_H
-#define _PPC64_PTRACE_COMMON_H
-
-#include <asm/system.h>
-
-/*
- * Set of msr bits that gdb can change on behalf of a process.
- */
-#define MSR_DEBUGCHANGE	(MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
+#ifndef _POWERPC_PTRACE_COMMON_H
+#define _POWERPC_PTRACE_COMMON_H
 
 /*
  * Get contents of register REGNO in task TASK.
@@ -24,18 +18,18 @@ static inline unsigned long get_reg(stru
 {
 	unsigned long tmp = 0;
 
-	/*
-	 * Put the correct FP bits in, they might be wrong as a result
-	 * of our lazy FP restore.
-	 */
+	if (task->thread.regs == NULL)
+		return -EIO;
+
 	if (regno == PT_MSR) {
 		tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
-		tmp |= task->thread.fpexc_mode;
-	} else if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) {
-		tmp = ((unsigned long *)task->thread.regs)[regno];
+		return PT_MUNGE_MSR(tmp, task);
 	}
 
-	return tmp;
+	if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
+		return ((unsigned long *)task->thread.regs)[regno];
+
+	return -EIO;
 }
 
 /*
@@ -44,7 +38,10 @@ static inline unsigned long get_reg(stru
 static inline int put_reg(struct task_struct *task, int regno,
 			  unsigned long data)
 {
-	if (regno < PT_SOFTE) {
+	if (task->thread.regs == NULL)
+		return -EIO;
+
+	if (regno <= PT_MAX_PUT_REG) {
 		if (regno == PT_MSR)
 			data = (data & MSR_DEBUGCHANGE)
 				| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
@@ -54,21 +51,6 @@ static inline int put_reg(struct task_st
 	return -EIO;
 }
 
-static inline void set_single_step(struct task_struct *task)
-{
-	struct pt_regs *regs = task->thread.regs;
-	if (regs != NULL)
-		regs->msr |= MSR_SE;
-	set_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
-
-static inline void clear_single_step(struct task_struct *task)
-{
-	struct pt_regs *regs = task->thread.regs;
-	if (regs != NULL)
-		regs->msr &= ~MSR_SE;
-	clear_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
 
 #ifdef CONFIG_ALTIVEC
 /*
@@ -137,25 +119,36 @@ static inline int set_vrregs(struct task
 
 	return 0;
 }
-#endif
+#endif /* CONFIG_ALTIVEC */
 
-static inline int ptrace_set_debugreg(struct task_struct *task,
-				      unsigned long addr, unsigned long data)
+static inline void set_single_step(struct task_struct *task)
 {
-	/* We only support one DABR and no IABRS at the moment */
-	if (addr > 0)
-		return -EINVAL;
+	struct pt_regs *regs = task->thread.regs;
 
-	/* The bottom 3 bits are flags */
-	if ((data & ~0x7UL) >= TASK_SIZE)
-		return -EIO;
+	if (regs != NULL) {
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+		task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
+		regs->msr |= MSR_DE;
+#else
+		regs->msr |= MSR_SE;
+#endif
+	}
+	set_tsk_thread_flag(task, TIF_SINGLESTEP);
+}
 
-	/* Ensure translation is on */
-	if (data && !(data & DABR_TRANSLATION))
-		return -EIO;
+static inline void clear_single_step(struct task_struct *task)
+{
+	struct pt_regs *regs = task->thread.regs;
 
-	task->thread.dabr = data;
-	return 0;
+	if (regs != NULL) {
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+		task->thread.dbcr0 = 0;
+		regs->msr &= ~MSR_DE;
+#else
+		regs->msr &= ~MSR_SE;
+#endif
+	}
+	clear_tsk_thread_flag(task, TIF_SINGLESTEP);
 }
 
-#endif /* _PPC64_PTRACE_COMMON_H */
+#endif /* _POWERPC_PTRACE_COMMON_H */
arch/powerpc/kernel/ptrace-ppc32.h new file +100 -0

100 lines not on this page · raw message

arch/powerpc/kernel/ptrace-ppc64.h new file +51 -0

51 lines not on this page · raw message

arch/powerpc/kernel/ptrace.c +4 -194

212 lines not on this page · raw message

arch/powerpc/kernel/ptrace32.c +1 -0
Index: linux-cell/arch/powerpc/kernel/ptrace32.c
===================================================================
@@ -33,6 +33,7 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
+#include "ptrace-ppc64.h"
 #include "ptrace-common.h"
 
 /*
#1 lore raw
Quoted 6 lines · Benjamin Herrenschmidt

This patch cleans that up a bit by having a ptrace-common.h which contains
really common code (and makes a lot more code common), and ptrace-ppc32.h and
ptrace-ppc64.h files that contain the few remaining different bits.

Hrm.. we do have a subtle difference in vrregs that I've missed.. I'll respin tomorrow. It looks like we don't store the VRSAVE register at the same place on 32 and 64 bits... yuck. I need to double check tomorrow.

Ben.

#2 lore raw
Quoted 11 lines · Benjamin Herrenschmidt
Quoted 6 lines · Benjamin Herrenschmidt

This patch cleans that up a bit by having a ptrace-common.h which contains
really common code (and makes a lot more code common), and ptrace-ppc32.h and
ptrace-ppc64.h files that contain the few remaining different bits.

Hrm.. we do have a subtle difference in vrregs that I've missed.. I'll respin tomorrow. It looks like we don't store the VRSAVE register at the same place on 32 and 64 bits... yuck. I need to double check tomorrow.

That's bad. We really should have VRSAVE in the same location for both. (wondering if GDB expects it a different locations on 32 vs 64-bits.)

- k

#3 lore raw

Kumar Gala <[email protected]> wrote on 05/29/2007 03:19:42 PM:

Quoted 9 lines · Benjamin Herrenschmidt
Quoted 4 lines

Hrm.. we do have a subtle difference in vrregs that I've missed.. I'll respin tomorrow. It looks like we don't store the VRSAVE register at the
same place on 32 and 64 bits... yuck. I need to double check tomorrow.

That's bad. We really should have VRSAVE in the same location for both. (wondering if GDB expects it a different locations on 32 vs 64- bits.)

It looks like GDB will expect VRSAVE at offset 33*16 (length 4 bytes) in the area returned by PTRACE_GETVRREGS, for both 32-bit and 64-bit applications:

/* This oddity is because the Linux kernel defines elf_vrregset_t as
an array of 33 16 bytes long elements. I.e. it leaves out vrsave. However the PTRACE_GETVRREGS and PTRACE_SETVRREGS requests return the vrsave as an extra 4 bytes at the end. I opted for creating a flat array of chars, so that it is easier to manipulate for gdb.

There are 32 vector registers 16 bytes longs, plus a VSCR register which is only 4 bytes long, but is fetched as a 16 bytes quantity. Up to here we have the elf_vrregset_t structure. Appended to this there is space for the VRSAVE register: 4 bytes. Even though this vrsave register is not included in the regset typedef, it is handled by the ptrace requests.

Note that GNU/Linux doesn't support little endian PPC hardware, therefore the offset at which the real value of the VSCR register is located will be always 12 bytes.

The layout is like this (where x is the actual value of the vscr reg):
*/

/* *INDENT-OFF* */
/*

   |.|.|.|.|.....|.|.|.|.||.|.|.|x||.|
   <------->     <-------><-------><->
     VR0           VR31     VSCR    VRSAVE

*/
/* *INDENT-ON* */

#define SIZEOF_VRREGS 33*16+4

typedef char gdb_vrregset_t[SIZEOF_VRREGS];

Mit freundlichen Gruessen / Best Regards

Ulrich Weigand

Signature · 7 lines
  Dr. Ulrich Weigand | Phone: +49-7031/16-3727
  GNU compiler/toolchain for Linux on System z and Cell BE
  IBM Deutschland Entwicklung GmbH
  Vorsitzender des Aufsichtsrats: Martin Jetter | Geschäftsführung: 
Herbert Kircher
  Sitz der Gesellschaft: Böblingen | Registergericht: Amtsgericht 
Stuttgart, HRB 243294
#4 lore raw
Quoted 4 lines · Ulrich Weigand

It looks like GDB will expect VRSAVE at offset 33*16 (length 4 bytes) in the area returned by PTRACE_GETVRREGS, for both 32-bit and 64-bit applications:

I have to check exactly what's going on there, it might be correct in both cases, I just remember that the code did something subtely different but it might result in the same thing. I'll double check today.

Ben.

#5 lore raw
Quoted 10 lines · Benjamin Herrenschmidt
Quoted 1 line

It looks like GDB will expect VRSAVE at offset 33*16 (length 4

bytes)

Quoted 1 line

in the area returned by PTRACE_GETVRREGS, for both 32-bit and

64-bit

Quoted 1 line

applications:

I have to check exactly what's going on there, it might be correct in both cases, I just remember that the code did something subtely different but it might result in the same thing. I'll double check today.

It was indeed correct in both cases, it just stupidly did direct ulong refs on 32 bits and cast to u32 on 64 bits, which I consolidated into a single implementation that uses u32 for vrsave so it should work fine.

Ben.

#6 lore raw
In reply to Benjamin Herrenschmidt
Quoted 53 lines · Benjamin Herrenschmidt

The powerpc ptrace code has some weirdness, like a ptrace-common.h file that is actually ppc64 only and some of the 32 bits code ifdef'ed inside ptrace.c.

There are also separate implementations for things like get/set_vrregs for 32 and 64 bits which is totally unnecessary.

This patch cleans that up a bit by having a ptrace-common.h which contains really common code (and makes a lot more code common), and ptrace-ppc32.h and ptrace-ppc64.h files that contain the few remaining different bits.

 arch/powerpc/kernel/ptrace-common.h |   89 +++++++---------
 arch/powerpc/kernel/ptrace-ppc32.h  |  100 ++++++++++++++++++
 arch/powerpc/kernel/ptrace-ppc64.h  |   51 +++++++++
 arch/powerpc/kernel/ptrace.c        |  198  
------------------------------------
 arch/powerpc/kernel/ptrace32.c      |    1
 5 files changed, 197 insertions(+), 242 deletions(-)

Index: linux-cell/arch/powerpc/kernel/ptrace-common.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/ptrace-common.h 2007-05-29
13:05:55.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/ptrace-common.h 2007-05-29
16:22:00.000000000 +1000

arch/powerpc/kernel/ptrace-common.h +1 -0
@@ -1,5 +1,6 @@
 /*
  *    Copyright (c) 2002 Stephen Rothwell, IBM Coproration
+ *    Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
  *    Extracted from ptrace.c and ptrace32.c
  *
  * This file is subject to the terms and conditions of the GNU  

General

arch/powerpc/kernel/ptrace-common.h +2 -9
@@ -7,15 +8,8 @@
  * this archive for more details.
  */
 
-#ifndef _PPC64_PTRACE_COMMON_H
-#define _PPC64_PTRACE_COMMON_H
-
-#include <asm/system.h>
-
-/*
- * Set of msr bits that gdb can change on behalf of a process.
- */
-#define MSR_DEBUGCHANGE	(MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
+#ifndef _POWERPC_PTRACE_COMMON_H
+#define _POWERPC_PTRACE_COMMON_H
 
 /*
  * Get contents of register REGNO in task TASK.

arch/powerpc/kernel/ptrace-common.h static inline unsigned long get_reg(stru · line 30

Quoted 7 lines
arch/powerpc/kernel/ptrace-common.h +0 -4
@@ -24,18 +18,18 @@ static inline unsigned long get_reg(stru
 {
 	unsigned long tmp = 0;
 
-	/*
-	 * Put the correct FP bits in, they might be wrong as a result
-	 * of our lazy FP restore.
-	 */

Do we do some different lazy save/restore on ppc64 than ppc32? I'm trying to understand why the comment isn't (or wasn't) valid for ppc32 as well.

Quoted 18 lines
arch/powerpc/kernel/ptrace-common.h +8 -4
+	if (task->thread.regs == NULL)
+		return -EIO;
+
 	if (regno == PT_MSR) {
 		tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
-		tmp |= task->thread.fpexc_mode;
-	} else if (regno < (sizeof(struct pt_regs) / sizeof(unsigned  
 long))) {
-		tmp = ((unsigned long *)task->thread.regs)[regno];
+		return PT_MUNGE_MSR(tmp, task);
 	}
 
-	return tmp;
+	if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
+		return ((unsigned long *)task->thread.regs)[regno];
+
+	return -EIO;
 }
#7 lore raw
Quoted 3 lines · Kumar Gala

Do we do some different lazy save/restore on ppc64 than ppc32? I'm trying to understand why the comment isn't (or wasn't) valid for ppc32 as well.

Not sure :-) The code did different things and I didn't want to change everything at once in that patch. It's on my list to clarify and possibly fix.

Ben.

#9 lore raw
Quoted 2 lines · Christoph Hellwig

This one doesn't seem to apply against current mainline plus the first patch. The hung in ptrace.c rejects.

It needs the 32 bits single step fixup that I posted a few days ago...

Ben.