1
/* libunwind - a platform-independent unwind library
2
Copyright (C) 2001-2004 Hewlett-Packard Co
3
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
5
This file is part of libunwind.
7
Permission is hereby granted, free of charge, to any person obtaining
8
a copy of this software and associated documentation files (the
9
"Software"), to deal in the Software without restriction, including
10
without limitation the rights to use, copy, modify, merge, publish,
11
distribute, sublicense, and/or sell copies of the Software, and to
12
permit persons to whom the Software is furnished to do so, subject to
13
the following conditions:
15
The above copyright notice and this permission notice shall be
16
included in all copies or substantial portions of the Software.
18
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
31
#ifdef HAVE_SYS_UC_ACCESS_H
32
# include <sys/uc_access.h>
38
ia64_strloc (ia64_loc_t loc)
42
if (IA64_IS_NULL_LOC (loc))
47
if (IA64_IS_MEMSTK_NAT (loc))
48
strcat (buf, "memstk_nat(");
49
if (IA64_IS_UC_LOC (loc))
51
if (IA64_IS_FP_LOC (loc))
54
if (IA64_IS_REG_LOC (loc))
55
sprintf (buf + strlen (buf), "%s", unw_regname (IA64_GET_REG (loc)));
57
sprintf (buf + strlen (buf), "0x%llx",
58
(unsigned long long) IA64_GET_ADDR (loc));
60
if (IA64_IS_FP_LOC (loc))
62
if (IA64_IS_UC_LOC (loc))
64
if (IA64_IS_MEMSTK_NAT (loc))
70
#endif /* UNW_DEBUG */
72
#ifdef UNW_REMOTE_ONLY
74
/* unw_local_addr_space is a NULL pointer in this case. */
75
PROTECTED unw_addr_space_t unw_local_addr_space;
77
#else /* !UNW_REMOTE_ONLY */
79
static struct unw_addr_space local_addr_space;
81
PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
83
#ifdef HAVE_SYS_UC_ACCESS_H
85
#else /* !HAVE_SYS_UC_ACCESS_H */
88
tdep_uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr)
90
return inlined_uc_addr (uc, reg, nat_bitnr);
93
#endif /* !HAVE_SYS_UC_ACCESS_H */
96
put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
102
get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
105
*dyn_info_list_addr = _U_dyn_info_list_addr ();
110
access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
115
Debug (12, "mem[%lx] <- %lx\n", addr, *val);
116
*(unw_word_t *) addr = *val;
120
*val = *(unw_word_t *) addr;
121
Debug (12, "mem[%lx] -> %lx\n", addr, *val);
126
#ifdef HAVE_SYS_UC_ACCESS_H
128
#define SYSCALL_CFM_SAVE_REG 11 /* on a syscall, ar.pfs is saved in r11 */
129
#define REASON_SYSCALL 0
132
access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
135
ucontext_t *uc = arg;
136
unsigned int nat, mask;
141
__uc_get_reason (uc, &reason);
145
case UNW_IA64_GR ... UNW_IA64_GR + 31:
146
if ((ret = __uc_get_grs (uc, (reg - UNW_IA64_GR), 1, &value, &nat)))
150
ret = __uc_set_grs (uc, (reg - UNW_IA64_GR), 1, val, nat);
155
case UNW_IA64_NAT ... UNW_IA64_NAT + 31:
156
if ((ret = __uc_get_grs (uc, (reg - UNW_IA64_GR), 1, &value, &nat)))
159
mask = 1 << (reg - UNW_IA64_GR);
167
ret = __uc_set_grs (uc, (reg - UNW_IA64_GR), 1, &value, nat);
170
*val = (nat & mask) != 0;
173
case UNW_IA64_AR ... UNW_IA64_AR + 127:
174
if (reg == UNW_IA64_AR_BSP)
177
ret = __uc_set_ar (uc, (reg - UNW_IA64_AR), *val);
179
ret = __uc_get_ar (uc, (reg - UNW_IA64_AR), val);
181
else if (reg == UNW_IA64_AR_PFS && reason == REASON_SYSCALL)
183
/* As of HP-UX 11.22, getcontext() does not have unwind info
184
and because of that, we need to hack thins manually here.
185
Hopefully, this is OK because the HP-UX kernel also needs
186
to know where AR.PFS has been saved, so the use of
187
register r11 for this purpose is pretty much nailed
190
ret = __uc_set_grs (uc, SYSCALL_CFM_SAVE_REG, 1, val, 0);
192
ret = __uc_get_grs (uc, SYSCALL_CFM_SAVE_REG, 1, val, &nat);
197
ret = __uc_set_ar (uc, (reg - UNW_IA64_AR), *val);
199
ret = __uc_get_ar (uc, (reg - UNW_IA64_AR), val);
203
case UNW_IA64_BR ... UNW_IA64_BR + 7:
205
ret = __uc_set_brs (uc, (reg - UNW_IA64_BR), 1, val);
207
ret = __uc_get_brs (uc, (reg - UNW_IA64_BR), 1, val);
212
ret = __uc_set_prs (uc, *val);
214
ret = __uc_get_prs (uc, val);
219
ret = __uc_set_ip (uc, *val);
221
ret = __uc_get_ip (uc, val);
226
ret = __uc_set_cfm (uc, *val);
228
ret = __uc_get_cfm (uc, val);
231
case UNW_IA64_FR ... UNW_IA64_FR + 127:
239
Debug (1, "failed to %s %s (ret = %d)\n",
240
write ? "write" : "read", unw_regname (reg), ret);
245
Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
247
Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
252
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
253
int write, void *arg)
255
ucontext_t *uc = arg;
256
fp_regval_t fp_regval;
261
case UNW_IA64_FR ... UNW_IA64_FR + 127:
264
memcpy (&fp_regval, val, sizeof (fp_regval));
265
ret = __uc_set_frs (uc, (reg - UNW_IA64_FR), 1, &fp_regval);
269
ret = __uc_get_frs (uc, (reg - UNW_IA64_FR), 1, &fp_regval);
270
memcpy (val, &fp_regval, sizeof (*val));
284
#else /* !HAVE_SYS_UC_ACCESS_H */
287
access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
290
unw_word_t *addr, mask;
291
ucontext_t *uc = arg;
293
if (reg >= UNW_IA64_NAT + 4 && reg <= UNW_IA64_NAT + 7)
295
mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT);
299
uc->uc_mcontext.sc_nat |= mask;
301
uc->uc_mcontext.sc_nat &= ~mask;
304
*val = (uc->uc_mcontext.sc_nat & mask) != 0;
307
Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
309
Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
313
addr = tdep_uc_addr (uc, reg, NULL);
319
if (ia64_read_only_reg (addr))
321
Debug (16, "attempt to write read-only register\n");
322
return -UNW_EREADONLYREG;
325
Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
329
*val = *(unw_word_t *) addr;
330
Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
335
Debug (1, "bad register number %u\n", reg);
340
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
341
int write, void *arg)
343
ucontext_t *uc = arg;
346
if (reg < UNW_IA64_FR || reg >= UNW_IA64_FR + 128)
349
addr = tdep_uc_addr (uc, reg, NULL);
355
if (ia64_read_only_reg (addr))
357
Debug (16, "attempt to write read-only register\n");
358
return -UNW_EREADONLYREG;
361
Debug (12, "%s <- %016lx.%016lx\n",
362
unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
366
*val = *(unw_fpreg_t *) addr;
367
Debug (12, "%s -> %016lx.%016lx\n",
368
unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
373
Debug (1, "bad register number %u\n", reg);
374
/* attempt to access a non-preserved register */
378
#endif /* !HAVE_SYS_UC_ACCESS_H */
381
get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
382
char *buf, size_t buf_len, unw_word_t *offp,
385
return _Uelf64_get_proc_name (getpid (), ip, buf, buf_len, offp);
389
ia64_local_addr_space_init (void)
391
memset (&local_addr_space, 0, sizeof (local_addr_space));
392
local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
394
local_addr_space.abi = ABI_LINUX;
395
#elif defined(__hpux)
396
local_addr_space.abi = ABI_HPUX;
398
local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
399
local_addr_space.acc.find_proc_info = tdep_find_proc_info;
400
local_addr_space.acc.put_unwind_info = put_unwind_info;
401
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
402
local_addr_space.acc.access_mem = access_mem;
403
local_addr_space.acc.access_reg = access_reg;
404
local_addr_space.acc.access_fpreg = access_fpreg;
405
local_addr_space.acc.resume = ia64_local_resume;
406
local_addr_space.acc.get_proc_name = get_static_proc_name;
407
unw_flush_cache (&local_addr_space, 0, 0);
410
#endif /* !UNW_REMOTE_ONLY */
412
#ifndef UNW_LOCAL_ONLY
415
ia64_uc_access_reg (struct cursor *c, ia64_loc_t loc, unw_word_t *valp,
418
#ifdef HAVE_SYS_UC_ACCESS_H
419
unw_word_t uc_addr = IA64_GET_AUX_ADDR (loc);
423
Debug (16, "%s location %s\n",
424
write ? "writing" : "reading", ia64_strloc (loc));
426
if (c->as == unw_local_addr_space)
427
ucp = (ucontext_t *) uc_addr;
430
unw_word_t *dst, src;
432
/* Need to copy-in ucontext_t first. */
433
ucp = alloca (sizeof (ucontext_t));
437
/* For now, there is no non-HP-UX implementation of the
438
uc_access(3) interface. Because of that, we cannot, e.g.,
439
unwind an HP-UX program from a Linux program. Should that
440
become possible at some point in the future, the
441
copy-in/copy-out needs to be adjusted to do byte-swapping if
443
assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN));
445
dst = (unw_word_t *) ucp;
446
for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8)
447
if ((ret = (*c->as->acc.access_mem) (c->as, src, dst++, 0, c->as_arg))
452
if (IA64_IS_REG_LOC (loc))
453
ret = access_reg (unw_local_addr_space, IA64_GET_REG (loc), valp, write,
457
/* Must be an access to the RSE backing store in ucontext_t. */
458
unw_word_t addr = IA64_GET_ADDR (loc);
461
ret = __uc_set_rsebs (ucp, (uint64_t *) addr, 1, valp);
463
ret = __uc_get_rsebs (ucp, (uint64_t *) addr, 1, valp);
470
if (write && c->as != unw_local_addr_space)
472
/* need to copy-out ucontext_t: */
473
unw_word_t dst, *src = (unw_word_t *) ucp;
474
for (dst = uc_addr; dst < uc_addr + sizeof (ucontext_t); dst += 8)
475
if ((ret = (*c->as->acc.access_mem) (c->as, dst, src++, 1, c->as_arg))
480
#else /* !HAVE_SYS_UC_ACCESS_H */
482
#endif /* !HAVE_SYS_UC_ACCESS_H */
486
ia64_uc_access_fpreg (struct cursor *c, ia64_loc_t loc, unw_fpreg_t *valp,
489
#ifdef HAVE_SYS_UC_ACCESS_H
490
unw_word_t uc_addr = IA64_GET_AUX_ADDR (loc);
494
if (c->as == unw_local_addr_space)
495
ucp = (ucontext_t *) uc_addr;
498
unw_word_t *dst, src;
500
/* Need to copy-in ucontext_t first. */
501
ucp = alloca (sizeof (ucontext_t));
505
/* For now, there is no non-HP-UX implementation of the
506
uc_access(3) interface. Because of that, we cannot, e.g.,
507
unwind an HP-UX program from a Linux program. Should that
508
become possible at some point in the future, the
509
copy-in/copy-out needs to be adjusted to do byte-swapping if
511
assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN));
513
dst = (unw_word_t *) ucp;
514
for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8)
515
if ((ret = (*c->as->acc.access_mem) (c->as, src, dst++, 0, c->as_arg))
520
if ((ret = access_fpreg (unw_local_addr_space, IA64_GET_REG (loc), valp,
524
if (write && c->as != unw_local_addr_space)
526
/* need to copy-out ucontext_t: */
527
unw_word_t dst, *src = (unw_word_t *) ucp;
528
for (dst = uc_addr; dst < uc_addr + sizeof (ucontext_t); dst += 8)
529
if ((ret = (*c->as->acc.access_mem) (c->as, dst, src++, 1, c->as_arg))
534
#else /* !HAVE_SYS_UC_ACCESS_H */
536
#endif /* !HAVE_SYS_UC_ACCESS_H */
539
#endif /* UNW_LOCAL_ONLY */