Imported Upstream version 1.1
[platform/upstream/libunwind.git] / src / ia64 / Grbs.c
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>
4
5 This file is part of libunwind.
6
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:
14
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17
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.  */
25
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.  */
39
40 #include "unwind_i.h"
41
42 #if UNW_DEBUG
43
44 HIDDEN const char *
45 ia64_strloc (ia64_loc_t loc)
46 {
47   static char buf[128];
48
49   if (IA64_IS_NULL_LOC (loc))
50     return "<null>";
51
52   buf[0] = '\0';
53
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(");
60
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));
66
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, ")");
73
74   return buf;
75 }
76
77 #endif /* UNW_DEBUG */
78
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)
83 {
84   struct rbs_area *rbs = &c->rbs_area[c->rbs_curr];
85   unw_word_t lo, ndirty, rbs_base;
86   int ret;
87
88   Debug (10, "(left=%u, curr=%u)\n", c->rbs_left_edge, c->rbs_curr);
89
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);
93
94   rbs->size = (rbs->end - lo);
95
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)
99     {
100       Debug (10, "inner=[0x%lx-0x%lx)\n",
101              (long) (rbs->end - rbs->size), (long) rbs->end);
102
103       c->rbs_curr = (c->rbs_curr + 1) % ARRAY_SIZE (c->rbs_area);
104       rbs = c->rbs_area + c->rbs_curr;
105
106       if (c->rbs_curr == c->rbs_left_edge)
107         c->rbs_left_edge = (c->rbs_left_edge + 1) % ARRAY_SIZE (c->rbs_area);
108     }
109
110   if ((ret = rbs_get_base (c, saved_bspstore, &rbs_base)) < 0)
111     return ret;
112
113   rbs->end = saved_bspstore;
114   rbs->size = saved_bspstore - rbs_base;
115   rbs->rnat_loc = saved_rnat_loc;
116
117   c->bsp = saved_bsp;
118
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;
122 }
123
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)
127 {
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
133
134   while (!rbs_contains (&c->rbs_area[curr], bsp))
135     {
136       if (curr == left_edge)
137         {
138           Debug (1, "could not find register r%d!\n", reg);
139           return -UNW_EBADREG;
140         }
141
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);
145     }
146
147   while (1)
148     {
149       nregs = rse_num_regs (bsp, c->rbs_area[curr].end);
150
151       if (regs_to_skip < nregs)
152         {
153           /* found it: */
154           unw_word_t addr;
155
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;
162         }
163
164       if (curr == left_edge)
165         {
166           Debug (1, "could not find register r%d!\n", reg);
167           return -UNW_EBADREG;
168         }
169
170       regs_to_skip -= nregs;
171
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;
174     }
175 }
176
177 #ifdef NEED_RBS_COVER_AND_FLUSH
178
179 static inline int
180 get_rnat (struct cursor *c, struct rbs_area *rbs, unw_word_t bsp,
181           unw_word_t *__restrict rnatp)
182 {
183   ia64_loc_t rnat_locp = rbs_get_rnat_loc (rbs, bsp);
184
185   return ia64_get (c, rnat_locp, rnatp);
186 }
187
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".
193
194    This function returns the size of the dirty-partition that was
195    created or a negative error-code in case of error.
196
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)
202 {
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;
207
208   bsp = c->bsp;
209   c->bsp = rse_skip_regs (bsp, nregs);
210
211   if (likely (rbs_contains (rbs, bsp)))
212     {
213       /* at least _some_ registers are on rbs... */
214       n = rse_num_regs (bsp, rbs->end);
215       if (likely (n >= nregs))
216         {
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);
220
221           *bspstore = c->bsp;
222
223           if (IA64_IS_REG_LOC (rnat_loc))
224             {
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);
228             }
229           c->loc[IA64_REG_RNAT] = rnat_loc;
230           return 0;     /* all done */
231         }
232       nregs -= n;       /* account for registers already on the rbs */
233
234       assert (rse_skip_regs (c->bsp, -nregs) == rse_skip_regs (rbs->end, 0));
235     }
236   else
237     /* Earlier frames also didn't get spilled; need to "loadrs" those,
238        too... */
239     nregs += rse_num_regs (rbs->end, bsp);
240
241   /* OK, we need to copy NREGS registers to the dirty partition.  */
242
243   *bspstore = bsp = rbs->end;
244   c->loc[IA64_REG_RNAT] = rbs->rnat_loc;
245   assert (!IA64_IS_REG_LOC (rbs->rnat_loc));
246
247   dst = dirty_partition;
248
249   while (nregs > 0)
250     {
251       if (unlikely (!rbs_contains (rbs, bsp)))
252         {
253           /* switch to next non-empty rbs-area: */
254           do
255             {
256               if (curr == left_edge)
257                 {
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;
262                 }
263
264               assert (rse_num_regs (rbs->end, bsp) == 0);
265
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;
270             }
271           while (rbs->size == 0);
272
273           if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0)
274             return ret;
275         }
276
277       if (unlikely (rse_is_rnat_slot (bsp)))
278         {
279           bsp += 8;
280           if ((ret = get_rnat (c, rbs, bsp, &src_rnat)) < 0)
281             return ret;
282         }
283       if (unlikely (rse_is_rnat_slot ((unw_word_t) dst)))
284         {
285           *dst++ = dst_rnat;
286           dst_rnat = 0;
287         }
288
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);
291
292       if (src_rnat & src_mask)
293         dst_rnat |= dst_mask;
294       else
295         dst_rnat &= ~dst_mask;
296
297       /* copy one slot: */
298       if ((ret = ia64_get (c, rbs_loc (rbs, bsp), dst)) < 0)
299         return ret;
300
301       /* advance to next slot: */
302       --nregs;
303       bsp += 8;
304       ++dst;
305     }
306   if (unlikely (rse_is_rnat_slot ((unw_word_t) dst)))
307     {
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;
314     }
315   *dirty_rnat = dst_rnat;
316   return (char *) dst - (char *) dirty_partition;
317 }
318
319 #endif /* !UNW_REMOTE_ONLY */