OSDN Git Service

From Paul Hilfinger. Add attribs param to hpux_thread_xfer_memory.
[pf3gnuchains/pf3gnuchains3x.git] / gdb / hppab-nat.c
1 /* Machine-dependent hooks for the unix child process stratum.  This
2    code is for the HP PA-RISC cpu.
3
4    Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
5
6    Contributed by the Center for Software Science at the
7    University of Utah (pa-gdb-bugs@cs.utah.edu).
8
9    This file is part of GDB.
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place - Suite 330,
24    Boston, MA 02111-1307, USA.  */
25
26 #include "defs.h"
27 #include "inferior.h"
28 #include "target.h"
29 #include <sys/ptrace.h>
30
31 /* Use an extra level of indirection for ptrace calls.
32    This lets us breakpoint usefully on call_ptrace.   It also
33    allows us to pass an extra argument to ptrace without
34    using an ANSI-C specific macro.  */
35
36 #define ptrace call_ptrace
37
38 #if !defined (offsetof)
39 #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
40 #endif
41
42 /* U_REGS_OFFSET is the offset of the registers within the u area.  */
43 #if !defined (U_REGS_OFFSET)
44 #define U_REGS_OFFSET \
45   ptrace (PT_READ_U, inferior_pid, \
46           (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
47     - KERNEL_U_ADDR
48 #endif
49
50 /* Fetch one register.  */
51
52 static void
53 fetch_register (int regno)
54 {
55   register unsigned int regaddr;
56   char buf[MAX_REGISTER_RAW_SIZE];
57   register int i;
58
59   /* Offset of registers within the u area.  */
60   unsigned int offset;
61
62   offset = U_REGS_OFFSET;
63
64   regaddr = register_addr (regno, offset);
65   for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
66     {
67       errno = 0;
68       *(int *) &buf[i] = ptrace (PT_RUREGS, inferior_pid,
69                                  (PTRACE_ARG3_TYPE) regaddr, 0);
70       regaddr += sizeof (int);
71       if (errno != 0)
72         {
73           /* Warning, not error, in case we are attached; sometimes the
74              kernel doesn't let us at the registers.  */
75           char *err = safe_strerror (errno);
76           char *msg = alloca (strlen (err) + 128);
77           sprintf (msg, "reading register %s: %s", REGISTER_NAME (regno), err);
78           warning (msg);
79           goto error_exit;
80         }
81     }
82   supply_register (regno, buf);
83 error_exit:;
84 }
85
86 /* Fetch all registers, or just one, from the child process.  */
87
88 void
89 fetch_inferior_registers (int regno)
90 {
91   if (regno == -1)
92     for (regno = 0; regno < NUM_REGS; regno++)
93       fetch_register (regno);
94   else
95     fetch_register (regno);
96 }
97
98 /* Store our register values back into the inferior.
99    If REGNO is -1, do this for all registers.
100    Otherwise, REGNO specifies which register (so we can save time).  */
101
102 void
103 store_inferior_registers (int regno)
104 {
105   register unsigned int regaddr;
106   char buf[80];
107   register int i;
108   unsigned int offset = U_REGS_OFFSET;
109   int scratch;
110
111   if (regno >= 0)
112     {
113       if (CANNOT_STORE_REGISTER (regno))
114         return;
115       regaddr = register_addr (regno, offset);
116       errno = 0;
117       if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM)
118         {
119           scratch = *(int *) &registers[REGISTER_BYTE (regno)] | 0x3;
120           ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
121                   scratch);
122           if (errno != 0)
123             {
124               /* Error, even if attached.  Failing to write these two
125                  registers is pretty serious.  */
126               sprintf (buf, "writing register number %d", regno);
127               perror_with_name (buf);
128             }
129         }
130       else
131         for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
132           {
133             errno = 0;
134             ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
135                     *(int *) &registers[REGISTER_BYTE (regno) + i]);
136             if (errno != 0)
137               {
138                 /* Warning, not error, in case we are attached; sometimes the
139                    kernel doesn't let us at the registers.  */
140                 char *err = safe_strerror (errno);
141                 char *msg = alloca (strlen (err) + 128);
142                 sprintf (msg, "writing register %s: %s",
143                          REGISTER_NAME (regno), err);
144                 warning (msg);
145                 return;
146               }
147             regaddr += sizeof (int);
148           }
149     }
150   else
151     for (regno = 0; regno < NUM_REGS; regno++)
152       store_inferior_registers (regno);
153 }
154
155 /* PT_PROT is specific to the PA BSD kernel and isn't documented
156    anywhere (except here).  
157
158    PT_PROT allows one to enable/disable the data memory break bit
159    for pages of memory in an inferior process.  This bit is used
160    to cause "Data memory break traps" to occur when the appropriate
161    page is written to.
162
163    The arguments are as follows:
164
165    PT_PROT -- The ptrace action to perform.
166
167    INFERIOR_PID -- The pid of the process who's page table entries
168    will be modified.
169
170    PT_ARGS -- The *address* of a 3 word block of memory which has
171    additional information:
172
173    word 0 -- The start address to watch.  This should be a page-aligned
174    address.
175
176    word 1 -- The ending address to watch.  Again, this should be a 
177    page aligned address.
178
179    word 2 -- Nonzero to enable the data memory break bit on the
180    given address range or zero to disable the data memory break
181    bit on the given address range.
182
183    This call may fail if the given addresses are not valid in the inferior
184    process.  This most often happens when restarting a program which
185    has watchpoints inserted on heap or stack memory.  */
186
187 #define PT_PROT 21
188
189 int
190 hppa_set_watchpoint (int addr, int len, int flag)
191 {
192   int pt_args[3];
193   pt_args[0] = addr;
194   pt_args[1] = addr + len;
195   pt_args[2] = flag;
196
197   /* Mask off the lower 12 bits since we want to work on a page basis.  */
198   pt_args[0] >>= 12;
199   pt_args[1] >>= 12;
200
201   /* Rounding adjustments.  */
202   pt_args[1] -= pt_args[0];
203   pt_args[1]++;
204
205   /* Put the lower 12 bits back as zero.  */
206   pt_args[0] <<= 12;
207   pt_args[1] <<= 12;
208
209   /* Do it.  */
210   return ptrace (PT_PROT, inferior_pid, (PTRACE_ARG3_TYPE) pt_args, 0);
211 }