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