/* General utility routines for GDB, the GNU debugger.
- Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 1998, 1999, 2000, 2001
+ Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
This file is part of GDB.
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include "defs.h"
-#include "gdb_assert.h"
-#include <ctype.h>
-#include "gdb_string.h"
-#include "event-top.h"
+/* FIXME: cagney/2002-02-28: The GDB coding standard indicates that
+ "defs.h" should be included first. Unfortunatly some systems
+ (currently Debian GNU/Linux) include the <stdbool.h> via <curses.h>
+ and they clash with "bfd.h"'s definiton of true/false. The correct
+ fix is to remove true/false from "bfd.h", however, until that
+ happens, hack around it by including "config.h" and <curses.h>
+ first. */
+
+#include "config.h"
#ifdef HAVE_CURSES_H
#include <curses.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
#include "expression.h"
#include "language.h"
#include "annotate.h"
+#include "filenames.h"
#include "inferior.h" /* for signed_pointer_to_address */
+#include <sys/param.h> /* For MAXPATHLEN */
+
#include <readline/readline.h>
-#ifndef MALLOC_INCOMPATIBLE
+#ifdef USE_MMALLOC
+#include "mmalloc.h"
+#endif
+
#ifdef NEED_DECLARATION_MALLOC
extern PTR malloc ();
#endif
#ifdef NEED_DECLARATION_FREE
extern void free ();
#endif
+/* Actually, we'll never have the decl, since we don't define _GNU_SOURCE. */
+#if defined(HAVE_CANONICALIZE_FILE_NAME) \
+ && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
+extern char *canonicalize_file_name (const char *);
#endif
-#undef XMALLOC
-#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
-
/* readline defines this. */
#undef savestring
\f
-/* Print a warning message. Way to use this is to call warning_begin,
- output the warning message (use unfiltered output to gdb_stderr),
- ending in a newline. There is not currently a warning_end that you
- call afterwards, but such a thing might be added if it is useful
- for a GUI to separate warning messages from other output.
-
- FIXME: Why do warnings use unfiltered output and errors filtered?
- Is this anything other than a historical accident? */
+/* Print a warning message. The first argument STRING is the warning
+ message, used as an fprintf format string, the second is the
+ va_list of arguments for that string. A warning is unfiltered (not
+ paginated) so that the user does not need to page through each
+ screen full of warnings when there are lots of them. */
void
-warning_begin (void)
+vwarning (const char *string, va_list args)
{
- target_terminal_ours ();
- wrap_here (""); /* Force out any buffered output */
- gdb_flush (gdb_stdout);
- if (warning_pre_print)
- fprintf_unfiltered (gdb_stderr, warning_pre_print);
+ if (warning_hook)
+ (*warning_hook) (string, args);
+ else
+ {
+ target_terminal_ours ();
+ wrap_here (""); /* Force out any buffered output */
+ 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);
+ }
}
/* Print a warning message.
{
va_list args;
va_start (args, string);
- if (warning_hook)
- (*warning_hook) (string, args);
- else
- {
- warning_begin ();
- vfprintf_unfiltered (gdb_stderr, string, args);
- fprintf_unfiltered (gdb_stderr, "\n");
- va_end (args);
- }
-}
-
-/* Start the printing of an error message. Way to use this is to call
- this, output the error message (use filtered output to gdb_stderr
- (FIXME: Some callers, like memory_error, use gdb_stdout)), ending
- in a newline, and then call return_to_top_level (RETURN_ERROR).
- error() provides a convenient way to do this for the special case
- that the error message can be formatted with a single printf call,
- but this is more general. */
-void
-error_begin (void)
-{
- if (error_begin_hook)
- error_begin_hook ();
-
- target_terminal_ours ();
- wrap_here (""); /* Force out any buffered output */
- gdb_flush (gdb_stdout);
-
- annotate_error_begin ();
-
- if (error_pre_print)
- fprintf_filtered (gdb_stderr, error_pre_print);
+ vwarning (string, args);
+ va_end (args);
}
/* Print an error message and return to command level.
NORETURN void
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.
- Unfortunately 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 (xfree, err_string);
- fputs_filtered (err_string, gdb_stderr);
- fprintf_filtered (gdb_stderr, "\n");
- do_cleanups (err_string_cleanup);
- return_to_top_level (RETURN_ERROR);
+ 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
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)
{
- long size;
- char *msg = ui_file_xstrdup (stream, &size);
- make_cleanup (xfree, msg);
- error ("%s", msg);
+ if (error_begin_hook)
+ error_begin_hook ();
+
+ /* Copy the stream into the GDB_LASTERR buffer. */
+ ui_file_rewind (gdb_lasterr);
+ ui_file_put (stream, do_write, gdb_lasterr);
+
+ /* Write the message plus any error_pre_print to gdb_stderr. */
+ target_terminal_ours ();
+ wrap_here (""); /* Force out any buffered output */
+ 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);
}
/* Get the last error message issued by gdb */
{
static char msg[] = "Internal GDB error: recursive internal error.\n";
static int dejavu = 0;
- int continue_p;
+ int quit_p;
int dump_core_p;
/* don't allow infinite error recursion. */
case 1:
dejavu = 2;
fputs_unfiltered (msg, gdb_stderr);
- internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ abort (); /* NOTE: GDB has only three calls to abort(). */
default:
dejavu = 3;
write (STDERR_FILENO, msg, sizeof (msg));
vfprintf_unfiltered (gdb_stderr, fmt, ap);
fputs_unfiltered ("\n", gdb_stderr);
- /* Default (no case) is to quit GDB. When in batch mode this
+ /* Default (yes/batch case) is to quit GDB. When in batch mode this
lessens the likelhood of GDB going into an infinate loop. */
- continue_p = query ("\
+ quit_p = query ("\
An internal GDB error was detected. This may make further\n\
-debugging unreliable. Continue this debugging session? ");
+debugging unreliable. Quit this debugging session? ");
- /* Default (no case) is to not dump core. Lessen the chance of GDB
- leaving random core files around. */
+ /* Default (yes/batch case) is to dump core. This leaves a GDB
+ dropping so that it is easier to see that something went wrong to
+ GDB. */
dump_core_p = query ("\
Create a core file containing the current state of GDB? ");
- if (continue_p)
+ if (quit_p)
{
if (dump_core_p)
- {
- if (fork () == 0)
- internal_error (__FILE__, __LINE__, "failed internal consistency check");
- }
+ abort (); /* NOTE: GDB has only three calls to abort(). */
+ else
+ exit (1);
}
else
{
if (dump_core_p)
- internal_error (__FILE__, __LINE__, "failed internal consistency check");
- else
- exit (1);
+ {
+ if (fork () == 0)
+ abort (); /* NOTE: GDB has only three calls to abort(). */
+ }
}
dejavu = 0;
- return_to_top_level (RETURN_ERROR);
+ throw_exception (RETURN_ERROR);
}
NORETURN void
Then return to command level. */
NORETURN void
-perror_with_name (char *string)
+perror_with_name (const char *string)
{
char *err;
char *combined;
as the file name for which the error was encountered. */
void
-print_sys_errmsg (char *string, int errcode)
+print_sys_errmsg (const char *string, int errcode)
{
char *err;
char *combined;
fprintf_unfiltered (gdb_stderr,
"Quit (expect signal SIGINT when the program is resumed)\n");
#endif
- return_to_top_level (RETURN_QUIT);
+ throw_exception (RETURN_QUIT);
}
/* Control C comes here */
/* NOTE: These must use PTR so that their definition matches the
declaration found in "mmalloc.h". */
-PTR
-mmalloc (PTR md, size_t size)
+static void *
+mmalloc (void *md, size_t size)
{
return malloc (size); /* NOTE: GDB's only call to malloc() */
}
-PTR
-mrealloc (PTR md, PTR ptr, size_t size)
+static void *
+mrealloc (void *md, void *ptr, size_t size)
{
if (ptr == 0) /* Guard against old realloc's */
return mmalloc (md, size);
return realloc (ptr, size); /* NOTE: GDB's only call to ralloc() */
}
-PTR
-mcalloc (PTR md, size_t number, size_t size)
+static void *
+mcalloc (void *md, size_t number, size_t size)
{
return calloc (number, size); /* NOTE: GDB's only call to calloc() */
}
-void
-mfree (PTR md, PTR ptr)
+static void
+mfree (void *md, void *ptr)
{
free (ptr); /* NOTE: GDB's only call to free() */
}
/* VARARGS */
int
-query (char *ctlstr,...)
+query (const char *ctlstr,...)
{
va_list args;
register int answer;
/* Automatically answer "yes" if input is not from a terminal. */
if (!input_from_terminal_p ())
return 1;
- /* 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");
- /* 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);
/* Call readline, not gdb_readline, because GO32 readline handles control-C
whereas control-C to gdb_readline will cause the user to get dumped
out to DOS. */
- ignore = readline (cont_prompt);
+ ignore = gdb_readline_wrapper (cont_prompt);
if (annotation_level > 1)
printf_unfiltered ("\n\032\032post-prompt-for-continue\n");
case language_java:
demangled = cplus_demangle (name, arg_mode | DMGL_JAVA);
break;
- case language_chill:
- demangled = chill_demangle (name);
- break;
+#if 0
+ /* OBSOLETE case language_chill: */
+ /* OBSOLETE demangled = chill_demangle (name); */
+ /* OBSOLETE break; */
+#endif
default:
demangled = NULL;
break;
"Set number of characters gdb thinks are in a line.",
&setlist);
add_show_from_set (c, &showlist);
- c->function.sfunc = set_width_command;
+ set_cmd_sfunc (c, set_width_command);
add_show_from_set
(add_set_cmd ("height", class_support,
char *
phex (ULONGEST l, int sizeof_l)
{
- char *str = get_cell ();
+ 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:
- phex (l, sizeof (l));
+ str = phex (l, sizeof (l));
break;
}
return str;
char *
phex_nz (ULONGEST l, int sizeof_l)
{
- char *str = get_cell ();
+ 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
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:
- phex_nz (l, sizeof (l));
+ str = phex_nz (l, sizeof (l));
break;
}
return 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");
+ gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
return POINTER_TO_ADDRESS (builtin_type_void_data_ptr, &ptr);
}
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");
+
+ gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
return ptr;
}
+
+/* Convert a CORE_ADDR into a string. */
+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;
+}
+
+/* Convert a string back into a CORE_ADDR. */
+CORE_ADDR
+string_to_core_addr (const char *my_string)
+{
+ CORE_ADDR addr = 0;
+ if (my_string[0] == '0' && tolower (my_string[1]) == 'x')
+ {
+ /* Assume that it is in decimal. */
+ 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
+ {
+ /* Assume that it is in decimal. */
+ 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 /* HAVE_REALPATH */
+
+#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
+}
+
+/* Return a copy of FILENAME, with its directory prefix canonicalized
+ by gdb_realpath. */
+
+char *
+xfullpath (const char *filename)
+{
+ const char *base_name = lbasename (filename);
+ char *dir_name;
+ char *real_path;
+ char *result;
+
+ /* Extract the basename of filename, and return immediately
+ a copy of filename if it does not contain any directory prefix. */
+ if (base_name == filename)
+ return xstrdup (filename);
+
+ dir_name = alloca ((size_t) (base_name - filename + 2));
+ /* Allocate enough space to store the dir_name + plus one extra
+ character sometimes needed under Windows (see below), and
+ then the closing \000 character */
+ strncpy (dir_name, filename, base_name - filename);
+ dir_name[base_name - filename] = '\000';
+
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ /* We need to be careful when filename is of the form 'd:foo', which
+ is equivalent of d:./foo, which is totally different from d:/foo. */
+ if (strlen (dir_name) == 2 &&
+ isalpha (dir_name[0]) && dir_name[1] == ':')
+ {
+ dir_name[2] = '.';
+ dir_name[3] = '\000';
+ }
+#endif
+
+ /* Canonicalize the directory prefix, and build the resulting
+ filename. If the dirname realpath already contains an ending
+ directory separator, avoid doubling it. */
+ 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;
+}