Commit | Line | Data |
---|---|---|
cc61838f WJ |
1 | /*- |
2 | * This code is derived from software copyrighted by the Free Software | |
3 | * Foundation. | |
4 | * | |
5 | * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. | |
6 | * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. | |
7 | */ | |
8 | ||
9 | #ifndef lint | |
10 | static char sccsid[] = "@(#)inflow.c 6.5 (Berkeley) 5/8/91"; | |
11 | #endif /* not lint */ | |
12 | ||
13 | /* Low level interface to ptrace, for GDB when running under Unix. | |
14 | Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. | |
15 | ||
16 | This file is part of GDB. | |
17 | ||
18 | GDB is free software; you can redistribute it and/or modify | |
19 | it under the terms of the GNU General Public License as published by | |
20 | the Free Software Foundation; either version 1, or (at your option) | |
21 | any later version. | |
22 | ||
23 | GDB is distributed in the hope that it will be useful, | |
24 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
26 | GNU General Public License for more details. | |
27 | ||
28 | You should have received a copy of the GNU General Public License | |
29 | along with GDB; see the file COPYING. If not, write to | |
30 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
31 | ||
32 | #include <stdio.h> | |
33 | #include "defs.h" | |
34 | #include "param.h" | |
35 | #include "frame.h" | |
36 | #include "inferior.h" | |
37 | ||
38 | #ifdef USG | |
39 | #include <sys/types.h> | |
40 | #endif | |
41 | ||
42 | /* Some USG-esque systems (some of which are BSD-esque enough so that USG | |
43 | is not defined) want this header, and it won't do any harm. */ | |
44 | #include <fcntl.h> | |
45 | ||
46 | #include <sys/param.h> | |
47 | #include <sys/dir.h> | |
48 | #include <signal.h> | |
49 | ||
50 | #ifdef HAVE_TERMIO | |
51 | #include <termio.h> | |
52 | #undef TIOCGETP | |
53 | #define TIOCGETP TCGETA | |
54 | #undef TIOCSETN | |
55 | #define TIOCSETN TCSETA | |
56 | #undef TIOCSETP | |
57 | #define TIOCSETP TCSETAF | |
58 | #define TERMINAL struct termio | |
59 | #else | |
60 | #include <sys/ioctl.h> | |
61 | #include <fcntl.h> | |
62 | #include <sgtty.h> | |
63 | #define TERMINAL struct sgttyb | |
64 | #endif | |
65 | ||
66 | #ifdef SET_STACK_LIMIT_HUGE | |
67 | #include <sys/time.h> | |
68 | #include <sys/resource.h> | |
69 | extern int original_stack_limit; | |
70 | #endif /* SET_STACK_LIMIT_HUGE */ | |
71 | ||
72 | extern int errno; | |
73 | ||
74 | /* Nonzero if we are debugging an attached outside process | |
75 | rather than an inferior. */ | |
76 | ||
77 | int attach_flag; | |
78 | ||
79 | \f | |
80 | /* Record terminal status separately for debugger and inferior. */ | |
81 | ||
82 | static TERMINAL sg_inferior; | |
83 | static TERMINAL sg_ours; | |
84 | ||
85 | static int tflags_inferior; | |
86 | static int tflags_ours; | |
87 | ||
88 | #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) | |
89 | static struct tchars tc_inferior; | |
90 | static struct tchars tc_ours; | |
91 | #endif | |
92 | ||
93 | #ifdef TIOCGLTC | |
94 | static struct ltchars ltc_inferior; | |
95 | static struct ltchars ltc_ours; | |
96 | #endif | |
97 | ||
98 | #ifdef TIOCLGET | |
99 | static int lmode_inferior; | |
100 | static int lmode_ours; | |
101 | #endif | |
102 | ||
103 | #ifdef TIOCGPGRP | |
104 | static int pgrp_inferior; | |
105 | static int pgrp_ours; | |
106 | #else | |
107 | static int (*sigint_ours) (); | |
108 | static int (*sigquit_ours) (); | |
109 | #endif /* TIOCGPGRP */ | |
110 | ||
111 | /* Copy of inferior_io_terminal when inferior was last started. */ | |
112 | static char *inferior_thisrun_terminal; | |
113 | ||
114 | static void terminal_ours_1 (); | |
115 | ||
116 | /* Nonzero if our terminal settings are in effect. | |
117 | Zero if the inferior's settings are in effect. */ | |
118 | static int terminal_is_ours; | |
119 | ||
120 | /* Initialize the terminal settings we record for the inferior, | |
121 | before we actually run the inferior. */ | |
122 | ||
123 | void | |
124 | terminal_init_inferior () | |
125 | { | |
126 | if (remote_debugging) | |
127 | return; | |
128 | ||
129 | sg_inferior = sg_ours; | |
130 | tflags_inferior = tflags_ours; | |
131 | ||
132 | #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) | |
133 | tc_inferior = tc_ours; | |
134 | #endif | |
135 | ||
136 | #ifdef TIOCGLTC | |
137 | ltc_inferior = ltc_ours; | |
138 | #endif | |
139 | ||
140 | #ifdef TIOCLGET | |
141 | lmode_inferior = lmode_ours; | |
142 | #endif | |
143 | ||
144 | #ifdef TIOCGPGRP | |
145 | pgrp_inferior = inferior_pid; | |
146 | #endif /* TIOCGPGRP */ | |
147 | ||
148 | terminal_is_ours = 1; | |
149 | } | |
150 | ||
151 | /* Put the inferior's terminal settings into effect. | |
152 | This is preparation for starting or resuming the inferior. */ | |
153 | ||
154 | void | |
155 | terminal_inferior () | |
156 | { | |
157 | if (remote_debugging) | |
158 | return; | |
159 | ||
160 | if (terminal_is_ours) /* && inferior_thisrun_terminal == 0) */ | |
161 | { | |
162 | fcntl (0, F_SETFL, tflags_inferior); | |
163 | fcntl (0, F_SETFL, tflags_inferior); | |
164 | ioctl (0, TIOCSETN, &sg_inferior); | |
165 | ||
166 | #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) | |
167 | ioctl (0, TIOCSETC, &tc_inferior); | |
168 | #endif | |
169 | #ifdef TIOCGLTC | |
170 | ioctl (0, TIOCSLTC, <c_inferior); | |
171 | #endif | |
172 | #ifdef TIOCLGET | |
173 | ioctl (0, TIOCLSET, &lmode_inferior); | |
174 | #endif | |
175 | ||
176 | #ifdef TIOCGPGRP | |
177 | ioctl (0, TIOCSPGRP, &pgrp_inferior); | |
178 | #else | |
179 | sigint_ours = (int (*) ()) signal (SIGINT, SIG_IGN); | |
180 | sigquit_ours = (int (*) ()) signal (SIGQUIT, SIG_IGN); | |
181 | #endif /* TIOCGPGRP */ | |
182 | } | |
183 | terminal_is_ours = 0; | |
184 | } | |
185 | ||
186 | /* Put some of our terminal settings into effect, | |
187 | enough to get proper results from our output, | |
188 | but do not change into or out of RAW mode | |
189 | so that no input is discarded. | |
190 | ||
191 | After doing this, either terminal_ours or terminal_inferior | |
192 | should be called to get back to a normal state of affairs. */ | |
193 | ||
194 | void | |
195 | terminal_ours_for_output () | |
196 | { | |
197 | if (remote_debugging) | |
198 | return; | |
199 | ||
200 | terminal_ours_1 (1); | |
201 | } | |
202 | ||
203 | /* Put our terminal settings into effect. | |
204 | First record the inferior's terminal settings | |
205 | so they can be restored properly later. */ | |
206 | ||
207 | void | |
208 | terminal_ours () | |
209 | { | |
210 | if (remote_debugging) | |
211 | return; | |
212 | ||
213 | terminal_ours_1 (0); | |
214 | } | |
215 | ||
216 | static void | |
217 | terminal_ours_1 (output_only) | |
218 | int output_only; | |
219 | { | |
220 | #ifdef TIOCGPGRP | |
221 | /* Ignore this signal since it will happen when we try to set the pgrp. */ | |
222 | void (*osigttou) (); | |
223 | #endif /* TIOCGPGRP */ | |
224 | ||
225 | if (!terminal_is_ours) /* && inferior_thisrun_terminal == 0) */ | |
226 | { | |
227 | terminal_is_ours = 1; | |
228 | ||
229 | #ifdef TIOCGPGRP | |
230 | osigttou = signal (SIGTTOU, SIG_IGN); | |
231 | ||
232 | ioctl (0, TIOCGPGRP, &pgrp_inferior); | |
233 | ioctl (0, TIOCSPGRP, &pgrp_ours); | |
234 | ||
235 | signal (SIGTTOU, osigttou); | |
236 | #else | |
237 | signal (SIGINT, sigint_ours); | |
238 | signal (SIGQUIT, sigquit_ours); | |
239 | #endif /* TIOCGPGRP */ | |
240 | ||
241 | tflags_inferior = fcntl (0, F_GETFL, 0); | |
242 | ioctl (0, TIOCGETP, &sg_inferior); | |
243 | ||
244 | #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) | |
245 | ioctl (0, TIOCGETC, &tc_inferior); | |
246 | #endif | |
247 | #ifdef TIOCGLTC | |
248 | ioctl (0, TIOCGLTC, <c_inferior); | |
249 | #endif | |
250 | #ifdef TIOCLGET | |
251 | ioctl (0, TIOCLGET, &lmode_inferior); | |
252 | #endif | |
253 | } | |
254 | ||
255 | #ifdef HAVE_TERMIO | |
256 | sg_ours.c_lflag |= ICANON; | |
257 | if (output_only && !(sg_inferior.c_lflag & ICANON)) | |
258 | sg_ours.c_lflag &= ~ICANON; | |
259 | #else /* not HAVE_TERMIO */ | |
260 | sg_ours.sg_flags &= ~RAW & ~CBREAK; | |
261 | if (output_only) | |
262 | sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags; | |
263 | #endif /* not HAVE_TERMIO */ | |
264 | ||
265 | fcntl (0, F_SETFL, tflags_ours); | |
266 | fcntl (0, F_SETFL, tflags_ours); | |
267 | ioctl (0, TIOCSETN, &sg_ours); | |
268 | ||
269 | #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) | |
270 | ioctl (0, TIOCSETC, &tc_ours); | |
271 | #endif | |
272 | #ifdef TIOCGLTC | |
273 | ioctl (0, TIOCSLTC, <c_ours); | |
274 | #endif | |
275 | #ifdef TIOCLGET | |
276 | ioctl (0, TIOCLSET, &lmode_ours); | |
277 | #endif | |
278 | ||
279 | #ifdef HAVE_TERMIO | |
280 | sg_ours.c_lflag |= ICANON; | |
281 | #else /* not HAVE_TERMIO */ | |
282 | sg_ours.sg_flags &= ~RAW & ~CBREAK; | |
283 | #endif /* not HAVE_TERMIO */ | |
284 | } | |
285 | ||
286 | static void | |
287 | term_status_command () | |
288 | { | |
289 | register int i; | |
290 | ||
291 | if (remote_debugging) | |
292 | { | |
293 | printf_filtered ("No terminal status when remote debugging.\n"); | |
294 | return; | |
295 | } | |
296 | ||
297 | printf_filtered ("Inferior's terminal status (currently saved by GDB):\n"); | |
298 | ||
299 | #ifdef HAVE_TERMIO | |
300 | ||
301 | printf_filtered ("fcntl flags = 0x%x, c_iflag = 0x%x, c_oflag = 0x%x,\n", | |
302 | tflags_inferior, sg_inferior.c_iflag, sg_inferior.c_oflag); | |
303 | printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n", | |
304 | sg_inferior.c_cflag, sg_inferior.c_lflag, sg_inferior.c_line); | |
305 | printf_filtered ("c_cc: "); | |
306 | for (i = 0; (i < NCC); i += 1) | |
307 | printf_filtered ("0x%x ", sg_inferior.c_cc[i]); | |
308 | printf_filtered ("\n"); | |
309 | ||
310 | #else /* not HAVE_TERMIO */ | |
311 | ||
312 | printf_filtered ("fcntl flags = 0x%x, sgttyb.sg_flags = 0x%x, owner pid = %d.\n", | |
313 | tflags_inferior, sg_inferior.sg_flags, pgrp_inferior); | |
314 | ||
315 | #endif /* not HAVE_TERMIO */ | |
316 | ||
317 | #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) | |
318 | printf_filtered ("tchars: "); | |
319 | for (i = 0; i < sizeof (struct tchars); i++) | |
320 | printf_filtered ("0x%x ", ((char *)&tc_inferior)[i]); | |
321 | printf_filtered ("\n"); | |
322 | #endif | |
323 | ||
324 | #ifdef TIOCGLTC | |
325 | printf_filtered ("ltchars: "); | |
326 | for (i = 0; i < sizeof (struct ltchars); i++) | |
327 | printf_filtered ("0x%x ", ((char *)<c_inferior)[i]); | |
328 | printf_filtered ("\n"); | |
329 | ioctl (0, TIOCSLTC, <c_ours); | |
330 | #endif | |
331 | ||
332 | #ifdef TIOCLGET | |
333 | printf_filtered ("lmode: %x\n", lmode_inferior); | |
334 | #endif | |
335 | } | |
336 | \f | |
337 | static void | |
338 | new_tty (ttyname) | |
339 | char *ttyname; | |
340 | { | |
341 | register int tty; | |
342 | register int fd; | |
343 | ||
344 | #ifdef TIOCNOTTY | |
345 | /* Disconnect the child process from our controlling terminal. */ | |
346 | tty = open("/dev/tty", O_RDWR); | |
347 | if (tty > 0) | |
348 | { | |
349 | ioctl(tty, TIOCNOTTY, 0); | |
350 | close(tty); | |
351 | } | |
352 | #endif | |
353 | ||
354 | /* Now open the specified new terminal. */ | |
355 | ||
356 | tty = open(ttyname, O_RDWR); | |
357 | if (tty == -1) | |
358 | _exit(1); | |
359 | ||
360 | /* Avoid use of dup2; doesn't exist on all systems. */ | |
361 | if (tty != 0) | |
362 | { close (0); dup (tty); } | |
363 | if (tty != 1) | |
364 | { close (1); dup (tty); } | |
365 | if (tty != 2) | |
366 | { close (2); dup (tty); } | |
367 | if (tty > 2) | |
368 | close(tty); | |
369 | } | |
370 | \f | |
371 | /* Start an inferior process and returns its pid. | |
372 | ALLARGS is a string containing shell command to run the program. | |
373 | ENV is the environment vector to pass. */ | |
374 | ||
375 | #ifndef SHELL_FILE | |
376 | #define SHELL_FILE "/bin/sh" | |
377 | #endif | |
378 | ||
379 | int | |
380 | create_inferior (allargs, env) | |
381 | char *allargs; | |
382 | char **env; | |
383 | { | |
384 | int pid; | |
385 | char *shell_command; | |
386 | extern int sys_nerr; | |
387 | extern char *sys_errlist[]; | |
388 | extern int errno; | |
389 | ||
390 | /* If desired, concat something onto the front of ALLARGS. | |
391 | SHELL_COMMAND is the result. */ | |
392 | #ifdef SHELL_COMMAND_CONCAT | |
393 | shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + strlen (allargs) + 1); | |
394 | strcpy (shell_command, SHELL_COMMAND_CONCAT); | |
395 | strcat (shell_command, allargs); | |
396 | #else | |
397 | shell_command = allargs; | |
398 | #endif | |
399 | ||
400 | /* exec is said to fail if the executable is open. */ | |
401 | close_exec_file (); | |
402 | ||
403 | #if defined(USG) && !defined(HAVE_VFORK) | |
404 | pid = fork (); | |
405 | #else | |
406 | pid = vfork (); | |
407 | #endif | |
408 | ||
409 | if (pid < 0) | |
410 | perror_with_name ("vfork"); | |
411 | ||
412 | if (pid == 0) | |
413 | { | |
414 | #ifdef TIOCGPGRP | |
415 | /* Run inferior in a separate process group. */ | |
416 | setpgrp (getpid (), getpid ()); | |
417 | #endif /* TIOCGPGRP */ | |
418 | ||
419 | #ifdef SET_STACK_LIMIT_HUGE | |
420 | /* Reset the stack limit back to what it was. */ | |
421 | { | |
422 | struct rlimit rlim; | |
423 | ||
424 | getrlimit (RLIMIT_STACK, &rlim); | |
425 | rlim.rlim_cur = original_stack_limit; | |
426 | setrlimit (RLIMIT_STACK, &rlim); | |
427 | } | |
428 | #endif /* SET_STACK_LIMIT_HUGE */ | |
429 | ||
430 | ||
431 | inferior_thisrun_terminal = inferior_io_terminal; | |
432 | if (inferior_io_terminal != 0) | |
433 | new_tty (inferior_io_terminal); | |
434 | ||
435 | /* It seems that changing the signal handlers for the inferior after | |
436 | a vfork also changes them for the superior. See comments in | |
437 | initialize_signals for how we get the right signal handlers | |
438 | for the inferior. */ | |
439 | /* Not needed on Sun, at least, and loses there | |
440 | because it clobbers the superior. */ | |
441 | /*??? signal (SIGQUIT, SIG_DFL); | |
442 | signal (SIGINT, SIG_DFL); */ | |
443 | ||
444 | call_ptrace (0); | |
445 | execle (SHELL_FILE, "sh", "-c", shell_command, 0, env); | |
446 | ||
447 | fprintf (stderr, "Cannot exec %s: %s.\n", SHELL_FILE, | |
448 | errno < sys_nerr ? sys_errlist[errno] : "unknown error"); | |
449 | fflush (stderr); | |
450 | _exit (0177); | |
451 | } | |
452 | ||
453 | #ifdef TIOCGPGRP | |
454 | /* Avoid race with TIOCSPGRP: guarantee that inferior's pgrp exists. */ | |
455 | setpgrp (pid, pid); | |
456 | #endif /* TIOCGPGRP */ | |
457 | ||
458 | #ifdef CREATE_INFERIOR_HOOK | |
459 | CREATE_INFERIOR_HOOK (pid); | |
460 | #endif | |
461 | return pid; | |
462 | } | |
463 | ||
464 | /* Kill the inferior process. Make us have no inferior. */ | |
465 | ||
466 | static void | |
467 | kill_command () | |
468 | { | |
469 | if (remote_debugging) | |
470 | { | |
471 | inferior_pid = 0; | |
472 | return; | |
473 | } | |
474 | if (inferior_pid == 0) | |
475 | error ("The program is not being run."); | |
476 | if (!query ("Kill the inferior process? ")) | |
477 | error ("Not confirmed."); | |
478 | kill_inferior (); | |
479 | } | |
480 | ||
481 | void | |
482 | inferior_died () | |
483 | { | |
484 | inferior_pid = 0; | |
485 | attach_flag = 0; | |
486 | mark_breakpoints_out (); | |
487 | select_frame ((FRAME) 0, -1); | |
488 | reopen_exec_file (); | |
489 | if (have_core_file_p ()) | |
490 | set_current_frame ( create_new_frame (read_register (FP_REGNUM), | |
491 | read_pc ())); | |
492 | else | |
493 | set_current_frame (0); | |
494 | } | |
495 | \f | |
496 | #if 0 | |
497 | /* This function is just for testing, and on some systems (Sony NewsOS | |
498 | 3.2) <sys/user.h> also includes <sys/time.h> which leads to errors | |
499 | (since on this system at least sys/time.h is not protected against | |
500 | multiple inclusion). */ | |
501 | static void | |
502 | try_writing_regs_command () | |
503 | { | |
504 | register int i; | |
505 | register int value; | |
506 | extern int errno; | |
507 | ||
508 | if (inferior_pid == 0) | |
509 | error ("There is no inferior process now."); | |
510 | ||
511 | /* A Sun 3/50 or 3/60 (at least) running SunOS 4.0.3 will have a | |
512 | kernel panic if we try to write past the end of the user area. | |
513 | Presumably Sun will fix this bug (it has been reported), but it | |
514 | is tacky to crash the system, so at least on SunOS4 we need to | |
515 | stop writing when we hit the end of the user area. */ | |
516 | for (i = 0; i < sizeof (struct user); i += 2) | |
517 | { | |
518 | QUIT; | |
519 | errno = 0; | |
520 | value = call_ptrace (3, inferior_pid, i, 0); | |
521 | call_ptrace (6, inferior_pid, i, value); | |
522 | if (errno == 0) | |
523 | { | |
524 | printf (" Succeeded with address 0x%x; value 0x%x (%d).\n", | |
525 | i, value, value); | |
526 | } | |
527 | else if ((i & 0377) == 0) | |
528 | printf (" Failed at 0x%x.\n", i); | |
529 | } | |
530 | } | |
531 | #endif | |
532 | \f | |
533 | void | |
534 | _initialize_inflow () | |
535 | { | |
536 | add_com ("term-status", class_obscure, term_status_command, | |
537 | "Print info on inferior's saved terminal status."); | |
538 | ||
539 | #if 0 | |
540 | add_com ("try-writing-regs", class_obscure, try_writing_regs_command, | |
541 | "Try writing all locations in inferior's system block.\n\ | |
542 | Report which ones can be written."); | |
543 | #endif | |
544 | ||
545 | add_com ("kill", class_run, kill_command, | |
546 | "Kill execution of program being debugged."); | |
547 | ||
548 | inferior_pid = 0; | |
549 | ||
550 | ioctl (0, TIOCGETP, &sg_ours); | |
551 | tflags_ours = fcntl (0, F_GETFL, 0); | |
552 | ||
553 | #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) | |
554 | ioctl (0, TIOCGETC, &tc_ours); | |
555 | #endif | |
556 | #ifdef TIOCGLTC | |
557 | ioctl (0, TIOCGLTC, <c_ours); | |
558 | #endif | |
559 | #ifdef TIOCLGET | |
560 | ioctl (0, TIOCLGET, &lmode_ours); | |
561 | #endif | |
562 | ||
563 | #ifdef TIOCGPGRP | |
564 | ioctl (0, TIOCGPGRP, &pgrp_ours); | |
565 | #endif /* TIOCGPGRP */ | |
566 | ||
567 | terminal_is_ours = 1; | |
568 | } | |
569 |