Commit | Line | Data |
---|---|---|
d3225ea0 SG |
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 *)®isters[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 | |
67ac9759 | 216 | of error; store status through argument pointer OURSTATUS. */ |
d3225ea0 SG |
217 | |
218 | int | |
219 | child_wait (pid, status) | |
220 | int pid; | |
67ac9759 | 221 | struct target_waitstatus *ourstatus; |
d3225ea0 SG |
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)); | |
67ac9759 JK |
245 | /* Claim it exited with unknown signal. */ |
246 | ourstatus->kind = TARGET_WAITKIND_SIGNALLED; | |
247 | ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; | |
d3225ea0 SG |
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 | ||
67ac9759 JK |
268 | store_waitstatus (ourstatus, status); |
269 | ||
d3225ea0 SG |
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 | } |