* configure.in: Check for working mmap, ansi headers, string.h,
[external/binutils.git] / gdb / i386v-nat.c
1 /* Intel 386 native support for SYSV systems (pre-SVR4).
2    Copyright (C) 1988, 1989, 1991, 1992, 1994 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include "defs.h"
21 #include "frame.h"
22 #include "inferior.h"
23 #include "language.h"
24 #include "gdbcore.h"
25
26 #ifdef USG
27 #include <sys/types.h>
28 #endif
29
30 #include <sys/param.h>
31 #include <sys/dir.h>
32 #include <signal.h>
33 #include <sys/user.h>
34 #include <sys/ioctl.h>
35 #include <fcntl.h>
36
37 #ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
38 #include <sys/debugreg.h>
39 #endif
40
41 #include <sys/file.h>
42 #include "gdb_stat.h"
43
44 #ifndef NO_SYS_REG_H
45 #include <sys/reg.h>
46 #endif
47
48 #include "floatformat.h"
49
50 #include "target.h"
51
52 \f
53 /* this table must line up with REGISTER_NAMES in tm-i386v.h */
54 /* symbols like 'EAX' come from <sys/reg.h> */
55 static int regmap[] = 
56 {
57   EAX, ECX, EDX, EBX,
58   UESP, EBP, ESI, EDI,
59   EIP, EFL, CS, SS,
60   DS, ES, FS, GS,
61 };
62
63 /* blockend is the value of u.u_ar0, and points to the
64  * place where GS is stored
65  */
66
67 int
68 i386_register_u_addr (blockend, regnum)
69      int blockend;
70      int regnum;
71 {
72 #if 0
73   /* this will be needed if fp registers are reinstated */
74   /* for now, you can look at them with 'info float'
75    * sys5 wont let you change them with ptrace anyway
76    */
77   if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM) 
78     {
79       int ubase, fpstate;
80       struct user u;
81       ubase = blockend + 4 * (SS + 1) - KSTKSZ;
82       fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u);
83       return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
84     } 
85   else
86 #endif
87     return (blockend + 4 * regmap[regnum]);
88   
89 }
90 \f
91 #ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
92
93 #if !defined (offsetof)
94 #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
95 #endif
96
97 /* Record the value of the debug control register.  */
98 static int debug_control_mirror;
99
100 /* Record which address associates with which register.  */
101 static CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1];
102
103 static int
104 i386_insert_aligned_watchpoint PARAMS ((int, CORE_ADDR, CORE_ADDR, int,
105                                            int));
106
107 static int
108 i386_insert_nonaligned_watchpoint PARAMS ((int, CORE_ADDR, CORE_ADDR, int,
109                                            int));
110
111 /* Insert a watchpoint.  */
112
113 int
114 i386_insert_watchpoint (pid, addr, len, rw)
115      int pid;
116      CORE_ADDR addr;
117      int len;
118      int rw;
119 {
120   return i386_insert_aligned_watchpoint (pid, addr, addr, len, rw);
121 }
122
123 static int
124 i386_insert_aligned_watchpoint (pid, waddr, addr, len, rw)
125      int pid;
126      CORE_ADDR waddr;
127      CORE_ADDR addr;
128      int len;
129      int rw;
130 {
131   int i;
132   int read_write_bits, len_bits;
133   int free_debug_register;
134   int register_number;
135   
136   /* Look for a free debug register.  */
137   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
138     {
139       if (address_lookup[i - DR_FIRSTADDR] == 0)
140         break;
141     }
142
143   /* No more debug registers!  */
144   if (i > DR_LASTADDR)
145     return -1;
146
147   read_write_bits = ((rw & 1) ? DR_RW_READ : 0) | ((rw & 2) ? DR_RW_WRITE : 0);
148
149   if (len == 1)
150     len_bits = DR_LEN_1;
151   else if (len == 2)
152     {
153       if (addr % 2)
154         return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
155       len_bits = DR_LEN_2;
156     }
157
158   else if (len == 4)
159     {
160       if (addr % 4)
161         return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
162       len_bits = DR_LEN_4;
163     }
164   else
165     return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
166   
167   free_debug_register = i;
168   register_number = free_debug_register - DR_FIRSTADDR;
169   debug_control_mirror |=
170     ((read_write_bits | len_bits)
171      << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number));
172   debug_control_mirror |=
173     (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
174   debug_control_mirror |= DR_LOCAL_SLOWDOWN;
175   debug_control_mirror &= ~DR_CONTROL_RESERVED;
176   
177   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
178           debug_control_mirror);
179   ptrace (6, pid, offsetof (struct user, u_debugreg[free_debug_register]),
180           addr);
181
182   /* Record where we came from.  */
183   address_lookup[register_number] = addr;
184   return 0;
185 }
186
187 static int
188 i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw)
189      int pid;
190      CORE_ADDR waddr;
191      CORE_ADDR addr;
192      int len;
193      int rw;
194 {
195   int align;
196   int size;
197   int rv;
198
199   static int size_try_array[16] = {
200     1, 1, 1, 1,                 /* trying size one */
201     2, 1, 2, 1,                 /* trying size two */
202     2, 1, 2, 1,                 /* trying size three */
203     4, 1, 2, 1                  /* trying size four */
204   };
205
206   rv = 0;
207   while (len > 0)
208     {
209       align = addr % 4;
210       /* Four is the maximum length for 386.  */
211       size = (len > 4) ? 3 : len - 1;
212       size = size_try_array[size * 4 + align];
213
214       rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
215       if (rv)
216         {
217           i386_remove_watchpoint (pid, waddr, size);
218           return rv;
219         }
220       addr += size;
221       len -= size;
222     }
223   return rv;
224 }
225
226 /* Remove a watchpoint.  */
227
228 int
229 i386_remove_watchpoint (pid, addr, len)
230      int pid;
231      CORE_ADDR addr;
232      int len;
233 {
234   int i;
235   int register_number;
236
237   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
238     {
239       register_number = i - DR_FIRSTADDR;
240       if (address_lookup[register_number] == addr)
241         {
242           debug_control_mirror &=
243             ~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
244           address_lookup[register_number] = 0;
245         }
246     }
247   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
248           debug_control_mirror);
249   ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
250
251   return 0;
252 }
253
254 /* Check if stopped by a watchpoint.  */
255
256 CORE_ADDR
257 i386_stopped_by_watchpoint (pid)
258     int pid;
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 */
276
277 #if 0
278 /* using FLOAT_INFO as is would be a problem.  FLOAT_INFO is called
279    via a command xxx and eventually calls ptrace without ever having
280    traversed the target vector.  This would be terribly impolite
281    behaviour for a sun4 hosted remote gdb.
282
283    A fix might be to move this code into the "info registers" command.
284    rich@cygnus.com 15 Sept 92. */
285 i386_float_info ()
286 {
287   struct user u; /* just for address computations */
288   int i;
289   /* fpstate defined in <sys/user.h> */
290   struct fpstate *fpstatep;
291   char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
292   unsigned int uaddr;
293   char fpvalid = 0;
294   unsigned int rounded_addr;
295   unsigned int rounded_size;
296   extern int corechan;
297   int skip;
298   
299   uaddr = (char *)&u.u_fpvalid - (char *)&u;
300   if (target_has_execution)
301     {
302       unsigned int data;
303       unsigned int mask;
304       
305       rounded_addr = uaddr & -sizeof (int);
306       data = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0);
307       mask = 0xff << ((uaddr - rounded_addr) * 8);
308       
309       fpvalid = ((data & mask) != 0);
310     } 
311 #if 0
312   else 
313     {
314       if (lseek (corechan, uaddr, 0) < 0)
315         perror ("seek on core file");
316       if (myread (corechan, &fpvalid, 1) < 0) 
317         perror ("read on core file");
318       
319     }
320 #endif  /* no core support yet */
321   
322   if (fpvalid == 0) 
323     {
324       printf_unfiltered ("no floating point status saved\n");
325       return;
326     }
327   
328   uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
329   if (target_has_execution)
330     {
331       int *ip;
332       
333       rounded_addr = uaddr & -sizeof (int);
334       rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) +
335                       sizeof (int) - 1) / sizeof (int);
336       skip = uaddr - rounded_addr;
337       
338       ip = (int *)buf;
339       for (i = 0; i < rounded_size; i++) 
340         {
341           *ip++ = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0);
342           rounded_addr += sizeof (int);
343         }
344     } 
345 #if 0
346   else 
347     {
348       if (lseek (corechan, uaddr, 0) < 0)
349         perror_with_name ("seek on core file");
350       if (myread (corechan, buf, sizeof (struct fpstate)) < 0) 
351         perror_with_name ("read from core file");
352       skip = 0;
353     }
354 #endif  /* 0 */ 
355
356   fpstatep = (struct fpstate *)(buf + skip);
357   print_387_status (fpstatep->status, (struct env387 *)fpstatep->state);
358 }
359
360 #endif /* never */