138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm/* libunwind - a platform-independent unwind library
27f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm   Copyright (C) 2003-2005 Hewlett-Packard Co
338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmThis file is part of libunwind.
638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmPermission is hereby granted, free of charge, to any person obtaining
838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidma copy of this software and associated documentation files (the
938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm"Software"), to deal in the Software without restriction, including
1038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmwithout limitation the rights to use, copy, modify, merge, publish,
1138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmdistribute, sublicense, and/or sell copies of the Software, and to
1238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmpermit persons to whom the Software is furnished to do so, subject to
1338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmthe following conditions:
1438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
1538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmThe above copyright notice and this permission notice shall be
1638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmincluded in all copies or substantial portions of the Software.
1738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
1838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
2538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
2638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm/* Logically, we like to think of the stack as a contiguous region of
2738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmmemory.  Unfortunately, this logical view doesn't work for the
2838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmregister backing store, because the RSE is an asynchronous engine and
2938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmbecause UNIX/Linux allow for stack-switching via sigaltstack(2).
3038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmSpecifically, this means that any given stacked register may or may
3138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmnot be backed up by memory in the current stack.  If not, then the
3238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmbacking memory may be found in any of the "more inner" (younger)
3338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmstacks.  The routines in this file help manage the discontiguous
3438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmnature of the register backing store.  The routines are completely
3538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmindependent of UNIX/Linux, but each stack frame that switches the
3638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmbacking store is expected to reserve 4 words for use by libunwind. For
3738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmexample, in the Linux sigcontext, sc_fr[0] and sc_fr[1] serve this
3838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmpurpose.  */
3938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
4038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm#include "unwind_i.h"
4138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
4296407911ee56be584395c491cffa2f4824647911hp.com!davidm#if UNW_DEBUG
4396407911ee56be584395c491cffa2f4824647911hp.com!davidm
4496407911ee56be584395c491cffa2f4824647911hp.com!davidmHIDDEN const char *
4596407911ee56be584395c491cffa2f4824647911hp.com!davidmia64_strloc (ia64_loc_t loc)
4696407911ee56be584395c491cffa2f4824647911hp.com!davidm{
4796407911ee56be584395c491cffa2f4824647911hp.com!davidm  static char buf[128];
4896407911ee56be584395c491cffa2f4824647911hp.com!davidm
4996407911ee56be584395c491cffa2f4824647911hp.com!davidm  if (IA64_IS_NULL_LOC (loc))
5096407911ee56be584395c491cffa2f4824647911hp.com!davidm    return "<null>";
5196407911ee56be584395c491cffa2f4824647911hp.com!davidm
5296407911ee56be584395c491cffa2f4824647911hp.com!davidm  buf[0] = '\0';
5396407911ee56be584395c491cffa2f4824647911hp.com!davidm
5496407911ee56be584395c491cffa2f4824647911hp.com!davidm  if (IA64_IS_MEMSTK_NAT (loc))
5596407911ee56be584395c491cffa2f4824647911hp.com!davidm    strcat (buf, "memstk_nat(");
5696407911ee56be584395c491cffa2f4824647911hp.com!davidm  if (IA64_IS_UC_LOC (loc))
5796407911ee56be584395c491cffa2f4824647911hp.com!davidm    strcat (buf, "uc(");
5896407911ee56be584395c491cffa2f4824647911hp.com!davidm  if (IA64_IS_FP_LOC (loc))
5996407911ee56be584395c491cffa2f4824647911hp.com!davidm    strcat (buf, "fp(");
6096407911ee56be584395c491cffa2f4824647911hp.com!davidm
6196407911ee56be584395c491cffa2f4824647911hp.com!davidm  if (IA64_IS_REG_LOC (loc))
6296407911ee56be584395c491cffa2f4824647911hp.com!davidm    sprintf (buf + strlen (buf), "%s", unw_regname (IA64_GET_REG (loc)));
6396407911ee56be584395c491cffa2f4824647911hp.com!davidm  else
6496407911ee56be584395c491cffa2f4824647911hp.com!davidm    sprintf (buf + strlen (buf), "0x%llx",
6596407911ee56be584395c491cffa2f4824647911hp.com!davidm	     (unsigned long long) IA64_GET_ADDR (loc));
6696407911ee56be584395c491cffa2f4824647911hp.com!davidm
6796407911ee56be584395c491cffa2f4824647911hp.com!davidm  if (IA64_IS_FP_LOC (loc))
6896407911ee56be584395c491cffa2f4824647911hp.com!davidm    strcat (buf, ")");
6996407911ee56be584395c491cffa2f4824647911hp.com!davidm  if (IA64_IS_UC_LOC (loc))
7096407911ee56be584395c491cffa2f4824647911hp.com!davidm    strcat (buf, ")");
7196407911ee56be584395c491cffa2f4824647911hp.com!davidm  if (IA64_IS_MEMSTK_NAT (loc))
7296407911ee56be584395c491cffa2f4824647911hp.com!davidm    strcat (buf, ")");
7396407911ee56be584395c491cffa2f4824647911hp.com!davidm
7496407911ee56be584395c491cffa2f4824647911hp.com!davidm  return buf;
7596407911ee56be584395c491cffa2f4824647911hp.com!davidm}
7696407911ee56be584395c491cffa2f4824647911hp.com!davidm
7796407911ee56be584395c491cffa2f4824647911hp.com!davidm#endif /* UNW_DEBUG */
7896407911ee56be584395c491cffa2f4824647911hp.com!davidm
7938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmHIDDEN int
8038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmrbs_switch (struct cursor *c,
8138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	    unw_word_t saved_bsp, unw_word_t saved_bspstore,
8238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	    ia64_loc_t saved_rnat_loc)
8338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm{
8438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  struct rbs_area *rbs = &c->rbs_area[c->rbs_curr];
8519e3bf3ea675ea64dbe23730e2600ae99ab0b187hp.com!davidm  unw_word_t lo, ndirty, rbs_base;
8619e3bf3ea675ea64dbe23730e2600ae99ab0b187hp.com!davidm  int ret;
8738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
88f20eb7ea72c517e53165d86e1be4d421d1f7bf22hp.com!davidm  Debug (10, "(left=%u, curr=%u)\n", c->rbs_left_edge, c->rbs_curr);
8938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
9038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  /* Calculate address "lo" at which the backing store starts:  */
917f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm  ndirty = rse_num_regs (saved_bspstore, saved_bsp);
927f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm  lo = rse_skip_regs (c->bsp, -ndirty);
9338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
9438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  rbs->size = (rbs->end - lo);
9538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
9638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  /* If the previously-recorded rbs-area is empty we don't need to
9738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm     track it and we can simply overwrite it... */
9838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  if (rbs->size)
9938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    {
100f20eb7ea72c517e53165d86e1be4d421d1f7bf22hp.com!davidm      Debug (10, "inner=[0x%lx-0x%lx)\n",
10138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	     (long) (rbs->end - rbs->size), (long) rbs->end);
10238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
1037f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      c->rbs_curr = (c->rbs_curr + 1) % ARRAY_SIZE (c->rbs_area);
10438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm      rbs = c->rbs_area + c->rbs_curr;
10538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
10638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm      if (c->rbs_curr == c->rbs_left_edge)
1077f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm	c->rbs_left_edge = (c->rbs_left_edge + 1) % ARRAY_SIZE (c->rbs_area);
10838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    }
10919e3bf3ea675ea64dbe23730e2600ae99ab0b187hp.com!davidm
11019e3bf3ea675ea64dbe23730e2600ae99ab0b187hp.com!davidm  if ((ret = rbs_get_base (c, saved_bspstore, &rbs_base)) < 0)
11119e3bf3ea675ea64dbe23730e2600ae99ab0b187hp.com!davidm    return ret;
11219e3bf3ea675ea64dbe23730e2600ae99ab0b187hp.com!davidm
11338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  rbs->end = saved_bspstore;
11419e3bf3ea675ea64dbe23730e2600ae99ab0b187hp.com!davidm  rbs->size = saved_bspstore - rbs_base;
11538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  rbs->rnat_loc = saved_rnat_loc;
11638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
11738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  c->bsp = saved_bsp;
11838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
11919e3bf3ea675ea64dbe23730e2600ae99ab0b187hp.com!davidm  Debug (10, "outer=[0x%llx-0x%llx), rnat@%s\n", (long long) rbs_base,
12038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	 (long long) rbs->end, ia64_strloc (rbs->rnat_loc));
12138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  return 0;
12238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm}
12338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
12438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmHIDDEN int
12538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmrbs_find_stacked (struct cursor *c, unw_word_t regs_to_skip,
12638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm		  ia64_loc_t *locp, ia64_loc_t *rnat_locp)
12738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm{
12838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  unw_word_t nregs, bsp = c->bsp, curr = c->rbs_curr, n;
12938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  unw_word_t left_edge = c->rbs_left_edge;
13038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm#if UNW_DEBUG
13138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  int reg = 32 + regs_to_skip;
13238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm#endif
13338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
13438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  while (!rbs_contains (&c->rbs_area[curr], bsp))
13538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    {
13638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm      if (curr == left_edge)
13738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	{
13838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	  Debug (1, "could not find register r%d!\n", reg);
13938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	  return -UNW_EBADREG;
14038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	}
14138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
1427f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      n = rse_num_regs (c->rbs_area[curr].end, bsp);
1437f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      curr = (curr + ARRAY_SIZE (c->rbs_area) - 1) % ARRAY_SIZE (c->rbs_area);
1447f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      bsp = rse_skip_regs (c->rbs_area[curr].end - c->rbs_area[curr].size, n);
14538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    }
14638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
14738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  while (1)
14838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    {
1497f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      nregs = rse_num_regs (bsp, c->rbs_area[curr].end);
15038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
15138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm      if (regs_to_skip < nregs)
15238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	{
15338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	  /* found it: */
15438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	  unw_word_t addr;
15538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
1567f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm	  addr = rse_skip_regs (bsp, regs_to_skip);
15738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	  if (locp)
15838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	    *locp = rbs_loc (c->rbs_area + curr, addr);
15938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	  if (rnat_locp)
16038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	    *rnat_locp = rbs_get_rnat_loc (c->rbs_area + curr, addr);
16138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	  return 0;
16238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	}
16338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
16438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm      if (curr == left_edge)
16538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	{
16638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	  Debug (1, "could not find register r%d!\n", reg);
16738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	  return -UNW_EBADREG;
16838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	}
16938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
17038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm      regs_to_skip -= nregs;
17138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
1727f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      curr = (curr + ARRAY_SIZE (c->rbs_area) - 1) % ARRAY_SIZE (c->rbs_area);
17338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm      bsp = c->rbs_area[curr].end - c->rbs_area[curr].size;
17438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    }
17538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm}
17638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
17796407911ee56be584395c491cffa2f4824647911hp.com!davidm#ifdef NEED_RBS_COVER_AND_FLUSH
178cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm
17938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmstatic inline int
18038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmget_rnat (struct cursor *c, struct rbs_area *rbs, unw_word_t bsp,
181cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  unw_word_t *__restrict rnatp)
18238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm{
183cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  ia64_loc_t rnat_locp = rbs_get_rnat_loc (rbs, bsp);
184cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm
185cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  return ia64_get (c, rnat_locp, rnatp);
18638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm}
18738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
188cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm/* Simulate the effect of "cover" followed by a "flushrs" for the
189cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm   target-frame.  However, since the target-frame's backing store
190cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm   may not have space for the registers that got spilled onto other
191cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm   rbs-areas, we save those registers to DIRTY_PARTITION where
192cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm   we can then load them via a single "loadrs".
193cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm
194cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm   This function returns the size of the dirty-partition that was
195cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm   created or a negative error-code in case of error.
19638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
19738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm   Note: This does not modify the rbs_area[] structure in any way.  */
19838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidmHIDDEN int
199cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidmrbs_cover_and_flush (struct cursor *c, unw_word_t nregs,
200cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm		     unw_word_t *dirty_partition, unw_word_t *dirty_rnat,
201cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm		     unw_word_t *bspstore)
20238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm{
203cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  unw_word_t n, src_mask, dst_mask, bsp, *dst, src_rnat, dst_rnat = 0;
204cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  unw_word_t curr = c->rbs_curr, left_edge = c->rbs_left_edge;
205cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  struct rbs_area *rbs = c->rbs_area + curr;
20638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm  int ret;
20738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
208cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  bsp = c->bsp;
2097f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm  c->bsp = rse_skip_regs (bsp, nregs);
21038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
211cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  if (likely (rbs_contains (rbs, bsp)))
21238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    {
213cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      /* at least _some_ registers are on rbs... */
2147f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      n = rse_num_regs (bsp, rbs->end);
215cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      if (likely (n >= nregs))
216cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	{
217cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  /* common case #1: all registers are on current rbs... */
218cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  /* got lucky: _all_ registers are on rbs... */
219cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  ia64_loc_t rnat_loc = rbs_get_rnat_loc (rbs, c->bsp);
22038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
221cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  *bspstore = c->bsp;
22238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
223cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  if (IA64_IS_REG_LOC (rnat_loc))
224cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	    {
225cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	      unw_word_t rnat_addr = (unw_word_t)
226cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm		tdep_uc_addr (c->as_arg, UNW_IA64_AR_RNAT, NULL);
227cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	      rnat_loc = IA64_LOC_ADDR (rnat_addr, 0);
228cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	    }
229cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  c->loc[IA64_REG_RNAT] = rnat_loc;
230cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  return 0;	/* all done */
231cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	}
232cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      nregs -= n;	/* account for registers already on the rbs */
23338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
2347f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      assert (rse_skip_regs (c->bsp, -nregs) == rse_skip_regs (rbs->end, 0));
23538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    }
236cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  else
237cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm    /* Earlier frames also didn't get spilled; need to "loadrs" those,
238cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm       too... */
2397f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm    nregs += rse_num_regs (rbs->end, bsp);
240cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm
241cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  /* OK, we need to copy NREGS registers to the dirty partition.  */
242cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm
243cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  *bspstore = bsp = rbs->end;
244cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  c->loc[IA64_REG_RNAT] = rbs->rnat_loc;
245cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  assert (!IA64_IS_REG_LOC (rbs->rnat_loc));
24638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
247cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  dst = dirty_partition;
248cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm
249cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  while (nregs > 0)
25038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    {
251cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      if (unlikely (!rbs_contains (rbs, bsp)))
25238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	{
253cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  /* switch to next non-empty rbs-area: */
254cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  do
25538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	    {
256cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	      if (curr == left_edge)
257cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm		{
258cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm		  Debug (0, "rbs-underflow while flushing %lu regs, "
259cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm			 "bsp=0x%lx, dst=0x%p\n", (unsigned long) nregs,
260cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm			 (unsigned long) bsp, dst);
261cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm		  return -UNW_EBADREG;
262cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm		}
263cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm
2647f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm	      assert (rse_num_regs (rbs->end, bsp) == 0);
265cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm
2667f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm	      curr = (curr + ARRAY_SIZE (c->rbs_area) - 1)
2677f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm		      % ARRAY_SIZE (c->rbs_area);
268cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	      rbs = c->rbs_area + curr;
269cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	      bsp = rbs->end - rbs->size;
27038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	    }
271cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  while (rbs->size == 0);
27238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
273cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0)
274cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	    return ret;
275cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	}
27638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
2777f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      if (unlikely (rse_is_rnat_slot (bsp)))
278cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	{
279cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  bsp += 8;
280cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0)
281cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	    return ret;
282cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	}
2837f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      if (unlikely (rse_is_rnat_slot ((unw_word_t) dst)))
284cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	{
285cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  *dst++ = dst_rnat;
286cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	  dst_rnat = 0;
287cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	}
28838b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
2897f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      src_mask = ((unw_word_t) 1) << rse_slot_num (bsp);
2907f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm      dst_mask = ((unw_word_t) 1) << rse_slot_num ((unw_word_t) dst);
29138b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
29238b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm      if (src_rnat & src_mask)
29338b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	dst_rnat |= dst_mask;
29438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm      else
29538b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	dst_rnat &= ~dst_mask;
29638b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
297cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      /* copy one slot: */
298cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      if ((ret = ia64_get (c, rbs_loc (rbs, bsp), dst)) < 0)
29938b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm	return ret;
30038b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm
301cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      /* advance to next slot: */
302cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      --nregs;
303cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      bsp += 8;
304cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      ++dst;
305cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm    }
3067f8b54ae5c0aae5bc2574b727946c8b9ecccc09dmostang.com!davidm  if (unlikely (rse_is_rnat_slot ((unw_word_t) dst)))
307cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm    {
308cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      /* The LOADRS instruction loads "the N bytes below the current
309cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	 BSP" but BSP can never point to an RNaT slot so if the last
310cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	 destination word happens to be an RNaT slot, we need to write
311cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm	 that slot now. */
312cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      *dst++ = dst_rnat;
313cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm      dst_rnat = 0;
31438b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm    }
315cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  *dirty_rnat = dst_rnat;
316cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm  return (char *) dst - (char *) dirty_partition;
31738b586f953d19b8d775b8165d76567f8eae5f3d7homeip.net!davidm}
318cd69bfec0c6e20fef5ea60e8f8363cb773e79065hp.com!davidm
31981f4953a1f3114dfe328a0fe6126527cd9c8c1e6mostang.com!davidm#endif /* !UNW_REMOTE_ONLY */
320