1 /* libunwind - a platform-independent unwind library 2 Copyright (C) 2003-2005 Hewlett-Packard Co 3 Contributed by David Mosberger-Tang <davidm (at) hpl.hp.com> 4 Copyright (C) 2010 Konstantin Belousov <kib (at) freebsd.org> 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 "_UPT_internal.h" 28 29 #if UNW_TARGET_IA64 30 # include <elf.h> 31 # ifdef HAVE_ASM_PTRACE_OFFSETS_H 32 # include <asm/ptrace_offsets.h> 33 # endif 34 # include "tdep-ia64/rse.h" 35 #elif defined(__aarch64__) 36 # include <sys/uio.h> 37 #endif 38 39 #if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE 40 int 41 _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, 42 int write, void *arg) 43 { 44 struct UPT_info *ui = arg; 45 pid_t pid = ui->pid; 46 47 #if UNW_DEBUG 48 Debug(16, "using pokeuser: reg: %s [%u], val: %lx, write: %d\n", unw_regname(reg), (unsigned) reg, (long) val, write); 49 50 if (write) 51 Debug (16, "%s <- %lx\n", unw_regname (reg), (long) *val); 52 #endif 53 54 #if UNW_TARGET_IA64 55 if ((unsigned) reg - UNW_IA64_NAT < 32) 56 { 57 unsigned long nat_bits, mask; 58 59 /* The Linux ptrace represents the statc NaT bits as a single word. */ 60 mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT); 61 errno = 0; 62 #ifdef HAVE_TTRACE 63 # warning No support for ttrace() yet. 64 #else 65 nat_bits = ptrace (PTRACE_PEEKUSER, pid, PT_NAT_BITS, 0); 66 if (errno) 67 goto badreg; 68 #endif 69 70 if (write) 71 { 72 if (*val) 73 nat_bits |= mask; 74 else 75 nat_bits &= ~mask; 76 #ifdef HAVE_TTRACE 77 # warning No support for ttrace() yet. 78 #else 79 errno = 0; 80 ptrace (PTRACE_POKEUSER, pid, PT_NAT_BITS, nat_bits); 81 if (errno) 82 goto badreg; 83 #endif 84 } 85 goto out; 86 } 87 else 88 switch (reg) 89 { 90 case UNW_IA64_GR + 0: 91 if (write) 92 goto badreg; 93 *val = 0; 94 return 0; 95 96 case UNW_REG_IP: 97 { 98 unsigned long ip, psr; 99 100 /* distribute bundle-addr. & slot-number across PT_IIP & PT_IPSR. */ 101 #ifdef HAVE_TTRACE 102 # warning No support for ttrace() yet. 103 #else 104 errno = 0; 105 psr = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IPSR, 0); 106 if (errno) 107 goto badreg; 108 #endif 109 if (write) 110 { 111 ip = *val & ~0xfUL; 112 psr = (psr & ~0x3UL << 41) | (*val & 0x3); 113 #ifdef HAVE_TTRACE 114 # warning No support for ttrace() yet. 115 #else 116 errno = 0; 117 ptrace (PTRACE_POKEUSER, pid, PT_CR_IIP, ip); 118 ptrace (PTRACE_POKEUSER, pid, PT_CR_IPSR, psr); 119 if (errno) 120 goto badreg; 121 #endif 122 } 123 else 124 { 125 #ifdef HAVE_TTRACE 126 # warning No support for ttrace() yet. 127 #else 128 errno = 0; 129 ip = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IIP, 0); 130 if (errno) 131 goto badreg; 132 #endif 133 *val = ip + ((psr >> 41) & 0x3); 134 } 135 goto out; 136 } 137 138 case UNW_IA64_AR_BSPSTORE: 139 reg = UNW_IA64_AR_BSP; 140 break; 141 142 case UNW_IA64_AR_BSP: 143 case UNW_IA64_BSP: 144 { 145 unsigned long sof, cfm, bsp; 146 147 #ifdef HAVE_TTRACE 148 # warning No support for ttrace() yet. 149 #else 150 /* Account for the fact that ptrace() expects bsp to point 151 _after_ the current register frame. */ 152 errno = 0; 153 cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0); 154 if (errno) 155 goto badreg; 156 #endif 157 sof = (cfm & 0x7f); 158 159 if (write) 160 { 161 bsp = rse_skip_regs (*val, sof); 162 #ifdef HAVE_TTRACE 163 # warning No support for ttrace() yet. 164 #else 165 errno = 0; 166 ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, bsp); 167 if (errno) 168 goto badreg; 169 #endif 170 } 171 else 172 { 173 #ifdef HAVE_TTRACE 174 # warning No support for ttrace() yet. 175 #else 176 errno = 0; 177 bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0); 178 if (errno) 179 goto badreg; 180 #endif 181 *val = rse_skip_regs (bsp, -sof); 182 } 183 goto out; 184 } 185 186 case UNW_IA64_CFM: 187 /* If we change CFM, we need to adjust ptrace's notion of bsp 188 accordingly, so that the real bsp remains unchanged. */ 189 if (write) 190 { 191 unsigned long new_sof, old_sof, cfm, bsp; 192 193 #ifdef HAVE_TTRACE 194 # warning No support for ttrace() yet. 195 #else 196 errno = 0; 197 bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0); 198 cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0); 199 #endif 200 if (errno) 201 goto badreg; 202 old_sof = (cfm & 0x7f); 203 new_sof = (*val & 0x7f); 204 if (old_sof != new_sof) 205 { 206 bsp = rse_skip_regs (bsp, -old_sof + new_sof); 207 #ifdef HAVE_TTRACE 208 # warning No support for ttrace() yet. 209 #else 210 errno = 0; 211 ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, 0); 212 if (errno) 213 goto badreg; 214 #endif 215 } 216 #ifdef HAVE_TTRACE 217 # warning No support for ttrace() yet. 218 #else 219 errno = 0; 220 ptrace (PTRACE_POKEUSER, pid, PT_CFM, *val); 221 if (errno) 222 goto badreg; 223 #endif 224 goto out; 225 } 226 break; 227 } 228 #endif /* End of IA64 */ 229 230 if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) 231 { 232 #if UNW_DEBUG 233 Debug(2, "register out of range: >= %zu / %zu\n", sizeof(_UPT_reg_offset), sizeof(_UPT_reg_offset[0])); 234 #endif 235 errno = EINVAL; 236 goto badreg; 237 } 238 239 #ifdef HAVE_TTRACE 240 # warning No support for ttrace() yet. 241 #else 242 errno = 0; 243 if (write) 244 /* ANDROID support update. */ 245 ptrace (PTRACE_POKEUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], (void*) *val); 246 /* End of ANDROID update. */ 247 else { 248 #if UNW_DEBUG 249 Debug(16, "ptrace PEEKUSER pid: %lu , reg: %lu , offs: %lu\n", (unsigned long)pid, (unsigned long)reg, 250 (unsigned long)_UPT_reg_offset[reg]); 251 #endif 252 /* ANDROID support update. */ 253 *val = ptrace (PTRACE_PEEKUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], 0); 254 /* End of ANDROID update. */ 255 } 256 if (errno) { 257 #if UNW_DEBUG 258 Debug(2, "ptrace failure\n"); 259 #endif 260 goto badreg; 261 } 262 #endif 263 264 #ifdef UNW_TARGET_IA64 265 out: 266 #endif 267 #if UNW_DEBUG 268 if (!write) 269 Debug (16, "%s[%u] -> %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); 270 #endif 271 return 0; 272 273 badreg: 274 Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); 275 return -UNW_EBADREG; 276 } 277 #elif HAVE_DECL_PT_GETREGS 278 int 279 _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, 280 int write, void *arg) 281 { 282 struct UPT_info *ui = arg; 283 pid_t pid = ui->pid; 284 /* ANDROID support update. */ 285 #if defined(__mips__) 286 struct 287 { 288 uint64_t regs[32]; 289 uint64_t lo; 290 uint64_t hi; 291 uint64_t epc; 292 uint64_t badvaddr; 293 uint64_t status; 294 uint64_t cause; 295 } 296 regs; 297 #else 298 char *r; 299 gregset_t regs; 300 #endif 301 302 #if UNW_DEBUG 303 Debug(16, "using getregs: reg: %s [%u], val: %lx, write: %u\n", unw_regname(reg), (unsigned) reg, (long) val, write); 304 305 if (write) 306 Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); 307 #endif 308 #if defined(__mips__) 309 if (ptrace(PTRACE_GETREGS, pid, 0, (void*)®s) == -1) 310 goto badreg; 311 if (write) 312 { 313 if (reg <= UNW_MIPS_R31) 314 regs.regs[reg] = *val; 315 else if (reg == UNW_MIPS_PC) 316 regs.epc = *val; 317 else 318 goto badreg; 319 if (ptrace(PTRACE_SETREGS, pid, 0, (void*)®s) == -1) 320 goto badreg; 321 } 322 else 323 { 324 if (reg <= UNW_MIPS_R31) 325 *val = regs.regs[reg]; 326 else if (reg == UNW_MIPS_PC) 327 *val = regs.epc; 328 else 329 goto badreg; 330 } 331 #else 332 if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) 333 { 334 errno = EINVAL; 335 goto badreg; 336 } 337 r = (char *)®s + _UPT_reg_offset[reg]; 338 if (ptrace(PT_GETREGS, pid, (caddr_t)®s, 0) == -1) 339 goto badreg; 340 if (write) { 341 memcpy(r, val, sizeof(unw_word_t)); 342 if (ptrace(PT_SETREGS, pid, (caddr_t)®s, 0) == -1) 343 goto badreg; 344 } else 345 memcpy(val, r, sizeof(unw_word_t)); 346 #endif 347 /* End of ANDROID update. */ 348 return 0; 349 350 badreg: 351 Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); 352 return -UNW_EBADREG; 353 } 354 /* ANDROID support update. */ 355 #elif HAVE_DECL_PT_GETREGSET 356 int 357 _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, 358 int write, void *arg) 359 { 360 struct UPT_info *ui = arg; 361 pid_t pid = ui->pid; 362 #if defined(__aarch64__) 363 struct user_pt_regs regs; 364 struct iovec io; 365 io.iov_base = ®s; 366 io.iov_len = sizeof(regs); 367 368 #if UNW_DEBUG 369 Debug(16, "using getregset: reg: %s [%u], val: %lx, write: %u\n", unw_regname(reg), (unsigned) reg, (long) val, write); 370 371 if (write) 372 Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); 373 #endif 374 if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1) 375 goto badreg; 376 if (write) 377 { 378 if (reg == UNW_AARCH64_SP) 379 regs.sp = *val; 380 else if (reg == UNW_AARCH64_PC) 381 regs.pc = *val; 382 else if (reg < UNW_AARCH64_SP) 383 regs.regs[reg] = *val; 384 else 385 goto badreg; 386 if (ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1) 387 goto badreg; 388 } 389 else 390 { 391 if (reg == UNW_AARCH64_SP) 392 *val = regs.sp; 393 else if (reg == UNW_AARCH64_PC) 394 *val = regs.pc; 395 else if (reg < UNW_AARCH64_SP) 396 *val = regs.regs[reg]; 397 else 398 goto badreg; 399 } 400 #else 401 #error Unsupported architecture for getregset 402 #endif 403 return 0; 404 405 badreg: 406 Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); 407 return -UNW_EBADREG; 408 } 409 /* End of ANDROID update. */ 410 #else 411 #error Port me 412 #endif 413