2003-01-31 Frank Ch. Eigler <fche@redhat.com>
[deliverable/binutils-gdb.git] / gdb / i386v-nat.c
CommitLineData
d4e0bab4 1/* Intel 386 native support for System V systems (pre-SVR4).
ca557f44
AC
2
3 Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
4 1999, 2000, 2002 Free Software Foundation, Inc.
c906108c 5
4e326852 6 This file is part of GDB.
c906108c 7
4e326852
JB
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
c906108c 12
4e326852
JB
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
c906108c 17
4e326852
JB
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
c906108c
SS
22
23#include "defs.h"
24
25#ifdef HAVE_PTRACE_H
4e326852 26#include <ptrace.h>
c906108c 27#else
4e326852
JB
28#ifdef HAVE_SYS_PTRACE_H
29#include <sys/ptrace.h>
30#endif
c906108c
SS
31#endif
32
33#include "frame.h"
34#include "inferior.h"
35#include "language.h"
36#include "gdbcore.h"
37
38#ifdef USG
39#include <sys/types.h>
40#endif
41
42#include <sys/param.h>
43#include <sys/dir.h>
44#include <signal.h>
45#include <sys/user.h>
46#include <sys/ioctl.h>
47#include <fcntl.h>
48
c906108c 49#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
4e326852
JB
50#include <sys/debugreg.h>
51#endif
c906108c
SS
52
53#include <sys/file.h>
54#include "gdb_stat.h"
55
56#ifdef HAVE_SYS_REG_H
57#include <sys/reg.h>
58#endif
59
60#include "floatformat.h"
61
62#include "target.h"
1f2baacc
MK
63
64#include "i386-tdep.h"
77d2aaae 65\f
4e326852 66
d4e0bab4
MK
67/* Mapping between the general-purpose registers in `struct user'
68 format and GDB's register array layout. */
4e326852 69static int regmap[] =
c906108c
SS
70{
71 EAX, ECX, EDX, EBX,
72 UESP, EBP, ESI, EDI,
73 EIP, EFL, CS, SS,
74 DS, ES, FS, GS,
75};
76
d4e0bab4 77/* Support for the user struct. */
c906108c 78
d4e0bab4
MK
79/* Return the address of register REGNUM. BLOCKEND is the value of
80 u.u_ar0, and points to the place where GS is stored. */
81
82CORE_ADDR
83register_u_addr (CORE_ADDR blockend, int regnum)
c906108c
SS
84{
85 struct user u;
d4e0bab4 86 CORE_ADDR fpstate;
c906108c 87
23a34459 88 if (i386_fp_regnum_p (regnum))
c906108c 89 {
d4e0bab4
MK
90#ifdef KSTKSZ /* SCO, and others? */
91 blockend += 4 * (SS + 1) - KSTKSZ;
92 fpstate = blockend + ((char *) &u.u_fps.u_fpstate - (char *) &u);
c906108c
SS
93 return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
94#else
d4e0bab4 95 fpstate = blockend + ((char *) &u.i387.st_space - (char *) &u);
c906108c
SS
96 return (fpstate + 10 * (regnum - FP0_REGNUM));
97#endif
4e326852 98 }
4e326852 99
d4e0bab4 100 return (blockend + 4 * regmap[regnum]);
c906108c 101}
d4e0bab4
MK
102
103/* Return the size of the user struct. */
104
c906108c 105int
fba45db2 106kernel_u_size (void)
c906108c
SS
107{
108 return (sizeof (struct user));
109}
110\f
111#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
112
113#if !defined (offsetof)
114#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
115#endif
116
117/* Record the value of the debug control register. */
118static int debug_control_mirror;
119
120/* Record which address associates with which register. */
121static CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1];
122
570b8f7c
AC
123static int i386_insert_aligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int,
124 int);
c906108c 125
570b8f7c
AC
126static int i386_insert_nonaligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int,
127 int);
c906108c
SS
128
129/* Insert a watchpoint. */
130
131int
fba45db2 132i386_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
c906108c
SS
133{
134 return i386_insert_aligned_watchpoint (pid, addr, addr, len, rw);
135}
136
137static int
fba45db2
KB
138i386_insert_aligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
139 int len, int rw)
c906108c
SS
140{
141 int i;
142 int read_write_bits, len_bits;
143 int free_debug_register;
144 int register_number;
4e326852 145
c906108c
SS
146 /* Look for a free debug register. */
147 for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
148 {
149 if (address_lookup[i - DR_FIRSTADDR] == 0)
150 break;
151 }
152
153 /* No more debug registers! */
154 if (i > DR_LASTADDR)
155 return -1;
156
157 read_write_bits = (rw & 1) ? DR_RW_READ : DR_RW_WRITE;
158
159 if (len == 1)
160 len_bits = DR_LEN_1;
161 else if (len == 2)
162 {
163 if (addr % 2)
164 return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
165 len_bits = DR_LEN_2;
166 }
167
168 else if (len == 4)
169 {
170 if (addr % 4)
171 return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
172 len_bits = DR_LEN_4;
173 }
174 else
175 return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
4e326852 176
c906108c
SS
177 free_debug_register = i;
178 register_number = free_debug_register - DR_FIRSTADDR;
179 debug_control_mirror |=
180 ((read_write_bits | len_bits)
181 << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number));
182 debug_control_mirror |=
183 (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
184 debug_control_mirror |= DR_LOCAL_SLOWDOWN;
185 debug_control_mirror &= ~DR_CONTROL_RESERVED;
4e326852 186
c906108c
SS
187 ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
188 debug_control_mirror);
189 ptrace (6, pid, offsetof (struct user, u_debugreg[free_debug_register]),
190 addr);
191
192 /* Record where we came from. */
193 address_lookup[register_number] = addr;
194 return 0;
195}
196
197static int
fba45db2
KB
198i386_insert_nonaligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
199 int len, int rw)
c906108c
SS
200{
201 int align;
202 int size;
203 int rv;
204
ceef0e30 205 static int size_try_array[4][4] =
4e326852 206 {
ceef0e30
JB
207 { 1, 1, 1, 1 }, /* trying size one */
208 { 2, 1, 2, 1 }, /* trying size two */
209 { 2, 1, 2, 1 }, /* trying size three */
210 { 4, 1, 2, 1 } /* trying size four */
c906108c
SS
211 };
212
213 rv = 0;
214 while (len > 0)
215 {
216 align = addr % 4;
217 /* Four is the maximum length for 386. */
ceef0e30 218 size = size_try_array[len > 4 ? 3 : len - 1][align];
c906108c
SS
219
220 rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
221 if (rv)
222 {
223 i386_remove_watchpoint (pid, waddr, size);
224 return rv;
225 }
226 addr += size;
227 len -= size;
228 }
229 return rv;
230}
231
232/* Remove a watchpoint. */
233
234int
fba45db2 235i386_remove_watchpoint (int pid, CORE_ADDR addr, int len)
c906108c
SS
236{
237 int i;
238 int register_number;
239
240 for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
241 {
242 register_number = i - DR_FIRSTADDR;
243 if (address_lookup[register_number] == addr)
244 {
245 debug_control_mirror &=
246 ~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
247 address_lookup[register_number] = 0;
248 }
249 }
250 ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
251 debug_control_mirror);
252 ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
253
254 return 0;
255}
256
257/* Check if stopped by a watchpoint. */
258
259CORE_ADDR
fba45db2 260i386_stopped_by_watchpoint (int pid)
c906108c
SS
261{
262 int i;
263 int status;
264
265 status = ptrace (3, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
266 ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
267
268 for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
269 {
270 if (status & (1 << (i - DR_FIRSTADDR)))
271 return address_lookup[i - DR_FIRSTADDR];
272 }
273
274 return 0;
275}
276
277#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */
This page took 0.326453 seconds and 4 git commands to generate.