2004-11-08 Andrew Cagney <cagney@gnu.org>
[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
c906108c
SS
38#include <sys/param.h>
39#include <sys/dir.h>
40#include <signal.h>
41#include <sys/user.h>
42#include <sys/ioctl.h>
43#include <fcntl.h>
44
c906108c 45#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
4e326852
JB
46#include <sys/debugreg.h>
47#endif
c906108c
SS
48
49#include <sys/file.h>
50#include "gdb_stat.h"
51
52#ifdef HAVE_SYS_REG_H
53#include <sys/reg.h>
54#endif
55
56#include "floatformat.h"
57
58#include "target.h"
1f2baacc
MK
59
60#include "i386-tdep.h"
77d2aaae 61\f
4e326852 62
d4e0bab4
MK
63/* Mapping between the general-purpose registers in `struct user'
64 format and GDB's register array layout. */
4e326852 65static int regmap[] =
c906108c
SS
66{
67 EAX, ECX, EDX, EBX,
68 UESP, EBP, ESI, EDI,
69 EIP, EFL, CS, SS,
70 DS, ES, FS, GS,
71};
72
d4e0bab4 73/* Support for the user struct. */
c906108c 74
d4e0bab4
MK
75/* Return the address of register REGNUM. BLOCKEND is the value of
76 u.u_ar0, and points to the place where GS is stored. */
77
78CORE_ADDR
79register_u_addr (CORE_ADDR blockend, int regnum)
c906108c
SS
80{
81 struct user u;
d4e0bab4 82 CORE_ADDR fpstate;
c906108c 83
23a34459 84 if (i386_fp_regnum_p (regnum))
c906108c 85 {
d4e0bab4
MK
86#ifdef KSTKSZ /* SCO, and others? */
87 blockend += 4 * (SS + 1) - KSTKSZ;
88 fpstate = blockend + ((char *) &u.u_fps.u_fpstate - (char *) &u);
c906108c
SS
89 return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
90#else
d4e0bab4 91 fpstate = blockend + ((char *) &u.i387.st_space - (char *) &u);
c906108c
SS
92 return (fpstate + 10 * (regnum - FP0_REGNUM));
93#endif
4e326852 94 }
4e326852 95
d4e0bab4 96 return (blockend + 4 * regmap[regnum]);
c906108c 97}
d4e0bab4
MK
98
99/* Return the size of the user struct. */
100
c906108c 101int
fba45db2 102kernel_u_size (void)
c906108c
SS
103{
104 return (sizeof (struct user));
105}
106\f
107#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
108
109#if !defined (offsetof)
110#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
111#endif
112
113/* Record the value of the debug control register. */
114static int debug_control_mirror;
115
116/* Record which address associates with which register. */
117static CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1];
118
570b8f7c
AC
119static int i386_insert_aligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int,
120 int);
c906108c 121
570b8f7c
AC
122static int i386_insert_nonaligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int,
123 int);
c906108c
SS
124
125/* Insert a watchpoint. */
126
127int
fba45db2 128i386_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
c906108c
SS
129{
130 return i386_insert_aligned_watchpoint (pid, addr, addr, len, rw);
131}
132
133static int
fba45db2
KB
134i386_insert_aligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
135 int len, int rw)
c906108c
SS
136{
137 int i;
138 int read_write_bits, len_bits;
139 int free_debug_register;
140 int register_number;
4e326852 141
c906108c
SS
142 /* Look for a free debug register. */
143 for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
144 {
145 if (address_lookup[i - DR_FIRSTADDR] == 0)
146 break;
147 }
148
149 /* No more debug registers! */
150 if (i > DR_LASTADDR)
151 return -1;
152
153 read_write_bits = (rw & 1) ? DR_RW_READ : DR_RW_WRITE;
154
155 if (len == 1)
156 len_bits = DR_LEN_1;
157 else if (len == 2)
158 {
159 if (addr % 2)
160 return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
161 len_bits = DR_LEN_2;
162 }
163
164 else if (len == 4)
165 {
166 if (addr % 4)
167 return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
168 len_bits = DR_LEN_4;
169 }
170 else
171 return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
4e326852 172
c906108c
SS
173 free_debug_register = i;
174 register_number = free_debug_register - DR_FIRSTADDR;
175 debug_control_mirror |=
176 ((read_write_bits | len_bits)
177 << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number));
178 debug_control_mirror |=
179 (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
180 debug_control_mirror |= DR_LOCAL_SLOWDOWN;
181 debug_control_mirror &= ~DR_CONTROL_RESERVED;
4e326852 182
c906108c
SS
183 ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
184 debug_control_mirror);
185 ptrace (6, pid, offsetof (struct user, u_debugreg[free_debug_register]),
186 addr);
187
188 /* Record where we came from. */
189 address_lookup[register_number] = addr;
190 return 0;
191}
192
193static int
fba45db2
KB
194i386_insert_nonaligned_watchpoint (int pid, CORE_ADDR waddr, CORE_ADDR addr,
195 int len, int rw)
c906108c
SS
196{
197 int align;
198 int size;
199 int rv;
200
ceef0e30 201 static int size_try_array[4][4] =
4e326852 202 {
ceef0e30
JB
203 { 1, 1, 1, 1 }, /* trying size one */
204 { 2, 1, 2, 1 }, /* trying size two */
205 { 2, 1, 2, 1 }, /* trying size three */
206 { 4, 1, 2, 1 } /* trying size four */
c906108c
SS
207 };
208
209 rv = 0;
210 while (len > 0)
211 {
212 align = addr % 4;
213 /* Four is the maximum length for 386. */
ceef0e30 214 size = size_try_array[len > 4 ? 3 : len - 1][align];
c906108c
SS
215
216 rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
217 if (rv)
218 {
219 i386_remove_watchpoint (pid, waddr, size);
220 return rv;
221 }
222 addr += size;
223 len -= size;
224 }
225 return rv;
226}
227
228/* Remove a watchpoint. */
229
230int
fba45db2 231i386_remove_watchpoint (int pid, CORE_ADDR addr, int len)
c906108c
SS
232{
233 int i;
234 int register_number;
235
236 for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
237 {
238 register_number = i - DR_FIRSTADDR;
239 if (address_lookup[register_number] == addr)
240 {
241 debug_control_mirror &=
242 ~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
243 address_lookup[register_number] = 0;
244 }
245 }
246 ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
247 debug_control_mirror);
248 ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
249
250 return 0;
251}
252
253/* Check if stopped by a watchpoint. */
254
255CORE_ADDR
fba45db2 256i386_stopped_by_watchpoint (int pid)
c906108c
SS
257{
258 int i;
259 int status;
260
261 status = ptrace (3, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
262 ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
263
264 for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
265 {
266 if (status & (1 << (i - DR_FIRSTADDR)))
267 return address_lookup[i - DR_FIRSTADDR];
268 }
269
270 return 0;
271}
272
273#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */
This page took 0.692438 seconds and 4 git commands to generate.