#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)
{
struct unw_script *script, *prev, *tmp;
unw_hash_index_t index;
- unsigned long flags;
unsigned short head;
STAT(++unw.stat.script.news);
* 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
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;
{
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 */
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);
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;
}
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));
int
unw_unwind_to_user (struct unw_frame_info *info)
{
- unsigned long ip;
+ unsigned long ip, sp;
while (unw_unwind(info) >= 0) {
if (unw_get_rp(info, &ip) < 0) {
__FUNCTION__, ip);
return -1;
}
+ unw_get_sp(info, &sp);
+ if (sp >= (unsigned long)info->task + IA64_STK_OFFSET)
+ break;
if (ip < FIXADDR_USER_END)
return 0;
}
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)
{
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;