Updated to libg++ 2.4
[unix-history] / gnu / usr.bin / kgdb / inflow.c
CommitLineData
04497f0b
NW
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
10static 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
16This file is part of GDB.
17
18GDB is free software; you can redistribute it and/or modify
19it under the terms of the GNU General Public License as published by
20the Free Software Foundation; either version 1, or (at your option)
21any later version.
22
23GDB is distributed in the hope that it will be useful,
24but WITHOUT ANY WARRANTY; without even the implied warranty of
25MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26GNU General Public License for more details.
27
28You should have received a copy of the GNU General Public License
29along with GDB; see the file COPYING. If not, write to
30the 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>
69extern int original_stack_limit;
70#endif /* SET_STACK_LIMIT_HUGE */
71
72extern int errno;
73
74/* Nonzero if we are debugging an attached outside process
75 rather than an inferior. */
76
77int attach_flag;
78
79\f
80/* Record terminal status separately for debugger and inferior. */
81
82static TERMINAL sg_inferior;
83static TERMINAL sg_ours;
84
85static int tflags_inferior;
86static int tflags_ours;
87
88#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
89static struct tchars tc_inferior;
90static struct tchars tc_ours;
91#endif
92
93#ifdef TIOCGLTC
94static struct ltchars ltc_inferior;
95static struct ltchars ltc_ours;
96#endif
97
98#ifdef TIOCLGET
99static int lmode_inferior;
100static int lmode_ours;
101#endif
102
103#ifdef TIOCGPGRP
104static int pgrp_inferior;
105static int pgrp_ours;
106#else
107static int (*sigint_ours) ();
108static int (*sigquit_ours) ();
109#endif /* TIOCGPGRP */
110
111/* Copy of inferior_io_terminal when inferior was last started. */
112static char *inferior_thisrun_terminal;
113
114static void terminal_ours_1 ();
115
116/* Nonzero if our terminal settings are in effect.
117 Zero if the inferior's settings are in effect. */
118static int terminal_is_ours;
119
120/* Initialize the terminal settings we record for the inferior,
121 before we actually run the inferior. */
122
123void
124terminal_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
154void
155terminal_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, &ltc_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
194void
195terminal_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
207void
208terminal_ours ()
209{
210 if (remote_debugging)
211 return;
212
213 terminal_ours_1 (0);
214}
215
216static void
217terminal_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, &ltc_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, &ltc_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
286static void
287term_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 *)&ltc_inferior)[i]);
328 printf_filtered ("\n");
329 ioctl (0, TIOCSLTC, &ltc_ours);
330#endif
331
332#ifdef TIOCLGET
333 printf_filtered ("lmode: %x\n", lmode_inferior);
334#endif
335}
336\f
337static void
338new_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
379int
380create_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
466static void
467kill_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
481void
482inferior_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). */
501static void
502try_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
533void
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\
542Report 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, &ltc_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