[IA64] Tighten up unw_unwind_to_user check

Linux Kernel Mailing List <[email protected]> Fri, 18 Mar 2005 20:47:58 +0000
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
ChangeSet 1.1466, 2005/03/18 13:47:58-07:00, [email protected]

	[IA64] Tighten up unw_unwind_to_user check
	
	Detect user space by the unwind frame with predicate PRED_USER_STACK
	set, instead of a user space IP.  Tighten up the last ditch check for
	running off the top of the kernel stack.
	
	Based on a suggestion by David Mosberger, reworked to fit the current
	tree.  This survives my stress test which used to break 2.6.9 kernels.
	Unlike 2.6.11, the stress test now unwinds to the correct point, so
	gdb can get the user space registers.
	
	Signed-off-by: Keith Owens <[email protected]>
	Signed-off-by: Tony Luck <[email protected]>



 unwind.c |   33 +++++++++++++++++++--------------
 1 files changed, 19 insertions(+), 14 deletions(-)


diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
--- a/arch/ia64/kernel/unwind.c	2005-03-24 09:05:30 -08:00
+++ b/arch/ia64/kernel/unwind.c	2005-03-24 09:05:30 -08:00
@@ -48,6 +48,8 @@
 
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #define p5		5
+#define PRED_USER_STACK pUser
+#define p3		3	/* for pUser */
 
 #define UNW_LOG_CACHE_SIZE	7	/* each unw_script is ~256 bytes in size */
 #define UNW_CACHE_SIZE		(1 << UNW_LOG_CACHE_SIZE)
@@ -1916,27 +1918,30 @@
 int
 unw_unwind_to_user (struct unw_frame_info *info)
 {
-	unsigned long ip, sp;
+	unsigned long ip, sp, pr = 0;
 
 	while (unw_unwind(info) >= 0) {
-		if (unw_get_rp(info, &ip) < 0) {
-			unw_get_ip(info, &ip);
-			UNW_DPRINT(0, "unwind.%s: failed to read return pointer (ip=0x%lx)\n",
-				   __FUNCTION__, ip);
-			return -1;
-		}
 		unw_get_sp(info, &sp);
-		if (sp >= (unsigned long)info->task + IA64_STK_OFFSET)
+		if ((long)((unsigned long)info->task + IA64_STK_OFFSET - sp)
+		    < IA64_PT_REGS_SIZE) {
+			UNW_DPRINT(0, "unwind.%s: ran off the top of the kernel stack\n",
+				   __FUNCTION__);
 			break;
-		/*
-		 * We don't have unwind info for the gate page, so we consider that part
-		 * of user-space for the purpose of unwinding.
-		 */
-		if (ip < GATE_ADDR + PAGE_SIZE)
+		}
+		if (unw_is_intr_frame(info) &&
+		    (pr & (1UL << PRED_USER_STACK)))
 			return 0;
+		if (unw_get_pr (info, &pr) < 0) {
+			unw_get_rp(info, &ip);
+			UNW_DPRINT(0, "unwind.%s: failed to read "
+				   "predicate register (ip=0x%lx)\n",
+				__FUNCTION__, ip);
+			return -1;
+		}
 	}
 	unw_get_ip(info, &ip);
-	UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", __FUNCTION__, ip);
+	UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n",
+		   __FUNCTION__, ip);
 	return -1;
 }
 EXPORT_SYMBOL(unw_unwind_to_user);