* This code is derived from software copyrighted by the Free Software
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
* Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
* $Header: utils.c,v 1.6 91/03/07 17:44:30 mccanne Exp $;
static char sccsid
[] = "@(#)utils.c 6.4 (Berkeley) 5/8/91";
/* General utility routines for GDB, the GNU debugger.
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* If this definition isn't overridden by the header files, assume
that isatty and fileno exist on this system. */
#define ISATTY(FP) (isatty (fileno (FP)))
/* Chain of cleanup actions established with make_cleanup,
to be executed if an error happens. */
static struct cleanup
*cleanup_chain
;
/* Nonzero means a quit has been requested. */
/* Nonzero means quit immediately if Control-C is typed now,
rather than waiting until QUIT is executed. */
/* Add a new cleanup to the cleanup_chain,
and return the previous chain pointer
to be passed later to do_cleanups or discard_cleanups.
Args are FUNCTION to clean up with, and ARG to pass to it. */
make_cleanup (function
, arg
)
register struct cleanup
*new
= (struct cleanup
*) xmalloc (sizeof (struct cleanup
));
register struct cleanup
*old_chain
= cleanup_chain
;
new->next
= cleanup_chain
;
new->function
= function
;
/* Discard cleanups and do the actions they describe
until we get back to the point OLD_CHAIN in the cleanup_chain. */
register struct cleanup
*old_chain
;
register struct cleanup
*ptr
;
while ((ptr
= cleanup_chain
) != old_chain
)
(*ptr
->function
) (ptr
->arg
);
cleanup_chain
= ptr
->next
;
/* Discard cleanups, not doing the actions they describe,
until we get back to the point OLD_CHAIN in the cleanup_chain. */
discard_cleanups (old_chain
)
register struct cleanup
*old_chain
;
register struct cleanup
*ptr
;
while ((ptr
= cleanup_chain
) != old_chain
)
cleanup_chain
= ptr
->next
;
/* Set the cleanup_chain to 0, and return the old cleanup chain. */
struct cleanup
*old_chain
= cleanup_chain
;
/* Restore the cleanup chain from a previously saved chain. */
/* This function is useful for cleanups.
old_chain = make_cleanup (free_current_contents, &foo);
to arrange to free the object thus allocated. */
free_current_contents (location
)
/* Generally useful subroutines used throughout the program. */
/* Like malloc but get error if no storage available. */
register char *val
= (char *) malloc (size
);
fatal ("virtual memory exhausted.", 0);
/* Like realloc but get error if no storage available. */
register char *val
= (char *) realloc (ptr
, size
);
fatal ("virtual memory exhausted.", 0);
/* Print the system error message for errno, and also mention STRING
as the file name for which the error was encountered.
Then return to command level. */
perror_with_name (string
)
extern char *sys_errlist
[];
err
= sys_errlist
[errno
];
combined
= (char *) alloca (strlen (err
) + strlen (string
) + 3);
strcpy (combined
, string
);
/* Print the system error message for ERRCODE, and also mention STRING
as the file name for which the error was encountered. */
print_sys_errmsg (string
, errcode
)
extern char *sys_errlist
[];
err
= sys_errlist
[errcode
];
combined
= (char *) alloca (strlen (err
) + strlen (string
) + 3);
strcpy (combined
, string
);
printf ("%s.\n", combined
);
ioctl (fileno (stdout
), TCFLSH
, 1);
#else /* not HAVE_TERMIO */
ioctl (fileno (stdout
), TIOCFLUSH
, 0);
#endif /* not HAVE_TERMIO */
error ("Quit (expect signal %d when inferior is resumed)", SIGINT
);
/* Control C comes here */
extern int remote_debugging
;
/* Restore the signal handler. */
signal (SIGINT
, request_quit
);
/* Print an error message and return to command level.
STRING is the error message, used as a fprintf string,
and ARG is passed as an argument to it. */
error (string
, arg1
, arg2
, arg3
)
terminal_ours (); /* Should be ok even if no inf. */
fprintf (stderr
, string
, arg1
, arg2
, arg3
);
/* Print an error message and exit reporting failure.
This is for a error that we cannot continue from.
STRING and ARG are passed to fprintf. */
fprintf (stderr
, "gdb: ");
fprintf (stderr
, string
, arg
);
/* Print an error message and exit, dumping core.
STRING is a printf-style control string, and ARG is a corresponding
fatal_dump_core (string
, arg
)
/* "internal error" is always correct, since GDB should never dump
core, no matter what the input. */
fprintf (stderr
, "gdb internal error: ");
fprintf (stderr
, string
, arg
);
signal (SIGQUIT
, SIG_DFL
);
kill (getpid (), SIGQUIT
);
/* We should never get here, but just in case... */
/* Make a copy of the string at PTR with SIZE characters
(and add a null character at the end in the copy).
Uses malloc to get the space. Returns the address of the copy. */
register char *p
= (char *) xmalloc (size
+ 1);
register int len
= strlen (s1
) + strlen (s2
) + strlen (s3
) + 1;
register char *val
= (char *) xmalloc (len
);
/* Ask user a y-or-n question and return 1 iff answer is yes.
Takes three args which are given to printf to print the question.
The first, a control string, should end in "? ".
It should not say how to answer, because we do that. */
query (ctlstr
, arg1
, arg2
)
/* Automatically answer "yes" if input is not from a terminal. */
if (!input_from_terminal_p ())
printf (ctlstr
, arg1
, arg2
);
clearerr (stdin
); /* in case of C-d */
while (fgetc (stdin
) != '\n') clearerr (stdin
);
printf ("Please answer y or n.\n");
/* Parse a C escape sequence. STRING_PTR points to a variable
containing a pointer to the string to parse. That pointer
is updated past the characters we use. The value of the
escape sequence is returned.
A negative value means the sequence \ newline was seen,
which is supposed to be equivalent to nothing at all.
If \ is followed by a null character, we return a negative
value and leave the string pointer pointing at the null character.
If \ is followed by 000, we return 0 and leave the string pointer
after the zeros. A value of 0 does not mean end of string. */
parse_escape (string_ptr
)
register int c
= *(*string_ptr
)++;
c
= parse_escape (string_ptr
);
return (c
& 0200) | (c
& 037);
register int i
= c
- '0';
if ((c
= *(*string_ptr
)++) >= '0' && c
<= '7')
/* Print the character CH on STREAM as part of the contents
of a literal string whose delimiter is QUOTER. */
printchar (ch
, stream
, quoter
)
if (c
< 040 || c
>= 0177)
fputs_filtered ("\\n", stream
);
fputs_filtered ("\\b", stream
);
fputs_filtered ("\\t", stream
);
fputs_filtered ("\\f", stream
);
fputs_filtered ("\\r", stream
);
fputs_filtered ("\\e", stream
);
fputs_filtered ("\\a", stream
);
fprintf_filtered (stream
, "\\%.3o", (unsigned int) c
);
if (c
== '\\' || c
== quoter
)
fputs_filtered ("\\", stream
);
fprintf_filtered (stream
, "%c", c
);
static int lines_per_page
, lines_printed
, chars_per_line
, chars_printed
;
/* Set values of page and line size. */
set_screensize_command (arg
, from_tty
)
int tolinesize
= lines_per_page
;
int tocharsize
= chars_per_line
;
error_no_arg ("set screensize");
while (*p
>= '0' && *p
<= '9')
if (*p
&& *p
!= ' ' && *p
!= '\t')
error ("Non-integral argument given to \"set screensize\".");
while (*p
== ' ' || *p
== '\t')
while (*p1
>= '0' && *p1
<= '9')
error ("Non-integral second argument given to \"set screensize\".");
lines_per_page
= tolinesize
;
chars_per_line
= tocharsize
;
if (ISATTY(stdin
) && ISATTY(stdout
))
struct cleanup
*old_chain
= make_cleanup(instream_cleanup
, instream
);
char *cp
, *gdb_readline();
if (cp
= gdb_readline ("---Type <return> to continue---"))
chars_printed
= lines_printed
= 0;
/* Reinitialize filter; ie. tell it to reset to original values. */
reinitialize_more_filter ()
screensize_info (arg
, from_tty
)
error ("\"info screensize\" does not take any arguments.");
printf ("Output more filtering is disabled.\n");
printf ("Output more filtering is enabled with\n");
printf ("%d lines per page and %d characters per line.\n",
lines_per_page
, chars_per_line
);
/* Like fputs but pause after every screenful.
Unlike fputs, fputs_filtered does not return a value.
It is OK for LINEBUFFER to be NULL, in which case just don't print
Note that a longjmp to top level may occur in this routine
(since prompt_for_continue may do so) so this routine should not be
called when cleanups are not in place. */
fputs_filtered (linebuffer
, stream
)
/* Don't do any filtering if it is disabled. */
if (stream
!= stdout
|| !ISATTY(stdout
) || lines_per_page
== 0)
fputs (linebuffer
, stream
);
/* Go through and output each character. Show line extension
when this is necessary; prompt user for new page when this is
if (lines_printed
>= lines_per_page
- 1)
while (*lineptr
&& *lineptr
!= '\n')
/* Print a single line. */
/* Shifting right by 3 produces the number of tab stops
we have already passed, and then adding one and
shifting left 3 advances to the next tab stop. */
chars_printed
= ((chars_printed
>> 3) + 1) << 3;
if (chars_printed
>= chars_per_line
)
if (lines_printed
>= lines_per_page
- 1)
/* fputs_demangled is a variant of fputs_filtered that
fputs_demangled (linebuffer
, stream
, arg_mode
)
extern char *cplus_demangle (const char *, int);
extern char *cplus_demangle ();
#define SYMBOL_CHAR(c) (isascii(c) && (isalnum(c) || (c) == '_' || (c) == '$'))
while ( *p
!= (char) 0 ) {
/* collect non-interesting characters into buf */
while ( *p
!= (char) 0 && !SYMBOL_CHAR(*p
) ) {
/* output the non-interesting characters without demangling */
fputs_filtered(buf
, stream
);
/* and now the interesting characters */
while (i
< SYMBOL_MAX
&& *p
!= (char) 0 && SYMBOL_CHAR(*p
) ) {
if ( (result
= cplus_demangle(buf
, arg_mode
)) != NULL
) {
fputs_filtered(result
, stream
);
fputs_filtered(buf
, stream
);
/* Print ARG1, ARG2, and ARG3 on stdout using format FORMAT. If this
information is going to put the amount written since the last call
to INIIALIZE_MORE_FILTER or the last page break over the page size,
print out a pause message and do a gdb_readline to get the users
Unlike fprintf, this function does not return a value.
Note that this routine has a restriction that the length of the
final output line must be less than 255 characters *or* it must be
less than twice the size of the format string. This is a very
arbitrary restriction, but it is an internal restriction, so I'll
put it in. This means that the %s format specifier is almost
useless; unless the caller can GUARANTEE that the string is short
enough, fputs_filtered should be used instead.
Note also that a longjmp to top level may occur in this routine
(since prompt_for_continue may do so) so this routine should not be
called when cleanups are not in place. */
fprintf_filtered (stream
, format
, arg1
, arg2
, arg3
, arg4
, arg5
, arg6
)
int arg1
, arg2
, arg3
, arg4
, arg5
, arg6
;
static char *linebuffer
= (char *) 0;
int format_length
= strlen (format
);
/* Allocated linebuffer for the first time. */
linebuffer
= (char *) xmalloc (255);
/* Reallocate buffer to a larger size if this is necessary. */
if (format_length
* 2 > line_size
)
line_size
= format_length
* 2;
/* You don't have to copy. */
linebuffer
= (char *) xmalloc (line_size
);
/* This won't blow up if the restrictions described above are
(void) sprintf (linebuffer
, format
, arg1
, arg2
, arg3
, arg4
, arg5
, arg6
);
fputs_filtered (linebuffer
, stream
);
printf_filtered (format
, arg1
, arg2
, arg3
, arg4
, arg5
, arg6
)
int arg1
, arg2
, arg3
, arg4
, arg5
, arg6
;
fprintf_filtered (stdout
, format
, arg1
, arg2
, arg3
, arg4
, arg5
, arg6
);
print_spaces_filtered (n
, stream
)
register char *s
= (char *) alloca (n
+ 1);
fputs_filtered (s
, stream
);
memcpy (to
, from
, count
);
return (memcmp (to
, from
, count
));
getcwd (buf
, MAXPATHLEN
);
char *sys_siglist
[32] = {
item
->forw
= after
->forw
;
after
->forw
->back
= item
;
item
->forw
->back
= item
->back
;
item
->back
->forw
= item
->forw
;
/* There is too much variation in Sys V signal numbers and names, so
we must initialize them at runtime. */
static char undoc
[] = "(undocumented)";
extern struct cmd_list_element
*setlist
;
add_cmd ("screensize", class_support
, set_screensize_command
,
"Change gdb's notion of the size of the output screen.\n\
The first argument is the number of lines on a page.\n\
The second argument (optional) is the number of characters on a line.",
add_info ("screensize", screensize_info
,
"Show gdb's current notion of the size of the output screen.");
/* These defaults will be used if we are unable to get the correct
/* Initialize the screen height and width from termcap. */
int termtype
= getenv ("TERM");
/* Positive means success, nonpositive means failure. */
/* 2048 is large enough for all known terminals, according to the
status
= tgetent (term_buffer
, termtype
);
/* The number of lines per page is not mentioned
in the terminal description. This probably means
that paging is not useful (e.g. emacs shell window),
/* Initialize signal names. */
for (i
= 0; i
< NSIG
; i
++)
sys_siglist
[SIGHUP
] = "SIGHUP";
sys_siglist
[SIGINT
] = "SIGINT";
sys_siglist
[SIGQUIT
] = "SIGQUIT";
sys_siglist
[SIGILL
] = "SIGILL";
sys_siglist
[SIGTRAP
] = "SIGTRAP";
sys_siglist
[SIGIOT
] = "SIGIOT";
sys_siglist
[SIGEMT
] = "SIGEMT";
sys_siglist
[SIGFPE
] = "SIGFPE";
sys_siglist
[SIGKILL
] = "SIGKILL";
sys_siglist
[SIGBUS
] = "SIGBUS";
sys_siglist
[SIGSEGV
] = "SIGSEGV";
sys_siglist
[SIGSYS
] = "SIGSYS";
sys_siglist
[SIGPIPE
] = "SIGPIPE";
sys_siglist
[SIGALRM
] = "SIGALRM";
sys_siglist
[SIGTERM
] = "SIGTERM";
sys_siglist
[SIGUSR1
] = "SIGUSR1";
sys_siglist
[SIGUSR2
] = "SIGUSR2";
sys_siglist
[SIGCLD
] = "SIGCLD";
sys_siglist
[SIGCHLD
] = "SIGCHLD";
sys_siglist
[SIGPWR
] = "SIGPWR";
sys_siglist
[SIGTSTP
] = "SIGTSTP";
sys_siglist
[SIGTTIN
] = "SIGTTIN";
sys_siglist
[SIGTTOU
] = "SIGTTOU";
sys_siglist
[SIGSTOP
] = "SIGSTOP";
sys_siglist
[SIGXCPU
] = "SIGXCPU";
sys_siglist
[SIGXFSZ
] = "SIGXFSZ";
sys_siglist
[SIGVTALRM
] = "SIGVTALRM";
sys_siglist
[SIGPROF
] = "SIGPROF";
sys_siglist
[SIGWINCH
] = "SIGWINCH";
sys_siglist
[SIGCONT
] = "SIGCONT";
sys_siglist
[SIGURG
] = "SIGURG";
sys_siglist
[SIGIO
] = "SIGIO";
sys_siglist
[SIGWIND
] = "SIGWIND";
sys_siglist
[SIGPHONE
] = "SIGPHONE";
sys_siglist
[SIGPOLL
] = "SIGPOLL";