blob: fbe15cdc8d427680ff0d8ded3dfafaabfd597dab [file] [log] [blame]
mostang.com!davidm997f0252002-12-19 07:16:50 +00001/* libunwind - a platform-independent unwind library
mostang.com!davidmea0a71a2003-01-21 17:41:20 +00002 Copyright (C) 2001-2003 Hewlett-Packard Co
mostang.com!davidm997f0252002-12-19 07:16:50 +00003 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5This file is part of libunwind.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
25
26#include <stdlib.h>
27
28#include "rse.h"
29#include "unwind_i.h"
mostang.com!davidmea0a71a2003-01-21 17:41:20 +000030#include "offsets.h"
mostang.com!davidm997f0252002-12-19 07:16:50 +000031
32#ifndef UNW_REMOTE_ONLY
33
34HIDDEN inline int
35ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
36{
mostang.com!davidm02c8c0c2003-02-14 06:25:36 +000037 unw_word_t val, sol, sof, pri_unat, loadrs, n, pfs;
mostang.com!davidm997f0252002-12-19 07:16:50 +000038 struct cursor *c = (struct cursor *) cursor;
mostang.com!davidm678d3202003-02-08 10:10:59 +000039 struct
40 {
41 unw_word_t r1;
42 unw_word_t r4;
43 unw_word_t r5;
44 unw_word_t r6;
45 unw_word_t r7;
46 unw_word_t r15;
47 unw_word_t r16;
48 unw_word_t r17;
49 unw_word_t r18;
50 }
51 extra;
52 int ret;
53# define GET_NAT(n) \
mostang.com!davidm997f0252002-12-19 07:16:50 +000054 do \
55 { \
56 ret = ia64_access_reg (c, UNW_IA64_NAT + (n), &val, 0); \
57 if (ret < 0) \
58 return ret; \
59 if (val) \
mostang.com!davidm678d3202003-02-08 10:10:59 +000060 pri_unat |= (unw_word_t) 1 << n; \
mostang.com!davidm997f0252002-12-19 07:16:50 +000061 } \
62 while (0)
mostang.com!davidm997f0252002-12-19 07:16:50 +000063
64 /* ensure c->pi is up-to-date: */
65 if ((ret = ia64_make_proc_info (c)) < 0)
66 return ret;
67
mostang.com!davidm678d3202003-02-08 10:10:59 +000068 /* Copy contents of r4-r7 into "extra", so that their values end up
69 contiguous, so we can use a single (primary-) UNaT value. */
70 if ((ret = ia64_get (c, c->r4_loc, &extra.r4)) < 0
71 || (ret = ia64_get (c, c->r5_loc, &extra.r5)) < 0
72 || (ret = ia64_get (c, c->r6_loc, &extra.r6)) < 0
73 || (ret = ia64_get (c, c->r7_loc, &extra.r7)) < 0)
74 return ret;
mostang.com!davidm997f0252002-12-19 07:16:50 +000075
mostang.com!davidm678d3202003-02-08 10:10:59 +000076 /* Form the primary UNaT value: */
77 pri_unat = 0;
78 GET_NAT (4); GET_NAT(5);
79 GET_NAT (6); GET_NAT(7);
80 n = (((uintptr_t) &extra.r4) / 8 - 4) % 64;
81 pri_unat = (pri_unat << n) | (pri_unat >> (64 - n));
mostang.com!davidm997f0252002-12-19 07:16:50 +000082
mostang.com!davidmea0a71a2003-01-21 17:41:20 +000083 if (unlikely (c->sigcontext_loc))
84 {
85 struct sigcontext *sc = (struct sigcontext *) c->sigcontext_loc;
mostang.com!davidm678d3202003-02-08 10:10:59 +000086# define PR_SCRATCH 0xffc0 /* p6-p15 are scratch */
87# define PR_PRESERVED (~(PR_SCRATCH | 1))
mostang.com!davidmea0a71a2003-01-21 17:41:20 +000088
89 /* We're returning to a frame that was (either directly or
90 indirectly) interrupted by a signal. We have to restore
91 _both_ "preserved" and "scratch" registers. That doesn't
92 leave us any registers to work with, and the only way we can
93 achieve this is by doing a sigreturn().
94
95 Note: it might be tempting to think that we don't have to
96 restore the scratch registers when returning to a frame that
97 was indirectly interrupted by a signal. However, that is not
98 safe because that frame and its descendants could have been
99 using a special convention that stores "preserved" state in
mostang.com!davidm678d3202003-02-08 10:10:59 +0000100 scratch registers. For example, the Linux fsyscall
101 convention does this with r11 (to save ar.pfs) and b6 (to
102 save "rp"). */
mostang.com!davidmea0a71a2003-01-21 17:41:20 +0000103
mostang.com!davidm678d3202003-02-08 10:10:59 +0000104 sc->sc_gr[12] = c->psp;
105 c->psp = (c->sigcontext_loc - c->sigcontext_off);
106
107 sof = (c->cfm & 0x7f);
mostang.com!davidm02c8c0c2003-02-14 06:25:36 +0000108 rbs_cover_and_flush (c, sof);
mostang.com!davidm678d3202003-02-08 10:10:59 +0000109
110 sc->sc_ip = c->ip;
111 sc->sc_cfm = c->cfm & (((unw_word_t) 1 << 38) - 1);
112 sc->sc_pr = (c->pr & ~PR_SCRATCH) | (sc->sc_pr & ~PR_PRESERVED);
113 if ((ret = ia64_get (c, c->pfs_loc, &sc->sc_ar_pfs)) < 0
114 || (ret = ia64_get (c, c->fpsr_loc, &sc->sc_ar_fpsr)) < 0
115 || (ret = ia64_get (c, c->unat_loc, &sc->sc_ar_unat)) < 0)
116 return ret;
117
118 sc->sc_gr[1] = c->pi.gp;
119 if (c->eh_valid_mask & 0x1) sc->sc_gr[15] = c->eh_args[0];
120 if (c->eh_valid_mask & 0x2) sc->sc_gr[16] = c->eh_args[1];
121 if (c->eh_valid_mask & 0x4) sc->sc_gr[17] = c->eh_args[2];
122 if (c->eh_valid_mask & 0x8) sc->sc_gr[18] = c->eh_args[3];
mostang.com!davidmea0a71a2003-01-21 17:41:20 +0000123 }
124 else
125 {
mostang.com!davidm678d3202003-02-08 10:10:59 +0000126 /* Account for the fact that _Uia64_install_context() will
127 return via br.ret, which will decrement bsp by size-of-locals. */
128 if ((ret = ia64_get (c, c->pfs_loc, &pfs)) < 0)
129 return ret;
130 sol = (pfs >> 7) & 0x7f;
mostang.com!davidm02c8c0c2003-02-14 06:25:36 +0000131 rbs_cover_and_flush (c, sol);
mostang.com!davidm678d3202003-02-08 10:10:59 +0000132
133 extra.r1 = c->pi.gp;
134 extra.r15 = c->eh_args[0];
135 extra.r16 = c->eh_args[1];
136 extra.r17 = c->eh_args[2];
137 extra.r18 = c->eh_args[3];
mostang.com!davidmea0a71a2003-01-21 17:41:20 +0000138 }
mostang.com!davidm02c8c0c2003-02-14 06:25:36 +0000139 _Uia64_install_context (c, pri_unat, (unw_word_t *) &extra);
mostang.com!davidm997f0252002-12-19 07:16:50 +0000140}
141
142#endif /* !UNW_REMOTE_ONLY */
143
mostang.com!davidm678d3202003-02-08 10:10:59 +0000144#ifndef UNW_LOCAL_ONLY
145
146static inline int
147remote_install_cursor (struct cursor *c)
148{
149 printf ("%s: XXX implement me!\n", __FUNCTION__);
150 return -1;
151}
152
153#endif
154
mostang.com!davidm997f0252002-12-19 07:16:50 +0000155int
156unw_resume (unw_cursor_t *cursor)
157{
158 struct cursor *c = (struct cursor *) cursor;
159
160#ifdef UNW_LOCAL_ONLY
161 return ia64_local_resume (c->as, cursor, c->as_arg);
162#else
mostang.com!davidm678d3202003-02-08 10:10:59 +0000163 {
164 int ret;
165
166 if ((ret = remote_install_cursor (c)) < 0)
167 return ret;
168 return (*c->as->acc.resume) (c->as, cursor, c->as_arg);
169 }
mostang.com!davidm997f0252002-12-19 07:16:50 +0000170#endif
171}