1 /* libunwind - a platform-independent unwind library 2 Copyright (C) 2002, 2004 Hewlett-Packard Co 3 Copyright (C) 2007 David Mosberger-Tang 4 Contributed by David Mosberger-Tang <dmosberger (at) gmail.com> 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 void *addr; 47 48 if ((unsigned) (reg - UNW_HPPA_GR) < 32) 49 addr = &uc->uc_mcontext.sc_gr[reg - UNW_HPPA_GR]; 50 else if ((unsigned) (reg - UNW_HPPA_FR) < 32) 51 addr = &uc->uc_mcontext.sc_fr[reg - UNW_HPPA_FR]; 52 else 53 addr = NULL; 54 return addr; 55 } 56 57 # ifdef UNW_LOCAL_ONLY 58 59 void * 60 _Uhppa_uc_addr (ucontext_t *uc, int reg) 61 { 62 return uc_addr (uc, reg); 63 } 64 65 # endif /* UNW_LOCAL_ONLY */ 66 67 HIDDEN unw_dyn_info_list_t _U_dyn_info_list; 68 69 /* XXX fix me: there is currently no way to locate the dyn-info list 70 by a remote unwinder. On ia64, this is done via a special 71 unwind-table entry. Perhaps something similar can be done with 72 DWARF2 unwind info. */ 73 74 static void 75 put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) 76 { 77 /* it's a no-op */ 78 } 79 80 static int 81 get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr, 82 void *arg) 83 { 84 *dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list; 85 return 0; 86 } 87 88 static int 89 access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, 90 void *arg) 91 { 92 if (write) 93 { 94 /* ANDROID support update. */ 95 #ifdef UNW_LOCAL_ONLY 96 if (map_local_is_writable (addr)) 97 { 98 #endif 99 Debug (12, "mem[%x] <- %x\n", addr, *val); 100 *(unw_word_t *) addr = *val; 101 #ifdef UNW_LOCAL_ONLY 102 } 103 else 104 { 105 Debug (12, "Unwritable memory mem[%x] <- %x\n", addr, *val); 106 return -1; 107 } 108 #endif 109 /* End of ANDROID update. */ 110 } 111 else 112 { 113 /* ANDROID support update. */ 114 #ifdef UNW_LOCAL_ONLY 115 if (map_local_is_readable (addr)) 116 { 117 #endif 118 *val = *(unw_word_t *) addr; 119 Debug (12, "mem[%x] -> %x\n", addr, *val); 120 #ifdef UNW_LOCAL_ONLY 121 } 122 else 123 { 124 Debug (12, "Unreadable memory mem[%x] -> XXX\n", addr); 125 return -1; 126 } 127 #endif 128 /* End of ANDROID update. */ 129 } 130 return 0; 131 } 132 133 static int 134 access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write, 135 void *arg) 136 { 137 unw_word_t *addr; 138 ucontext_t *uc = arg; 139 140 if ((unsigned int) (reg - UNW_HPPA_FR) < 32) 141 goto badreg; 142 143 addr = uc_addr (uc, reg); 144 if (!addr) 145 goto badreg; 146 147 if (write) 148 { 149 *(unw_word_t *) addr = *val; 150 Debug (12, "%s <- %x\n", unw_regname (reg), *val); 151 } 152 else 153 { 154 *val = *(unw_word_t *) addr; 155 Debug (12, "%s -> %x\n", unw_regname (reg), *val); 156 } 157 return 0; 158 159 badreg: 160 Debug (1, "bad register number %u\n", reg); 161 return -UNW_EBADREG; 162 } 163 164 static int 165 access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, 166 int write, void *arg) 167 { 168 ucontext_t *uc = arg; 169 unw_fpreg_t *addr; 170 171 if ((unsigned) (reg - UNW_HPPA_FR) > 32) 172 goto badreg; 173 174 addr = uc_addr (uc, reg); 175 if (!addr) 176 goto badreg; 177 178 if (write) 179 { 180 Debug (12, "%s <- %08x.%08x\n", 181 unw_regname (reg), val->raw.bits[1], val->raw.bits[0]); 182 *(unw_fpreg_t *) addr = *val; 183 } 184 else 185 { 186 *val = *(unw_fpreg_t *) addr; 187 Debug (12, "%s -> %08x.%08x\n", 188 unw_regname (reg), val->raw.bits[1], val->raw.bits[0]); 189 } 190 return 0; 191 192 badreg: 193 Debug (1, "bad register number %u\n", reg); 194 /* attempt to access a non-preserved register */ 195 return -UNW_EBADREG; 196 } 197 198 static int 199 get_static_proc_name (unw_addr_space_t as, unw_word_t ip, 200 char *buf, size_t buf_len, unw_word_t *offp, 201 void *arg) 202 { 203 return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp); 204 } 205 206 HIDDEN void 207 hppa_local_addr_space_init (void) 208 { 209 memset (&local_addr_space, 0, sizeof (local_addr_space)); 210 local_addr_space.caching_policy = UNW_CACHE_GLOBAL; 211 local_addr_space.acc.find_proc_info = dwarf_find_proc_info; 212 local_addr_space.acc.put_unwind_info = put_unwind_info; 213 local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; 214 local_addr_space.acc.access_mem = access_mem; 215 local_addr_space.acc.access_reg = access_reg; 216 local_addr_space.acc.access_fpreg = access_fpreg; 217 local_addr_space.acc.resume = hppa_local_resume; 218 local_addr_space.acc.get_proc_name = get_static_proc_name; 219 unw_flush_cache (&local_addr_space, 0, 0); 220 221 map_local_init (); 222 } 223 224 #endif /* !UNW_REMOTE_ONLY */ 225