• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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