Home | History | Annotate | Download | only in aarch64
      1 /* libunwind - a platform-independent unwind library
      2    Copyright (C) 2008 CodeSourcery
      3    Copyright (C) 2012 Tommi Rantala <tt.rantala (at) gmail.com>
      4    Copyright (C) 2013 Linaro Limited
      5 
      6 This file is part of libunwind.
      7 
      8 Permission is hereby granted, free of charge, to any person obtaining
      9 a copy of this software and associated documentation files (the
     10 "Software"), to deal in the Software without restriction, including
     11 without limitation the rights to use, copy, modify, merge, publish,
     12 distribute, sublicense, and/or sell copies of the Software, and to
     13 permit persons to whom the Software is furnished to do so, subject to
     14 the following conditions:
     15 
     16 The above copyright notice and this permission notice shall be
     17 included in all copies or substantial portions of the Software.
     18 
     19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
     26 
     27 #include <stdlib.h>
     28 #include <string.h>
     29 
     30 #include "unwind_i.h"
     31 
     32 #ifdef UNW_REMOTE_ONLY
     33 
     34 /* unw_local_addr_space is a NULL pointer in this case.  */
     35 PROTECTED unw_addr_space_t unw_local_addr_space;
     36 
     37 #else /* !UNW_REMOTE_ONLY */
     38 
     39 static struct unw_addr_space local_addr_space;
     40 
     41 PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
     42 
     43 static inline void *
     44 uc_addr (ucontext_t *uc, int reg)
     45 {
     46   if (reg >= UNW_AARCH64_X0 && reg <= UNW_AARCH64_V31)
     47     return &uc->uc_mcontext.regs[reg];
     48   else
     49     return NULL;
     50 }
     51 
     52 # ifdef UNW_LOCAL_ONLY
     53 
     54 HIDDEN void *
     55 tdep_uc_addr (ucontext_t *uc, int reg)
     56 {
     57   return uc_addr (uc, reg);
     58 }
     59 
     60 # endif /* UNW_LOCAL_ONLY */
     61 
     62 HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
     63 
     64 /* XXX fix me: there is currently no way to locate the dyn-info list
     65        by a remote unwinder.  On ia64, this is done via a special
     66        unwind-table entry.  Perhaps something similar can be done with
     67        DWARF2 unwind info.  */
     68 
     69 static void
     70 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
     71 {
     72   /* it's a no-op */
     73 }
     74 
     75 static int
     76 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
     77 			void *arg)
     78 {
     79   *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
     80   return 0;
     81 }
     82 
     83 static int
     84 access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
     85 	    void *arg)
     86 {
     87   if (write)
     88     {
     89       /* ANDROID support update. */
     90 #ifdef UNW_LOCAL_ONLY
     91       if (map_local_is_writable (addr, sizeof(unw_word_t)))
     92         {
     93 #endif
     94           Debug (16, "mem[%lx] <- %lx\n", addr, *val);
     95           *(unw_word_t *) addr = *val;
     96 #ifdef UNW_LOCAL_ONLY
     97         }
     98       else
     99         {
    100           Debug (16, "Unwritable memory mem[%lx] <- %lx\n", addr, *val);
    101           return -1;
    102         }
    103 #endif
    104       /* End of ANDROID update. */
    105     }
    106   else
    107     {
    108       /* ANDROID support update. */
    109 #ifdef UNW_LOCAL_ONLY
    110       if (map_local_is_readable (addr, sizeof(unw_word_t)))
    111         {
    112 #endif
    113           *val = *(unw_word_t *) addr;
    114           Debug (16, "mem[%lx] -> %lx\n", addr, *val);
    115 #ifdef UNW_LOCAL_ONLY
    116         }
    117       else
    118         {
    119           Debug (16, "Unreadable memory mem[%lx] -> XXX\n", addr);
    120           return -1;
    121         }
    122 #endif
    123       /* End of ANDROID update. */
    124     }
    125   return 0;
    126 }
    127 
    128 static int
    129 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
    130 	    void *arg)
    131 {
    132   unw_word_t *addr;
    133   ucontext_t *uc = arg;
    134 
    135   if (unw_is_fpreg (reg))
    136     goto badreg;
    137 
    138   if (!(addr = uc_addr (uc, reg)))
    139     goto badreg;
    140 
    141   if (write)
    142     {
    143       *(unw_word_t *) addr = *val;
    144       Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
    145     }
    146   else
    147     {
    148       *val = *(unw_word_t *) addr;
    149       Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
    150     }
    151   return 0;
    152 
    153  badreg:
    154   Debug (1, "bad register number %u\n", reg);
    155   return -UNW_EBADREG;
    156 }
    157 
    158 static int
    159 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
    160 	      int write, void *arg)
    161 {
    162   ucontext_t *uc = arg;
    163   unw_fpreg_t *addr;
    164 
    165   if (!unw_is_fpreg (reg))
    166     goto badreg;
    167 
    168   if (!(addr = uc_addr (uc, reg)))
    169     goto badreg;
    170 
    171   if (write)
    172     {
    173       Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
    174 	     ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
    175       *(unw_fpreg_t *) addr = *val;
    176     }
    177   else
    178     {
    179       *val = *(unw_fpreg_t *) addr;
    180       Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
    181 	     ((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
    182     }
    183   return 0;
    184 
    185  badreg:
    186   Debug (1, "bad register number %u\n", reg);
    187   /* attempt to access a non-preserved register */
    188   return -UNW_EBADREG;
    189 }
    190 
    191 static int
    192 get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
    193 		      char *buf, size_t buf_len, unw_word_t *offp,
    194 		      void *arg)
    195 {
    196   return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
    197 }
    198 
    199 static int
    200 access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
    201                          int write, void *arg)
    202 {
    203   if (write)
    204     return -1;
    205 
    206   *val = *(unw_word_t *) addr;
    207   Debug (16, "mem[%lx] -> %lx\n", addr, *val);
    208   return 0;
    209 }
    210 
    211 // This initializes just enough of the address space to call the
    212 // access memory function.
    213 PROTECTED void
    214 unw_local_access_addr_space_init (unw_addr_space_t as)
    215 {
    216   memset (as, 0, sizeof (*as));
    217   as->acc.access_mem = access_mem_unrestricted;
    218 }
    219 
    220 HIDDEN void
    221 aarch64_local_addr_space_init (void)
    222 {
    223   memset (&local_addr_space, 0, sizeof (local_addr_space));
    224   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
    225   local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
    226   local_addr_space.acc.put_unwind_info = put_unwind_info;
    227   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
    228   local_addr_space.acc.access_mem = access_mem;
    229   local_addr_space.acc.access_reg = access_reg;
    230   local_addr_space.acc.access_fpreg = access_fpreg;
    231   local_addr_space.acc.resume = aarch64_local_resume;
    232   local_addr_space.acc.get_proc_name = get_static_proc_name;
    233   unw_flush_cache (&local_addr_space, 0, 0);
    234 
    235   map_local_init ();
    236 }
    237 
    238 #endif /* !UNW_REMOTE_ONLY */
    239