_UPT_access_reg.c revision c5a37d6efcfd45d0f68edca1bbc8f51556f69d92
1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2003-2004 Hewlett-Packard Co
3	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5This file is part of libunwind.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25
26#include "_UPT_internal.h"
27
28#if UNW_TARGET_IA64
29# include <elf.h>
30# ifdef HAVE_ASM_PTRACE_OFFSETS_H
31#   include <asm/ptrace_offsets.h>
32# endif
33# include "ia64/rse.h"
34#endif
35
36int
37_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
38		 int write, void *arg)
39{
40  struct UPT_info *ui = arg;
41  pid_t pid = ui->pid;
42
43#if UNW_DEBUG
44  if (write)
45    Debug (16, "%s <- %lx\n", unw_regname (reg), (long) *val);
46#endif
47
48#if UNW_TARGET_IA64
49  if ((unsigned) reg - UNW_IA64_NAT < 32)
50    {
51      unsigned long nat_bits, mask;
52
53      /* The Linux ptrace represents the statc NaT bits as a single word.  */
54      mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT);
55      errno = 0;
56#ifdef HAVE_TTRACE
57#	warning No support for ttrace() yet.
58#else
59      nat_bits = ptrace (PTRACE_PEEKUSER, pid, PT_NAT_BITS, 0);
60      if (errno)
61	goto badreg;
62#endif
63
64      if (write)
65	{
66	  if (*val)
67	    nat_bits |= mask;
68	  else
69	    nat_bits &= ~mask;
70#ifdef HAVE_TTRACE
71#	warning No support for ttrace() yet.
72#else
73	  errno = 0;
74	  ptrace (PTRACE_POKEUSER, pid, PT_NAT_BITS, nat_bits);
75	  if (errno)
76	    goto badreg;
77#endif
78	}
79      goto out;
80    }
81  else
82    switch (reg)
83      {
84      case UNW_IA64_GR + 0:
85	if (write)
86	  goto badreg;
87	*val = 0;
88	return 0;
89
90      case UNW_REG_IP:
91	{
92	  unsigned long ip, psr;
93
94	  /* distribute bundle-addr. & slot-number across PT_IIP & PT_IPSR.  */
95#ifdef HAVE_TTRACE
96#	warning No support for ttrace() yet.
97#else
98	  errno = 0;
99	  psr = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IPSR, 0);
100	  if (errno)
101	    goto badreg;
102#endif
103	  if (write)
104	    {
105	      ip = *val & ~0xfUL;
106	      psr = (psr & ~0x3UL << 41) | (*val & 0x3);
107#ifdef HAVE_TTRACE
108#	warning No support for ttrace() yet.
109#else
110	      errno = 0;
111	      ptrace (PTRACE_POKEUSER, pid, PT_CR_IIP, ip);
112	      ptrace (PTRACE_POKEUSER, pid, PT_CR_IPSR, psr);
113	      if (errno)
114		goto badreg;
115#endif
116	    }
117	  else
118	    {
119#ifdef HAVE_TTRACE
120#	warning No support for ttrace() yet.
121#else
122	      errno = 0;
123	      ip = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IIP, 0);
124	      if (errno)
125		goto badreg;
126#endif
127	      *val = ip + ((psr >> 41) & 0x3);
128	    }
129	  goto out;
130	}
131
132      case UNW_IA64_AR_BSPSTORE:
133	reg = UNW_IA64_AR_BSP;
134	break;
135
136      case UNW_IA64_AR_BSP:
137      case UNW_IA64_BSP:
138	{
139	  unsigned long sof, cfm, bsp;
140
141#ifdef HAVE_TTRACE
142#	warning No support for ttrace() yet.
143#else
144	  /* Account for the fact that ptrace() expects bsp to point
145	     _after_ the current register frame.  */
146	  errno = 0;
147	  cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0);
148	  if (errno)
149	    goto badreg;
150#endif
151	  sof = (cfm & 0x7f);
152
153	  if (write)
154	    {
155	      bsp = ia64_rse_skip_regs (*val, sof);
156#ifdef HAVE_TTRACE
157#	warning No support for ttrace() yet.
158#else
159	      errno = 0;
160	      ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, bsp);
161	      if (errno)
162		goto badreg;
163#endif
164	    }
165	  else
166	    {
167#ifdef HAVE_TTRACE
168#	warning No support for ttrace() yet.
169#else
170	      errno = 0;
171	      bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0);
172	      if (errno)
173		goto badreg;
174#endif
175	      *val = ia64_rse_skip_regs (bsp, -sof);
176	    }
177	  goto out;
178	}
179
180      case UNW_IA64_CFM:
181	/* If we change CFM, we need to adjust ptrace's notion of bsp
182	   accordingly, so that the real bsp remains unchanged.  */
183	if (write)
184	  {
185	    unsigned long new_sof, old_sof, cfm, bsp;
186
187#ifdef HAVE_TTRACE
188#	warning No support for ttrace() yet.
189#else
190	    errno = 0;
191	    bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0);
192	    cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0);
193#endif
194	    if (errno)
195	      goto badreg;
196	    old_sof = (cfm & 0x7f);
197	    new_sof = (*val & 0x7f);
198	    if (old_sof != new_sof)
199	      {
200		bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
201#ifdef HAVE_TTRACE
202#	warning No support for ttrace() yet.
203#else
204		errno = 0;
205		ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, 0);
206		if (errno)
207		  goto badreg;
208#endif
209	      }
210#ifdef HAVE_TTRACE
211#	warning No support for ttrace() yet.
212#else
213	    errno = 0;
214	    ptrace (PTRACE_POKEUSER, pid, PT_CFM, *val);
215	    if (errno)
216	      goto badreg;
217#endif
218	    goto out;
219	  }
220	break;
221      }
222#endif
223
224  if ((unsigned) reg >= sizeof (_UPT_reg_offset) / sizeof (_UPT_reg_offset[0]))
225    goto badreg;
226
227#ifdef HAVE_TTRACE
228#	warning No support for ttrace() yet.
229#else
230  errno = 0;
231  if (write)
232    ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg], *val);
233  else
234    *val = ptrace (PTRACE_PEEKUSER, pid, _UPT_reg_offset[reg], 0);
235  if (errno)
236    goto badreg;
237#endif
238
239#ifdef UNW_TARGET_IA64
240 out:
241#endif
242#if UNW_DEBUG
243  if (!write)
244    Debug (16, "%s -> %lx\n", unw_regname (reg), (long) *val);
245#endif
246  return 0;
247
248 badreg:
249  Debug (1, "bad register number %u\n", reg);
250  return -UNW_EBADREG;
251}
252