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