/* General utility routines for GDB, the GNU debugger.
- Copyright 1986, 89, 90, 91, 92, 95, 96, 1998 Free Software Foundation, Inc.
+ Copyright 1986, 1989, 1990-1992, 1995, 1996, 1998, 2000
+ Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include <ctype.h>
#include "gdb_string.h"
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
+#include "event-top.h"
#ifdef HAVE_CURSES_H
#include <curses.h>
#include <readline/readline.h>
+#undef XMALLOC
+#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
+
/* readline defines this. */
#undef savestring
void (*error_begin_hook) PARAMS ((void));
+/* Holds the last error message issued by gdb */
+
+static struct ui_file *gdb_lasterr;
+
/* Prototypes for local functions */
-static void vfprintf_maybe_filtered PARAMS ((GDB_FILE *, const char *,
- va_list, int));
+static void vfprintf_maybe_filtered (struct ui_file *, const char *,
+ va_list, int);
-static void fputs_maybe_filtered PARAMS ((const char *, GDB_FILE *, int));
+static void fputs_maybe_filtered (const char *, struct ui_file *, int);
#if defined (USE_MMALLOC) && !defined (NO_MMCHECK)
static void malloc_botch PARAMS ((void));
#endif
-static void
-fatal_dump_core PARAMS ((char *,...));
-
static void
prompt_for_continue PARAMS ((void));
static void
set_width PARAMS ((void));
-/* If this definition isn't overridden by the header files, assume
- that isatty and fileno exist on this system. */
-#ifndef ISATTY
-#define ISATTY(FP) (isatty (fileno (FP)))
-#endif
-
-#ifndef GDB_FILE_ISATTY
-#define GDB_FILE_ISATTY(GDB_FILE_PTR) (gdb_file_isatty(GDB_FILE_PTR))
-#endif
-
/* Chain of cleanup actions established with make_cleanup,
to be executed if an error happens. */
static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */
static struct cleanup *run_cleanup_chain; /* cleaned up on each 'run' */
static struct cleanup *exec_cleanup_chain; /* cleaned up on each execution command */
+/* cleaned up on each error from within an execution command */
+static struct cleanup *exec_error_cleanup_chain;
/* Pointer to what is left to do for an execution command after the
target stops. Used only in asynchronous mode, by targets that
support async execution. The finish and until commands use it. So
does the target extended-remote command. */
struct continuation *cmd_continuation;
+struct continuation *intermediate_continuation;
/* Nonzero if we have job control. */
return make_my_cleanup (&exec_cleanup_chain, function, arg);
}
+struct cleanup *
+make_exec_error_cleanup (function, arg)
+ void (*function) PARAMS ((PTR));
+ PTR arg;
+{
+ return make_my_cleanup (&exec_error_cleanup_chain, function, arg);
+}
+
static void
do_freeargv (arg)
void *arg;
return make_my_cleanup (&cleanup_chain, do_freeargv, arg);
}
+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);
+}
+
struct cleanup *
make_my_cleanup (pmy_chain, function, arg)
struct cleanup **pmy_chain;
do_my_cleanups (&exec_cleanup_chain, old_chain);
}
+void
+do_exec_error_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ do_my_cleanups (&exec_error_cleanup_chain, old_chain);
+}
+
void
do_my_cleanups (pmy_chain, old_chain)
register struct cleanup **pmy_chain;
discard_my_cleanups (&final_cleanup_chain, old_chain);
}
+void
+discard_exec_error_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ discard_my_cleanups (&exec_error_cleanup_chain, old_chain);
+}
+
void
discard_my_cleanups (pmy_chain, old_chain)
register struct cleanup **pmy_chain;
}
/* Add a continuation to the continuation list, the gloabl list
- cmd_continuation. */
+ cmd_continuation. The new continuation will be added at the front.*/
void
add_continuation (continuation_hook, arg_list)
void (*continuation_hook) PARAMS ((struct continuation_arg *));
}
/* Walk down the cmd_continuation list, and execute all the
- continuations. */
+ continuations. There is a problem though. In some cases new
+ continuations may be added while we are in the middle of this
+ loop. If this happens they will be added in the front, and done
+ before we have a chance of exhausting those that were already
+ there. We need to then save the beginning of the list in a pointer
+ and do the continuations from there on, instead of using the
+ global beginning of list as our iteration pointer.*/
void
do_all_continuations ()
+{
+ struct continuation *continuation_ptr;
+ struct continuation *saved_continuation;
+
+ /* Copy the list header into another pointer, and set the global
+ list header to null, so that the global list can change as a side
+ effect of invoking the continuations and the processing of
+ the preexisting continuations will not be affected. */
+ continuation_ptr = cmd_continuation;
+ cmd_continuation = NULL;
+
+ /* Work now on the list we have set aside. */
+ while (continuation_ptr)
+ {
+ (continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
+ saved_continuation = continuation_ptr;
+ continuation_ptr = continuation_ptr->next;
+ free (saved_continuation);
+ }
+}
+
+/* Walk down the cmd_continuation list, and get rid of all the
+ continuations. */
+void
+discard_all_continuations ()
{
struct continuation *continuation_ptr;
while (cmd_continuation)
{
- (cmd_continuation->continuation_hook) (cmd_continuation->arg_list);
continuation_ptr = cmd_continuation;
cmd_continuation = continuation_ptr->next;
free (continuation_ptr);
}
}
+
+/* Add a continuation to the continuation list, the gloabl list
+ intermediate_continuation. The new continuation will be added at the front.*/
+void
+add_intermediate_continuation (continuation_hook, arg_list)
+ void (*continuation_hook) PARAMS ((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;
+}
+
+/* Walk down the cmd_continuation list, and execute all the
+ continuations. There is a problem though. In some cases new
+ continuations may be added while we are in the middle of this
+ loop. If this happens they will be added in the front, and done
+ before we have a chance of exhausting those that were already
+ there. We need to then save the beginning of the list in a pointer
+ and do the continuations from there on, instead of using the
+ global beginning of list as our iteration pointer.*/
+void
+do_all_intermediate_continuations ()
+{
+ struct continuation *continuation_ptr;
+ struct continuation *saved_continuation;
+
+ /* Copy the list header into another pointer, and set the global
+ list header to null, so that the global list can change as a side
+ effect of invoking the continuations and the processing of
+ the preexisting continuations will not be affected. */
+ continuation_ptr = intermediate_continuation;
+ intermediate_continuation = NULL;
+
+ /* Work now on the list we have set aside. */
+ while (continuation_ptr)
+ {
+ (continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
+ saved_continuation = continuation_ptr;
+ continuation_ptr = continuation_ptr->next;
+ free (saved_continuation);
+ }
+}
+
+/* Walk down the cmd_continuation list, and get rid of all the
+ continuations. */
+void
+discard_all_intermediate_continuations ()
+{
+ struct continuation *continuation_ptr;
+
+ while (intermediate_continuation)
+ {
+ continuation_ptr = intermediate_continuation;
+ intermediate_continuation = continuation_ptr->next;
+ free (continuation_ptr);
+ }
+}
+
\f
/* Print a warning message. Way to use this is to call warning_begin,
The primary difference between warnings and errors is that a warning
does not force the return to command level. */
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
warning (const char *string,...)
-#else
-warning (va_alist)
- va_dcl
-#endif
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, string);
-#else
- char *string;
-
- va_start (args);
- string = va_arg (args, char *);
-#endif
if (warning_hook)
(*warning_hook) (string, args);
else
The first argument STRING is the error message, used as a fprintf string,
and the remaining args are passed as arguments to it. */
-/* VARARGS */
NORETURN void
-#ifdef ANSI_PROTOTYPES
+verror (const char *string, va_list args)
+{
+ char *err_string;
+ struct cleanup *err_string_cleanup;
+ /* FIXME: cagney/1999-11-10: All error calls should come here.
+ Unfortunatly some code uses the sequence: error_begin(); print
+ error message; return_to_top_level. That code should be
+ flushed. */
+ error_begin ();
+ /* NOTE: It's tempting to just do the following...
+ vfprintf_filtered (gdb_stderr, string, args);
+ and then follow with a similar looking statement to cause the message
+ to also go to gdb_lasterr. But if we do this, we'll be traversing the
+ va_list twice which works on some platforms and fails miserably on
+ others. */
+ /* Save it as the last error */
+ ui_file_rewind (gdb_lasterr);
+ vfprintf_filtered (gdb_lasterr, string, args);
+ /* Retrieve the last error and print it to gdb_stderr */
+ err_string = error_last_message ();
+ err_string_cleanup = make_cleanup (free, err_string);
+ fputs_filtered (err_string, gdb_stderr);
+ fprintf_filtered (gdb_stderr, "\n");
+ do_cleanups (err_string_cleanup);
+ return_to_top_level (RETURN_ERROR);
+}
+
+NORETURN void
error (const char *string,...)
-#else
-error (va_alist)
- va_dcl
-#endif
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, string);
-#else
- va_start (args);
-#endif
- if (error_hook)
- (*error_hook) ();
- else
- {
- error_begin ();
-#ifdef ANSI_PROTOTYPES
- vfprintf_filtered (gdb_stderr, string, args);
-#else
- {
- char *string1;
-
- string1 = va_arg (args, char *);
- vfprintf_filtered (gdb_stderr, string1, args);
- }
-#endif
- fprintf_filtered (gdb_stderr, "\n");
- va_end (args);
- return_to_top_level (RETURN_ERROR);
- }
+ verror (string, args);
+ va_end (args);
}
+NORETURN void
+error_stream (struct ui_file *stream)
+{
+ long size;
+ char *msg = ui_file_xstrdup (stream, &size);
+ make_cleanup (free, msg);
+ error ("%s", msg);
+}
-/* Print an error message and exit reporting failure.
- This is for a error that we cannot continue from.
- The arguments are printed a la printf.
+/* Get the last error message issued by gdb */
- This function cannot be declared volatile (NORETURN) in an
- ANSI environment because exit() is not declared volatile. */
+char *
+error_last_message (void)
+{
+ long len;
+ return ui_file_xstrdup (gdb_lasterr, &len);
+}
+
+/* This is to be called by main() at the very beginning */
-/* VARARGS */
-NORETURN void
-#ifdef ANSI_PROTOTYPES
-fatal (char *string,...)
-#else
-fatal (va_alist)
- va_dcl
-#endif
+void
+error_init (void)
{
- va_list args;
-#ifdef ANSI_PROTOTYPES
- va_start (args, string);
-#else
- char *string;
- va_start (args);
- string = va_arg (args, char *);
-#endif
- fprintf_unfiltered (gdb_stderr, "\ngdb: ");
- vfprintf_unfiltered (gdb_stderr, string, args);
- fprintf_unfiltered (gdb_stderr, "\n");
- va_end (args);
- exit (1);
+ gdb_lasterr = mem_fileopen ();
}
-/* Print an error message and exit, dumping core.
- The arguments are printed a la printf (). */
+/* Print a message reporting an internal error. Ask the user if they
+ want to continue, dump core, or just exit. */
-/* VARARGS */
-static void
-#ifdef ANSI_PROTOTYPES
-fatal_dump_core (char *string,...)
-#else
-fatal_dump_core (va_alist)
- va_dcl
-#endif
+NORETURN void
+internal_verror (const char *fmt, va_list ap)
{
- va_list args;
-#ifdef ANSI_PROTOTYPES
- va_start (args, string);
-#else
- char *string;
+ static char msg[] = "Internal GDB error: recursive internal error.\n";
+ static int dejavu = 0;
+ int continue_p;
+ int dump_core_p;
- va_start (args);
- string = va_arg (args, char *);
-#endif
- /* "internal error" is always correct, since GDB should never dump
- core, no matter what the input. */
- fprintf_unfiltered (gdb_stderr, "\ngdb internal error: ");
- vfprintf_unfiltered (gdb_stderr, string, args);
- fprintf_unfiltered (gdb_stderr, "\n");
- va_end (args);
+ /* don't allow infinite error recursion. */
+ 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);
+ }
- signal (SIGQUIT, SIG_DFL);
- kill (getpid (), SIGQUIT);
- /* We should never get here, but just in case... */
- exit (1);
+ /* Try to get the message out */
+ fputs_unfiltered ("gdb-internal-error: ", gdb_stderr);
+ vfprintf_unfiltered (gdb_stderr, fmt, ap);
+ fputs_unfiltered ("\n", gdb_stderr);
+
+ /* Default (no case) is to quit GDB. When in batch mode this
+ lessens the likelhood of GDB going into an infinate loop. */
+ continue_p = query ("\
+An internal GDB error was detected. This may make make further\n\
+debugging unreliable. Continue this debugging session? ");
+
+ /* Default (no case) is to not dump core. Lessen the chance of GDB
+ leaving random core files around. */
+ dump_core_p = query ("\
+Create a core file containing the current state of GDB? ");
+
+ if (continue_p)
+ {
+ if (dump_core_p)
+ {
+ if (fork () == 0)
+ abort ();
+ }
+ }
+ else
+ {
+ if (dump_core_p)
+ abort ();
+ else
+ exit (1);
+ }
+
+ dejavu = 0;
+ return_to_top_level (RETURN_ERROR);
+}
+
+NORETURN void
+internal_error (char *string, ...)
+{
+ va_list ap;
+ va_start (ap, string);
+ internal_verror (string, ap);
+ va_end (ap);
}
/* The strerror() function can return NULL for errno values that are
if (quit_pre_print)
fprintf_unfiltered (gdb_stderr, quit_pre_print);
+#ifdef __MSDOS__
+ /* No steenking SIGINT will ever be coming our way when the
+ program is resumed. Don't lie. */
+ fprintf_unfiltered (gdb_stderr, "Quit\n");
+#else
if (job_control
/* If there is no terminal switching for this target, then we can't
possibly get screwed by the lack of job control. */
else
fprintf_unfiltered (gdb_stderr,
"Quit (expect signal SIGINT when the program is resumed)\n");
+#endif
return_to_top_level (RETURN_QUIT);
}
-#if defined(__GO32__)
-
-/* In the absence of signals, poll keyboard for a quit.
- Called from #define QUIT pollquit() in xm-go32.h. */
-
-void
-notice_quit ()
-{
- if (kbhit ())
- switch (getkey ())
- {
- case 1:
- quit_flag = 1;
- break;
- case 2:
- immediate_quit = 2;
- break;
- default:
- /* We just ignore it */
- /* FIXME!! Don't think this actually works! */
- fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n");
- break;
- }
-}
-
-#elif defined(_MSC_VER) /* should test for wingdb instead? */
+#if defined(_MSC_VER) /* should test for wingdb instead? */
/*
* Windows translates all keyboard and mouse events
immediate_quit = 1;
}
-#else /* !defined(__GO32__) && !defined(_MSC_VER) */
+#else /* !defined(_MSC_VER) */
void
notice_quit ()
/* Done by signals */
}
-#endif /* !defined(__GO32__) && !defined(_MSC_VER) */
+#endif /* !defined(_MSC_VER) */
/* Control C comes here */
void
#if !defined (USE_MMALLOC)
+void *
+mcalloc (void *md, size_t number, size_t size)
+{
+ return calloc (number, size);
+}
+
PTR
mmalloc (md, size)
PTR md;
static void
malloc_botch ()
{
- fatal_dump_core ("Memory corruption");
+ fprintf_unfiltered (gdb_stderr, "Memory corruption\n");
+ abort ();
}
/* Attempt to install hooks in mmalloc/mrealloc/mfree for the heap specified
{
if (size > 0)
{
- fatal ("virtual memory exhausted: can't allocate %ld bytes.", size);
+ internal_error ("virtual memory exhausted: can't allocate %ld bytes.", size);
}
else
{
- fatal ("virtual memory exhausted.");
+ internal_error ("virtual memory exhausted.");
}
}
return (xmmalloc ((PTR) NULL, size));
}
+/* Like calloc but get error if no storage available */
+
+PTR
+xcalloc (size_t number, size_t size)
+{
+ void *mem = mcalloc (NULL, number, size);
+ if (mem == NULL)
+ nomem (number * size);
+ return mem;
+}
+
/* Like mrealloc but get error if no storage available. */
PTR
void
print_spaces (n, file)
register int n;
- register GDB_FILE *file;
+ register struct ui_file *file;
{
fputs_unfiltered (n_spaces (n), file);
}
/* Print a host address. */
void
-gdb_print_address (addr, stream)
- PTR addr;
- GDB_FILE *stream;
+gdb_print_host_address (void *addr, struct ui_file *stream)
{
/* We could use the %p conversion specifier to fprintf if we had any
/* VARARGS */
int
-#ifdef ANSI_PROTOTYPES
query (char *ctlstr,...)
-#else
-query (va_alist)
- va_dcl
-#endif
{
va_list args;
register int answer;
register int ans2;
int retval;
-#ifdef ANSI_PROTOTYPES
va_start (args, ctlstr);
-#else
- char *ctlstr;
- va_start (args);
- ctlstr = va_arg (args, char *);
-#endif
if (query_hook)
{
be call for printing things which are independent of the language
of the program being debugged. */
-static void printchar PARAMS ((int c, void (*do_fputs) (const char *, GDB_FILE*), void (*do_fprintf) (GDB_FILE*, const char *, ...), GDB_FILE *stream, int quoter));
+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);
static void
printchar (c, do_fputs, do_fprintf, stream, quoter)
int c;
- void (*do_fputs) PARAMS ((const char *, GDB_FILE*));
- void (*do_fprintf) PARAMS ((GDB_FILE*, const char *, ...));
- GDB_FILE *stream;
+ void (*do_fputs) PARAMS ((const char *, struct ui_file*));
+ void (*do_fprintf) PARAMS ((struct ui_file*, const char *, ...));
+ struct ui_file *stream;
int quoter;
{
fputstr_filtered (str, quoter, stream)
const char *str;
int quoter;
- GDB_FILE *stream;
+ struct ui_file *stream;
{
while (*str)
printchar (*str++, fputs_filtered, fprintf_filtered, stream, quoter);
fputstr_unfiltered (str, quoter, stream)
const char *str;
int quoter;
- GDB_FILE *stream;
+ struct ui_file *stream;
{
while (*str)
printchar (*str++, fputs_unfiltered, fprintf_unfiltered, stream, quoter);
const char *str;
int n;
int quoter;
- GDB_FILE *stream;
+ struct ui_file *stream;
{
int i;
for (i = 0; i < n; i++)
/* Number of lines per page or UINT_MAX if paging is disabled. */
static unsigned int lines_per_page;
-/* Number of chars per line or UNIT_MAX is line folding is disabled. */
+/* Number of chars per line or UNIT_MAX if line folding is disabled. */
static unsigned int chars_per_line;
/* Current count of lines printed on this page, chars on this line. */
static unsigned int lines_printed, chars_printed;
#endif
#endif
/* If the output is not a terminal, don't paginate it. */
- if (!GDB_FILE_ISATTY (gdb_stdout))
+ if (!ui_file_isatty (gdb_stdout))
lines_per_page = UINT_MAX;
} /* the command_line_version */
set_width ();
++p;
if (p[0] == 'q')
{
- if (!async_p)
+ if (!event_loop_p)
request_quit (SIGINT);
else
async_request_quit (0);
}
-/* ``struct gdb_file'' implementation that maps directly onto
- <stdio.h>'s FILE. */
-
-static gdb_file_fputs_ftype stdio_file_fputs;
-static gdb_file_isatty_ftype stdio_file_isatty;
-static gdb_file_delete_ftype stdio_file_delete;
-static struct gdb_file *stdio_file_new PARAMS ((FILE * file, int close_p));
-static gdb_file_flush_ftype stdio_file_flush;
-
-static int stdio_file_magic;
-
-struct stdio_file
- {
- int *magic;
- FILE *file;
- int close_p;
- };
-
-static struct gdb_file *
-stdio_file_new (file, close_p)
- FILE *file;
- int close_p;
-{
- struct gdb_file *gdb_file = gdb_file_new ();
- struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
- stdio->magic = &stdio_file_magic;
- stdio->file = file;
- stdio->close_p = close_p;
- set_gdb_file_data (gdb_file, stdio, stdio_file_delete);
- set_gdb_file_flush (gdb_file, stdio_file_flush);
- set_gdb_file_fputs (gdb_file, stdio_file_fputs);
- set_gdb_file_isatty (gdb_file, stdio_file_isatty);
- return gdb_file;
-}
-
-static void
-stdio_file_delete (file)
- struct gdb_file *file;
-{
- struct stdio_file *stdio = gdb_file_data (file);
- if (stdio->magic != &stdio_file_magic)
- error ("Internal error: bad magic number");
- if (stdio->close_p)
- {
- fclose (stdio->file);
- }
- free (stdio);
-}
-
-static void
-stdio_file_flush (file)
- struct gdb_file *file;
-{
- struct stdio_file *stdio = gdb_file_data (file);
- if (stdio->magic != &stdio_file_magic)
- error ("Internal error: bad magic number");
- fflush (stdio->file);
-}
-
-static void
-stdio_file_fputs (linebuffer, file)
- const char *linebuffer;
- struct gdb_file *file;
-{
- struct stdio_file *stdio = gdb_file_data (file);
- if (stdio->magic != &stdio_file_magic)
- error ("Internal error: bad magic number");
- fputs (linebuffer, stdio->file);
-}
-
-static int
-stdio_file_isatty (file)
- struct gdb_file *file;
-{
- struct stdio_file *stdio = gdb_file_data (file);
- if (stdio->magic != &stdio_file_magic)
- error ("Internal error: bad magic number");
- return (isatty (fileno (stdio->file)));
-}
-
-/* Like fdopen(). Create a gdb_file from a previously opened FILE. */
-
-struct gdb_file *
-stdio_fileopen (file)
- FILE *file;
-{
- return stdio_file_new (file, 0);
-}
-
-
-/* A ``struct gdb_file'' that is compatible with all the legacy
- code. */
-
-static gdb_file_flush_ftype tui_file_flush;
-extern gdb_file_fputs_ftype tui_file_fputs;
-static gdb_file_isatty_ftype tui_file_isatty;
-static gdb_file_rewind_ftype tui_file_rewind;
-static gdb_file_put_ftype tui_file_put;
-static gdb_file_delete_ftype tui_file_delete;
-static struct gdb_file *tui_file_new PARAMS ((void));
-static int tui_file_magic;
-
-static struct gdb_file *
-tui_file_new ()
-{
- struct tui_stream *tui = xmalloc (sizeof (struct tui_stream));
- struct gdb_file *file = gdb_file_new ();
- set_gdb_file_data (file, tui, tui_file_delete);
- set_gdb_file_flush (file, tui_file_flush);
- set_gdb_file_fputs (file, tui_file_fputs);
- set_gdb_file_isatty (file, tui_file_isatty);
- set_gdb_file_rewind (file, tui_file_rewind);
- set_gdb_file_put (file, tui_file_put);
- tui->ts_magic = &tui_file_magic;
- return file;
-}
-
-static void
-tui_file_delete (file)
- struct gdb_file *file;
-{
- struct tui_stream *tmpstream = gdb_file_data (file);
- if (tmpstream->ts_magic != &tui_file_magic)
- error ("Internal error: bad magic number");
- if ((tmpstream->ts_streamtype == astring) &&
- (tmpstream->ts_strbuf != NULL))
- {
- free (tmpstream->ts_strbuf);
- }
- free (tmpstream);
-}
-
-struct gdb_file *
-tui_fileopen (stream)
- FILE *stream;
-{
- struct gdb_file *file = tui_file_new ();
- struct tui_stream *tmpstream = gdb_file_data (file);
- tmpstream->ts_streamtype = afile;
- tmpstream->ts_filestream = stream;
- tmpstream->ts_strbuf = NULL;
- tmpstream->ts_buflen = 0;
- return file;
-}
-
-static int
-tui_file_isatty (file)
- struct gdb_file *file;
-{
- struct tui_stream *stream = gdb_file_data (file);
- if (stream->ts_magic != &tui_file_magic)
- error ("Internal error: bad magic number");
- if (stream->ts_streamtype == afile)
- return (isatty (fileno (stream->ts_filestream)));
- else
- return 0;
-}
-
-static void
-tui_file_rewind (file)
- struct gdb_file *file;
-{
- struct tui_stream *stream = gdb_file_data (file);
- if (stream->ts_magic != &tui_file_magic)
- error ("Internal error: bad magic number");
- stream->ts_strbuf[0] = '\0';
-}
-
-static void
-tui_file_put (file, dest)
- struct gdb_file *file;
- struct gdb_file *dest;
-{
- struct tui_stream *stream = gdb_file_data (file);
- if (stream->ts_magic != &tui_file_magic)
- error ("Internal error: bad magic number");
- if (stream->ts_streamtype == astring)
- {
- fputs_unfiltered (stream->ts_strbuf, dest);
- }
-}
-
-GDB_FILE *
-gdb_file_init_astring (n)
- int n;
-{
- struct gdb_file *file = tui_file_new ();
- struct tui_stream *tmpstream = gdb_file_data (file);
- if (tmpstream->ts_magic != &tui_file_magic)
- error ("Internal error: bad magic number");
-
- tmpstream->ts_streamtype = astring;
- tmpstream->ts_filestream = NULL;
- if (n > 0)
- {
- tmpstream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
- tmpstream->ts_strbuf[0] = '\0';
- }
- else
- tmpstream->ts_strbuf = NULL;
- tmpstream->ts_buflen = n;
-
- return file;
-}
-
-void
-gdb_file_deallocate (streamptr)
- GDB_FILE **streamptr;
-{
- gdb_file_delete (*streamptr);
- *streamptr = NULL;
-}
-
-char *
-gdb_file_get_strbuf (file)
- GDB_FILE *file;
-{
- struct tui_stream *stream = gdb_file_data (file);
- if (stream->ts_magic != &tui_file_magic)
- error ("Internal error: bad magic number");
- return (stream->ts_strbuf);
-}
-
-/* adjust the length of the buffer by the amount necessary
- to accomodate appending a string of length N to the buffer contents */
-void
-gdb_file_adjust_strbuf (n, file)
- int n;
- GDB_FILE *file;
-{
- struct tui_stream *stream = gdb_file_data (file);
- int non_null_chars;
- if (stream->ts_magic != &tui_file_magic)
- error ("Internal error: bad magic number");
-
- if (stream->ts_streamtype != astring)
- return;
-
- if (stream->ts_strbuf)
- {
- /* There is already a buffer allocated */
- non_null_chars = strlen (stream->ts_strbuf);
-
- if (n > (stream->ts_buflen - non_null_chars - 1))
- {
- stream->ts_buflen = n + non_null_chars + 1;
- stream->ts_strbuf = xrealloc (stream->ts_strbuf, stream->ts_buflen);
- }
- }
- else
- /* No buffer yet, so allocate one of the desired size */
- stream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
-}
-
-GDB_FILE *
-gdb_fopen (name, mode)
- char *name;
- char *mode;
-{
- FILE *f = fopen (name, mode);
- if (f == NULL)
- return NULL;
- return stdio_file_new (f, 1);
-}
-
-static void
-tui_file_flush (file)
- GDB_FILE *file;
-{
- struct tui_stream *stream = gdb_file_data (file);
- if (stream->ts_magic != &tui_file_magic)
- error ("Internal error: bad magic number");
- if (flush_hook
- && (file == gdb_stdout
- || file == gdb_stderr))
- {
- flush_hook (file);
- return;
- }
-
- fflush (stream->ts_filestream);
-}
-
-void
-gdb_fclose (streamptr)
- GDB_FILE **streamptr;
-{
- gdb_file_delete (*streamptr);
- *streamptr = NULL;
-}
-
-
-/* Implement the ``struct gdb_file'' object. */
-
-static gdb_file_isatty_ftype null_file_isatty;
-static gdb_file_fputs_ftype null_file_fputs;
-static gdb_file_flush_ftype null_file_flush;
-static gdb_file_delete_ftype null_file_delete;
-static gdb_file_rewind_ftype null_file_rewind;
-static gdb_file_put_ftype null_file_put;
-
-struct gdb_file
- {
- gdb_file_flush_ftype *to_flush;
- gdb_file_fputs_ftype *to_fputs;
- gdb_file_delete_ftype *to_delete;
- gdb_file_isatty_ftype *to_isatty;
- gdb_file_rewind_ftype *to_rewind;
- gdb_file_put_ftype *to_put;
- void *to_data;
- };
-
-struct gdb_file *
-gdb_file_new ()
-{
- struct gdb_file *file = xmalloc (sizeof (struct gdb_file));
- set_gdb_file_data (file, NULL, null_file_delete);
- set_gdb_file_flush (file, null_file_flush);
- set_gdb_file_fputs (file, null_file_fputs);
- set_gdb_file_isatty (file, null_file_isatty);
- set_gdb_file_rewind (file, null_file_rewind);
- set_gdb_file_put (file, null_file_put);
- return file;
-}
-
-void
-gdb_file_delete (file)
- struct gdb_file *file;
-{
- file->to_delete (file);
- free (file);
-}
-
-static int
-null_file_isatty (file)
- struct gdb_file *file;
-{
- return 0;
-}
-
-static void
-null_file_rewind (file)
- struct gdb_file *file;
-{
- return;
-}
-
-static void
-null_file_put (file, src)
- struct gdb_file *file;
- struct gdb_file *src;
-{
- return;
-}
-
-static void
-null_file_flush (file)
- struct gdb_file *file;
-{
- return;
-}
-
-static void
-null_file_fputs (buf, file)
- const char *buf;
- struct gdb_file *file;
-{
- return;
-}
-
-static void
-null_file_delete (file)
- struct gdb_file *file;
-{
- return;
-}
-
-void *
-gdb_file_data (file)
- struct gdb_file *file;
-{
- return file->to_data;
-}
-
-void
-gdb_flush (file)
- struct gdb_file *file;
-{
- file->to_flush (file);
-}
-
-int
-gdb_file_isatty (file)
- struct gdb_file *file;
-{
- return file->to_isatty (file);
-}
-
-void
-gdb_file_rewind (file)
- struct gdb_file *file;
-{
- file->to_rewind (file);
-}
-
-void
-gdb_file_put (file, dest)
- struct gdb_file *file;
- struct gdb_file *dest;
-{
- file->to_put (file, dest);
-}
-
-void
-fputs_unfiltered (buf, file)
- const char *buf;
- struct gdb_file *file;
-{
- file->to_fputs (buf, file);
-}
-
-void
-set_gdb_file_flush (file, flush)
- struct gdb_file *file;
- gdb_file_flush_ftype *flush;
-{
- file->to_flush = flush;
-}
-
-void
-set_gdb_file_isatty (file, isatty)
- struct gdb_file *file;
- gdb_file_isatty_ftype *isatty;
-{
- file->to_isatty = isatty;
-}
-
-void
-set_gdb_file_rewind (file, rewind)
- struct gdb_file *file;
- gdb_file_rewind_ftype *rewind;
-{
- file->to_rewind = rewind;
-}
-
-void
-set_gdb_file_put (file, put)
- struct gdb_file *file;
- gdb_file_put_ftype *put;
-{
- file->to_put = put;
-}
-
-void
-set_gdb_file_fputs (file, fputs)
- struct gdb_file *file;
- gdb_file_fputs_ftype *fputs;
-{
- file->to_fputs = fputs;
-}
-
-void
-set_gdb_file_data (file, data, delete)
- struct gdb_file *file;
- void *data;
- gdb_file_delete_ftype *delete;
-{
- file->to_data = data;
- file->to_delete = delete;
-}
-
/* Like fputs but if FILTER is true, pause after every screenful.
Regardless of FILTER can wrap at points other than the final
static void
fputs_maybe_filtered (linebuffer, stream, filter)
const char *linebuffer;
- GDB_FILE *stream;
+ struct ui_file *stream;
int filter;
{
const char *lineptr;
void
fputs_filtered (linebuffer, stream)
const char *linebuffer;
- GDB_FILE *stream;
+ struct ui_file *stream;
{
fputs_maybe_filtered (linebuffer, stream, 1);
}
putchar_unfiltered (c)
int c;
{
- char buf[2];
-
- buf[0] = c;
- buf[1] = 0;
- fputs_unfiltered (buf, gdb_stdout);
+ char buf = c;
+ ui_file_write (gdb_stdout, &buf, 1);
return c;
}
int
fputc_unfiltered (c, stream)
int c;
- GDB_FILE *stream;
+ struct ui_file *stream;
{
- char buf[2];
-
- buf[0] = c;
- buf[1] = 0;
- fputs_unfiltered (buf, stream);
+ char buf = c;
+ ui_file_write (stream, &buf, 1);
return c;
}
int
fputc_filtered (c, stream)
int c;
- GDB_FILE *stream;
+ struct ui_file *stream;
{
char buf[2];
static void
vfprintf_maybe_filtered (stream, format, args, filter)
- GDB_FILE *stream;
+ struct ui_file *stream;
const char *format;
va_list args;
int filter;
void
vfprintf_filtered (stream, format, args)
- GDB_FILE *stream;
+ struct ui_file *stream;
const char *format;
va_list args;
{
void
vfprintf_unfiltered (stream, format, args)
- GDB_FILE *stream;
+ struct ui_file *stream;
const char *format;
va_list args;
{
vfprintf_unfiltered (gdb_stdout, format, args);
}
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-fprintf_filtered (GDB_FILE * stream, const char *format,...)
-#else
-fprintf_filtered (va_alist)
- va_dcl
-#endif
+fprintf_filtered (struct ui_file * stream, const char *format,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- GDB_FILE *stream;
- char *format;
-
- va_start (args);
- stream = va_arg (args, GDB_FILE *);
- format = va_arg (args, char *);
-#endif
vfprintf_filtered (stream, format, args);
va_end (args);
}
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-fprintf_unfiltered (GDB_FILE * stream, const char *format,...)
-#else
-fprintf_unfiltered (va_alist)
- va_dcl
-#endif
+fprintf_unfiltered (struct ui_file * stream, const char *format,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- GDB_FILE *stream;
- char *format;
-
- va_start (args);
- stream = va_arg (args, GDB_FILE *);
- format = va_arg (args, char *);
-#endif
vfprintf_unfiltered (stream, format, args);
va_end (args);
}
/* Like fprintf_filtered, but prints its result indented.
Called as fprintfi_filtered (spaces, stream, format, ...); */
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
-fprintfi_filtered (int spaces, GDB_FILE * stream, const char *format,...)
-#else
-fprintfi_filtered (va_alist)
- va_dcl
-#endif
+fprintfi_filtered (int spaces, struct ui_file * stream, const char *format,...)
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- int spaces;
- GDB_FILE *stream;
- char *format;
-
- va_start (args);
- spaces = va_arg (args, int);
- stream = va_arg (args, GDB_FILE *);
- format = va_arg (args, char *);
-#endif
print_spaces_filtered (spaces, stream);
vfprintf_filtered (stream, format, args);
}
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
printf_filtered (const char *format,...)
-#else
-printf_filtered (va_alist)
- va_dcl
-#endif
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- char *format;
-
- va_start (args);
- format = va_arg (args, char *);
-#endif
vfprintf_filtered (gdb_stdout, format, args);
va_end (args);
}
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
printf_unfiltered (const char *format,...)
-#else
-printf_unfiltered (va_alist)
- va_dcl
-#endif
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- char *format;
-
- va_start (args);
- format = va_arg (args, char *);
-#endif
vfprintf_unfiltered (gdb_stdout, format, args);
va_end (args);
}
/* Like printf_filtered, but prints it's result indented.
Called as printfi_filtered (spaces, format, ...); */
-/* VARARGS */
void
-#ifdef ANSI_PROTOTYPES
printfi_filtered (int spaces, const char *format,...)
-#else
-printfi_filtered (va_alist)
- va_dcl
-#endif
{
va_list args;
-#ifdef ANSI_PROTOTYPES
va_start (args, format);
-#else
- int spaces;
- char *format;
-
- va_start (args);
- spaces = va_arg (args, int);
- format = va_arg (args, char *);
-#endif
print_spaces_filtered (spaces, gdb_stdout);
vfprintf_filtered (gdb_stdout, format, args);
va_end (args);
void
print_spaces_filtered (n, stream)
int n;
- GDB_FILE *stream;
+ struct ui_file *stream;
{
fputs_filtered (n_spaces (n), stream);
}
void
fprintf_symbol_filtered (stream, name, lang, arg_mode)
- GDB_FILE *stream;
+ struct ui_file *stream;
char *name;
enum language lang;
int arg_mode;
init_page_info ();
/* If the output is not a terminal, don't paginate it. */
- if (!GDB_FILE_ISATTY (gdb_stdout))
+ if (!ui_file_isatty (gdb_stdout))
lines_per_page = UINT_MAX;
set_width_command ((char *) NULL, 0, c);
int cur_bitshift;
/* Start at the least significant part of the field. */
- cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
- cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
- cur_bitshift =
- ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
- result = *(data + cur_byte) >> (-cur_bitshift);
+ {
+ /* We start counting from the other end (i.e, from the high bytes
+ rather than the low bytes). As such, we need to be concerned
+ with what happens if bit 0 doesn't start on a byte boundary.
+ I.e, we need to properly handle the case where total_len is
+ not evenly divisible by 8. So we compute ``excess'' which
+ represents the number of bits from the end of our starting
+ byte needed to get to bit 0. */
+ int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
+ cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
+ - ((start + len + excess) / FLOATFORMAT_CHAR_BIT);
+ cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT)
+ - FLOATFORMAT_CHAR_BIT;
+ }
+ else
+ {
+ cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
+ cur_bitshift =
+ ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
+ }
+ if (cur_bitshift > -FLOATFORMAT_CHAR_BIT)
+ result = *(data + cur_byte) >> (-cur_bitshift);
+ else
+ result = 0;
cur_bitshift += FLOATFORMAT_CHAR_BIT;
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
++cur_byte;
/* Move towards the most significant part of the field. */
while (cur_bitshift < len)
{
- if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
- /* This is the last byte; zero out the bits which are not part of
- this field. */
- result |=
- (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
- << cur_bitshift;
- else
- result |= *(data + cur_byte) << cur_bitshift;
+ result |= (unsigned long)*(data + cur_byte) << cur_bitshift;
cur_bitshift += FLOATFORMAT_CHAR_BIT;
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
++cur_byte;
else
--cur_byte;
}
+ if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
+ /* Mask out bits which are not part of the field */
+ result &= ((1UL << len) - 1);
return result;
}
special_exponent = exponent == 0 || exponent == fmt->exp_nan;
-/* Don't bias zero's, denorms or NaNs. */
+/* Don't bias NaNs. Use minimum exponent for denorms. For simplicity,
+ we don't check for zero as the exponent doesn't matter. */
if (!special_exponent)
exponent -= fmt->exp_bias;
+ else if (exponent == 0)
+ exponent = 1 - fmt->exp_bias;
/* Build the result algebraically. Might go infinite, underflow, etc;
who cares. */
int cur_bitshift;
/* Start at the least significant part of the field. */
- cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
- cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
- cur_bitshift =
- ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
- *(data + cur_byte) &=
- ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
- *(data + cur_byte) |=
- (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
+ {
+ int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
+ cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
+ - ((start + len + excess) / FLOATFORMAT_CHAR_BIT);
+ cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT)
+ - FLOATFORMAT_CHAR_BIT;
+ }
+ else
+ {
+ cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
+ cur_bitshift =
+ ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
+ }
+ if (cur_bitshift > -FLOATFORMAT_CHAR_BIT)
+ {
+ *(data + cur_byte) &=
+ ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1)
+ << (-cur_bitshift));
+ *(data + cur_byte) |=
+ (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
+ }
cur_bitshift += FLOATFORMAT_CHAR_BIT;
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
++cur_byte;
*/
-static int thirty_two = 32; /* eliminate warning from compiler on 32-bit systems */
+int
+strlen_paddr (void)
+{
+ return (TARGET_PTR_BIT / 8 * 2);
+}
+
+
+/* eliminate warning from compiler on 32-bit systems */
+static int thirty_two = 32;
char *
-paddr (addr)
- t_addr addr;
+paddr (CORE_ADDR addr)
{
char *paddr_str = get_cell ();
- switch (sizeof (t_addr))
+ switch (TARGET_PTR_BIT / 8)
{
case 8:
sprintf (paddr_str, "%08lx%08lx",
}
char *
-preg (reg)
- t_reg reg;
-{
- char *preg_str = get_cell ();
- switch (sizeof (t_reg))
- {
- case 8:
- sprintf (preg_str, "%08lx%08lx",
- (unsigned long) (reg >> thirty_two), (unsigned long) (reg & 0xffffffff));
- break;
- case 4:
- sprintf (preg_str, "%08lx", (unsigned long) reg);
- break;
- case 2:
- sprintf (preg_str, "%04x", (unsigned short) (reg & 0xffff));
- break;
- default:
- sprintf (preg_str, "%lx", (unsigned long) reg);
- }
- return preg_str;
-}
-
-char *
-paddr_nz (addr)
- t_addr addr;
+paddr_nz (CORE_ADDR addr)
{
char *paddr_str = get_cell ();
- switch (sizeof (t_addr))
+ switch (TARGET_PTR_BIT / 8)
{
case 8:
{
return paddr_str;
}
+static void
+decimal2str (char *paddr_str, char *sign, ULONGEST addr)
+{
+ /* steal code from valprint.c:print_decimal(). Should this worry
+ about the real size of addr as the above does? */
+ 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:
+ abort ();
+ }
+}
+
+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;
+}
+
+char *
+preg (reg)
+ t_reg reg;
+{
+ char *preg_str = get_cell ();
+ switch (sizeof (t_reg))
+ {
+ case 8:
+ sprintf (preg_str, "%08lx%08lx",
+ (unsigned long) (reg >> thirty_two), (unsigned long) (reg & 0xffffffff));
+ break;
+ case 4:
+ sprintf (preg_str, "%08lx", (unsigned long) reg);
+ break;
+ case 2:
+ sprintf (preg_str, "%04x", (unsigned short) (reg & 0xffff));
+ break;
+ default:
+ sprintf (preg_str, "%lx", (unsigned long) reg);
+ }
+ return preg_str;
+}
+
char *
preg_nz (reg)
t_reg reg;