* target.h: Add enum target_waitkind, enum target_signal, and
[external/binutils.git] / gdb / lynx-nat.c
1 /* Native-dependent code for LynxOS.
2    Copyright 1993 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 "target.h"
24
25 #include <sys/ptrace.h>
26 #include "/usr/include/sys/wait.h"
27
28 static unsigned long registers_addr PARAMS ((int pid));
29
30 #define X(ENTRY)(offsetof(struct econtext, ENTRY))
31
32 #ifdef I386
33 /* Mappings from tm-i386v.h */
34
35 static int regmap[] =
36 {
37   X(eax),
38   X(ecx),
39   X(edx),
40   X(ebx),
41   X(esp),                       /* sp */
42   X(ebp),                       /* fp */
43   X(esi),
44   X(edi),
45   X(eip),                       /* pc */
46   X(flags),                     /* ps */
47   X(cs),
48   X(ss),
49   X(ds),
50   X(es),
51   X(ecode),                     /* Lynx doesn't give us either fs or gs, so */
52   X(fault),                     /* we just substitute these two in the hopes
53                                    that they are useful. */
54 };
55 #endif
56
57 #ifdef M68K
58 /* Mappings from tm-m68k.h */
59
60 static int regmap[] =
61 {
62   X(regs[0]),                   /* d0 */
63   X(regs[1]),                   /* d1 */
64   X(regs[2]),                   /* d2 */
65   X(regs[3]),                   /* d3 */
66   X(regs[4]),                   /* d4 */
67   X(regs[5]),                   /* d5 */
68   X(regs[6]),                   /* d6 */
69   X(regs[7]),                   /* d7 */
70   X(regs[8]),                   /* a0 */
71   X(regs[9]),                   /* a1 */
72   X(regs[10]),                  /* a2 */
73   X(regs[11]),                  /* a3 */
74   X(regs[12]),                  /* a4 */
75   X(regs[13]),                  /* a5 */
76   X(regs[14]),                  /* fp */
77   offsetof (st_t, usp) - offsetof (st_t, ec), /* sp */
78   X(status),                    /* ps */
79   X(pc),
80
81   X(fregs[0*3]),                /* fp0 */
82   X(fregs[1*3]),                /* fp1 */
83   X(fregs[2*3]),                /* fp2 */
84   X(fregs[3*3]),                /* fp3 */
85   X(fregs[4*3]),                /* fp4 */
86   X(fregs[5*3]),                /* fp5 */
87   X(fregs[6*3]),                /* fp6 */
88   X(fregs[7*3]),                /* fp7 */
89
90   X(fcregs[0]),                 /* fpcontrol */
91   X(fcregs[1]),                 /* fpstatus */
92   X(fcregs[2]),                 /* fpiaddr */
93   X(ssw),                       /* fpcode */
94   X(fault),                     /* fpflags */
95 };
96 #endif
97
98 /* Return the offset relative to the start of the per-thread data to the
99    saved context block.  */
100
101 static unsigned long
102 registers_addr(pid)
103      int pid;
104 {
105   CORE_ADDR stblock;
106   int ecpoff = offsetof(st_t, ecp);
107   CORE_ADDR ecp;
108
109   errno = 0;
110   stblock = (CORE_ADDR) ptrace (PTRACE_THREADUSER, pid, (PTRACE_ARG3_TYPE)0,
111                                 0);
112   if (errno)
113     perror_with_name ("registers_addr(PTRACE_THREADUSER)");
114
115   ecp = (CORE_ADDR) ptrace (PTRACE_PEEKTHREAD, pid, (PTRACE_ARG3_TYPE)ecpoff,
116                             0);
117   if (errno)
118     perror_with_name ("registers_addr(PTRACE_PEEKTHREAD)");
119
120   return ecp - stblock;
121 }
122
123 /* Fetch one or more registers from the inferior.  REGNO == -1 to get
124    them all.  We actually fetch more than requested, when convenient,
125    marking them as valid so we won't fetch them again.  */
126
127 void
128 fetch_inferior_registers (regno)
129      int regno;
130 {
131   int reglo, reghi;
132   int i;
133   unsigned long ecp;
134
135   if (regno == -1)
136     {
137       reglo = 0;
138       reghi = NUM_REGS - 1;
139     }
140   else
141     reglo = reghi = regno;
142
143   ecp = registers_addr (inferior_pid);
144
145   for (regno = reglo; regno <= reghi; regno++)
146     {
147       char buf[MAX_REGISTER_RAW_SIZE];
148       int ptrace_fun = PTRACE_PEEKTHREAD;
149
150 #ifdef PTRACE_PEEKUSP
151       ptrace_fun = regno == SP_REGNUM ? PTRACE_PEEKUSP : PTRACE_PEEKTHREAD;
152 #endif
153
154       for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
155         {
156           unsigned int reg;
157
158           errno = 0;
159           reg = ptrace (ptrace_fun, inferior_pid,
160                         (PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), 0);
161           if (errno)
162             perror_with_name ("fetch_inferior_registers(ptrace)");
163   
164           *(int *)&buf[i] = reg;
165         }
166       supply_register (regno, buf);
167     }
168 }
169
170 /* Store our register values back into the inferior.
171    If REGNO is -1, do this for all registers.
172    Otherwise, REGNO specifies which register (so we can save time).  */
173
174 void
175 store_inferior_registers (regno)
176      int regno;
177 {
178   int reglo, reghi;
179   int i;
180   unsigned long ecp;
181
182   if (regno == -1)
183     {
184       reglo = 0;
185       reghi = NUM_REGS - 1;
186     }
187   else
188     reglo = reghi = regno;
189
190   ecp = registers_addr (inferior_pid);
191
192   for (regno = reglo; regno <= reghi; regno++)
193     {
194       int ptrace_fun = PTRACE_POKEUSER;
195
196 #ifdef PTRACE_POKEUSP
197       ptrace_fun = regno == SP_REGNUM ? PTRACE_POKEUSP : PTRACE_POKEUSER;
198 #endif
199
200       for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
201         {
202           unsigned int reg;
203
204           reg = *(unsigned int *)&registers[REGISTER_BYTE (regno) + i];
205
206           errno = 0;
207           ptrace (ptrace_fun, inferior_pid,
208                   (PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), reg);
209           if (errno)
210             perror_with_name ("PTRACE_POKEUSER");
211         }
212     }
213 }
214
215 /* Wait for child to do something.  Return pid of child, or -1 in case
216    of error; store status through argument pointer OURSTATUS.  */
217
218 int
219 child_wait (pid, status)
220      int pid;
221      struct target_waitstatus *ourstatus;
222 {
223   int save_errno;
224   int thread;
225
226   while (1)
227     {
228       int sig;
229
230       if (attach_flag)
231         set_sigint_trap();      /* Causes SIGINT to be passed on to the
232                                    attached process. */
233       pid = wait (status);
234       save_errno = errno;
235
236       if (attach_flag)
237         clear_sigint_trap();
238
239       if (pid == -1)
240         {
241           if (save_errno == EINTR)
242             continue;
243           fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing: %s.\n",
244                    safe_strerror (save_errno));
245           /* Claim it exited with unknown signal.  */
246           ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
247           ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
248           return -1;
249         }
250
251       if (pid != PIDGET (inferior_pid)) /* Some other process?!? */
252         continue;
253
254 /*      thread = WIFTID (*status);*/
255       thread = *status >> 16;
256
257       /* Initial thread value can only be acquired via wait, so we have to
258          resort to this hack.  */
259
260       if (TIDGET (inferior_pid) == 0)
261         {
262           inferior_pid = BUILDPID (inferior_pid, thread);
263           add_thread (inferior_pid);
264         }
265
266       pid = BUILDPID (pid, thread);
267
268       store_waitstatus (ourstatus, status);
269
270       return pid;
271     }
272 }
273
274 /* Convert a Lynx process ID to a string.  Returns the string in a static
275    buffer.  */
276
277 char *
278 lynx_pid_to_str (pid)
279      int pid;
280 {
281   static char buf[40];
282
283   sprintf (buf, "process %d thread %d", PIDGET (pid), TIDGET (pid));
284
285   return buf;
286 }
287
288 /* Extract the register values out of the core file and store
289    them where `read_register' will find them.
290
291    CORE_REG_SECT points to the register values themselves, read into memory.
292    CORE_REG_SIZE is the size of that area.
293    WHICH says which set of registers we are handling (0 = int, 2 = float
294          on machines where they are discontiguous).
295    REG_ADDR is the offset from u.u_ar0 to the register values relative to
296             core_reg_sect.  This is used with old-fashioned core files to
297             locate the registers in a large upage-plus-stack ".reg" section.
298             Original upage address X is at location core_reg_sect+x+reg_addr.
299  */
300
301 void
302 fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
303      char *core_reg_sect;
304      unsigned core_reg_size;
305      int which;
306      unsigned reg_addr;
307 {
308   struct st_entry s;
309   unsigned int regno;
310
311   for (regno = 0; regno < NUM_REGS; regno++)
312     supply_register (regno, core_reg_sect + offsetof (st_t, ec)
313                      + regmap[regno]);
314 }