Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / ia64 / kernel / unwind.c
index 69e095a..93d5a3b 100644 (file)
@@ -47,8 +47,6 @@
 #include "entry.h"
 #include "unwind_i.h"
 
-#define p5             5
-
 #define UNW_LOG_CACHE_SIZE     7       /* each unw_script is ~256 bytes in size */
 #define UNW_CACHE_SIZE         (1 << UNW_LOG_CACHE_SIZE)
 
@@ -364,7 +362,7 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char
                        if (info->pri_unat_loc)
                                nat_addr = info->pri_unat_loc;
                        else
-                               nat_addr = &info->sw->ar_unat;
+                               nat_addr = &info->sw->caller_unat;
                        nat_mask = (1UL << ((long) addr & 0x1f8)/8);
                }
        } else {
@@ -526,7 +524,7 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int
              case UNW_AR_UNAT:
                addr = info->unat_loc;
                if (!addr)
-                       addr = &info->sw->ar_unat;
+                       addr = &info->sw->caller_unat;
                break;
 
              case UNW_AR_LC:
@@ -1269,7 +1267,6 @@ script_new (unsigned long ip)
 {
        struct unw_script *script, *prev, *tmp;
        unw_hash_index_t index;
-       unsigned long flags;
        unsigned short head;
 
        STAT(++unw.stat.script.news);
@@ -1278,13 +1275,9 @@ script_new (unsigned long ip)
         * Can't (easily) use cmpxchg() here because of ABA problem
         * that is intrinsic in cmpxchg()...
         */
-       spin_lock_irqsave(&unw.lock, flags);
-       {
-               head = unw.lru_head;
-               script = unw.cache + head;
-               unw.lru_head = script->lru_chain;
-       }
-       spin_unlock(&unw.lock);
+       head = unw.lru_head;
+       script = unw.cache + head;
+       unw.lru_head = script->lru_chain;
 
        /*
         * We'd deadlock here if we interrupted a thread that is holding a read lock on
@@ -1295,43 +1288,39 @@ script_new (unsigned long ip)
        if (!write_trylock(&script->lock))
                return NULL;
 
-       spin_lock(&unw.lock);
-       {
-               /* re-insert script at the tail of the LRU chain: */
-               unw.cache[unw.lru_tail].lru_chain = head;
-               unw.lru_tail = head;
-
-               /* remove the old script from the hash table (if it's there): */
-               if (script->ip) {
-                       index = hash(script->ip);
-                       tmp = unw.cache + unw.hash[index];
-                       prev = NULL;
-                       while (1) {
-                               if (tmp == script) {
-                                       if (prev)
-                                               prev->coll_chain = tmp->coll_chain;
-                                       else
-                                               unw.hash[index] = tmp->coll_chain;
-                                       break;
-                               } else
-                                       prev = tmp;
-                               if (tmp->coll_chain >= UNW_CACHE_SIZE)
-                               /* old script wasn't in the hash-table */
-                                       break;
-                               tmp = unw.cache + tmp->coll_chain;
-                       }
+       /* re-insert script at the tail of the LRU chain: */
+       unw.cache[unw.lru_tail].lru_chain = head;
+       unw.lru_tail = head;
+
+       /* remove the old script from the hash table (if it's there): */
+       if (script->ip) {
+               index = hash(script->ip);
+               tmp = unw.cache + unw.hash[index];
+               prev = NULL;
+               while (1) {
+                       if (tmp == script) {
+                               if (prev)
+                                       prev->coll_chain = tmp->coll_chain;
+                               else
+                                       unw.hash[index] = tmp->coll_chain;
+                               break;
+                       } else
+                               prev = tmp;
+                       if (tmp->coll_chain >= UNW_CACHE_SIZE)
+                       /* old script wasn't in the hash-table */
+                               break;
+                       tmp = unw.cache + tmp->coll_chain;
                }
+       }
 
-               /* enter new script in the hash table */
-               index = hash(ip);
-               script->coll_chain = unw.hash[index];
-               unw.hash[index] = script - unw.cache;
+       /* enter new script in the hash table */
+       index = hash(ip);
+       script->coll_chain = unw.hash[index];
+       unw.hash[index] = script - unw.cache;
 
-               script->ip = ip;        /* set new IP while we're holding the locks */
+       script->ip = ip;        /* set new IP while we're holding the locks */
 
-               STAT(if (script->coll_chain < UNW_CACHE_SIZE) ++unw.stat.script.collisions);
-       }
-       spin_unlock_irqrestore(&unw.lock, flags);
+       STAT(if (script->coll_chain < UNW_CACHE_SIZE) ++unw.stat.script.collisions);
 
        script->flags = 0;
        script->hint = 0;
@@ -1786,7 +1775,7 @@ run_script (struct unw_script *script, struct unw_frame_info *state)
 
                      case UNW_INSN_SETNAT_MEMSTK:
                        if (!state->pri_unat_loc)
-                               state->pri_unat_loc = &state->sw->ar_unat;
+                               state->pri_unat_loc = &state->sw->caller_unat;
                        /* register off. is a multiple of 8, so the least 3 bits (type) are 0 */
                        s[dst+1] = ((unsigned long) state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;
                        break;
@@ -1830,6 +1819,7 @@ find_save_locs (struct unw_frame_info *info)
 {
        int have_write_lock = 0;
        struct unw_script *scr;
+       unsigned long flags = 0;
 
        if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) {
                /* don't let obviously bad addresses pollute the cache */
@@ -1841,8 +1831,10 @@ find_save_locs (struct unw_frame_info *info)
 
        scr = script_lookup(info);
        if (!scr) {
+               spin_lock_irqsave(&unw.lock, flags);
                scr = build_script(info);
                if (!scr) {
+                       spin_unlock_irqrestore(&unw.lock, flags);
                        UNW_DPRINT(0,
                                   "unwind.%s: failed to locate/build unwind script for ip %lx\n",
                                   __FUNCTION__, info->ip);
@@ -1855,9 +1847,10 @@ find_save_locs (struct unw_frame_info *info)
 
        run_script(scr, info);
 
-       if (have_write_lock)
+       if (have_write_lock) {
                write_unlock(&scr->lock);
-       else
+               spin_unlock_irqrestore(&unw.lock, flags);
+       } else
                read_unlock(&scr->lock);
        return 0;
 }
@@ -1904,7 +1897,7 @@ unw_unwind (struct unw_frame_info *info)
        num_regs = 0;
        if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) {
                info->pt = info->sp + 16;
-               if ((pr & (1UL << pNonSys)) != 0)
+               if ((pr & (1UL << PRED_NON_SYSCALL)) != 0)
                        num_regs = *info->cfm_loc & 0x7f;               /* size of frame */
                info->pfs_loc =
                        (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs));
@@ -1950,20 +1943,30 @@ EXPORT_SYMBOL(unw_unwind);
 int
 unw_unwind_to_user (struct unw_frame_info *info)
 {
-       unsigned long ip;
+       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 ((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);
@@ -2016,28 +2019,6 @@ init_frame_info (struct unw_frame_info *info, struct task_struct *t,
        STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
 }
 
-void
-unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t,
-                           struct pt_regs *pt, struct switch_stack *sw)
-{
-       unsigned long sof;
-
-       init_frame_info(info, t, sw, pt->r12);
-       info->cfm_loc = &pt->cr_ifs;
-       info->unat_loc = &pt->ar_unat;
-       info->pfs_loc = &pt->ar_pfs;
-       sof = *info->cfm_loc & 0x7f;
-       info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof);
-       info->ip = pt->cr_iip + ia64_psr(pt)->ri;
-       info->pt = (unsigned long) pt;
-       UNW_DPRINT(3, "unwind.%s:\n"
-                  "  bsp    0x%lx\n"
-                  "  sof    0x%lx\n"
-                  "  ip     0x%lx\n",
-                  __FUNCTION__, info->bsp, sof, info->ip);
-       find_save_locs(info);
-}
-
 void
 unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw)
 {
@@ -2056,6 +2037,8 @@ unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct
        find_save_locs(info);
 }
 
+EXPORT_SYMBOL(unw_init_frame_info);
+
 void
 unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t)
 {
@@ -2238,11 +2221,11 @@ unw_init (void)
        if (8*sizeof(unw_hash_index_t) < UNW_LOG_HASH_SIZE)
                unw_hash_index_t_is_too_narrow();
 
-       unw.sw_off[unw.preg_index[UNW_REG_PRI_UNAT_GR]] = SW(AR_UNAT);
+       unw.sw_off[unw.preg_index[UNW_REG_PRI_UNAT_GR]] = SW(CALLER_UNAT);
        unw.sw_off[unw.preg_index[UNW_REG_BSPSTORE]] = SW(AR_BSPSTORE);
-       unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_UNAT);
+       unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_PFS);
        unw.sw_off[unw.preg_index[UNW_REG_RP]] = SW(B0);
-       unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(AR_UNAT);
+       unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(CALLER_UNAT);
        unw.sw_off[unw.preg_index[UNW_REG_PR]] = SW(PR);
        unw.sw_off[unw.preg_index[UNW_REG_LC]] = SW(AR_LC);
        unw.sw_off[unw.preg_index[UNW_REG_FPSR]] = SW(AR_FPSR);
@@ -2259,7 +2242,7 @@ unw_init (void)
                if (i > 0)
                        unw.cache[i].lru_chain = (i - 1);
                unw.cache[i].coll_chain = -1;
-               unw.cache[i].lock = RW_LOCK_UNLOCKED;
+               rwlock_init(&unw.cache[i].lock);
        }
        unw.lru_head = UNW_CACHE_SIZE - 1;
        unw.lru_tail = 0;