1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2001-2005 Hewlett-Packard Co
3	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#ifndef unwind_i_h
27#define unwind_i_h
28
29#include <string.h>
30#include <inttypes.h>
31
32#include <libunwind-ia64.h>
33
34#include "rse.h"
35
36#include "libunwind_i.h"
37
38#define IA64_UNW_VER(x)		    ((x) >> 48)
39#define IA64_UNW_FLAG_MASK	    ((unw_word_t) 0x0000ffff00000000ULL)
40#define IA64_UNW_FLAG_OSMASK	    ((unw_word_t) 0x0000f00000000000ULL)
41#define IA64_UNW_FLAG_EHANDLER(x)   ((x) & (unw_word_t) 0x0000000100000000ULL)
42#define IA64_UNW_FLAG_UHANDLER(x)   ((x) & (unw_word_t) 0x0000000200000000ULL)
43#define IA64_UNW_LENGTH(x)	    ((x) & (unw_word_t) 0x00000000ffffffffULL)
44
45#ifdef MIN
46# undef MIN
47#endif
48#define MIN(a,b)	((a) < (b) ? (a) : (b))
49
50#if !defined(HAVE_SYS_UC_ACCESS_H) && !defined(UNW_REMOTE_ONLY)
51
52static ALWAYS_INLINE void *
53inlined_uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr)
54{
55  unw_word_t reg_addr;
56  void *addr;
57
58  switch (reg)
59    {
60    case UNW_IA64_GR + 0:	addr = &unw.read_only.r0; break;
61    case UNW_IA64_NAT + 0:	addr = &unw.read_only.r0; break;
62    case UNW_IA64_FR + 0:	addr = &unw.read_only.f0; break;
63    case UNW_IA64_FR + 1:
64      if (__BYTE_ORDER == __BIG_ENDIAN)
65	addr = &unw.read_only.f1_be;
66      else
67	addr = &unw.read_only.f1_le;
68      break;
69    case UNW_IA64_IP:		addr = &uc->uc_mcontext.sc_br[0]; break;
70    case UNW_IA64_CFM:		addr = &uc->uc_mcontext.sc_ar_pfs; break;
71    case UNW_IA64_AR_RNAT:	addr = &uc->uc_mcontext.sc_ar_rnat; break;
72    case UNW_IA64_AR_UNAT:	addr = &uc->uc_mcontext.sc_ar_unat; break;
73    case UNW_IA64_AR_LC:	addr = &uc->uc_mcontext.sc_ar_lc; break;
74    case UNW_IA64_AR_FPSR:	addr = &uc->uc_mcontext.sc_ar_fpsr; break;
75    case UNW_IA64_PR:		addr = &uc->uc_mcontext.sc_pr; break;
76    case UNW_IA64_AR_BSPSTORE:	addr = &uc->uc_mcontext.sc_ar_bsp; break;
77
78    case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7:
79    case UNW_IA64_GR + 12:
80      addr = &uc->uc_mcontext.sc_gr[reg - UNW_IA64_GR];
81      break;
82
83    case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7:
84    case UNW_IA64_NAT + 12:
85      addr = &uc->uc_mcontext.sc_nat;
86      reg_addr = (unw_word_t) &uc->uc_mcontext.sc_gr[reg - UNW_IA64_NAT];
87      *nat_bitnr = reg - UNW_IA64_NAT;
88      break;
89
90    case UNW_IA64_BR + 1 ... UNW_IA64_BR + 5:
91      addr = &uc->uc_mcontext.sc_br[reg - UNW_IA64_BR];
92      break;
93
94    case UNW_IA64_FR+ 2 ... UNW_IA64_FR+ 5:
95    case UNW_IA64_FR+16 ... UNW_IA64_FR+31:
96      addr = &uc->uc_mcontext.sc_fr[reg - UNW_IA64_FR];
97      break;
98
99    default:
100      addr = NULL;
101    }
102  return addr;
103}
104
105static inline void *
106uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr)
107{
108  if (__builtin_constant_p (reg))
109    return inlined_uc_addr (uc, reg, nat_bitnr);
110  else
111    return tdep_uc_addr (uc, reg, nat_bitnr);
112}
113
114/* Return TRUE if ADDR points inside unw.read_only_reg.  */
115
116static inline long
117ia64_read_only_reg (void *addr)
118{
119  return ((unsigned long) ((char *) addr - (char *) &unw.read_only)
120	  < sizeof (unw.read_only));
121}
122
123#endif /* !defined(HAVE_SYS_UC_ACCESS_H) && !defined(UNW_REMOTE_ONLY) */
124
125/* Bits 0 and 1 of a location are used to encode its type:
126	bit 0: set if location uses floating-point format.
127	bit 1: set if location is a NaT bit on memory stack.  */
128
129#define IA64_LOC_TYPE_FP		(1 << 0)
130#define IA64_LOC_TYPE_MEMSTK_NAT	(1 << 1)
131
132#ifdef UNW_LOCAL_ONLY
133#define IA64_LOC_REG(r,t)	(((r) << 2) | (t))
134#define IA64_LOC_ADDR(a,t)	(((a) & ~0x3) | (t))
135#define IA64_LOC_UC_ADDR(a,t)	IA64_LOC_ADDR(a, t)
136#define IA64_NULL_LOC		(0)
137
138#define IA64_GET_REG(l)		((l) >> 2)
139#define IA64_GET_ADDR(l)	((l) & ~0x3)
140#define IA64_IS_NULL_LOC(l)	((l) == 0)
141#define IA64_IS_FP_LOC(l)	(((l) & IA64_LOC_TYPE_FP) != 0)
142#define IA64_IS_MEMSTK_NAT(l)	(((l) & IA64_LOC_TYPE_MEMSTK_NAT) != 0)
143#define IA64_IS_REG_LOC(l)	0
144#define IA64_IS_UC_LOC(l)	0
145
146#define IA64_REG_LOC(c,r)	((unw_word_t) uc_addr((c)->as_arg, r, NULL))
147#define IA64_REG_NAT_LOC(c,r,n)	((unw_word_t) uc_addr((c)->as_arg, r, n))
148#define IA64_FPREG_LOC(c,r)						 \
149	((unw_word_t) uc_addr((c)->as_arg, (r), NULL) | IA64_LOC_TYPE_FP)
150
151# define ia64_find_proc_info(c,ip,n)					\
152	tdep_find_proc_info(unw_local_addr_space, (ip), &(c)->pi, (n),	\
153			    (c)->as_arg)
154# define ia64_put_unwind_info(c, pi)	do { ; } while (0)
155
156/* Note: the register accessors (ia64_{get,set}{,fp}()) must check for
157   NULL locations because uc_addr() returns NULL for unsaved
158   registers.  */
159
160static inline int
161ia64_getfp (struct cursor *c, unw_word_t loc, unw_fpreg_t *val)
162{
163  if (IA64_IS_NULL_LOC (loc))
164    {
165      Debug (16, "access to unsaved register\n");
166      return -UNW_EBADREG;
167    }
168  *val = *(unw_fpreg_t *) IA64_GET_ADDR (loc);
169  return 0;
170}
171
172static inline int
173ia64_putfp (struct cursor *c, unw_word_t loc, unw_fpreg_t val)
174{
175  unw_fpreg_t *addr = (unw_fpreg_t *) IA64_GET_ADDR (loc);
176
177  if (IA64_IS_NULL_LOC (loc))
178    {
179      Debug (16, "access to unsaved register\n");
180      return -UNW_EBADREG;
181    }
182  else if (ia64_read_only_reg (addr))
183    {
184      Debug (16, "attempt to read-only register\n");
185      return -UNW_EREADONLYREG;
186    }
187  *addr = val;
188  return 0;
189}
190
191static inline int
192ia64_get (struct cursor *c, unw_word_t loc, unw_word_t *val)
193{
194  if (IA64_IS_NULL_LOC (loc))
195    {
196      Debug (16, "access to unsaved register\n");
197      return -UNW_EBADREG;
198    }
199  *val = *(unw_word_t *) IA64_GET_ADDR (loc);
200  return 0;
201}
202
203static inline int
204ia64_put (struct cursor *c, unw_word_t loc, unw_word_t val)
205{
206  unw_word_t *addr = (unw_word_t *) IA64_GET_ADDR (loc);
207
208  if (IA64_IS_NULL_LOC (loc))
209    {
210      Debug (16, "access to unsaved register\n");
211      return -UNW_EBADREG;
212    }
213  else if (ia64_read_only_reg (addr))
214    {
215      Debug (16, "attempt to read-only register\n");
216      return -UNW_EREADONLYREG;
217    }
218  *addr = val;
219  return 0;
220}
221
222#else /* !UNW_LOCAL_ONLY */
223
224/* Bits 0 and 1 of the second word (w1) of a location are used
225   to further distinguish what location we're dealing with:
226
227   	bit 0: set if the location is a register
228	bit 1: set of the location is accessed via uc_access(3)  */
229#define IA64_LOC_TYPE_REG	(1 << 0)
230#define IA64_LOC_TYPE_UC	(1 << 1)
231
232#define IA64_LOC_REG(r,t)	((ia64_loc_t) { ((r) << 2) | (t),	\
233						IA64_LOC_TYPE_REG })
234#define IA64_LOC_ADDR(a,t)	((ia64_loc_t) { ((a) & ~0x3) | (t), 0 })
235#define IA64_LOC_UC_ADDR(a,t)	((ia64_loc_t) { ((a) & ~0x3) | (t),	\
236						IA64_LOC_TYPE_UC })
237#define IA64_LOC_UC_REG(r,a)	((ia64_loc_t) { ((r) << 2),		 \
238						((a) | IA64_LOC_TYPE_REG \
239					         | IA64_LOC_TYPE_UC) })
240#define IA64_NULL_LOC		((ia64_loc_t) { 0, 0 })
241
242#define IA64_GET_REG(l)		((l).w0 >> 2)
243#define IA64_GET_ADDR(l)	((l).w0 & ~0x3)
244#define IA64_GET_AUX_ADDR(l)	((l).w1 & ~0x3)
245#define IA64_IS_NULL_LOC(l)	(((l).w0 | (l).w1) == 0)
246#define IA64_IS_FP_LOC(l)	(((l).w0 & IA64_LOC_TYPE_FP) != 0)
247#define IA64_IS_MEMSTK_NAT(l)	(((l).w0 & IA64_LOC_TYPE_MEMSTK_NAT) != 0)
248#define IA64_IS_REG_LOC(l)	(((l).w1 & IA64_LOC_TYPE_REG) != 0)
249#define IA64_IS_UC_LOC(l)	(((l).w1 & IA64_LOC_TYPE_UC) != 0)
250
251#define IA64_REG_LOC(c,r)	IA64_LOC_REG ((r), 0)
252#define IA64_REG_NAT_LOC(c,r,n)	IA64_LOC_REG ((r), 0)
253#define IA64_FPREG_LOC(c,r)	IA64_LOC_REG ((r), IA64_LOC_TYPE_FP)
254
255# define ia64_find_proc_info(c,ip,n)					\
256	(*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n),	\
257				       (c)->as_arg)
258# define ia64_put_unwind_info(c,pi)					\
259	(*(c)->as->acc.put_unwind_info)((c)->as, (pi), (c)->as_arg)
260
261#define ia64_uc_access_reg	UNW_OBJ(uc_access_reg)
262#define ia64_uc_access_fpreg	UNW_OBJ(uc_access_fpreg)
263
264extern int ia64_uc_access_reg (struct cursor *c, ia64_loc_t loc,
265			       unw_word_t *valp, int write);
266extern int ia64_uc_access_fpreg (struct cursor *c, ia64_loc_t loc,
267				 unw_fpreg_t *valp, int write);
268
269static inline int
270ia64_getfp (struct cursor *c, ia64_loc_t loc, unw_fpreg_t *val)
271{
272  unw_word_t addr;
273  int ret;
274
275  if (IA64_IS_NULL_LOC (loc))
276    {
277      Debug (16, "access to unsaved register\n");
278      return -UNW_EBADREG;
279    }
280
281  if (IA64_IS_UC_LOC (loc))
282    return ia64_uc_access_fpreg (c, loc, val, 0);
283
284  if (IA64_IS_REG_LOC (loc))
285    return (*c->as->acc.access_fpreg) (c->as, IA64_GET_REG (loc),
286				       val, 0, c->as_arg);
287
288  addr = IA64_GET_ADDR (loc);
289  ret = (*c->as->acc.access_mem) (c->as, addr + 0, &val->raw.bits[0], 0,
290				  c->as_arg);
291  if (ret < 0)
292    return ret;
293
294  return (*c->as->acc.access_mem) (c->as, addr + 8, &val->raw.bits[1], 0,
295				   c->as_arg);
296}
297
298static inline int
299ia64_putfp (struct cursor *c, ia64_loc_t loc, unw_fpreg_t val)
300{
301  unw_word_t addr;
302  int ret;
303
304  if (IA64_IS_NULL_LOC (loc))
305    {
306      Debug (16, "access to unsaved register\n");
307      return -UNW_EBADREG;
308    }
309
310  if (IA64_IS_UC_LOC (loc))
311    return ia64_uc_access_fpreg (c, loc, &val, 1);
312
313  if (IA64_IS_REG_LOC (loc))
314    return (*c->as->acc.access_fpreg) (c->as, IA64_GET_REG (loc), &val, 1,
315				       c->as_arg);
316
317  addr = IA64_GET_ADDR (loc);
318  ret = (*c->as->acc.access_mem) (c->as, addr + 0, &val.raw.bits[0], 1,
319				  c->as_arg);
320  if (ret < 0)
321    return ret;
322
323  return (*c->as->acc.access_mem) (c->as, addr + 8, &val.raw.bits[1], 1,
324				   c->as_arg);
325}
326
327/* Get the 64 data bits from location LOC.  If bit 0 is cleared, LOC
328   is a memory address, otherwise it is a register number.  If the
329   register is a floating-point register, the 64 bits are read from
330   the significand bits.  */
331
332static inline int
333ia64_get (struct cursor *c, ia64_loc_t loc, unw_word_t *val)
334{
335  if (IA64_IS_NULL_LOC (loc))
336    {
337      Debug (16, "access to unsaved register\n");
338      return -UNW_EBADREG;
339    }
340
341  if (IA64_IS_FP_LOC (loc))
342    {
343      unw_fpreg_t tmp;
344      int ret;
345
346      ret = ia64_getfp (c, loc, &tmp);
347      if (ret < 0)
348	return ret;
349
350      if (c->as->big_endian)
351	*val = tmp.raw.bits[1];
352      else
353	*val = tmp.raw.bits[0];
354      return 0;
355    }
356
357  if (IA64_IS_UC_LOC (loc))
358    return ia64_uc_access_reg (c, loc, val, 0);
359
360  if (IA64_IS_REG_LOC (loc))
361    return (*c->as->acc.access_reg)(c->as, IA64_GET_REG (loc), val, 0,
362				    c->as_arg);
363  else
364    return (*c->as->acc.access_mem)(c->as, IA64_GET_ADDR (loc), val, 0,
365				    c->as_arg);
366}
367
368static inline int
369ia64_put (struct cursor *c, ia64_loc_t loc, unw_word_t val)
370{
371  if (IA64_IS_NULL_LOC (loc))
372    {
373      Debug (16, "access to unsaved register\n");
374      return -UNW_EBADREG;
375    }
376
377  if (IA64_IS_FP_LOC (loc))
378    {
379      unw_fpreg_t tmp;
380
381      memset (&tmp, 0, sizeof (tmp));
382      if (c->as->big_endian)
383	tmp.raw.bits[1] = val;
384      else
385	tmp.raw.bits[0] = val;
386      return ia64_putfp (c, loc, tmp);
387    }
388
389  if (IA64_IS_UC_LOC (loc))
390    return ia64_uc_access_reg (c, loc, &val, 1);
391
392  if (IA64_IS_REG_LOC (loc))
393    return (*c->as->acc.access_reg)(c->as, IA64_GET_REG (loc), &val, 1,
394				    c->as_arg);
395  else
396    return (*c->as->acc.access_mem)(c->as, IA64_GET_ADDR (loc), &val, 1,
397				    c->as_arg);
398}
399
400#endif /* !UNW_LOCAL_ONLY */
401
402struct ia64_unwind_block
403  {
404    unw_word_t header;
405    unw_word_t desc[0];			/* unwind descriptors */
406
407    /* Personality routine and language-specific data follow behind
408       descriptors.  */
409  };
410
411enum ia64_where
412  {
413    IA64_WHERE_NONE,	/* register isn't saved at all */
414    IA64_WHERE_GR,	/* register is saved in a general register */
415    IA64_WHERE_FR,	/* register is saved in a floating-point register */
416    IA64_WHERE_BR,	/* register is saved in a branch register */
417    IA64_WHERE_SPREL,	/* register is saved on memstack (sp-relative) */
418    IA64_WHERE_PSPREL,	/* register is saved on memstack (psp-relative) */
419
420    /* At the end of each prologue these locations get resolved to
421       IA64_WHERE_PSPREL and IA64_WHERE_GR, respectively:  */
422
423    IA64_WHERE_SPILL_HOME, /* register is saved in its spill home */
424    IA64_WHERE_GR_SAVE	/* register is saved in next general register */
425  };
426
427#define IA64_WHEN_NEVER	0x7fffffff
428
429struct ia64_reg_info
430  {
431    unw_word_t val;		/* save location: register number or offset */
432    enum ia64_where where;	/* where the register gets saved */
433    int when;			/* when the register gets saved */
434  };
435
436struct ia64_labeled_state;	/* opaque structure */
437
438struct ia64_reg_state
439  {
440    struct ia64_reg_state *next;    /* next (outer) element on state stack */
441    struct ia64_reg_info reg[IA64_NUM_PREGS];	/* register save locations */
442  };
443
444struct ia64_state_record
445  {
446    unsigned int first_region : 1;	/* is this the first region? */
447    unsigned int done : 1;		/* are we done scanning descriptors? */
448    unsigned int any_spills : 1;	/* got any register spills? */
449    unsigned int in_body : 1;		/* are we inside prologue or body? */
450    uint8_t *imask;		/* imask of spill_mask record or NULL */
451    uint16_t abi_marker;
452
453    unw_word_t pr_val;		/* predicate values */
454    unw_word_t pr_mask;		/* predicate mask */
455
456    long spill_offset;		/* psp-relative offset for spill base */
457    int region_start;
458    int region_len;
459    int when_sp_restored;
460    int epilogue_count;
461    int when_target;
462
463    uint8_t gr_save_loc;	/* next save register */
464    uint8_t return_link_reg;	/* branch register used as return pointer */
465
466    struct ia64_labeled_state *labeled_states;
467    struct ia64_reg_state curr;
468  };
469
470struct ia64_labeled_state
471  {
472    struct ia64_labeled_state *next;	/* next label (or NULL) */
473    unsigned long label;			/* label for this state */
474    struct ia64_reg_state saved_state;
475  };
476
477/* Convenience macros: */
478#define ia64_make_proc_info		UNW_OBJ(make_proc_info)
479#define ia64_fetch_proc_info		UNW_OBJ(fetch_proc_info)
480#define ia64_create_state_record	UNW_OBJ(create_state_record)
481#define ia64_free_state_record		UNW_OBJ(free_state_record)
482#define ia64_find_save_locs		UNW_OBJ(find_save_locs)
483#define ia64_validate_cache		UNW_OBJ(ia64_validate_cache)
484#define ia64_local_validate_cache	UNW_OBJ(ia64_local_validate_cache)
485#define ia64_per_thread_cache		UNW_OBJ(per_thread_cache)
486#define ia64_scratch_loc		UNW_OBJ(scratch_loc)
487#define ia64_local_resume		UNW_OBJ(local_resume)
488#define ia64_local_addr_space_init	UNW_OBJ(local_addr_space_init)
489#define ia64_strloc			UNW_OBJ(strloc)
490#define ia64_install_cursor		UNW_OBJ(install_cursor)
491#define rbs_switch			UNW_OBJ(rbs_switch)
492#define rbs_find_stacked		UNW_OBJ(rbs_find_stacked)
493
494extern int ia64_make_proc_info (struct cursor *c);
495extern int ia64_fetch_proc_info (struct cursor *c, unw_word_t ip,
496				 int need_unwind_info);
497/* The proc-info must be valid for IP before this routine can be
498   called:  */
499extern int ia64_create_state_record (struct cursor *c,
500				     struct ia64_state_record *sr);
501extern int ia64_free_state_record (struct ia64_state_record *sr);
502extern int ia64_find_save_locs (struct cursor *c);
503extern void ia64_validate_cache (unw_addr_space_t as, void *arg);
504extern int ia64_local_validate_cache (unw_addr_space_t as, void *arg);
505extern void ia64_local_addr_space_init (void);
506extern ia64_loc_t ia64_scratch_loc (struct cursor *c, unw_regnum_t reg,
507				    uint8_t *nat_bitnr);
508
509extern NORETURN void ia64_install_cursor (struct cursor *c,
510					  unw_word_t pri_unat,
511					  unw_word_t *extra,
512					  unw_word_t bspstore,
513					  unw_word_t dirty_size,
514					  unw_word_t *dirty_partition,
515					  unw_word_t dirty_rnat);
516extern int ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor,
517			      void *arg);
518extern int rbs_switch (struct cursor *c,
519		       unw_word_t saved_bsp, unw_word_t saved_bspstore,
520		       ia64_loc_t saved_rnat_loc);
521extern int rbs_find_stacked (struct cursor *c, unw_word_t regs_to_skip,
522			     ia64_loc_t *locp, ia64_loc_t *rnat_locp);
523
524#ifndef UNW_REMOTE_ONLY
525# define NEED_RBS_COVER_AND_FLUSH
526# define rbs_cover_and_flush	UNW_OBJ(rbs_cover_and_flush)
527  extern int rbs_cover_and_flush (struct cursor *c, unw_word_t nregs,
528				  unw_word_t *dirty_partition,
529				  unw_word_t *dirty_rnat,
530				  unw_word_t *bspstore);
531#endif
532
533/* Warning: ia64_strloc() is for debugging only and it is NOT re-entrant! */
534extern const char *ia64_strloc (ia64_loc_t loc);
535
536/* Return true if the register-backing store is inside a ucontext_t
537   that needs to be accessed via uc_access(3).  */
538
539static inline int
540rbs_on_uc (struct rbs_area *rbs)
541{
542  return IA64_IS_UC_LOC (rbs->rnat_loc) && !IA64_IS_REG_LOC (rbs->rnat_loc);
543}
544
545/* Return true if BSP points to a word that's stored on register
546   backing-store RBS.  */
547static inline int
548rbs_contains (struct rbs_area *rbs, unw_word_t bsp)
549{
550  int result;
551
552  /* Caveat: this takes advantage of unsigned arithmetic.  The full
553     test is (bsp >= rbs->end - rbs->size) && (bsp < rbs->end).  We
554     take advantage of the fact that -n == ~n + 1.  */
555  result = bsp - rbs->end > ~rbs->size;
556  Debug (16, "0x%lx in [0x%lx-0x%lx) => %d\n",
557	 (long) bsp, (long) (rbs->end - rbs->size), (long) rbs->end, result);
558  return result;
559}
560
561static inline ia64_loc_t
562rbs_get_rnat_loc (struct rbs_area *rbs, unw_word_t bsp)
563{
564  unw_word_t rnat_addr = rse_rnat_addr (bsp);
565  ia64_loc_t rnat_loc;
566
567  if (rbs_contains (rbs, rnat_addr))
568    {
569      if (rbs_on_uc (rbs))
570	rnat_loc = IA64_LOC_UC_ADDR (rnat_addr, 0);
571      else
572	rnat_loc = IA64_LOC_ADDR (rnat_addr, 0);
573    }
574  else
575    rnat_loc = rbs->rnat_loc;
576  return rnat_loc;
577}
578
579static inline ia64_loc_t
580rbs_loc (struct rbs_area *rbs, unw_word_t bsp)
581{
582  if (rbs_on_uc (rbs))
583    return IA64_LOC_UC_ADDR (bsp, 0);
584  else
585    return IA64_LOC_ADDR (bsp, 0);
586}
587
588static inline int
589ia64_get_stacked (struct cursor *c, unw_word_t reg,
590		  ia64_loc_t *locp, ia64_loc_t *rnat_locp)
591{
592  struct rbs_area *rbs = c->rbs_area + c->rbs_curr;
593  unw_word_t addr, regs_to_skip = reg - 32;
594  int ret = 0;
595
596  assert (reg >= 32 && reg < 128);
597
598  addr = rse_skip_regs (c->bsp, regs_to_skip);
599  if (locp)
600    *locp = rbs_loc (rbs, addr);
601  if (rnat_locp)
602    *rnat_locp = rbs_get_rnat_loc (rbs, addr);
603
604  if (!rbs_contains (rbs, addr))
605    ret = rbs_find_stacked (c, regs_to_skip, locp, rnat_locp);
606  return ret;
607}
608
609/* The UNaT slot # calculation is identical to the one for RNaT slots,
610   but for readability/clarity, we don't want to use
611   ia64_rnat_slot_num() directly.  */
612#define ia64_unat_slot_num(addr)	rse_slot_num(addr)
613
614/* The following are helper macros which makes it easier for libunwind
615   to be used in the kernel.  They allow the kernel to optimize away
616   any unused code without littering everything with #ifdefs.  */
617#define ia64_is_big_endian(c)	((c)->as->big_endian)
618#define ia64_get_abi(c)		((c)->as->abi)
619#define ia64_set_abi(c, v)	((c)->as->abi = (v))
620#define ia64_get_abi_marker(c)	((c)->last_abi_marker)
621
622/* XXX should be in glibc: */
623#ifndef IA64_SC_FLAG_ONSTACK
624# define IA64_SC_FLAG_ONSTACK_BIT    0 /* running on signal stack? */
625# define IA64_SC_FLAG_IN_SYSCALL_BIT 1 /* did signal interrupt a syscall? */
626# define IA64_SC_FLAG_FPH_VALID_BIT  2 /* is state in f[32]-f[127] valid? */
627
628# define IA64_SC_FLAG_ONSTACK		(1 << IA64_SC_FLAG_ONSTACK_BIT)
629# define IA64_SC_FLAG_IN_SYSCALL	(1 << IA64_SC_FLAG_IN_SYSCALL_BIT)
630# define IA64_SC_FLAG_FPH_VALID		(1 << IA64_SC_FLAG_FPH_VALID_BIT)
631#endif
632
633#endif /* unwind_i_h */
634