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 *
ia64_strloc(ia64_loc_t loc)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
rbs_switch(struct cursor * c,unw_word_t saved_bsp,unw_word_t saved_bspstore,ia64_loc_t saved_rnat_loc)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
rbs_find_stacked(struct cursor * c,unw_word_t regs_to_skip,ia64_loc_t * locp,ia64_loc_t * rnat_locp)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
get_rnat(struct cursor * c,struct rbs_area * rbs,unw_word_t bsp,unw_word_t * __restrict rnatp)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
rbs_cover_and_flush(struct cursor * c,unw_word_t nregs,unw_word_t * dirty_partition,unw_word_t * dirty_rnat,unw_word_t * bspstore)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 */
320