* target.h: Add enum target_waitkind, enum target_signal, and
[deliverable/binutils-gdb.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 }
This page took 0.034769 seconds and 4 git commands to generate.