Skip to contentSkip to conversation

powerpc/ptrace: Fix build with gcc 4.6

PATCH Superseded Benjamin Herrenschmidt 1 participant 2 messages Sep 27, 2011

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

PATCH 1/1 powerpc/ptrace: Fix build with gcc 4.6

gcc (rightfully) complains that we are accessing beyond the end of the fpr array (we do, to access the fpscr).

The only sane thing to do (whether anything in that code can be called remotely sane is debatable) is to special case fpscr and handle it as a separate statement.

I initially tried to do it it by making the array access conditional to index < PT_FPSCR and using a 3rd else leg but for some reason gcc was unable to understand it and still spewed the warning.

So I ended up with something a tad more intricated but it seems to build on 32-bit and on 64-bit with and without VSX.

---

I very much welcome a few more pairs of eyes on this one in case I missed something, this code sucks. It took me a good 15mn to figure out that it was actually correct to begin with (hint: look at the definition of PT_FPSCR on 32-bit, don't miss the *2 in there).

arch/powerpc/kernel/ptrace.c +12 -4
index 05b7dd2..adf4d73 100644
@@ -1497,9 +1497,14 @@ long arch_ptrace(struct task_struct *child, long request,
 		if (index < PT_FPR0) {
 			tmp = ptrace_get_reg(child, (int) index);
 		} else {
+			unsigned int fpidx = index - PT_FPR0;
+
 			flush_fp_to_thread(child);
-			tmp = ((unsigned long *)child->thread.fpr)
-				[TS_FPRWIDTH * (index - PT_FPR0)];
+			if (fpidx < (PT_FPSCR - PT_FPR0))
+				tmp = ((unsigned long *)child->thread.fpr)
+					[fpidx * TS_FPRWIDTH];
+			else
+				tmp = child->thread.fpscr.val;
 		}
 		ret = put_user(tmp, datalp);
 		break;
@@ -1525,9 +1530,12 @@ long arch_ptrace(struct task_struct *child, long request,
 		if (index < PT_FPR0) {
 			ret = ptrace_put_reg(child, index, data);
 		} else {
+			unsigned int fpidx = index - PT_FPR0;
+
 			flush_fp_to_thread(child);
-			((unsigned long *)child->thread.fpr)
-				[TS_FPRWIDTH * (index - PT_FPR0)] = data;
+			if (fpidx < (PT_FPSCR - PT_FPR0))
+				((unsigned long *)child->thread.fpr)
+					[fpidx * TS_FPRWIDTH] = data;
 			ret = 0;
 		}
 		break;
#1 lore raw

PATCH v2 1/1 powerpc/ptrace: Fix build with gcc 4.6

gcc (rightfully) complains that we are accessing beyond the end of the fpr array (we do, to access the fpscr).

The only sane thing to do (whether anything in that code can be called remotely sane is debatable) is to special case fpscr and handle it as a separate statement.

I initially tried to do it it by making the array access conditional to index < PT_FPSCR and using a 3rd else leg but for some reason gcc was unable to understand it and still spewed the warning.

So I ended up with something a tad more intricated but it seems to build on 32-bit and on 64-bit with and without VSX.

---

I very much welcome a few more pairs of eyes on this one in case I missed something, this code sucks. It took me a good 15mn to figure out that it was actually correct to begin with (hint: look at the definition of PT_FPSCR on 32-bit, don't miss the *2 in there).

v2. Allow setting the fpscr (thanks Stephen)

arch/powerpc/kernel/ptrace.c +14 -4
index cb22024..9321d0f 100644
@@ -1497,9 +1497,14 @@ long arch_ptrace(struct task_struct *child, long request,
 		if (index < PT_FPR0) {
 			tmp = ptrace_get_reg(child, (int) index);
 		} else {
+			unsigned int fpidx = index - PT_FPR0;
+
 			flush_fp_to_thread(child);
-			tmp = ((unsigned long *)child->thread.fpr)
-				[TS_FPRWIDTH * (index - PT_FPR0)];
+			if (fpidx < (PT_FPSCR - PT_FPR0))
+				tmp = ((unsigned long *)child->thread.fpr)
+					[fpidx * TS_FPRWIDTH];
+			else
+				tmp = child->thread.fpscr.val;
 		}
 		ret = put_user(tmp, datalp);
 		break;
@@ -1525,9 +1530,14 @@ long arch_ptrace(struct task_struct *child, long request,
 		if (index < PT_FPR0) {
 			ret = ptrace_put_reg(child, index, data);
 		} else {
+			unsigned int fpidx = index - PT_FPR0;
+
 			flush_fp_to_thread(child);
-			((unsigned long *)child->thread.fpr)
-				[TS_FPRWIDTH * (index - PT_FPR0)] = data;
+			if (fpidx < (PT_FPSCR - PT_FPR0))
+				((unsigned long *)child->thread.fpr)
+					[fpidx * TS_FPRWIDTH] = data;
+			else
+				child->thread.fpscr.val = data;
 			ret = 0;
 		}
 		break;