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