Home | History | Annotate | Download | only in ia64
      1 /* libunwind - a platform-independent unwind library
      2    Copyright (C) 2001-2004 Hewlett-Packard Co
      3 	Contributed by David Mosberger-Tang <davidm (at) 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 #include <stdlib.h>
     27 
     28 #include "unwind_i.h"
     29 #include "offsets.h"
     30 
     31 #ifndef UNW_REMOTE_ONLY
     32 
     33 static inline int
     34 local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
     35 {
     36 #if defined(__linux)
     37   unw_word_t dirty_partition[2048]; /* AR.RSC.LOADRS is a 14-bit field */
     38   unw_word_t val, sol, sof, pri_unat, n, pfs, bspstore, dirty_rnat;
     39   struct cursor *c = (struct cursor *) cursor;
     40   struct
     41     {
     42       unw_word_t r1;
     43       unw_word_t r4;
     44       unw_word_t r5;
     45       unw_word_t r6;
     46       unw_word_t r7;
     47       unw_word_t r15;
     48       unw_word_t r16;
     49       unw_word_t r17;
     50       unw_word_t r18;
     51     }
     52   extra;
     53   int ret, dirty_size;
     54 # define GET_NAT(n)						\
     55   do								\
     56     {								\
     57       ret = tdep_access_reg (c, UNW_IA64_NAT + (n), &val, 0);	\
     58       if (ret < 0)						\
     59 	return ret;						\
     60       if (val)							\
     61 	pri_unat |= (unw_word_t) 1 << n;			\
     62     }								\
     63   while (0)
     64 
     65   /* ensure c->pi is up-to-date: */
     66   if ((ret = ia64_make_proc_info (c)) < 0)
     67     return ret;
     68 
     69   /* Copy contents of r4-r7 into "extra", so that their values end up
     70      contiguous, so we can use a single (primary-) UNaT value.  */
     71   if ((ret = ia64_get (c, c->loc[IA64_REG_R4], &extra.r4)) < 0
     72       || (ret = ia64_get (c, c->loc[IA64_REG_R5], &extra.r5)) < 0
     73       || (ret = ia64_get (c, c->loc[IA64_REG_R6], &extra.r6)) < 0
     74       || (ret = ia64_get (c, c->loc[IA64_REG_R7], &extra.r7)) < 0)
     75     return ret;
     76 
     77   /* Form the primary UNaT value: */
     78   pri_unat = 0;
     79   GET_NAT (4); GET_NAT(5);
     80   GET_NAT (6); GET_NAT(7);
     81   n = (((uintptr_t) &extra.r4) / 8 - 4) % 64;
     82   pri_unat = (pri_unat << n) | (pri_unat >> (64 - n));
     83 
     84   if (unlikely (c->sigcontext_addr))
     85     {
     86       struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
     87 #     define PR_SCRATCH		0xffc0	/* p6-p15 are scratch */
     88 #     define PR_PRESERVED	(~(PR_SCRATCH | 1))
     89 
     90       /* We're returning to a frame that was (either directly or
     91 	 indirectly) interrupted by a signal.  We have to restore
     92 	 _both_ "preserved" and "scratch" registers.  That doesn't
     93 	 leave us any registers to work with, and the only way we can
     94 	 achieve this is by doing a sigreturn().
     95 
     96 	 Note: it might be tempting to think that we don't have to
     97 	 restore the scratch registers when returning to a frame that
     98 	 was indirectly interrupted by a signal.  However, that is not
     99 	 safe because that frame and its descendants could have been
    100 	 using a special convention that stores "preserved" state in
    101 	 scratch registers.  For example, the Linux fsyscall
    102 	 convention does this with r11 (to save ar.pfs) and b6 (to
    103 	 save "rp"). */
    104 
    105       sc->sc_gr[12] = c->psp;
    106       c->psp = c->sigcontext_addr - c->sigcontext_off;
    107 
    108       sof = (c->cfm & 0x7f);
    109       if ((dirty_size = rbs_cover_and_flush (c, sof, dirty_partition,
    110 					     &dirty_rnat, &bspstore)) < 0)
    111 	return dirty_size;
    112 
    113       /* Clear the "in-syscall" flag, because in general we won't be
    114 	 returning to the interruption-point and we need all registers
    115 	 restored.  */
    116       sc->sc_flags &= ~IA64_SC_FLAG_IN_SYSCALL;
    117       sc->sc_ip = c->ip;
    118       sc->sc_cfm = c->cfm & (((unw_word_t) 1 << 38) - 1);
    119       sc->sc_pr = (c->pr & ~PR_SCRATCH) | (sc->sc_pr & ~PR_PRESERVED);
    120       if ((ret = ia64_get (c, c->loc[IA64_REG_PFS], &sc->sc_ar_pfs)) < 0
    121 	  || (ret = ia64_get (c, c->loc[IA64_REG_FPSR], &sc->sc_ar_fpsr)) < 0
    122 	  || (ret = ia64_get (c, c->loc[IA64_REG_UNAT], &sc->sc_ar_unat)) < 0)
    123 	return ret;
    124 
    125       sc->sc_gr[1] = c->pi.gp;
    126       if (c->eh_valid_mask & 0x1) sc->sc_gr[15] = c->eh_args[0];
    127       if (c->eh_valid_mask & 0x2) sc->sc_gr[16] = c->eh_args[1];
    128       if (c->eh_valid_mask & 0x4) sc->sc_gr[17] = c->eh_args[2];
    129       if (c->eh_valid_mask & 0x8) sc->sc_gr[18] = c->eh_args[3];
    130       Debug (9, "sc: r15=%lx,r16=%lx,r17=%lx,r18=%lx\n",
    131 	     (long) sc->sc_gr[15], (long) sc->sc_gr[16],
    132 	     (long) sc->sc_gr[17], (long) sc->sc_gr[18]);
    133     }
    134   else
    135     {
    136       /* Account for the fact that _Uia64_install_context() will
    137 	 return via br.ret, which will decrement bsp by size-of-locals.  */
    138       if ((ret = ia64_get (c, c->loc[IA64_REG_PFS], &pfs)) < 0)
    139 	return ret;
    140       sol = (pfs >> 7) & 0x7f;
    141       if ((dirty_size = rbs_cover_and_flush (c, sol, dirty_partition,
    142 					     &dirty_rnat, &bspstore)) < 0)
    143 	return dirty_size;
    144 
    145       extra.r1 = c->pi.gp;
    146       extra.r15 = c->eh_args[0];
    147       extra.r16 = c->eh_args[1];
    148       extra.r17 = c->eh_args[2];
    149       extra.r18 = c->eh_args[3];
    150       Debug (9, "extra: r15=%lx,r16=%lx,r17=%lx,r18=%lx\n",
    151 	     (long) extra.r15, (long) extra.r16,
    152 	     (long) extra.r17, (long) extra.r18);
    153     }
    154   Debug (8, "resuming at ip=%lx\n", (long) c->ip);
    155   ia64_install_cursor (c, pri_unat, (unw_word_t *) &extra,
    156 		       bspstore, dirty_size, dirty_partition + dirty_size/8,
    157 		       dirty_rnat);
    158 #elif defined(__hpux)
    159   struct cursor *c = (struct cursor *) cursor;
    160 
    161   setcontext (c->as_arg);	/* should not return */
    162 #endif
    163   return -UNW_EINVAL;
    164 }
    165 
    166 HIDDEN int
    167 ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
    168 {
    169   return local_resume (as, cursor, arg);
    170 }
    171 
    172 #endif /* !UNW_REMOTE_ONLY */
    173 
    174 #ifndef UNW_LOCAL_ONLY
    175 
    176 static inline int
    177 remote_install_cursor (struct cursor *c)
    178 {
    179   int (*access_reg) (unw_addr_space_t, unw_regnum_t, unw_word_t *,
    180 		     int write, void *);
    181   int (*access_fpreg) (unw_addr_space_t, unw_regnum_t, unw_fpreg_t *,
    182 		       int write, void *);
    183   unw_fpreg_t fpval;
    184   unw_word_t val;
    185   int reg;
    186 
    187 #if defined(__linux) && !defined(UNW_REMOTE_ONLY)
    188   if (c->as == unw_local_addr_space)
    189     {
    190       /* Take a short-cut: we directly resume out of the cursor and
    191 	 all we need to do is make sure that all locations point to
    192 	 memory, not registers.  Furthermore, R4-R7 and NAT4-NAT7 are
    193 	 taken care of by ia64_local_resume() so they don't need to be
    194 	 handled here.  */
    195 #     define MEMIFY(preg, reg)						 \
    196       do {								 \
    197 	if (IA64_IS_REG_LOC (c->loc[(preg)]))				 \
    198 	  c->loc[(preg)] = IA64_LOC_ADDR ((unw_word_t)			 \
    199 					  tdep_uc_addr(c->as_arg, (reg), \
    200 						       NULL), 0);	 \
    201       } while (0)
    202       MEMIFY (IA64_REG_PR,	UNW_IA64_PR);
    203       MEMIFY (IA64_REG_PFS,	UNW_IA64_AR_PFS);
    204       MEMIFY (IA64_REG_RNAT,	UNW_IA64_AR_RNAT);
    205       MEMIFY (IA64_REG_UNAT,	UNW_IA64_AR_UNAT);
    206       MEMIFY (IA64_REG_LC,	UNW_IA64_AR_LC);
    207       MEMIFY (IA64_REG_FPSR,	UNW_IA64_AR_FPSR);
    208       MEMIFY (IA64_REG_IP,	UNW_IA64_BR + 0);
    209       MEMIFY (IA64_REG_B1,	UNW_IA64_BR + 1);
    210       MEMIFY (IA64_REG_B2,	UNW_IA64_BR + 2);
    211       MEMIFY (IA64_REG_B3,	UNW_IA64_BR + 3);
    212       MEMIFY (IA64_REG_B4,	UNW_IA64_BR + 4);
    213       MEMIFY (IA64_REG_B5,	UNW_IA64_BR + 5);
    214       MEMIFY (IA64_REG_F2,	UNW_IA64_FR + 2);
    215       MEMIFY (IA64_REG_F3,	UNW_IA64_FR + 3);
    216       MEMIFY (IA64_REG_F4,	UNW_IA64_FR + 4);
    217       MEMIFY (IA64_REG_F5,	UNW_IA64_FR + 5);
    218       MEMIFY (IA64_REG_F16,	UNW_IA64_FR + 16);
    219       MEMIFY (IA64_REG_F17,	UNW_IA64_FR + 17);
    220       MEMIFY (IA64_REG_F18,	UNW_IA64_FR + 18);
    221       MEMIFY (IA64_REG_F19,	UNW_IA64_FR + 19);
    222       MEMIFY (IA64_REG_F20,	UNW_IA64_FR + 20);
    223       MEMIFY (IA64_REG_F21,	UNW_IA64_FR + 21);
    224       MEMIFY (IA64_REG_F22,	UNW_IA64_FR + 22);
    225       MEMIFY (IA64_REG_F23,	UNW_IA64_FR + 23);
    226       MEMIFY (IA64_REG_F24,	UNW_IA64_FR + 24);
    227       MEMIFY (IA64_REG_F25,	UNW_IA64_FR + 25);
    228       MEMIFY (IA64_REG_F26,	UNW_IA64_FR + 26);
    229       MEMIFY (IA64_REG_F27,	UNW_IA64_FR + 27);
    230       MEMIFY (IA64_REG_F28,	UNW_IA64_FR + 28);
    231       MEMIFY (IA64_REG_F29,	UNW_IA64_FR + 29);
    232       MEMIFY (IA64_REG_F30,	UNW_IA64_FR + 30);
    233       MEMIFY (IA64_REG_F31,	UNW_IA64_FR + 31);
    234     }
    235   else
    236 #endif /* __linux && !UNW_REMOTE_ONLY */
    237     {
    238       access_reg = c->as->acc.access_reg;
    239       access_fpreg = c->as->acc.access_fpreg;
    240 
    241       Debug (8, "copying out cursor state\n");
    242 
    243       for (reg = 0; reg <= UNW_REG_LAST; ++reg)
    244 	{
    245 	  if (unw_is_fpreg (reg))
    246 	    {
    247 	      if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0)
    248 		(*access_fpreg) (c->as, reg, &fpval, 1, c->as_arg);
    249 	    }
    250 	  else
    251 	    {
    252 	      if (tdep_access_reg (c, reg, &val, 0) >= 0)
    253 		(*access_reg) (c->as, reg, &val, 1, c->as_arg);
    254 	    }
    255 	}
    256     }
    257   return (*c->as->acc.resume) (c->as, (unw_cursor_t *) c, c->as_arg);
    258 }
    259 
    260 #endif /* !UNW_LOCAL_ONLY */
    261 
    262 PROTECTED int
    263 unw_resume (unw_cursor_t *cursor)
    264 {
    265   struct cursor *c = (struct cursor *) cursor;
    266 
    267   Debug (1, "(cursor=%p, ip=0x%016lx)\n", c, (unsigned long) c->ip);
    268 
    269 #ifdef UNW_LOCAL_ONLY
    270   return local_resume (c->as, cursor, c->as_arg);
    271 #else
    272   return remote_install_cursor (c);
    273 #endif
    274 }
    275