1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-06-30 05:01:44 +02:00

(get_rnat): Simplify to return only the RNaT value itself.

(rbs_cover_and_flush): Take additional arguments "dirty_partition",
	"dirty_rnat", and "bspstore".  When it is necessary to copy
	backing-store words, copy them to "dirty_partition" instead of
	the target rbs, which may be full already.

(Logical change 1.259)
This commit is contained in:
hp.com!davidm 2004-08-31 13:59:10 +00:00
parent 3dd5ca6713
commit cd69bfec0c

View file

@ -133,123 +133,146 @@ rbs_find_stacked (struct cursor *c, unw_word_t regs_to_skip,
} }
} }
#ifndef REMOTE_ONLY
static inline int static inline int
get_rnat (struct cursor *c, struct rbs_area *rbs, unw_word_t bsp, get_rnat (struct cursor *c, struct rbs_area *rbs, unw_word_t bsp,
ia64_loc_t *__restrict rnat_locp, unw_word_t *__restrict rnatp) unw_word_t *__restrict rnatp)
{ {
*rnat_locp = rbs_get_rnat_loc (rbs, bsp); ia64_loc_t rnat_locp = rbs_get_rnat_loc (rbs, bsp);
return ia64_get (c, *rnat_locp, rnatp);
return ia64_get (c, rnat_locp, rnatp);
} }
/* Ensure that the first "nregs" stacked registers are on the current /* Simulate the effect of "cover" followed by a "flushrs" for the
register backing store area. This effectively simulates the effect target-frame. However, since the target-frame's backing store
of a "cover" followed by a "flushrs" for the current frame. may not have space for the registers that got spilled onto other
rbs-areas, we save those registers to DIRTY_PARTITION where
we can then load them via a single "loadrs".
This function returns the size of the dirty-partition that was
created or a negative error-code in case of error.
Note: This does not modify the rbs_area[] structure in any way. */ Note: This does not modify the rbs_area[] structure in any way. */
HIDDEN int HIDDEN int
rbs_cover_and_flush (struct cursor *c, unw_word_t nregs) rbs_cover_and_flush (struct cursor *c, unw_word_t nregs,
unw_word_t *dirty_partition, unw_word_t *dirty_rnat,
unw_word_t *bspstore)
{ {
unw_word_t src_mask, dst_mask, curr, val, left_edge = c->rbs_left_edge; unw_word_t n, src_mask, dst_mask, bsp, *dst, src_rnat, dst_rnat = 0;
unw_word_t src_bsp, dst_bsp, src_rnat, dst_rnat, dst_rnat_addr; unw_word_t curr = c->rbs_curr, left_edge = c->rbs_left_edge;
ia64_loc_t src_rnat_loc, dst_rnat_loc; struct rbs_area *rbs = c->rbs_area + curr;
unw_word_t final_bsp;
struct rbs_area *dst_rbs;
int ret; int ret;
if (nregs < 1) bsp = c->bsp;
return 0; /* nothing to do... */ c->bsp = ia64_rse_skip_regs (bsp, nregs);
/* Handle the common case quickly: */ if (likely (rbs_contains (rbs, bsp)))
curr = c->rbs_curr;
dst_rbs = c->rbs_area + curr;
final_bsp = ia64_rse_skip_regs (c->bsp, nregs); /* final bsp */
if (likely (rbs_contains (dst_rbs, final_bsp) || curr == left_edge))
{ {
dst_rnat_addr = ia64_rse_rnat_addr (ia64_rse_skip_regs (c->bsp, /* at least _some_ registers are on rbs... */
nregs - 1)); n = ia64_rse_num_regs (bsp, rbs->end);
if (rbs_contains (dst_rbs, dst_rnat_addr)) if (likely (n >= nregs))
c->loc[IA64_REG_RNAT] = rbs_loc (dst_rbs, dst_rnat_addr);
c->bsp = final_bsp;
return 0;
}
/* Skip over regs that are already on the destination rbs-area: */
dst_bsp = src_bsp = dst_rbs->end;
if ((ret = get_rnat (c, dst_rbs, dst_bsp, &dst_rnat_loc, &dst_rnat)) < 0)
return ret;
/* This may seem a bit surprising, but with a hyper-lazy RSE, it's
perfectly common that ar.bspstore points to an RNaT slot at the
time of a backing-store switch. When that happens, install the
appropriate RNaT value (if necessary) and move on to the next
slot. */
if (ia64_rse_is_rnat_slot (dst_bsp))
{
if ((IA64_IS_REG_LOC (dst_rnat_loc)
|| IA64_GET_ADDR (dst_rnat_loc) != dst_bsp)
&& (ret = ia64_put (c, rbs_loc (dst_rbs, dst_bsp), dst_rnat)) < 0)
return ret;
dst_bsp = src_bsp = dst_bsp + 8;
}
while (dst_bsp != final_bsp)
{
while (!rbs_contains (&c->rbs_area[curr], src_bsp))
{ {
/* switch to next rbs-area, adjust src_bsp accordingly: */ /* common case #1: all registers are on current rbs... */
if (curr == left_edge) /* got lucky: _all_ registers are on rbs... */
ia64_loc_t rnat_loc = rbs_get_rnat_loc (rbs, c->bsp);
*bspstore = c->bsp;
if (IA64_IS_REG_LOC (rnat_loc))
{ {
Debug (1, "rbs-underflow while flushing %lu regs, " unw_word_t rnat_addr = (unw_word_t)
"src_bsp=0x%lx, dst_bsp=0x%lx\n", (unsigned long) nregs, tdep_uc_addr (c->as_arg, UNW_IA64_AR_RNAT, NULL);
(unsigned long) src_bsp, (unsigned long) dst_bsp); rnat_loc = IA64_LOC_ADDR (rnat_addr, 0);
return -UNW_EBADREG;
} }
curr = (curr + NELEMS (c->rbs_area) - 1) % NELEMS (c->rbs_area); c->loc[IA64_REG_RNAT] = rnat_loc;
src_bsp = c->rbs_area[curr].end - c->rbs_area[curr].size; return 0; /* all done */
}
nregs -= n; /* account for registers already on the rbs */
assert (ia64_rse_skip_regs (c->bsp, -nregs) ==
ia64_rse_skip_regs (rbs->end, 0));
}
else
/* Earlier frames also didn't get spilled; need to "loadrs" those,
too... */
nregs += ia64_rse_num_regs (rbs->end, bsp);
/* OK, we need to copy NREGS registers to the dirty partition. */
*bspstore = bsp = rbs->end;
c->loc[IA64_REG_RNAT] = rbs->rnat_loc;
assert (!IA64_IS_REG_LOC (rbs->rnat_loc));
dst = dirty_partition;
while (nregs > 0)
{
if (unlikely (!rbs_contains (rbs, bsp)))
{
/* switch to next non-empty rbs-area: */
do
{
if (curr == left_edge)
{
Debug (0, "rbs-underflow while flushing %lu regs, "
"bsp=0x%lx, dst=0x%p\n", (unsigned long) nregs,
(unsigned long) bsp, dst);
return -UNW_EBADREG;
}
assert (ia64_rse_num_regs (rbs->end, bsp) == 0);
curr = (curr + NELEMS (c->rbs_area) - 1) % NELEMS (c->rbs_area);
rbs = c->rbs_area + curr;
bsp = rbs->end - rbs->size;
}
while (rbs->size == 0);
if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0)
return ret;
} }
/* OK, found the right rbs-area. Now copy both the register if (unlikely (ia64_rse_is_rnat_slot (bsp)))
value and its NaT bit: */ {
bsp += 8;
if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0)
return ret;
}
if (unlikely (ia64_rse_is_rnat_slot ((unw_word_t) dst)))
{
*dst++ = dst_rnat;
dst_rnat = 0;
}
if ((ret = get_rnat (c, c->rbs_area + curr, src_bsp, src_mask = ((unw_word_t) 1) << ia64_rse_slot_num (bsp);
&src_rnat_loc, &src_rnat)) < 0) dst_mask = ((unw_word_t) 1) << ia64_rse_slot_num ((unw_word_t) dst);
return ret;
src_mask = ((unw_word_t) 1) << ia64_rse_slot_num (src_bsp);
dst_mask = ((unw_word_t) 1) << ia64_rse_slot_num (dst_bsp);
if (src_rnat & src_mask) if (src_rnat & src_mask)
dst_rnat |= dst_mask; dst_rnat |= dst_mask;
else else
dst_rnat &= ~dst_mask; dst_rnat &= ~dst_mask;
if ((ret = ia64_get (c, rbs_loc (c->rbs_area + curr, src_bsp), &val)) < 0 /* copy one slot: */
|| (ret = ia64_put (c, rbs_loc (dst_rbs, dst_bsp), val)) < 0) if ((ret = ia64_get (c, rbs_loc (rbs, bsp), dst)) < 0)
return ret; return ret;
/* advance src_bsp & dst_bsp to next slot: */ /* advance to next slot: */
--nregs;
src_bsp += 8; bsp += 8;
if (ia64_rse_is_rnat_slot (src_bsp)) ++dst;
src_bsp += 8;
dst_bsp += 8;
if (ia64_rse_is_rnat_slot (dst_bsp))
{
if ((ret = ia64_put (c, rbs_loc (dst_rbs, dst_bsp), dst_rnat)) < 0)
return ret;
dst_bsp += 8;
if ((ret = get_rnat (c, dst_rbs, dst_bsp,
&dst_rnat_loc, &dst_rnat)) < 0)
return ret;
}
} }
c->bsp = dst_bsp; if (unlikely (ia64_rse_is_rnat_slot ((unw_word_t) dst)))
c->loc[IA64_REG_RNAT] = dst_rnat_loc; {
return ia64_put (c, dst_rnat_loc, dst_rnat); /* The LOADRS instruction loads "the N bytes below the current
BSP" but BSP can never point to an RNaT slot so if the last
destination word happens to be an RNaT slot, we need to write
that slot now. */
*dst++ = dst_rnat;
dst_rnat = 0;
}
*dirty_rnat = dst_rnat;
return (char *) dst - (char *) dirty_partition;
} }
#endif /* !REMOTE_ONLY */