1f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm/* libunwind - a platform-independent unwind library
287081cebabb0525d4e3085cfdc3f751fbc5c8239mostang.com!davidm   Copyright (C) 2001-2005 Hewlett-Packard Co
3f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
5f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmThis file is part of libunwind.
6f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
7f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmPermission is hereby granted, free of charge, to any person obtaining
8f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidma copy of this software and associated documentation files (the
9f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm"Software"), to deal in the Software without restriction, including
10f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmwithout limitation the rights to use, copy, modify, merge, publish,
11f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmdistribute, sublicense, and/or sell copies of the Software, and to
12f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmpermit persons to whom the Software is furnished to do so, subject to
13f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmthe following conditions:
14f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
15f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmThe above copyright notice and this permission notice shall be
16f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmincluded in all copies or substantial portions of the Software.
17f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
18f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
26f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#include "offsets.h"
27f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#include "unwind_i.h"
28f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
29f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmstatic inline int
3026fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidmlinux_sigtramp (struct cursor *c, ia64_loc_t prev_cfm_loc,
3126fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm		unw_word_t *num_regsp)
32f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm{
33f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#if defined(UNW_LOCAL_ONLY) && !defined(__linux)
34f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  return -UNW_EINVAL;
35f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#else
36f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  unw_word_t sc_addr;
37f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  int ret;
38f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
39f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if ((ret = ia64_get (c, IA64_LOC_ADDR (c->sp + 0x10
40f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm					 + LINUX_SIGFRAME_ARG2_OFF, 0),
41f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm		       &sc_addr)) < 0)
42f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return ret;
43f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
44f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->sigcontext_addr = sc_addr;
45f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
46f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (!IA64_IS_REG_LOC (c->loc[IA64_REG_IP])
47f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      && IA64_GET_ADDR (c->loc[IA64_REG_IP]) == sc_addr + LINUX_SC_BR_OFF + 8)
48f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    {
49f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      /* Linux kernels before 2.4.19 and 2.5.10 had buggy
50f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 unwind info for sigtramp.  Fix it up here.  */
51f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      c->loc[IA64_REG_IP]  = IA64_LOC_ADDR (sc_addr + LINUX_SC_IP_OFF, 0);
52f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      c->cfm_loc = IA64_LOC_ADDR (sc_addr + LINUX_SC_CFM_OFF, 0);
53f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    }
54f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
55f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* do what can't be described by unwind directives: */
56f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_PFS] = IA64_LOC_ADDR (sc_addr + LINUX_SC_AR_PFS_OFF, 0);
5726fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm  c->ec_loc = prev_cfm_loc;
58f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  *num_regsp = c->cfm & 0x7f;		/* size of frame */
59f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  return 0;
60f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#endif
61f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm}
62f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
63f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmstatic inline int
6426fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidmlinux_interrupt (struct cursor *c, ia64_loc_t prev_cfm_loc,
6526fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm		 unw_word_t *num_regsp, int marker)
66f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm{
676675be4926ff3989da0542ed19c55ab3a01df010hp.com!davidm#if defined(UNW_LOCAL_ONLY) && !(defined(__linux) && defined(__KERNEL__))
68f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  return -UNW_EINVAL;
69f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#else
70f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  unw_word_t sc_addr, num_regs;
71f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  ia64_loc_t pfs_loc;
72f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
73f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  sc_addr = c->sigcontext_addr = c->sp + 0x10;
74f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
75f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if ((c->pr & (1UL << LINUX_PT_P_NONSYS)) != 0)
76f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    num_regs = c->cfm & 0x7f;
77f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  else
78f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    num_regs = 0;
79f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
80f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* do what can't be described by unwind directives: */
81f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (marker == ABI_MARKER_OLD_LINUX_INTERRUPT)
82f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	  pfs_loc = IA64_LOC_ADDR (sc_addr + LINUX_OLD_PT_PFS_OFF, 0);
83f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  else
84f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	  pfs_loc = IA64_LOC_ADDR (sc_addr + LINUX_PT_PFS_OFF, 0);
85f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_PFS] = pfs_loc;
8626fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm  c->ec_loc = prev_cfm_loc;
87f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  *num_regsp = num_regs;		/* size of frame */
88f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  return 0;
89f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#endif
90f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm}
91f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
92f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmstatic inline int
9326fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidmhpux_sigtramp (struct cursor *c, ia64_loc_t prev_cfm_loc,
9426fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm	       unw_word_t *num_regsp)
95f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm{
96f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#if defined(UNW_LOCAL_ONLY) && !defined(__hpux)
97f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  return -UNW_EINVAL;
98f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#else
99f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  unw_word_t sc_addr, bsp, bspstore;
100f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  ia64_loc_t sc_loc;
101f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  int ret, i;
102f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
103f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* HP-UX passes the address of ucontext_t in r32: */
104f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if ((ret = ia64_get_stacked (c, 32, &sc_loc, NULL)) < 0)
105f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return ret;
106f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if ((ret = ia64_get (c, sc_loc, &sc_addr)) < 0)
107f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return ret;
108f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
109f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->sigcontext_addr = sc_addr;
110f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
111f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* Now mark all (preserved) registers as coming from the
112f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm     signal context: */
113f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->cfm_loc = IA64_LOC_UC_REG (UNW_IA64_CFM, sc_addr);
114f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_PRI_UNAT_MEM] = IA64_NULL_LOC;
115f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_PSP] = IA64_LOC_UC_REG (UNW_IA64_GR + 12, sc_addr);
116f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_BSP] = IA64_LOC_UC_REG (UNW_IA64_AR_BSP, sc_addr);
117f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_BSPSTORE] = IA64_LOC_UC_REG (UNW_IA64_AR_BSPSTORE, sc_addr);
118f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_PFS] = IA64_LOC_UC_REG (UNW_IA64_AR_PFS, sc_addr);
119f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_RNAT] = IA64_LOC_UC_REG (UNW_IA64_AR_RNAT, sc_addr);
120f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_IP] = IA64_LOC_UC_REG (UNW_IA64_IP, sc_addr);
121f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_R4] = IA64_LOC_UC_REG (UNW_IA64_GR + 4, sc_addr);
122f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_R5] = IA64_LOC_UC_REG (UNW_IA64_GR + 5, sc_addr);
123f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_R6] = IA64_LOC_UC_REG (UNW_IA64_GR + 6, sc_addr);
124f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_R7] = IA64_LOC_UC_REG (UNW_IA64_GR + 7, sc_addr);
125f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_NAT4] = IA64_LOC_UC_REG (UNW_IA64_NAT + 4, sc_addr);
126f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_NAT5] = IA64_LOC_UC_REG (UNW_IA64_NAT + 5, sc_addr);
127f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_NAT6] = IA64_LOC_UC_REG (UNW_IA64_NAT + 6, sc_addr);
128f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_NAT7] = IA64_LOC_UC_REG (UNW_IA64_NAT + 7, sc_addr);
129f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_UNAT] = IA64_LOC_UC_REG (UNW_IA64_AR_UNAT, sc_addr);
130f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_PR] = IA64_LOC_UC_REG (UNW_IA64_PR, sc_addr);
131f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_LC] = IA64_LOC_UC_REG (UNW_IA64_AR_LC, sc_addr);
132f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_FPSR] = IA64_LOC_UC_REG (UNW_IA64_AR_FPSR, sc_addr);
133f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_B1] = IA64_LOC_UC_REG (UNW_IA64_BR + 1, sc_addr);
134f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_B2] = IA64_LOC_UC_REG (UNW_IA64_BR + 2, sc_addr);
135f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_B3] = IA64_LOC_UC_REG (UNW_IA64_BR + 3, sc_addr);
136f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_B4] = IA64_LOC_UC_REG (UNW_IA64_BR + 4, sc_addr);
137f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_B5] = IA64_LOC_UC_REG (UNW_IA64_BR + 5, sc_addr);
138f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_F2] = IA64_LOC_UC_REG (UNW_IA64_FR + 2, sc_addr);
139f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_F3] = IA64_LOC_UC_REG (UNW_IA64_FR + 3, sc_addr);
140f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_F4] = IA64_LOC_UC_REG (UNW_IA64_FR + 4, sc_addr);
141f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_F5] = IA64_LOC_UC_REG (UNW_IA64_FR + 5, sc_addr);
142f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  for (i = 0; i < 16; ++i)
143f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    c->loc[IA64_REG_F16 + i] = IA64_LOC_UC_REG (UNW_IA64_FR + 16 + i, sc_addr);
144f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
145f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->pi.flags |= UNW_PI_FLAG_IA64_RBS_SWITCH;
146f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
147f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* update the CFM cache: */
148f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if ((ret = ia64_get (c, c->cfm_loc, &c->cfm)) < 0)
149f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return ret;
150f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* update the PSP cache: */
151f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if ((ret = ia64_get (c, c->loc[IA64_REG_PSP], &c->psp)) < 0)
152f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return ret;
153f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
154f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if ((ret = ia64_get (c, c->loc[IA64_REG_BSP], &bsp)) < 0
155f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      || (ret = ia64_get (c, c->loc[IA64_REG_BSPSTORE], &bspstore)) < 0)
156f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return ret;
157f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (bspstore < bsp)
158f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    /* Dirty partition got spilled into the ucontext_t structure
159f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm       itself.  We'll need to access it via uc_access(3).  */
160f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    rbs_switch (c, bsp, bspstore, IA64_LOC_UC_ADDR (bsp | 0x1f8, 0));
161f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
16226fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm  c->ec_loc = prev_cfm_loc;
16326fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm
16426fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm  *num_regsp = 0;
165f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  return 0;
166f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm#endif
167f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm}
168f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
169f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
170f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmstatic inline int
171f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmcheck_rbs_switch (struct cursor *c)
172f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm{
173f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  unw_word_t saved_bsp, saved_bspstore, loadrs, ndirty;
174f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  int ret = 0;
175f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
176f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  saved_bsp = c->bsp;
177f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (c->pi.flags & UNW_PI_FLAG_IA64_RBS_SWITCH)
178f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    {
179f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      /* Got ourselves a frame that has saved ar.bspstore, ar.bsp,
180f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 and ar.rnat, so we're all set for rbs-switching:  */
181f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      if ((ret = ia64_get (c, c->loc[IA64_REG_BSP], &saved_bsp)) < 0
182f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	  || (ret = ia64_get (c, c->loc[IA64_REG_BSPSTORE], &saved_bspstore)))
183f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	return ret;
184f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    }
185f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  else if ((c->abi_marker == ABI_MARKER_LINUX_SIGTRAMP
186f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	    || c->abi_marker == ABI_MARKER_OLD_LINUX_SIGTRAMP)
187f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	   && !IA64_IS_REG_LOC (c->loc[IA64_REG_BSP])
188f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	   && (IA64_GET_ADDR (c->loc[IA64_REG_BSP])
189f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	       == c->sigcontext_addr + LINUX_SC_AR_BSP_OFF))
190f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    {
191f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      /* When Linux delivers a signal on an alternate stack, it
192f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 does things a bit differently from what the unwind
193f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 conventions allow us to describe: instead of saving
194f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 ar.rnat, ar.bsp, and ar.bspstore, it saves the former two
195f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 plus the "loadrs" value.  Because of this, we need to
196f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 detect & record a potential rbs-area switch
197f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 manually... */
198f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
199f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      /* If ar.bsp has been saved already AND the current bsp is
200f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 not equal to the saved value, then we know for sure that
201f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 we're past the point where the backing store has been
202f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	 switched (and before the point where it's restored).  */
203f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      if ((ret = ia64_get (c, IA64_LOC_ADDR (c->sigcontext_addr
204f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm					     + LINUX_SC_AR_BSP_OFF, 0),
205f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm			   &saved_bsp) < 0)
206f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	  || (ret = ia64_get (c, IA64_LOC_ADDR (c->sigcontext_addr
207f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm						+ LINUX_SC_LOADRS_OFF, 0),
208f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm			      &loadrs) < 0))
209f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	return ret;
210f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      loadrs >>= 16;
21187081cebabb0525d4e3085cfdc3f751fbc5c8239mostang.com!davidm      ndirty = rse_num_regs (c->bsp - loadrs, c->bsp);
21287081cebabb0525d4e3085cfdc3f751fbc5c8239mostang.com!davidm      saved_bspstore = rse_skip_regs (saved_bsp, -ndirty);
213f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    }
214f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
215f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (saved_bsp == c->bsp)
216f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return 0;
217f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
218f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  return rbs_switch (c, saved_bsp, saved_bspstore, c->loc[IA64_REG_RNAT]);
219f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm}
220f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
221f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmstatic inline int
222f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmupdate_frame_state (struct cursor *c)
223f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm{
224f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  unw_word_t prev_ip, prev_sp, prev_bsp, ip, num_regs;
22526fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm  ia64_loc_t prev_cfm_loc;
226f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  int ret;
227f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
22826fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm  prev_cfm_loc = c->cfm_loc;
229f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  prev_ip = c->ip;
230f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  prev_sp = c->sp;
231f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  prev_bsp = c->bsp;
232f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
233f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* Update the IP cache (do this first: if we reach the end of the
234f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm     frame-chain, the rest of the info may not be valid/useful
235f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm     anymore. */
236f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  ret = ia64_get (c, c->loc[IA64_REG_IP], &ip);
237f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (ret < 0)
238f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return ret;
239f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->ip = ip;
240f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
241f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if ((ip & 0xc) != 0)
242f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    {
243f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      /* don't let obviously bad addresses pollute the cache */
244f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      Debug (1, "rejecting bad ip=0x%lx\n", (long) c->ip);
245f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      return -UNW_EINVALIDIP;
246f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    }
247f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
248f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->cfm_loc = c->loc[IA64_REG_PFS];
249f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* update the CFM cache: */
250f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  ret = ia64_get (c, c->cfm_loc, &c->cfm);
251f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (ret < 0)
252f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return ret;
253f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
25426fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm  /* Normally, AR.EC is stored in the CFM save-location.  That
25526fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm     save-location contains the full function-state as defined by
25626fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm     AR.PFS.  However, interruptions only save the frame-marker, not
25726fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm     any other info in CFM.  Instead, AR.EC gets saved on the first
25826fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm     call by the interruption-handler.  Thus, interruption-related
25926fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm     frames need to track the _previous_ CFM save-location since
26026fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm     that's were AR.EC is saved.  We support this by setting ec_loc to
26126fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm     cfm_loc by default and giving frames marked with an ABI-marker
26226fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm     the chance to override this value with prev_cfm_loc.  */
26326fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm  c->ec_loc = c->cfm_loc;
26426fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm
265f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  num_regs = 0;
266f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (unlikely (c->abi_marker))
267f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    {
268f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      c->last_abi_marker = c->abi_marker;
2696675be4926ff3989da0542ed19c55ab3a01df010hp.com!davidm      switch (ia64_get_abi_marker (c))
270f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	{
271f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	case ABI_MARKER_LINUX_SIGTRAMP:
272f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	case ABI_MARKER_OLD_LINUX_SIGTRAMP:
2736675be4926ff3989da0542ed19c55ab3a01df010hp.com!davidm	  ia64_set_abi (c, ABI_LINUX);
27426fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm	  if ((ret = linux_sigtramp (c, prev_cfm_loc, &num_regs)) < 0)
275f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	    return ret;
276f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	  break;
277f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
278f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	case ABI_MARKER_OLD_LINUX_INTERRUPT:
279f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	case ABI_MARKER_LINUX_INTERRUPT:
2806675be4926ff3989da0542ed19c55ab3a01df010hp.com!davidm	  ia64_set_abi (c, ABI_LINUX);
28126fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm	  if ((ret = linux_interrupt (c, prev_cfm_loc, &num_regs,
28226fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm				      c->abi_marker)) < 0)
283f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	    return ret;
284f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	  break;
285f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
286f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	case ABI_MARKER_HP_UX_SIGTRAMP:
2876675be4926ff3989da0542ed19c55ab3a01df010hp.com!davidm	  ia64_set_abi (c, ABI_HPUX);
28826fdb45d764982fc6847f07caf42e56a343d410dhp.com!davidm	  if ((ret = hpux_sigtramp (c, prev_cfm_loc, &num_regs)) < 0)
289f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	    return ret;
290f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	  break;
291f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
292f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	default:
293f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	  Debug (1, "unknown ABI marker: ABI=%u, context=%u\n",
294f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm		 c->abi_marker >> 8, c->abi_marker & 0xff);
295f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	  return -UNW_EINVAL;
296f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	}
297f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      Debug (12, "sigcontext_addr=%lx (ret=%d)\n",
298f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	     (unsigned long) c->sigcontext_addr, ret);
299f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
300f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      c->sigcontext_off = c->sigcontext_addr - c->sp;
301f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
302f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      /* update the IP cache: */
303f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      if ((ret = ia64_get (c, c->loc[IA64_REG_IP], &ip)) < 0)
304f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm 	return ret;
305f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      c->ip = ip;
306f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      if (ip == 0)
307f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	/* end of frame-chain reached */
308f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	return 0;
309f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    }
310f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  else
311f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    num_regs = (c->cfm >> 7) & 0x7f;	/* size of locals */
312f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
313f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (!IA64_IS_NULL_LOC (c->loc[IA64_REG_BSP]))
314f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    {
315f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      ret = check_rbs_switch (c);
316f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      if (ret < 0)
317f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	return ret;
318f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    }
319f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
32087081cebabb0525d4e3085cfdc3f751fbc5c8239mostang.com!davidm  c->bsp = rse_skip_regs (c->bsp, -num_regs);
321f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
322f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->sp = c->psp;
323f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->abi_marker = 0;
324f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
325f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (c->ip == prev_ip && c->sp == prev_sp && c->bsp == prev_bsp)
326f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    {
327ec53de82ec7c00adb56c9e8b1b03d489a69c494bArun Sharma      Dprintf ("%s: ip, sp, and bsp unchanged; stopping here (ip=0x%lx)\n",
328f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm	       __FUNCTION__, (long) ip);
329f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm      return -UNW_EBADFRAME;
330f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    }
331f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
332f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* as we unwind, the saved ar.unat becomes the primary unat: */
333f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->loc[IA64_REG_PRI_UNAT_MEM] = c->loc[IA64_REG_UNAT];
334f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
335f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  /* restore the predicates: */
336f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  ret = ia64_get (c, c->loc[IA64_REG_PR], &c->pr);
337f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  if (ret < 0)
338f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm    return ret;
339f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
340f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  c->pi_valid = 0;
341f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  return 0;
342f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm}
343f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
344f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
345f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmPROTECTED int
346f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidmunw_step (unw_cursor_t *cursor)
347f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm{
348f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  struct cursor *c = (struct cursor *) cursor;
349f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm  int ret;
350f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
35187081cebabb0525d4e3085cfdc3f751fbc5c8239mostang.com!davidm  Debug (1, "(cursor=%p, ip=0x%016lx)\n", c, (unsigned long) c->ip);
352f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
35387081cebabb0525d4e3085cfdc3f751fbc5c8239mostang.com!davidm  if ((ret = ia64_find_save_locs (c)) >= 0
35487081cebabb0525d4e3085cfdc3f751fbc5c8239mostang.com!davidm      && (ret = update_frame_state (c)) >= 0)
35587081cebabb0525d4e3085cfdc3f751fbc5c8239mostang.com!davidm    ret = (c->ip == 0) ? 0 : 1;
356f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm
3576675be4926ff3989da0542ed19c55ab3a01df010hp.com!davidm  Debug (2, "returning %d (ip=0x%016lx)\n", ret, (unsigned long) c->ip);
35887081cebabb0525d4e3085cfdc3f751fbc5c8239mostang.com!davidm  return ret;
359f1734db27381d83b4c2f9395d55cef37a766bcd2homeip.net!davidm}
360