#include "config.h"
#ifdef HAVE_CURSES_H
#include <curses.h>
#endif
#ifdef HAVE_TERM_H
#include <term.h>
#endif
#include "defs.h"
#include "gdb_assert.h"
#include <ctype.h>
#include "gdb_string.h"
#include "event-top.h"
#ifdef __GO32__
#include <pc.h>
#endif
#ifdef reg
#undef reg
#endif
#include <signal.h>
#include "gdbcmd.h"
#include "serial.h"
#include "bfd.h"
#include "target.h"
#include "demangle.h"
#include "expression.h"
#include "language.h"
#include "annotate.h"
#include "filenames.h"
#include "inferior.h"
#include <sys/param.h>
#include <readline/readline.h>
#ifdef USE_MMALLOC
#include "mmalloc.h"
#endif
#ifdef NEED_DECLARATION_MALLOC
extern PTR malloc ();
#endif
#ifdef NEED_DECLARATION_REALLOC
extern PTR realloc ();
#endif
#ifdef NEED_DECLARATION_FREE
extern void free ();
#endif
#if defined(HAVE_CANONICALIZE_FILE_NAME) \
&& defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
extern char *canonicalize_file_name (const char *);
#endif
#undef savestring
#if defined (NeXT_PDO) && defined(__WIN32__)
#include <process.h>
#endif
void (*error_begin_hook) (void);
static struct ui_file *gdb_lasterr;
static void vfprintf_maybe_filtered (struct ui_file *, const char *,
va_list, int);
static void fputs_maybe_filtered (const char *, struct ui_file *, int);
#if defined (USE_MMALLOC) && !defined (NO_MMCHECK)
static void malloc_botch (void);
#endif
static void prompt_for_continue (void);
static void set_width_command (char *, int, struct cmd_list_element *);
void update_width (void);
#ifndef GDB_FILE_ISATTY
#define GDB_FILE_ISATTY(GDB_FILE_PTR) (gdb_file_isatty(GDB_FILE_PTR))
#endif
static struct cleanup *cleanup_chain;
static struct cleanup *final_cleanup_chain;
static struct cleanup *run_cleanup_chain;
static struct cleanup *exec_cleanup_chain;
static struct cleanup *exec_error_cleanup_chain;
struct continuation *cmd_continuation;
struct continuation *intermediate_continuation;
int job_control;
int quit_flag;
int immediate_quit;
int demangle = 1;
int asm_demangle = 0;
int sevenbit_strings = 0;
char *error_pre_print;
char *quit_pre_print;
char *warning_pre_print = "\nwarning: ";
int pagination_enabled = 1;
struct cleanup *
make_cleanup (make_cleanup_ftype *function, void *arg)
{
return make_my_cleanup (&cleanup_chain, function, arg);
}
struct cleanup *
make_final_cleanup (make_cleanup_ftype *function, void *arg)
{
return make_my_cleanup (&final_cleanup_chain, function, arg);
}
struct cleanup *
make_run_cleanup (make_cleanup_ftype *function, void *arg)
{
return make_my_cleanup (&run_cleanup_chain, function, arg);
}
struct cleanup *
make_exec_cleanup (make_cleanup_ftype *function, void *arg)
{
return make_my_cleanup (&exec_cleanup_chain, function, arg);
}
struct cleanup *
make_exec_error_cleanup (make_cleanup_ftype *function, void *arg)
{
return make_my_cleanup (&exec_error_cleanup_chain, function, arg);
}
static void
do_freeargv (void *arg)
{
freeargv ((char **) arg);
}
struct cleanup *
make_cleanup_freeargv (char **arg)
{
return make_my_cleanup (&cleanup_chain, do_freeargv, arg);
}
static void
do_bfd_close_cleanup (void *arg)
{
bfd_close (arg);
}
struct cleanup *
make_cleanup_bfd_close (bfd *abfd)
{
return make_cleanup (do_bfd_close_cleanup, abfd);
}
static void
do_close_cleanup (void *arg)
{
int *fd = arg;
close (*fd);
xfree (fd);
}
struct cleanup *
make_cleanup_close (int fd)
{
int *saved_fd = xmalloc (sizeof (fd));
*saved_fd = fd;
return make_cleanup (do_close_cleanup, saved_fd);
}
static void
do_ui_file_delete (void *arg)
{
ui_file_delete (arg);
}
struct cleanup *
make_cleanup_ui_file_delete (struct ui_file *arg)
{
return make_my_cleanup (&cleanup_chain, do_ui_file_delete, arg);
}
static void
do_ui_out_delete (void *arg)
{
ui_out_delete (arg);
}
struct cleanup *
make_cleanup_ui_out_delete (struct ui_out *arg)
{
return make_my_cleanup (&cleanup_chain, do_ui_out_delete, arg);
}
struct cleanup *
make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
void *arg)
{
register struct cleanup *new;
register struct cleanup *old_chain = *pmy_chain;
if (!function)
internal_error (__FILE__, __LINE__,
"Someone tried to put a null function on the cleanup chain!");
new = (struct cleanup *) xmalloc (sizeof (struct cleanup));
new->next = *pmy_chain;
new->function = function;
new->arg = arg;
*pmy_chain = new;
return old_chain;
}
void
do_cleanups (register struct cleanup *old_chain)
{
do_my_cleanups (&cleanup_chain, old_chain);
}
void
do_final_cleanups (register struct cleanup *old_chain)
{
do_my_cleanups (&final_cleanup_chain, old_chain);
}
void
do_run_cleanups (register struct cleanup *old_chain)
{
do_my_cleanups (&run_cleanup_chain, old_chain);
}
void
do_exec_cleanups (register struct cleanup *old_chain)
{
do_my_cleanups (&exec_cleanup_chain, old_chain);
}
void
do_exec_error_cleanups (register struct cleanup *old_chain)
{
do_my_cleanups (&exec_error_cleanup_chain, old_chain);
}
void
do_my_cleanups (register struct cleanup **pmy_chain,
register struct cleanup *old_chain)
{
register struct cleanup *ptr;
while ((ptr = *pmy_chain) != old_chain)
{
*pmy_chain = ptr->next;
(*ptr->function) (ptr->arg);
xfree (ptr);
}
}
void
discard_cleanups (register struct cleanup *old_chain)
{
discard_my_cleanups (&cleanup_chain, old_chain);
}
void
discard_final_cleanups (register struct cleanup *old_chain)
{
discard_my_cleanups (&final_cleanup_chain, old_chain);
}
void
discard_exec_error_cleanups (register struct cleanup *old_chain)
{
discard_my_cleanups (&exec_error_cleanup_chain, old_chain);
}
void
discard_my_cleanups (register struct cleanup **pmy_chain,
register struct cleanup *old_chain)
{
register struct cleanup *ptr;
while ((ptr = *pmy_chain) != old_chain)
{
*pmy_chain = ptr->next;
xfree ((PTR) ptr);
}
}
struct cleanup *
save_cleanups (void)
{
return save_my_cleanups (&cleanup_chain);
}
struct cleanup *
save_final_cleanups (void)
{
return save_my_cleanups (&final_cleanup_chain);
}
struct cleanup *
save_my_cleanups (struct cleanup **pmy_chain)
{
struct cleanup *old_chain = *pmy_chain;
*pmy_chain = 0;
return old_chain;
}
void
restore_cleanups (struct cleanup *chain)
{
restore_my_cleanups (&cleanup_chain, chain);
}
void
restore_final_cleanups (struct cleanup *chain)
{
restore_my_cleanups (&final_cleanup_chain, chain);
}
void
restore_my_cleanups (struct cleanup **pmy_chain, struct cleanup *chain)
{
*pmy_chain = chain;
}
void
free_current_contents (void *ptr)
{
void **location = ptr;
if (location == NULL)
internal_error (__FILE__, __LINE__,
"free_current_contents: NULL pointer");
if (*location != NULL)
{
xfree (*location);
*location = NULL;
}
}
void
null_cleanup (arg)
PTR arg;
{
}
void
add_continuation (void (*continuation_hook) (struct continuation_arg *),
struct continuation_arg *arg_list)
{
struct continuation *continuation_ptr;
continuation_ptr = (struct continuation *) xmalloc (sizeof (struct continuation));
continuation_ptr->continuation_hook = continuation_hook;
continuation_ptr->arg_list = arg_list;
continuation_ptr->next = cmd_continuation;
cmd_continuation = continuation_ptr;
}
void
do_all_continuations (void)
{
struct continuation *continuation_ptr;
struct continuation *saved_continuation;
continuation_ptr = cmd_continuation;
cmd_continuation = NULL;
while (continuation_ptr)
{
(continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
saved_continuation = continuation_ptr;
continuation_ptr = continuation_ptr->next;
xfree (saved_continuation);
}
}
void
discard_all_continuations (void)
{
struct continuation *continuation_ptr;
while (cmd_continuation)
{
continuation_ptr = cmd_continuation;
cmd_continuation = continuation_ptr->next;
xfree (continuation_ptr);
}
}
void
add_intermediate_continuation (void (*continuation_hook)
(struct continuation_arg *),
struct continuation_arg *arg_list)
{
struct continuation *continuation_ptr;
continuation_ptr = (struct continuation *) xmalloc (sizeof (struct continuation));
continuation_ptr->continuation_hook = continuation_hook;
continuation_ptr->arg_list = arg_list;
continuation_ptr->next = intermediate_continuation;
intermediate_continuation = continuation_ptr;
}
void
do_all_intermediate_continuations (void)
{
struct continuation *continuation_ptr;
struct continuation *saved_continuation;
continuation_ptr = intermediate_continuation;
intermediate_continuation = NULL;
while (continuation_ptr)
{
(continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
saved_continuation = continuation_ptr;
continuation_ptr = continuation_ptr->next;
xfree (saved_continuation);
}
}
void
discard_all_intermediate_continuations (void)
{
struct continuation *continuation_ptr;
while (intermediate_continuation)
{
continuation_ptr = intermediate_continuation;
intermediate_continuation = continuation_ptr->next;
xfree (continuation_ptr);
}
}
void
vwarning (const char *string, va_list args)
{
if (warning_hook)
(*warning_hook) (string, args);
else
{
target_terminal_ours ();
wrap_here ("");
gdb_flush (gdb_stdout);
if (warning_pre_print)
fprintf_unfiltered (gdb_stderr, warning_pre_print);
vfprintf_unfiltered (gdb_stderr, string, args);
fprintf_unfiltered (gdb_stderr, "\n");
va_end (args);
}
}
void
warning (const char *string,...)
{
va_list args;
va_start (args, string);
vwarning (string, args);
va_end (args);
}
NORETURN void
verror (const char *string, va_list args)
{
struct ui_file *tmp_stream = mem_fileopen ();
make_cleanup_ui_file_delete (tmp_stream);
vfprintf_unfiltered (tmp_stream, string, args);
error_stream (tmp_stream);
}
NORETURN void
error (const char *string,...)
{
va_list args;
va_start (args, string);
verror (string, args);
va_end (args);
}
static void
do_write (void *data, const char *buffer, long length_buffer)
{
ui_file_write (data, buffer, length_buffer);
}
NORETURN void
error_stream (struct ui_file *stream)
{
if (error_begin_hook)
error_begin_hook ();
ui_file_rewind (gdb_lasterr);
ui_file_put (stream, do_write, gdb_lasterr);
if (!ui_out_is_mi_like_p (uiout))
{
target_terminal_ours ();
wrap_here ("");
gdb_flush (gdb_stdout);
annotate_error_begin ();
if (error_pre_print)
fprintf_filtered (gdb_stderr, error_pre_print);
ui_file_put (stream, do_write, gdb_stderr);
fprintf_filtered (gdb_stderr, "\n");
}
throw_exception (RETURN_ERROR);
}
char *
error_last_message (void)
{
long len;
return ui_file_xstrdup (gdb_lasterr, &len);
}
void
error_init (void)
{
gdb_lasterr = mem_fileopen ();
}
NORETURN void
internal_verror (const char *file, int line,
const char *fmt, va_list ap)
{
static char msg[] = "Internal GDB error: recursive internal error.\n";
static int dejavu = 0;
int quit_p;
int dump_core_p;
switch (dejavu)
{
case 0:
dejavu = 1;
break;
case 1:
dejavu = 2;
fputs_unfiltered (msg, gdb_stderr);
abort ();
default:
dejavu = 3;
write (STDERR_FILENO, msg, sizeof (msg));
exit (1);
}
if (! gdb_stderr) {
fprintf (stderr, "gdb-internal-error: ");
vfprintf (stderr, fmt, ap);
fputs ("\n", stderr);
abort ();
}
target_terminal_ours ();
fprintf_unfiltered (gdb_stderr, "%s:%d: gdb-internal-error: ", file, line);
vfprintf_unfiltered (gdb_stderr, fmt, ap);
fputs_unfiltered ("\n", gdb_stderr);
quit_p = query ("\
An internal GDB error was detected. This may make further\n\
debugging unreliable. Quit this debugging session? ");
dump_core_p = query ("\
Create a core file containing the current state of GDB? ");
if (quit_p)
{
if (dump_core_p)
abort ();
else
exit (1);
}
else
{
if (dump_core_p)
{
if (fork () == 0)
abort ();
}
}
dejavu = 0;
throw_exception (RETURN_ERROR);
}
NORETURN void
internal_error (const char *file, int line, const char *string, ...)
{
va_list ap;
va_start (ap, string);
internal_verror (file, line, string, ap);
va_end (ap);
}
char *
safe_strerror (int errnum)
{
char *msg;
static char buf[32];
if ((msg = strerror (errnum)) == NULL)
{
sprintf (buf, "(undocumented errno %d)", errnum);
msg = buf;
}
return (msg);
}
NORETURN void
perror_with_name (const char *string)
{
char *err;
char *combined;
err = safe_strerror (errno);
combined = (char *) alloca (strlen (err) + strlen (string) + 3);
strcpy (combined, string);
strcat (combined, ": ");
strcat (combined, err);
bfd_set_error (bfd_error_no_error);
errno = 0;
error ("%s.", combined);
}
void
print_sys_errmsg (const char *string, int errcode)
{
char *err;
char *combined;
err = safe_strerror (errcode);
combined = (char *) alloca (strlen (err) + strlen (string) + 3);
strcpy (combined, string);
strcat (combined, ": ");
strcat (combined, err);
gdb_flush (gdb_stdout);
fprintf_unfiltered (gdb_stderr, "%s.\n", combined);
}
void
quit (void)
{
struct serial *gdb_stdout_serial = serial_fdopen (1);
target_terminal_ours ();
wrap_here ((char *) 0);
gdb_flush (gdb_stdout);
gdb_flush (gdb_stderr);
if (gdb_stdout_serial != NULL)
{
serial_drain_output (gdb_stdout_serial);
serial_un_fdopen (gdb_stdout_serial);
}
annotate_error_begin ();
if (quit_pre_print)
fprintf_unfiltered (gdb_stderr, quit_pre_print);
#ifdef __MSDOS__
fprintf_unfiltered (gdb_stderr, "Quit\n");
#else
if (job_control
|| current_target.to_terminal_ours == NULL)
fprintf_unfiltered (gdb_stderr, "Quit\n");
else
fprintf_unfiltered (gdb_stderr,
"Quit (expect signal SIGINT when the program is resumed)\n");
#endif
throw_exception (RETURN_QUIT);
}
void
request_quit (int signo)
{
quit_flag = 1;
signal (signo, request_quit);
#ifdef REQUEST_QUIT
REQUEST_QUIT;
#else
if (immediate_quit)
quit ();
#endif
}
#ifndef HAVE_STDDEF_H
#ifndef size_t
#define size_t unsigned int
#endif
#endif
NORETURN void
nomem (long size)
{
if (size > 0)
{
internal_error (__FILE__, __LINE__, "virtual memory exhausted: can't allocate %ld bytes.", size);
}
else
{
internal_error (__FILE__, __LINE__, "virtual memory exhausted.");
}
}
#if !defined (USE_MMALLOC)
PTR
init_malloc (PTR md)
{
return md;
}
#else
PTR
init_malloc (md)
PTR md;
{
return mmalloc_check_create (md);
}
void
init_mmalloc_default_pool (PTR md)
{
md = mmalloc_malloc_create ();
if (md == NULL)
internal_error (__FILE__, __LINE__, "unable to create default mmalloc allocator");
#if 0
md = mmalloc_check_create (md);
if (md == NULL)
internal_error (__FILE__, __LINE__, "unable to add error-checking to default mmalloc allocator");
#endif
mmalloc_set_default_allocator (md);
}
#endif
void
xasprintf (char **ret, const char *format, ...)
{
va_list args;
va_start (args, format);
xvasprintf (ret, format, args);
va_end (args);
}
void
xvasprintf (char **ret, const char *format, va_list ap)
{
char *tmp;
int status = vasprintf (ret, format, ap);
if ((*ret) == NULL)
internal_error (__FILE__, __LINE__,
"vasprintf returned NULL buffer (errno %d)",
errno);
if (status < 0)
internal_error (__FILE__, __LINE__,
"vasprintf call failed (errno %d)",
errno);
tmp = *ret;
*ret = xstrdup (tmp);
free (tmp);
}
int
myread (int desc, char *addr, int len)
{
register int val;
int orglen = len;
while (len > 0)
{
val = read (desc, addr, len);
if (val < 0)
return val;
if (val == 0)
return orglen - len;
len -= val;
addr += val;
}
return orglen;
}
char *
savestring (const char *ptr, size_t size)
{
register char *p = (char *) xmalloc (size + 1);
memcpy (p, ptr, size);
p[size] = 0;
return p;
}
char *
msavestring (void *md, const char *ptr, size_t size)
{
register char *p = (char *) xmmalloc (md, size + 1);
memcpy (p, ptr, size);
p[size] = 0;
return p;
}
char *
strsave (const char *ptr)
{
return savestring (ptr, strlen (ptr));
}
char *
mstrsave (md, ptr)
PTR md;
const char *ptr;
{
return (msavestring (md, ptr, strlen (ptr)));
}
void
print_spaces (register int n, register struct ui_file *file)
{
fputs_unfiltered (n_spaces (n), file);
}
void
gdb_print_host_address (void *addr, struct ui_file *stream)
{
fprintf_filtered (stream, "0x%lx", (unsigned long) addr);
}
int
query (const char *ctlstr,...)
{
va_list args;
register int answer;
register int ans2;
int retval;
va_start (args, ctlstr);
if (query_hook)
{
return query_hook (ctlstr, args);
}
if (!input_from_terminal_p ())
return 1;
while (1)
{
wrap_here ("");
gdb_flush (gdb_stdout);
if (annotation_level > 1)
printf_filtered ("\n\032\032pre-query\n");
vfprintf_filtered (gdb_stdout, ctlstr, args);
printf_filtered ("(y or n) ");
if (annotation_level > 1)
printf_filtered ("\n\032\032query\n");
wrap_here ("");
gdb_flush (gdb_stdout);
answer = fgetc (stdin);
clearerr (stdin);
if (answer == EOF)
{
retval = 1;
break;
}
if (answer != '\n')
do
{
ans2 = fgetc (stdin);
clearerr (stdin);
}
while (ans2 != EOF && ans2 != '\n' && ans2 != '\r');
if (answer >= 'a')
answer -= 040;
if (answer == 'Y')
{
retval = 1;
break;
}
if (answer == 'N')
{
retval = 0;
break;
}
printf_filtered ("Please answer y or n.\n");
}
if (annotation_level > 1)
printf_filtered ("\n\032\032post-query\n");
return retval;
}
int
parse_escape (char **string_ptr)
{
register int c = *(*string_ptr)++;
switch (c)
{
case 'a':
return 007;
case 'b':
return '\b';
case 'e':
return 033;
case 'f':
return '\f';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'v':
return '\v';
case '\n':
return -2;
case 0:
(*string_ptr)--;
return 0;
case '^':
c = *(*string_ptr)++;
if (c == '\\')
c = parse_escape (string_ptr);
if (c == '?')
return 0177;
return (c & 0200) | (c & 037);
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
{
register int i = c - '0';
register int count = 0;
while (++count < 3)
{
if ((c = *(*string_ptr)++) >= '0' && c <= '7')
{
i *= 8;
i += c - '0';
}
else
{
(*string_ptr)--;
break;
}
}
return i;
}
default:
return c;
}
}
static void
printchar (int c, void (*do_fputs) (const char *, struct ui_file *),
void (*do_fprintf) (struct ui_file *, const char *, ...),
struct ui_file *stream, int quoter)
{
c &= 0xFF;
if (c < 0x20 ||
(c >= 0x7F && c < 0xA0) ||
(sevenbit_strings && c >= 0x80))
{
switch (c)
{
case '\n':
do_fputs ("\\n", stream);
break;
case '\b':
do_fputs ("\\b", stream);
break;
case '\t':
do_fputs ("\\t", stream);
break;
case '\f':
do_fputs ("\\f", stream);
break;
case '\r':
do_fputs ("\\r", stream);
break;
case '\033':
do_fputs ("\\e", stream);
break;
case '\007':
do_fputs ("\\a", stream);
break;
default:
do_fprintf (stream, "\\%.3o", (unsigned int) c);
break;
}
}
else
{
if (c == '\\' || c == quoter)
do_fputs ("\\", stream);
do_fprintf (stream, "%c", c);
}
}
void
fputstr_filtered (const char *str, int quoter, struct ui_file *stream)
{
while (*str)
printchar (*str++, fputs_filtered, fprintf_filtered, stream, quoter);
}
void
fputstr_unfiltered (const char *str, int quoter, struct ui_file *stream)
{
while (*str)
printchar (*str++, fputs_unfiltered, fprintf_unfiltered, stream, quoter);
}
void
fputstrn_unfiltered (const char *str, int n, int quoter, struct ui_file *stream)
{
int i;
for (i = 0; i < n; i++)
printchar (str[i], fputs_unfiltered, fprintf_unfiltered, stream, quoter);
}
static unsigned int lines_per_page;
static unsigned int chars_per_line;
static unsigned int lines_printed, chars_printed;
static char *wrap_buffer;
static char *wrap_pointer;
static char *wrap_indent;
static int wrap_column;
void
init_page_info (void)
{
#if defined(TUI)
if (!tui_get_command_dimension (&chars_per_line, &lines_per_page))
#endif
{
#if defined(__GO32__)
lines_per_page = ScreenRows ();
chars_per_line = ScreenCols ();
#else
lines_per_page = 24;
chars_per_line = 80;
#if !defined (_WIN32)
{
char *termtype = getenv ("TERM");
int status;
char term_buffer[2048];
if (termtype)
{
status = tgetent (term_buffer, termtype);
if (status > 0)
{
int val;
int running_in_emacs = getenv ("EMACS") != NULL;
val = tgetnum ("li");
if (val >= 0 && !running_in_emacs)
lines_per_page = val;
else
lines_per_page = UINT_MAX;
val = tgetnum ("co");
if (val >= 0)
chars_per_line = val;
}
}
}
#endif
#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
SIGWINCH_HANDLER (SIGWINCH);
#endif
#endif
if (!ui_file_isatty (gdb_stdout))
lines_per_page = UINT_MAX;
}
update_width ();
}
void
update_width (void)
{
if (chars_per_line == 0)
{
chars_per_line = UINT_MAX;
}
if (!wrap_buffer)
{
wrap_buffer = (char *) xmalloc (chars_per_line + 2);
wrap_buffer[0] = '\0';
}
else
wrap_buffer = (char *) xrealloc (wrap_buffer, chars_per_line + 2);
wrap_pointer = wrap_buffer;
}
static void
set_width_command (char *args, int from_tty, struct cmd_list_element *c)
{
update_width ();
}
static void
prompt_for_continue (void)
{
char *ignore;
char cont_prompt[120];
if (annotation_level > 1)
printf_unfiltered ("\n\032\032pre-prompt-for-continue\n");
strcpy (cont_prompt,
"---Type <return> to continue, or q <return> to quit---");
if (annotation_level > 1)
strcat (cont_prompt, "\n\032\032prompt-for-continue\n");
reinitialize_more_filter ();
immediate_quit++;
ignore = readline (cont_prompt);
if (annotation_level > 1)
printf_unfiltered ("\n\032\032post-prompt-for-continue\n");
if (ignore)
{
char *p = ignore;
while (*p == ' ' || *p == '\t')
++p;
if (p[0] == 'q')
{
if (!event_loop_p)
request_quit (SIGINT);
else
async_request_quit (0);
}
xfree (ignore);
}
immediate_quit--;
reinitialize_more_filter ();
dont_repeat ();
}
void
reinitialize_more_filter (void)
{
lines_printed = 0;
chars_printed = 0;
}
void
wrap_here (char *indent)
{
if (!wrap_buffer)
internal_error (__FILE__, __LINE__, "failed internal consistency check");
if (wrap_buffer[0])
{
*wrap_pointer = '\0';
fputs_unfiltered (wrap_buffer, gdb_stdout);
}
wrap_pointer = wrap_buffer;
wrap_buffer[0] = '\0';
if (chars_per_line == UINT_MAX)
{
wrap_column = 0;
}
else if (chars_printed >= chars_per_line)
{
puts_filtered ("\n");
if (indent != NULL)
puts_filtered (indent);
wrap_column = 0;
}
else
{
wrap_column = chars_printed;
if (indent == NULL)
wrap_indent = "";
else
wrap_indent = indent;
}
}
void
puts_filtered_tabular (string, width, right)
char *string;
int width;
int right;
{
int spaces = 0;
int stringlen;
char *spacebuf;
gdb_assert (chars_per_line > 0);
if (chars_per_line == UINT_MAX)
{
fputs_filtered (string, gdb_stdout);
fputs_filtered ("\n", gdb_stdout);
return;
}
if (((chars_printed - 1) / width + 2) * width >= chars_per_line)
fputs_filtered ("\n", gdb_stdout);
if (width >= chars_per_line)
width = chars_per_line - 1;
stringlen = strlen (string);
if (chars_printed > 0)
spaces = width - (chars_printed - 1) % width - 1;
if (right)
spaces += width - stringlen;
spacebuf = alloca (spaces + 1);
spacebuf[spaces] = '\0';
while (spaces--)
spacebuf[spaces] = ' ';
fputs_filtered (spacebuf, gdb_stdout);
fputs_filtered (string, gdb_stdout);
}
void
begin_line (void)
{
if (chars_printed > 0)
{
puts_filtered ("\n");
}
}
static void
fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
int filter)
{
const char *lineptr;
gdb_assert (chars_per_line > 0);
if (linebuffer == 0)
return;
if ((stream != gdb_stdout) || !pagination_enabled
|| (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX))
{
fputs_unfiltered (linebuffer, stream);
return;
}
lineptr = linebuffer;
while (*lineptr)
{
if (filter &&
(lines_printed >= lines_per_page - 1))
prompt_for_continue ();
while (*lineptr && *lineptr != '\n')
{
if (*lineptr == '\t')
{
if (wrap_column)
*wrap_pointer++ = '\t';
else
fputc_unfiltered ('\t', stream);
chars_printed = ((chars_printed >> 3) + 1) << 3;
lineptr++;
}
else
{
if (wrap_column)
*wrap_pointer++ = *lineptr;
else
fputc_unfiltered (*lineptr, stream);
chars_printed++;
lineptr++;
}
if (chars_printed >= chars_per_line)
{
unsigned int save_chars = chars_printed;
chars_printed = 0;
lines_printed++;
if (wrap_column)
fputc_unfiltered ('\n', stream);
if (lines_printed >= lines_per_page - 1)
prompt_for_continue ();
if (wrap_column)
{
fputs_unfiltered (wrap_indent, stream);
*wrap_pointer = '\0';
fputs_unfiltered (wrap_buffer, stream);
chars_printed = strlen (wrap_indent)
+ (save_chars - wrap_column);
wrap_pointer = wrap_buffer;
wrap_buffer[0] = '\0';
wrap_column = 0;
}
}
}
if (*lineptr == '\n')
{
chars_printed = 0;
wrap_here ((char *) 0);
lines_printed++;
fputc_unfiltered ('\n', stream);
lineptr++;
}
}
}
void
fputs_filtered (const char *linebuffer, struct ui_file *stream)
{
fputs_maybe_filtered (linebuffer, stream, 1);
}
int
putchar_unfiltered (int c)
{
char buf = c;
ui_file_write (gdb_stdout, &buf, 1);
return c;
}
int
putchar_filtered (int c)
{
return fputc_filtered (c, gdb_stdout);
}
int
fputc_unfiltered (int c, struct ui_file *stream)
{
char buf = c;
ui_file_write (stream, &buf, 1);
return c;
}
int
fputc_filtered (int c, struct ui_file *stream)
{
char buf[2];
buf[0] = c;
buf[1] = 0;
fputs_filtered (buf, stream);
return c;
}
void
puts_debug (char *prefix, char *string, char *suffix)
{
int ch;
static int new_line = 1;
static int return_p = 0;
static char *prev_prefix = "";
static char *prev_suffix = "";
if (*string == '\n')
return_p = 0;
if ((return_p || (strcmp (prev_prefix, prefix) != 0)) && !new_line)
{
fputs_unfiltered (prev_suffix, gdb_stdlog);
fputs_unfiltered ("\n", gdb_stdlog);
fputs_unfiltered (prefix, gdb_stdlog);
}
if (new_line)
{
new_line = 0;
fputs_unfiltered (prefix, gdb_stdlog);
}
prev_prefix = prefix;
prev_suffix = suffix;
while ((ch = *string++) != '\0')
{
switch (ch)
{
default:
if (isprint (ch))
fputc_unfiltered (ch, gdb_stdlog);
else
fprintf_unfiltered (gdb_stdlog, "\\x%02x", ch & 0xff);
break;
case '\\':
fputs_unfiltered ("\\\\", gdb_stdlog);
break;
case '\b':
fputs_unfiltered ("\\b", gdb_stdlog);
break;
case '\f':
fputs_unfiltered ("\\f", gdb_stdlog);
break;
case '\n':
new_line = 1;
fputs_unfiltered ("\\n", gdb_stdlog);
break;
case '\r':
fputs_unfiltered ("\\r", gdb_stdlog);
break;
case '\t':
fputs_unfiltered ("\\t", gdb_stdlog);
break;
case '\v':
fputs_unfiltered ("\\v", gdb_stdlog);
break;
}
return_p = ch == '\r';
}
if (new_line)
{
fputs_unfiltered (suffix, gdb_stdlog);
fputs_unfiltered ("\n", gdb_stdlog);
}
}
static void
vfprintf_maybe_filtered (struct ui_file *stream, const char *format,
va_list args, int filter)
{
char *linebuffer;
struct cleanup *old_cleanups;
xvasprintf (&linebuffer, format, args);
old_cleanups = make_cleanup (xfree, linebuffer);
fputs_maybe_filtered (linebuffer, stream, filter);
do_cleanups (old_cleanups);
}
void
vfprintf_filtered (struct ui_file *stream, const char *format, va_list args)
{
vfprintf_maybe_filtered (stream, format, args, 1);
}
void
vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args)
{
char *linebuffer;
struct cleanup *old_cleanups;
xvasprintf (&linebuffer, format, args);
old_cleanups = make_cleanup (xfree, linebuffer);
fputs_unfiltered (linebuffer, stream);
do_cleanups (old_cleanups);
}
void
vprintf_filtered (const char *format, va_list args)
{
vfprintf_maybe_filtered (gdb_stdout, format, args, 1);
}
void
vprintf_unfiltered (const char *format, va_list args)
{
vfprintf_unfiltered (gdb_stdout, format, args);
}
void
fprintf_filtered (struct ui_file * stream, const char *format,...)
{
va_list args;
va_start (args, format);
vfprintf_filtered (stream, format, args);
va_end (args);
}
void
fprintf_unfiltered (struct ui_file * stream, const char *format,...)
{
va_list args;
va_start (args, format);
vfprintf_unfiltered (stream, format, args);
va_end (args);
}
void
fprintfi_filtered (int spaces, struct ui_file * stream, const char *format,...)
{
va_list args;
va_start (args, format);
print_spaces_filtered (spaces, stream);
vfprintf_filtered (stream, format, args);
va_end (args);
}
void
printf_filtered (const char *format,...)
{
va_list args;
va_start (args, format);
vfprintf_filtered (gdb_stdout, format, args);
va_end (args);
}
void
printf_unfiltered (const char *format,...)
{
va_list args;
va_start (args, format);
vfprintf_unfiltered (gdb_stdout, format, args);
va_end (args);
}
void
printfi_filtered (int spaces, const char *format,...)
{
va_list args;
va_start (args, format);
print_spaces_filtered (spaces, gdb_stdout);
vfprintf_filtered (gdb_stdout, format, args);
va_end (args);
}
void
puts_filtered (const char *string)
{
fputs_filtered (string, gdb_stdout);
}
void
puts_unfiltered (const char *string)
{
fputs_unfiltered (string, gdb_stdout);
}
char *
n_spaces (int n)
{
char *t;
static char *spaces = 0;
static int max_spaces = -1;
if (n > max_spaces)
{
if (spaces)
xfree (spaces);
spaces = (char *) xmalloc (n + 1);
for (t = spaces + n; t != spaces;)
*--t = ' ';
spaces[n] = '\0';
max_spaces = n;
}
return spaces + max_spaces - n;
}
void
print_spaces_filtered (int n, struct ui_file *stream)
{
fputs_filtered (n_spaces (n), stream);
}
void
fprintf_symbol_filtered (struct ui_file *stream, char *name, enum language lang,
int arg_mode)
{
char *demangled;
if (name != NULL)
{
if (!demangle)
{
fputs_filtered (name, stream);
}
else
{
switch (lang)
{
case language_cplus:
demangled = cplus_demangle (name, arg_mode);
break;
case language_java:
demangled = cplus_demangle (name, arg_mode | DMGL_JAVA);
break;
case language_chill:
demangled = chill_demangle (name);
break;
case language_objc:
case language_objcplus:
demangled = objc_demangle (name);
break;
default:
demangled = NULL;
break;
}
fputs_filtered (demangled ? demangled : name, stream);
if (demangled != NULL)
{
xfree (demangled);
}
}
}
}
int
strcmp_iw (const char *string1, const char *string2)
{
while ((*string1 != '\0') && (*string2 != '\0'))
{
while (isspace (*string1))
{
string1++;
}
while (isspace (*string2))
{
string2++;
}
if (*string1 != *string2)
{
break;
}
if (*string1 != '\0')
{
string1++;
string2++;
}
}
return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0');
}
int
subset_compare (char *string_to_compare, char *template_string)
{
int match;
if (template_string != (char *) NULL && string_to_compare != (char *) NULL &&
strlen (string_to_compare) <= strlen (template_string))
match = (strncmp (template_string,
string_to_compare,
strlen (string_to_compare)) == 0);
else
match = 0;
return match;
}
static void pagination_on_command (char *arg, int from_tty);
static void
pagination_on_command (char *arg, int from_tty)
{
pagination_enabled = 1;
}
static void pagination_on_command (char *arg, int from_tty);
static void
pagination_off_command (char *arg, int from_tty)
{
pagination_enabled = 0;
}
void
initialize_utils (void)
{
struct cmd_list_element *c;
c = add_set_cmd ("width", class_support, var_uinteger,
(char *) &chars_per_line,
"Set number of characters gdb thinks are in a line.",
&setlist);
add_show_from_set (c, &showlist);
set_cmd_sfunc (c, set_width_command);
add_show_from_set
(add_set_cmd ("height", class_support,
var_uinteger, (char *) &lines_per_page,
"Set number of lines gdb thinks are in a page.", &setlist),
&showlist);
init_page_info ();
if (!ui_file_isatty (gdb_stdout))
lines_per_page = UINT_MAX;
set_width_command ((char *) NULL, 0, c);
add_show_from_set
(add_set_cmd ("demangle", class_support, var_boolean,
(char *) &demangle,
"Set demangling of encoded C++/ObjC names when displaying symbols.",
&setprintlist),
&showprintlist);
add_show_from_set
(add_set_cmd ("pagination", class_support,
var_boolean, (char *) &pagination_enabled,
"Set state of pagination.", &setlist),
&showlist);
if (xdb_commands)
{
add_com ("am", class_support, pagination_on_command,
"Enable pagination");
add_com ("sm", class_support, pagination_off_command,
"Disable pagination");
}
add_show_from_set
(add_set_cmd ("sevenbit-strings", class_support, var_boolean,
(char *) &sevenbit_strings,
"Set printing of 8-bit characters in strings as \\nnn.",
&setprintlist),
&showprintlist);
add_show_from_set
(add_set_cmd ("asm-demangle", class_support, var_boolean,
(char *) &asm_demangle,
"Set demangling of C++/ObjC names in disassembly listings.",
&setprintlist),
&showprintlist);
}
#ifdef SIGWINCH_HANDLER_BODY
SIGWINCH_HANDLER_BODY
#endif
#define NUMCELLS 16
#define CELLSIZE 32
static char *
get_cell (void)
{
static char buf[NUMCELLS][CELLSIZE];
static int cell = 0;
if (++cell >= NUMCELLS)
cell = 0;
return buf[cell];
}
int
strlen_paddr (void)
{
return (TARGET_ADDR_BIT / 8 * 2);
}
char *
paddr (CORE_ADDR addr)
{
return phex (addr, TARGET_ADDR_BIT / 8);
}
char *
paddr_nz (CORE_ADDR addr)
{
return phex_nz (addr, TARGET_ADDR_BIT / 8);
}
static void
decimal2str (char *paddr_str, char *sign, ULONGEST addr)
{
unsigned long temp[3];
int i = 0;
do
{
temp[i] = addr % (1000 * 1000 * 1000);
addr /= (1000 * 1000 * 1000);
i++;
}
while (addr != 0 && i < (sizeof (temp) / sizeof (temp[0])));
switch (i)
{
case 1:
sprintf (paddr_str, "%s%lu",
sign, temp[0]);
break;
case 2:
sprintf (paddr_str, "%s%lu%09lu",
sign, temp[1], temp[0]);
break;
case 3:
sprintf (paddr_str, "%s%lu%09lu%09lu",
sign, temp[2], temp[1], temp[0]);
break;
default:
internal_error (__FILE__, __LINE__, "failed internal consistency check");
}
}
char *
paddr_u (CORE_ADDR addr)
{
char *paddr_str = get_cell ();
decimal2str (paddr_str, "", addr);
return paddr_str;
}
char *
paddr_d (LONGEST addr)
{
char *paddr_str = get_cell ();
if (addr < 0)
decimal2str (paddr_str, "-", -addr);
else
decimal2str (paddr_str, "", addr);
return paddr_str;
}
static int thirty_two = 32;
char *
phex (ULONGEST l, int sizeof_l)
{
char *str;
switch (sizeof_l)
{
case 8:
str = get_cell ();
sprintf (str, "%08lx%08lx",
(unsigned long) (l >> thirty_two),
(unsigned long) (l & 0xffffffff));
break;
case 4:
str = get_cell ();
sprintf (str, "%08lx", (unsigned long) l);
break;
case 2:
str = get_cell ();
sprintf (str, "%04x", (unsigned short) (l & 0xffff));
break;
default:
str = phex (l, sizeof (l));
break;
}
return str;
}
char *
phex_nz (ULONGEST l, int sizeof_l)
{
char *str;
switch (sizeof_l)
{
case 8:
{
unsigned long high = (unsigned long) (l >> thirty_two);
str = get_cell ();
if (high == 0)
sprintf (str, "%lx", (unsigned long) (l & 0xffffffff));
else
sprintf (str, "%lx%08lx",
high, (unsigned long) (l & 0xffffffff));
break;
}
case 4:
str = get_cell ();
sprintf (str, "%lx", (unsigned long) l);
break;
case 2:
str = get_cell ();
sprintf (str, "%x", (unsigned short) (l & 0xffff));
break;
default:
str = phex_nz (l, sizeof (l));
break;
}
return str;
}
void gdb_check (const char *str, const char *file, unsigned int line, const char *func)
{
error ("assertion failure on line %u of \"%s\" in function \"%s\": %s\n",
line, file, func, str);
}
void gdb_check_fatal (const char *str, const char *file, unsigned int line, const char *func)
{
internal_error (file, line, "assertion failure in function \"%s\": %s\n",
func, str);
}
CORE_ADDR
host_pointer_to_address (void *ptr)
{
if (sizeof (ptr) != TYPE_LENGTH (builtin_type_void_data_ptr))
internal_error (__FILE__, __LINE__,
"core_addr_to_void_ptr: bad cast");
return POINTER_TO_ADDRESS (builtin_type_void_data_ptr, &ptr);
}
void *
address_to_host_pointer (CORE_ADDR addr)
{
void *ptr;
if (sizeof (ptr) != TYPE_LENGTH (builtin_type_void_data_ptr))
internal_error (__FILE__, __LINE__,
"core_addr_to_void_ptr: bad cast");
ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
return ptr;
}
const char *
core_addr_to_string (const CORE_ADDR addr)
{
char *str = get_cell ();
strcpy (str, "0x");
strcat (str, phex (addr, sizeof (addr)));
return str;
}
const char *
core_addr_to_string_nz (const CORE_ADDR addr)
{
char *str = get_cell ();
strcpy (str, "0x");
strcat (str, phex_nz (addr, sizeof (addr)));
return str;
}
CORE_ADDR
string_to_core_addr (const char *my_string)
{
CORE_ADDR addr = 0;
if (my_string[0] == '0' && tolower (my_string[1]) == 'x')
{
int i;
for (i = 2; my_string[i] != '\0'; i++)
{
if (isdigit (my_string[i]))
addr = (my_string[i] - '0') + (addr * 16);
else if (isxdigit (my_string[i]))
addr = (tolower (my_string[i]) - 'a' + 0xa) + (addr * 16);
else
internal_error (__FILE__, __LINE__, "invalid hex");
}
}
else
{
int i;
for (i = 0; my_string[i] != '\0'; i++)
{
if (isdigit (my_string[i]))
addr = (my_string[i] - '0') + (addr * 10);
else
internal_error (__FILE__, __LINE__, "invalid decimal");
}
}
return addr;
}
char *
gdb_realpath (const char *filename)
{
#if defined(HAVE_REALPATH)
# if defined (PATH_MAX)
char buf[PATH_MAX];
# define USE_REALPATH
# elif defined (MAXPATHLEN)
char buf[MAXPATHLEN];
# define USE_REALPATH
# elif defined (HAVE_UNISTD_H) && defined(HAVE_ALLOCA)
char *buf = alloca ((size_t)pathconf ("/", _PC_PATH_MAX));
# define USE_REALPATH
# endif
#endif
#if defined(USE_REALPATH)
char *rp = realpath (filename, buf);
return xstrdup (rp ? rp : filename);
#elif defined(HAVE_CANONICALIZE_FILE_NAME)
char *rp = canonicalize_file_name (filename);
if (rp == NULL)
return xstrdup (filename);
else
return rp;
#else
return xstrdup (filename);
#endif
}
char *
xfullpath (const char *filename)
{
const char *base_name = lbasename (filename);
char *dir_name;
char *real_path;
char *result;
if (base_name == filename)
return xstrdup (filename);
dir_name = alloca ((size_t) (base_name - filename + 2));
strncpy (dir_name, filename, base_name - filename);
dir_name[base_name - filename] = '\000';
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
if (strlen (dir_name) == 2 &&
isalpha (dir_name[0]) && dir_name[1] == ':')
{
dir_name[2] = '.';
dir_name[3] = '\000';
}
#endif
real_path = gdb_realpath (dir_name);
if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1]))
result = concat (real_path, base_name, NULL);
else
result = concat (real_path, SLASH_STRING, base_name, NULL);
xfree (real_path);
return result;
}