[IA64] Tighten up unw_unwind_to_user check
[linux-2.6.git] / arch / ia64 / kernel / unwind.c
index d494ff647cacab37308ecfc4dbfcf34e9510b817..2776a074c6f10e92970c86b14c40af2689e80996 100644 (file)
@@ -1943,23 +1943,30 @@ EXPORT_SYMBOL(unw_unwind);
 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;
-               if (ip < FIXADDR_USER_END)
+               }
+               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);