/* General utility routines for GDB, the GNU debugger.
Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gdb_assert.h"
#include "filenames.h"
#include "symfile.h"
#include "gdb_obstack.h"
+#include "gdbcore.h"
#include "top.h"
#include "inferior.h" /* for signed_pointer_to_address */
#include "readline/readline.h"
+#include <sys/time.h>
+#include <time.h>
+
#if !HAVE_DECL_MALLOC
extern PTR malloc (); /* OK: PTR */
#endif
static void set_screen_size (void);
static void set_width (void);
+/* A flag indicating whether to timestamp debugging messages. */
+
+static int debug_timestamp = 0;
+
/* Chain of cleanup actions established with make_cleanup,
to be executed if an error happens. */
static struct cleanup *cleanup_chain; /* cleaned up after a failed command */
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
}
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)
+make_cleanup_dtor (make_cleanup_ftype *function, void *arg,
+ void (*dtor) (void *))
{
- return make_my_cleanup (&exec_cleanup_chain, function, arg);
+ return make_my_cleanup2 (&cleanup_chain,
+ function, arg, dtor);
}
struct cleanup *
-make_exec_error_cleanup (make_cleanup_ftype *function, void *arg)
+make_final_cleanup (make_cleanup_ftype *function, void *arg)
{
- return make_my_cleanup (&exec_error_cleanup_chain, function, arg);
+ return make_my_cleanup (&final_cleanup_chain, function, arg);
}
static void
return make_my_cleanup (&cleanup_chain, do_free_section_addr_info, addrs);
}
+struct restore_integer_closure
+{
+ int *variable;
+ int value;
+};
+
+static void
+restore_integer (void *p)
+{
+ struct restore_integer_closure *closure = p;
+ *(closure->variable) = closure->value;
+}
+/* Remember the current value of *VARIABLE and make it restored when the cleanup
+ is run. */
struct cleanup *
-make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
- void *arg)
+make_cleanup_restore_integer (int *variable)
+{
+ struct restore_integer_closure *c =
+ xmalloc (sizeof (struct restore_integer_closure));
+ c->variable = variable;
+ c->value = *variable;
+
+ return make_my_cleanup2 (&cleanup_chain, restore_integer, (void *)c,
+ xfree);
+}
+
+struct cleanup *
+make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function,
+ void *arg, void (*free_arg) (void *))
{
struct cleanup *new
= (struct cleanup *) xmalloc (sizeof (struct cleanup));
new->next = *pmy_chain;
new->function = function;
+ new->free_arg = free_arg;
new->arg = arg;
*pmy_chain = new;
return old_chain;
}
+struct cleanup *
+make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
+ void *arg)
+{
+ return make_my_cleanup2 (pmy_chain, function, arg, NULL);
+}
+
/* Discard cleanups and do the actions they describe
until we get back to the point OLD_CHAIN in the cleanup_chain. */
do_my_cleanups (&final_cleanup_chain, old_chain);
}
-void
-do_run_cleanups (struct cleanup *old_chain)
-{
- do_my_cleanups (&run_cleanup_chain, old_chain);
-}
-
-void
-do_exec_cleanups (struct cleanup *old_chain)
-{
- do_my_cleanups (&exec_cleanup_chain, old_chain);
-}
-
-void
-do_exec_error_cleanups (struct cleanup *old_chain)
-{
- do_my_cleanups (&exec_error_cleanup_chain, old_chain);
-}
-
static void
do_my_cleanups (struct cleanup **pmy_chain,
struct cleanup *old_chain)
{
*pmy_chain = ptr->next; /* Do this first incase recursion */
(*ptr->function) (ptr->arg);
+ if (ptr->free_arg)
+ (*ptr->free_arg) (ptr->arg);
xfree (ptr);
}
}
discard_my_cleanups (&final_cleanup_chain, old_chain);
}
-void
-discard_exec_error_cleanups (struct cleanup *old_chain)
-{
- discard_my_cleanups (&exec_error_cleanup_chain, old_chain);
-}
-
void
discard_my_cleanups (struct cleanup **pmy_chain,
struct cleanup *old_chain)
while ((ptr = *pmy_chain) != old_chain)
{
*pmy_chain = ptr->next;
+ if (ptr->free_arg)
+ (*ptr->free_arg) (ptr->arg);
xfree (ptr);
}
}
{
}
+/* Continuations are implemented as cleanups internally. Inherit from
+ cleanups. */
+struct continuation
+{
+ struct cleanup base;
+};
+
/* Add a continuation to the continuation list, the global list
- cmd_continuation. The new continuation will be added at the front.*/
+ cmd_continuation. The new continuation will be added at the
+ front. */
void
-add_continuation (void (*continuation_hook) (struct continuation_arg *),
- struct continuation_arg *arg_list)
+add_continuation (void (*continuation_hook) (void *), void *args,
+ void (*continuation_free_args) (void *))
{
- struct continuation *continuation_ptr;
+ struct cleanup *as_cleanup = &cmd_continuation->base;
+ make_cleanup_ftype *continuation_hook_fn = continuation_hook;
+
+ make_my_cleanup2 (&as_cleanup,
+ continuation_hook_fn,
+ args,
+ continuation_free_args);
- 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;
+ cmd_continuation = (struct continuation *) as_cleanup;
}
/* Walk down the cmd_continuation list, and execute all the
void
do_all_continuations (void)
{
- struct continuation *continuation_ptr;
- struct continuation *saved_continuation;
+ struct cleanup *continuation_ptr;
/* 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;
+ effect of invoking the continuations and the processing of the
+ preexisting continuations will not be affected. */
+
+ continuation_ptr = &cmd_continuation->base;
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;
- xfree (saved_continuation);
- }
+ do_my_cleanups (&continuation_ptr, NULL);
}
/* Walk down the cmd_continuation list, and get rid of all the
void
discard_all_continuations (void)
{
- struct continuation *continuation_ptr;
-
- while (cmd_continuation)
- {
- continuation_ptr = cmd_continuation;
- cmd_continuation = continuation_ptr->next;
- xfree (continuation_ptr);
- }
+ struct cleanup *continuation_ptr = &cmd_continuation->base;
+ discard_my_cleanups (&continuation_ptr, NULL);
+ cmd_continuation = NULL;
}
/* Add a continuation to the continuation list, the global list
the front. */
void
add_intermediate_continuation (void (*continuation_hook)
- (struct continuation_arg *),
- struct continuation_arg *arg_list)
+ (void *), void *args,
+ void (*continuation_free_args) (void *))
{
- struct continuation *continuation_ptr;
+ struct cleanup *as_cleanup = &intermediate_continuation->base;
+ make_cleanup_ftype *continuation_hook_fn = continuation_hook;
- 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;
+ make_my_cleanup2 (&as_cleanup,
+ continuation_hook_fn,
+ args,
+ continuation_free_args);
+
+ intermediate_continuation = (struct continuation *) as_cleanup;
}
/* Walk down the cmd_continuation list, and execute all the
void
do_all_intermediate_continuations (void)
{
- struct continuation *continuation_ptr;
- struct continuation *saved_continuation;
+ struct cleanup *continuation_ptr;
/* 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;
+ effect of invoking the continuations and the processing of the
+ preexisting continuations will not be affected. */
+
+ continuation_ptr = &intermediate_continuation->base;
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;
- xfree (saved_continuation);
- }
+ do_my_cleanups (&continuation_ptr, NULL);
}
/* Walk down the cmd_continuation list, and get rid of all the
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);
- }
+ struct cleanup *continuation_ptr = &intermediate_continuation->base;
+ discard_my_cleanups (&continuation_ptr, NULL);
+ continuation_ptr = NULL;
}
\f
rows = INT_MAX;
if (cols <= 0)
- rl_get_screen_size (NULL, &cols);
+ cols = INT_MAX;
/* Update Readline's idea of the terminal size. */
rl_set_screen_size (rows, cols);
linebuffer = xstrvprintf (format, args);
old_cleanups = make_cleanup (xfree, linebuffer);
+ if (debug_timestamp && stream == gdb_stdlog)
+ {
+ struct timeval tm;
+ char *timestamp;
+
+ gettimeofday (&tm, NULL);
+ timestamp = xstrprintf ("%ld:%ld ", (long) tm.tv_sec, (long) tm.tv_usec);
+ make_cleanup (xfree, timestamp);
+ fputs_unfiltered (timestamp, stream);
+ }
fputs_unfiltered (linebuffer, stream);
do_cleanups (old_cleanups);
}
{
pagination_enabled = 0;
}
+
+static void
+show_debug_timestamp (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Timestamping debugging messages is %s.\n"), value);
+}
\f
void
NULL,
show_asm_demangle,
&setprintlist, &showprintlist);
+
+ add_setshow_boolean_cmd ("timestamp", class_maintenance,
+ &debug_timestamp, _("\
+Set timestamping of debugging messages."), _("\
+Show timestamping of debugging messages."), _("\
+When set, debugging messages will be marked with seconds and microseconds."),
+ NULL,
+ show_debug_timestamp,
+ &setdebuglist, &showdebuglist);
}
/* Machine specific function to handle SIGWINCH signal. */
int
strlen_paddr (void)
{
- return (TARGET_ADDR_BIT / 8 * 2);
+ return (gdbarch_addr_bit (current_gdbarch) / 8 * 2);
}
char *
paddr (CORE_ADDR addr)
{
- return phex (addr, TARGET_ADDR_BIT / 8);
+ return phex (addr, gdbarch_addr_bit (current_gdbarch) / 8);
}
char *
paddr_nz (CORE_ADDR addr)
{
- return phex_nz (addr, TARGET_ADDR_BIT / 8);
+ return phex_nz (addr, gdbarch_addr_bit (current_gdbarch) / 8);
}
const char *
when it won't occur. */
/* NOTE: This assumes that the significant address information is
kept in the least significant bits of ADDR - the upper bits were
- either zero or sign extended. Should ADDRESS_TO_POINTER() or
+ either zero or sign extended. Should gdbarch_address_to_pointer or
some ADDRESS_TO_PRINTABLE() be used to do the conversion? */
- int addr_bit = TARGET_ADDR_BIT;
+ int addr_bit = gdbarch_addr_bit (current_gdbarch);
if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
addr &= ((CORE_ADDR) 1 << addr_bit) - 1;
}
char *
-paddr_u (CORE_ADDR addr)
+pulongest (ULONGEST u)
{
- return decimal2str ("", addr, 0);
+ return decimal2str ("", u, 0);
}
char *
-paddr_d (LONGEST addr)
+plongest (LONGEST l)
{
- if (addr < 0)
- return decimal2str ("-", -addr, 0);
+ if (l < 0)
+ return decimal2str ("-", -l, 0);
else
- return decimal2str ("", addr, 0);
+ return decimal2str ("", l, 0);
}
/* Eliminate warning from compiler on 32-bit systems. */
CORE_ADDR
string_to_core_addr (const char *my_string)
{
+ int addr_bit = gdbarch_addr_bit (current_gdbarch);
CORE_ADDR addr = 0;
+
if (my_string[0] == '0' && tolower (my_string[1]) == 'x')
{
- /* Assume that it is in decimal. */
+ /* Assume that it is in hex. */
int i;
for (i = 2; my_string[i] != '\0'; i++)
{
else
error (_("invalid hex \"%s\""), my_string);
}
+
+ /* Not very modular, but if the executable format expects
+ addresses to be sign-extended, then do so if the address was
+ specified with only 32 significant bits. Really this should
+ be determined by the target architecture, not by the object
+ file. */
+ if (i - 2 == addr_bit / 4
+ && exec_bfd
+ && bfd_get_sign_extend_vma (exec_bfd))
+ addr = (addr ^ ((CORE_ADDR) 1 << (addr_bit - 1)))
+ - ((CORE_ADDR) 1 << (addr_bit - 1));
}
else
{
error (_("invalid decimal \"%s\""), my_string);
}
}
+
return addr;
}
+const char *
+host_address_to_string (const void *addr)
+{
+ char *str = get_cell ();
+ sprintf (str, "0x%lx", (unsigned long) addr);
+ return str;
+}
+
char *
gdb_realpath (const char *filename)
{
else
return result;
}
+
+/* Simple, portable version of dirname that does not modify its
+ argument. */
+
+char *
+ldirname (const char *filename)
+{
+ const char *base = lbasename (filename);
+ char *dirname;
+
+ while (base > filename && IS_DIR_SEPARATOR (base[-1]))
+ --base;
+
+ if (base == filename)
+ return NULL;
+
+ dirname = xmalloc (base - filename + 2);
+ memcpy (dirname, filename, base - filename);
+
+ /* On DOS based file systems, convert "d:foo" to "d:.", so that we
+ create "d:./bar" later instead of the (different) "d:/bar". */
+ if (base - filename == 2 && IS_ABSOLUTE_PATH (base)
+ && !IS_DIR_SEPARATOR (filename[0]))
+ dirname[base++ - filename] = '.';
+
+ dirname[base - filename] = '\0';
+ return dirname;
+}