Make UEFI boot-platform build again
[haiku.git] / src / libs / libunwind / ia64 / Grbs.c
blobe7c01fe219e9e5d4cba70f29ad7325d31dfd3303
1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2003-2005 Hewlett-Packard Co
3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
5 This file is part of libunwind.
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
26 /* Logically, we like to think of the stack as a contiguous region of
27 memory. Unfortunately, this logical view doesn't work for the
28 register backing store, because the RSE is an asynchronous engine and
29 because UNIX/Linux allow for stack-switching via sigaltstack(2).
30 Specifically, this means that any given stacked register may or may
31 not be backed up by memory in the current stack. If not, then the
32 backing memory may be found in any of the "more inner" (younger)
33 stacks. The routines in this file help manage the discontiguous
34 nature of the register backing store. The routines are completely
35 independent of UNIX/Linux, but each stack frame that switches the
36 backing store is expected to reserve 4 words for use by libunwind. For
37 example, in the Linux sigcontext, sc_fr[0] and sc_fr[1] serve this
38 purpose. */
40 #include "unwind_i.h"
42 #if UNW_DEBUG
44 HIDDEN const char *
45 ia64_strloc (ia64_loc_t loc)
47 static char buf[128];
49 if (IA64_IS_NULL_LOC (loc))
50 return "<null>";
52 buf[0] = '\0';
54 if (IA64_IS_MEMSTK_NAT (loc))
55 strcat (buf, "memstk_nat(");
56 if (IA64_IS_UC_LOC (loc))
57 strcat (buf, "uc(");
58 if (IA64_IS_FP_LOC (loc))
59 strcat (buf, "fp(");
61 if (IA64_IS_REG_LOC (loc))
62 sprintf (buf + strlen (buf), "%s", unw_regname (IA64_GET_REG (loc)));
63 else
64 sprintf (buf + strlen (buf), "0x%llx",
65 (unsigned long long) IA64_GET_ADDR (loc));
67 if (IA64_IS_FP_LOC (loc))
68 strcat (buf, ")");
69 if (IA64_IS_UC_LOC (loc))
70 strcat (buf, ")");
71 if (IA64_IS_MEMSTK_NAT (loc))
72 strcat (buf, ")");
74 return buf;
77 #endif /* UNW_DEBUG */
79 HIDDEN int
80 rbs_switch (struct cursor *c,
81 unw_word_t saved_bsp, unw_word_t saved_bspstore,
82 ia64_loc_t saved_rnat_loc)
84 struct rbs_area *rbs = &c->rbs_area[c->rbs_curr];
85 unw_word_t lo, ndirty, rbs_base;
86 int ret;
88 Debug (10, "(left=%u, curr=%u)\n", c->rbs_left_edge, c->rbs_curr);
90 /* Calculate address "lo" at which the backing store starts: */
91 ndirty = rse_num_regs (saved_bspstore, saved_bsp);
92 lo = rse_skip_regs (c->bsp, -ndirty);
94 rbs->size = (rbs->end - lo);
96 /* If the previously-recorded rbs-area is empty we don't need to
97 track it and we can simply overwrite it... */
98 if (rbs->size)
100 Debug (10, "inner=[0x%lx-0x%lx)\n",
101 (long) (rbs->end - rbs->size), (long) rbs->end);
103 c->rbs_curr = (c->rbs_curr + 1) % ARRAY_SIZE (c->rbs_area);
104 rbs = c->rbs_area + c->rbs_curr;
106 if (c->rbs_curr == c->rbs_left_edge)
107 c->rbs_left_edge = (c->rbs_left_edge + 1) % ARRAY_SIZE (c->rbs_area);
110 if ((ret = rbs_get_base (c, saved_bspstore, &rbs_base)) < 0)
111 return ret;
113 rbs->end = saved_bspstore;
114 rbs->size = saved_bspstore - rbs_base;
115 rbs->rnat_loc = saved_rnat_loc;
117 c->bsp = saved_bsp;
119 Debug (10, "outer=[0x%llx-0x%llx), rnat@%s\n", (long long) rbs_base,
120 (long long) rbs->end, ia64_strloc (rbs->rnat_loc));
121 return 0;
124 HIDDEN int
125 rbs_find_stacked (struct cursor *c, unw_word_t regs_to_skip,
126 ia64_loc_t *locp, ia64_loc_t *rnat_locp)
128 unw_word_t nregs, bsp = c->bsp, curr = c->rbs_curr, n;
129 unw_word_t left_edge = c->rbs_left_edge;
130 #if UNW_DEBUG
131 int reg = 32 + regs_to_skip;
132 #endif
134 while (!rbs_contains (&c->rbs_area[curr], bsp))
136 if (curr == left_edge)
138 Debug (1, "could not find register r%d!\n", reg);
139 return -UNW_EBADREG;
142 n = rse_num_regs (c->rbs_area[curr].end, bsp);
143 curr = (curr + ARRAY_SIZE (c->rbs_area) - 1) % ARRAY_SIZE (c->rbs_area);
144 bsp = rse_skip_regs (c->rbs_area[curr].end - c->rbs_area[curr].size, n);
147 while (1)
149 nregs = rse_num_regs (bsp, c->rbs_area[curr].end);
151 if (regs_to_skip < nregs)
153 /* found it: */
154 unw_word_t addr;
156 addr = rse_skip_regs (bsp, regs_to_skip);
157 if (locp)
158 *locp = rbs_loc (c->rbs_area + curr, addr);
159 if (rnat_locp)
160 *rnat_locp = rbs_get_rnat_loc (c->rbs_area + curr, addr);
161 return 0;
164 if (curr == left_edge)
166 Debug (1, "could not find register r%d!\n", reg);
167 return -UNW_EBADREG;
170 regs_to_skip -= nregs;
172 curr = (curr + ARRAY_SIZE (c->rbs_area) - 1) % ARRAY_SIZE (c->rbs_area);
173 bsp = c->rbs_area[curr].end - c->rbs_area[curr].size;
177 #ifdef NEED_RBS_COVER_AND_FLUSH
179 static inline int
180 get_rnat (struct cursor *c, struct rbs_area *rbs, unw_word_t bsp,
181 unw_word_t *__restrict rnatp)
183 ia64_loc_t rnat_locp = rbs_get_rnat_loc (rbs, bsp);
185 return ia64_get (c, rnat_locp, rnatp);
188 /* Simulate the effect of "cover" followed by a "flushrs" for the
189 target-frame. However, since the target-frame's backing store
190 may not have space for the registers that got spilled onto other
191 rbs-areas, we save those registers to DIRTY_PARTITION where
192 we can then load them via a single "loadrs".
194 This function returns the size of the dirty-partition that was
195 created or a negative error-code in case of error.
197 Note: This does not modify the rbs_area[] structure in any way. */
198 HIDDEN int
199 rbs_cover_and_flush (struct cursor *c, unw_word_t nregs,
200 unw_word_t *dirty_partition, unw_word_t *dirty_rnat,
201 unw_word_t *bspstore)
203 unw_word_t n, src_mask, dst_mask, bsp, *dst, src_rnat, dst_rnat = 0;
204 unw_word_t curr = c->rbs_curr, left_edge = c->rbs_left_edge;
205 struct rbs_area *rbs = c->rbs_area + curr;
206 int ret;
208 bsp = c->bsp;
209 c->bsp = rse_skip_regs (bsp, nregs);
211 if (likely (rbs_contains (rbs, bsp)))
213 /* at least _some_ registers are on rbs... */
214 n = rse_num_regs (bsp, rbs->end);
215 if (likely (n >= nregs))
217 /* common case #1: all registers are on current rbs... */
218 /* got lucky: _all_ registers are on rbs... */
219 ia64_loc_t rnat_loc = rbs_get_rnat_loc (rbs, c->bsp);
221 *bspstore = c->bsp;
223 if (IA64_IS_REG_LOC (rnat_loc))
225 unw_word_t rnat_addr = (unw_word_t)
226 tdep_uc_addr (c->as_arg, UNW_IA64_AR_RNAT, NULL);
227 rnat_loc = IA64_LOC_ADDR (rnat_addr, 0);
229 c->loc[IA64_REG_RNAT] = rnat_loc;
230 return 0; /* all done */
232 nregs -= n; /* account for registers already on the rbs */
234 assert (rse_skip_regs (c->bsp, -nregs) == rse_skip_regs (rbs->end, 0));
236 else
237 /* Earlier frames also didn't get spilled; need to "loadrs" those,
238 too... */
239 nregs += rse_num_regs (rbs->end, bsp);
241 /* OK, we need to copy NREGS registers to the dirty partition. */
243 *bspstore = bsp = rbs->end;
244 c->loc[IA64_REG_RNAT] = rbs->rnat_loc;
245 assert (!IA64_IS_REG_LOC (rbs->rnat_loc));
247 dst = dirty_partition;
249 while (nregs > 0)
251 if (unlikely (!rbs_contains (rbs, bsp)))
253 /* switch to next non-empty rbs-area: */
256 if (curr == left_edge)
258 Debug (0, "rbs-underflow while flushing %lu regs, "
259 "bsp=0x%lx, dst=0x%p\n", (unsigned long) nregs,
260 (unsigned long) bsp, dst);
261 return -UNW_EBADREG;
264 assert (rse_num_regs (rbs->end, bsp) == 0);
266 curr = (curr + ARRAY_SIZE (c->rbs_area) - 1)
267 % ARRAY_SIZE (c->rbs_area);
268 rbs = c->rbs_area + curr;
269 bsp = rbs->end - rbs->size;
271 while (rbs->size == 0);
273 if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0)
274 return ret;
277 if (unlikely (rse_is_rnat_slot (bsp)))
279 bsp += 8;
280 if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0)
281 return ret;
283 if (unlikely (rse_is_rnat_slot ((unw_word_t) dst)))
285 *dst++ = dst_rnat;
286 dst_rnat = 0;
289 src_mask = ((unw_word_t) 1) << rse_slot_num (bsp);
290 dst_mask = ((unw_word_t) 1) << rse_slot_num ((unw_word_t) dst);
292 if (src_rnat & src_mask)
293 dst_rnat |= dst_mask;
294 else
295 dst_rnat &= ~dst_mask;
297 /* copy one slot: */
298 if ((ret = ia64_get (c, rbs_loc (rbs, bsp), dst)) < 0)
299 return ret;
301 /* advance to next slot: */
302 --nregs;
303 bsp += 8;
304 ++dst;
306 if (unlikely (rse_is_rnat_slot ((unw_word_t) dst)))
308 /* The LOADRS instruction loads "the N bytes below the current
309 BSP" but BSP can never point to an RNaT slot so if the last
310 destination word happens to be an RNaT slot, we need to write
311 that slot now. */
312 *dst++ = dst_rnat;
313 dst_rnat = 0;
315 *dirty_rnat = dst_rnat;
316 return (char *) dst - (char *) dirty_partition;
319 #endif /* !UNW_REMOTE_ONLY */