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@gmail.com> 5 6This file is part of libunwind. 7 8Permission is hereby granted, free of charge, to any person obtaining 9a copy of this software and associated documentation files (the 10"Software"), to deal in the Software without restriction, including 11without limitation the rights to use, copy, modify, merge, publish, 12distribute, sublicense, and/or sell copies of the Software, and to 13permit persons to whom the Software is furnished to do so, subject to 14the following conditions: 15 16The above copyright notice and this permission notice shall be 17included in all copies or substantial portions of the Software. 18 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25WITH 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. */ 35PROTECTED unw_addr_space_t unw_local_addr_space; 36 37#else /* !UNW_REMOTE_ONLY */ 38 39static struct unw_addr_space local_addr_space; 40 41PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; 42 43static inline void * 44uc_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 59void * 60_Uhppa_uc_addr (ucontext_t *uc, int reg) 61{ 62 return uc_addr (uc, reg); 63} 64 65# endif /* UNW_LOCAL_ONLY */ 66 67HIDDEN 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 74static void 75put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg) 76{ 77 /* it's a no-op */ 78} 79 80static int 81get_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 88static int 89access_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, sizeof(unw_word_t))) 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, sizeof(unw_word_t))) 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 133static int 134access_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 164static int 165access_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 198static int 199get_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, arg); 204} 205 206HIDDEN void 207hppa_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