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