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