/* General utility routines for GDB, the GNU debugger.
- Copyright 1986, 1989, 1990-1992, 1995, 1996, 1998, 2000
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This file is part of GDB.
Boston, MA 02111-1307, USA. */
#include "defs.h"
+#include "gdb_assert.h"
#include <ctype.h>
#include "gdb_string.h"
#include "event-top.h"
#undef reg
#endif
-#include "signals.h"
+#include <signal.h>
#include "gdbcmd.h"
#include "serial.h"
#include "bfd.h"
#include <readline/readline.h>
+#ifndef MALLOC_INCOMPATIBLE
+#ifdef NEED_DECLARATION_MALLOC
+extern PTR malloc ();
+#endif
+#ifdef NEED_DECLARATION_REALLOC
+extern PTR realloc ();
+#endif
+#ifdef NEED_DECLARATION_FREE
+extern void free ();
+#endif
+#endif
+
#undef XMALLOC
#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
static void
do_close_cleanup (void *arg)
{
- close ((int) arg);
+ int *fd = arg;
+ close (*fd);
+ xfree (fd);
}
struct cleanup *
make_cleanup_close (int fd)
{
- /* int into void*. Outch!! */
- return make_cleanup (do_close_cleanup, (void *) fd);
+ int *saved_fd = xmalloc (sizeof (fd));
+ *saved_fd = fd;
+ return make_cleanup (do_close_cleanup, saved_fd);
}
static void
{
*pmy_chain = ptr->next; /* Do this first incase recursion */
(*ptr->function) (ptr->arg);
- free (ptr);
+ xfree (ptr);
}
}
while ((ptr = *pmy_chain) != old_chain)
{
*pmy_chain = ptr->next;
- free (ptr);
+ xfree (ptr);
}
}
{
void **location = ptr;
if (location == NULL)
- internal_error ("free_current_contents: NULL pointer");
+ internal_error (__FILE__, __LINE__,
+ "free_current_contents: NULL pointer");
if (*location != NULL)
{
- free (*location);
+ xfree (*location);
*location = NULL;
}
}
(continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
saved_continuation = continuation_ptr;
continuation_ptr = continuation_ptr->next;
- free (saved_continuation);
+ xfree (saved_continuation);
}
}
{
continuation_ptr = cmd_continuation;
cmd_continuation = continuation_ptr->next;
- free (continuation_ptr);
+ xfree (continuation_ptr);
}
}
(continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
saved_continuation = continuation_ptr;
continuation_ptr = continuation_ptr->next;
- free (saved_continuation);
+ xfree (saved_continuation);
}
}
{
continuation_ptr = intermediate_continuation;
intermediate_continuation = continuation_ptr->next;
- free (continuation_ptr);
+ xfree (continuation_ptr);
}
}
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);
+ err_string_cleanup = make_cleanup (xfree, err_string);
fputs_filtered (err_string, gdb_stderr);
fprintf_filtered (gdb_stderr, "\n");
do_cleanups (err_string_cleanup);
{
long size;
char *msg = ui_file_xstrdup (stream, &size);
- make_cleanup (free, msg);
+ make_cleanup (xfree, msg);
error ("%s", msg);
}
want to continue, dump core, or just exit. */
NORETURN void
-internal_verror (const char *fmt, va_list ap)
+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;
case 1:
dejavu = 2;
fputs_unfiltered (msg, gdb_stderr);
- abort ();
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
default:
dejavu = 3;
write (STDERR_FILENO, msg, sizeof (msg));
/* Try to get the message out */
target_terminal_ours ();
- fputs_unfiltered ("gdb-internal-error: ", gdb_stderr);
+ fprintf_unfiltered (gdb_stderr, "%s:%d: gdb-internal-error: ", file, line);
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\
+An internal GDB error was detected. This may make further\n\
debugging unreliable. Continue this debugging session? ");
/* Default (no case) is to not dump core. Lessen the chance of GDB
if (dump_core_p)
{
if (fork () == 0)
- abort ();
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
}
}
else
{
if (dump_core_p)
- abort ();
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
else
exit (1);
}
}
NORETURN void
-internal_error (char *string, ...)
+internal_error (const char *file, int line, const char *string, ...)
{
va_list ap;
va_start (ap, string);
- internal_verror (string, ap);
+ internal_verror (file, line, string, ap);
va_end (ap);
}
\f
/* Memory management stuff (malloc friends). */
-/* Make a substitute size_t for non-ANSI compilers. */
-
-#ifndef HAVE_STDDEF_H
-#ifndef size_t
-#define size_t unsigned int
-#endif
-#endif
-
#if !defined (USE_MMALLOC)
-PTR
-mcalloc (PTR md, size_t number, size_t size)
-{
- return calloc (number, size);
-}
+/* NOTE: These must use PTR so that their definition matches the
+ declaration found in "mmalloc.h". */
PTR
mmalloc (PTR md, size_t size)
{
- return malloc (size);
+ return malloc (size); /* NOTE: GDB's only call to malloc() */
}
PTR
mrealloc (PTR md, PTR ptr, size_t size)
{
if (ptr == 0) /* Guard against old realloc's */
- return malloc (size);
+ return mmalloc (md, size);
else
- return realloc (ptr, size);
+ return realloc (ptr, size); /* NOTE: GDB's only call to ralloc() */
+}
+
+PTR
+mcalloc (PTR md, size_t number, size_t size)
+{
+ return calloc (number, size); /* NOTE: GDB's only call to calloc() */
}
void
mfree (PTR md, PTR ptr)
{
- free (ptr);
+ free (ptr); /* NOTE: GDB's only call to free() */
}
#endif /* USE_MMALLOC */
malloc_botch (void)
{
fprintf_unfiltered (gdb_stderr, "Memory corruption\n");
- abort ();
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
}
/* Attempt to install hooks in mmalloc/mrealloc/mfree for the heap specified
{
if (size > 0)
{
- internal_error ("virtual memory exhausted: can't allocate %ld bytes.", size);
+ internal_error (__FILE__, __LINE__,
+ "virtual memory exhausted: can't allocate %ld bytes.", size);
}
else
{
- internal_error ("virtual memory exhausted.");
+ internal_error (__FILE__, __LINE__,
+ "virtual memory exhausted.");
}
}
-/* Like mmalloc but get error if no storage available, and protect against
- the caller wanting to allocate zero bytes. Whether to return NULL for
- a zero byte request, or translate the request into a request for one
- byte of zero'd storage, is a religious issue. */
+/* The xmmalloc() family of memory management routines.
-PTR
-xmmalloc (PTR md, long size)
+ These are are like the mmalloc() family except that they implement
+ consistent semantics and guard against typical memory management
+ problems: if a malloc fails, an internal error is thrown; if
+ free(NULL) is called, it is ignored; if *alloc(0) is called, NULL
+ is returned.
+
+ All these routines are implemented using the mmalloc() family. */
+
+void *
+xmmalloc (void *md, size_t size)
{
- register PTR val;
+ void *val;
if (size == 0)
{
val = NULL;
}
- else if ((val = mmalloc (md, size)) == NULL)
+ else
{
- nomem (size);
+ val = mmalloc (md, size);
+ if (val == NULL)
+ nomem (size);
}
return (val);
}
-/* Like mrealloc but get error if no storage available. */
-
-PTR
-xmrealloc (PTR md, PTR ptr, long size)
+void *
+xmrealloc (void *md, void *ptr, size_t size)
{
- register PTR val;
+ void *val;
- if (ptr != NULL)
+ if (size == 0)
{
- val = mrealloc (md, ptr, size);
+ if (ptr != NULL)
+ mfree (md, ptr);
+ val = NULL;
}
else
{
- val = mmalloc (md, size);
+ if (ptr != NULL)
+ {
+ val = mrealloc (md, ptr, size);
+ }
+ else
+ {
+ val = mmalloc (md, size);
+ }
+ if (val == NULL)
+ {
+ nomem (size);
+ }
}
- if (val == NULL)
+ return (val);
+}
+
+void *
+xmcalloc (void *md, size_t number, size_t size)
+{
+ void *mem;
+ if (number == 0 || size == 0)
+ mem = NULL;
+ else
{
- nomem (size);
+ mem = mcalloc (md, number, size);
+ if (mem == NULL)
+ nomem (number * size);
}
- return (val);
+ return mem;
}
-/* Like malloc but get error if no storage available, and protect against
- the caller wanting to allocate zero bytes. */
+void
+xmfree (void *md, void *ptr)
+{
+ if (ptr != NULL)
+ mfree (md, ptr);
+}
+
+/* The xmalloc() (libiberty.h) family of memory management routines.
+
+ These are like the ISO-C malloc() family except that they implement
+ consistent semantics and guard against typical memory management
+ problems. See xmmalloc() above for further information.
+
+ All these routines are wrappers to the xmmalloc() family. */
+
+/* NOTE: These are declared using PTR to ensure consistency with
+ "libiberty.h". xfree() is GDB local. */
PTR
xmalloc (size_t size)
{
- return (xmmalloc ((PTR) NULL, size));
+ return xmmalloc (NULL, size);
}
-/* Like calloc but get error if no storage available */
+PTR
+xrealloc (PTR ptr, size_t size)
+{
+ return xmrealloc (NULL, ptr, size);
+}
PTR
xcalloc (size_t number, size_t size)
{
- void *mem = mcalloc (NULL, number, size);
- if (mem == NULL)
- nomem (number * size);
- return mem;
+ return xmcalloc (NULL, number, size);
}
-/* Like mrealloc but get error if no storage available. */
-
-PTR
-xrealloc (PTR ptr, size_t size)
+void
+xfree (void *ptr)
{
- return (xmrealloc ((PTR) NULL, ptr, size));
+ xmfree (NULL, ptr);
}
\f
+/* Like asprintf/vasprintf but get an internal_error if the call
+ fails. */
+
+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)
+{
+ int status = vasprintf (ret, format, ap);
+ /* NULL could be returned due to a memory allocation problem; a
+ badly format string; or something else. */
+ if ((*ret) == NULL)
+ internal_error (__FILE__, __LINE__,
+ "vasprintf returned NULL buffer (errno %d)",
+ errno);
+ /* A negative status with a non-NULL buffer shouldn't never
+ happen. But to be sure. */
+ if (status < 0)
+ internal_error (__FILE__, __LINE__,
+ "vasprintf call failed (errno %d)",
+ errno);
+}
+
+
/* My replacement for the read system call.
Used like `read' but keeps going if `read' returns too soon. */
Uses malloc to get the space. Returns the address of the copy. */
char *
-savestring (const char *ptr, int size)
+savestring (const char *ptr, size_t size)
{
register char *p = (char *) xmalloc (size + 1);
memcpy (p, ptr, size);
}
char *
-msavestring (void *md, const char *ptr, int size)
+msavestring (void *md, const char *ptr, size_t size)
{
register char *p = (char *) xmmalloc (md, size + 1);
memcpy (p, ptr, size);
return p;
}
-/* The "const" is so it compiles under DGUX (which prototypes strsave
- in <string.h>. FIXME: This should be named "xstrsave", shouldn't it?
- Doesn't real strsave return NULL if out of memory? */
-char *
-strsave (const char *ptr)
-{
- return savestring (ptr, strlen (ptr));
-}
-
char *
mstrsave (void *md, const char *ptr)
{
/* Automatically answer "yes" if input is not from a terminal. */
if (!input_from_terminal_p ())
return 1;
-#ifdef MPW
- /* FIXME Automatically answer "yes" if called from MacGDB. */
- if (mac_app)
- return 1;
-#endif /* MPW */
+ /* OBSOLETE #ifdef MPW */
+ /* OBSOLETE *//* FIXME Automatically answer "yes" if called from MacGDB. */
+ /* OBSOLETE if (mac_app) */
+ /* OBSOLETE return 1; */
+ /* OBSOLETE #endif *//* MPW */
while (1)
{
if (annotation_level > 1)
printf_filtered ("\n\032\032query\n");
-#ifdef MPW
- /* If not in MacGDB, move to a new line so the entered line doesn't
- have a prompt on the front of it. */
- if (!mac_app)
- fputs_unfiltered ("\n", gdb_stdout);
-#endif /* MPW */
+ /* OBSOLETE #ifdef MPW */
+ /* OBSOLETE *//* If not in MacGDB, move to a new line so the entered line doesn't */
+ /* OBSOLETE have a prompt on the front of it. */
+ /* OBSOLETE if (!mac_app) */
+ /* OBSOLETE fputs_unfiltered ("\n", gdb_stdout); */
+ /* OBSOLETE #endif *//* MPW */
wrap_here ("");
gdb_flush (gdb_stdout);
lines_per_page = 24;
chars_per_line = 80;
-#if !defined (MPW) && !defined (_WIN32)
+#if !defined (_WIN32)
/* No termcap under MPW, although might be cool to do something
by looking at worksheet or console window sizes. */
/* Initialize the screen height and width from termcap. */
else
async_request_quit (0);
}
- free (ignore);
+ xfree (ignore);
}
immediate_quit--;
{
/* This should have been allocated, but be paranoid anyway. */
if (!wrap_buffer)
- abort ();
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
if (wrap_buffer[0])
{
return c;
}
+/* Write character C to gdb_stdout using GDB's paging mechanism and return C.
+ May return nonlocally. */
+
+int
+putchar_filtered (int c)
+{
+ return fputc_filtered (c, gdb_stdout);
+}
+
int
fputc_unfiltered (int c, struct ui_file *stream)
{
char *linebuffer;
struct cleanup *old_cleanups;
- vasprintf (&linebuffer, format, args);
- if (linebuffer == NULL)
- {
- fputs_unfiltered ("\ngdb: virtual memory exhausted.\n", gdb_stderr);
- exit (1);
- }
- old_cleanups = make_cleanup (free, linebuffer);
+ xvasprintf (&linebuffer, format, args);
+ old_cleanups = make_cleanup (xfree, linebuffer);
fputs_maybe_filtered (linebuffer, stream, filter);
do_cleanups (old_cleanups);
}
char *linebuffer;
struct cleanup *old_cleanups;
- vasprintf (&linebuffer, format, args);
- if (linebuffer == NULL)
- {
- fputs_unfiltered ("\ngdb: virtual memory exhausted.\n", gdb_stderr);
- exit (1);
- }
- old_cleanups = make_cleanup (free, linebuffer);
+ xvasprintf (&linebuffer, format, args);
+ old_cleanups = make_cleanup (xfree, linebuffer);
fputs_unfiltered (linebuffer, stream);
do_cleanups (old_cleanups);
}
if (n > max_spaces)
{
if (spaces)
- free (spaces);
+ xfree (spaces);
spaces = (char *) xmalloc (n + 1);
for (t = spaces + n; t != spaces;)
*--t = ' ';
fputs_filtered (demangled ? demangled : name, stream);
if (demangled != NULL)
{
- free (demangled);
+ xfree (demangled);
}
}
}
}
}
+/* Check if VAL (which is assumed to be a floating point number whose
+ format is described by FMT) is negative. */
+
+int
+floatformat_is_negative (const struct floatformat *fmt, char *val)
+{
+ unsigned char *uval = (unsigned char *) val;
+
+ return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1);
+}
+
+/* Check if VAL is "not a number" (NaN) for FMT. */
+
+int
+floatformat_is_nan (const struct floatformat *fmt, char *val)
+{
+ unsigned char *uval = (unsigned char *) val;
+ long exponent;
+ unsigned long mant;
+ unsigned int mant_bits, mant_off;
+ int mant_bits_left;
+
+ if (! fmt->exp_nan)
+ return 0;
+
+ exponent = get_field (uval, fmt->byteorder, fmt->totalsize,
+ fmt->exp_start, fmt->exp_len);
+
+ if (exponent != fmt->exp_nan)
+ return 0;
+
+ mant_bits_left = fmt->man_len;
+ mant_off = fmt->man_start;
+
+ while (mant_bits_left > 0)
+ {
+ mant_bits = min (mant_bits_left, 32);
+
+ mant = get_field (uval, fmt->byteorder, fmt->totalsize,
+ mant_off, mant_bits);
+
+ /* If there is an explicit integer bit, mask it off. */
+ if (mant_off == fmt->man_start
+ && fmt->intbit == floatformat_intbit_yes)
+ mant &= ~(1 << (mant_bits - 1));
+
+ if (mant)
+ return 1;
+
+ mant_off += mant_bits;
+ mant_bits_left -= mant_bits;
+ }
+
+ return 0;
+}
+
+/* Convert the mantissa of VAL (which is assumed to be a floating
+ point number whose format is described by FMT) into a hexadecimal
+ and store it in a static string. Return a pointer to that string. */
+
+char *
+floatformat_mantissa (const struct floatformat *fmt, char *val)
+{
+ unsigned char *uval = (unsigned char *) val;
+ unsigned long mant;
+ unsigned int mant_bits, mant_off;
+ int mant_bits_left;
+ static char res[50];
+ char buf[9];
+
+ /* Make sure we have enough room to store the mantissa. */
+ gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2);
+
+ mant_off = fmt->man_start;
+ mant_bits_left = fmt->man_len;
+ mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32;
+
+ mant = get_field (uval, fmt->byteorder, fmt->totalsize,
+ mant_off, mant_bits);
+
+ sprintf (res, "%lx", mant);
+
+ mant_off += mant_bits;
+ mant_bits_left -= mant_bits;
+
+ while (mant_bits_left > 0)
+ {
+ mant = get_field (uval, fmt->byteorder, fmt->totalsize,
+ mant_off, 32);
+
+ sprintf (buf, "%08lx", mant);
+ strcat (res, buf);
+
+ mant_off += 32;
+ mant_bits_left -= 32;
+ }
+
+ return res;
+}
+
/* print routines to handle variable size regs, etc. */
/* temporary storage using circular buffer */
sign, temp[2], temp[1], temp[0]);
break;
default:
- abort ();
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
}
}
host_pointer_to_address (void *ptr)
{
if (sizeof (ptr) != TYPE_LENGTH (builtin_type_ptr))
- internal_error ("core_addr_to_void_ptr: bad cast");
+ internal_error (__FILE__, __LINE__,
+ "core_addr_to_void_ptr: bad cast");
return POINTER_TO_ADDRESS (builtin_type_ptr, &ptr);
}
{
void *ptr;
if (sizeof (ptr) != TYPE_LENGTH (builtin_type_ptr))
- internal_error ("core_addr_to_void_ptr: bad cast");
+ internal_error (__FILE__, __LINE__,
+ "core_addr_to_void_ptr: bad cast");
ADDRESS_TO_POINTER (builtin_type_ptr, &ptr, addr);
return ptr;
}