]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
This commit was manufactured by cvs2svn to create branch
authornobody <>
Fri, 20 Sep 2002 14:59:00 +0000 (14:59 +0000)
committernobody <>
Fri, 20 Sep 2002 14:59:00 +0000 (14:59 +0000)
'carlton_dictionary-branch'.

Cherrypick from master 2002-09-20 14:58:59 UTC Fernando Nasser <fnasser@redhat.com> '        * source.c: Make global variables current_source_symtab and':
    gdb/breakpoint.c
    gdb/mi/ChangeLog
    gdb/printcmd.c
    gdb/stack.c
    gdb/tracepoint.c
    gdb/valops.c
Cherrypick from gdb_5_3-branch 2002-09-03 22:29:15 UTC nobody 'This commit was manufactured by cvs2svn to create branch 'gdb_5_3-branch'.':
    gdb/mi/mi-cmd-stack.c
    gdb/objfiles.c

gdb/breakpoint.c [new file with mode: 0644]
gdb/mi/ChangeLog [new file with mode: 0644]
gdb/mi/mi-cmd-stack.c [new file with mode: 0644]
gdb/objfiles.c [new file with mode: 0644]
gdb/printcmd.c [new file with mode: 0644]
gdb/stack.c [new file with mode: 0644]
gdb/tracepoint.c [new file with mode: 0644]
gdb/valops.c [new file with mode: 0644]

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
new file mode 100644 (file)
index 0000000..caa8f1c
--- /dev/null
@@ -0,0 +1,7823 @@
+/* Everything about breakpoints, for GDB.
+
+   Copyright 1986, 1987, 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.
+
+   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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include <ctype.h>
+#include "symtab.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "value.h"
+#include "command.h"
+#include "inferior.h"
+#include "gdbthread.h"
+#include "target.h"
+#include "language.h"
+#include "gdb_string.h"
+#include "demangle.h"
+#include "annotate.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "source.h"
+#include "linespec.h"
+#include "completer.h"
+#include "gdb.h"
+#include "ui-out.h"
+#include "cli/cli-script.h"
+
+#include "gdb-events.h"
+
+/* Prototypes for local functions. */
+
+static void until_break_command_continuation (struct continuation_arg *arg);
+
+static void catch_command_1 (char *, int, int);
+
+static void enable_delete_command (char *, int);
+
+static void enable_delete_breakpoint (struct breakpoint *);
+
+static void enable_once_command (char *, int);
+
+static void enable_once_breakpoint (struct breakpoint *);
+
+static void disable_command (char *, int);
+
+static void enable_command (char *, int);
+
+static void map_breakpoint_numbers (char *, void (*)(struct breakpoint *));
+
+static void ignore_command (char *, int);
+
+static int breakpoint_re_set_one (PTR);
+
+static void clear_command (char *, int);
+
+static void catch_command (char *, int);
+
+static void handle_gnu_4_16_catch_command (char *, int, int);
+
+static struct symtabs_and_lines get_catch_sals (int);
+
+static void watch_command (char *, int);
+
+static int can_use_hardware_watchpoint (struct value *);
+
+extern void break_at_finish_command (char *, int);
+extern void break_at_finish_at_depth_command (char *, int);
+
+extern void tbreak_at_finish_command (char *, int);
+
+static void break_command_1 (char *, int, int);
+
+static void mention (struct breakpoint *);
+
+struct breakpoint *set_raw_breakpoint (struct symtab_and_line, enum bptype);
+
+static void check_duplicates (struct breakpoint *);
+
+static void describe_other_breakpoints (CORE_ADDR, asection *);
+
+static void breakpoints_info (char *, int);
+
+static void breakpoint_1 (int, int);
+
+static bpstat bpstat_alloc (struct breakpoint *, bpstat);
+
+static int breakpoint_cond_eval (PTR);
+
+static void cleanup_executing_breakpoints (PTR);
+
+static void commands_command (char *, int);
+
+static void condition_command (char *, int);
+
+static int get_number_trailer (char **, int);
+
+void set_breakpoint_count (int);
+
+typedef enum
+  {
+    mark_inserted,
+    mark_uninserted
+  }
+insertion_state_t;
+
+static int remove_breakpoint (struct breakpoint *, insertion_state_t);
+
+static enum print_stop_action print_it_typical (bpstat);
+
+static enum print_stop_action print_bp_stop_message (bpstat bs);
+
+typedef struct
+  {
+    enum exception_event_kind kind;
+    int enable_p;
+  }
+args_for_catchpoint_enable;
+
+static int watchpoint_check (PTR);
+
+static int cover_target_enable_exception_callback (PTR);
+
+static void maintenance_info_breakpoints (char *, int);
+
+static void create_longjmp_breakpoint (char *);
+
+static void create_overlay_event_breakpoint (char *);
+
+static int hw_breakpoint_used_count (void);
+
+static int hw_watchpoint_used_count (enum bptype, int *);
+
+static void hbreak_command (char *, int);
+
+static void thbreak_command (char *, int);
+
+static void watch_command_1 (char *, int, int);
+
+static void rwatch_command (char *, int);
+
+static void awatch_command (char *, int);
+
+static void do_enable_breakpoint (struct breakpoint *, enum bpdisp);
+
+static void solib_load_unload_1 (char *hookname,
+                                int tempflag,
+                                char *dll_pathname,
+                                char *cond_string, enum bptype bp_kind);
+
+static void create_fork_vfork_event_catchpoint (int tempflag,
+                                               char *cond_string,
+                                               enum bptype bp_kind);
+
+static void break_at_finish_at_depth_command_1 (char *arg,
+                                               int flag, int from_tty);
+
+static void break_at_finish_command_1 (char *arg, int flag, int from_tty);
+
+static void stop_command (char *arg, int from_tty);
+
+static void stopin_command (char *arg, int from_tty);
+
+static void stopat_command (char *arg, int from_tty);
+
+static char *ep_find_event_name_end (char *arg);
+
+static char *ep_parse_optional_if_clause (char **arg);
+
+static char *ep_parse_optional_filename (char **arg);
+
+#if defined(CHILD_INSERT_EXEC_CATCHPOINT)
+static void catch_exec_command_1 (char *arg, int tempflag, int from_tty);
+#endif
+
+static void create_exception_catchpoint (int tempflag, char *cond_string,
+                                        enum exception_event_kind ex_event,
+                                        struct symtab_and_line *sal);
+
+static void catch_exception_command_1 (enum exception_event_kind ex_event, 
+                                      char *arg, int tempflag, int from_tty);
+
+static void tcatch_command (char *arg, int from_tty);
+
+static void ep_skip_leading_whitespace (char **s);
+
+/* Prototypes for exported functions. */
+
+/* If FALSE, gdb will not use hardware support for watchpoints, even
+   if such is available. */
+static int can_use_hw_watchpoints;
+
+void _initialize_breakpoint (void);
+
+extern int addressprint;       /* Print machine addresses? */
+
+/* Are we executing breakpoint commands?  */
+static int executing_breakpoint_commands;
+
+/* Are overlay event breakpoints enabled? */
+static int overlay_events_enabled;
+
+/* Walk the following statement or block through all breakpoints.
+   ALL_BREAKPOINTS_SAFE does so even if the statment deletes the current
+   breakpoint.  */
+
+#define ALL_BREAKPOINTS(B)  for (B = breakpoint_chain; B; B = B->next)
+
+#define ALL_BREAKPOINTS_SAFE(B,TMP)    \
+       for (B = breakpoint_chain;      \
+            B ? (TMP=B->next, 1): 0;   \
+            B = TMP)
+
+/* True if SHIFT_INST_REGS defined, false otherwise.  */
+
+int must_shift_inst_regs =
+#if defined(SHIFT_INST_REGS)
+1
+#else
+0
+#endif
+ ;
+
+/* True if breakpoint hit counts should be displayed in breakpoint info.  */
+
+int show_breakpoint_hit_counts = 1;
+
+/* Chain of all breakpoints defined.  */
+
+struct breakpoint *breakpoint_chain;
+
+/* Number of last breakpoint made.  */
+
+int breakpoint_count;
+
+/* Pointer to current exception event record */
+static struct exception_event_record *current_exception_event;
+
+/* Indicator of whether exception catchpoints should be nuked
+   between runs of a program */
+int exception_catchpoints_are_fragile = 0;
+
+/* Indicator of when exception catchpoints set-up should be
+   reinitialized -- e.g. when program is re-run */
+int exception_support_initialized = 0;
+
+/* This function returns a pointer to the string representation of the
+   pathname of the dynamically-linked library that has just been
+   loaded.
+
+   This function must be used only when SOLIB_HAVE_LOAD_EVENT is TRUE,
+   or undefined results are guaranteed.
+
+   This string's contents are only valid immediately after the
+   inferior has stopped in the dynamic linker hook, and becomes
+   invalid as soon as the inferior is continued.  Clients should make
+   a copy of this string if they wish to continue the inferior and
+   then access the string.  */
+
+#ifndef SOLIB_LOADED_LIBRARY_PATHNAME
+#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) ""
+#endif
+
+/* This function returns a pointer to the string representation of the
+   pathname of the dynamically-linked library that has just been
+   unloaded.
+
+   This function must be used only when SOLIB_HAVE_UNLOAD_EVENT is
+   TRUE, or undefined results are guaranteed.
+
+   This string's contents are only valid immediately after the
+   inferior has stopped in the dynamic linker hook, and becomes
+   invalid as soon as the inferior is continued.  Clients should make
+   a copy of this string if they wish to continue the inferior and
+   then access the string.  */
+
+#ifndef SOLIB_UNLOADED_LIBRARY_PATHNAME
+#define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) ""
+#endif
+
+/* This function is called by the "catch load" command.  It allows the
+   debugger to be notified by the dynamic linker when a specified
+   library file (or any library file, if filename is NULL) is loaded.  */
+
+#ifndef SOLIB_CREATE_CATCH_LOAD_HOOK
+#define SOLIB_CREATE_CATCH_LOAD_HOOK(pid,tempflag,filename,cond_string) \
+   error ("catch of library loads not yet implemented on this platform")
+#endif
+
+/* This function is called by the "catch unload" command.  It allows
+   the debugger to be notified by the dynamic linker when a specified
+   library file (or any library file, if filename is NULL) is
+   unloaded.  */
+
+#ifndef SOLIB_CREATE_CATCH_UNLOAD_HOOK
+#define SOLIB_CREATE_CATCH_UNLOAD_HOOK(pid,tempflag,filename,cond_string) \
+   error ("catch of library unloads not yet implemented on this platform")
+#endif
+
+/* Set breakpoint count to NUM.  */
+
+void
+set_breakpoint_count (int num)
+{
+  breakpoint_count = num;
+  set_internalvar (lookup_internalvar ("bpnum"),
+                  value_from_longest (builtin_type_int, (LONGEST) num));
+}
+
+/* Used in run_command to zero the hit count when a new run starts. */
+
+void
+clear_breakpoint_hit_counts (void)
+{
+  struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    b->hit_count = 0;
+}
+
+/* Default address, symtab and line to put a breakpoint at
+   for "break" command with no arg.
+   if default_breakpoint_valid is zero, the other three are
+   not valid, and "break" with no arg is an error.
+
+   This set by print_stack_frame, which calls set_default_breakpoint.  */
+
+int default_breakpoint_valid;
+CORE_ADDR default_breakpoint_address;
+struct symtab *default_breakpoint_symtab;
+int default_breakpoint_line;
+\f
+/* *PP is a string denoting a breakpoint.  Get the number of the breakpoint.
+   Advance *PP after the string and any trailing whitespace.
+
+   Currently the string can either be a number or "$" followed by the name
+   of a convenience variable.  Making it an expression wouldn't work well
+   for map_breakpoint_numbers (e.g. "4 + 5 + 6").
+   
+   TRAILER is a character which can be found after the number; most
+   commonly this is `-'.  If you don't want a trailer, use \0.  */ 
+static int
+get_number_trailer (char **pp, int trailer)
+{
+  int retval = 0;      /* default */
+  char *p = *pp;
+
+  if (p == NULL)
+    /* Empty line means refer to the last breakpoint.  */
+    return breakpoint_count;
+  else if (*p == '$')
+    {
+      /* Make a copy of the name, so we can null-terminate it
+         to pass to lookup_internalvar().  */
+      char *varname;
+      char *start = ++p;
+      struct value *val;
+
+      while (isalnum (*p) || *p == '_')
+       p++;
+      varname = (char *) alloca (p - start + 1);
+      strncpy (varname, start, p - start);
+      varname[p - start] = '\0';
+      val = value_of_internalvar (lookup_internalvar (varname));
+      if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT)
+       retval = (int) value_as_long (val);
+      else
+       {
+         printf_filtered ("Convenience variable must have integer value.\n");
+         retval = 0;
+       }
+    }
+  else
+    {
+      if (*p == '-')
+       ++p;
+      while (*p >= '0' && *p <= '9')
+       ++p;
+      if (p == *pp)
+       /* There is no number here.  (e.g. "cond a == b").  */
+       {
+         /* Skip non-numeric token */
+         while (*p && !isspace((int) *p))
+           ++p;
+         /* Return zero, which caller must interpret as error. */
+         retval = 0;
+       }
+      else
+       retval = atoi (*pp);
+    }
+  if (!(isspace (*p) || *p == '\0' || *p == trailer))
+    {
+      /* Trailing junk: return 0 and let caller print error msg. */
+      while (!(isspace (*p) || *p == '\0' || *p == trailer))
+       ++p;
+      retval = 0;
+    }
+  while (isspace (*p))
+    p++;
+  *pp = p;
+  return retval;
+}
+
+
+/* Like get_number_trailer, but don't allow a trailer.  */
+int
+get_number (char **pp)
+{
+  return get_number_trailer (pp, '\0');
+}
+
+/* Parse a number or a range.
+ * A number will be of the form handled by get_number.
+ * A range will be of the form <number1> - <number2>, and 
+ * will represent all the integers between number1 and number2,
+ * inclusive.
+ *
+ * While processing a range, this fuction is called iteratively;
+ * At each call it will return the next value in the range.
+ *
+ * At the beginning of parsing a range, the char pointer PP will
+ * be advanced past <number1> and left pointing at the '-' token.
+ * Subsequent calls will not advance the pointer until the range
+ * is completed.  The call that completes the range will advance
+ * pointer PP past <number2>.
+ */
+
+int 
+get_number_or_range (char **pp)
+{
+  static int last_retval, end_value;
+  static char *end_ptr;
+  static int in_range = 0;
+
+  if (**pp != '-')
+    {
+      /* Default case: pp is pointing either to a solo number, 
+        or to the first number of a range.  */
+      last_retval = get_number_trailer (pp, '-');
+      if (**pp == '-')
+       {
+         char **temp;
+
+         /* This is the start of a range (<number1> - <number2>).
+            Skip the '-', parse and remember the second number,
+            and also remember the end of the final token.  */
+
+         temp = &end_ptr; 
+         end_ptr = *pp + 1; 
+         while (isspace ((int) *end_ptr))
+           end_ptr++;  /* skip white space */
+         end_value = get_number (temp);
+         if (end_value < last_retval) 
+           {
+             error ("inverted range");
+           }
+         else if (end_value == last_retval)
+           {
+             /* degenerate range (number1 == number2).  Advance the
+                token pointer so that the range will be treated as a
+                single number.  */ 
+             *pp = end_ptr;
+           }
+         else
+           in_range = 1;
+       }
+    }
+  else if (! in_range)
+    error ("negative value");
+  else
+    {
+      /* pp points to the '-' that betokens a range.  All
+        number-parsing has already been done.  Return the next
+        integer value (one greater than the saved previous value).
+        Do not advance the token pointer 'pp' until the end of range
+        is reached.  */
+
+      if (++last_retval == end_value)
+       {
+         /* End of range reached; advance token pointer.  */
+         *pp = end_ptr;
+         in_range = 0;
+       }
+    }
+  return last_retval;
+}
+
+
+\f
+/* condition N EXP -- set break condition of breakpoint N to EXP.  */
+
+static void
+condition_command (char *arg, int from_tty)
+{
+  register struct breakpoint *b;
+  char *p;
+  register int bnum;
+
+  if (arg == 0)
+    error_no_arg ("breakpoint number");
+
+  p = arg;
+  bnum = get_number (&p);
+  if (bnum == 0)
+    error ("Bad breakpoint argument: '%s'", arg);
+
+  ALL_BREAKPOINTS (b)
+    if (b->number == bnum)
+    {
+      if (b->cond)
+       {
+         xfree (b->cond);
+         b->cond = 0;
+       }
+      if (b->cond_string != NULL)
+       xfree (b->cond_string);
+
+      if (*p == 0)
+       {
+         b->cond = 0;
+         b->cond_string = NULL;
+         if (from_tty)
+           printf_filtered ("Breakpoint %d now unconditional.\n", bnum);
+       }
+      else
+       {
+         arg = p;
+         /* I don't know if it matters whether this is the string the user
+            typed in or the decompiled expression.  */
+         b->cond_string = savestring (arg, strlen (arg));
+         b->cond = parse_exp_1 (&arg, block_for_pc (b->address), 0);
+         if (*arg)
+           error ("Junk at end of expression");
+       }
+      breakpoints_changed ();
+      breakpoint_modify_event (b->number);
+      return;
+    }
+
+  error ("No breakpoint number %d.", bnum);
+}
+
+/* ARGSUSED */
+static void
+commands_command (char *arg, int from_tty)
+{
+  register struct breakpoint *b;
+  char *p;
+  register int bnum;
+  struct command_line *l;
+
+  /* If we allowed this, we would have problems with when to
+     free the storage, if we change the commands currently
+     being read from.  */
+
+  if (executing_breakpoint_commands)
+    error ("Can't use the \"commands\" command among a breakpoint's commands.");
+
+  p = arg;
+  bnum = get_number (&p);
+
+  if (p && *p)
+    error ("Unexpected extra arguments following breakpoint number.");
+
+  ALL_BREAKPOINTS (b)
+    if (b->number == bnum)
+    {
+      char tmpbuf[128];
+      sprintf (tmpbuf, 
+              "Type commands for when breakpoint %d is hit, one per line.", 
+              bnum);
+      l = read_command_lines (tmpbuf, from_tty);
+      free_command_lines (&b->commands);
+      b->commands = l;
+      breakpoints_changed ();
+      breakpoint_modify_event (b->number);
+      return;
+    }
+  error ("No breakpoint number %d.", bnum);
+}
+\f
+/* Like target_read_memory() but if breakpoints are inserted, return
+   the shadow contents instead of the breakpoints themselves.
+
+   Read "memory data" from whatever target or inferior we have. 
+   Returns zero if successful, errno value if not.  EIO is used
+   for address out of bounds.  If breakpoints are inserted, returns
+   shadow contents, not the breakpoints themselves.  From breakpoint.c.  */
+
+int
+read_memory_nobpt (CORE_ADDR memaddr, char *myaddr, unsigned len)
+{
+  int status;
+  struct breakpoint *b;
+  CORE_ADDR bp_addr = 0;
+  int bp_size = 0;
+
+  if (BREAKPOINT_FROM_PC (&bp_addr, &bp_size) == NULL)
+    /* No breakpoints on this machine. */
+    return target_read_memory (memaddr, myaddr, len);
+
+  ALL_BREAKPOINTS (b)
+  {
+    if (b->type == bp_none)
+      warning ("reading through apparently deleted breakpoint #%d?", 
+              b->number);
+
+    /* memory breakpoint? */
+    if (b->type == bp_watchpoint
+       || b->type == bp_hardware_watchpoint
+       || b->type == bp_read_watchpoint
+       || b->type == bp_access_watchpoint)
+      continue;
+    /* bp in memory? */
+    if (!b->inserted)
+      continue;
+    /* Addresses and length of the part of the breakpoint that
+       we need to copy.  */
+    /* XXXX The m68k, sh and h8300 have different local and remote
+       breakpoint values.  BREAKPOINT_FROM_PC still manages to
+       correctly determine the breakpoints memory address and size
+       for these targets. */
+    bp_addr = b->address;
+    bp_size = 0;
+    if (BREAKPOINT_FROM_PC (&bp_addr, &bp_size) == NULL)
+      continue;
+    if (bp_size == 0)
+      /* bp isn't valid */
+      continue;
+    if (bp_addr + bp_size <= memaddr)
+      /* The breakpoint is entirely before the chunk of memory we
+         are reading.  */
+      continue;
+    if (bp_addr >= memaddr + len)
+      /* The breakpoint is entirely after the chunk of memory we are
+         reading. */
+      continue;
+    /* Copy the breakpoint from the shadow contents, and recurse for
+       the things before and after.  */
+    {
+      /* Offset within shadow_contents.  */
+      int bptoffset = 0;
+
+      if (bp_addr < memaddr)
+       {
+         /* Only copy the second part of the breakpoint.  */
+         bp_size -= memaddr - bp_addr;
+         bptoffset = memaddr - bp_addr;
+         bp_addr = memaddr;
+       }
+
+      if (bp_addr + bp_size > memaddr + len)
+       {
+         /* Only copy the first part of the breakpoint.  */
+         bp_size -= (bp_addr + bp_size) - (memaddr + len);
+       }
+
+      memcpy (myaddr + bp_addr - memaddr,
+             b->shadow_contents + bptoffset, bp_size);
+
+      if (bp_addr > memaddr)
+       {
+         /* Copy the section of memory before the breakpoint.  */
+         status = read_memory_nobpt (memaddr, myaddr, bp_addr - memaddr);
+         if (status != 0)
+           return status;
+       }
+
+      if (bp_addr + bp_size < memaddr + len)
+       {
+         /* Copy the section of memory after the breakpoint.  */
+         status = read_memory_nobpt (bp_addr + bp_size,
+                                     myaddr + bp_addr + bp_size - memaddr,
+                                     memaddr + len - (bp_addr + bp_size));
+         if (status != 0)
+           return status;
+       }
+      return 0;
+    }
+  }
+  /* Nothing overlaps.  Just call read_memory_noerr.  */
+  return target_read_memory (memaddr, myaddr, len);
+}
+\f
+
+/* insert_breakpoints is used when starting or continuing the program.
+   remove_breakpoints is used when the program stops.
+   Both return zero if successful,
+   or an `errno' value if could not write the inferior.  */
+
+int
+insert_breakpoints (void)
+{
+  register struct breakpoint *b, *temp;
+  int return_val = 0;  /* return success code. */
+  int val = 0;
+  int disabled_breaks = 0;
+  int hw_breakpoint_error = 0;
+#ifdef ONE_PROCESS_WRITETEXT
+  int process_warning = 0;
+#endif
+
+  static char message1[] = "Error inserting catchpoint %d:\n";
+  static char message[sizeof (message1) + 30];
+
+  struct ui_file *tmp_error_stream = mem_fileopen ();
+  make_cleanup_ui_file_delete (tmp_error_stream);
+
+  /* Explicitly mark the warning -- this will only be printed if
+     there was an error.  */
+  fprintf_unfiltered (tmp_error_stream, "Warning:\n");
+
+  ALL_BREAKPOINTS_SAFE (b, temp)
+  {
+    if (b->enable_state == bp_permanent)
+      /* Permanent breakpoints cannot be inserted or removed.  */
+      continue;
+    if ((b->type == bp_watchpoint
+        || b->type == bp_hardware_watchpoint
+        || b->type == bp_read_watchpoint
+        || b->type == bp_access_watchpoint) && (!b->val))
+      {
+       struct value *val;
+       val = evaluate_expression (b->exp);
+       release_value (val);
+       if (VALUE_LAZY (val))
+         value_fetch_lazy (val);
+       b->val = val;
+      } 
+    if (b->type != bp_watchpoint
+       && b->type != bp_hardware_watchpoint
+       && b->type != bp_read_watchpoint
+       && b->type != bp_access_watchpoint
+       && b->type != bp_catch_fork
+       && b->type != bp_catch_vfork
+       && b->type != bp_catch_exec
+       && b->type != bp_catch_throw
+       && b->type != bp_catch_catch
+       && b->enable_state != bp_disabled
+       && b->enable_state != bp_shlib_disabled
+       && b->enable_state != bp_call_disabled
+       && !b->inserted
+       && !b->duplicate)
+      {
+       /* "Normal" instruction breakpoint: either the standard
+          trap-instruction bp (bp_breakpoint), or a
+          bp_hardware_breakpoint.  */
+
+       /* First check to see if we have to handle an overlay.  */
+       if (overlay_debugging == ovly_off
+           || b->section == NULL
+           || !(section_is_overlay (b->section)))
+         {
+           /* No overlay handling: just set the breakpoint.  */
+
+           if (b->type == bp_hardware_breakpoint)
+             val = target_insert_hw_breakpoint (b->address, 
+                                                b->shadow_contents);
+           else
+             val = target_insert_breakpoint (b->address, b->shadow_contents);
+         }
+       else
+         {
+           /* This breakpoint is in an overlay section.  
+              Shall we set a breakpoint at the LMA?  */
+           if (!overlay_events_enabled)
+             {
+               /* Yes -- overlay event support is not active, 
+                  so we must try to set a breakpoint at the LMA.
+                  This will not work for a hardware breakpoint.  */
+               if (b->type == bp_hardware_breakpoint)
+                 warning ("hardware breakpoint %d not supported in overlay!\n",
+                          b->number);
+               else
+                 {
+                   CORE_ADDR addr = overlay_unmapped_address (b->address, 
+                                                              b->section);
+                   /* Set a software (trap) breakpoint at the LMA.  */
+                   val = target_insert_breakpoint (addr, b->shadow_contents);
+                   if (val != 0)
+                     fprintf_unfiltered (tmp_error_stream, 
+                                         "Overlay breakpoint %d failed: in ROM?", 
+                                         b->number);
+                 }
+             }
+           /* Shall we set a breakpoint at the VMA? */
+           if (section_is_mapped (b->section))
+             {
+               /* Yes.  This overlay section is mapped into memory.  */
+               if (b->type == bp_hardware_breakpoint)
+                 val = target_insert_hw_breakpoint (b->address, 
+                                                    b->shadow_contents);
+               else
+                 val = target_insert_breakpoint (b->address,
+                                                 b->shadow_contents);
+             }
+           else
+             {
+               /* No.  This breakpoint will not be inserted.  
+                  No error, but do not mark the bp as 'inserted'.  */
+               continue;
+             }
+         }
+
+       if (val)
+         {
+           /* Can't set the breakpoint.  */
+#if defined (DISABLE_UNSETTABLE_BREAK)
+           if (DISABLE_UNSETTABLE_BREAK (b->address))
+             {
+               /* See also: disable_breakpoints_in_shlibs. */
+               val = 0;
+               b->enable_state = bp_shlib_disabled;
+               if (!disabled_breaks)
+                 {
+                   fprintf_unfiltered (tmp_error_stream, 
+                                       "Cannot insert breakpoint %d.\n", 
+                                       b->number);
+                   fprintf_unfiltered (tmp_error_stream, 
+                                       "Temporarily disabling shared library breakpoints:\n");
+                 }
+               disabled_breaks = 1;
+               fprintf_unfiltered (tmp_error_stream, 
+                                   "breakpoint #%d\n", b->number);
+             }
+           else
+#endif
+             {
+#ifdef ONE_PROCESS_WRITETEXT
+               process_warning = 1;
+#endif
+               if (b->type == bp_hardware_breakpoint)
+                 {
+                   hw_breakpoint_error = 1;
+                   fprintf_unfiltered (tmp_error_stream, 
+                                       "Cannot insert hardware breakpoint %d.\n",
+                                       b->number);
+                 }
+               else
+                 {
+                   fprintf_unfiltered (tmp_error_stream, 
+                                       "Cannot insert breakpoint %d.\n", 
+                                       b->number);
+                   fprintf_filtered (tmp_error_stream, 
+                                     "Error accessing memory address ");
+                   print_address_numeric (b->address, 1, tmp_error_stream);
+                   fprintf_filtered (tmp_error_stream, ": %s.\n",
+                                     safe_strerror (val));
+                 }
+
+             }
+         }
+       else
+         b->inserted = 1;
+
+       if (val)
+         return_val = val;     /* remember failure */
+      }
+    else if (ep_is_exception_catchpoint (b)
+            && b->enable_state != bp_disabled
+            && b->enable_state != bp_shlib_disabled
+            && b->enable_state != bp_call_disabled
+            && !b->inserted
+            && !b->duplicate)
+
+      {
+       /* If we get here, we must have a callback mechanism for exception
+          events -- with g++ style embedded label support, we insert
+          ordinary breakpoints and not catchpoints. */
+       /* Format possible error message */
+       sprintf (message, message1, b->number);
+
+       val = target_insert_breakpoint (b->address, b->shadow_contents);
+       if (val)
+         {
+           /* Couldn't set breakpoint for some reason */
+           fprintf_unfiltered (tmp_error_stream, 
+                               "Cannot insert catchpoint %d; disabling it.\n",
+                               b->number);
+           fprintf_filtered (tmp_error_stream, 
+                             "Error accessing memory address ");
+           print_address_numeric (b->address, 1, tmp_error_stream);
+           fprintf_filtered (tmp_error_stream, ": %s.\n",
+                             safe_strerror (val));
+           b->enable_state = bp_disabled;
+         }
+       else
+         {
+           /* Bp set, now make sure callbacks are enabled */
+           int val;
+           args_for_catchpoint_enable args;
+           args.kind = b->type == bp_catch_catch ? 
+             EX_EVENT_CATCH : EX_EVENT_THROW;
+           args.enable_p = 1;
+           val = catch_errors (cover_target_enable_exception_callback,
+                               &args,
+                               message, RETURN_MASK_ALL);
+           if (val != 0 && val != -1)
+             {
+               b->inserted = 1;
+             }
+           /* Check if something went wrong; val == 0 can be ignored */
+           if (val == -1)
+             {
+               /* something went wrong */
+               fprintf_unfiltered (tmp_error_stream, 
+                                   "Cannot insert catchpoint %d; disabling it.\n",
+                                   b->number);
+               b->enable_state = bp_disabled;
+             }
+         }
+
+       if (val)
+         return_val = val;     /* remember failure */
+      }
+
+    else if ((b->type == bp_hardware_watchpoint ||
+             b->type == bp_read_watchpoint ||
+             b->type == bp_access_watchpoint)
+            && b->enable_state == bp_enabled
+            && b->disposition != disp_del_at_next_stop
+            && !b->inserted
+            && !b->duplicate)
+      {
+       struct frame_info *saved_frame;
+       int saved_level, within_current_scope;
+       struct value *mark = value_mark ();
+       struct value *v;
+
+       /* Save the current frame and level so we can restore it after
+          evaluating the watchpoint expression on its own frame.  */
+       saved_frame = selected_frame;
+       saved_level = frame_relative_level (selected_frame);
+
+       /* Determine if the watchpoint is within scope.  */
+       if (b->exp_valid_block == NULL)
+         within_current_scope = 1;
+       else
+         {
+           struct frame_info *fi;
+           fi = frame_find_by_id (b->watchpoint_frame);
+           within_current_scope = (fi != NULL);
+           if (within_current_scope)
+             select_frame (fi);
+         }
+
+       if (within_current_scope)
+         {
+           /* Evaluate the expression and cut the chain of values
+              produced off from the value chain.
+
+              Make sure the value returned isn't lazy; we use
+              laziness to determine what memory GDB actually needed
+              in order to compute the value of the expression.  */
+           v = evaluate_expression (b->exp);
+           VALUE_CONTENTS(v);
+           value_release_to_mark (mark);
+
+           b->val_chain = v;
+           b->inserted = 1;
+
+           /* Look at each value on the value chain.  */
+           for (; v; v = v->next)
+             {
+               /* If it's a memory location, and GDB actually needed
+                   its contents to evaluate the expression, then we
+                   must watch it.  */
+               if (VALUE_LVAL (v) == lval_memory
+                   && ! VALUE_LAZY (v))
+                 {
+                   struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+                   /* We only watch structs and arrays if user asked
+                      for it explicitly, never if they just happen to
+                      appear in the middle of some value chain.  */
+                   if (v == b->val_chain
+                       || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+                           && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+                     {
+                       CORE_ADDR addr;
+                       int len, type;
+
+                       addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+                       len = TYPE_LENGTH (VALUE_TYPE (v));
+                       type = hw_write;
+                       if (b->type == bp_read_watchpoint)
+                         type = hw_read;
+                       else if (b->type == bp_access_watchpoint)
+                         type = hw_access;
+
+                       val = target_insert_watchpoint (addr, len, type);
+                       if (val == -1)
+                         {
+                           /* Don't exit the loop, try to insert
+                              every value on the value chain.  That's
+                              because we will be removing all the
+                              watches below, and removing a
+                              watchpoint we didn't insert could have
+                              adverse effects.  */
+                           b->inserted = 0;
+                         }
+                       val = 0;
+                     }
+                 }
+             }
+           /* Failure to insert a watchpoint on any memory value in the
+              value chain brings us here.  */
+           if (!b->inserted)
+             {
+               remove_breakpoint (b, mark_uninserted);
+               hw_breakpoint_error = 1;
+               fprintf_unfiltered (tmp_error_stream,
+                                   "Could not insert hardware watchpoint %d.\n", 
+                                   b->number);
+               val = -1;
+             }               
+         }
+       else
+         {
+           printf_filtered ("Hardware watchpoint %d deleted ", b->number);
+           printf_filtered ("because the program has left the block \n");
+           printf_filtered ("in which its expression is valid.\n");
+           if (b->related_breakpoint)
+             b->related_breakpoint->disposition = disp_del_at_next_stop;
+           b->disposition = disp_del_at_next_stop;
+         }
+
+       /* Restore the frame and level.  */
+       if ((saved_frame != selected_frame) ||
+           (saved_level != frame_relative_level (selected_frame)))
+         select_frame (saved_frame);
+
+       if (val)
+         return_val = val;     /* remember failure */
+      }
+    else if ((b->type == bp_catch_fork
+             || b->type == bp_catch_vfork
+             || b->type == bp_catch_exec)
+            && b->enable_state == bp_enabled
+            && !b->inserted
+            && !b->duplicate)
+      {
+       val = -1;
+       switch (b->type)
+         {
+         case bp_catch_fork:
+           val = target_insert_fork_catchpoint (PIDGET (inferior_ptid));
+           break;
+         case bp_catch_vfork:
+           val = target_insert_vfork_catchpoint (PIDGET (inferior_ptid));
+           break;
+         case bp_catch_exec:
+           val = target_insert_exec_catchpoint (PIDGET (inferior_ptid));
+           break;
+         default:
+           warning ("Internal error, %s line %d.", __FILE__, __LINE__);
+           break;
+         }
+       if (val < 0)
+         {
+           fprintf_unfiltered (tmp_error_stream, 
+                               "Cannot insert catchpoint %d.", b->number);
+         }
+       else
+         b->inserted = 1;
+
+       if (val)
+         return_val = val;     /* remember failure */
+      }
+  }
+  
+  if (return_val) 
+    {
+      /* If a hardware breakpoint or watchpoint was inserted, add a
+         message about possibly exhausted resources.  */
+      if (hw_breakpoint_error)  
+       {
+         fprintf_unfiltered (tmp_error_stream, 
+                             "Could not insert hardware breakpoints:\n\
+You may have requested too many hardware breakpoints/watchpoints.\n");
+       }
+#ifdef ONE_PROCESS_WRITETEXT
+      if (process_warning)
+       fprintf_unfiltered (tmp_error_stream,
+                           "The same program may be running in another process.");
+#endif
+      target_terminal_ours_for_output ();
+      error_stream (tmp_error_stream);
+    }
+  return return_val;
+}
+
+int
+remove_breakpoints (void)
+{
+  register struct breakpoint *b;
+  int val;
+
+  ALL_BREAKPOINTS (b)
+  {
+    if (b->inserted)
+      {
+       val = remove_breakpoint (b, mark_uninserted);
+       if (val != 0)
+         return val;
+      }
+  }
+  return 0;
+}
+
+int
+remove_hw_watchpoints (void)
+{
+  register struct breakpoint *b;
+  int val;
+
+  ALL_BREAKPOINTS (b)
+  {
+    if (b->inserted
+       && (b->type == bp_hardware_watchpoint
+           || b->type == bp_read_watchpoint
+           || b->type == bp_access_watchpoint))
+      {
+       val = remove_breakpoint (b, mark_uninserted);
+       if (val != 0)
+         return val;
+      }
+  }
+  return 0;
+}
+
+int
+reattach_breakpoints (int pid)
+{
+  register struct breakpoint *b;
+  int val;
+  struct cleanup *old_chain = save_inferior_ptid ();
+
+  /* Set inferior_ptid; remove_breakpoint uses this global.  */
+  inferior_ptid = pid_to_ptid (pid);
+  ALL_BREAKPOINTS (b)
+  {
+    if (b->inserted)
+      {
+       remove_breakpoint (b, mark_inserted);
+       if (b->type == bp_hardware_breakpoint)
+         val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
+       else
+         val = target_insert_breakpoint (b->address, b->shadow_contents);
+       if (val != 0)
+         {
+           do_cleanups (old_chain);
+           return val;
+         }
+      }
+  }
+  do_cleanups (old_chain);
+  return 0;
+}
+
+void
+update_breakpoints_after_exec (void)
+{
+  struct breakpoint *b;
+  struct breakpoint *temp;
+
+  /* Doing this first prevents the badness of having delete_breakpoint()
+     write a breakpoint's current "shadow contents" to lift the bp.  That
+     shadow is NOT valid after an exec()! */
+  mark_breakpoints_out ();
+
+  ALL_BREAKPOINTS_SAFE (b, temp)
+  {
+    /* Solib breakpoints must be explicitly reset after an exec(). */
+    if (b->type == bp_shlib_event)
+      {
+       delete_breakpoint (b);
+       continue;
+      }
+
+    /* Thread event breakpoints must be set anew after an exec(),
+       as must overlay event breakpoints.  */
+    if (b->type == bp_thread_event || b->type == bp_overlay_event)
+      {
+       delete_breakpoint (b);
+       continue;
+      }
+
+    /* Step-resume breakpoints are meaningless after an exec(). */
+    if (b->type == bp_step_resume)
+      {
+       delete_breakpoint (b);
+       continue;
+      }
+
+    /* Ditto the sigtramp handler breakpoints. */
+    if (b->type == bp_through_sigtramp)
+      {
+       delete_breakpoint (b);
+       continue;
+      }
+
+    /* Ditto the exception-handling catchpoints. */
+    if ((b->type == bp_catch_catch) || (b->type == bp_catch_throw))
+      {
+       delete_breakpoint (b);
+       continue;
+      }
+
+    /* Don't delete an exec catchpoint, because else the inferior
+       won't stop when it ought!
+
+       Similarly, we probably ought to keep vfork catchpoints, 'cause
+       on this target, we may not be able to stop when the vfork is
+       seen, but only when the subsequent exec is seen.  (And because
+       deleting fork catchpoints here but not vfork catchpoints will
+       seem mysterious to users, keep those too.)
+
+       ??rehrauer: Let's hope that merely clearing out this catchpoint's
+       target address field, if any, is sufficient to have it be reset
+       automagically.  Certainly on HP-UX that's true.
+
+       Jim Blandy <jimb@redhat.com>: Actually, zero is a perfectly
+       valid code address on some platforms (like the mn10200 and
+       mn10300 simulators).  We shouldn't assign any special
+       interpretation to a breakpoint with a zero address.  And in
+       fact, GDB doesn't --- I can't see what that comment above is
+       talking about.  As far as I can tell, setting the address of a
+       bp_catch_exec/bp_catch_vfork/bp_catch_fork breakpoint to zero
+       is meaningless, since those are implemented with HP-UX kernel
+       hackery, not by storing breakpoint instructions somewhere.  */
+    if ((b->type == bp_catch_exec) ||
+       (b->type == bp_catch_vfork) ||
+       (b->type == bp_catch_fork))
+      {
+       b->address = (CORE_ADDR) NULL;
+       continue;
+      }
+
+    /* bp_finish is a special case.  The only way we ought to be able
+       to see one of these when an exec() has happened, is if the user
+       caught a vfork, and then said "finish".  Ordinarily a finish just
+       carries them to the call-site of the current callee, by setting
+       a temporary bp there and resuming.  But in this case, the finish
+       will carry them entirely through the vfork & exec.
+
+       We don't want to allow a bp_finish to remain inserted now.  But
+       we can't safely delete it, 'cause finish_command has a handle to
+       the bp on a bpstat, and will later want to delete it.  There's a
+       chance (and I've seen it happen) that if we delete the bp_finish
+       here, that its storage will get reused by the time finish_command
+       gets 'round to deleting the "use to be a bp_finish" breakpoint.
+       We really must allow finish_command to delete a bp_finish.
+
+       In the absense of a general solution for the "how do we know
+       it's safe to delete something others may have handles to?"
+       problem, what we'll do here is just uninsert the bp_finish, and
+       let finish_command delete it.
+
+       (We know the bp_finish is "doomed" in the sense that it's
+       momentary, and will be deleted as soon as finish_command sees
+       the inferior stopped.  So it doesn't matter that the bp's
+       address is probably bogus in the new a.out, unlike e.g., the
+       solib breakpoints.)  */
+
+    if (b->type == bp_finish)
+      {
+       continue;
+      }
+
+    /* Without a symbolic address, we have little hope of the
+       pre-exec() address meaning the same thing in the post-exec()
+       a.out. */
+    if (b->addr_string == NULL)
+      {
+       delete_breakpoint (b);
+       continue;
+      }
+
+    /* If this breakpoint has survived the above battery of checks, then
+       it must have a symbolic address.  Be sure that it gets reevaluated
+       to a target address, rather than reusing the old evaluation.
+
+       Jim Blandy <jimb@redhat.com>: As explained above in the comment
+       for bp_catch_exec and friends, I'm pretty sure this is entirely
+       unnecessary.  A call to breakpoint_re_set_one always recomputes
+       the breakpoint's address from scratch, or deletes it if it can't.
+       So I think this assignment could be deleted without effect.  */
+    b->address = (CORE_ADDR) NULL;
+  }
+  /* FIXME what about longjmp breakpoints?  Re-create them here?  */
+  create_overlay_event_breakpoint ("_ovly_debug_event");
+}
+
+int
+detach_breakpoints (int pid)
+{
+  register struct breakpoint *b;
+  int val;
+  struct cleanup *old_chain = save_inferior_ptid ();
+
+  if (pid == PIDGET (inferior_ptid))
+    error ("Cannot detach breakpoints of inferior_ptid");
+
+  /* Set inferior_ptid; remove_breakpoint uses this global.  */
+  inferior_ptid = pid_to_ptid (pid);
+  ALL_BREAKPOINTS (b)
+  {
+    if (b->inserted)
+      {
+       val = remove_breakpoint (b, mark_inserted);
+       if (val != 0)
+         {
+           do_cleanups (old_chain);
+           return val;
+         }
+      }
+  }
+  do_cleanups (old_chain);
+  return 0;
+}
+
+static int
+remove_breakpoint (struct breakpoint *b, insertion_state_t is)
+{
+  int val;
+
+  if (b->enable_state == bp_permanent)
+    /* Permanent breakpoints cannot be inserted or removed.  */
+    return 0;
+
+  if (b->type == bp_none)
+    warning ("attempted to remove apparently deleted breakpoint #%d?", 
+            b->number);
+
+  if (b->type != bp_watchpoint
+      && b->type != bp_hardware_watchpoint
+      && b->type != bp_read_watchpoint
+      && b->type != bp_access_watchpoint
+      && b->type != bp_catch_fork
+      && b->type != bp_catch_vfork
+      && b->type != bp_catch_exec
+      && b->type != bp_catch_catch
+      && b->type != bp_catch_throw)
+    {
+      /* "Normal" instruction breakpoint: either the standard
+        trap-instruction bp (bp_breakpoint), or a
+        bp_hardware_breakpoint.  */
+
+      /* First check to see if we have to handle an overlay.  */
+      if (overlay_debugging == ovly_off
+         || b->section == NULL
+         || !(section_is_overlay (b->section)))
+       {
+         /* No overlay handling: just remove the breakpoint.  */
+
+         if (b->type == bp_hardware_breakpoint)
+           val = target_remove_hw_breakpoint (b->address, 
+                                              b->shadow_contents);
+         else
+           val = target_remove_breakpoint (b->address, b->shadow_contents);
+       }
+      else
+       {
+         /* This breakpoint is in an overlay section.  
+            Did we set a breakpoint at the LMA?  */
+         if (!overlay_events_enabled)
+             {
+               /* Yes -- overlay event support is not active, so we
+                  should have set a breakpoint at the LMA.  Remove it.  
+               */
+               CORE_ADDR addr = overlay_unmapped_address (b->address, 
+                                                          b->section);
+               /* Ignore any failures: if the LMA is in ROM, we will
+                  have already warned when we failed to insert it.  */
+               if (b->type != bp_hardware_breakpoint)
+                 target_remove_hw_breakpoint (addr, b->shadow_contents);
+               else
+                 target_remove_breakpoint (addr, b->shadow_contents);
+             }
+         /* Did we set a breakpoint at the VMA? 
+            If so, we will have marked the breakpoint 'inserted'.  */
+         if (b->inserted)
+           {
+             /* Yes -- remove it.  Previously we did not bother to
+                remove the breakpoint if the section had been
+                unmapped, but let's not rely on that being safe.  We
+                don't know what the overlay manager might do.  */
+             if (b->type == bp_hardware_breakpoint)
+               val = target_remove_hw_breakpoint (b->address, 
+                                                  b->shadow_contents);
+             else
+               val = target_remove_breakpoint (b->address,
+                                               b->shadow_contents);
+           }
+         else
+           {
+             /* No -- not inserted, so no need to remove.  No error.  */
+             val = 0;
+           }
+       }
+      if (val)
+       return val;
+      b->inserted = (is == mark_inserted);
+    }
+  else if ((b->type == bp_hardware_watchpoint ||
+           b->type == bp_read_watchpoint ||
+           b->type == bp_access_watchpoint)
+          && b->enable_state == bp_enabled
+          && !b->duplicate)
+    {
+      struct value *v;
+      struct value *n;
+
+      b->inserted = (is == mark_inserted);
+      /* Walk down the saved value chain.  */
+      for (v = b->val_chain; v; v = v->next)
+       {
+         /* For each memory reference remove the watchpoint
+            at that address.  */
+         if (VALUE_LVAL (v) == lval_memory
+             && ! VALUE_LAZY (v))
+           {
+             struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+             if (v == b->val_chain
+                 || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+                     && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+               {
+                 CORE_ADDR addr;
+                 int len, type;
+
+                 addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+                 len = TYPE_LENGTH (VALUE_TYPE (v));
+                 type   = hw_write;
+                 if (b->type == bp_read_watchpoint)
+                   type = hw_read;
+                 else if (b->type == bp_access_watchpoint)
+                   type = hw_access;
+
+                 val = target_remove_watchpoint (addr, len, type);
+                 if (val == -1)
+                   b->inserted = 1;
+                 val = 0;
+               }
+           }
+       }
+      /* Failure to remove any of the hardware watchpoints comes here.  */
+      if ((is == mark_uninserted) && (b->inserted))
+       warning ("Could not remove hardware watchpoint %d.",
+                b->number);
+
+      /* Free the saved value chain.  We will construct a new one
+         the next time the watchpoint is inserted.  */
+      for (v = b->val_chain; v; v = n)
+       {
+         n = v->next;
+         value_free (v);
+       }
+      b->val_chain = NULL;
+    }
+  else if ((b->type == bp_catch_fork ||
+           b->type == bp_catch_vfork ||
+           b->type == bp_catch_exec)
+          && b->enable_state == bp_enabled
+          && !b->duplicate)
+    {
+      val = -1;
+      switch (b->type)
+       {
+       case bp_catch_fork:
+         val = target_remove_fork_catchpoint (PIDGET (inferior_ptid));
+         break;
+       case bp_catch_vfork:
+         val = target_remove_vfork_catchpoint (PIDGET (inferior_ptid));
+         break;
+       case bp_catch_exec:
+         val = target_remove_exec_catchpoint (PIDGET (inferior_ptid));
+         break;
+       default:
+         warning ("Internal error, %s line %d.", __FILE__, __LINE__);
+         break;
+       }
+      if (val)
+       return val;
+      b->inserted = (is == mark_inserted);
+    }
+  else if ((b->type == bp_catch_catch ||
+           b->type == bp_catch_throw)
+          && b->enable_state == bp_enabled
+          && !b->duplicate)
+    {
+
+      val = target_remove_breakpoint (b->address, b->shadow_contents);
+      if (val)
+       return val;
+      b->inserted = (is == mark_inserted);
+    }
+  else if (ep_is_exception_catchpoint (b)
+          && b->inserted       /* sometimes previous insert doesn't happen */
+          && b->enable_state == bp_enabled
+          && !b->duplicate)
+    {
+
+      val = target_remove_breakpoint (b->address, b->shadow_contents);
+      if (val)
+       return val;
+
+      b->inserted = (is == mark_inserted);
+    }
+
+  return 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints.  */
+
+void
+mark_breakpoints_out (void)
+{
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    b->inserted = 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints and delete any
+   breakpoints which should go away between runs of the program.
+
+   Plus other such housekeeping that has to be done for breakpoints
+   between runs.
+
+   Note: this function gets called at the end of a run (by
+   generic_mourn_inferior) and when a run begins (by
+   init_wait_for_inferior). */
+
+
+
+void
+breakpoint_init_inferior (enum inf_context context)
+{
+  register struct breakpoint *b, *temp;
+  static int warning_needed = 0;
+
+  ALL_BREAKPOINTS_SAFE (b, temp)
+  {
+    b->inserted = 0;
+
+    switch (b->type)
+      {
+      case bp_call_dummy:
+      case bp_watchpoint_scope:
+
+       /* If the call dummy breakpoint is at the entry point it will
+          cause problems when the inferior is rerun, so we better
+          get rid of it. 
+
+          Also get rid of scope breakpoints.  */
+       delete_breakpoint (b);
+       break;
+
+      case bp_watchpoint:
+      case bp_hardware_watchpoint:
+      case bp_read_watchpoint:
+      case bp_access_watchpoint:
+
+       /* Likewise for watchpoints on local expressions.  */
+       if (b->exp_valid_block != NULL)
+         delete_breakpoint (b);
+       if (context == inf_starting) 
+         {
+           /* Reset val field to force reread of starting value
+              in insert_breakpoints.  */
+           if (b->val)
+             value_free (b->val);
+           b->val = NULL;
+         }
+       break;
+      default:
+       /* Likewise for exception catchpoints in dynamic-linked
+          executables where required */
+       if (ep_is_exception_catchpoint (b) &&
+           exception_catchpoints_are_fragile)
+         {
+           warning_needed = 1;
+           delete_breakpoint (b);
+         }
+       break;
+      }
+  }
+
+  if (exception_catchpoints_are_fragile)
+    exception_support_initialized = 0;
+
+  /* Don't issue the warning unless it's really needed... */
+  if (warning_needed && (context != inf_exited))
+    {
+      warning ("Exception catchpoints from last run were deleted.");
+      warning ("You must reinsert them explicitly.");
+      warning_needed = 0;
+    }
+}
+
+/* breakpoint_here_p (PC) returns non-zero if an enabled breakpoint
+   exists at PC.  It returns ordinary_breakpoint_here if it's an
+   ordinary breakpoint, or permanent_breakpoint_here if it's a
+   permanent breakpoint.
+   - When continuing from a location with an ordinary breakpoint, we
+     actually single step once before calling insert_breakpoints.
+   - When continuing from a localion with a permanent breakpoint, we
+     need to use the `SKIP_PERMANENT_BREAKPOINT' macro, provided by
+     the target, to advance the PC past the breakpoint.  */
+
+enum breakpoint_here
+breakpoint_here_p (CORE_ADDR pc)
+{
+  register struct breakpoint *b;
+  int any_breakpoint_here = 0;
+
+  ALL_BREAKPOINTS (b)
+    if ((b->enable_state == bp_enabled
+        || b->enable_state == bp_permanent)
+       && b->address == pc)    /* bp is enabled and matches pc */
+      {
+       if (overlay_debugging 
+           && section_is_overlay (b->section) 
+           && !section_is_mapped (b->section))
+         continue;             /* unmapped overlay -- can't be a match */
+       else if (b->enable_state == bp_permanent)
+         return permanent_breakpoint_here;
+       else
+         any_breakpoint_here = 1;
+      }
+
+  return any_breakpoint_here ? ordinary_breakpoint_here : 0;
+}
+
+
+/* breakpoint_inserted_here_p (PC) is just like breakpoint_here_p(),
+   but it only returns true if there is actually a breakpoint inserted
+   at PC.  */
+
+int
+breakpoint_inserted_here_p (CORE_ADDR pc)
+{
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->inserted
+       && b->address == pc)    /* bp is inserted and matches pc */
+    {
+      if (overlay_debugging 
+         && section_is_overlay (b->section) 
+         && !section_is_mapped (b->section))
+       continue;               /* unmapped overlay -- can't be a match */
+      else
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Return nonzero if FRAME is a dummy frame.  We can't use
+   PC_IN_CALL_DUMMY because figuring out the saved SP would take too
+   much time, at least using get_saved_register on the 68k.  This
+   means that for this function to work right a port must use the
+   bp_call_dummy breakpoint.  */
+
+int
+frame_in_dummy (struct frame_info *frame)
+{
+  struct breakpoint *b;
+
+  if (!CALL_DUMMY_P)
+    return 0;
+
+  if (USE_GENERIC_DUMMY_FRAMES)
+    return generic_pc_in_call_dummy (frame->pc, frame->frame, frame->frame);
+
+  ALL_BREAKPOINTS (b)
+  {
+    if (b->type == bp_call_dummy
+       && b->frame == frame->frame
+    /* We need to check the PC as well as the frame on the sparc,
+       for signals.exp in the testsuite.  */
+       && (frame->pc
+           >= (b->address
+             - SIZEOF_CALL_DUMMY_WORDS / sizeof (LONGEST) * REGISTER_SIZE))
+       && frame->pc <= b->address)
+      return 1;
+  }
+  return 0;
+}
+
+/* breakpoint_thread_match (PC, PID) returns true if the breakpoint at
+   PC is valid for process/thread PID.  */
+
+int
+breakpoint_thread_match (CORE_ADDR pc, ptid_t ptid)
+{
+  struct breakpoint *b;
+  int thread;
+
+  thread = pid_to_thread_id (ptid);
+
+  ALL_BREAKPOINTS (b)
+    if (b->enable_state != bp_disabled
+       && b->enable_state != bp_shlib_disabled
+       && b->enable_state != bp_call_disabled
+       && b->address == pc
+       && (b->thread == -1 || b->thread == thread))
+    {
+      if (overlay_debugging 
+         && section_is_overlay (b->section) 
+         && !section_is_mapped (b->section))
+       continue;               /* unmapped overlay -- can't be a match */
+      else
+       return 1;
+    }
+
+  return 0;
+}
+\f
+
+/* bpstat stuff.  External routines' interfaces are documented
+   in breakpoint.h.  */
+
+int
+ep_is_catchpoint (struct breakpoint *ep)
+{
+  return
+    (ep->type == bp_catch_load)
+    || (ep->type == bp_catch_unload)
+    || (ep->type == bp_catch_fork)
+    || (ep->type == bp_catch_vfork)
+    || (ep->type == bp_catch_exec)
+    || (ep->type == bp_catch_catch)
+    || (ep->type == bp_catch_throw);
+
+  /* ??rehrauer: Add more kinds here, as are implemented... */
+}
+
+int
+ep_is_shlib_catchpoint (struct breakpoint *ep)
+{
+  return
+    (ep->type == bp_catch_load)
+    || (ep->type == bp_catch_unload);
+}
+
+int
+ep_is_exception_catchpoint (struct breakpoint *ep)
+{
+  return
+    (ep->type == bp_catch_catch)
+    || (ep->type == bp_catch_throw);
+}
+
+/* Clear a bpstat so that it says we are not at any breakpoint.
+   Also free any storage that is part of a bpstat.  */
+
+void
+bpstat_clear (bpstat *bsp)
+{
+  bpstat p;
+  bpstat q;
+
+  if (bsp == 0)
+    return;
+  p = *bsp;
+  while (p != NULL)
+    {
+      q = p->next;
+      if (p->old_val != NULL)
+       value_free (p->old_val);
+      free_command_lines (&p->commands);
+      xfree (p);
+      p = q;
+    }
+  *bsp = NULL;
+}
+
+/* Return a copy of a bpstat.  Like "bs1 = bs2" but all storage that
+   is part of the bpstat is copied as well.  */
+
+bpstat
+bpstat_copy (bpstat bs)
+{
+  bpstat p = NULL;
+  bpstat tmp;
+  bpstat retval = NULL;
+
+  if (bs == NULL)
+    return bs;
+
+  for (; bs != NULL; bs = bs->next)
+    {
+      tmp = (bpstat) xmalloc (sizeof (*tmp));
+      memcpy (tmp, bs, sizeof (*tmp));
+      if (p == NULL)
+       /* This is the first thing in the chain.  */
+       retval = tmp;
+      else
+       p->next = tmp;
+      p = tmp;
+    }
+  p->next = NULL;
+  return retval;
+}
+
+/* Find the bpstat associated with this breakpoint */
+
+bpstat
+bpstat_find_breakpoint (bpstat bsp, struct breakpoint *breakpoint)
+{
+  if (bsp == NULL)
+    return NULL;
+
+  for (; bsp != NULL; bsp = bsp->next)
+    {
+      if (bsp->breakpoint_at == breakpoint)
+       return bsp;
+    }
+  return NULL;
+}
+
+/* Find a step_resume breakpoint associated with this bpstat.
+   (If there are multiple step_resume bp's on the list, this function
+   will arbitrarily pick one.)
+
+   It is an error to use this function if BPSTAT doesn't contain a
+   step_resume breakpoint.
+
+   See wait_for_inferior's use of this function.  */
+struct breakpoint *
+bpstat_find_step_resume_breakpoint (bpstat bsp)
+{
+  int current_thread;
+
+  if (bsp == NULL)
+    error ("Internal error (bpstat_find_step_resume_breakpoint)");
+
+  current_thread = pid_to_thread_id (inferior_ptid);
+
+  for (; bsp != NULL; bsp = bsp->next)
+    {
+      if ((bsp->breakpoint_at != NULL) &&
+         (bsp->breakpoint_at->type == bp_step_resume) &&
+         (bsp->breakpoint_at->thread == current_thread || 
+          bsp->breakpoint_at->thread == -1))
+       return bsp->breakpoint_at;
+    }
+
+  error ("Internal error (no step_resume breakpoint found)");
+}
+
+
+/* Return the breakpoint number of the first breakpoint we are stopped
+   at.  *BSP upon return is a bpstat which points to the remaining
+   breakpoints stopped at (but which is not guaranteed to be good for
+   anything but further calls to bpstat_num).
+   Return 0 if passed a bpstat which does not indicate any breakpoints.  */
+
+int
+bpstat_num (bpstat *bsp)
+{
+  struct breakpoint *b;
+
+  if ((*bsp) == NULL)
+    return 0;                  /* No more breakpoint values */
+  else
+    {
+      b = (*bsp)->breakpoint_at;
+      *bsp = (*bsp)->next;
+      if (b == NULL)
+       return -1;              /* breakpoint that's been deleted since */
+      else
+       return b->number;       /* We have its number */
+    }
+}
+
+/* Modify BS so that the actions will not be performed.  */
+
+void
+bpstat_clear_actions (bpstat bs)
+{
+  for (; bs != NULL; bs = bs->next)
+    {
+      free_command_lines (&bs->commands);
+      if (bs->old_val != NULL)
+       {
+         value_free (bs->old_val);
+         bs->old_val = NULL;
+       }
+    }
+}
+
+/* Stub for cleaning up our state if we error-out of a breakpoint command */
+/* ARGSUSED */
+static void
+cleanup_executing_breakpoints (PTR ignore)
+{
+  executing_breakpoint_commands = 0;
+}
+
+/* Execute all the commands associated with all the breakpoints at this
+   location.  Any of these commands could cause the process to proceed
+   beyond this point, etc.  We look out for such changes by checking
+   the global "breakpoint_proceeded" after each command.  */
+
+void
+bpstat_do_actions (bpstat *bsp)
+{
+  bpstat bs;
+  struct cleanup *old_chain;
+  struct command_line *cmd;
+
+  /* Avoid endless recursion if a `source' command is contained
+     in bs->commands.  */
+  if (executing_breakpoint_commands)
+    return;
+
+  executing_breakpoint_commands = 1;
+  old_chain = make_cleanup (cleanup_executing_breakpoints, 0);
+
+top:
+  /* Note that (as of this writing), our callers all appear to
+     be passing us the address of global stop_bpstat.  And, if
+     our calls to execute_control_command cause the inferior to
+     proceed, that global (and hence, *bsp) will change.
+
+     We must be careful to not touch *bsp unless the inferior
+     has not proceeded. */
+
+  /* This pointer will iterate over the list of bpstat's. */
+  bs = *bsp;
+
+  breakpoint_proceeded = 0;
+  for (; bs != NULL; bs = bs->next)
+    {
+      cmd = bs->commands;
+      while (cmd != NULL)
+       {
+         execute_control_command (cmd);
+
+         if (breakpoint_proceeded)
+           break;
+         else
+           cmd = cmd->next;
+       }
+      if (breakpoint_proceeded)
+       /* The inferior is proceeded by the command; bomb out now.
+          The bpstat chain has been blown away by wait_for_inferior.
+          But since execution has stopped again, there is a new bpstat
+          to look at, so start over.  */
+       goto top;
+      else
+       free_command_lines (&bs->commands);
+    }
+  do_cleanups (old_chain);
+}
+
+/* This is the normal print function for a bpstat.  In the future,
+   much of this logic could (should?) be moved to bpstat_stop_status,
+   by having it set different print_it values.
+
+   Current scheme: When we stop, bpstat_print() is called.  It loops
+   through the bpstat list of things causing this stop, calling the
+   print_bp_stop_message function on each one. The behavior of the
+   print_bp_stop_message function depends on the print_it field of
+   bpstat. If such field so indicates, call this function here.
+
+   Return values from this routine (ultimately used by bpstat_print()
+   and normal_stop() to decide what to do): 
+   PRINT_NOTHING: Means we already printed all we needed to print,
+   don't print anything else.
+   PRINT_SRC_ONLY: Means we printed something, and we do *not* desire
+   that something to be followed by a location.
+   PRINT_SCR_AND_LOC: Means we printed something, and we *do* desire
+   that something to be followed by a location.
+   PRINT_UNKNOWN: Means we printed nothing or we need to do some more
+   analysis.  */
+
+static enum print_stop_action
+print_it_typical (bpstat bs)
+{
+  struct cleanup *old_chain;
+  struct ui_stream *stb;
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+  /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
+     which has since been deleted.  */
+  if (bs->breakpoint_at == NULL)
+    return PRINT_UNKNOWN;
+
+  switch (bs->breakpoint_at->type)
+    {
+    case bp_breakpoint:
+    case bp_hardware_breakpoint:
+      annotate_breakpoint (bs->breakpoint_at->number);
+      ui_out_text (uiout, "\nBreakpoint ");
+      if (ui_out_is_mi_like_p (uiout))
+       ui_out_field_string (uiout, "reason", "breakpoint-hit");
+      ui_out_field_int (uiout, "bkptno", bs->breakpoint_at->number);
+      ui_out_text (uiout, ", ");
+      return PRINT_SRC_AND_LOC;
+      break;
+
+    case bp_shlib_event:
+      /* Did we stop because the user set the stop_on_solib_events
+        variable?  (If so, we report this as a generic, "Stopped due
+        to shlib event" message.) */
+      printf_filtered ("Stopped due to shared library event\n");
+      return PRINT_NOTHING;
+      break;
+
+    case bp_thread_event:
+      /* Not sure how we will get here. 
+        GDB should not stop for these breakpoints.  */
+      printf_filtered ("Thread Event Breakpoint: gdb should not stop!\n");
+      return PRINT_NOTHING;
+      break;
+
+    case bp_overlay_event:
+      /* By analogy with the thread event, GDB should not stop for these. */
+      printf_filtered ("Overlay Event Breakpoint: gdb should not stop!\n");
+      return PRINT_NOTHING;
+      break;
+
+    case bp_catch_load:
+      annotate_catchpoint (bs->breakpoint_at->number);
+      printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
+      printf_filtered ("loaded");
+      printf_filtered (" %s), ", bs->breakpoint_at->triggered_dll_pathname);
+      return PRINT_SRC_AND_LOC;
+      break;
+
+    case bp_catch_unload:
+      annotate_catchpoint (bs->breakpoint_at->number);
+      printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
+      printf_filtered ("unloaded");
+      printf_filtered (" %s), ", bs->breakpoint_at->triggered_dll_pathname);
+      return PRINT_SRC_AND_LOC;
+      break;
+
+    case bp_catch_fork:
+      annotate_catchpoint (bs->breakpoint_at->number);
+      printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
+      printf_filtered ("forked");
+      printf_filtered (" process %d), ", 
+                      bs->breakpoint_at->forked_inferior_pid);
+      return PRINT_SRC_AND_LOC;
+      break;
+
+    case bp_catch_vfork:
+      annotate_catchpoint (bs->breakpoint_at->number);
+      printf_filtered ("\nCatchpoint %d (", bs->breakpoint_at->number);
+      printf_filtered ("vforked");
+      printf_filtered (" process %d), ", 
+                      bs->breakpoint_at->forked_inferior_pid);
+      return PRINT_SRC_AND_LOC;
+      break;
+
+    case bp_catch_exec:
+      annotate_catchpoint (bs->breakpoint_at->number);
+      printf_filtered ("\nCatchpoint %d (exec'd %s), ",
+                      bs->breakpoint_at->number,
+                      bs->breakpoint_at->exec_pathname);
+      return PRINT_SRC_AND_LOC;
+      break;
+
+    case bp_catch_catch:
+      if (current_exception_event && 
+         (CURRENT_EXCEPTION_KIND == EX_EVENT_CATCH))
+       {
+         annotate_catchpoint (bs->breakpoint_at->number);
+         printf_filtered ("\nCatchpoint %d (exception caught), ", 
+                          bs->breakpoint_at->number);
+         printf_filtered ("throw location ");
+         if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
+           printf_filtered ("%s:%d",
+                            CURRENT_EXCEPTION_THROW_FILE,
+                            CURRENT_EXCEPTION_THROW_LINE);
+         else
+           printf_filtered ("unknown");
+
+         printf_filtered (", catch location ");
+         if (CURRENT_EXCEPTION_CATCH_PC && CURRENT_EXCEPTION_CATCH_LINE)
+           printf_filtered ("%s:%d",
+                            CURRENT_EXCEPTION_CATCH_FILE,
+                            CURRENT_EXCEPTION_CATCH_LINE);
+         else
+           printf_filtered ("unknown");
+
+         printf_filtered ("\n");
+         /* don't bother to print location frame info */
+         return PRINT_SRC_ONLY;
+       }
+      else
+       {
+         /* really throw, some other bpstat will handle it */
+         return PRINT_UNKNOWN; 
+       }
+      break;
+
+    case bp_catch_throw:
+      if (current_exception_event && 
+         (CURRENT_EXCEPTION_KIND == EX_EVENT_THROW))
+       {
+         annotate_catchpoint (bs->breakpoint_at->number);
+         printf_filtered ("\nCatchpoint %d (exception thrown), ",
+                          bs->breakpoint_at->number);
+         printf_filtered ("throw location ");
+         if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
+           printf_filtered ("%s:%d",
+                            CURRENT_EXCEPTION_THROW_FILE,
+                            CURRENT_EXCEPTION_THROW_LINE);
+         else
+           printf_filtered ("unknown");
+
+         printf_filtered (", catch location ");
+         if (CURRENT_EXCEPTION_CATCH_PC && CURRENT_EXCEPTION_CATCH_LINE)
+           printf_filtered ("%s:%d",
+                            CURRENT_EXCEPTION_CATCH_FILE,
+                            CURRENT_EXCEPTION_CATCH_LINE);
+         else
+           printf_filtered ("unknown");
+
+         printf_filtered ("\n");
+         /* don't bother to print location frame info */
+         return PRINT_SRC_ONLY; 
+       }
+      else
+       {
+         /* really catch, some other bpstat will handle it */
+         return PRINT_UNKNOWN; 
+       }
+      break;
+
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+      if (bs->old_val != NULL)
+       {
+         annotate_watchpoint (bs->breakpoint_at->number);
+         if (ui_out_is_mi_like_p (uiout))
+           ui_out_field_string (uiout, "reason", "watchpoint-trigger");
+         mention (bs->breakpoint_at);
+         ui_out_tuple_begin (uiout, "value");
+         ui_out_text (uiout, "\nOld value = ");
+         value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
+         ui_out_field_stream (uiout, "old", stb);
+         ui_out_text (uiout, "\nNew value = ");
+         value_print (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
+         ui_out_field_stream (uiout, "new", stb);
+         ui_out_tuple_end (uiout);
+         ui_out_text (uiout, "\n");
+         value_free (bs->old_val);
+         bs->old_val = NULL;
+       }
+      /* More than one watchpoint may have been triggered.  */
+      return PRINT_UNKNOWN;
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+       ui_out_field_string (uiout, "reason", "read-watchpoint-trigger");
+      mention (bs->breakpoint_at);
+      ui_out_tuple_begin (uiout, "value");
+      ui_out_text (uiout, "\nValue = ");
+      value_print (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
+      ui_out_field_stream (uiout, "value", stb);
+      ui_out_tuple_end (uiout);
+      ui_out_text (uiout, "\n");
+      return PRINT_UNKNOWN;
+      break;
+
+    case bp_access_watchpoint:
+      if (bs->old_val != NULL)     
+       {
+         annotate_watchpoint (bs->breakpoint_at->number);
+         if (ui_out_is_mi_like_p (uiout))
+           ui_out_field_string (uiout, "reason", "access-watchpoint-trigger");
+         mention (bs->breakpoint_at);
+         ui_out_tuple_begin (uiout, "value");
+         ui_out_text (uiout, "\nOld value = ");
+         value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
+         ui_out_field_stream (uiout, "old", stb);
+         value_free (bs->old_val);
+         bs->old_val = NULL;
+         ui_out_text (uiout, "\nNew value = ");
+       }
+      else 
+       {
+         mention (bs->breakpoint_at);
+         if (ui_out_is_mi_like_p (uiout))
+           ui_out_field_string (uiout, "reason", "access-watchpoint-trigger");
+         ui_out_tuple_begin (uiout, "value");
+         ui_out_text (uiout, "\nValue = ");
+       }
+      value_print (bs->breakpoint_at->val, stb->stream, 0,Val_pretty_default);
+      ui_out_field_stream (uiout, "new", stb);
+      ui_out_tuple_end (uiout);
+      ui_out_text (uiout, "\n");
+      return PRINT_UNKNOWN;
+      break;
+
+    /* Fall through, we don't deal with these types of breakpoints
+       here. */
+
+    case bp_finish:
+      if (ui_out_is_mi_like_p (uiout))
+       ui_out_field_string (uiout, "reason", "function-finished");
+      return PRINT_UNKNOWN;
+      break;
+
+    case bp_until:
+      if (ui_out_is_mi_like_p (uiout))
+       ui_out_field_string (uiout, "reason", "location-reached");
+      return PRINT_UNKNOWN;
+      break;
+
+    case bp_none:
+    case bp_longjmp:
+    case bp_longjmp_resume:
+    case bp_step_resume:
+    case bp_through_sigtramp:
+    case bp_watchpoint_scope:
+    case bp_call_dummy:
+    default:
+      return PRINT_UNKNOWN;
+    }
+}
+
+/* Generic routine for printing messages indicating why we
+   stopped. The behavior of this function depends on the value
+   'print_it' in the bpstat structure.  Under some circumstances we
+   may decide not to print anything here and delegate the task to
+   normal_stop(). */
+
+static enum print_stop_action
+print_bp_stop_message (bpstat bs)
+{
+  switch (bs->print_it)
+    {
+    case print_it_noop:
+      /* Nothing should be printed for this bpstat entry. */
+      return PRINT_UNKNOWN;
+      break;
+
+    case print_it_done:
+      /* We still want to print the frame, but we already printed the
+         relevant messages. */
+      return PRINT_SRC_AND_LOC;
+      break;
+
+    case print_it_normal:
+      /* Normal case, we handle everything in print_it_typical. */
+      return print_it_typical (bs);
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "print_bp_stop_message: unrecognized enum value");
+      break;
+    }
+}
+
+/* Print a message indicating what happened.  This is called from
+   normal_stop().  The input to this routine is the head of the bpstat
+   list - a list of the eventpoints that caused this stop.  This
+   routine calls the generic print routine for printing a message
+   about reasons for stopping.  This will print (for example) the
+   "Breakpoint n," part of the output.  The return value of this
+   routine is one of:
+
+   PRINT_UNKNOWN: Means we printed nothing
+   PRINT_SRC_AND_LOC: Means we printed something, and expect subsequent
+   code to print the location. An example is 
+   "Breakpoint 1, " which should be followed by
+   the location.
+   PRINT_SRC_ONLY: Means we printed something, but there is no need
+   to also print the location part of the message.
+   An example is the catch/throw messages, which
+   don't require a location appended to the end.  
+   PRINT_NOTHING: We have done some printing and we don't need any 
+   further info to be printed.*/
+
+enum print_stop_action
+bpstat_print (bpstat bs)
+{
+  int val;
+
+  /* Maybe another breakpoint in the chain caused us to stop.
+     (Currently all watchpoints go on the bpstat whether hit or not.
+     That probably could (should) be changed, provided care is taken
+     with respect to bpstat_explains_signal).  */
+  for (; bs; bs = bs->next)
+    {
+      val = print_bp_stop_message (bs);
+      if (val == PRINT_SRC_ONLY 
+         || val == PRINT_SRC_AND_LOC 
+         || val == PRINT_NOTHING)
+       return val;
+    }
+
+  /* We reached the end of the chain, or we got a null BS to start
+     with and nothing was printed. */
+  return PRINT_UNKNOWN;
+}
+
+/* Evaluate the expression EXP and return 1 if value is zero.
+   This is used inside a catch_errors to evaluate the breakpoint condition. 
+   The argument is a "struct expression *" that has been cast to char * to 
+   make it pass through catch_errors.  */
+
+static int
+breakpoint_cond_eval (PTR exp)
+{
+  struct value *mark = value_mark ();
+  int i = !value_true (evaluate_expression ((struct expression *) exp));
+  value_free_to_mark (mark);
+  return i;
+}
+
+/* Allocate a new bpstat and chain it to the current one.  */
+
+static bpstat
+bpstat_alloc (struct breakpoint *b, bpstat cbs /* Current "bs" value */ )
+{
+  bpstat bs;
+
+  bs = (bpstat) xmalloc (sizeof (*bs));
+  cbs->next = bs;
+  bs->breakpoint_at = b;
+  /* If the condition is false, etc., don't do the commands.  */
+  bs->commands = NULL;
+  bs->old_val = NULL;
+  bs->print_it = print_it_normal;
+  return bs;
+}
+\f
+/* Possible return values for watchpoint_check (this can't be an enum
+   because of check_errors).  */
+/* The watchpoint has been deleted.  */
+#define WP_DELETED 1
+/* The value has changed.  */
+#define WP_VALUE_CHANGED 2
+/* The value has not changed.  */
+#define WP_VALUE_NOT_CHANGED 3
+
+#define BP_TEMPFLAG 1
+#define BP_HARDWAREFLAG 2
+
+/* Check watchpoint condition.  */
+
+static int
+watchpoint_check (PTR p)
+{
+  bpstat bs = (bpstat) p;
+  struct breakpoint *b;
+  struct frame_info *fr;
+  int within_current_scope;
+
+  b = bs->breakpoint_at;
+
+  if (b->exp_valid_block == NULL)
+    within_current_scope = 1;
+  else
+    {
+      /* There is no current frame at this moment.  If we're going to have
+         any chance of handling watchpoints on local variables, we'll need
+         the frame chain (so we can determine if we're in scope).  */
+      reinit_frame_cache ();
+      fr = frame_find_by_id (b->watchpoint_frame);
+      within_current_scope = (fr != NULL);
+      /* in_function_epilogue_p() returns a non-zero value if we're still
+        in the function but the stack frame has already been invalidated.
+        Since we can't rely on the values of local variables after the
+        stack has been destroyed, we are treating the watchpoint in that
+        state as `not changed' without further checking. */
+      if (within_current_scope && fr == get_current_frame ()
+          && gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ()))
+       return WP_VALUE_NOT_CHANGED;
+      if (within_current_scope)
+       /* If we end up stopping, the current frame will get selected
+          in normal_stop.  So this call to select_frame won't affect
+          the user.  */
+       select_frame (fr);
+    }
+
+  if (within_current_scope)
+    {
+      /* We use value_{,free_to_}mark because it could be a
+         *long* time before we return to the command level and
+         call free_all_values.  We can't call free_all_values because
+         we might be in the middle of evaluating a function call.  */
+
+      struct value *mark = value_mark ();
+      struct value *new_val = evaluate_expression (bs->breakpoint_at->exp);
+      if (!value_equal (b->val, new_val))
+       {
+         release_value (new_val);
+         value_free_to_mark (mark);
+         bs->old_val = b->val;
+         b->val = new_val;
+         /* We will stop here */
+         return WP_VALUE_CHANGED;
+       }
+      else
+       {
+         /* Nothing changed, don't do anything.  */
+         value_free_to_mark (mark);
+         /* We won't stop here */
+         return WP_VALUE_NOT_CHANGED;
+       }
+    }
+  else
+    {
+      /* This seems like the only logical thing to do because
+         if we temporarily ignored the watchpoint, then when
+         we reenter the block in which it is valid it contains
+         garbage (in the case of a function, it may have two
+         garbage values, one before and one after the prologue).
+         So we can't even detect the first assignment to it and
+         watch after that (since the garbage may or may not equal
+         the first value assigned).  */
+      /* We print all the stop information in print_it_typical(), but
+        in this case, by the time we call print_it_typical() this bp
+        will be deleted already. So we have no choice but print the
+        information here. */
+      if (ui_out_is_mi_like_p (uiout))
+       ui_out_field_string (uiout, "reason", "watchpoint-scope");
+      ui_out_text (uiout, "\nWatchpoint ");
+      ui_out_field_int (uiout, "wpnum", bs->breakpoint_at->number);
+      ui_out_text (uiout, " deleted because the program has left the block in\n\
+which its expression is valid.\n");     
+
+      if (b->related_breakpoint)
+       b->related_breakpoint->disposition = disp_del_at_next_stop;
+      b->disposition = disp_del_at_next_stop;
+
+      return WP_DELETED;
+    }
+}
+
+/* Get a bpstat associated with having just stopped at address *PC
+   and frame address CORE_ADDRESS.  Update *PC to point at the
+   breakpoint (if we hit a breakpoint).  NOT_A_SW_BREAKPOINT is nonzero
+   if this is known to not be a real breakpoint (it could still be a
+   watchpoint, though).  */
+
+/* Determine whether we stopped at a breakpoint, etc, or whether we
+   don't understand this stop.  Result is a chain of bpstat's such that:
+
+   if we don't understand the stop, the result is a null pointer.
+
+   if we understand why we stopped, the result is not null.
+
+   Each element of the chain refers to a particular breakpoint or
+   watchpoint at which we have stopped.  (We may have stopped for
+   several reasons concurrently.)
+
+   Each element of the chain has valid next, breakpoint_at,
+   commands, FIXME??? fields.  */
+
+bpstat
+bpstat_stop_status (CORE_ADDR *pc, int not_a_sw_breakpoint)
+{
+  register struct breakpoint *b, *temp;
+  CORE_ADDR bp_addr;
+  /* True if we've hit a breakpoint (as opposed to a watchpoint).  */
+  int real_breakpoint = 0;
+  /* Root of the chain of bpstat's */
+  struct bpstats root_bs[1];
+  /* Pointer to the last thing in the chain currently.  */
+  bpstat bs = root_bs;
+  static char message1[] =
+  "Error evaluating expression for watchpoint %d\n";
+  char message[sizeof (message1) + 30 /* slop */ ];
+
+  /* Get the address where the breakpoint would have been.  The
+     "not_a_sw_breakpoint" argument is meant to distinguish between a
+     breakpoint trap event and a trace/singlestep trap event.  For a
+     trace/singlestep trap event, we would not want to subtract
+     DECR_PC_AFTER_BREAK from the PC. */
+
+  bp_addr = *pc - (not_a_sw_breakpoint ? 0 : DECR_PC_AFTER_BREAK);
+
+  ALL_BREAKPOINTS_SAFE (b, temp)
+  {
+    if (b->enable_state == bp_disabled
+       || b->enable_state == bp_shlib_disabled
+       || b->enable_state == bp_call_disabled)
+      continue;
+
+    if (b->type != bp_watchpoint
+       && b->type != bp_hardware_watchpoint
+       && b->type != bp_read_watchpoint
+       && b->type != bp_access_watchpoint
+       && b->type != bp_hardware_breakpoint
+       && b->type != bp_catch_fork
+       && b->type != bp_catch_vfork
+       && b->type != bp_catch_exec
+       && b->type != bp_catch_catch
+       && b->type != bp_catch_throw)   /* a non-watchpoint bp */
+      {
+       if (b->address != bp_addr)      /* address doesn't match */
+         continue;
+       if (overlay_debugging           /* unmapped overlay section */
+           && section_is_overlay (b->section) 
+           && !section_is_mapped (b->section))
+         continue;
+      }
+
+    if (b->type == bp_hardware_breakpoint)
+      {
+       if (b->address != (*pc - DECR_PC_AFTER_HW_BREAK))
+         continue;
+       if (overlay_debugging           /* unmapped overlay section */
+           && section_is_overlay (b->section) 
+           && !section_is_mapped (b->section))
+         continue;
+      }
+
+    /* Is this a catchpoint of a load or unload?  If so, did we
+       get a load or unload of the specified library?  If not,
+       ignore it. */
+    if ((b->type == bp_catch_load)
+#if defined(SOLIB_HAVE_LOAD_EVENT)
+       && (!SOLIB_HAVE_LOAD_EVENT (PIDGET (inferior_ptid))
+           || ((b->dll_pathname != NULL)
+               && (strcmp (b->dll_pathname, 
+                           SOLIB_LOADED_LIBRARY_PATHNAME (
+                             PIDGET (inferior_ptid)))
+                   != 0)))
+#endif
+      )
+      continue;
+
+    if ((b->type == bp_catch_unload)
+#if defined(SOLIB_HAVE_UNLOAD_EVENT)
+       && (!SOLIB_HAVE_UNLOAD_EVENT (PIDGET (inferior_ptid))
+           || ((b->dll_pathname != NULL)
+               && (strcmp (b->dll_pathname, 
+                           SOLIB_UNLOADED_LIBRARY_PATHNAME (
+                             PIDGET (inferior_ptid)))
+                   != 0)))
+#endif
+      )
+      continue;
+
+    if ((b->type == bp_catch_fork)
+       && !target_has_forked (PIDGET (inferior_ptid),
+                              &b->forked_inferior_pid))
+      continue;
+
+    if ((b->type == bp_catch_vfork)
+       && !target_has_vforked (PIDGET (inferior_ptid),
+                               &b->forked_inferior_pid))
+      continue;
+
+    if ((b->type == bp_catch_exec)
+       && !target_has_execd (PIDGET (inferior_ptid), &b->exec_pathname))
+      continue;
+
+    if (ep_is_exception_catchpoint (b) &&
+       !(current_exception_event = target_get_current_exception_event ()))
+      continue;
+
+    /* Come here if it's a watchpoint, or if the break address matches */
+
+    bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */
+
+    /* Watchpoints may change this, if not found to have triggered. */
+    bs->stop = 1;
+    bs->print = 1;
+
+    sprintf (message, message1, b->number);
+    if (b->type == bp_watchpoint ||
+       b->type == bp_hardware_watchpoint)
+      {
+       switch (catch_errors (watchpoint_check, bs, message, 
+                             RETURN_MASK_ALL))
+         {
+         case WP_DELETED:
+           /* We've already printed what needs to be printed.  */
+           /* Actually this is superfluous, because by the time we
+               call print_it_typical() the wp will be already deleted,
+               and the function will return immediately. */
+           bs->print_it = print_it_done;
+           /* Stop.  */
+           break;
+         case WP_VALUE_CHANGED:
+           /* Stop.  */
+           ++(b->hit_count);
+           break;
+         case WP_VALUE_NOT_CHANGED:
+           /* Don't stop.  */
+           bs->print_it = print_it_noop;
+           bs->stop = 0;
+           continue;
+         default:
+           /* Can't happen.  */
+           /* FALLTHROUGH */
+         case 0:
+           /* Error from catch_errors.  */
+           printf_filtered ("Watchpoint %d deleted.\n", b->number);
+           if (b->related_breakpoint)
+             b->related_breakpoint->disposition = disp_del_at_next_stop;
+           b->disposition = disp_del_at_next_stop;
+           /* We've already printed what needs to be printed.  */
+           bs->print_it = print_it_done;
+
+           /* Stop.  */
+           break;
+         }
+      }
+    else if (b->type == bp_read_watchpoint || 
+            b->type == bp_access_watchpoint)
+      {
+       CORE_ADDR addr;
+       struct value *v;
+       int found = 0;
+
+       addr = target_stopped_data_address ();
+       if (addr == 0)
+         continue;
+       for (v = b->val_chain; v; v = v->next)
+         {
+           if (VALUE_LVAL (v) == lval_memory
+               && ! VALUE_LAZY (v))
+             {
+               struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+               if (v == b->val_chain
+                   || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+                       && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+                 {
+                   CORE_ADDR vaddr;
+
+                   vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+                   /* Exact match not required.  Within range is
+                       sufficient.  */
+                   if (addr >= vaddr &&
+                       addr < vaddr + TYPE_LENGTH (VALUE_TYPE (v)))
+                     found = 1;
+                 }
+             }
+         }
+       if (found)
+         switch (catch_errors (watchpoint_check, bs, message,
+                               RETURN_MASK_ALL))
+           {
+           case WP_DELETED:
+             /* We've already printed what needs to be printed.  */
+             bs->print_it = print_it_done;
+             /* Stop.  */
+             break;
+           case WP_VALUE_CHANGED:
+             if (b->type == bp_read_watchpoint)
+               {
+                 /* Don't stop: read watchpoints shouldn't fire if
+                    the value has changed.  This is for targets which
+                    cannot set read-only watchpoints.  */
+                 bs->print_it = print_it_noop;
+                 bs->stop = 0;
+                 continue;
+               }
+             ++(b->hit_count);
+             break;
+           case WP_VALUE_NOT_CHANGED:
+             /* Stop.  */
+             ++(b->hit_count);
+             break;
+           default:
+             /* Can't happen.  */
+           case 0:
+             /* Error from catch_errors.  */
+             printf_filtered ("Watchpoint %d deleted.\n", b->number);
+             if (b->related_breakpoint)
+               b->related_breakpoint->disposition = disp_del_at_next_stop;
+             b->disposition = disp_del_at_next_stop;
+             /* We've already printed what needs to be printed.  */
+             bs->print_it = print_it_done;
+             break;
+           }
+       else    /* found == 0 */
+         {
+           /* This is a case where some watchpoint(s) triggered,
+              but not at the address of this watchpoint (FOUND
+              was left zero).  So don't print anything for this
+              watchpoint.  */
+           bs->print_it = print_it_noop;
+           bs->stop = 0;
+            continue;
+         }
+      }
+    else
+      {
+       /* By definition, an encountered breakpoint is a triggered
+          breakpoint. */
+       ++(b->hit_count);
+
+       real_breakpoint = 1;
+      }
+
+    if (b->frame &&
+       b->frame != (get_current_frame ())->frame)
+      bs->stop = 0;
+    else
+      {
+       int value_is_zero = 0;
+
+       if (b->cond)
+         {
+           /* Need to select the frame, with all that implies
+              so that the conditions will have the right context.  */
+           select_frame (get_current_frame ());
+           value_is_zero
+             = catch_errors (breakpoint_cond_eval, (b->cond),
+                             "Error in testing breakpoint condition:\n",
+                             RETURN_MASK_ALL);
+           /* FIXME-someday, should give breakpoint # */
+           free_all_values ();
+         }
+       if (b->cond && value_is_zero)
+         {
+           bs->stop = 0;
+           /* Don't consider this a hit.  */
+           --(b->hit_count);
+         }
+       else if (b->ignore_count > 0)
+         {
+           b->ignore_count--;
+           annotate_ignore_count_change ();
+           bs->stop = 0;
+         }
+       else
+         {
+           /* We will stop here */
+           if (b->disposition == disp_disable)
+             b->enable_state = bp_disabled;
+           bs->commands = copy_command_lines (b->commands);
+           if (b->silent)
+             bs->print = 0;
+           if (bs->commands &&
+               (STREQ ("silent", bs->commands->line) ||
+                (xdb_commands && STREQ ("Q", bs->commands->line))))
+             {
+               bs->commands = bs->commands->next;
+               bs->print = 0;
+             }
+         }
+      }
+    /* Print nothing for this entry if we dont stop or if we dont print.  */
+    if (bs->stop == 0 || bs->print == 0)
+      bs->print_it = print_it_noop;
+  }
+
+  bs->next = NULL;             /* Terminate the chain */
+  bs = root_bs->next;          /* Re-grab the head of the chain */
+
+  if (real_breakpoint && bs)
+    {
+      if (bs->breakpoint_at->type == bp_hardware_breakpoint)
+       {
+         if (DECR_PC_AFTER_HW_BREAK != 0)
+           {
+             *pc = *pc - DECR_PC_AFTER_HW_BREAK;
+             write_pc (*pc);
+           }
+       }
+      else
+       {
+         if (DECR_PC_AFTER_BREAK != 0 || must_shift_inst_regs)
+           {
+             *pc = bp_addr;
+#if defined (SHIFT_INST_REGS)
+             SHIFT_INST_REGS ();
+#else /* No SHIFT_INST_REGS.  */
+             write_pc (bp_addr);
+#endif /* No SHIFT_INST_REGS.  */
+           }
+       }
+    }
+
+  /* The value of a hardware watchpoint hasn't changed, but the
+     intermediate memory locations we are watching may have.  */
+  if (bs && !bs->stop &&
+      (bs->breakpoint_at->type == bp_hardware_watchpoint ||
+       bs->breakpoint_at->type == bp_read_watchpoint ||
+       bs->breakpoint_at->type == bp_access_watchpoint))
+    {
+      remove_breakpoints ();
+      insert_breakpoints ();
+    }
+  return bs;
+}
+\f
+/* Tell what to do about this bpstat.  */
+struct bpstat_what
+bpstat_what (bpstat bs)
+{
+  /* Classify each bpstat as one of the following.  */
+  enum class
+    {
+      /* This bpstat element has no effect on the main_action.  */
+      no_effect = 0,
+
+      /* There was a watchpoint, stop but don't print.  */
+      wp_silent,
+
+      /* There was a watchpoint, stop and print.  */
+      wp_noisy,
+
+      /* There was a breakpoint but we're not stopping.  */
+      bp_nostop,
+
+      /* There was a breakpoint, stop but don't print.  */
+      bp_silent,
+
+      /* There was a breakpoint, stop and print.  */
+      bp_noisy,
+
+      /* We hit the longjmp breakpoint.  */
+      long_jump,
+
+      /* We hit the longjmp_resume breakpoint.  */
+      long_resume,
+
+      /* We hit the step_resume breakpoint.  */
+      step_resume,
+
+      /* We hit the through_sigtramp breakpoint.  */
+      through_sig,
+
+      /* We hit the shared library event breakpoint.  */
+      shlib_event,
+
+      /* We caught a shared library event.  */
+      catch_shlib_event,
+
+      /* This is just used to count how many enums there are.  */
+      class_last
+    };
+
+  /* Here is the table which drives this routine.  So that we can
+     format it pretty, we define some abbreviations for the
+     enum bpstat_what codes.  */
+#define kc BPSTAT_WHAT_KEEP_CHECKING
+#define ss BPSTAT_WHAT_STOP_SILENT
+#define sn BPSTAT_WHAT_STOP_NOISY
+#define sgl BPSTAT_WHAT_SINGLE
+#define slr BPSTAT_WHAT_SET_LONGJMP_RESUME
+#define clr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME
+#define clrs BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE
+#define sr BPSTAT_WHAT_STEP_RESUME
+#define ts BPSTAT_WHAT_THROUGH_SIGTRAMP
+#define shl BPSTAT_WHAT_CHECK_SHLIBS
+#define shlr BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK
+
+/* "Can't happen."  Might want to print an error message.
+   abort() is not out of the question, but chances are GDB is just
+   a bit confused, not unusable.  */
+#define err BPSTAT_WHAT_STOP_NOISY
+
+  /* Given an old action and a class, come up with a new action.  */
+  /* One interesting property of this table is that wp_silent is the same
+     as bp_silent and wp_noisy is the same as bp_noisy.  That is because
+     after stopping, the check for whether to step over a breakpoint
+     (BPSTAT_WHAT_SINGLE type stuff) is handled in proceed() without
+     reference to how we stopped.  We retain separate wp_silent and
+     bp_silent codes in case we want to change that someday. 
+
+     Another possibly interesting property of this table is that
+     there's a partial ordering, priority-like, of the actions.  Once
+     you've decided that some action is appropriate, you'll never go
+     back and decide something of a lower priority is better.  The
+     ordering is:
+
+     kc   < clr sgl shl shlr slr sn sr ss ts
+     sgl  < clrs shl shlr slr sn sr ss ts
+     slr  < err shl shlr sn sr ss ts
+     clr  < clrs err shl shlr sn sr ss ts
+     clrs < err shl shlr sn sr ss ts
+     ss   < shl shlr sn sr ts
+     sn   < shl shlr sr ts
+     sr   < shl shlr ts
+     shl  < shlr
+     ts   < 
+     shlr <
+
+     What I think this means is that we don't need a damned table
+     here.  If you just put the rows and columns in the right order,
+     it'd look awfully regular.  We could simply walk the bpstat list
+     and choose the highest priority action we find, with a little
+     logic to handle the 'err' cases, and the CLEAR_LONGJMP_RESUME/
+     CLEAR_LONGJMP_RESUME_SINGLE distinction (which breakpoint.h says
+     is messy anyway).  */
+
+  /* step_resume entries: a step resume breakpoint overrides another
+     breakpoint of signal handling (see comment in wait_for_inferior
+     at first PC_IN_SIGTRAMP where we set the step_resume breakpoint).  */
+  /* We handle the through_sigtramp_breakpoint the same way; having both
+     one of those and a step_resume_breakpoint is probably very rare (?).  */
+
+  static const enum bpstat_what_main_action
+    table[(int) class_last][(int) BPSTAT_WHAT_LAST] =
+  {
+  /*                              old action */
+  /*       kc    ss    sn    sgl    slr   clr    clrs   sr    ts   shl   shlr
+   */
+/*no_effect */
+    {kc, ss, sn, sgl, slr, clr, clrs, sr, ts, shl, shlr},
+/*wp_silent */
+    {ss, ss, sn, ss, ss, ss, ss, sr, ts, shl, shlr},
+/*wp_noisy */
+    {sn, sn, sn, sn, sn, sn, sn, sr, ts, shl, shlr},
+/*bp_nostop */
+    {sgl, ss, sn, sgl, slr, clrs, clrs, sr, ts, shl, shlr},
+/*bp_silent */
+    {ss, ss, sn, ss, ss, ss, ss, sr, ts, shl, shlr},
+/*bp_noisy */
+    {sn, sn, sn, sn, sn, sn, sn, sr, ts, shl, shlr},
+/*long_jump */
+    {slr, ss, sn, slr, slr, err, err, sr, ts, shl, shlr},
+/*long_resume */
+    {clr, ss, sn, clrs, err, err, err, sr, ts, shl, shlr},
+/*step_resume */
+    {sr, sr, sr, sr, sr, sr, sr, sr, ts, shl, shlr},
+/*through_sig */
+    {ts, ts, ts, ts, ts, ts, ts, ts, ts, shl, shlr},
+/*shlib */
+    {shl, shl, shl, shl, shl, shl, shl, shl, ts, shl, shlr},
+/*catch_shlib */
+    {shlr, shlr, shlr, shlr, shlr, shlr, shlr, shlr, ts, shlr, shlr}
+  };
+
+#undef kc
+#undef ss
+#undef sn
+#undef sgl
+#undef slr
+#undef clr
+#undef clrs
+#undef err
+#undef sr
+#undef ts
+#undef shl
+#undef shlr
+  enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
+  struct bpstat_what retval;
+
+  retval.call_dummy = 0;
+  for (; bs != NULL; bs = bs->next)
+    {
+      enum class bs_class = no_effect;
+      if (bs->breakpoint_at == NULL)
+       /* I suspect this can happen if it was a momentary breakpoint
+          which has since been deleted.  */
+       continue;
+      switch (bs->breakpoint_at->type)
+       {
+       case bp_none:
+         continue;
+
+       case bp_breakpoint:
+       case bp_hardware_breakpoint:
+       case bp_until:
+       case bp_finish:
+         if (bs->stop)
+           {
+             if (bs->print)
+               bs_class = bp_noisy;
+             else
+               bs_class = bp_silent;
+           }
+         else
+           bs_class = bp_nostop;
+         break;
+       case bp_watchpoint:
+       case bp_hardware_watchpoint:
+       case bp_read_watchpoint:
+       case bp_access_watchpoint:
+         if (bs->stop)
+           {
+             if (bs->print)
+               bs_class = wp_noisy;
+             else
+               bs_class = wp_silent;
+           }
+         else
+           /* There was a watchpoint, but we're not stopping. 
+              This requires no further action.  */
+           bs_class = no_effect;
+         break;
+       case bp_longjmp:
+         bs_class = long_jump;
+         break;
+       case bp_longjmp_resume:
+         bs_class = long_resume;
+         break;
+       case bp_step_resume:
+         if (bs->stop)
+           {
+             bs_class = step_resume;
+           }
+         else
+           /* It is for the wrong frame.  */
+           bs_class = bp_nostop;
+         break;
+       case bp_through_sigtramp:
+         bs_class = through_sig;
+         break;
+       case bp_watchpoint_scope:
+         bs_class = bp_nostop;
+         break;
+       case bp_shlib_event:
+         bs_class = shlib_event;
+         break;
+       case bp_thread_event:
+       case bp_overlay_event:
+         bs_class = bp_nostop;
+         break;
+       case bp_catch_load:
+       case bp_catch_unload:
+         /* Only if this catchpoint triggered should we cause the
+            step-out-of-dld behaviour.  Otherwise, we ignore this
+            catchpoint.  */
+         if (bs->stop)
+           bs_class = catch_shlib_event;
+         else
+           bs_class = no_effect;
+         break;
+       case bp_catch_fork:
+       case bp_catch_vfork:
+       case bp_catch_exec:
+         if (bs->stop)
+           {
+             if (bs->print)
+               bs_class = bp_noisy;
+             else
+               bs_class = bp_silent;
+           }
+         else
+           /* There was a catchpoint, but we're not stopping.  
+              This requires no further action.  */
+           bs_class = no_effect;
+         break;
+       case bp_catch_catch:
+         if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_CATCH)
+           bs_class = bp_nostop;
+         else if (bs->stop)
+           bs_class = bs->print ? bp_noisy : bp_silent;
+         break;
+       case bp_catch_throw:
+         if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_THROW)
+           bs_class = bp_nostop;
+         else if (bs->stop)
+           bs_class = bs->print ? bp_noisy : bp_silent;
+         break;
+       case bp_call_dummy:
+         /* Make sure the action is stop (silent or noisy),
+            so infrun.c pops the dummy frame.  */
+         bs_class = bp_silent;
+         retval.call_dummy = 1;
+         break;
+       }
+      current_action = table[(int) bs_class][(int) current_action];
+    }
+  retval.main_action = current_action;
+  return retval;
+}
+
+/* Nonzero if we should step constantly (e.g. watchpoints on machines
+   without hardware support).  This isn't related to a specific bpstat,
+   just to things like whether watchpoints are set.  */
+
+int
+bpstat_should_step (void)
+{
+  struct breakpoint *b;
+  ALL_BREAKPOINTS (b)
+    if (b->enable_state == bp_enabled && b->type == bp_watchpoint)
+      return 1;
+  return 0;
+}
+
+/* Nonzero if there are enabled hardware watchpoints. */
+int
+bpstat_have_active_hw_watchpoints (void)
+{
+  struct breakpoint *b;
+  ALL_BREAKPOINTS (b)
+    if ((b->enable_state == bp_enabled) &&
+       (b->inserted) &&
+       ((b->type == bp_hardware_watchpoint) ||
+        (b->type == bp_read_watchpoint) ||
+        (b->type == bp_access_watchpoint)))
+      return 1;
+  return 0;
+}
+\f
+
+/* Given a bpstat that records zero or more triggered eventpoints, this
+   function returns another bpstat which contains only the catchpoints
+   on that first list, if any. */
+void
+bpstat_get_triggered_catchpoints (bpstat ep_list, bpstat *cp_list)
+{
+  struct bpstats root_bs[1];
+  bpstat bs = root_bs;
+  struct breakpoint *ep;
+  char *dll_pathname;
+
+  bpstat_clear (cp_list);
+  root_bs->next = NULL;
+
+  for (; ep_list != NULL; ep_list = ep_list->next)
+    {
+      /* Is this eventpoint a catchpoint?  If not, ignore it. */
+      ep = ep_list->breakpoint_at;
+      if (ep == NULL)
+       break;
+      if ((ep->type != bp_catch_load) &&
+         (ep->type != bp_catch_unload) &&
+         (ep->type != bp_catch_catch) &&
+         (ep->type != bp_catch_throw))         
+       /* pai: (temp) ADD fork/vfork here!!  */
+       continue;
+
+      /* Yes; add it to the list. */
+      bs = bpstat_alloc (ep, bs);
+      *bs = *ep_list;
+      bs->next = NULL;
+      bs = root_bs->next;
+
+#if defined(SOLIB_ADD)
+      /* Also, for each triggered catchpoint, tag it with the name of
+         the library that caused this trigger.  (We copy the name now,
+         because it's only guaranteed to be available NOW, when the
+         catchpoint triggers.  Clients who may wish to know the name
+         later must get it from the catchpoint itself.) */
+      if (ep->triggered_dll_pathname != NULL)
+       xfree (ep->triggered_dll_pathname);
+      if (ep->type == bp_catch_load)
+       dll_pathname = SOLIB_LOADED_LIBRARY_PATHNAME (
+                        PIDGET (inferior_ptid));
+      else
+       dll_pathname = SOLIB_UNLOADED_LIBRARY_PATHNAME (
+                        PIDGET (inferior_ptid));
+#else
+      dll_pathname = NULL;
+#endif
+      if (dll_pathname)
+       {
+         ep->triggered_dll_pathname = (char *) 
+           xmalloc (strlen (dll_pathname) + 1);
+         strcpy (ep->triggered_dll_pathname, dll_pathname);
+       }
+      else
+       ep->triggered_dll_pathname = NULL;
+    }
+
+  *cp_list = bs;
+}
+
+/* Print B to gdb_stdout. */
+static void
+print_one_breakpoint (struct breakpoint *b,
+                     CORE_ADDR *last_addr)
+{
+  register struct command_line *l;
+  register struct symbol *sym;
+  struct ep_type_description
+    {
+      enum bptype type;
+      char *description;
+    };
+  static struct ep_type_description bptypes[] =
+  {
+    {bp_none, "?deleted?"},
+    {bp_breakpoint, "breakpoint"},
+    {bp_hardware_breakpoint, "hw breakpoint"},
+    {bp_until, "until"},
+    {bp_finish, "finish"},
+    {bp_watchpoint, "watchpoint"},
+    {bp_hardware_watchpoint, "hw watchpoint"},
+    {bp_read_watchpoint, "read watchpoint"},
+    {bp_access_watchpoint, "acc watchpoint"},
+    {bp_longjmp, "longjmp"},
+    {bp_longjmp_resume, "longjmp resume"},
+    {bp_step_resume, "step resume"},
+    {bp_through_sigtramp, "sigtramp"},
+    {bp_watchpoint_scope, "watchpoint scope"},
+    {bp_call_dummy, "call dummy"},
+    {bp_shlib_event, "shlib events"},
+    {bp_thread_event, "thread events"},
+    {bp_overlay_event, "overlay events"},
+    {bp_catch_load, "catch load"},
+    {bp_catch_unload, "catch unload"},
+    {bp_catch_fork, "catch fork"},
+    {bp_catch_vfork, "catch vfork"},
+    {bp_catch_exec, "catch exec"},
+    {bp_catch_catch, "catch catch"},
+    {bp_catch_throw, "catch throw"}
+  };
+  
+  static char *bpdisps[] =
+  {"del", "dstp", "dis", "keep"};
+  static char bpenables[] = "nynny";
+  char wrap_indent[80];
+  struct ui_stream *stb = ui_out_stream_new (uiout);
+  struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  annotate_record ();
+  ui_out_tuple_begin (uiout, "bkpt");
+
+  /* 1 */
+  annotate_field (0);
+  ui_out_field_int (uiout, "number", b->number);
+
+  /* 2 */
+  annotate_field (1);
+  if (((int) b->type > (sizeof (bptypes) / sizeof (bptypes[0])))
+      || ((int) b->type != bptypes[(int) b->type].type))
+    internal_error (__FILE__, __LINE__,
+                   "bptypes table does not describe type #%d.",
+                   (int) b->type);
+  ui_out_field_string (uiout, "type", bptypes[(int) b->type].description);
+
+  /* 3 */
+  annotate_field (2);
+  ui_out_field_string (uiout, "disp", bpdisps[(int) b->disposition]);
+
+  /* 4 */
+  annotate_field (3);
+  ui_out_field_fmt (uiout, "enabled", "%c", bpenables[(int) b->enable_state]);
+  ui_out_spaces (uiout, 2);
+  
+  /* 5 and 6 */
+  strcpy (wrap_indent, "                           ");
+  if (addressprint)
+    {
+      if (TARGET_ADDR_BIT <= 32)
+       strcat (wrap_indent, "           ");
+      else
+       strcat (wrap_indent, "                   ");
+    }
+  switch (b->type)
+    {
+    case bp_none:
+      internal_error (__FILE__, __LINE__,
+                     "print_one_breakpoint: bp_none encountered\n");
+      break;
+
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+    case bp_read_watchpoint:
+    case bp_access_watchpoint:
+      /* Field 4, the address, is omitted (which makes the columns
+        not line up too nicely with the headers, but the effect
+        is relatively readable).  */
+      if (addressprint)
+       ui_out_field_skip (uiout, "addr");
+      annotate_field (5);
+      print_expression (b->exp, stb->stream);
+      ui_out_field_stream (uiout, "what", stb);
+      break;
+      
+    case bp_catch_load:
+    case bp_catch_unload:
+      /* Field 4, the address, is omitted (which makes the columns
+        not line up too nicely with the headers, but the effect
+        is relatively readable).  */
+      if (addressprint)
+       ui_out_field_skip (uiout, "addr");
+      annotate_field (5);
+      if (b->dll_pathname == NULL)
+       {
+         ui_out_field_string (uiout, "what", "<any library>");
+         ui_out_spaces (uiout, 1);
+       }
+      else
+       {
+         ui_out_text (uiout, "library \"");
+         ui_out_field_string (uiout, "what", b->dll_pathname);
+         ui_out_text (uiout, "\" ");
+       }
+      break;
+      
+    case bp_catch_fork:
+    case bp_catch_vfork:
+      /* Field 4, the address, is omitted (which makes the columns
+        not line up too nicely with the headers, but the effect
+        is relatively readable).  */
+      if (addressprint)
+       ui_out_field_skip (uiout, "addr");
+      annotate_field (5);
+      if (b->forked_inferior_pid != 0)
+       {
+         ui_out_text (uiout, "process ");
+         ui_out_field_int (uiout, "what", b->forked_inferior_pid);
+         ui_out_spaces (uiout, 1);
+       }
+      
+    case bp_catch_exec:
+      /* Field 4, the address, is omitted (which makes the columns
+        not line up too nicely with the headers, but the effect
+        is relatively readable).  */
+      if (addressprint)
+       ui_out_field_skip (uiout, "addr");
+      annotate_field (5);
+      if (b->exec_pathname != NULL)
+       {
+         ui_out_text (uiout, "program \"");
+         ui_out_field_string (uiout, "what", b->exec_pathname);
+         ui_out_text (uiout, "\" ");
+       }
+      break;
+
+    case bp_catch_catch:
+      /* Field 4, the address, is omitted (which makes the columns
+        not line up too nicely with the headers, but the effect
+        is relatively readable).  */
+      if (addressprint)
+       ui_out_field_skip (uiout, "addr");
+      annotate_field (5);
+      ui_out_field_string (uiout, "what", "exception catch");
+      ui_out_spaces (uiout, 1);
+      break;
+
+    case bp_catch_throw:
+      /* Field 4, the address, is omitted (which makes the columns
+        not line up too nicely with the headers, but the effect
+        is relatively readable).  */
+      if (addressprint)
+       ui_out_field_skip (uiout, "addr");
+      annotate_field (5);
+      ui_out_field_string (uiout, "what", "exception throw");
+      ui_out_spaces (uiout, 1);
+      break;
+      
+    case bp_breakpoint:
+    case bp_hardware_breakpoint:
+    case bp_until:
+    case bp_finish:
+    case bp_longjmp:
+    case bp_longjmp_resume:
+    case bp_step_resume:
+    case bp_through_sigtramp:
+    case bp_watchpoint_scope:
+    case bp_call_dummy:
+    case bp_shlib_event:
+    case bp_thread_event:
+    case bp_overlay_event:
+      if (addressprint)
+       {
+         annotate_field (4);
+         ui_out_field_core_addr (uiout, "addr", b->address);
+       }
+      annotate_field (5);
+      *last_addr = b->address;
+      if (b->source_file)
+       {
+         sym = find_pc_sect_function (b->address, b->section);
+         if (sym)
+           {
+             ui_out_text (uiout, "in ");
+             ui_out_field_string (uiout, "func",
+                                  SYMBOL_SOURCE_NAME (sym));
+             ui_out_wrap_hint (uiout, wrap_indent);
+             ui_out_text (uiout, " at ");
+           }
+         ui_out_field_string (uiout, "file", b->source_file);
+         ui_out_text (uiout, ":");
+         ui_out_field_int (uiout, "line", b->line_number);
+       }
+      else
+       {
+         print_address_symbolic (b->address, stb->stream, demangle, "");
+         ui_out_field_stream (uiout, "at", stb);
+       }
+      break;
+    }
+  
+  if (b->thread != -1)
+    {
+      /* FIXME: This seems to be redundant and lost here; see the
+        "stop only in" line a little further down. */
+      ui_out_text (uiout, " thread ");
+      ui_out_field_int (uiout, "thread", b->thread);
+    }
+  
+  ui_out_text (uiout, "\n");
+  
+  if (b->frame)
+    {
+      annotate_field (6);
+      ui_out_text (uiout, "\tstop only in stack frame at ");
+      ui_out_field_core_addr (uiout, "frame", b->frame);
+      ui_out_text (uiout, "\n");
+    }
+  
+  if (b->cond)
+    {
+      annotate_field (7);
+      ui_out_text (uiout, "\tstop only if ");
+      print_expression (b->cond, stb->stream);
+      ui_out_field_stream (uiout, "cond", stb);
+      ui_out_text (uiout, "\n");
+    }
+  
+  if (b->thread != -1)
+    {
+      /* FIXME should make an annotation for this */
+      ui_out_text (uiout, "\tstop only in thread ");
+      ui_out_field_int (uiout, "thread", b->thread);
+      ui_out_text (uiout, "\n");
+    }
+  
+  if (show_breakpoint_hit_counts && b->hit_count)
+    {
+      /* FIXME should make an annotation for this */
+      if (ep_is_catchpoint (b))
+       ui_out_text (uiout, "\tcatchpoint");
+      else
+       ui_out_text (uiout, "\tbreakpoint");
+      ui_out_text (uiout, " already hit ");
+      ui_out_field_int (uiout, "times", b->hit_count);
+      if (b->hit_count == 1)
+       ui_out_text (uiout, " time\n");
+      else
+       ui_out_text (uiout, " times\n");
+    }
+  
+  /* Output the count also if it is zero, but only if this is
+     mi. FIXME: Should have a better test for this. */
+  if (ui_out_is_mi_like_p (uiout))
+    if (show_breakpoint_hit_counts && b->hit_count == 0)
+      ui_out_field_int (uiout, "times", b->hit_count);
+
+  if (b->ignore_count)
+    {
+      annotate_field (8);
+      ui_out_text (uiout, "\tignore next ");
+      ui_out_field_int (uiout, "ignore", b->ignore_count);
+      ui_out_text (uiout, " hits\n");
+    }
+  
+  if ((l = b->commands))
+    {
+      annotate_field (9);
+      ui_out_tuple_begin (uiout, "script");
+      print_command_lines (uiout, l, 4);
+      ui_out_tuple_end (uiout);
+    }
+  ui_out_tuple_end (uiout);
+  do_cleanups (old_chain);
+}
+
+struct captured_breakpoint_query_args
+  {
+    int bnum;
+  };
+
+static int
+do_captured_breakpoint_query (struct ui_out *uiout, void *data)
+{
+  struct captured_breakpoint_query_args *args = data;
+  register struct breakpoint *b;
+  CORE_ADDR dummy_addr = 0;
+  ALL_BREAKPOINTS (b)
+    {
+      if (args->bnum == b->number)
+       {
+         print_one_breakpoint (b, &dummy_addr);
+         return GDB_RC_OK;
+       }
+    }
+  return GDB_RC_NONE;
+}
+
+enum gdb_rc
+gdb_breakpoint_query (struct ui_out *uiout, int bnum)
+{
+  struct captured_breakpoint_query_args args;
+  args.bnum = bnum;
+  /* For the moment we don't trust print_one_breakpoint() to not throw
+     an error. */
+  return catch_exceptions (uiout, do_captured_breakpoint_query, &args,
+                          NULL, RETURN_MASK_ALL);
+}
+
+/* Return non-zero if B is user settable (breakpoints, watchpoints,
+   catchpoints, et.al.). */
+
+static int
+user_settable_breakpoint (const struct breakpoint *b)
+{
+  return (b->type == bp_breakpoint
+         || b->type == bp_catch_load
+         || b->type == bp_catch_unload
+         || b->type == bp_catch_fork
+         || b->type == bp_catch_vfork
+         || b->type == bp_catch_exec
+         || b->type == bp_catch_catch
+         || b->type == bp_catch_throw
+         || b->type == bp_hardware_breakpoint
+         || b->type == bp_watchpoint
+         || b->type == bp_read_watchpoint
+         || b->type == bp_access_watchpoint
+         || b->type == bp_hardware_watchpoint);
+}
+       
+/* Print information on user settable breakpoint (watchpoint, etc)
+   number BNUM.  If BNUM is -1 print all user settable breakpoints.
+   If ALLFLAG is non-zero, include non- user settable breakpoints. */
+
+static void
+breakpoint_1 (int bnum, int allflag)
+{
+  register struct breakpoint *b;
+  CORE_ADDR last_addr = (CORE_ADDR) -1;
+  int nr_printable_breakpoints;
+  
+  /* Compute the number of rows in the table. */
+  nr_printable_breakpoints = 0;
+  ALL_BREAKPOINTS (b)
+    if (bnum == -1
+       || bnum == b->number)
+      {
+       if (allflag || user_settable_breakpoint (b))
+         nr_printable_breakpoints++;
+      }
+
+  if (addressprint)
+    ui_out_table_begin (uiout, 6, nr_printable_breakpoints, "BreakpointTable");
+  else
+    ui_out_table_begin (uiout, 5, nr_printable_breakpoints, "BreakpointTable");
+
+  if (nr_printable_breakpoints > 0)
+    annotate_breakpoints_headers ();
+  if (nr_printable_breakpoints > 0)
+    annotate_field (0);
+  ui_out_table_header (uiout, 3, ui_left, "number", "Num");            /* 1 */
+  if (nr_printable_breakpoints > 0)
+    annotate_field (1);
+  ui_out_table_header (uiout, 14, ui_left, "type", "Type");            /* 2 */
+  if (nr_printable_breakpoints > 0)
+    annotate_field (2);
+  ui_out_table_header (uiout, 4, ui_left, "disp", "Disp");             /* 3 */
+  if (nr_printable_breakpoints > 0)
+    annotate_field (3);
+  ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb");   /* 4 */
+  if (addressprint)
+       {
+         if (nr_printable_breakpoints > 0)
+           annotate_field (4);
+         if (TARGET_ADDR_BIT <= 32)
+           ui_out_table_header (uiout, 10, ui_left, "addr", "Address");/* 5 */
+         else
+           ui_out_table_header (uiout, 18, ui_left, "addr", "Address");/* 5 */
+       }
+  if (nr_printable_breakpoints > 0)
+    annotate_field (5);
+  ui_out_table_header (uiout, 40, ui_noalign, "what", "What"); /* 6 */
+  ui_out_table_body (uiout);
+  if (nr_printable_breakpoints > 0)
+    annotate_breakpoints_table ();
+
+  ALL_BREAKPOINTS (b)
+    if (bnum == -1
+       || bnum == b->number)
+      {
+       /* We only print out user settable breakpoints unless the
+          allflag is set. */
+       if (allflag || user_settable_breakpoint (b))
+         print_one_breakpoint (b, &last_addr);
+      }
+  
+  ui_out_table_end (uiout);
+
+  if (nr_printable_breakpoints == 0)
+    {
+      if (bnum == -1)
+       ui_out_message (uiout, 0, "No breakpoints or watchpoints.\n");
+      else
+       ui_out_message (uiout, 0, "No breakpoint or watchpoint number %d.\n",
+                       bnum);
+    }
+  else
+    {
+      /* Compare against (CORE_ADDR)-1 in case some compiler decides
+        that a comparison of an unsigned with -1 is always false.  */
+      if (last_addr != (CORE_ADDR) -1)
+       set_next_address (last_addr);
+    }
+
+  /* FIXME? Should this be moved up so that it is only called when
+     there have been breakpoints? */
+  annotate_breakpoints_table_end ();
+}
+
+/* ARGSUSED */
+static void
+breakpoints_info (char *bnum_exp, int from_tty)
+{
+  int bnum = -1;
+
+  if (bnum_exp)
+    bnum = parse_and_eval_long (bnum_exp);
+
+  breakpoint_1 (bnum, 0);
+}
+
+/* ARGSUSED */
+static void
+maintenance_info_breakpoints (char *bnum_exp, int from_tty)
+{
+  int bnum = -1;
+
+  if (bnum_exp)
+    bnum = parse_and_eval_long (bnum_exp);
+
+  breakpoint_1 (bnum, 1);
+}
+
+/* Print a message describing any breakpoints set at PC.  */
+
+static void
+describe_other_breakpoints (CORE_ADDR pc, asection *section)
+{
+  register int others = 0;
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->address == pc)      /* address match / overlay match */
+      if (!overlay_debugging || b->section == section)
+       others++;
+  if (others > 0)
+    {
+      printf_filtered ("Note: breakpoint%s ", (others > 1) ? "s" : "");
+      ALL_BREAKPOINTS (b)
+       if (b->address == pc)   /* address match / overlay match */
+         if (!overlay_debugging || b->section == section)
+           {
+             others--;
+             printf_filtered ("%d%s%s ",
+                              b->number,
+                              ((b->enable_state == bp_disabled || 
+                                b->enable_state == bp_shlib_disabled || 
+                                b->enable_state == bp_call_disabled) 
+                               ? " (disabled)" 
+                               : b->enable_state == bp_permanent 
+                               ? " (permanent)"
+                               : ""),
+                              (others > 1) ? "," 
+                              : ((others == 1) ? " and" : ""));
+           }
+      printf_filtered ("also set at pc ");
+      print_address_numeric (pc, 1, gdb_stdout);
+      printf_filtered (".\n");
+    }
+}
+\f
+/* Set the default place to put a breakpoint
+   for the `break' command with no arguments.  */
+
+void
+set_default_breakpoint (int valid, CORE_ADDR addr, struct symtab *symtab,
+                       int line)
+{
+  default_breakpoint_valid = valid;
+  default_breakpoint_address = addr;
+  default_breakpoint_symtab = symtab;
+  default_breakpoint_line = line;
+}
+
+/* Return true iff it is meaningful to use the address member of
+   BPT.  For some breakpoint types, the address member is irrelevant
+   and it makes no sense to attempt to compare it to other addresses
+   (or use it for any other purpose either).
+
+   More specifically, each of the following breakpoint types will always
+   have a zero valued address and we don't want check_duplicates() to mark
+   breakpoints of any of these types to be a duplicate of an actual
+   breakpoint at address zero:
+
+      bp_watchpoint
+      bp_hardware_watchpoint
+      bp_read_watchpoint
+      bp_access_watchpoint
+      bp_catch_exec
+      bp_longjmp_resume
+      bp_catch_fork
+      bp_catch_vork */
+
+static int
+breakpoint_address_is_meaningful (struct breakpoint *bpt)
+{
+  enum bptype type = bpt->type;
+
+  return (type != bp_watchpoint
+         && type != bp_hardware_watchpoint
+         && type != bp_read_watchpoint
+         && type != bp_access_watchpoint
+         && type != bp_catch_exec
+         && type != bp_longjmp_resume
+         && type != bp_catch_fork
+         && type != bp_catch_vfork);
+}
+
+/* Rescan breakpoints at the same address and section as BPT,
+   marking the first one as "first" and any others as "duplicates".
+   This is so that the bpt instruction is only inserted once.
+   If we have a permanent breakpoint at the same place as BPT, make
+   that one the official one, and the rest as duplicates.  */
+
+static void
+check_duplicates (struct breakpoint *bpt)
+{
+  register struct breakpoint *b;
+  register int count = 0;
+  struct breakpoint *perm_bp = 0;
+  CORE_ADDR address = bpt->address;
+  asection *section = bpt->section;
+
+  if (! breakpoint_address_is_meaningful (bpt))
+    return;
+
+  ALL_BREAKPOINTS (b)
+    if (b->enable_state != bp_disabled
+       && b->enable_state != bp_shlib_disabled
+       && b->enable_state != bp_call_disabled
+       && b->address == address        /* address / overlay match */
+       && (!overlay_debugging || b->section == section)
+       && breakpoint_address_is_meaningful (b))
+    {
+      /* Have we found a permanent breakpoint?  */
+      if (b->enable_state == bp_permanent)
+       {
+         perm_bp = b;
+         break;
+       }
+       
+      count++;
+      b->duplicate = count > 1;
+    }
+
+  /* If we found a permanent breakpoint at this address, go over the
+     list again and declare all the other breakpoints there to be the
+     duplicates.  */
+  if (perm_bp)
+    {
+      perm_bp->duplicate = 0;
+
+      /* Permanent breakpoint should always be inserted.  */
+      if (! perm_bp->inserted)
+       internal_error (__FILE__, __LINE__,
+                       "allegedly permanent breakpoint is not "
+                       "actually inserted");
+
+      ALL_BREAKPOINTS (b)
+       if (b != perm_bp)
+         {
+           if (b->inserted)
+             internal_error (__FILE__, __LINE__,
+                             "another breakpoint was inserted on top of "
+                             "a permanent breakpoint");
+
+           if (b->enable_state != bp_disabled
+               && b->enable_state != bp_shlib_disabled
+               && b->enable_state != bp_call_disabled
+               && b->address == address        /* address / overlay match */
+               && (!overlay_debugging || b->section == section)
+               && breakpoint_address_is_meaningful (b))
+             b->duplicate = 1;
+         }
+    }
+}
+
+/* set_raw_breakpoint() is a low level routine for allocating and
+   partially initializing a breakpoint of type BPTYPE.  The newly
+   created breakpoint's address, section, source file name, and line
+   number are provided by SAL.  The newly created and partially
+   initialized breakpoint is added to the breakpoint chain and
+   is also returned as the value of this function.
+
+   It is expected that the caller will complete the initialization of
+   the newly created breakpoint struct as well as output any status
+   information regarding the creation of a new breakpoint.  In
+   particular, set_raw_breakpoint() does NOT set the breakpoint
+   number!  Care should be taken to not allow an error() to occur
+   prior to completing the initialization of the breakpoint.  If this
+   should happen, a bogus breakpoint will be left on the chain.  */
+
+struct breakpoint *
+set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
+{
+  register struct breakpoint *b, *b1;
+
+  b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
+  memset (b, 0, sizeof (*b));
+  b->address = sal.pc;
+  if (sal.symtab == NULL)
+    b->source_file = NULL;
+  else
+    b->source_file = savestring (sal.symtab->filename,
+                                strlen (sal.symtab->filename));
+  b->section = sal.section;
+  b->type = bptype;
+  b->language = current_language->la_language;
+  b->input_radix = input_radix;
+  b->thread = -1;
+  b->line_number = sal.line;
+  b->enable_state = bp_enabled;
+  b->next = 0;
+  b->silent = 0;
+  b->ignore_count = 0;
+  b->commands = NULL;
+  b->frame = 0;
+  b->dll_pathname = NULL;
+  b->triggered_dll_pathname = NULL;
+  b->forked_inferior_pid = 0;
+  b->exec_pathname = NULL;
+
+  /* Add this breakpoint to the end of the chain
+     so that a list of breakpoints will come out in order
+     of increasing numbers.  */
+
+  b1 = breakpoint_chain;
+  if (b1 == 0)
+    breakpoint_chain = b;
+  else
+    {
+      while (b1->next)
+       b1 = b1->next;
+      b1->next = b;
+    }
+
+  check_duplicates (b);
+  breakpoints_changed ();
+
+  return b;
+}
+
+
+/* Note that the breakpoint object B describes a permanent breakpoint
+   instruction, hard-wired into the inferior's code.  */
+void
+make_breakpoint_permanent (struct breakpoint *b)
+{
+  b->enable_state = bp_permanent;
+
+  /* By definition, permanent breakpoints are already present in the code.  */
+  b->inserted = 1;
+}
+
+static struct breakpoint *
+create_internal_breakpoint (CORE_ADDR address, enum bptype type)
+{
+  static int internal_breakpoint_number = -1;
+  struct symtab_and_line sal;
+  struct breakpoint *b;
+
+  INIT_SAL (&sal);             /* initialize to zeroes */
+
+  sal.pc = address;
+  sal.section = find_pc_overlay (sal.pc);
+
+  b = set_raw_breakpoint (sal, type);
+  b->number = internal_breakpoint_number--;
+  b->disposition = disp_donttouch;
+
+  return b;
+}
+
+
+static void
+create_longjmp_breakpoint (char *func_name)
+{
+  struct breakpoint *b;
+  struct minimal_symbol *m;
+
+  if (func_name == NULL)
+    b = create_internal_breakpoint (0, bp_longjmp_resume);
+  else
+    {
+      if ((m = lookup_minimal_symbol_text (func_name, NULL, NULL)) == NULL)
+       return;
+      b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), bp_longjmp);
+    }
+
+  b->enable_state = bp_disabled;
+  b->silent = 1;
+  if (func_name)
+    b->addr_string = xstrdup (func_name);
+}
+
+/* Call this routine when stepping and nexting to enable a breakpoint
+   if we do a longjmp().  When we hit that breakpoint, call
+   set_longjmp_resume_breakpoint() to figure out where we are going. */
+
+void
+enable_longjmp_breakpoint (void)
+{
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->type == bp_longjmp)
+    {
+      b->enable_state = bp_enabled;
+      check_duplicates (b);
+    }
+}
+
+void
+disable_longjmp_breakpoint (void)
+{
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->type == bp_longjmp
+       || b->type == bp_longjmp_resume)
+    {
+      b->enable_state = bp_disabled;
+      check_duplicates (b);
+    }
+}
+
+static void
+create_overlay_event_breakpoint (char *func_name)
+{
+  struct breakpoint *b;
+  struct minimal_symbol *m;
+
+  if ((m = lookup_minimal_symbol_text (func_name, NULL, NULL)) == NULL)
+    return;
+  b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), 
+                                 bp_overlay_event);
+  b->addr_string = xstrdup (func_name);
+
+  if (overlay_debugging == ovly_auto)
+    {
+      b->enable_state = bp_enabled;
+      overlay_events_enabled = 1;
+    }
+  else 
+    {
+      b->enable_state = bp_disabled;
+      overlay_events_enabled = 0;
+    }
+}
+
+void
+enable_overlay_breakpoints (void)
+{
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->type == bp_overlay_event)
+    {
+      b->enable_state = bp_enabled;
+      check_duplicates (b);
+      overlay_events_enabled = 1;
+    }
+}
+
+void
+disable_overlay_breakpoints (void)
+{
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->type == bp_overlay_event)
+    {
+      b->enable_state = bp_disabled;
+      check_duplicates (b);
+      overlay_events_enabled = 0;
+    }
+}
+
+struct breakpoint *
+create_thread_event_breakpoint (CORE_ADDR address)
+{
+  struct breakpoint *b;
+  char addr_string[80];                /* Surely an addr can't be longer than that. */
+
+  b = create_internal_breakpoint (address, bp_thread_event);
+  
+  b->enable_state = bp_enabled;
+  /* addr_string has to be used or breakpoint_re_set will delete me.  */
+  sprintf (addr_string, "*0x%s", paddr (b->address));
+  b->addr_string = xstrdup (addr_string);
+
+  return b;
+}
+
+void
+remove_thread_event_breakpoints (void)
+{
+  struct breakpoint *b, *temp;
+
+  ALL_BREAKPOINTS_SAFE (b, temp)
+    if (b->type == bp_thread_event)
+      delete_breakpoint (b);
+}
+
+#ifdef SOLIB_ADD
+void
+remove_solib_event_breakpoints (void)
+{
+  register struct breakpoint *b, *temp;
+
+  ALL_BREAKPOINTS_SAFE (b, temp)
+    if (b->type == bp_shlib_event)
+      delete_breakpoint (b);
+}
+
+struct breakpoint *
+create_solib_event_breakpoint (CORE_ADDR address)
+{
+  struct breakpoint *b;
+
+  b = create_internal_breakpoint (address, bp_shlib_event);
+  return b;
+}
+
+/* Disable any breakpoints that are on code in shared libraries.  Only
+   apply to enabled breakpoints, disabled ones can just stay disabled.  */
+
+void
+disable_breakpoints_in_shlibs (int silent)
+{
+  struct breakpoint *b;
+  int disabled_shlib_breaks = 0;
+
+  /* See also: insert_breakpoints, under DISABLE_UNSETTABLE_BREAK. */
+  ALL_BREAKPOINTS (b)
+  {
+#if defined (PC_SOLIB)
+    if (((b->type == bp_breakpoint) ||
+        (b->type == bp_hardware_breakpoint)) &&
+       b->enable_state == bp_enabled &&
+       !b->duplicate &&
+       PC_SOLIB (b->address))
+      {
+       b->enable_state = bp_shlib_disabled;
+       if (!silent)
+         {
+           if (!disabled_shlib_breaks)
+             {
+               target_terminal_ours_for_output ();
+               warning ("Temporarily disabling shared library breakpoints:");
+             }
+           disabled_shlib_breaks = 1;
+           warning ("breakpoint #%d ", b->number);
+         }
+      }
+#endif
+  }
+}
+
+/* Try to reenable any breakpoints in shared libraries.  */
+void
+re_enable_breakpoints_in_shlibs (void)
+{
+  struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->enable_state == bp_shlib_disabled)
+    {
+      char buf[1];
+
+      /* Do not reenable the breakpoint if the shared library
+         is still not mapped in.  */
+      if (target_read_memory (b->address, buf, 1) == 0)
+       b->enable_state = bp_enabled;
+    }
+}
+
+#endif
+
+static void
+solib_load_unload_1 (char *hookname, int tempflag, char *dll_pathname,
+                    char *cond_string, enum bptype bp_kind)
+{
+  struct breakpoint *b;
+  struct symtabs_and_lines sals;
+  struct cleanup *old_chain;
+  struct cleanup *canonical_strings_chain = NULL;
+  char *addr_start = hookname;
+  char *addr_end = NULL;
+  char **canonical = (char **) NULL;
+  int thread = -1;             /* All threads. */
+
+  /* Set a breakpoint on the specified hook. */
+  sals = decode_line_1 (&hookname, 1, (struct symtab *) NULL, 0, &canonical);
+  addr_end = hookname;
+
+  if (sals.nelts == 0)
+    {
+      warning ("Unable to set a breakpoint on dynamic linker callback.");
+      warning ("Suggest linking with /opt/langtools/lib/end.o.");
+      warning ("GDB will be unable to track shl_load/shl_unload calls");
+      return;
+    }
+  if (sals.nelts != 1)
+    {
+      warning ("Unable to set unique breakpoint on dynamic linker callback.");
+      warning ("GDB will be unable to track shl_load/shl_unload calls");
+      return;
+    }
+
+  /* Make sure that all storage allocated in decode_line_1 gets freed
+     in case the following errors out.  */
+  old_chain = make_cleanup (xfree, sals.sals);
+  if (canonical != (char **) NULL)
+    {
+      make_cleanup (xfree, canonical);
+      canonical_strings_chain = make_cleanup (null_cleanup, 0);
+      if (canonical[0] != NULL)
+       make_cleanup (xfree, canonical[0]);
+    }
+
+  resolve_sal_pc (&sals.sals[0]);
+
+  /* Remove the canonical strings from the cleanup, they are needed below.  */
+  if (canonical != (char **) NULL)
+    discard_cleanups (canonical_strings_chain);
+
+  b = set_raw_breakpoint (sals.sals[0], bp_kind);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->cond = NULL;
+  b->cond_string = (cond_string == NULL) ? 
+    NULL : savestring (cond_string, strlen (cond_string));
+  b->thread = thread;
+
+  if (canonical != (char **) NULL && canonical[0] != NULL)
+    b->addr_string = canonical[0];
+  else if (addr_start)
+    b->addr_string = savestring (addr_start, addr_end - addr_start);
+
+  b->enable_state = bp_enabled;
+  b->disposition = tempflag ? disp_del : disp_donttouch;
+
+  if (dll_pathname == NULL)
+    b->dll_pathname = NULL;
+  else
+    {
+      b->dll_pathname = (char *) xmalloc (strlen (dll_pathname) + 1);
+      strcpy (b->dll_pathname, dll_pathname);
+    }
+
+  mention (b);
+  do_cleanups (old_chain);
+}
+
+void
+create_solib_load_event_breakpoint (char *hookname, int tempflag,
+                                   char *dll_pathname, char *cond_string)
+{
+  solib_load_unload_1 (hookname, tempflag, dll_pathname, 
+                      cond_string, bp_catch_load);
+}
+
+void
+create_solib_unload_event_breakpoint (char *hookname, int tempflag,
+                                     char *dll_pathname, char *cond_string)
+{
+  solib_load_unload_1 (hookname,tempflag, dll_pathname, 
+                      cond_string, bp_catch_unload);
+}
+
+static void
+create_fork_vfork_event_catchpoint (int tempflag, char *cond_string,
+                                   enum bptype bp_kind)
+{
+  struct symtab_and_line sal;
+  struct breakpoint *b;
+  int thread = -1;             /* All threads. */
+
+  INIT_SAL (&sal);
+  sal.pc = 0;
+  sal.symtab = NULL;
+  sal.line = 0;
+
+  b = set_raw_breakpoint (sal, bp_kind);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->cond = NULL;
+  b->cond_string = (cond_string == NULL) ? 
+    NULL : savestring (cond_string, strlen (cond_string));
+  b->thread = thread;
+  b->addr_string = NULL;
+  b->enable_state = bp_enabled;
+  b->disposition = tempflag ? disp_del : disp_donttouch;
+  b->forked_inferior_pid = 0;
+
+  mention (b);
+}
+
+void
+create_fork_event_catchpoint (int tempflag, char *cond_string)
+{
+  create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_fork);
+}
+
+void
+create_vfork_event_catchpoint (int tempflag, char *cond_string)
+{
+  create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_vfork);
+}
+
+void
+create_exec_event_catchpoint (int tempflag, char *cond_string)
+{
+  struct symtab_and_line sal;
+  struct breakpoint *b;
+  int thread = -1;             /* All threads. */
+
+  INIT_SAL (&sal);
+  sal.pc = 0;
+  sal.symtab = NULL;
+  sal.line = 0;
+
+  b = set_raw_breakpoint (sal, bp_catch_exec);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->cond = NULL;
+  b->cond_string = (cond_string == NULL) ?
+    NULL : savestring (cond_string, strlen (cond_string));
+  b->thread = thread;
+  b->addr_string = NULL;
+  b->enable_state = bp_enabled;
+  b->disposition = tempflag ? disp_del : disp_donttouch;
+
+  mention (b);
+}
+
+static int
+hw_breakpoint_used_count (void)
+{
+  register struct breakpoint *b;
+  int i = 0;
+
+  ALL_BREAKPOINTS (b)
+  {
+    if (b->type == bp_hardware_breakpoint && b->enable_state == bp_enabled)
+      i++;
+  }
+
+  return i;
+}
+
+static int
+hw_watchpoint_used_count (enum bptype type, int *other_type_used)
+{
+  register struct breakpoint *b;
+  int i = 0;
+
+  *other_type_used = 0;
+  ALL_BREAKPOINTS (b)
+  {
+    if (b->enable_state == bp_enabled)
+      {
+       if (b->type == type)
+         i++;
+       else if ((b->type == bp_hardware_watchpoint ||
+                 b->type == bp_read_watchpoint ||
+                 b->type == bp_access_watchpoint)
+                && b->enable_state == bp_enabled)
+         *other_type_used = 1;
+      }
+  }
+  return i;
+}
+
+/* Call this after hitting the longjmp() breakpoint.  Use this to set
+   a new breakpoint at the target of the jmp_buf.
+
+   FIXME - This ought to be done by setting a temporary breakpoint
+   that gets deleted automatically... */
+
+void
+set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_info *frame)
+{
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->type == bp_longjmp_resume)
+    {
+      b->address = pc;
+      b->enable_state = bp_enabled;
+      if (frame != NULL)
+       b->frame = frame->frame;
+      else
+       b->frame = 0;
+      check_duplicates (b);
+      return;
+    }
+}
+
+void
+disable_watchpoints_before_interactive_call_start (void)
+{
+  struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+  {
+    if (((b->type == bp_watchpoint)
+        || (b->type == bp_hardware_watchpoint)
+        || (b->type == bp_read_watchpoint)
+        || (b->type == bp_access_watchpoint)
+        || ep_is_exception_catchpoint (b))
+       && (b->enable_state == bp_enabled))
+      {
+       b->enable_state = bp_call_disabled;
+       check_duplicates (b);
+      }
+  }
+}
+
+void
+enable_watchpoints_after_interactive_call_stop (void)
+{
+  struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+  {
+    if (((b->type == bp_watchpoint)
+        || (b->type == bp_hardware_watchpoint)
+        || (b->type == bp_read_watchpoint)
+        || (b->type == bp_access_watchpoint)
+        || ep_is_exception_catchpoint (b))
+       && (b->enable_state == bp_call_disabled))
+      {
+       b->enable_state = bp_enabled;
+       check_duplicates (b);
+      }
+  }
+}
+
+
+/* Set a breakpoint that will evaporate an end of command
+   at address specified by SAL.
+   Restrict it to frame FRAME if FRAME is nonzero.  */
+
+struct breakpoint *
+set_momentary_breakpoint (struct symtab_and_line sal, struct frame_info *frame,
+                         enum bptype type)
+{
+  register struct breakpoint *b;
+  b = set_raw_breakpoint (sal, type);
+  b->enable_state = bp_enabled;
+  b->disposition = disp_donttouch;
+  b->frame = (frame ? frame->frame : 0);
+
+  /* If we're debugging a multi-threaded program, then we
+     want momentary breakpoints to be active in only a 
+     single thread of control.  */
+  if (in_thread_list (inferior_ptid))
+    b->thread = pid_to_thread_id (inferior_ptid);
+
+  return b;
+}
+\f
+
+/* Tell the user we have just set a breakpoint B.  */
+
+static void
+mention (struct breakpoint *b)
+{
+  int say_where = 0;
+  struct cleanup *old_chain;
+  struct ui_stream *stb;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  /* FIXME: This is misplaced; mention() is called by things (like hitting a
+     watchpoint) other than breakpoint creation.  It should be possible to
+     clean this up and at the same time replace the random calls to
+     breakpoint_changed with this hook, as has already been done for
+     delete_breakpoint_hook and so on.  */
+  if (create_breakpoint_hook)
+    create_breakpoint_hook (b);
+  breakpoint_create_event (b->number);
+
+  switch (b->type)
+    {
+    case bp_none:
+      printf_filtered ("(apparently deleted?) Eventpoint %d: ", b->number);
+      break;
+    case bp_watchpoint:
+      ui_out_text (uiout, "Watchpoint ");
+      ui_out_tuple_begin (uiout, "wpt");
+      ui_out_field_int (uiout, "number", b->number);
+      ui_out_text (uiout, ": ");
+      print_expression (b->exp, stb->stream);
+      ui_out_field_stream (uiout, "exp", stb);
+      ui_out_tuple_end (uiout);
+      break;
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Hardware watchpoint ");
+      ui_out_tuple_begin (uiout, "wpt");
+      ui_out_field_int (uiout, "number", b->number);
+      ui_out_text (uiout, ": ");
+      print_expression (b->exp, stb->stream);
+      ui_out_field_stream (uiout, "exp", stb);
+      ui_out_tuple_end (uiout);
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Hardware read watchpoint ");
+      ui_out_tuple_begin (uiout, "hw-rwpt");
+      ui_out_field_int (uiout, "number", b->number);
+      ui_out_text (uiout, ": ");
+      print_expression (b->exp, stb->stream);
+      ui_out_field_stream (uiout, "exp", stb);
+      ui_out_tuple_end (uiout);
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
+      ui_out_tuple_begin (uiout, "hw-awpt");
+      ui_out_field_int (uiout, "number", b->number);
+      ui_out_text (uiout, ": ");
+      print_expression (b->exp, stb->stream);
+      ui_out_field_stream (uiout, "exp", stb);
+      ui_out_tuple_end (uiout);
+      break;
+    case bp_breakpoint:
+      if (ui_out_is_mi_like_p (uiout))
+       {
+         say_where = 0;
+         break;
+       }
+      printf_filtered ("Breakpoint %d", b->number);
+      say_where = 1;
+      break;
+    case bp_hardware_breakpoint:
+      if (ui_out_is_mi_like_p (uiout))
+       {
+         say_where = 0;
+         break;
+       }
+      printf_filtered ("Hardware assisted breakpoint %d", b->number);
+      say_where = 1;
+      break;
+    case bp_catch_load:
+    case bp_catch_unload:
+      printf_filtered ("Catchpoint %d (%s %s)",
+                      b->number,
+                      (b->type == bp_catch_load) ? "load" : "unload",
+                      (b->dll_pathname != NULL) ? 
+                      b->dll_pathname : "<any library>");
+      break;
+    case bp_catch_fork:
+    case bp_catch_vfork:
+      printf_filtered ("Catchpoint %d (%s)",
+                      b->number,
+                      (b->type == bp_catch_fork) ? "fork" : "vfork");
+      break;
+    case bp_catch_exec:
+      printf_filtered ("Catchpoint %d (exec)",
+                      b->number);
+      break;
+    case bp_catch_catch:
+    case bp_catch_throw:
+      printf_filtered ("Catchpoint %d (%s)",
+                      b->number,
+                      (b->type == bp_catch_catch) ? "catch" : "throw");
+      break;
+
+    case bp_until:
+    case bp_finish:
+    case bp_longjmp:
+    case bp_longjmp_resume:
+    case bp_step_resume:
+    case bp_through_sigtramp:
+    case bp_call_dummy:
+    case bp_watchpoint_scope:
+    case bp_shlib_event:
+    case bp_thread_event:
+    case bp_overlay_event:
+      break;
+    }
+  if (say_where)
+    {
+      if (addressprint || b->source_file == NULL)
+       {
+         printf_filtered (" at ");
+         print_address_numeric (b->address, 1, gdb_stdout);
+       }
+      if (b->source_file)
+       printf_filtered (": file %s, line %d.",
+                        b->source_file, b->line_number);
+    }
+  do_cleanups (old_chain);
+  if (ui_out_is_mi_like_p (uiout))
+    return;
+  printf_filtered ("\n");
+}
+\f
+
+/* Add SALS.nelts breakpoints to the breakpoint table.  For each
+   SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i],
+   COND[i] and COND_STRING[i] values.
+
+   NOTE: If the function succeeds, the caller is expected to cleanup
+   the arrays ADDR_STRING, COND_STRING, COND and SALS (but not the
+   array contents).  If the function fails (error() is called), the
+   caller is expected to cleanups both the ADDR_STRING, COND_STRING,
+   COND and SALS arrays and each of those arrays contents. */
+
+static void
+create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
+                   struct expression **cond, char **cond_string,
+                   enum bptype type, enum bpdisp disposition,
+                   int thread, int ignore_count, int from_tty)
+{
+  if (type == bp_hardware_breakpoint)
+    {
+      int i = hw_breakpoint_used_count ();
+      int target_resources_ok = 
+       TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_hardware_breakpoint, 
+                                           i + sals.nelts, 0);
+      if (target_resources_ok == 0)
+       error ("No hardware breakpoint support in the target.");
+      else if (target_resources_ok < 0)
+       error ("Hardware breakpoints used exceeds limit.");
+    }
+
+  /* Now set all the breakpoints.  */
+  {
+    int i;
+    for (i = 0; i < sals.nelts; i++)
+      {
+       struct breakpoint *b;
+       struct symtab_and_line sal = sals.sals[i];
+
+       if (from_tty)
+         describe_other_breakpoints (sal.pc, sal.section);
+       
+       b = set_raw_breakpoint (sal, type);
+       set_breakpoint_count (breakpoint_count + 1);
+       b->number = breakpoint_count;
+       b->cond = cond[i];
+       b->thread = thread;
+       b->addr_string = addr_string[i];
+       b->cond_string = cond_string[i];
+       b->ignore_count = ignore_count;
+       b->enable_state = bp_enabled;
+       b->disposition = disposition;
+       mention (b);
+      }
+  }    
+}
+
+/* Parse ARG which is assumed to be a SAL specification possibly
+   followed by conditionals.  On return, SALS contains an array of SAL
+   addresses found. ADDR_STRING contains a vector of (canonical)
+   address strings. ARG points to the end of the SAL. */
+
+void
+parse_breakpoint_sals (char **address,
+                      struct symtabs_and_lines *sals,
+                      char ***addr_string)
+{
+  char *addr_start = *address;
+  *addr_string = NULL;
+  /* If no arg given, or if first arg is 'if ', use the default
+     breakpoint. */
+  if ((*address) == NULL
+      || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
+    {
+      if (default_breakpoint_valid)
+       {
+         struct symtab_and_line sal;
+         INIT_SAL (&sal);              /* initialize to zeroes */
+         sals->sals = (struct symtab_and_line *)
+           xmalloc (sizeof (struct symtab_and_line));
+         sal.pc = default_breakpoint_address;
+         sal.line = default_breakpoint_line;
+         sal.symtab = default_breakpoint_symtab;
+         sal.section = find_pc_overlay (sal.pc);
+         sals->sals[0] = sal;
+         sals->nelts = 1;
+       }
+      else
+       error ("No default breakpoint address now.");
+    }
+  else
+    {
+      /* Force almost all breakpoints to be in terms of the
+         current_source_symtab (which is decode_line_1's default).  This
+         should produce the results we want almost all of the time while
+         leaving default_breakpoint_* alone.  */
+        
+      struct symtab_and_line cursal = 
+                       get_current_or_default_source_symtab_and_line ();
+                       
+      if (default_breakpoint_valid
+         && (!cursal.symtab
+             || (strchr ("+-", (*address)[0]) != NULL)))
+       *sals = decode_line_1 (address, 1, default_breakpoint_symtab,
+                              default_breakpoint_line, addr_string);
+      else
+       *sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0, addr_string);
+    }
+  /* For any SAL that didn't have a canonical string, fill one in. */
+  if (sals->nelts > 0 && *addr_string == NULL)
+    *addr_string = xcalloc (sals->nelts, sizeof (char **));
+  if (addr_start != (*address))
+    {
+      int i;
+      for (i = 0; i < sals->nelts; i++)
+       {
+         /* Add the string if not present. */
+         if ((*addr_string)[i] == NULL)
+           (*addr_string)[i] = savestring (addr_start, (*address) - addr_start);
+       }
+    }
+}
+
+
+/* Convert each SAL into a real PC.  Verify that the PC can be
+   inserted as a breakpoint.  If it can't throw an error. */
+
+void
+breakpoint_sals_to_pc (struct symtabs_and_lines *sals,
+                      char *address)
+{    
+  int i;
+  for (i = 0; i < sals->nelts; i++)
+    {
+      resolve_sal_pc (&sals->sals[i]);
+
+      /* It's possible for the PC to be nonzero, but still an illegal
+         value on some targets.
+
+         For example, on HP-UX if you start gdb, and before running the
+         inferior you try to set a breakpoint on a shared library function
+         "foo" where the inferior doesn't call "foo" directly but does
+         pass its address to another function call, then we do find a
+         minimal symbol for the "foo", but it's address is invalid.
+         (Appears to be an index into a table that the loader sets up
+         when the inferior is run.)
+
+         Give the target a chance to bless sals.sals[i].pc before we
+         try to make a breakpoint for it. */
+      if (PC_REQUIRES_RUN_BEFORE_USE (sals->sals[i].pc))
+       {
+         if (address == NULL)
+           error ("Cannot break without a running program.");
+         else
+           error ("Cannot break on %s without a running program.", 
+                  address);
+       }
+    }
+}
+
+/* Set a breakpoint according to ARG (function, linenum or *address)
+   flag: first bit  : 0 non-temporary, 1 temporary.
+   second bit : 0 normal breakpoint, 1 hardware breakpoint. */
+
+static void
+break_command_1 (char *arg, int flag, int from_tty)
+{
+  int tempflag, hardwareflag;
+  struct symtabs_and_lines sals;
+  register struct expression **cond = 0;
+  /* Pointers in arg to the start, and one past the end, of the
+     condition.  */
+  char **cond_string = (char **) NULL;
+  char *addr_start = arg;
+  char **addr_string;
+  struct cleanup *old_chain;
+  struct cleanup *breakpoint_chain = NULL;
+  int i;
+  int thread = -1;
+  int ignore_count = 0;
+
+  hardwareflag = flag & BP_HARDWAREFLAG;
+  tempflag = flag & BP_TEMPFLAG;
+
+  sals.sals = NULL;
+  sals.nelts = 0;
+  addr_string = NULL;
+  parse_breakpoint_sals (&arg, &sals, &addr_string);
+
+  if (!sals.nelts)
+    return;
+
+  /* Create a chain of things that always need to be cleaned up. */
+  old_chain = make_cleanup (null_cleanup, 0);
+
+  /* Make sure that all storage allocated to SALS gets freed.  */
+  make_cleanup (xfree, sals.sals);
+
+  /* Cleanup the addr_string array but not its contents. */
+  make_cleanup (xfree, addr_string);
+
+  /* Allocate space for all the cond expressions. */
+  cond = xcalloc (sals.nelts, sizeof (struct expression *));
+  make_cleanup (xfree, cond);
+
+  /* Allocate space for all the cond strings. */
+  cond_string = xcalloc (sals.nelts, sizeof (char **));
+  make_cleanup (xfree, cond_string);
+
+  /* ----------------------------- SNIP -----------------------------
+     Anything added to the cleanup chain beyond this point is assumed
+     to be part of a breakpoint.  If the breakpoint create succeeds
+     then the memory is not reclaimed. */
+  breakpoint_chain = make_cleanup (null_cleanup, 0);
+
+  /* Mark the contents of the addr_string for cleanup.  These go on
+     the breakpoint_chain and only occure if the breakpoint create
+     fails. */
+  for (i = 0; i < sals.nelts; i++)
+    {
+      if (addr_string[i] != NULL)
+       make_cleanup (xfree, addr_string[i]);
+    }
+
+  /* Resolve all line numbers to PC's and verify that the addresses
+     are ok for the target.  */
+  breakpoint_sals_to_pc (&sals, addr_start);
+
+  /* Verify that condition can be parsed, before setting any
+     breakpoints.  Allocate a separate condition expression for each
+     breakpoint. */
+  thread = -1;                 /* No specific thread yet */
+  for (i = 0; i < sals.nelts; i++)
+    {
+      char *tok = arg;
+      while (tok && *tok)
+       {
+         char *end_tok;
+         int toklen;
+         char *cond_start = NULL;
+         char *cond_end = NULL;
+         while (*tok == ' ' || *tok == '\t')
+           tok++;
+
+         end_tok = tok;
+
+         while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
+           end_tok++;
+
+         toklen = end_tok - tok;
+
+         if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
+           {
+             tok = cond_start = end_tok + 1;
+             cond[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0);
+             make_cleanup (xfree, cond[i]);
+             cond_end = tok;
+             cond_string[i] = savestring (cond_start, cond_end - cond_start);
+             make_cleanup (xfree, cond_string[i]);
+           }
+         else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+           {
+             char *tmptok;
+
+             tok = end_tok + 1;
+             tmptok = tok;
+             thread = strtol (tok, &tok, 0);
+             if (tok == tmptok)
+               error ("Junk after thread keyword.");
+             if (!valid_thread_id (thread))
+               error ("Unknown thread %d\n", thread);
+           }
+         else
+           error ("Junk at end of arguments.");
+       }
+    }
+
+  create_breakpoints (sals, addr_string, cond, cond_string,
+                     hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
+                     tempflag ? disp_del : disp_donttouch,
+                     thread, ignore_count, from_tty);
+
+  if (sals.nelts > 1)
+    {
+      warning ("Multiple breakpoints were set.");
+      warning ("Use the \"delete\" command to delete unwanted breakpoints.");
+    }
+  /* That's it. Discard the cleanups for data inserted into the
+     breakpoint. */
+  discard_cleanups (breakpoint_chain);
+  /* But cleanup everything else. */
+  do_cleanups (old_chain);
+}
+
+/* Set a breakpoint of TYPE/DISPOSITION according to ARG (function,
+   linenum or *address) with COND and IGNORE_COUNT. */
+
+struct captured_breakpoint_args
+  {
+    char *address;
+    char *condition;
+    int hardwareflag;
+    int tempflag;
+    int thread;
+    int ignore_count;
+  };
+
+static int
+do_captured_breakpoint (void *data)
+{
+  struct captured_breakpoint_args *args = data;
+  struct symtabs_and_lines sals;
+  register struct expression **cond;
+  struct cleanup *old_chain;
+  struct cleanup *breakpoint_chain = NULL;
+  int i;
+  char **addr_string;
+  char **cond_string;
+
+  char *address_end;
+
+  /* Parse the source and lines spec.  Delay check that the expression
+     didn't contain trailing garbage until after cleanups are in
+     place. */
+  sals.sals = NULL;
+  sals.nelts = 0;
+  address_end = args->address;
+  addr_string = NULL;
+  parse_breakpoint_sals (&address_end, &sals, &addr_string);
+
+  if (!sals.nelts)
+    return GDB_RC_NONE;
+
+  /* Create a chain of things at always need to be cleaned up. */
+  old_chain = make_cleanup (null_cleanup, 0);
+
+  /* Always have a addr_string array, even if it is empty. */
+  make_cleanup (xfree, addr_string);
+
+  /* Make sure that all storage allocated to SALS gets freed.  */
+  make_cleanup (xfree, sals.sals);
+
+  /* Allocate space for all the cond expressions. */
+  cond = xcalloc (sals.nelts, sizeof (struct expression *));
+  make_cleanup (xfree, cond);
+
+  /* Allocate space for all the cond strings. */
+  cond_string = xcalloc (sals.nelts, sizeof (char **));
+  make_cleanup (xfree, cond_string);
+
+  /* ----------------------------- SNIP -----------------------------
+     Anything added to the cleanup chain beyond this point is assumed
+     to be part of a breakpoint.  If the breakpoint create goes
+     through then that memory is not cleaned up. */
+  breakpoint_chain = make_cleanup (null_cleanup, 0);
+
+  /* Mark the contents of the addr_string for cleanup.  These go on
+     the breakpoint_chain and only occure if the breakpoint create
+     fails. */
+  for (i = 0; i < sals.nelts; i++)
+    {
+      if (addr_string[i] != NULL)
+       make_cleanup (xfree, addr_string[i]);
+    }
+
+  /* Wait until now before checking for garbage at the end of the
+     address. That way cleanups can take care of freeing any
+     memory. */
+  if (*address_end != '\0')
+    error ("Garbage %s following breakpoint address", address_end);
+
+  /* Resolve all line numbers to PC's.  */
+  breakpoint_sals_to_pc (&sals, args->address);
+
+  /* Verify that conditions can be parsed, before setting any
+     breakpoints.  */
+  for (i = 0; i < sals.nelts; i++)
+    {
+      if (args->condition != NULL)
+       {
+         char *tok = args->condition;
+         cond[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0);
+         if (*tok != '\0')
+           error ("Garbage %s follows condition", tok);
+         make_cleanup (xfree, cond[i]);
+         cond_string[i] = xstrdup (args->condition);
+       }
+    }
+
+  create_breakpoints (sals, addr_string, cond, cond_string,
+                     args->hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
+                     args->tempflag ? disp_del : disp_donttouch,
+                     args->thread, args->ignore_count, 0/*from-tty*/);
+
+  /* That's it. Discard the cleanups for data inserted into the
+     breakpoint. */
+  discard_cleanups (breakpoint_chain);
+  /* But cleanup everything else. */
+  do_cleanups (old_chain);
+  return GDB_RC_OK;
+}
+
+enum gdb_rc
+gdb_breakpoint (char *address, char *condition,
+               int hardwareflag, int tempflag,
+               int thread, int ignore_count)
+{
+  struct captured_breakpoint_args args;
+  args.address = address;
+  args.condition = condition;
+  args.hardwareflag = hardwareflag;
+  args.tempflag = tempflag;
+  args.thread = thread;
+  args.ignore_count = ignore_count;
+  return catch_errors (do_captured_breakpoint, &args,
+                      NULL, RETURN_MASK_ALL);
+}
+
+
+static void
+break_at_finish_at_depth_command_1 (char *arg, int flag, int from_tty)
+{
+  struct frame_info *frame;
+  CORE_ADDR low, high, selected_pc = 0;
+  char *extra_args = NULL;
+  char *level_arg;
+  char *addr_string;
+  int extra_args_len = 0, if_arg = 0;
+
+  if (!arg ||
+      (arg[0] == 'i' && arg[1] == 'f' && (arg[2] == ' ' || arg[2] == '\t')))
+    {
+
+      if (default_breakpoint_valid)
+       {
+         if (selected_frame)
+           {
+             selected_pc = selected_frame->pc;
+             if (arg)
+               if_arg = 1;
+           }
+         else
+           error ("No selected frame.");
+       }
+      else
+       error ("No default breakpoint address now.");
+    }
+  else
+    {
+      extra_args = strchr (arg, ' ');
+      if (extra_args)
+       {
+         extra_args++;
+         extra_args_len = strlen (extra_args);
+         level_arg = (char *) xmalloc (extra_args - arg);
+         strncpy (level_arg, arg, extra_args - arg - 1);
+         level_arg[extra_args - arg - 1] = '\0';
+       }
+      else
+       {
+         level_arg = (char *) xmalloc (strlen (arg) + 1);
+         strcpy (level_arg, arg);
+       }
+
+      frame = parse_frame_specification (level_arg);
+      if (frame)
+       selected_pc = frame->pc;
+      else
+       selected_pc = 0;
+    }
+  if (if_arg)
+    {
+      extra_args = arg;
+      extra_args_len = strlen (arg);
+    }
+
+  if (selected_pc)
+    {
+      if (find_pc_partial_function (selected_pc, (char **) NULL, &low, &high))
+       {
+         addr_string = (char *) xmalloc (26 + extra_args_len);
+         if (extra_args_len)
+           sprintf (addr_string, "*0x%s %s", paddr_nz (high), extra_args);
+         else
+           sprintf (addr_string, "*0x%s", paddr_nz (high));
+         break_command_1 (addr_string, flag, from_tty);
+         xfree (addr_string);
+       }
+      else
+       error ("No function contains the specified address");
+    }
+  else
+    error ("Unable to set breakpoint at procedure exit");
+}
+
+
+static void
+break_at_finish_command_1 (char *arg, int flag, int from_tty)
+{
+  char *addr_string, *break_string, *beg_addr_string;
+  CORE_ADDR low, high;
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  struct cleanup *old_chain;
+  char *extra_args = NULL;
+  int extra_args_len = 0;
+  int i, if_arg = 0;
+
+  if (!arg ||
+      (arg[0] == 'i' && arg[1] == 'f' && (arg[2] == ' ' || arg[2] == '\t')))
+    {
+      if (default_breakpoint_valid)
+       {
+         if (selected_frame)
+           {
+             addr_string = (char *) xmalloc (15);
+             sprintf (addr_string, "*0x%s", paddr_nz (selected_frame->pc));
+             if (arg)
+               if_arg = 1;
+           }
+         else
+           error ("No selected frame.");
+       }
+      else
+       error ("No default breakpoint address now.");
+    }
+  else
+    {
+      addr_string = (char *) xmalloc (strlen (arg) + 1);
+      strcpy (addr_string, arg);
+    }
+
+  if (if_arg)
+    {
+      extra_args = arg;
+      extra_args_len = strlen (arg);
+    }
+  else if (arg)
+    {
+      /* get the stuff after the function name or address */
+      extra_args = strchr (arg, ' ');
+      if (extra_args)
+       {
+         extra_args++;
+         extra_args_len = strlen (extra_args);
+       }
+    }
+
+  sals.sals = NULL;
+  sals.nelts = 0;
+
+  beg_addr_string = addr_string;
+  sals = decode_line_1 (&addr_string, 1, (struct symtab *) NULL, 0,
+                       (char ***) NULL);
+
+  xfree (beg_addr_string);
+  old_chain = make_cleanup (xfree, sals.sals);
+  for (i = 0; (i < sals.nelts); i++)
+    {
+      sal = sals.sals[i];
+      if (find_pc_partial_function (sal.pc, (char **) NULL, &low, &high))
+       {
+         break_string = (char *) xmalloc (extra_args_len + 26);
+         if (extra_args_len)
+           sprintf (break_string, "*0x%s %s", paddr_nz (high), extra_args);
+         else
+           sprintf (break_string, "*0x%s", paddr_nz (high));
+         break_command_1 (break_string, flag, from_tty);
+         xfree (break_string);
+       }
+      else
+       error ("No function contains the specified address");
+    }
+  if (sals.nelts > 1)
+    {
+      warning ("Multiple breakpoints were set.\n");
+      warning ("Use the \"delete\" command to delete unwanted breakpoints.");
+    }
+  do_cleanups (old_chain);
+}
+
+
+/* Helper function for break_command_1 and disassemble_command.  */
+
+void
+resolve_sal_pc (struct symtab_and_line *sal)
+{
+  CORE_ADDR pc;
+
+  if (sal->pc == 0 && sal->symtab != NULL)
+    {
+      if (!find_line_pc (sal->symtab, sal->line, &pc))
+       error ("No line %d in file \"%s\".",
+              sal->line, sal->symtab->filename);
+      sal->pc = pc;
+    }
+
+  if (sal->section == 0 && sal->symtab != NULL)
+    {
+      struct blockvector *bv;
+      struct block *b;
+      struct symbol *sym;
+      int index;
+
+      bv = blockvector_for_pc_sect (sal->pc, 0, &index, sal->symtab);
+      if (bv != NULL)
+       {
+         b = BLOCKVECTOR_BLOCK (bv, index);
+         sym = block_function (b);
+         if (sym != NULL)
+           {
+             fixup_symbol_section (sym, sal->symtab->objfile);
+             sal->section = SYMBOL_BFD_SECTION (sym);
+           }
+         else
+           {
+             /* It really is worthwhile to have the section, so we'll just
+                have to look harder. This case can be executed if we have 
+                line numbers but no functions (as can happen in assembly 
+                source).  */
+
+             struct minimal_symbol *msym;
+
+             msym = lookup_minimal_symbol_by_pc (sal->pc);
+             if (msym)
+               sal->section = SYMBOL_BFD_SECTION (msym);
+           }
+       }
+    }
+}
+
+void
+break_command (char *arg, int from_tty)
+{
+  break_command_1 (arg, 0, from_tty);
+}
+
+void
+break_at_finish_command (char *arg, int from_tty)
+{
+  break_at_finish_command_1 (arg, 0, from_tty);
+}
+
+void
+break_at_finish_at_depth_command (char *arg, int from_tty)
+{
+  break_at_finish_at_depth_command_1 (arg, 0, from_tty);
+}
+
+void
+tbreak_command (char *arg, int from_tty)
+{
+  break_command_1 (arg, BP_TEMPFLAG, from_tty);
+}
+
+void
+tbreak_at_finish_command (char *arg, int from_tty)
+{
+  break_at_finish_command_1 (arg, BP_TEMPFLAG, from_tty);
+}
+
+static void
+hbreak_command (char *arg, int from_tty)
+{
+  break_command_1 (arg, BP_HARDWAREFLAG, from_tty);
+}
+
+static void
+thbreak_command (char *arg, int from_tty)
+{
+  break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty);
+}
+
+static void
+stop_command (char *arg, int from_tty)
+{
+  printf_filtered ("Specify the type of breakpoint to set.\n\
+Usage: stop in <function | address>\n\
+       stop at <line>\n");
+}
+
+static void
+stopin_command (char *arg, int from_tty)
+{
+  int badInput = 0;
+
+  if (arg == (char *) NULL)
+    badInput = 1;
+  else if (*arg != '*')
+    {
+      char *argptr = arg;
+      int hasColon = 0;
+
+      /* look for a ':'.  If this is a line number specification, then
+         say it is bad, otherwise, it should be an address or
+         function/method name */
+      while (*argptr && !hasColon)
+       {
+         hasColon = (*argptr == ':');
+         argptr++;
+       }
+
+      if (hasColon)
+       badInput = (*argptr != ':');    /* Not a class::method */
+      else
+       badInput = isdigit (*arg);      /* a simple line number */
+    }
+
+  if (badInput)
+    printf_filtered ("Usage: stop in <function | address>\n");
+  else
+    break_command_1 (arg, 0, from_tty);
+}
+
+static void
+stopat_command (char *arg, int from_tty)
+{
+  int badInput = 0;
+
+  if (arg == (char *) NULL || *arg == '*')     /* no line number */
+    badInput = 1;
+  else
+    {
+      char *argptr = arg;
+      int hasColon = 0;
+
+      /* look for a ':'.  If there is a '::' then get out, otherwise
+         it is probably a line number. */
+      while (*argptr && !hasColon)
+       {
+         hasColon = (*argptr == ':');
+         argptr++;
+       }
+
+      if (hasColon)
+       badInput = (*argptr == ':');    /* we have class::method */
+      else
+       badInput = !isdigit (*arg);     /* not a line number */
+    }
+
+  if (badInput)
+    printf_filtered ("Usage: stop at <line>\n");
+  else
+    break_command_1 (arg, 0, from_tty);
+}
+
+/* ARGSUSED */
+/* accessflag:  hw_write:  watch write, 
+                hw_read:   watch read, 
+               hw_access: watch access (read or write) */
+static void
+watch_command_1 (char *arg, int accessflag, int from_tty)
+{
+  struct breakpoint *b;
+  struct symtab_and_line sal;
+  struct expression *exp;
+  struct block *exp_valid_block;
+  struct value *val, *mark;
+  struct frame_info *frame;
+  struct frame_info *prev_frame = NULL;
+  char *exp_start = NULL;
+  char *exp_end = NULL;
+  char *tok, *end_tok;
+  int toklen;
+  char *cond_start = NULL;
+  char *cond_end = NULL;
+  struct expression *cond = NULL;
+  int i, other_type_used, target_resources_ok = 0;
+  enum bptype bp_type;
+  int mem_cnt = 0;
+
+  INIT_SAL (&sal);             /* initialize to zeroes */
+
+  /* Parse arguments.  */
+  innermost_block = NULL;
+  exp_start = arg;
+  exp = parse_exp_1 (&arg, 0, 0);
+  exp_end = arg;
+  exp_valid_block = innermost_block;
+  mark = value_mark ();
+  val = evaluate_expression (exp);
+  release_value (val);
+  if (VALUE_LAZY (val))
+    value_fetch_lazy (val);
+
+  tok = arg;
+  while (*tok == ' ' || *tok == '\t')
+    tok++;
+  end_tok = tok;
+
+  while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
+    end_tok++;
+
+  toklen = end_tok - tok;
+  if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
+    {
+      tok = cond_start = end_tok + 1;
+      cond = parse_exp_1 (&tok, 0, 0);
+      cond_end = tok;
+    }
+  if (*tok)
+    error ("Junk at end of command.");
+
+  if (accessflag == hw_read)
+    bp_type = bp_read_watchpoint;
+  else if (accessflag == hw_access)
+    bp_type = bp_access_watchpoint;
+  else
+    bp_type = bp_hardware_watchpoint;
+
+  mem_cnt = can_use_hardware_watchpoint (val);
+  if (mem_cnt == 0 && bp_type != bp_hardware_watchpoint)
+    error ("Expression cannot be implemented with read/access watchpoint.");
+  if (mem_cnt != 0)
+    {
+      i = hw_watchpoint_used_count (bp_type, &other_type_used);
+      target_resources_ok = 
+       TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_type, i + mem_cnt, 
+                                           other_type_used);
+      if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint)
+       error ("Target does not support this type of hardware watchpoint.");
+
+      if (target_resources_ok < 0 && bp_type != bp_hardware_watchpoint)
+       error ("Target can only support one kind of HW watchpoint at a time.");
+    }
+
+#if defined(HPUXHPPA)
+  /*  On HP-UX if you set a h/w
+     watchpoint before the "run" command, the inferior dies with a e.g.,
+     SIGILL once you start it.  I initially believed this was due to a
+     bad interaction between page protection traps and the initial
+     startup sequence by the dynamic linker.
+
+     However, I tried avoiding that by having HP-UX's implementation of
+     TARGET_CAN_USE_HW_WATCHPOINT return FALSE if there was no inferior_ptid
+     yet, which forced slow watches before a "run" or "attach", and it
+     still fails somewhere in the startup code.
+
+     Until I figure out what's happening, I'm disallowing watches altogether
+     before the "run" or "attach" command.  We'll tell the user they must
+     set watches after getting the program started. */
+  if (!target_has_execution)
+    {
+      warning ("can't do that without a running program; try \"break main\", \"run\" first");
+      return;
+    }
+#endif /* HPUXHPPA */
+
+  /* Change the type of breakpoint to an ordinary watchpoint if a hardware
+     watchpoint could not be set.  */
+  if (!mem_cnt || target_resources_ok <= 0)
+    bp_type = bp_watchpoint;
+
+  /* Now set up the breakpoint.  */
+  b = set_raw_breakpoint (sal, bp_type);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->disposition = disp_donttouch;
+  b->exp = exp;
+  b->exp_valid_block = exp_valid_block;
+  b->exp_string = savestring (exp_start, exp_end - exp_start);
+  b->val = val;
+  b->cond = cond;
+  if (cond_start)
+    b->cond_string = savestring (cond_start, cond_end - cond_start);
+  else
+    b->cond_string = 0;
+
+  frame = block_innermost_frame (exp_valid_block);
+  if (frame)
+    {
+      prev_frame = get_prev_frame (frame);
+      get_frame_id (frame, &b->watchpoint_frame);
+    }
+  else
+    {
+      memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
+    }
+
+  /* If the expression is "local", then set up a "watchpoint scope"
+     breakpoint at the point where we've left the scope of the watchpoint
+     expression.  */
+  if (innermost_block)
+    {
+      if (prev_frame)
+       {
+         struct breakpoint *scope_breakpoint;
+         scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
+                                                        bp_watchpoint_scope);
+
+         scope_breakpoint->enable_state = bp_enabled;
+
+         /* Automatically delete the breakpoint when it hits.  */
+         scope_breakpoint->disposition = disp_del;
+
+         /* Only break in the proper frame (help with recursion).  */
+         scope_breakpoint->frame = prev_frame->frame;
+
+         /* Set the address at which we will stop.  */
+         scope_breakpoint->address = get_frame_pc (prev_frame);
+
+         /* The scope breakpoint is related to the watchpoint.  We
+            will need to act on them together.  */
+         b->related_breakpoint = scope_breakpoint;
+       }
+    }
+  value_free_to_mark (mark);
+  mention (b);
+}
+
+/* Return count of locations need to be watched and can be handled
+   in hardware.  If the watchpoint can not be handled
+   in hardware return zero.  */
+
+#if !defined(TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT)
+#define TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(BYTE_SIZE) \
+    ((BYTE_SIZE) <= (REGISTER_SIZE))
+#endif
+
+#if !defined(TARGET_REGION_OK_FOR_HW_WATCHPOINT)
+#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(ADDR,LEN) \
+     (TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(LEN))
+#endif
+
+static int
+can_use_hardware_watchpoint (struct value *v)
+{
+  int found_memory_cnt = 0;
+  struct value *head = v;
+
+  /* Did the user specifically forbid us to use hardware watchpoints? */
+  if (!can_use_hw_watchpoints)
+    return 0;
+
+  /* Make sure that the value of the expression depends only upon
+     memory contents, and values computed from them within GDB.  If we
+     find any register references or function calls, we can't use a
+     hardware watchpoint.
+
+     The idea here is that evaluating an expression generates a series
+     of values, one holding the value of every subexpression.  (The
+     expression a*b+c has five subexpressions: a, b, a*b, c, and
+     a*b+c.)  GDB's values hold almost enough information to establish
+     the criteria given above --- they identify memory lvalues,
+     register lvalues, computed values, etcetera.  So we can evaluate
+     the expression, and then scan the chain of values that leaves
+     behind to decide whether we can detect any possible change to the
+     expression's final value using only hardware watchpoints.
+
+     However, I don't think that the values returned by inferior
+     function calls are special in any way.  So this function may not
+     notice that an expression involving an inferior function call
+     can't be watched with hardware watchpoints.  FIXME.  */
+  for (; v; v = v->next)
+    {
+      if (VALUE_LVAL (v) == lval_memory)
+       {
+         if (VALUE_LAZY (v))
+           /* A lazy memory lvalue is one that GDB never needed to fetch;
+              we either just used its address (e.g., `a' in `a.b') or
+              we never needed it at all (e.g., `a' in `a,b').  */
+           ;
+         else
+           {
+             /* Ahh, memory we actually used!  Check if we can cover
+                 it with hardware watchpoints.  */
+             struct type *vtype = check_typedef (VALUE_TYPE (v));
+
+             /* We only watch structs and arrays if user asked for it
+                explicitly, never if they just happen to appear in a
+                middle of some value chain.  */
+             if (v == head
+                 || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+                     && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+               {
+                 CORE_ADDR vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+                 int       len   = TYPE_LENGTH (VALUE_TYPE (v));
+
+                 if (!TARGET_REGION_OK_FOR_HW_WATCHPOINT (vaddr, len))
+                   return 0;
+                 else
+                   found_memory_cnt++;
+               }
+           }
+       }
+      else if (v->lval != not_lval && v->modifiable == 0)
+       return 0;       /* ??? What does this represent? */
+      else if (v->lval == lval_register)
+       return 0;       /* cannot watch a register with a HW watchpoint */
+    }
+
+  /* The expression itself looks suitable for using a hardware
+     watchpoint, but give the target machine a chance to reject it.  */
+  return found_memory_cnt;
+}
+
+void
+watch_command_wrapper (char *arg, int from_tty)
+{
+  watch_command (arg, from_tty);
+}
+
+static void
+watch_command (char *arg, int from_tty)
+{
+  watch_command_1 (arg, hw_write, from_tty);
+}
+
+void
+rwatch_command_wrapper (char *arg, int from_tty)
+{
+  rwatch_command (arg, from_tty);
+}
+
+static void
+rwatch_command (char *arg, int from_tty)
+{
+  watch_command_1 (arg, hw_read, from_tty);
+}
+
+void
+awatch_command_wrapper (char *arg, int from_tty)
+{
+  awatch_command (arg, from_tty);
+}
+
+static void
+awatch_command (char *arg, int from_tty)
+{
+  watch_command_1 (arg, hw_access, from_tty);
+}
+\f
+
+/* Helper routines for the until_command routine in infcmd.c.  Here
+   because it uses the mechanisms of breakpoints.  */
+
+/* This function is called by fetch_inferior_event via the
+   cmd_continuation pointer, to complete the until command. It takes
+   care of cleaning up the temporary breakpoints set up by the until
+   command. */
+static void
+until_break_command_continuation (struct continuation_arg *arg)
+{
+  struct cleanup *cleanups;
+
+  cleanups = (struct cleanup *) arg->data.pointer;
+  do_exec_cleanups (cleanups);
+}
+
+/* ARGSUSED */
+void
+until_break_command (char *arg, int from_tty)
+{
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  struct frame_info *prev_frame = get_prev_frame (selected_frame);
+  struct breakpoint *breakpoint;
+  struct cleanup *old_chain;
+  struct continuation_arg *arg1;
+
+
+  clear_proceed_status ();
+
+  /* Set a breakpoint where the user wants it and at return from
+     this function */
+
+  if (default_breakpoint_valid)
+    sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
+                         default_breakpoint_line, (char ***) NULL);
+  else
+    sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 
+                         0, (char ***) NULL);
+
+  if (sals.nelts != 1)
+    error ("Couldn't get information on specified line.");
+
+  sal = sals.sals[0];
+  xfree (sals.sals);   /* malloc'd, so freed */
+
+  if (*arg)
+    error ("Junk at end of arguments.");
+
+  resolve_sal_pc (&sal);
+
+  breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until);
+
+  if (!event_loop_p || !target_can_async_p ())
+    old_chain = make_cleanup_delete_breakpoint (breakpoint);
+  else
+    old_chain = make_exec_cleanup_delete_breakpoint (breakpoint);
+
+  /* If we are running asynchronously, and the target supports async
+     execution, we are not waiting for the target to stop, in the call
+     tp proceed, below. This means that we cannot delete the
+     brekpoints until the target has actually stopped. The only place
+     where we get a chance to do that is in fetch_inferior_event, so
+     we must set things up for that. */
+
+  if (event_loop_p && target_can_async_p ())
+    {
+      /* In this case the arg for the continuation is just the point
+         in the exec_cleanups chain from where to start doing
+         cleanups, because all the continuation does is the cleanups in
+         the exec_cleanup_chain. */
+      arg1 =
+       (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+      arg1->next         = NULL;
+      arg1->data.pointer = old_chain;
+
+      add_continuation (until_break_command_continuation, arg1);
+    }
+
+  /* Keep within the current frame */
+
+  if (prev_frame)
+    {
+      sal = find_pc_line (prev_frame->pc, 0);
+      sal.pc = prev_frame->pc;
+      breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until);
+      if (!event_loop_p || !target_can_async_p ())
+       make_cleanup_delete_breakpoint (breakpoint);
+      else
+       make_exec_cleanup_delete_breakpoint (breakpoint);
+    }
+
+  proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
+  /* Do the cleanups now, anly if we are not running asynchronously,
+     of if we are, but the target is still synchronous. */
+  if (!event_loop_p || !target_can_async_p ())
+    do_cleanups (old_chain);
+}
+\f
+#if 0
+/* These aren't used; I don't konw what they were for.  */
+/* Set a breakpoint at the catch clause for NAME.  */
+static int
+catch_breakpoint (char *name)
+{
+}
+
+static int
+disable_catch_breakpoint (void)
+{
+}
+
+static int
+delete_catch_breakpoint (void)
+{
+}
+
+static int
+enable_catch_breakpoint (void)
+{
+}
+#endif /* 0 */
+
+struct sal_chain
+{
+  struct sal_chain *next;
+  struct symtab_and_line sal;
+};
+
+#if 0
+/* Not really used -- invocation in handle_gnu_4_16_catch_command
+   had been commented out in the v.4.16 sources, and stays
+   disabled there now because "catch NAME" syntax isn't allowed.
+   pai/1997-07-11 */
+/* This isn't used; I don't know what it was for.  */
+/* For each catch clause identified in ARGS, run FUNCTION
+   with that clause as an argument.  */
+static struct symtabs_and_lines
+map_catch_names (char *args, int (*function) ())
+{
+  register char *p = args;
+  register char *p1;
+  struct symtabs_and_lines sals;
+#if 0
+  struct sal_chain *sal_chain = 0;
+#endif
+
+  if (p == 0)
+    error_no_arg ("one or more catch names");
+
+  sals.nelts = 0;
+  sals.sals = NULL;
+
+  while (*p)
+    {
+      p1 = p;
+      /* Don't swallow conditional part.  */
+      if (p1[0] == 'i' && p1[1] == 'f'
+         && (p1[2] == ' ' || p1[2] == '\t'))
+       break;
+
+      if (isalpha (*p1))
+       {
+         p1++;
+         while (isalnum (*p1) || *p1 == '_' || *p1 == '$')
+           p1++;
+       }
+
+      if (*p1 && *p1 != ' ' && *p1 != '\t')
+       error ("Arguments must be catch names.");
+
+      *p1 = 0;
+#if 0
+      if (function (p))
+       {
+         struct sal_chain *next = (struct sal_chain *)
+         alloca (sizeof (struct sal_chain));
+         next->next = sal_chain;
+         next->sal = get_catch_sal (p);
+         sal_chain = next;
+         goto win;
+       }
+#endif
+      printf_unfiltered ("No catch clause for exception %s.\n", p);
+#if 0
+    win:
+#endif
+      p = p1;
+      while (*p == ' ' || *p == '\t')
+       p++;
+    }
+}
+#endif
+
+/* This shares a lot of code with `print_frame_label_vars' from stack.c.  */
+
+static struct symtabs_and_lines
+get_catch_sals (int this_level_only)
+{
+  register struct blockvector *bl;
+  register struct block *block;
+  int index, have_default = 0;
+  CORE_ADDR pc;
+  struct symtabs_and_lines sals;
+  struct sal_chain *sal_chain = 0;
+  char *blocks_searched;
+
+  /* Not sure whether an error message is always the correct response,
+     but it's better than a core dump.  */
+  if (selected_frame == NULL)
+    error ("No selected frame.");
+  block = get_frame_block (selected_frame, 0);
+  pc = selected_frame->pc;
+
+  sals.nelts = 0;
+  sals.sals = NULL;
+
+  if (block == 0)
+    error ("No symbol table info available.\n");
+
+  bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
+  blocks_searched = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+  memset (blocks_searched, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+
+  while (block != 0)
+    {
+      CORE_ADDR end = BLOCK_END (block) - 4;
+      int last_index;
+
+      if (bl != blockvector_for_pc (end, &index))
+       error ("blockvector blotch");
+      if (BLOCKVECTOR_BLOCK (bl, index) != block)
+       error ("blockvector botch");
+      last_index = BLOCKVECTOR_NBLOCKS (bl);
+      index += 1;
+
+      /* Don't print out blocks that have gone by.  */
+      while (index < last_index
+            && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
+       index++;
+
+      while (index < last_index
+            && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
+       {
+         if (blocks_searched[index] == 0)
+           {
+             struct block *b = BLOCKVECTOR_BLOCK (bl, index);
+             register int i;
+             register struct symbol *sym;
+
+             ALL_BLOCK_SYMBOLS (b, i, sym)
+               {
+                 if (STREQ (SYMBOL_NAME (sym), "default"))
+                   {
+                     if (have_default)
+                       continue;
+                     have_default = 1;
+                   }
+                 if (SYMBOL_CLASS (sym) == LOC_LABEL)
+                   {
+                     struct sal_chain *next = (struct sal_chain *)
+                     alloca (sizeof (struct sal_chain));
+                     next->next = sal_chain;
+                     next->sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 
+                                               0);
+                     sal_chain = next;
+                   }
+               }
+             blocks_searched[index] = 1;
+           }
+         index++;
+       }
+      if (have_default)
+       break;
+      if (sal_chain && this_level_only)
+       break;
+
+      /* After handling the function's top-level block, stop.
+         Don't continue to its superblock, the block of
+         per-file symbols.  */
+      if (BLOCK_FUNCTION (block))
+       break;
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  if (sal_chain)
+    {
+      struct sal_chain *tmp_chain;
+
+      /* Count the number of entries.  */
+      for (index = 0, tmp_chain = sal_chain; tmp_chain;
+          tmp_chain = tmp_chain->next)
+       index++;
+
+      sals.nelts = index;
+      sals.sals = (struct symtab_and_line *)
+       xmalloc (index * sizeof (struct symtab_and_line));
+      for (index = 0; sal_chain; sal_chain = sal_chain->next, index++)
+       sals.sals[index] = sal_chain->sal;
+    }
+
+  return sals;
+}
+
+static void
+ep_skip_leading_whitespace (char **s)
+{
+  if ((s == NULL) || (*s == NULL))
+    return;
+  while (isspace (**s))
+    *s += 1;
+}
+
+/* This function examines a string, and attempts to find a token
+   that might be an event name in the leading characters.  If a
+   possible match is found, a pointer to the last character of
+   the token is returned.  Else, NULL is returned. */
+
+static char *
+ep_find_event_name_end (char *arg)
+{
+  char *s = arg;
+  char *event_name_end = NULL;
+
+  /* If we could depend upon the presense of strrpbrk, we'd use that... */
+  if (arg == NULL)
+    return NULL;
+
+  /* We break out of the loop when we find a token delimiter.
+     Basically, we're looking for alphanumerics and underscores;
+     anything else delimites the token. */
+  while (*s != '\0')
+    {
+      if (!isalnum (*s) && (*s != '_'))
+       break;
+      event_name_end = s;
+      s++;
+    }
+
+  return event_name_end;
+}
+
+
+/* This function attempts to parse an optional "if <cond>" clause
+   from the arg string.  If one is not found, it returns NULL.
+
+   Else, it returns a pointer to the condition string.  (It does not
+   attempt to evaluate the string against a particular block.)  And,
+   it updates arg to point to the first character following the parsed
+   if clause in the arg string. */
+
+static char *
+ep_parse_optional_if_clause (char **arg)
+{
+  char *cond_string;
+
+  if (((*arg)[0] != 'i') || ((*arg)[1] != 'f') || !isspace ((*arg)[2]))
+    return NULL;
+
+  /* Skip the "if" keyword. */
+  (*arg) += 2;
+
+  /* Skip any extra leading whitespace, and record the start of the
+     condition string. */
+  ep_skip_leading_whitespace (arg);
+  cond_string = *arg;
+
+  /* Assume that the condition occupies the remainder of the arg string. */
+  (*arg) += strlen (cond_string);
+
+  return cond_string;
+}
+
+/* This function attempts to parse an optional filename from the arg
+   string.  If one is not found, it returns NULL.
+
+   Else, it returns a pointer to the parsed filename.  (This function
+   makes no attempt to verify that a file of that name exists, or is
+   accessible.)  And, it updates arg to point to the first character
+   following the parsed filename in the arg string.
+
+   Note that clients needing to preserve the returned filename for
+   future access should copy it to their own buffers. */
+static char *
+ep_parse_optional_filename (char **arg)
+{
+  static char filename[1024];
+  char *arg_p = *arg;
+  int i;
+  char c;
+
+  if ((*arg_p == '\0') || isspace (*arg_p))
+    return NULL;
+
+  for (i = 0;; i++)
+    {
+      c = *arg_p;
+      if (isspace (c))
+       c = '\0';
+      filename[i] = c;
+      if (c == '\0')
+       break;
+      arg_p++;
+    }
+  *arg = arg_p;
+
+  return filename;
+}
+
+/* Commands to deal with catching events, such as signals, exceptions,
+   process start/exit, etc.  */
+
+typedef enum
+{
+  catch_fork, catch_vfork
+}
+catch_fork_kind;
+
+#if defined(CHILD_INSERT_FORK_CATCHPOINT) || defined(CHILD_INSERT_VFORK_CATCHPOINT)
+static void catch_fork_command_1 (catch_fork_kind fork_kind,
+                                 char *arg, int tempflag, int from_tty);
+
+static void
+catch_fork_command_1 (catch_fork_kind fork_kind, char *arg, int tempflag,
+                     int from_tty)
+{
+  char *cond_string = NULL;
+
+  ep_skip_leading_whitespace (&arg);
+
+  /* The allowed syntax is:
+     catch [v]fork
+     catch [v]fork if <cond>
+
+     First, check if there's an if clause. */
+  cond_string = ep_parse_optional_if_clause (&arg);
+
+  if ((*arg != '\0') && !isspace (*arg))
+    error ("Junk at end of arguments.");
+
+  /* If this target supports it, create a fork or vfork catchpoint
+     and enable reporting of such events. */
+  switch (fork_kind)
+    {
+    case catch_fork:
+      create_fork_event_catchpoint (tempflag, cond_string);
+      break;
+    case catch_vfork:
+      create_vfork_event_catchpoint (tempflag, cond_string);
+      break;
+    default:
+      error ("unsupported or unknown fork kind; cannot catch it");
+      break;
+    }
+}
+#endif
+
+#if defined(CHILD_INSERT_EXEC_CATCHPOINT)
+static void
+catch_exec_command_1 (char *arg, int tempflag, int from_tty)
+{
+  char *cond_string = NULL;
+
+  ep_skip_leading_whitespace (&arg);
+
+  /* The allowed syntax is:
+     catch exec
+     catch exec if <cond>
+
+     First, check if there's an if clause. */
+  cond_string = ep_parse_optional_if_clause (&arg);
+
+  if ((*arg != '\0') && !isspace (*arg))
+    error ("Junk at end of arguments.");
+
+  /* If this target supports it, create an exec catchpoint
+     and enable reporting of such events. */
+  create_exec_event_catchpoint (tempflag, cond_string);
+}
+#endif
+
+#if defined(SOLIB_ADD)
+static void
+catch_load_command_1 (char *arg, int tempflag, int from_tty)
+{
+  char *dll_pathname = NULL;
+  char *cond_string = NULL;
+
+  ep_skip_leading_whitespace (&arg);
+
+  /* The allowed syntax is:
+     catch load
+     catch load if <cond>
+     catch load <filename>
+     catch load <filename> if <cond>
+
+     The user is not allowed to specify the <filename> after an
+     if clause.
+
+     We'll ignore the pathological case of a file named "if".
+
+     First, check if there's an if clause.  If so, then there
+     cannot be a filename. */
+  cond_string = ep_parse_optional_if_clause (&arg);
+
+  /* If there was an if clause, then there cannot be a filename.
+     Else, there might be a filename and an if clause. */
+  if (cond_string == NULL)
+    {
+      dll_pathname = ep_parse_optional_filename (&arg);
+      ep_skip_leading_whitespace (&arg);
+      cond_string = ep_parse_optional_if_clause (&arg);
+    }
+
+  if ((*arg != '\0') && !isspace (*arg))
+    error ("Junk at end of arguments.");
+
+  /* Create a load breakpoint that only triggers when a load of
+     the specified dll (or any dll, if no pathname was specified)
+     occurs. */
+  SOLIB_CREATE_CATCH_LOAD_HOOK (PIDGET (inferior_ptid), tempflag, 
+                               dll_pathname, cond_string);
+}
+
+static void
+catch_unload_command_1 (char *arg, int tempflag, int from_tty)
+{
+  char *dll_pathname = NULL;
+  char *cond_string = NULL;
+
+  ep_skip_leading_whitespace (&arg);
+
+  /* The allowed syntax is:
+     catch unload
+     catch unload if <cond>
+     catch unload <filename>
+     catch unload <filename> if <cond>
+
+     The user is not allowed to specify the <filename> after an
+     if clause.
+
+     We'll ignore the pathological case of a file named "if".
+
+     First, check if there's an if clause.  If so, then there
+     cannot be a filename. */
+  cond_string = ep_parse_optional_if_clause (&arg);
+
+  /* If there was an if clause, then there cannot be a filename.
+     Else, there might be a filename and an if clause. */
+  if (cond_string == NULL)
+    {
+      dll_pathname = ep_parse_optional_filename (&arg);
+      ep_skip_leading_whitespace (&arg);
+      cond_string = ep_parse_optional_if_clause (&arg);
+    }
+
+  if ((*arg != '\0') && !isspace (*arg))
+    error ("Junk at end of arguments.");
+
+  /* Create an unload breakpoint that only triggers when an unload of
+     the specified dll (or any dll, if no pathname was specified)
+     occurs. */
+  SOLIB_CREATE_CATCH_UNLOAD_HOOK (PIDGET (inferior_ptid), tempflag, 
+                                 dll_pathname, cond_string);
+}
+#endif /* SOLIB_ADD */
+
+/* Commands to deal with catching exceptions.  */
+
+/* Set a breakpoint at the specified callback routine for an
+   exception event callback */
+
+static void
+create_exception_catchpoint (int tempflag, char *cond_string,
+                            enum exception_event_kind ex_event,
+                            struct symtab_and_line *sal)
+{
+  struct breakpoint *b;
+  int thread = -1;             /* All threads. */
+  enum bptype bptype;
+
+  if (!sal)                    /* no exception support? */
+    return;
+
+  switch (ex_event)
+    {
+    case EX_EVENT_THROW:
+      bptype = bp_catch_throw;
+      break;
+    case EX_EVENT_CATCH:
+      bptype = bp_catch_catch;
+      break;
+    default:                   /* error condition */
+      error ("Internal error -- invalid catchpoint kind");
+    }
+
+  b = set_raw_breakpoint (*sal, bptype);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->cond = NULL;
+  b->cond_string = (cond_string == NULL) ? 
+    NULL : savestring (cond_string, strlen (cond_string));
+  b->thread = thread;
+  b->addr_string = NULL;
+  b->enable_state = bp_enabled;
+  b->disposition = tempflag ? disp_del : disp_donttouch;
+  mention (b);
+}
+
+/* Deal with "catch catch" and "catch throw" commands */
+
+static void
+catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
+                          int tempflag, int from_tty)
+{
+  char *cond_string = NULL;
+  struct symtab_and_line *sal = NULL;
+
+  ep_skip_leading_whitespace (&arg);
+
+  cond_string = ep_parse_optional_if_clause (&arg);
+
+  if ((*arg != '\0') && !isspace (*arg))
+    error ("Junk at end of arguments.");
+
+  if ((ex_event != EX_EVENT_THROW) &&
+      (ex_event != EX_EVENT_CATCH))
+    error ("Unsupported or unknown exception event; cannot catch it");
+
+  /* See if we can find a callback routine */
+  sal = target_enable_exception_callback (ex_event, 1);
+
+  if (sal)
+    {
+      /* We have callbacks from the runtime system for exceptions.
+         Set a breakpoint on the sal found, if no errors */
+      if (sal != (struct symtab_and_line *) -1)
+       create_exception_catchpoint (tempflag, cond_string, ex_event, sal);
+      else
+       return;         /* something went wrong with setting up callbacks */
+    }
+  else
+    {
+      /* No callbacks from runtime system for exceptions.
+         Try GNU C++ exception breakpoints using labels in debug info. */
+      if (ex_event == EX_EVENT_CATCH)
+       {
+         handle_gnu_4_16_catch_command (arg, tempflag, from_tty);
+       }
+      else if (ex_event == EX_EVENT_THROW)
+       {
+         /* Set a breakpoint on __raise_exception () */
+
+         warning ("Unsupported with this platform/compiler combination.");
+         warning ("Perhaps you can achieve the effect you want by setting");
+         warning ("a breakpoint on __raise_exception().");
+       }
+    }
+}
+
+/* Cover routine to allow wrapping target_enable_exception_catchpoints
+   inside a catch_errors */
+
+static int
+cover_target_enable_exception_callback (PTR arg)
+{
+  args_for_catchpoint_enable *args = arg;
+  struct symtab_and_line *sal;
+  sal = target_enable_exception_callback (args->kind, args->enable_p);
+  if (sal == NULL)
+    return 0;
+  else if (sal == (struct symtab_and_line *) -1)
+    return -1;
+  else
+    return 1;                  /*is valid */
+}
+
+
+
+/* This is the original v.4.16 and earlier version of the
+   catch_command_1() function.  Now that other flavours of "catch"
+   have been introduced, and since exception handling can be handled
+   in other ways (through target ops) also, this is used only for the
+   GNU C++ exception handling system.
+   Note: Only the "catch" flavour of GDB 4.16 is handled here.  The
+   "catch NAME" is now no longer allowed in catch_command_1().  Also,
+   there was no code in GDB 4.16 for "catch throw". 
+
+   Called from catch_exception_command_1 () */
+
+
+static void
+handle_gnu_4_16_catch_command (char *arg, int tempflag, int from_tty)
+{
+  /* First, translate ARG into something we can deal with in terms
+     of breakpoints.  */
+
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  register struct expression *cond = 0;
+  register struct breakpoint *b;
+  char *save_arg;
+  int i;
+
+  INIT_SAL (&sal);             /* initialize to zeroes */
+
+  /* If no arg given, or if first arg is 'if ', all active catch clauses
+     are breakpointed. */
+
+  if (!arg || (arg[0] == 'i' && arg[1] == 'f'
+              && (arg[2] == ' ' || arg[2] == '\t')))
+    {
+      /* Grab all active catch clauses.  */
+      sals = get_catch_sals (0);
+    }
+  else
+    {
+      /* Grab selected catch clauses.  */
+      error ("catch NAME not implemented");
+
+#if 0
+      /* Not sure why this code has been disabled. I'm leaving
+         it disabled.  We can never come here now anyway
+         since we don't allow the "catch NAME" syntax.
+         pai/1997-07-11 */
+
+      /* This isn't used; I don't know what it was for.  */
+      sals = map_catch_names (arg, catch_breakpoint);
+#endif
+    }
+
+  if (!sals.nelts)
+    return;
+
+  save_arg = arg;
+  for (i = 0; i < sals.nelts; i++)
+    {
+      resolve_sal_pc (&sals.sals[i]);
+
+      while (arg && *arg)
+       {
+         if (arg[0] == 'i' && arg[1] == 'f'
+             && (arg[2] == ' ' || arg[2] == '\t'))
+           cond = parse_exp_1 ((arg += 2, &arg),
+                               block_for_pc (sals.sals[i].pc), 0);
+         else
+           error ("Junk at end of arguments.");
+       }
+      arg = save_arg;
+    }
+
+  for (i = 0; i < sals.nelts; i++)
+    {
+      sal = sals.sals[i];
+
+      if (from_tty)
+       describe_other_breakpoints (sal.pc, sal.section);
+
+      /* Important -- this is an ordinary breakpoint.  For platforms
+        with callback support for exceptions,
+        create_exception_catchpoint() will create special bp types
+        (bp_catch_catch and bp_catch_throw), and there is code in
+        insert_breakpoints() and elsewhere that depends on that. */
+      b = set_raw_breakpoint (sal, bp_breakpoint);
+      set_breakpoint_count (breakpoint_count + 1);
+      b->number = breakpoint_count;
+
+      b->cond = cond;
+      b->enable_state = bp_enabled;
+      b->disposition = tempflag ? disp_del : disp_donttouch;
+
+      mention (b);
+    }
+
+  if (sals.nelts > 1)
+    {
+      warning ("Multiple breakpoints were set.");
+      warning ("Use the \"delete\" command to delete unwanted breakpoints.");
+    }
+  xfree (sals.sals);
+}
+
+static void
+catch_command_1 (char *arg, int tempflag, int from_tty)
+{
+
+  /* The first argument may be an event name, such as "start" or "load".
+     If so, then handle it as such.  If it doesn't match an event name,
+     then attempt to interpret it as an exception name.  (This latter is
+     the v4.16-and-earlier GDB meaning of the "catch" command.)
+
+     First, try to find the bounds of what might be an event name. */
+  char *arg1_start = arg;
+  char *arg1_end;
+  int arg1_length;
+
+  if (arg1_start == NULL)
+    {
+      /* Old behaviour was to use pre-v-4.16 syntax */
+      /* catch_throw_command_1 (arg1_start, tempflag, from_tty); */
+      /* return; */
+      /* Now, this is not allowed */
+      error ("Catch requires an event name.");
+
+    }
+  arg1_end = ep_find_event_name_end (arg1_start);
+  if (arg1_end == NULL)
+    error ("catch requires an event");
+  arg1_length = arg1_end + 1 - arg1_start;
+
+  /* Try to match what we found against known event names. */
+  if (strncmp (arg1_start, "signal", arg1_length) == 0)
+    {
+      error ("Catch of signal not yet implemented");
+    }
+  else if (strncmp (arg1_start, "catch", arg1_length) == 0)
+    {
+      catch_exception_command_1 (EX_EVENT_CATCH, arg1_end + 1, 
+                                tempflag, from_tty);
+    }
+  else if (strncmp (arg1_start, "throw", arg1_length) == 0)
+    {
+      catch_exception_command_1 (EX_EVENT_THROW, arg1_end + 1, 
+                                tempflag, from_tty);
+    }
+  else if (strncmp (arg1_start, "thread_start", arg1_length) == 0)
+    {
+      error ("Catch of thread_start not yet implemented");
+    }
+  else if (strncmp (arg1_start, "thread_exit", arg1_length) == 0)
+    {
+      error ("Catch of thread_exit not yet implemented");
+    }
+  else if (strncmp (arg1_start, "thread_join", arg1_length) == 0)
+    {
+      error ("Catch of thread_join not yet implemented");
+    }
+  else if (strncmp (arg1_start, "start", arg1_length) == 0)
+    {
+      error ("Catch of start not yet implemented");
+    }
+  else if (strncmp (arg1_start, "exit", arg1_length) == 0)
+    {
+      error ("Catch of exit not yet implemented");
+    }
+  else if (strncmp (arg1_start, "fork", arg1_length) == 0)
+    {
+#if defined(CHILD_INSERT_FORK_CATCHPOINT)
+      catch_fork_command_1 (catch_fork, arg1_end + 1, tempflag, from_tty);
+#else
+      error ("Catch of fork not yet implemented");
+#endif
+    }
+  else if (strncmp (arg1_start, "vfork", arg1_length) == 0)
+    {
+#if defined(CHILD_INSERT_VFORK_CATCHPOINT)
+      catch_fork_command_1 (catch_vfork, arg1_end + 1, tempflag, from_tty);
+#else
+      error ("Catch of vfork not yet implemented");
+#endif
+    }
+  else if (strncmp (arg1_start, "exec", arg1_length) == 0)
+    {
+#if defined(CHILD_INSERT_EXEC_CATCHPOINT)
+      catch_exec_command_1 (arg1_end + 1, tempflag, from_tty);
+#else
+      error ("Catch of exec not yet implemented");
+#endif
+    }
+  else if (strncmp (arg1_start, "load", arg1_length) == 0)
+    {
+#if defined(SOLIB_ADD)
+      catch_load_command_1 (arg1_end + 1, tempflag, from_tty);
+#else
+      error ("Catch of load not implemented");
+#endif
+    }
+  else if (strncmp (arg1_start, "unload", arg1_length) == 0)
+    {
+#if defined(SOLIB_ADD)
+      catch_unload_command_1 (arg1_end + 1, tempflag, from_tty);
+#else
+      error ("Catch of load not implemented");
+#endif
+    }
+  else if (strncmp (arg1_start, "stop", arg1_length) == 0)
+    {
+      error ("Catch of stop not yet implemented");
+    }
+
+  /* This doesn't appear to be an event name */
+
+  else
+    {
+      /* Pre-v.4.16 behaviour was to treat the argument
+         as the name of an exception */
+      /* catch_throw_command_1 (arg1_start, tempflag, from_tty); */
+      /* Now this is not allowed */
+      error ("Unknown event kind specified for catch");
+
+    }
+}
+
+/* Used by the gui, could be made a worker for other things. */
+
+struct breakpoint *
+set_breakpoint_sal (struct symtab_and_line sal)
+{
+  struct breakpoint *b;
+  b = set_raw_breakpoint (sal, bp_breakpoint);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->cond = 0;
+  b->thread = -1;
+  return b;
+}
+
+#if 0
+/* These aren't used; I don't know what they were for.  */
+/* Disable breakpoints on all catch clauses described in ARGS.  */
+static void
+disable_catch (char *args)
+{
+  /* Map the disable command to catch clauses described in ARGS.  */
+}
+
+/* Enable breakpoints on all catch clauses described in ARGS.  */
+static void
+enable_catch (char *args)
+{
+  /* Map the disable command to catch clauses described in ARGS.  */
+}
+
+/* Delete breakpoints on all catch clauses in the active scope.  */
+static void
+delete_catch (char *args)
+{
+  /* Map the delete command to catch clauses described in ARGS.  */
+}
+#endif /* 0 */
+
+static void
+catch_command (char *arg, int from_tty)
+{
+  catch_command_1 (arg, 0, from_tty);
+}
+\f
+
+static void
+tcatch_command (char *arg, int from_tty)
+{
+  catch_command_1 (arg, 1, from_tty);
+}
+
+/* Delete breakpoints by address or line.  */
+
+static void
+clear_command (char *arg, int from_tty)
+{
+  struct breakpoint *b, *tmp, *prev, *found;
+  int default_match;
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  int i;
+
+  if (arg)
+    {
+      sals = decode_line_spec (arg, 1);
+      default_match = 0;
+    }
+  else
+    {
+      sals.sals = (struct symtab_and_line *)
+       xmalloc (sizeof (struct symtab_and_line));
+      make_cleanup (xfree, sals.sals);
+      INIT_SAL (&sal);         /* initialize to zeroes */
+      sal.line = default_breakpoint_line;
+      sal.symtab = default_breakpoint_symtab;
+      sal.pc = default_breakpoint_address;
+      if (sal.symtab == 0)
+       error ("No source file specified.");
+
+      sals.sals[0] = sal;
+      sals.nelts = 1;
+
+      default_match = 1;
+    }
+
+  /* For each line spec given, delete bps which correspond
+     to it.  Do it in two passes, solely to preserve the current
+     behavior that from_tty is forced true if we delete more than
+     one breakpoint.  */
+
+  found = NULL;
+  for (i = 0; i < sals.nelts; i++)
+    {
+      /* If exact pc given, clear bpts at that pc.
+         If line given (pc == 0), clear all bpts on specified line.
+         If defaulting, clear all bpts on default line
+         or at default pc.
+
+         defaulting    sal.pc != 0    tests to do
+
+         0              1             pc
+         1              1             pc _and_ line
+         0              0             line
+         1              0             <can't happen> */
+
+      sal = sals.sals[i];
+      prev = NULL;
+
+      /* Find all matching breakpoints, remove them from the
+        breakpoint chain, and add them to the 'found' chain.  */
+      ALL_BREAKPOINTS_SAFE (b, tmp)
+       {
+         /* Are we going to delete b? */
+         if (b->type != bp_none
+             && b->type != bp_watchpoint
+             && b->type != bp_hardware_watchpoint
+             && b->type != bp_read_watchpoint
+             && b->type != bp_access_watchpoint
+             /* Not if b is a watchpoint of any sort... */
+             && (((sal.pc && (b->address == sal.pc)) 
+                  && (!section_is_overlay (b->section)
+                      || b->section == sal.section))
+                 /* Yes, if sal.pc matches b (modulo overlays).  */
+                 || ((default_match || (0 == sal.pc))
+                     && b->source_file != NULL
+                     && sal.symtab != NULL
+                     && STREQ (b->source_file, sal.symtab->filename)
+                     && b->line_number == sal.line)))
+           /* Yes, if sal source file and line matches b.  */
+           {
+             /* Remove it from breakpoint_chain...  */
+             if (b == breakpoint_chain)
+               {
+                 /* b is at the head of the list */
+                 breakpoint_chain = b->next;
+               }
+             else
+               {
+                 prev->next = b->next;
+               }
+             /* And add it to 'found' chain.  */
+             b->next = found;
+             found = b;
+           }
+         else
+           {
+             /* Keep b, and keep a pointer to it.  */
+             prev = b;
+           }
+       }
+    }
+  /* Now go thru the 'found' chain and delete them.  */
+  if (found == 0)
+    {
+      if (arg)
+       error ("No breakpoint at %s.", arg);
+      else
+       error ("No breakpoint at this line.");
+    }
+
+  if (found->next)
+    from_tty = 1;              /* Always report if deleted more than one */
+  if (from_tty)
+    printf_unfiltered ("Deleted breakpoint%s ", found->next ? "s" : "");
+  breakpoints_changed ();
+  while (found)
+    {
+      if (from_tty)
+       printf_unfiltered ("%d ", found->number);
+      tmp = found->next;
+      delete_breakpoint (found);
+      found = tmp;
+    }
+  if (from_tty)
+    putchar_unfiltered ('\n');
+}
+\f
+/* Delete breakpoint in BS if they are `delete' breakpoints and
+   all breakpoints that are marked for deletion, whether hit or not.
+   This is called after any breakpoint is hit, or after errors.  */
+
+void
+breakpoint_auto_delete (bpstat bs)
+{
+  struct breakpoint *b, *temp;
+
+  for (; bs; bs = bs->next)
+    if (bs->breakpoint_at && bs->breakpoint_at->disposition == disp_del
+       && bs->stop)
+      delete_breakpoint (bs->breakpoint_at);
+
+  ALL_BREAKPOINTS_SAFE (b, temp)
+  {
+    if (b->disposition == disp_del_at_next_stop)
+      delete_breakpoint (b);
+  }
+}
+
+/* Delete a breakpoint and clean up all traces of it in the data
+   structures. */
+
+void
+delete_breakpoint (struct breakpoint *bpt)
+{
+  register struct breakpoint *b;
+  register bpstat bs;
+
+  if (bpt == NULL)
+    error ("Internal error (attempted to delete a NULL breakpoint)");
+
+
+  /* Has this bp already been deleted?  This can happen because multiple
+     lists can hold pointers to bp's.  bpstat lists are especial culprits.
+
+     One example of this happening is a watchpoint's scope bp.  When the
+     scope bp triggers, we notice that the watchpoint is out of scope, and
+     delete it.  We also delete its scope bp.  But the scope bp is marked
+     "auto-deleting", and is already on a bpstat.  That bpstat is then
+     checked for auto-deleting bp's, which are deleted.
+
+     A real solution to this problem might involve reference counts in bp's,
+     and/or giving them pointers back to their referencing bpstat's, and
+     teaching delete_breakpoint to only free a bp's storage when no more
+     references were extent.  A cheaper bandaid was chosen. */
+  if (bpt->type == bp_none)
+    return;
+
+  if (delete_breakpoint_hook)
+    delete_breakpoint_hook (bpt);
+  breakpoint_delete_event (bpt->number);
+
+  if (bpt->inserted)
+    remove_breakpoint (bpt, mark_inserted);
+
+  if (breakpoint_chain == bpt)
+    breakpoint_chain = bpt->next;
+
+  /* If we have callback-style exception catchpoints, don't go through
+     the adjustments to the C++ runtime library etc. if the inferior
+     isn't actually running.  target_enable_exception_callback for a
+     null target ops vector gives an undesirable error message, so we
+     check here and avoid it. Since currently (1997-09-17) only HP-UX aCC's
+     exceptions are supported in this way, it's OK for now. FIXME */
+  if (ep_is_exception_catchpoint (bpt) && target_has_execution)
+    {
+      static char message1[] = "Error in deleting catchpoint %d:\n";
+      static char message[sizeof (message1) + 30];
+      args_for_catchpoint_enable args;
+
+      /* Format possible error msg */
+      sprintf (message, message1, bpt->number);
+      args.kind = bpt->type == bp_catch_catch ? 
+       EX_EVENT_CATCH : EX_EVENT_THROW;
+      args.enable_p = 0;
+      catch_errors (cover_target_enable_exception_callback, &args,
+                   message, RETURN_MASK_ALL);
+    }
+
+
+  ALL_BREAKPOINTS (b)
+    if (b->next == bpt)
+    {
+      b->next = bpt->next;
+      break;
+    }
+
+  check_duplicates (bpt);
+  /* If this breakpoint was inserted, and there is another breakpoint
+     at the same address, we need to insert the other breakpoint.  */
+  if (bpt->inserted
+      && bpt->type != bp_hardware_watchpoint
+      && bpt->type != bp_read_watchpoint
+      && bpt->type != bp_access_watchpoint
+      && bpt->type != bp_catch_fork
+      && bpt->type != bp_catch_vfork
+      && bpt->type != bp_catch_exec)
+    {
+      ALL_BREAKPOINTS (b)
+       if (b->address == bpt->address
+           && b->section == bpt->section
+           && !b->duplicate
+           && b->enable_state != bp_disabled
+           && b->enable_state != bp_shlib_disabled
+           && b->enable_state != bp_call_disabled)
+       {
+         int val;
+
+         /* We should never reach this point if there is a permanent
+            breakpoint at the same address as the one being deleted.
+            If there is a permanent breakpoint somewhere, it should
+            always be the only one inserted.  */
+         if (b->enable_state == bp_permanent)
+           internal_error (__FILE__, __LINE__,
+                           "another breakpoint was inserted on top of "
+                           "a permanent breakpoint");
+
+         if (b->type == bp_hardware_breakpoint)
+           val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
+         else
+           val = target_insert_breakpoint (b->address, b->shadow_contents);
+
+         /* If there was an error in the insert, print a message, then stop execution.  */
+         if (val != 0)
+           {
+             struct ui_file *tmp_error_stream = mem_fileopen ();
+             make_cleanup_ui_file_delete (tmp_error_stream);
+            
+
+             if (b->type == bp_hardware_breakpoint)
+               {
+                 fprintf_unfiltered (tmp_error_stream, 
+                                       "Cannot insert hardware breakpoint %d.\n"
+                                     "You may have requested too many hardware breakpoints.\n",
+                                       b->number);
+                 }
+               else
+                 {
+                   fprintf_unfiltered (tmp_error_stream, "Cannot insert breakpoint %d.\n", b->number);
+                   fprintf_filtered (tmp_error_stream, "Error accessing memory address ");
+                   print_address_numeric (b->address, 1, tmp_error_stream);
+                   fprintf_filtered (tmp_error_stream, ": %s.\n",
+                                     safe_strerror (val));
+                 }
+             
+             fprintf_unfiltered (tmp_error_stream,"The same program may be running in another process.");
+             target_terminal_ours_for_output ();
+             error_stream(tmp_error_stream); 
+           }
+         else
+           b->inserted = 1;
+       }
+    }
+
+  free_command_lines (&bpt->commands);
+  if (bpt->cond)
+    xfree (bpt->cond);
+  if (bpt->cond_string != NULL)
+    xfree (bpt->cond_string);
+  if (bpt->addr_string != NULL)
+    xfree (bpt->addr_string);
+  if (bpt->exp != NULL)
+    xfree (bpt->exp);
+  if (bpt->exp_string != NULL)
+    xfree (bpt->exp_string);
+  if (bpt->val != NULL)
+    value_free (bpt->val);
+  if (bpt->source_file != NULL)
+    xfree (bpt->source_file);
+  if (bpt->dll_pathname != NULL)
+    xfree (bpt->dll_pathname);
+  if (bpt->triggered_dll_pathname != NULL)
+    xfree (bpt->triggered_dll_pathname);
+  if (bpt->exec_pathname != NULL)
+    xfree (bpt->exec_pathname);
+
+  /* Be sure no bpstat's are pointing at it after it's been freed.  */
+  /* FIXME, how can we find all bpstat's?
+     We just check stop_bpstat for now.  */
+  for (bs = stop_bpstat; bs; bs = bs->next)
+    if (bs->breakpoint_at == bpt)
+      {
+       bs->breakpoint_at = NULL;
+       bs->old_val = NULL;
+       /* bs->commands will be freed later.  */
+      }
+  /* On the chance that someone will soon try again to delete this same
+     bp, we mark it as deleted before freeing its storage. */
+  bpt->type = bp_none;
+
+  xfree (bpt);
+}
+
+static void
+do_delete_breakpoint_cleanup (void *b)
+{
+  delete_breakpoint (b);
+}
+
+struct cleanup *
+make_cleanup_delete_breakpoint (struct breakpoint *b)
+{
+  return make_cleanup (do_delete_breakpoint_cleanup, b);
+}
+
+struct cleanup *
+make_exec_cleanup_delete_breakpoint (struct breakpoint *b)
+{
+  return make_exec_cleanup (do_delete_breakpoint_cleanup, b);
+}
+
+void
+delete_command (char *arg, int from_tty)
+{
+  struct breakpoint *b, *temp;
+
+  dont_repeat ();
+
+  if (arg == 0)
+    {
+      int breaks_to_delete = 0;
+
+      /* Delete all breakpoints if no argument.
+         Do not delete internal or call-dummy breakpoints, these
+         have to be deleted with an explicit breakpoint number argument.  */
+      ALL_BREAKPOINTS (b)
+      {
+       if (b->type != bp_call_dummy &&
+           b->type != bp_shlib_event &&
+           b->type != bp_thread_event &&
+           b->type != bp_overlay_event &&
+           b->number >= 0)
+         breaks_to_delete = 1;
+      }
+
+      /* Ask user only if there are some breakpoints to delete.  */
+      if (!from_tty
+         || (breaks_to_delete && query ("Delete all breakpoints? ")))
+       {
+         ALL_BREAKPOINTS_SAFE (b, temp)
+         {
+           if (b->type != bp_call_dummy &&
+               b->type != bp_shlib_event &&
+               b->type != bp_thread_event &&
+               b->type != bp_overlay_event &&
+               b->number >= 0)
+             delete_breakpoint (b);
+         }
+       }
+    }
+  else
+    map_breakpoint_numbers (arg, delete_breakpoint);
+}
+
+/* Reset a breakpoint given it's struct breakpoint * BINT.
+   The value we return ends up being the return value from catch_errors.
+   Unused in this case.  */
+
+static int
+breakpoint_re_set_one (PTR bint)
+{
+  /* get past catch_errs */
+  struct breakpoint *b = (struct breakpoint *) bint;
+  struct value *mark;
+  int i;
+  struct symtabs_and_lines sals;
+  char *s;
+  enum enable_state save_enable;
+
+  switch (b->type)
+    {
+    case bp_none:
+      warning ("attempted to reset apparently deleted breakpoint #%d?",
+              b->number);
+      return 0;
+    case bp_breakpoint:
+    case bp_hardware_breakpoint:
+    case bp_catch_load:
+    case bp_catch_unload:
+      if (b->addr_string == NULL)
+       {
+         /* Anything without a string can't be re-set. */
+         delete_breakpoint (b);
+         return 0;
+       }
+      /* HACK: cagney/2001-11-11: kettenis/2001-11-11: MarkK wrote:
+
+        ``And a hack it is, although Apple's Darwin version of GDB
+        contains an almost identical hack to implement a "future
+        break" command.  It seems to work in many real world cases,
+        but it is easy to come up with a test case where the patch
+        doesn't help at all.''
+
+        ``It seems that the way GDB implements breakpoints - in -
+        shared - libraries was designed for a.out shared library
+        systems (SunOS 4) where shared libraries were loaded at a
+        fixed address in memory.  Since ELF shared libraries can (and
+        will) be loaded at any address in memory, things break.
+        Fixing this is not trivial.  Therefore, I'm not sure whether
+        we should add this hack to the branch only.  I cannot
+        guarantee that things will be fixed on the trunk in the near
+        future.''
+
+         In case we have a problem, disable this breakpoint.  We'll
+         restore its status if we succeed.  Don't disable a
+         shlib_disabled breakpoint though.  There's a fair chance we
+         can't re-set it if the shared library it's in hasn't been
+         loaded yet.  */
+      save_enable = b->enable_state;
+      if (b->enable_state != bp_shlib_disabled)
+        b->enable_state = bp_disabled;
+
+      set_language (b->language);
+      input_radix = b->input_radix;
+      s = b->addr_string;
+      sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL);
+      for (i = 0; i < sals.nelts; i++)
+       {
+         resolve_sal_pc (&sals.sals[i]);
+
+         /* Reparse conditions, they might contain references to the
+            old symtab.  */
+         if (b->cond_string != NULL)
+           {
+             s = b->cond_string;
+             if (b->cond)
+               xfree (b->cond);
+             b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0);
+           }
+
+         /* We need to re-set the breakpoint if the address changes... */
+         if (b->address != sals.sals[i].pc
+         /* ...or new and old breakpoints both have source files, and
+            the source file name or the line number changes...  */
+             || (b->source_file != NULL
+                 && sals.sals[i].symtab != NULL
+                 && (!STREQ (b->source_file, sals.sals[i].symtab->filename)
+                     || b->line_number != sals.sals[i].line)
+             )
+         /* ...or we switch between having a source file and not having
+            one.  */
+             || ((b->source_file == NULL) != (sals.sals[i].symtab == NULL))
+           )
+           {
+             if (b->source_file != NULL)
+               xfree (b->source_file);
+             if (sals.sals[i].symtab == NULL)
+               b->source_file = NULL;
+             else
+               b->source_file =
+                 savestring (sals.sals[i].symtab->filename,
+                             strlen (sals.sals[i].symtab->filename));
+             b->line_number = sals.sals[i].line;
+             b->address = sals.sals[i].pc;
+
+             /* Used to check for duplicates here, but that can
+                cause trouble, as it doesn't check for disabled
+                breakpoints. */
+
+             mention (b);
+
+             /* Might be better to do this just once per breakpoint_re_set,
+                rather than once for every breakpoint.  */
+             breakpoints_changed ();
+           }
+         b->section = sals.sals[i].section;
+         b->enable_state = save_enable;        /* Restore it, this worked. */
+
+
+         /* Now that this is re-enabled, check_duplicates
+            can be used. */
+         check_duplicates (b);
+
+       }
+      xfree (sals.sals);
+      break;
+
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+    case bp_read_watchpoint:
+    case bp_access_watchpoint:
+      innermost_block = NULL;
+      /* The issue arises of what context to evaluate this in.  The
+         same one as when it was set, but what does that mean when
+         symbols have been re-read?  We could save the filename and
+         functionname, but if the context is more local than that, the
+         best we could do would be something like how many levels deep
+         and which index at that particular level, but that's going to
+         be less stable than filenames or function names.  */
+
+      /* So for now, just use a global context.  */
+      if (b->exp)
+       xfree (b->exp);
+      b->exp = parse_expression (b->exp_string);
+      b->exp_valid_block = innermost_block;
+      mark = value_mark ();
+      if (b->val)
+       value_free (b->val);
+      b->val = evaluate_expression (b->exp);
+      release_value (b->val);
+      if (VALUE_LAZY (b->val))
+       value_fetch_lazy (b->val);
+
+      if (b->cond_string != NULL)
+       {
+         s = b->cond_string;
+         if (b->cond)
+           xfree (b->cond);
+         b->cond = parse_exp_1 (&s, (struct block *) 0, 0);
+       }
+      if (b->enable_state == bp_enabled)
+       mention (b);
+      value_free_to_mark (mark);
+      break;
+    case bp_catch_catch:
+    case bp_catch_throw:
+      break;
+      /* We needn't really do anything to reset these, since the mask
+         that requests them is unaffected by e.g., new libraries being
+         loaded. */
+    case bp_catch_fork:
+    case bp_catch_vfork:
+    case bp_catch_exec:
+      break;
+
+    default:
+      printf_filtered ("Deleting unknown breakpoint type %d\n", b->type);
+      /* fall through */
+      /* Delete longjmp and overlay event breakpoints; they will be
+         reset later by breakpoint_re_set.  */
+    case bp_longjmp:
+    case bp_longjmp_resume:
+    case bp_overlay_event:
+      delete_breakpoint (b);
+      break;
+
+      /* This breakpoint is special, it's set up when the inferior
+         starts and we really don't want to touch it.  */
+    case bp_shlib_event:
+
+      /* Like bp_shlib_event, this breakpoint type is special.
+        Once it is set up, we do not want to touch it.  */
+    case bp_thread_event:
+
+      /* Keep temporary breakpoints, which can be encountered when we step
+         over a dlopen call and SOLIB_ADD is resetting the breakpoints.
+         Otherwise these should have been blown away via the cleanup chain
+         or by breakpoint_init_inferior when we rerun the executable.  */
+    case bp_until:
+    case bp_finish:
+    case bp_watchpoint_scope:
+    case bp_call_dummy:
+    case bp_step_resume:
+      break;
+    }
+
+  return 0;
+}
+
+/* Re-set all breakpoints after symbols have been re-loaded.  */
+void
+breakpoint_re_set (void)
+{
+  struct breakpoint *b, *temp;
+  enum language save_language;
+  int save_input_radix;
+  static char message1[] = "Error in re-setting breakpoint %d:\n";
+  char message[sizeof (message1) + 30 /* slop */ ];
+
+  save_language = current_language->la_language;
+  save_input_radix = input_radix;
+  ALL_BREAKPOINTS_SAFE (b, temp)
+  {
+    /* Format possible error msg */
+    sprintf (message, message1, b->number);
+    catch_errors (breakpoint_re_set_one, b, message, RETURN_MASK_ALL);
+  }
+  set_language (save_language);
+  input_radix = save_input_radix;
+
+  if (GET_LONGJMP_TARGET_P ())
+    {
+      create_longjmp_breakpoint ("longjmp");
+      create_longjmp_breakpoint ("_longjmp");
+      create_longjmp_breakpoint ("siglongjmp");
+      create_longjmp_breakpoint ("_siglongjmp");
+      create_longjmp_breakpoint (NULL);
+    }
+  
+  create_overlay_event_breakpoint ("_ovly_debug_event");
+}
+\f
+/* Reset the thread number of this breakpoint:
+
+   - If the breakpoint is for all threads, leave it as-is.
+   - Else, reset it to the current thread for inferior_ptid. */
+void
+breakpoint_re_set_thread (struct breakpoint *b)
+{
+  if (b->thread != -1)
+    {
+      if (in_thread_list (inferior_ptid))
+       b->thread = pid_to_thread_id (inferior_ptid);
+    }
+}
+
+/* Set ignore-count of breakpoint number BPTNUM to COUNT.
+   If from_tty is nonzero, it prints a message to that effect,
+   which ends with a period (no newline).  */
+
+void
+set_ignore_count (int bptnum, int count, int from_tty)
+{
+  register struct breakpoint *b;
+
+  if (count < 0)
+    count = 0;
+
+  ALL_BREAKPOINTS (b)
+    if (b->number == bptnum)
+    {
+      b->ignore_count = count;
+      if (from_tty)
+       {
+         if (count == 0)
+           printf_filtered ("Will stop next time breakpoint %d is reached.",
+                            bptnum);
+         else if (count == 1)
+           printf_filtered ("Will ignore next crossing of breakpoint %d.",
+                            bptnum);
+         else
+           printf_filtered ("Will ignore next %d crossings of breakpoint %d.",
+                            count, bptnum);
+       }
+      breakpoints_changed ();
+      breakpoint_modify_event (b->number);
+      return;
+    }
+
+  error ("No breakpoint number %d.", bptnum);
+}
+
+/* Clear the ignore counts of all breakpoints.  */
+void
+breakpoint_clear_ignore_counts (void)
+{
+  struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    b->ignore_count = 0;
+}
+
+/* Command to set ignore-count of breakpoint N to COUNT.  */
+
+static void
+ignore_command (char *args, int from_tty)
+{
+  char *p = args;
+  register int num;
+
+  if (p == 0)
+    error_no_arg ("a breakpoint number");
+
+  num = get_number (&p);
+  if (num == 0)
+    error ("bad breakpoint number: '%s'", args);
+  if (*p == 0)
+    error ("Second argument (specified ignore-count) is missing.");
+
+  set_ignore_count (num,
+                   longest_to_int (value_as_long (parse_and_eval (p))),
+                   from_tty);
+  if (from_tty)
+    printf_filtered ("\n");
+}
+\f
+/* Call FUNCTION on each of the breakpoints
+   whose numbers are given in ARGS.  */
+
+static void
+map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
+{
+  register char *p = args;
+  char *p1;
+  register int num;
+  register struct breakpoint *b, *tmp;
+  int match;
+
+  if (p == 0)
+    error_no_arg ("one or more breakpoint numbers");
+
+  while (*p)
+    {
+      match = 0;
+      p1 = p;
+
+      num = get_number_or_range (&p1);
+      if (num == 0)
+       {
+         warning ("bad breakpoint number at or near '%s'", p);
+       }
+      else
+       {
+         ALL_BREAKPOINTS_SAFE (b, tmp)
+           if (b->number == num)
+             {
+               struct breakpoint *related_breakpoint = b->related_breakpoint;
+               match = 1;
+               function (b);
+               if (related_breakpoint)
+                 function (related_breakpoint);
+               break;
+             }
+         if (match == 0)
+           printf_unfiltered ("No breakpoint number %d.\n", num);
+       }
+      p = p1;
+    }
+}
+
+/* Set ignore-count of breakpoint number BPTNUM to COUNT.
+   If from_tty is nonzero, it prints a message to that effect,
+   which ends with a period (no newline).  */
+
+void
+disable_breakpoint (struct breakpoint *bpt)
+{
+  /* Never disable a watchpoint scope breakpoint; we want to
+     hit them when we leave scope so we can delete both the
+     watchpoint and its scope breakpoint at that time.  */
+  if (bpt->type == bp_watchpoint_scope)
+    return;
+
+  /* You can't disable permanent breakpoints.  */
+  if (bpt->enable_state == bp_permanent)
+    return;
+
+  bpt->enable_state = bp_disabled;
+
+  check_duplicates (bpt);
+
+  if (modify_breakpoint_hook)
+    modify_breakpoint_hook (bpt);
+  breakpoint_modify_event (bpt->number);
+}
+
+/* ARGSUSED */
+static void
+disable_command (char *args, int from_tty)
+{
+  register struct breakpoint *bpt;
+  if (args == 0)
+    ALL_BREAKPOINTS (bpt)
+      switch (bpt->type)
+      {
+      case bp_none:
+       warning ("attempted to disable apparently deleted breakpoint #%d?",
+                bpt->number);
+       continue;
+      case bp_breakpoint:
+      case bp_catch_load:
+      case bp_catch_unload:
+      case bp_catch_fork:
+      case bp_catch_vfork:
+      case bp_catch_exec:
+      case bp_catch_catch:
+      case bp_catch_throw:
+      case bp_hardware_breakpoint:
+      case bp_watchpoint:
+      case bp_hardware_watchpoint:
+      case bp_read_watchpoint:
+      case bp_access_watchpoint:
+       disable_breakpoint (bpt);
+      default:
+       continue;
+      }
+  else
+    map_breakpoint_numbers (args, disable_breakpoint);
+}
+
+static void
+do_enable_breakpoint (struct breakpoint *bpt, enum bpdisp disposition)
+{
+  struct frame_info *save_selected_frame = NULL;
+  int save_selected_frame_level = -1;
+  int target_resources_ok, other_type_used;
+  struct value *mark;
+
+  if (bpt->type == bp_hardware_breakpoint)
+    {
+      int i;
+      i = hw_breakpoint_used_count ();
+      target_resources_ok = 
+       TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_hardware_breakpoint, 
+                                           i + 1, 0);
+      if (target_resources_ok == 0)
+       error ("No hardware breakpoint support in the target.");
+      else if (target_resources_ok < 0)
+       error ("Hardware breakpoints used exceeds limit.");
+    }
+
+  if (bpt->enable_state != bp_permanent)
+    bpt->enable_state = bp_enabled;
+  bpt->disposition = disposition;
+  check_duplicates (bpt);
+  breakpoints_changed ();
+
+  if (bpt->type == bp_watchpoint || 
+      bpt->type == bp_hardware_watchpoint ||
+      bpt->type == bp_read_watchpoint || 
+      bpt->type == bp_access_watchpoint)
+    {
+      if (bpt->exp_valid_block != NULL)
+       {
+         struct frame_info *fr =
+         fr = frame_find_by_id (bpt->watchpoint_frame);
+         if (fr == NULL)
+           {
+             printf_filtered ("\
+Cannot enable watchpoint %d because the block in which its expression\n\
+is valid is not currently in scope.\n", bpt->number);
+             bpt->enable_state = bp_disabled;
+             return;
+           }
+
+         save_selected_frame = selected_frame;
+         save_selected_frame_level = frame_relative_level (selected_frame);
+         select_frame (fr);
+       }
+
+      value_free (bpt->val);
+      mark = value_mark ();
+      bpt->val = evaluate_expression (bpt->exp);
+      release_value (bpt->val);
+      if (VALUE_LAZY (bpt->val))
+       value_fetch_lazy (bpt->val);
+
+      if (bpt->type == bp_hardware_watchpoint ||
+         bpt->type == bp_read_watchpoint ||
+         bpt->type == bp_access_watchpoint)
+       {
+         int i = hw_watchpoint_used_count (bpt->type, &other_type_used);
+         int mem_cnt = can_use_hardware_watchpoint (bpt->val);
+
+         /* Hack around 'unused var' error for some targets here */
+         (void) mem_cnt, i;
+         target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT (
+                                  bpt->type, i + mem_cnt, other_type_used);
+         /* we can consider of type is bp_hardware_watchpoint, convert to 
+            bp_watchpoint in the following condition */
+         if (target_resources_ok < 0)
+           {
+             printf_filtered ("\
+Cannot enable watchpoint %d because target watch resources\n\
+have been allocated for other watchpoints.\n", bpt->number);
+             bpt->enable_state = bp_disabled;
+             value_free_to_mark (mark);
+             return;
+           }
+       }
+
+      if (save_selected_frame_level >= 0)
+       select_frame (save_selected_frame);
+      value_free_to_mark (mark);
+    }
+  if (modify_breakpoint_hook)
+    modify_breakpoint_hook (bpt);
+  breakpoint_modify_event (bpt->number);
+}
+
+void
+enable_breakpoint (struct breakpoint *bpt)
+{
+  do_enable_breakpoint (bpt, bpt->disposition);
+}
+
+/* The enable command enables the specified breakpoints (or all defined
+   breakpoints) so they once again become (or continue to be) effective
+   in stopping the inferior. */
+
+/* ARGSUSED */
+static void
+enable_command (char *args, int from_tty)
+{
+  register struct breakpoint *bpt;
+  if (args == 0)
+    ALL_BREAKPOINTS (bpt)
+      switch (bpt->type)
+      {
+      case bp_none:
+       warning ("attempted to enable apparently deleted breakpoint #%d?",
+                bpt->number);
+       continue;
+      case bp_breakpoint:
+      case bp_catch_load:
+      case bp_catch_unload:
+      case bp_catch_fork:
+      case bp_catch_vfork:
+      case bp_catch_exec:
+      case bp_catch_catch:
+      case bp_catch_throw:
+      case bp_hardware_breakpoint:
+      case bp_watchpoint:
+      case bp_hardware_watchpoint:
+      case bp_read_watchpoint:
+      case bp_access_watchpoint:
+       enable_breakpoint (bpt);
+      default:
+       continue;
+      }
+  else
+    map_breakpoint_numbers (args, enable_breakpoint);
+}
+
+static void
+enable_once_breakpoint (struct breakpoint *bpt)
+{
+  do_enable_breakpoint (bpt, disp_disable);
+}
+
+/* ARGSUSED */
+static void
+enable_once_command (char *args, int from_tty)
+{
+  map_breakpoint_numbers (args, enable_once_breakpoint);
+}
+
+static void
+enable_delete_breakpoint (struct breakpoint *bpt)
+{
+  do_enable_breakpoint (bpt, disp_del);
+}
+
+/* ARGSUSED */
+static void
+enable_delete_command (char *args, int from_tty)
+{
+  map_breakpoint_numbers (args, enable_delete_breakpoint);
+}
+\f
+/* Use default_breakpoint_'s, or nothing if they aren't valid.  */
+
+struct symtabs_and_lines
+decode_line_spec_1 (char *string, int funfirstline)
+{
+  struct symtabs_and_lines sals;
+  if (string == 0)
+    error ("Empty line specification.");
+  if (default_breakpoint_valid)
+    sals = decode_line_1 (&string, funfirstline,
+                         default_breakpoint_symtab,
+                         default_breakpoint_line,
+                         (char ***) NULL);
+  else
+    sals = decode_line_1 (&string, funfirstline,
+                         (struct symtab *) NULL, 0, (char ***) NULL);
+  if (*string)
+    error ("Junk at end of line specification: %s", string);
+  return sals;
+}
+\f
+void
+_initialize_breakpoint (void)
+{
+  struct cmd_list_element *c;
+
+  breakpoint_chain = 0;
+  /* Don't bother to call set_breakpoint_count.  $bpnum isn't useful
+     before a breakpoint is set.  */
+  breakpoint_count = 0;
+
+  add_com ("ignore", class_breakpoint, ignore_command,
+          "Set ignore-count of breakpoint number N to COUNT.\n\
+Usage is `ignore N COUNT'.");
+  if (xdb_commands)
+    add_com_alias ("bc", "ignore", class_breakpoint, 1);
+
+  add_com ("commands", class_breakpoint, commands_command,
+          "Set commands to be executed when a breakpoint is hit.\n\
+Give breakpoint number as argument after \"commands\".\n\
+With no argument, the targeted breakpoint is the last one set.\n\
+The commands themselves follow starting on the next line.\n\
+Type a line containing \"end\" to indicate the end of them.\n\
+Give \"silent\" as the first line to make the breakpoint silent;\n\
+then no output is printed when it is hit, except what the commands print.");
+
+  add_com ("condition", class_breakpoint, condition_command,
+          "Specify breakpoint number N to break only if COND is true.\n\
+Usage is `condition N COND', where N is an integer and COND is an\n\
+expression to be evaluated whenever breakpoint N is reached.");
+
+  c = add_com ("tbreak", class_breakpoint, tbreak_command,
+              "Set a temporary breakpoint.  Args like \"break\" command.\n\
+Like \"break\" except the breakpoint is only temporary,\n\
+so it will be deleted when hit.  Equivalent to \"break\" followed\n\
+by using \"enable delete\" on the breakpoint number.");
+  set_cmd_completer (c, location_completer);
+
+  c = add_com ("hbreak", class_breakpoint, hbreak_command,
+              "Set a hardware assisted  breakpoint. Args like \"break\" command.\n\
+Like \"break\" except the breakpoint requires hardware support,\n\
+some target hardware may not have this support.");
+  set_cmd_completer (c, location_completer);
+
+  c = add_com ("thbreak", class_breakpoint, thbreak_command,
+              "Set a temporary hardware assisted breakpoint. Args like \"break\" command.\n\
+Like \"hbreak\" except the breakpoint is only temporary,\n\
+so it will be deleted when hit.");
+  set_cmd_completer (c, location_completer);
+
+  add_prefix_cmd ("enable", class_breakpoint, enable_command,
+                 "Enable some breakpoints.\n\
+Give breakpoint numbers (separated by spaces) as arguments.\n\
+With no subcommand, breakpoints are enabled until you command otherwise.\n\
+This is used to cancel the effect of the \"disable\" command.\n\
+With a subcommand you can enable temporarily.",
+                 &enablelist, "enable ", 1, &cmdlist);
+  if (xdb_commands)
+    add_com ("ab", class_breakpoint, enable_command,
+            "Enable some breakpoints.\n\
+Give breakpoint numbers (separated by spaces) as arguments.\n\
+With no subcommand, breakpoints are enabled until you command otherwise.\n\
+This is used to cancel the effect of the \"disable\" command.\n\
+With a subcommand you can enable temporarily.");
+
+  add_com_alias ("en", "enable", class_breakpoint, 1);
+
+  add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command,
+                        "Enable some breakpoints.\n\
+Give breakpoint numbers (separated by spaces) as arguments.\n\
+This is used to cancel the effect of the \"disable\" command.\n\
+May be abbreviated to simply \"enable\".\n",
+                  &enablebreaklist, "enable breakpoints ", 1, &enablelist);
+
+  add_cmd ("once", no_class, enable_once_command,
+          "Enable breakpoints for one hit.  Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it becomes disabled.",
+          &enablebreaklist);
+
+  add_cmd ("delete", no_class, enable_delete_command,
+          "Enable breakpoints and delete when hit.  Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it is deleted.",
+          &enablebreaklist);
+
+  add_cmd ("delete", no_class, enable_delete_command,
+          "Enable breakpoints and delete when hit.  Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it is deleted.",
+          &enablelist);
+
+  add_cmd ("once", no_class, enable_once_command,
+          "Enable breakpoints for one hit.  Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it becomes disabled.",
+          &enablelist);
+
+  add_prefix_cmd ("disable", class_breakpoint, disable_command,
+                 "Disable some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To disable all breakpoints, give no argument.\n\
+A disabled breakpoint is not forgotten, but has no effect until reenabled.",
+                 &disablelist, "disable ", 1, &cmdlist);
+  add_com_alias ("dis", "disable", class_breakpoint, 1);
+  add_com_alias ("disa", "disable", class_breakpoint, 1);
+  if (xdb_commands)
+    add_com ("sb", class_breakpoint, disable_command,
+            "Disable some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To disable all breakpoints, give no argument.\n\
+A disabled breakpoint is not forgotten, but has no effect until reenabled.");
+
+  add_cmd ("breakpoints", class_alias, disable_command,
+          "Disable some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To disable all breakpoints, give no argument.\n\
+A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\
+This command may be abbreviated \"disable\".",
+          &disablelist);
+
+  add_prefix_cmd ("delete", class_breakpoint, delete_command,
+                 "Delete some breakpoints or auto-display expressions.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n\
+\n\
+Also a prefix command for deletion of other GDB objects.\n\
+The \"unset\" command is also an alias for \"delete\".",
+                 &deletelist, "delete ", 1, &cmdlist);
+  add_com_alias ("d", "delete", class_breakpoint, 1);
+  if (xdb_commands)
+    add_com ("db", class_breakpoint, delete_command,
+            "Delete some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n");
+
+  add_cmd ("breakpoints", class_alias, delete_command,
+          "Delete some breakpoints or auto-display expressions.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n\
+This command may be abbreviated \"delete\".",
+          &deletelist);
+
+  add_com ("clear", class_breakpoint, clear_command,
+          concat ("Clear breakpoint at specified line or function.\n\
+Argument may be line number, function name, or \"*\" and an address.\n\
+If line number is specified, all breakpoints in that line are cleared.\n\
+If function is specified, breakpoints at beginning of function are cleared.\n\
+If an address is specified, breakpoints at that address are cleared.\n\n",
+                  "With no argument, clears all breakpoints in the line that the selected frame\n\
+is executing in.\n\
+\n\
+See also the \"delete\" command which clears breakpoints by number.", NULL));
+
+  c = add_com ("break", class_breakpoint, break_command,
+              concat ("Set breakpoint at specified line or function.\n\
+Argument may be line number, function name, or \"*\" and an address.\n\
+If line number is specified, break at start of code for that line.\n\
+If function is specified, break at start of code for that function.\n\
+If an address is specified, break at that exact address.\n",
+                  "With no arg, uses current execution address of selected stack frame.\n\
+This is useful for breaking on return to a stack frame.\n\
+\n\
+Multiple breakpoints at one place are permitted, and useful if conditional.\n\
+\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL));
+  set_cmd_completer (c, location_completer);
+
+  add_com_alias ("b", "break", class_run, 1);
+  add_com_alias ("br", "break", class_run, 1);
+  add_com_alias ("bre", "break", class_run, 1);
+  add_com_alias ("brea", "break", class_run, 1);
+
+ if (xdb_commands)
+    {
+      add_com_alias ("ba", "break", class_breakpoint, 1);
+      add_com_alias ("bu", "ubreak", class_breakpoint, 1);
+    }
+
+  if (dbx_commands)
+    {
+      add_abbrev_prefix_cmd ("stop", class_breakpoint, stop_command,
+       "Break in function/address or break at a line in the current file.",
+                            &stoplist, "stop ", 1, &cmdlist);
+      add_cmd ("in", class_breakpoint, stopin_command,
+              "Break in function or address.\n", &stoplist);
+      add_cmd ("at", class_breakpoint, stopat_command,
+              "Break at a line in the current file.\n", &stoplist);
+      add_com ("status", class_info, breakpoints_info,
+              concat ("Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tbreakpoint     - normal breakpoint\n\
+\twatchpoint     - watchpoint\n\
+The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+the disposition of the breakpoint after it gets hit.  \"dis\" means that the\n\
+breakpoint will be disabled.  The \"Address\" and \"What\" columns indicate the\n\
+address and file/line number respectively.\n\n",
+                      "Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.\n\n\
+Convenience variable \"$bpnum\" contains the number of the last\n\
+breakpoint set.", NULL));
+    }
+
+  add_info ("breakpoints", breakpoints_info,
+           concat ("Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tbreakpoint     - normal breakpoint\n\
+\twatchpoint     - watchpoint\n\
+The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+the disposition of the breakpoint after it gets hit.  \"dis\" means that the\n\
+breakpoint will be disabled.  The \"Address\" and \"What\" columns indicate the\n\
+address and file/line number respectively.\n\n",
+                   "Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.\n\n\
+Convenience variable \"$bpnum\" contains the number of the last\n\
+breakpoint set.", NULL));
+
+  if (xdb_commands)
+    add_com ("lb", class_breakpoint, breakpoints_info,
+            concat ("Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tbreakpoint     - normal breakpoint\n\
+\twatchpoint     - watchpoint\n\
+The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+the disposition of the breakpoint after it gets hit.  \"dis\" means that the\n\
+breakpoint will be disabled.  The \"Address\" and \"What\" columns indicate the\n\
+address and file/line number respectively.\n\n",
+                    "Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.\n\n\
+Convenience variable \"$bpnum\" contains the number of the last\n\
+breakpoint set.", NULL));
+
+  add_cmd ("breakpoints", class_maintenance, maintenance_info_breakpoints,
+          concat ("Status of all breakpoints, or breakpoint number NUMBER.\n\
+The \"Type\" column indicates one of:\n\
+\tbreakpoint     - normal breakpoint\n\
+\twatchpoint     - watchpoint\n\
+\tlongjmp        - internal breakpoint used to step through longjmp()\n\
+\tlongjmp resume - internal breakpoint at the target of longjmp()\n\
+\tuntil          - internal breakpoint used by the \"until\" command\n\
+\tfinish         - internal breakpoint used by the \"finish\" command\n",
+                  "The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\
+the disposition of the breakpoint after it gets hit.  \"dis\" means that the\n\
+breakpoint will be disabled.  The \"Address\" and \"What\" columns indicate the\n\
+address and file/line number respectively.\n\n",
+                  "Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.\n\n\
+Convenience variable \"$bpnum\" contains the number of the last\n\
+breakpoint set.", NULL),
+          &maintenanceinfolist);
+
+  add_com ("catch", class_breakpoint, catch_command,
+          "Set catchpoints to catch events.\n\
+Raised signals may be caught:\n\
+\tcatch signal              - all signals\n\
+\tcatch signal <signame>    - a particular signal\n\
+Raised exceptions may be caught:\n\
+\tcatch throw               - all exceptions, when thrown\n\
+\tcatch throw <exceptname>  - a particular exception, when thrown\n\
+\tcatch catch               - all exceptions, when caught\n\
+\tcatch catch <exceptname>  - a particular exception, when caught\n\
+Thread or process events may be caught:\n\
+\tcatch thread_start        - any threads, just after creation\n\
+\tcatch thread_exit         - any threads, just before expiration\n\
+\tcatch thread_join         - any threads, just after joins\n\
+Process events may be caught:\n\
+\tcatch start               - any processes, just after creation\n\
+\tcatch exit                - any processes, just before expiration\n\
+\tcatch fork                - calls to fork()\n\
+\tcatch vfork               - calls to vfork()\n\
+\tcatch exec                - calls to exec()\n\
+Dynamically-linked library events may be caught:\n\
+\tcatch load                - loads of any library\n\
+\tcatch load <libname>      - loads of a particular library\n\
+\tcatch unload              - unloads of any library\n\
+\tcatch unload <libname>    - unloads of a particular library\n\
+The act of your program's execution stopping may also be caught:\n\
+\tcatch stop\n\n\
+C++ exceptions may be caught:\n\
+\tcatch throw               - all exceptions, when thrown\n\
+\tcatch catch               - all exceptions, when caught\n\
+\n\
+Do \"help set follow-fork-mode\" for info on debugging your program\n\
+after a fork or vfork is caught.\n\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.");
+
+  add_com ("tcatch", class_breakpoint, tcatch_command,
+          "Set temporary catchpoints to catch events.\n\
+Args like \"catch\" command.\n\
+Like \"catch\" except the catchpoint is only temporary,\n\
+so it will be deleted when hit.  Equivalent to \"catch\" followed\n\
+by using \"enable delete\" on the catchpoint number.");
+
+  c = add_com ("watch", class_breakpoint, watch_command,
+              "Set a watchpoint for an expression.\n\
+A watchpoint stops execution of your program whenever the value of\n\
+an expression changes.");
+  set_cmd_completer (c, location_completer);
+
+  c = add_com ("rwatch", class_breakpoint, rwatch_command,
+              "Set a read watchpoint for an expression.\n\
+A watchpoint stops execution of your program whenever the value of\n\
+an expression is read.");
+  set_cmd_completer (c, location_completer);
+
+  c = add_com ("awatch", class_breakpoint, awatch_command,
+              "Set a watchpoint for an expression.\n\
+A watchpoint stops execution of your program whenever the value of\n\
+an expression is either read or written.");
+  set_cmd_completer (c, location_completer);
+
+  add_info ("watchpoints", breakpoints_info,
+           "Synonym for ``info breakpoints''.");
+
+
+  c = add_set_cmd ("can-use-hw-watchpoints", class_support, var_zinteger,
+                  (char *) &can_use_hw_watchpoints,
+                  "Set debugger's willingness to use watchpoint hardware.\n\
+If zero, gdb will not use hardware for new watchpoints, even if\n\
+such is available.  (However, any hardware watchpoints that were\n\
+created before setting this to nonzero, will continue to use watchpoint\n\
+hardware.)",
+                  &setlist);
+  add_show_from_set (c, &showlist);
+
+  can_use_hw_watchpoints = 1;
+}
diff --git a/gdb/mi/ChangeLog b/gdb/mi/ChangeLog
new file mode 100644 (file)
index 0000000..51d9973
--- /dev/null
@@ -0,0 +1,1836 @@
+2002-09-11  Keith Seitz  <keiths@redhat.com>
+
+       * mi-main.c (mi_cmd_data_list_register_names): Use cleanups
+       for the uiout list. Do the cleanups when returning an error.
+       (mi_cmd_data_list_changed_registers): Ditto.
+       (mi_cmd_data_list_register_values): Use cleanups for the uiout list
+       and tuples. Do the cleanups when returning errors.
+
+2002-07-29  Andrew Cagney  <ac131313@redhat.com>
+
+
+       * mi-cmd-var.c: Include "gdb_string.h".
+       * mi-cmd-disas.c: Ditto.
+
+2002-06-17  Keith Seitz  <keiths@redhat.com>
+
+       * gdbmi.texinfo: Update command examples with real MI behavior.
+
+2002-05-20  Keith Seitz  <keiths@redhat.com>
+
+       * mi-main.c (captured_mi_execute_command): Add uiout parameter.
+       "data" is now a structure which is used to pass data to/from this
+       function to mi_execute_command.
+       Modify function to comply with requirements from catch_exceptions.
+       Store real return result and command's return result in data.
+       (mi_execute_command): Use catch_exceptions.
+       Use enum to handle actions to be performed instead of overloading
+       catch_errors return result and the mi return result.
+
+2002-04-14  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_cmd_exec_return): 
+
+2002-04-09  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (register_changed_p): Use frame_register_read instead
+       of read_relative_register_raw_bytes.
+       (get_register): Delete out-of-date comment.
+
+2002-04-07  Elena Zannoni  <ezannoni@redhat.com>
+
+        * mi-cmd-disas.c: Run through indent.
+
+2002-04-07  Elena Zannoni  <ezannoni@redhat.com>
+
+        * mi-cmd-disas.c (dump_insns): New function.
+        (do_mixed_source_and_assembly): New function.
+        (do_assembly_only): New function.
+        (do_disassembly): New function.
+        (mi_cmd_disassemble): Rewrite using smaller, more modular
+        functions.
+
+2002-04-05  Jim Blandy  <jimb@redhat.com>
+
+       * mi-cmd-stack.c (list_args_or_locals): Pass new arg to
+       get_frame_block.  (See entry in gdb/ChangeLog.)
+
+2002-04-05  Elena Zannoni  <ezannoni@redhat.com>
+
+       * mi-cmd-disas.c (mi_cmd_disassemble): Use TARGET_PRINT_INSN
+       instead of tm_print_insn.
+       Update copyright year.
+
+2002-04-04  Daniel Jacobowitz  <drow@mvista.com>
+
+       * mi-cmd-disas.c (mi_cmd_disassemble): Skip end-of-function
+       markers in the line table.
+
+2002-03-15  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (XMALLOC): Delete macro.
+       * mi-out.c (XMALLOC): Ditto.
+       * mi-parse.c (XMALLOC): Ditto.
+       * mi-console.c (XMALLOC): Ditto.
+       * mi-cmd-var.c (XMALLOC): Ditto.
+       * mi-cmd-break.c (XMALLOC): Ditto.
+       
+       * mi/mi-cmd-var.c, mi/mi-console.c, mi/mi-out.c: Update copyright
+       * mi/mi-parse.c: Ditto.
+
+2002-02-24  Andrew Cagney  <ac131313@redhat.com>
+
+       From wiz at danbala:
+       * gdbmi.texinfo: Fix grammar and typos.
+       Fix PR gdb/287.
+
+2002-02-03  Jim Blandy  <jimb@redhat.com>
+
+       * mi-cmd-stack.c (list_args_or_locals): Move declaration of
+       print_me inside the loop body, so it gets re-initialized every
+       iteration.  The cases for the different symbol kinds leave
+       print_me unchanged if they don't want the symbol printed.
+
+2002-01-22  Andrew Cagney  <ac131313@redhat.com>
+
+       * gdbmi.texinfo: Remove makeinfo 3.12 hacks.
+
+2002-01-21  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-cmd-stack.c: Remove #else clause of #ifdef UI_OUT.
+       * mi-cmd-break.c: Ditto.
+       * mi-main.c: Ditto.
+
+2001-12-30  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * gdbmi.texinfo: Fix the application of GFDL in the Copyright notice.
+
+2001-10-12  Daniel Jacobowitz  <drow@mvista.com>
+
+       * mi-cmd-stack.c (list_args_or_locals): Use ALL_BLOCK_SYMBOLS.
+
+2001-09-18  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_cmd_thread_select): Pass uiout to
+       gdb_thread_select.
+       (mi_cmd_thread_list_ids): Pass uiout to gdb_list_thread_ids.
+
+       * mi-cmd-break.c (breakpoint_notify): Pass uiout to
+       gdb_breakpoint_query.
+
+2001-08-17  Keith Seitz  <keiths@redhat.com>
+
+       * mi-cmd-var.c (varobj_update_one): Update call to
+       varobj_update to reflect recent api change.
+
+2001-07-26  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c: Include "gdb.h".
+       * mi-cmd-break.c: Include "gdb.h".
+
+2001-07-12  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_execute_command): Flush output after ``(gdb)''
+       prompt.  Bug reported by David Whedon.
+       (mi_execute_async_cli_command): Ditto.
+       (mi_exec_async_cli_cmd_continuation): Ditto.
+       (mi_command_loop): Ditto.
+
+2001-07-10  Mark Kettenis  <kettenis@gnu.org>
+
+       * mi-out.c (mi_out_new): Initialize suppress_ouput field of newly
+       created `struct ui_out_data'.
+
+2001-07-09  Kevin Buettner  <kevinb@redhat.com>
+
+       * mi-main.c (register_changed_p, get_register): Use alloca()
+       to allocate space previously allocated via gcc's
+       variable-length array extension.
+       (mi_cmd_data_write_register_values, mi_cmd_data_write_memory):
+       Change type of ``buffer'' to ``void *''.  Don't cast return value
+       from xmalloc().  Add a cleanup to free the xmalloc'd buffer.
+
+2001-07-07  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_cmd_data_evaluate_expression): Replace value_ptr
+       with `struct value *'.
+
+2001-07-08  Kevin Buettner  <kevinb@redhat.com>
+
+       * mi-out.c (mi_table_header, mi_field_int, mi_field_skip)
+       (mi_field_string) Make function declarators match earlier
+       declarations.
+
+2001-07-04  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (mi_ui_out_impl): Initialize is_mi_like_p to one.
+
+2001-06-27  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (mi_table_begin): Include nr_cols and nr_rows in mi1
+       table output.
+       * mi-out.c (mi_table_begin): Only suppress output when mi0. Change
+       the header to a list.
+       (mi_table_body): For mi1, close the header list and open a table
+       body list.
+       (mi_table_end): For mi1, close the body list.
+       (mi_table_header): For mi1, output a tuple containing all the
+       header information.
+       (mi_open, mi_close): Reverse logic of mi_version test.
+       * gdbmi.texinfo (GDB/MI Breakpoint Table Commands): Update.
+
+2001-06-26  Andrew Cagney  <ac131313@redhat.com>
+
+       * gdbmi.texinfo (GDB/MI Output Syntax): Delete reference to query
+       packet.
+
+2001-06-26  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-cmd-stack.c (list_args_or_locals): Output a list of "args" or
+       "locals" entries.
+       * gdbmi.texinfo (stack-list-locals, stack-list-arguments)
+       (exec-interrupt, target-select, thread-select): Update
+       documentation.
+
+2001-06-26  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-cmd-stack.c (mi_cmd_stack_list_frames): Output a list of
+       "stack" entries.
+       (mi_cmd_stack_list_args): Ditto for "stack-args".
+       * gdbmi.texinfo (stack-list-frames, stack-list-arguments): Update
+       documentation.
+       (GDB/MI Stack Manipulation Commands): Fix section title.  Was
+       Stack Manipulation Commands in GDB/MI.
+
+2001-06-25  Andrew Cagney  <ac131313@redhat.com>
+
+       * gdbmi.texinfo: Update output examples that contain stop reason
+       output, change the args=.... to a list.
+       (exec-return): Ditto.
+
+2001-06-25  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_cmd_data_read_memory): Output the memory contents
+       - memory and data - as a list.
+       * gdbmi.texinfo (data-read-memory): Update documentation.
+
+2001-06-25  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_cmd_data_list_register_values): Output a list of
+       register values.
+       * gdbmi.texinfo (data-list-register-values): Update documentation.
+
+2001-06-25  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_cmd_data_list_register_names): Output a list of
+       register names.
+       (mi_cmd_data_list_register_names): Include the pseudo registers.
+       (mi_cmd_data_list_register_names): Don't leave holes in the list,
+       output "" for NULL registers.
+       * gdbmi.texinfo (data-list-register-names): Update documentation.
+
+2001-06-23  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_cmd_data_list_changed_registers): Output a list of
+       register numbers.
+       * gdbmi.texinfo (data-list-changed-registers): Update
+       documentation.
+       
+2001-06-23  Andrew Cagney  <ac131313@redhat.com>
+
+       * gdbmi.texinfo (data-disassemble): Update documentation of
+       output.  Produces a list of instructions and a list of source
+       lines.
+
+2001-06-22  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-cmd-disas.c (mi_cmd_disassemble): For "-data-disassemble",
+       output a list instead of a tupple.
+
+2001-06-21  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (struct ui_out_data): Replace field first_header with
+       suppress_output.
+       (mi_begin, mi_end): Check suppress_header.
+       (mi_field_int, mi_field_skip): Ditto.
+       (mi_field_string, mi_field_fmt): Ditto.
+       (mi_table_begin): When nr_rows is zero, set suppress_header else,
+       output the start of the header.
+       (mi_table_body): Clear suppress header.
+
+2001-06-21  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (mi_open): For lists, when mi_version > 0, use ``[''.
+       (mi_close): Ditto for ``]''.
+
+2001-06-20  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (mi_table_header): Add parameter ``col_name''.
+
+2001-06-18  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c: Include "gdb_assert.h".
+       (mi_table_begin): Add parameter ``nr_rows''.
+
+2001-06-18  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c: Use strncmp as the "mi" test.  Allow "mi", "mi0" and
+       "mi1".
+       (mi_command_loop): Add parameter mi_version, pass to mi_out_new.
+       (mi1_command_loop, mi0_command_loop): New functions.
+       (_initialize_mi_main): Recognize "mi", "mi0" and "mi1".
+       * mi-out.c (mi_out_new): Add parameter mi_version.
+       (struct ui_out_data): Add field mi_version.
+       * mi-out.h (mi_out_new): Update.
+
+2001-06-07  Andrew Cagney  <ac131313@redhat.com>
+
+       * gdbmi.texinfo (GDB/MI Output Syntax): Add tuples and lists to
+       syntax.
+       (GDB/MI Draft Changes to Output Syntax): Delete section.
+       
+Mon Jun 11 17:22:25 2001  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-out.c: Fix typo. s/supress/suppress/.
+
+2001-06-09  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (mi_table_end, mi_table_begin, mi_begin, mi_end): Move
+       supress_field_separator updates from here.
+       (mi_open, mi_close): To here.
+       (mi_open): Add parameter name. Output a field_separator.
+       (mi_table_begin): Update.
+       (mi_table_header): Update.
+       (mi_begin): Update.
+
+2001-06-09  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (mi_table_begin): Make char* parameters constant.
+       (mi_table_header): Ditto.
+       (mi_field_int): Ditto.
+       (mi_field_skip): Ditto.
+       (mi_field_string): Ditto.
+       (mi_field_fmt): Ditto.
+       (mi_text): Ditto.
+       (mi_message): Ditto.
+
+2001-05-12  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (mi_close, mi_open): Output ``[]'' when a list.
+
+Fri May 11 13:55:07 2001  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmd-var.c: Replace ui_out_list_begin, ui_out_list_end and
+       make_cleanup_ui_out_list_end with ui_out_tupple_begin,
+       ui_out_tupple_end and make_cleanup_ui_out_tupple_begin_end.
+       * mi-cmd-stack.c: Ditto.
+       * mi-cmd-disas.c: Ditto.
+       * mi-main.c: Ditto.
+
+2001-05-10  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (mi_open, mi_close): Replace list_open and list_close.
+       (mi_table_begin): Update.
+       (mi_table_header): Update.
+       (mi_begin): Update.
+       (mi_table_body): Update.
+       (mi_table_end): Update.
+       (mi_end): Update.
+
+Thu May 10 16:28:13 2001  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_execute_async_cli_command): Always initialize
+       old_cleanups.
+
+2001-05-08  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.c (mi_begin, mi_end): Replace mi_list_begin and
+       mi_list_end.
+       (mi_ui_out_impl): Update.
+
+2001-03-28  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_cmd_data_read_memory): Use xcalloc.
+
+2001-03-26  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * gdbmi.texinfo: Update copyright.  Change Permissions to GFDL.
+
+2001-03-20  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-cmd-disas.c (mi_cmd_disassemble): Initialize ``file_string''
+       and ``line_num''.  Consolidate declaration of argument variables.
+
+2001-03-19  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-out.h: Remove #ifdef __STDC__.
+
+2001-03-08  Andrew Cagney  <ac131313@redhat.com>
+
+       * mi-main.c (mi_cmd_data_list_register_names): Use NUM_REGS, not
+       ARCH_NUM_REGS.
+       (mi_cmd_data_list_changed_registers): Ditto.
+       (mi_cmd_data_list_register_values): Ditto.
+       (mi_cmd_data_write_register_values): Ditto.
+
+2001-03-06  Kevin Buettner  <kevinb@redhat.com>
+
+       * gdbmi.texinfo, mi-cmd-disas.c, mi-cmd-stack.c, mi-cmd-var.c,
+       mi-cmds.c, mi-cmds.h, mi-console.c, mi-console.h, mi-getopt.c,
+       mi-getopt.h, mi-out.c, mi-out.h, mi-parse.c, mi-parse.h: 
+       Update/correct copyright notices.
+
+Wed Feb  7 19:50:37 2001  Andrew Cagney  <cagney@redhat.com>
+
+       * mi-getopt.c: Add __FILE__ and __LINE__ parameter to calls to
+       internal_error.
+       * mi-console.c: Ditto.
+       * mi-cmds.c: Ditto.
+       * mi-cmd-break.c: Ditto.
+
+2001-01-27  Fernando Nasser  <fnasser@redhat.com>
+
+       From Momchil Velikov  <velco@fadata.bg>
+       * mi-cmd-disas.c (gdb_dis_asm_read_memory): Add missing memory
+       attributes argument in the call to `xfer_memory'.
+
+2000-12-14  Kevin Buettner  <kevinb@redhat.com>
+
+       * mi-cmd-disas.c, mi-cmd-var.c, mi-console.c, mi-main.c,
+       mi-parse.c: Replace occurrences of free() with xfree().
+
+Fri Nov 17 16:07:23 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c: Replace asprintf with xasprintf.
+       * mi-cmd-var.c (mi_cmd_var_create): Ditto.
+
+2000-10-16  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * gdbmi.texinfo (GDB/MI Variable Objects): Dimensions of
+       multitable changed to "@columnfractions .4 .6".  Suggested by
+       Dmitry Sivachenko <dima@Chg.RU>.
+
+2000-08-23  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * gdbmi.texinfo: Change flathead -> @sc{gdb/mi}.
+       Fix typos and markup mistakes (from Dmitry S.
+       Sivachenko <dima@Chg.RU>).
+
+2000-07-24  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * gdbmi.texinfo: Change GDB -> @value{GDBN}, and
+       (gdb) -> (@value{GDBP}).  Fix a few typos and some markup.  From
+       Dmitry S. Sivachenko <dima@Chg.RU>.
+
+Tue May 16 14:13:41 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_cmd_execute): Use free_current_contents.
+       (free_and_reset): Delete.
+
+Mon May 15 16:17:56 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_cmd_data_assign, mi_cmd_data_evaluate_expression),
+       mi-cmd-var.c (mi_cmd_var_create, mi_cmd_var_delete): Delete
+       make_cleanup_func casts. Not needed.
+
+2000-05-07  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * gdbmi.texinfo: Lots of typos and grammar fixes from Brian
+        Youmans <3diff@flib.gnu.ai.mit.edu>.
+
+Wed Apr 26 18:35:19 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * gdbmi.texinfo (GDB/MI Output Syntax v2.0): Convert Draft 2.0
+       Output Syntax into a new section.  Cross reference.
+       (menu): Fix tipo. GDB/MI Compatibility with CLI.
+
+2000-04-23  Eli Zaretskii  <eliz@is.elta.co.il>
+
+       * gdbmi.texinfo: Lots of changes, to include this document as part
+       of the GDB manual.
+
+2000-03-13  James Ingham  <jingham@leda.cygnus.com>
+
+       * mi-cmd-var.c (mi_cmd_var_create): Add special frame cookie "@"
+       to indicate an "USE_CURRENT_FRAME" variable.
+       (varobj_update_one): Add "in_scope" and "type_changed" to the
+       result.
+
+2000-03-06  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.h: Export mi_cmd_data_write_register_values.
+       
+       * mi-cmds.c (mi_cmds): Implement data-write-register-values with
+       mi_cmd_data_write_register_values.
+
+       * mi-main.c (mi_cmd_data_write_register_values): New
+       function. Write a value into a register.
+
+2000-03-06  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Update data-disassemble documentation.
+
+2000-03-01  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmd-disas.c (mi_cmd_disassemble): Use
+       ui_out_field_core_addr() instead of print_address_numeric(), to
+       maintain consistency throughout MI.
+
+Wed Feb 23 17:09:39 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmd-break.c, mi-cmd-disas.c, mi-cmd-stack.c, mi-cmd-var.c,
+       mi-cmds.c, mi-cmds.h, mi-console.c, mi-console.h, mi-getopt.c,
+       mi-getopt.h, mi-main.c, mi-out.c, mi-out.h, mi-parse.c,
+       mi-parse.h: Update copyright information.
+
+Wed Feb 23 13:31:16 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmd-disas.c (gdb_dis_asm_read_memory): Change LEN to unsigned
+       long.  Match ../include/dis-asm.h change.
+
+Wed Feb 23 10:30:55 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * gdbmi.texinfo: Update copyright - FSF.  Update version
+       information.
+
+       mi-cmd-break.c, mi-cmd-disas.c, mi-cmd-stack.c, mi-cmd-var.c,
+       mi-cmds.h, mi-main.c, mi-parse.c, mi-parse.h: Re-format using GNU
+       indent.
+
+2000-02-21  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c: Add include of gdbcore.h for write_memory()
+       prototype.
+
+2000-02-18  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmd-disas.c (mi_cmd_disassemble): Change syntax of
+       command. Now use options.  
+       Instead of printing the symbolic address of instructions via
+       print_address_symbolic(), use build_address_symbolic() and format
+       properly for output.
+       (gdb_do_disassmble): Delete.
+
+2000-02-18  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmd-disas.c (mi_cmd_disassemble): 
+
+2000-02-17  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_data_write_memory): New function. Write a
+       value into target memory.
+
+       * mi-cmds.h (mi_cmd_data_write_memory): Export. 
+
+       * mi-cmds.c (mi_cmds): Hook up data-write-memory to
+       mi_cmd_data_write_memory().
+
+2000-02-17  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_target_download): Correct error message to
+       report right function name.
+       (mi_cmd_target_select): Add doing exec cleanups at end.
+       (mi_cmd_data_read_memory): Correct typo.
+       (mi_cmd_execute): Do not simply free last_async_command, but reset
+       it to NULL as well.
+       (free_and_reset): New function, free the argument and set it to
+       NULL.
+       (mi_cmd_target_select_continuation): Delete prototype.
+       
+Tue Feb  1 00:17:12 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmd-disas.c, mi-cmds.h, mi-console.c, mi-console.h,
+       mi-main.c, mi-out.c, mi-out.h: Update to reflect rename of
+       gdb-file / GDB_FILE to ui-file / ``struct ui_file''.
+       
+Mon Jan 31 18:33:28 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_command_loop): Delete reference to
+       fputs_unfiltered_hook.
+
+2000-01-27  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.c (mi_cmds): Update entries for
+       mi_cmd_data_list_register_names,
+       mi_cmd_data_list_changed_registers,
+       mi_cmd_data_list_register_values.
+
+       * mi-cmds.h (mi_cmd_data_list_register_names,
+       mi_cmd_data_list_changed_registers,
+       mi_cmd_data_list_register_values): Update to mi_cmd_argv_ftype.
+
+       * mi-main.c (mi_cmd_data_list_register_names,
+       mi_cmd_data_list_changed_registers,
+       mi_cmd_data_list_register_values): Update to use argc, argv
+       parameters.
+       
+2000-01-27  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_data_read_memory): Correct the computation of
+       next-row.
+
+2000-01-27  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-cmd-var.c (mi_cmd_var_create): Test for NULL type.
+       (mi_cmd_var_set_format, mi_cmd_var_show_format,
+       mi_cmd_var_info_num_children, mi_cmd_var_list_children,
+       mi_cmd_var_info_type, mi_cmd_var_info_expression,
+       mi_cmd_var_show_attributes, mi_cmd_var_evaluate_expression,
+       mi_cmd_var_assign, mi_cmd_var_update): Prevent possibility of memory
+       leak on error.
+
+2000-01-27  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-out.c (mi_field_string): Test for NULL string pointer.
+
+2000-01-17  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmd-stack.c (mi_cmd_stack_list_frames): Call
+       print_frmae_info() with the correct arguments.
+
+       * mi-main.c (mi_cmd_exec_return): Call
+       show_and_print_stack_frame() with LOC_AND_ADDRESS, so it does the
+       right thing.  Update Copyright.
+
+2000-01-13  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c: Move disassemble commands from here.
+
+       * mi-cmd-disas.c: To here. New file.
+
+2000-01-13  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmd-stack.c: Remove include of mi-out.h.
+
+       * mi-main.c (mi_cmd_disassemble): Update function to use argc/argv
+       interface.
+
+       * mi-cmds.h: Ditto.
+
+       * mi-cmds.c: Ditto.
+
+2000-01-12  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Update stack commands descriptions.
+       Add thread commands descriptions and examples.
+
+       * mi-main.c (mi_cmd_thread_list_ids): Fix typo.
+
+2000-01-12  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_thread_list_ids): New function, print a list
+       of currently known threads ids, and the total number of threads.
+       (mi_cmd_thread_select): New function. Switch current thread.
+
+       * mi-cmds.c (mi_cmds): Implement thread-list-ids by
+       mi_cmd_thread_list_ids, and thread-select by mi_cmd_thread_select.
+
+       * mi-cmds.h (mi_cmd_thread_select, mi_cmd_thread_list_ids): Export.
+
+2000-01-11  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c: Move stack commands from here.
+
+       * mi-cmd-stack.c: To here. New file.
+
+2000-01-07  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (list_args_or_locals): Add a new paramter, the frame
+       for which to display args or locals. Don't use selected_frame
+       anymore, use the new parameter instead. Return void instead of
+       mi_cmd_result, let callers do so.
+       (mi_cmd_stack_list_args): Change interface. Now accept low and
+       high frame numbers to display args for a range of frames. Without
+       these two, display args for the whole stack.
+       (mi_cmd_stack_list_locals): Adapt to new interface for
+       list_args_or_locals.
+
+2000-01-06  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_stack_info_depth, mi_cmd_stack_list_args,
+       mi_cmd_stack_list_frames, mi_cmd_stack_list_locals,
+       mi_cmd_stack_select_frame): Change to use argv type of parameters.
+
+       * mi-cmds.c (mi_cmds): Change stack-info-depth,
+       stack-list-arguments, stack-list-frames, stack-list-locals,
+       stack-select-frame to use argv parameters.
+
+       * mi-cmds.h (mi_cmd_stack_info_depth, mi_cmd_stack_list_args,
+       mi_cmd_stack_list_frames, mi_cmd_stack_list_locals,
+       mi_cmd_stack_select_frame): Update definitions.
+
+Tue Jan  4 12:38:54 2000  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_command_loop): Force the MI interface to use seven
+       bit strings.
+       * gdbmi.texinfo: Make it clear that a quoted C string is seven
+       bit.
+
+Thu Dec 30 14:15:22 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-getopt.c (mi_getopt): Rewrite.  Allow long options.
+       * mi-getopt.h (struct mi_opt): Declare.
+       (mi_getopt): Update.
+
+       * mi-main.c (mi_cmd_data_read_memory), mi-cmd-break.c
+       (mi_cmd_break_insert, mi_cmd_break_watch): Update.
+
+Wed Dec 29 23:38:35 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmd-break.c (mi_cmd_break_insert): Add support for -c
+       <condition>, -i <ignore-count> and -p <thread>.
+       (breakpoint_notify): New function.
+       (mi_cmd_break_insert): Wrap GDB call with callback hooks so that
+       MI is notified when ever a breakpoint is created.
+
+       * gdbmi.texinfo: Update.
+
+Fri Dec 24 11:23:22 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (gdb_do_disassemble): Strip out more useless #ifdef
+       UI_OUTs.
+
+1999-12-23  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (gdb_do_disassemble): Fix output. Lines that have no
+       assembly instructions must still be outputted, to keep the source
+       line numbering correct.
+       Remove #ifdef UI_OUT's, they are useless.
+
+1999-12-17  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (gdb_do_disassemble): Don't print a new list in mixed
+       mode, every time. Just do it when we actually encounter a new
+       source line.
+
+1999-12-17  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-cmd-var.c (mi_cmd_var_list_children): Add test for C++ pseudo
+       variable objects (private, public, protected) as these do not have
+        a type and the -var-list-children operation was dumping core.
+       
+Fri Dec 17 20:23:33 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * gdbmi.texinfo: Document recommended syntax for options.
+
+       * mi-main.c (mi_cmd_data_read_memory): Add support for ``-o
+       <offset>''.
+       * gdbmi.texinfo: Document.
+       
+Wed Dec 15 17:43:08 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-getopt.h (mi_getopt): Change optarg to a char pointer. Check
+       optind.
+       * mi-cmd-break.c (mi_cmd_break_insert): Update.
+
+       * mi-main.c (mi_cmd_data_read_memory): Add fields "next-row-addr",
+       "prev-row-addr", "next-page-addr", "prev-page-addr" and a per row
+       "addr".
+       * gdbmi.texinfo: Update.
+
+Wed Dec 15 01:05:40 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmds.h (mi_cmd_result): Add MI_CMD_CAUGHT_ERROR for when the
+       error is caught.
+
+       * mi-main.c (captured_mi_execute_command): When
+       MI_CMD_CAUGHT_ERROR return 0 rethrowing the eror.
+
+1999-12-13  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmd-break.c (mi_cmd_break_insert): Remove unused var.
+
+       * mi-cmd-var.c (mi_cmd_var_update): Remove unused variables.
+
+Mon Dec 13 18:43:36 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-parse.c (mi_parse): Quote the command when printing it.
+       (mi_parse_argv): Fix handling of quoted strings. Was not
+       de-quoting them.
+       (mi_parse_argv): Make static.
+
+Mon Dec 13 18:30:03 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmds.h (mi_cmd_break_insert, mi_cmd_break_watch): Change type
+       to mi_cmd_argv_ftype.
+       * mi-cmds.c (mi_cmds): Update.
+       * mi-cmd-break.c (mi_cmd_break_insert, mi_cmd_break_watch): Change
+       to new style of arguments with argc and argv.  Parse arguments
+       using mi_getopt.
+
+       * mi-cmd-break.c (mi_cmd_break_insert): Wrap body in #ifdef UI_OUT
+       to avoid non-ui compile problems.
+
+Mon Dec 13 15:08:36 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-getopt.h, mi-getopt.c: New files. Similar to getopt but with
+       well defined semantics.
+       
+Mon Dec 13 14:22:21 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_cmd_break_insert, mi_cmd_break_watch, enum
+       wp_type, enum bp_type): Move from here.
+       * mi-cmd-break.c: To here.  New file.
+       (mi_cmd_break_insert, mi_cmd_break_insert, mi_cmd_break_watch):
+       Use error to report problems.
+
+1999-12-09  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Update description of exec-interrupt.
+
+       * mi-main.c (mi_cmd_exec_interrupt): If the program is not
+       executing, don't try to interrupt it, but error out instead.  Make
+       sure previous_async_command is not null before duplicating it into
+       last_async_command.
+
+       * gdbmi.texinfo: Add examples for data-evaluate-expression.
+
+1999-12-08  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmd-var.c (mi_cmd_var_assign, mi_cmd_var_create,
+       mi_cmd_var_delete, mi_cmd_var_evaluate_expression,
+       mi_cmd_var_info_expression, mi_cmd_var_info_num_children,
+       mi_cmd_var_info_type, mi_cmd_var_list_children,
+       mi_cmd_var_set_format, mi_cmd_var_show_attributes,
+       mi_cmd_var_show_format, mi_cmd_var_update): Change to use new
+       style of arguments with argc and argv.
+       (next_arg): Delete.
+       (which_var): Delete.
+
+       * mi-cmds.c (mi_cmds): Update entries for mi_cmd_var_assign,
+       mi_cmd_var_create, mi_cmd_var_delete,
+       mi_cmd_var_evaluate_expression, mi_cmd_var_info_expression,
+       mi_cmd_var_info_num_children, mi_cmd_var_info_type,
+       mi_cmd_var_list_children, mi_cmd_var_set_format,
+       mi_cmd_var_show_attributes, mi_cmd_var_show_format,
+       mi_cmd_var_update.
+
+       * mi-cmds.h (mi_cmd_var_assign, mi_cmd_var_create,
+       mi_cmd_var_delete, mi_cmd_var_evaluate_expression,
+       mi_cmd_var_info_expression, mi_cmd_var_info_num_children,
+       mi_cmd_var_info_type, mi_cmd_var_list_children,
+       mi_cmd_var_set_format, mi_cmd_var_show_attributes,
+       mi_cmd_var_show_format, mi_cmd_var_update): Update declarations.
+
+1999-12-08  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Comment out -data-assign command.  * mi-main.c
+       (mi_cmd_data_assign): Do not use, comment out.  * mi-cmds.h
+       (mi_cmd_data_assign): Remove.  * mi-cmds.c: Remove -data-assign
+       command from MI interface.
+
+1999-12-07  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-parse.c (mi_parse): Add '\n' at end of error messages, so
+       that prompt comes out on new line.
+
+       * gdbmi.texinfo: Update disassembly command output.
+
+1999-12-06  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (gdb_do_disassemble): Update output for UI_OUT case.
+
+1999-12-02  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Update exec-until output, including the reason
+       for stopping.
+
+Thu Dec  2 17:17:22 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmds.c: Include <string.h> for memset.
+
+1999-12-01  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_exec_return): ifdef the references to
+       return_command_wrapper().
+       
+1999-12-01  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_gdb_exit, mi_cmd_exec_interrupt,
+       mi_cmd_target_select, mi_execute_async_cli_command,
+       mi_exec_async_cli_cmd_continuation, mi_load_progress): Don't print
+       last_async_command if it is NULL.
+       (mi_cmd_exec_return): 
+
+1999-12-01  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_exec_return): Reimplement using
+       return_command() instead of mi_execute_async_cli_command().
+
+1999-12-01  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.h: Export mi_cmd_data_assign and
+       mi_cmd_data_evaluate_expression.
+
+       * mi-cmds.c (mi_cmds): Hook data-assign to mi_cmd_data_assign and
+       data-evaluate-expression to mi_cmd_data_evaluate_expression.
+
+       * mi-main.c (mi_cmd_data_assign): New function. Implement
+       data-assign command.
+       (mi_cmd_data_evaluate_expression): New function. Implement
+       data-evaluate-expression command.
+
+1999-12-01  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Fix some texinfo formatting errors.
+
+1999-12-01  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Update data-list-register-values description.
+
+       * mi-cmds.h: Export mi_cmd_data_list_register_values.
+
+       * mi-cmds.c (mi_cmds): Hook data-list-register-values to
+       mi_cmd_data_list_register_values.
+
+       * mi-main.c (mi_cmd_data_list_register_values): New
+       function. Implements the -data-list-register-values command.
+       (get_register): New function. Output the contents of a given
+       register.
+
+Wed Dec  1 20:27:22 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_execute_async_cli_command): Append missing "\n"
+       for synchronous stopped message.
+
+1999-11-30  James Ingham  <jingham@leda.cygnus.com>
+
+       * gdbmi.texinfo: Fix obvious typo in @end statement.
+
+Wed Dec  1 12:36:27 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmd-var.c: Include "value.h".
+       * mi-console.c: Include <string.h>.
+
+Wed Dec  1 00:21:03 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (captured_mi_execute_command): For a CLI command, pass
+       "%s" to mi_execute_cli_command to stop core dumps.
+       (captured_mi_execute_command): Echo CLI commands on gdb_stdlog.
+
+Wed Dec  1 00:10:07 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * gdbmi.texinfo: Explain NR-BYTES and ADDR.
+
+Tue Nov 30 23:31:57 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmd-var.c (mi_cmd_var_create, mi_cmd_var_delete,
+       mi_cmd_var_set_format, mi_cmd_var_show_format,
+       mi_cmd_var_info_num_children, mi_cmd_var_list_children,
+       mi_cmd_var_info_type, mi_cmd_var_info_expression,
+       mi_cmd_var_show_attributes, mi_cmd_var_evaluate_expression,
+       mi_cmd_var_assign, mi_cmd_var_update, varobj_update_one, next_arg,
+       which_var): New file.  Move varobj commands to here from
+       mi-main.c.
+
+       * mi-console.h, mi-console.c (mi_console_file_new,
+       mi_console_file_delete, mi_console_file_fputs,
+       mi_console_raw_packet, mi_console_file_flush): New files. Move
+       mi_console_file to here from mi-main.c.
+
+Tue Nov 30 19:37:25 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (captured_mi_execute_command): Use fputstr_unfiltered
+       when printing error messages.
+       (mi_cmd_execute): Ditto.
+
+1999-11-29  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Describe -data-list-changed-registers,
+       -data-list-register-names. Add examples for
+       -exec-next-instruction, exec-step-instruction, -exec-run,
+       -exec-until.  Format examples for -data-read-memory.
+       update example for -target-download.
+       
+1999-11-29  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Remove mentioning of inaccurate watchpoint hit
+       count.
+       
+Mon Nov 29 19:28:55 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_execute_async_cli_command): Return ``enum
+       mi_cmd_cmd_result''.  mi_cmd_exec_run, mi_cmd_exec_next,
+       mi_cmd_exec_step, mi_cmd_exec_step_instruction,
+       mi_cmd_exec_finish, mi_cmd_exec_until, mi_cmd_exec_return,
+       mi_cmd_exec_continue): Update call.
+       (mi_execute_async_cli_command): When target is synchronous, fake
+       asynchronous behavour (ulgh).  Allows tests to be run on built-in
+       simulator and native targets.
+
+Mon Nov 29 15:15:16 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmds.h (mi_cmd_gdb_exit), mi-cmds.c (mi_cmds), mi-main.c
+       (mi_cmd_gdb_exit): Change function signature to mi_cmd_argv_ftype.
+
+1999-11-28  Andew Cagney  <cagney@rat-in-a-hat.cygnus.com>
+
+       * mi-parse.c: Include <ctype.h> and <string.h>
+
+1999-11-26  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * gdbmi.texinfo: Added watchpoint command descriptions and
+       examples.
+
+       * mi-main.c (mi_load_progress): Add parameter for total sent so far.
+       Print it as well.
+       
+Fri Nov 26 10:17:49 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * gdbmi.texinfo (section Output Syntax): For lists, the <string>
+       part of a <result> is optional.  Clarify syntax.
+       (appendix Proposed v2.0 Output Syntax): New section. Provide
+       record of discussion of possible changes to syntax.
+
+Wed Nov 24 19:41:35 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_cmd_data_read_memory): Simplify.  Fix coredump
+       when arguments were bad.
+       (mi_cmd_execute): Change parameter to ``struct mi_parse''.  Handle
+       case of argv_func as well as args_func.
+       (captured_mi_execute_command): Update.
+
+       * mi-cmds.c (struct mi_cmd): Add field for mi_cmd_argv_ftype.
+       (mi_cmds): Update mi_cmd_data_read_memory.
+       (mi_lookup): Return 
+
+       * mi-cmds.h (mi_cmd_args_ftype): Rename mi_cmd_ftype. Make all
+       functions of type this type.
+       (mi_cmd_argv_ftype): Declare.
+       (mi_cmd_data_read_memory): Change type to mi_cmd_argv_fytpe.
+       (struct mi_cmd): Move declaration to here from mi-cmds.c.
+       (mi_lookup): Return a pointer to ``struct mi_cmd''.
+       
+Wed Nov 24 15:03:34 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-parse.c (mi_parse): Initialize TOKEN when a CLI command.
+
+       * gdbmi.texinfo: Allow a <token> before a CLI command.
+
+       * mi-parse.h (struct mi_parse): Declare.
+       (mi_parse): Change to return a ``struct mi_parse''.
+       (enum mi_command_type): Delete PARSE_ERROR.
+
+       * mi-main.c (struct mi_execute_command_context): Delete.
+       (captured_mi_execute_command): Update
+       (mi_execute_command): Update.  Check for mi_parse returning NULL.
+
+Wed Nov 24 12:57:14 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-parse.h: Remove const, from cmd parameter.  Causes cascading
+       warnings.
+
+Wed Nov 24 15:03:34 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-parse.c (mi_parse): New function.  Move parse code to here.
+       * mi-main.c (parse): From here. Delete.
+
+Wed Nov 24 12:57:14 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-parse.c, mi-parse.h: New files. Implement mi_parse_env.
+
+Wed Nov 24 11:24:05 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-out.c (mi_field_string): Make string parameter constant.
+
+1999-11-23  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.h (mi_cmd_target_download): Export. 
+
+       * mi-cmds.c (mi_cmds): Add mi_cmd_target_download.
+
+       * mi-main.c: Include <sys/time.h>.
+       (mi_cmd_target_download): New function, implement the
+       target-download command.
+       (mi_load_progress): New function. Called via the
+       show_load_progress hook. Prints updates every 0.5 secs.
+       (mi_command_loop): Initialize the show_load_progress hook.
+
+1999-11-22  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_exec_until): New function. Implement until
+       command.
+       (mi_cmd_exec_step_instruction): New function. Implement stepi
+       command.
+       (mi_cmd_exec_next_instruction): New function. Implement nexti
+       command.
+       
+       * mi-cmds.c (mi_cmds): Add mi_cmd_exec_step_instruction,
+       mi_cmd_exec_next_instruction, mi_cmd_exec_until.
+
+       * mi-cmds.h (mi_cmd_exec_step_instruction,
+       mi_cmd_exec_next_instruction, mi_cmd_exec_until): Export.
+       
+Tue Nov 23 00:30:37 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi/gdbmi.texinfo: Document -data-read-memory.
+       
+       * mi-main.c (mi_cmd_data_read_memory): Fix off-by-one check of
+       argc.
+       (mi_cmd_data_read_memory): Label the output table with "memory".
+
+Thu Nov 18 18:15:53 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_cmd_exec_interrupt, mi_cmd_break_insert,
+       mi_cmd_break_watch, mi_cmd_disassemble, mi_cmd_execute): Replace
+       strdup with xstrdup.
+
+Thu Nov 18 20:50:09 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_cmd_data_read_memory): New function.  Implement
+       data-read-memory.
+
+       * mi-cmds.h, mi-cmds.c: Add mi_cmd_data_read_memory.
+       * mi-cmds.c (mi_cmds): Ditto.
+
+1999-11-11  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.h (mi_cmd_break_watch): Export.
+
+       * mi-cmds.c (mi_cmds): Hook up break-watch to function
+       mi_cmd_break_watch.
+
+       * mi-main.c (wp_type): New enumeration for the possible types of
+       watchpoints.
+       (mi_cmd_break_watch): New function, implements the break-watch
+       command.
+
+1999-11-11  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_break_insert): Handle case in which the command is
+       just a -break-insert w/o args.
+
+Fri Nov 12 00:01:52 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-out.c (mi_field_string): Always quote the string.
+
+1999-11-10  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.h(mi_cmd_data_list_changed_registers,
+       mi_cmd_data_list_register_names): Export.
+
+       * mi-cmds.c (mi_cmds): Hook up data-list-changed-registers to
+       mi_cmd_data_list_changed_registers and data-list-register-names to
+       mi_cmd_data_list_register_names.
+
+       * mi-main.c (mi_cmd_data_list_changed_registers): New function,
+       implements the data-list-changed-registers command.
+       (mi_cmd_data_list_register_names): New function, implements the
+       data-list-register-names command.
+       (register_changed_p): New function. Decide whether the register
+       contents have changed.
+       (setup_architecture_data): New function. Initialize registers
+       memory.
+       (_initialize_mi_main): Call setup_architecture_data(), and
+       register_gdbarch_swap().
+
+Wed Nov 10 18:35:08 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_execute_command): Correctly quote error messages.
+
+Wed Nov 10 11:05:14 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi/gdbmi.texinfo: Delete <stream-output>.  Replaced by
+       <c-string>.
+
+       * mi-main.c (mi_console_raw_packet): Always quote console output.
+
+Tue Nov  9 17:53:05 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_console_file_new), mi-out.c (mi_out_new): Replace
+       the tui_file with a mem_file. Ya!
+       
+       * mi-out.c (do_write): New function, wrapper to gdb_file_write.
+       (mi_out_put): Pass do_write to gdb_file_put.
+
+       * mi-main.c (mi_console_file_flush): Rewrite.  Use
+       mi_console_raw_packet to send data to the console.
+       (mi_console_raw_packet): New function. Correctly
+       create quoted C string packets.
+
+1999-11-08  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.c (mi_cmds): Break-insert is now implemented by
+       mi_cmd_break_insert.
+       * mi-cmds.h (mi_cmd_break_insert): Export. 
+       * mi-main.c (bp_type): New enumeration.
+       (mi_cmd_break_insert): New function. Implements all flavors of
+       breakpoint insertion.
+
+Mon Nov  8 17:49:17 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_console_file_flush): Replace gdb_file_get_strbuf
+       with tui_file_get_strbuf.
+
+Fri Nov  5 17:06:07 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_console_file_delete, mi_console_file_fputs,
+       mi_console_file_flush): Call internal_error instead of error.
+
+Thu Nov  4 19:53:32 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (captured_mi_execute_command): New function.
+       (mi_execute_command): Rewrite.  Replace SET_TOP_LEVEL() with call
+       to captured_mi_execute_command via catch_errors.
+
+Thu Nov  4 20:33:58 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (clean): Delete.
+       (mi_command_loop): Delete extern declaration of
+       mi_execute_command.
+
+1999-10-28  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_stack_select_frame): Conditionalize the body
+       on UI_OUT, because select_frame_command_wrapper is only defined if
+       UI_OUT is.
+       (mi_cmd_exec_interrupt): Conditionalize the body on UI_OUT,
+       because interrupt_target_command_wrapper is only defined if UI_OUT is.
+
+       * mi-cmds.c (mi_cmds): Implement command exec-interrupt by
+       mi_cmd_exec_interrupt.  
+
+       * mi-main.c (mi_cmd_exec_interrupt): New function. Implements
+       exec-interrupt command.
+       (mi_cmd_execute): If the target is running save execution command
+       token in previous_async_command. If the command is not 'interrupt' 
+       and the target is running, reject it.
+       (clean): New function. Free the arg and reset it to NULL.
+
+       * mi-cmds.h (mi_cmd_exec_interrupt):Export.
+
+1999-10-28  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.c (mi_cmds): Implement command stack-select-frame by
+       mi_cmd_stack_select_frame.  
+
+       * mi-main.c (mi_cmd_stack_select_frame): New function. Implements
+       stack-select-frame command.
+
+       * mi-cmds.h (mi_cmd_select_frame):Export.
+
+1999-10-26  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.c (mi_cmds): Implement commands stack-list-locals and
+       stack-list-arguments by mi_cmd_stack_list_locals and
+       mi_cmd_stack_list_args.
+
+       * mi-main.c (mi_cmd_stack_list_locals): New function. Implements
+       stack-list-locals command.
+       (mi_cmd_stack_list_args): New function. Implements
+       stack-list-arguments command.
+       (list_args_or_locals): New function. Do all the work for the
+       listing of locals or arguments.
+
+       * mi-cmds.h (mi_cmd_stack_list_args,mi_cmd_stack_list_locals) :
+       Export.
+
+1999-10-25  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-cmds.c (mi_cmds): Add new command stack-info-depth.
+
+       * mi-main.c (mi_cmd_stack_info_depth): New function. Implements
+       the stack-info-depth command.
+       * mi-cmds.h (mi_cmd_stack_info_depth): Export.
+
+
+1999-10-22  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_execute_command): Handle MI_CMD_ERROR case
+       properly, for command that return error code and don't set
+       mi_error_message.
+
+       * mi-cmds.c (mi_cmds): Hook stack-list-frames command to
+       mi_cmd_stack_list_frames function.
+       * mi-cmds.h (mi_cmd_stack_list_frames): Export.
+       
+       * mi-main.c (mi_execute_command): Deal with a return code of
+       MI_CMD_ERROR from the execution of mi commands.
+       (mi_error_message): Static string variable, to contain the error
+       message from mi commands.
+       (mi_cmd_stack_list_frames): New function. Prints a backtrace.
+
+1999-10-18  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_disassemble): Handle the new command line
+       parameter that specifies the number of disassembly lines to be
+       displayed.
+       (gdb_do_disassemble): Add new parameter. Count the number of lines
+       that have been displayed, and stop when limit is reached.
+
+Wed Oct 13 18:04:13 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_command_loop): Don't initialize ``flush_hook''.
+
+1999-10-13  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi/gdbmi.texinfo: More reformatting of the grammars.
+
+1999-10-12  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi/gdbmi.texinfo: More TeX formatting.
+
+1999-10-11  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi/gdbmi.texinfo: First pass completed. All commands should have
+       some comments/info.
+       Escape '@' output special char.
+       Reformat for TeX.
+
+1999-10-08  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi/gdbmi.texinfo: Filled in part of file command section, and
+       stack section.
+
+1999-10-07  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi/gdbmi.texinfo: Filled in some sections about execution
+       commands.
+
+Tue Oct  5 15:27:28 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmds.h: Sort table
+       * mi-cmds.c: Ditto.
+       (MI_TABLE_SIZE): Increase to 251.
+
+1999-10-04  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_cmd_var_create, mi_cmd_var_delete): Add missing
+       cleanups.
+       
+1999-10-04  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (next_arg): Returns lenght as well.
+       (which_var, mi_cmd_var_create, mi_cmd_var_delete,
+       mi_cmd_var_set_format, mi_cmd_var_update): Do not modify the input
+       string, use allocated storage instead.
+       (mi_cmd_var_assign): Adjust call to next_arg() to include new
+       argument.
+
+1999-10-04  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_execute_command): Fix handling of errors.
+
+1999-10-04  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-out.c (mi_out_new): Call tui_sfileopen() instead of
+        deprecated gdb_file_init_astream().
+       * mi-main.c (mi_console_file_new): Ditto.
+
+Mon Oct  4 15:17:29 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmds.h: Sort function declarations.
+       (mi_lookup): Add extern.
+
+       * mi-cmds.c (mi_lookup): Delete dead code.
+       (build_table): Call  internal_error instead of error.
+       (build_table): Send trace output to gdb_stdlog.
+
+1999-10-01  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_execute_async_cli_command): Don't do the cleanups
+       if target_executing is null.
+
+1999-09-28  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (async_p): Change var name to event_loop_p.
+
+Mon Sep 27 15:11:00 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_execute_async_cli_command, mi_execute_command):
+       Replace target_has_async with function target_can_async_p.
+
+Sun Sep 26 00:12:52 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_cmd_target_select_continuation): Delete function.
+       (mi_cmd_target_select): Simplify.  target-connect is guarenteed to
+       be synchronous.
+
+Sun Sep 26 00:12:52 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmds.h (mi_cmd_ftype): Replace mi_impl_ftype.
+       (enum mi_cmd_result): Define.
+       * mi-cmds.c (struct mi_cmd): Update.
+       (mi_lookup): Update.
+       * mi-main.c (mi_cmd_execute): Update.
+
+       * mi-main.c (mi_cmd_gdb_exit, mi_cmd_exec_run, mi_cmd_exec_next,
+       mi_cmd_exec_step, mi_cmd_target_select, mi_cmd_exec_continue,
+       mi_cmd_exec_return, mi_cmd_exec_finish, mi_cmd_disassemble,
+       mi_cmd_var_create, mi_cmd_var_delete, mi_cmd_var_set_format,
+       mi_cmd_var_show_format, mi_cmd_var_info_num_children,
+       mi_cmd_var_list_children, mi_cmd_var_info_type,
+       mi_cmd_var_info_expression, mi_cmd_var_show_attributes,
+       mi_cmd_var_evaluate_expression, mi_cmd_var_update): Update.
+       Return MI_CMD_DONE.
+
+1999-09-22  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_cmd_var_create): Use paddr() to format address
+       on trace output.
+
+1999-09-21  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_cmd_var_create): Test for varobjdebug before
+       printing trace and send it to gdb_stdlog.
+
+Mon Sep 20 13:41:04 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * Makefile.in (mi-out.o): Add dependency list.
+       * mi-out.c: Include "mi-out.h".
+
+1999-09-18  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (_initialize_mi_main): Events on stadin are now
+       handled by stdin_event_handler.
+
+1999-09-17  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-cmds.c (mi_cmds): Add var-* commands.
+
+1999-09-17  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_cmd_var_create, mi_cmd_var_delete,
+       mi_cmd_var_set_format, mi_cmd_var_show_format,
+       mi_cmd_var_info_num_children, mi_cmd_var_list_children,
+       mi_cmd_var_info_type, mi_cmd_var_info_expression,
+       mi_cmd_var_show_attributes, mi_cmd_var_evaluate_expression,
+       mi_cmd_var_assign, mi_cmd_var_update, varobj_update_one,
+       which_var, next_arg): New functions.  Implement the -var-*
+       commands.
+       * mi-cmds.h: Add prototypes for the above.
+
+1999-09-14  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-cmds.c (mi_cmds): Add detach command.
+
+1999-09-09  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-cmds.c (lookup_table): Fix typo.
+
+1999-09-09  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-cmds.c (mi_cmds): Fix typo and missing command.
+
+1999-09-09  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c: Properly align function prototypes.
+       (mi_cmd_target_select): Proper check for NULL value.
+
+1999-09-09  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_execute_async_cli_command): Fix for native targets
+       that do not have async yet.
+
+1999-09-01  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_disassemble): Remove unused var.
+       (gdb_do_disassemble): Ditto.
+
+1999-08-30  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c: Replace all the occurrences of 'asynch' in variable
+       or function names with 'async' to make it consistent with the rest
+       of gdb.
+
+Mon Aug 30 18:16:39 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c: #include <ctype.h> for isspace().
+
+1999-08-27  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (gdb_do_disassemble): This function returns void, not
+       int.
+
+1999-08-26  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_disassemble): Don't use atoi() on the high
+       address string, just treat it same as address low.
+       (gdb_do_disassemble): Parse high_address string before seeing if
+       it is zero.
+
+1999-08-25  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_disassemble): New function to produce
+       disassembly output for mi.
+       (gdb_dis_asm_read_memory): New function. Read the disassembly from
+       the executable file, instead of target memory.
+       (compare_lines): New function. Compare order of disassembly lines.
+       (gdb_do_disassemble): New function. Do the real job of getting the
+       assembly code out.
+
+       * mi-cmds.c (mi_cmds): Do data-disassemble mi command via the
+       mi_cmd_disassemble function.
+
+       * mi-cmds.h: Export new function mi_cmd_disassemble.
+
+Wed Aug 25 15:58:31 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_command_loop): Remove references to ui-hooks.
+
+1999-08-21  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_execute_asynch_cli_command): Fix the incorrect
+       usage of strcat(): allocate enough space for the string.
+
+1999-08-13  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       From Christopher Faylor <cgf@cygnus.com>
+       * mi-main.c (mi_execute_command): Make sure we flush all the
+       output after each command.
+
+1999-08-10  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (_initialize_mi_main): Remove casting in call to
+       add_file_handler.
+
+Sun Aug  8 17:20:57 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_cmd_target_select, mi_execute_asynch_cli_command):
+       Replace call to fatal with call to internal_error.
+
+1999-07-26  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_cmd_execute): Add return code.
+       (mi_execute_command): Make appropriate changes when calling the
+       function mentioned above.
+       (mi_cmd_gdb_exit, mi_cmd_target_select,
+       mi_cmd_target_select_continuation, mi_execute_command,
+       mi_exec_asynch_cli_cmd, mi_exec_asynch_cli_cmd_continuation):
+       Print token, prefix, class and output (if any) in one single group
+       of statements.
+       (mi_execute_command, mi_cmd_execute): Fix error prefix.
+       (mi_cmd_execute): Use exec cleanup for token.
+       * mi-out.c (mi_out_rewind): New function.
+       * mi-out.h: Prototype for the above.
+
+1999-07-16  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_cmd_gdb_exit): Use buffer for exit message.
+       (mi_cmd_execute): Route error messages to correct file.
+       (mi_execute_asynch_cli_command): Insert line feed after running
+       message.
+
+1999-07-16  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-out.h (mi_out_buffered): Add extern declaration.
+       * mi-out.c (mi_out_buffered): New function. Insert a string at the
+       current buffer position.
+       * mi-main.c (mi_cmd_target_select, mi_execute_command,
+       mi_cmd_execute, mi_execute_asynch_cli_command): Use the above
+       function instead of printing to raw_stdout.
+       (mi_cmd_target_select, mi_cmd_target_select_continuation,
+       mi_execute_command, mi_cmd_execute, mi_execute_cli_command,
+       mi_exec_asynch_cli_cmd_continuation): Fix handling of token and
+       prefix.
+       (mi_execute_cli_command): Remove parameter no longer needed.
+
+1999-07-15  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c (mi_cmd_target_select_continuation): Print the numeric
+       token when we are connected.
+       (mi_execute_command): Don't print the token now, do it later.
+       (mi_execute_cli_command): Add a new parameter for the numeric
+       token.  Print the token, the prefix and the class after the
+       command has executed, not before.
+       (mi_execute_asynch_cli_command): Don't print an extra blank line.
+
+1999-07-15  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_gdb_exit): Add \n at the end.
+
+1999-07-15  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_cmd_execute): New function. Dispatch a mi operation.
+       (mi_execute_command): Use the above.
+
+1999-07-15  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c: Fix identation.
+
+1999-07-15  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * mi-main.c: Include target.h and inferior.h.
+       (mi_cmd_target_select): New function to execute the target-select
+       mi operation.
+       (mi_cmd_target_select_continuation): New function. Continuation
+       for the target-select operation.
+       (mi_execute_command): In case of an MI command which requires
+       asynchronous execution, do not try to display the result now. If
+       the execution has to look synchronous don't display the "(gdb)"
+       prompt.
+       (mi_execute_asynch_cli_command): Invoke real asynchronous
+       commands, set up exec_cleanups, and continuations.
+       (mi_exec_asynch_cli_cmd_continuation): New function. Continuation
+       for all the MI execution commands except 'target-select'.
+       (mi_execute_command): Handle null commands by exiting gdb, instead
+       of core dumping.
+
+       * mi-cmds.c (mi_cmds): Hook up -target-select operation to new mi
+       function.
+
+       * mi-cmds.h (mi_cmd_target_select): Add extern declaration.
+
+Thu Jul 15 10:31:39 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (struct mi_console_file): Add field ``prefix''.
+       (mi_console_file_new): Add argument prefix.  Initialize prefix
+       field.
+       (mi_console_file_flush): Use ``prefix'' instead of "~" as the
+       prefix string.
+       (mi_command_loop): Update stream output prefixes. gdb_stdout ==
+       "~", gdb_stderr / gdb_stdlog == "&", gdb_stdtarg == "@".
+
+1999-07-13  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (ui_out_data): New field first_header. Fix output when
+       no breakpoints are found.
+       (mi_table_begin, mi_table_body, mi_table_header): Test for
+       first_header.
+       (mi_table_end): Test for supress_field_separator.
+       (mi_message): Remove messages from MI output.
+
+1999-06-30  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-cmds.c (mi_cmds[]): Delete gdb-cli operation.
+       * mi-main.c (parse): Remove ifdefs for cli commands parsing.
+       (mi-execute-command): Ditto.
+
+Mon Jun 28 13:06:52 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-out.h: New file.
+       (mi_out_new, mi_out_put): Move mi specific delcarations to here.
+       * ui-out.h: From here.
+
+       * mi-main.c: Include "mi-out.h".
+
+1999-06-25  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * top.c (print_gdb_version): Add the word HEADLESS when output
+       follows headless format.
+       (print_command_lines): Fix typo.
+
+1999-06-25  Elena Zannoni  <ezannoni@kwikemart.cygnus.com>
+
+       * event-loop.h: Export input_fd.  
+       * mi-main.c (mi_command_loop): Use the event loop if running
+       asynchronously.
+       (mi_execute_command_wrapper): New function.
+       (_initialize_mi-main): Set things up for running asynchronously.
+
+1999-06-18  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+        * mi-cmds.c (mi_lookup): Deleted.
+        (lookup_table): New function. Replaces old mi_lookup() for local
+        use.
+        (mi_lookup): New function. External interface for command table
+        searchs.
+        (build_table): New definition.
+        (mi_cmds[]): Add several command implementations and the gdb-cli
+        special operation.
+        (mi_cmd_execute): Deleted.
+        * mi-cmds.h: Add type definition for command implementation
+        function pointers, add declaration for new implementation
+        functions and a declaration for mi_lookup().
+        * mi-main.c (mi_execute_asynch_cli_command): New
+        function. Captures code that was repeated for all asynch
+        operations.
+        (mi_cmd_exec_*): Use the above new function.
+        (mi_gdb_cmd_exit): Fix the output, printing something appropriate.
+        (mi_cmd_exec_finish): New operation implementation function.
+        (mi_cmd_exec_return): Ditto.
+        (parse): Prepare to remove cli commands.
+        (mi_execute_command): Fix the output and change the way mi-cmds is
+        used.
+
+1999-06-18  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+        * mi-out.c (mi_table_begin): Add missing field separator call.
+
+Thu Jun 17 21:05:40 1999  Fernando Nasser  <fnasser@tofu.to.cygnus.com>
+
+       * breakpoint.c (breakpoint_1): Remove space in breakpoint table
+       id.
+       (mention): Use ui_out for last new line (forgotten).
+
+1999-06-16  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c (mi_console_file_flush): Prevent prefix printing when
+       buffer empty; change prefix to '~'.
+       (mi_cmd_exec_*): Prefix normal output with '^' instead of
+       ','; remove unwanted new lines before "stopped".
+
+1999-06-16  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-cmds.c (struct mi_cmds): Updated entries for -exec-continue
+       and exec-next operations.
+       (mi_cmd_execute): New text for error messages.
+       * mi-cmds.h: Add declaration for mi_cmd_exec_next and
+       mi_cmd_exec_continue.
+       * mi-main.c (mi_cmd_exec_next): New function. Implements exec-next
+       operation.
+       (mi_cmd_exec_continue): New function. Implements exec-continue
+       operation.
+       (mi_execute_comand): Add missing space to prompt.
+       (mi_cmd_exec_run): Ditto.
+       (mi_cmd_exec_step): Ditto.
+       * mi-out.c (mi_out_new): Add flags argument to ui_out_new call.
+       (ui_list_end): Reset supress_field_separator flag.
+
+Sat Jun 12 11:49:10 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmds.h. mi-cmds.c (exec step): Command implemented by
+       mi_cmd_exec_step instead of cli call.
+       * mi-main.c (mi_cmd_exec_step): New function.
+
+       * mi-cmds.h. mi-cmds.c (exec run): Command implemented by
+       mi_cmd_exec_run instead of cli call.
+       * mi-main.c (mi_cmd_exec_run): New function.
+
+       * mi-cmds.h. mi-cmds.c (gdb exit): Command implemented by
+       mi_cmd_gdb_exit instead of quit_force.
+       * mi-main.c (mi_cmd_gdb_exit): New function.
+
+Sat Jun 12 11:33:23 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_command_loop): Pass mi_input to
+       simplified_command_loop.
+       (mi_input): New function.  Calls gdb_readline with no prompt.
+
+Sat Jun 12 11:19:02 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_console_file_fputs): Re-implement.  Use a buffer
+       to accumulate output.
+
+       * mi-main.c (struct mi_console_file): Add a buffer.
+       (mi_console_file_new): Create a buffer.
+       (mi_console_file_flush): New function.
+
+Sat Jun 12 10:59:39 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-cmds.h (raw_stdout): Declare.  Will be moved later.
+       * mi-cmds.c (mi_cmd_execute): Send error messages to RAW stdout.
+       (mi_cmds): Sort by class.
+
+       * mi-main.c (raw_stdout): Make global.
+       * mi-main.c: Remove #ifdef UI_OUT.  File assumes UI_OUT is
+       present.
+       * mi-main.c: Include "gdb_string.h".
+       (mi_out_put): Delete declaration.
+
+1999-06-11  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-main.c: Add pre-processor test for UI_OUT.
+       (mi_execute_command): Add pre-processor test for UI_OUT.
+
+Fri Jun 11 23:11:41 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (raw_stdout): New variable.
+       (mi_execute_command): Write mi-out direct to raw_stdout.
+       (mi_command_loop): Create raw_stdout. Attach gdb_stdout to the
+       console.
+       (mi_console_file_fputs, mi_console_file_delete,
+       mi_console_file_new): New functions.
+       (struct mi_console_file): Declare.
+
+Fri Jun 11 18:34:33 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c (mi_execute_command): Call mi_out_put to display the
+       result.
+       * mi-out.c (mi_out_put): New function.
+       * ui-out.h (mi_out_put): Add declare.  Will move later.
+       * Makefile.in (mi-cmds.o, mi-main.o): Add dependency on ui-out.h.
+
+       * mi-out.c (mi_field_string, mi_field_fmt, mi_message, mi_flush,
+       out_field_fmt, list_open, list_close): Replace gdb_stdout with
+       data->buffer.
+       (field_separator, list_open, list_close): Add uiout parameter.
+       (mi_table_begin, mi_table_body, mi_table_end, mi_list_begin,
+       mi_list_end, mi_field_string, mi_field_fmt, out_field_fmt,
+       out_field_fmt): Update.
+
+       * mi-out.c (mi_out_new): Initialize supress_field_separator.
+       (supress_field_separator): Move into mi-out local data object.
+       (mi_table_begin, mi_list_begin, field_separator): Update.
+
+Fri Jun 11 16:08:37 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-out.c (mi_out_new): New function, replace init_mi_out.
+       * mi-main.c (mi_command_loop): Call mi_out_new().
+
+       * ui-out.h (mi_out_new): Add declaration.  Will move later.
+       (mi_ui_out_impl): Delete.
+
+Wed Jun  9 16:42:16 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * mi-main.c: Include "ui-hooks.h".
+       (mi_init_ui, mi_command_loop): New functions.
+       (_initialize_mi_main): Install ``mi'' as the interpreter when
+       selected.
+
+Mon Jun  7 18:43:43 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       From Fernando Nasser  <fnasser@totem.to.cygnus.com>
+       * mi-cmds.c (build_table): Clean up error message.
+       * mi-cmds.c (mi_cmd_execute), mi-main.c (mi_execute_command): Only
+       print debug information when mi_debug_p.
+       * mi-cmds.h (mi_debug_p), mi-main.c: Global, control debug messages.
+       
+Thu Jun  3 00:44:52 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       From Fernando Nasser  <fnasser@totem.to.cygnus.com>:
+       * mi-cmds.c: Add CLI definitions for "exec-arguments",
+       "exec-next", "gdb-exit", "break-list", "break-info", "exec-step"
+       and "stack-list-frames" to mi_cmds.
+       (struct mi_command): Add ``from_tty'' argument to func.
+       * mi-cmds.h (quit_force): Declare.
+
+1999-05-31  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-out.c (mi_table_end): Remove unwanted "\n".
+
+Thu May 27 14:59:06 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * top.c: Include "ui-hooks.h".
+       (call_interp_loop): Tempoary.  Pass mi_execute_command to
+       simplified_command_loop.  Initialize gdb_stdout & gdb_stderr to
+       stdio gdb_file streams.  Force all hooks to null.
+
+       * mi-cmds.h, mi-main.c, mi-cmds.c: New files.
+       * Makefile.in (SFILES): Add mi-main.c, mi-cmds.c
+       (COMMON_OBS): Add mi-main.o, mi-cmds.o.
+       (mi_cmds_h): Define.
+
+Wed May 26 12:39:49 1999  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * top.c (call_interp_loop): Hack.  Add extern declaration for
+       mi_ui_out_impl.
+
+1999-05-25  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-out.c: New table syntax.
+
+Mon May 24 16:16:29 1999  Andrew Cagney  <cagney@amy.cygnus.com>
+
+       mi-out.c (_initialize_mi_out): Add external declaration.
+
+1999-05-21  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-out.c (mi_table_begin): Added missing parameter.
+
+1999-05-21  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-out.c: Changed table markers and added table id.
+
+1999-05-21  Fernando Nasser  <fnasser@totem.to.cygnus.com>
+
+       * mi-out.c: New file. Implements low-level ui-out primitives for
+       CLI-based interaction.
+
+\f
+Local Variables:
+mode: change-log
+left-margin: 8
+fill-column: 74
+version-control: never
+End:
diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
new file mode 100644 (file)
index 0000000..b4bae47
--- /dev/null
@@ -0,0 +1,309 @@
+/* MI Command Set - stack commands.
+   Copyright 2000, 2002 Free Software Foundation, Inc.
+   Contributed by Cygnus Solutions (a Red Hat company).
+
+   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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "target.h"
+#include "frame.h"
+#include "value.h"
+#include "mi-cmds.h"
+#include "ui-out.h"
+#include "symtab.h"
+
+/* FIXME: these should go in some .h file but stack.c doesn't have a
+   corresponding .h file. These wrappers will be obsolete anyway, once
+   we pull the plug on the sanitization. */
+extern void select_frame_command_wrapper (char *, int);
+
+static void list_args_or_locals (int locals, int values, struct frame_info *fi);
+
+/* Print a list of the stack frames. Args can be none, in which case
+   we want to print the whole backtrace, or a pair of numbers
+   specifying the frame numbers at which to start and stop the
+   display. If the two numbers are equal, a single frame will be
+   displayed. */
+enum mi_cmd_result
+mi_cmd_stack_list_frames (char *command, char **argv, int argc)
+{
+  int frame_low;
+  int frame_high;
+  int i;
+  struct frame_info *fi;
+
+  if (!target_has_stack)
+    error ("mi_cmd_stack_list_frames: No stack.");
+
+  if (argc > 2 || argc == 1)
+    error ("mi_cmd_stack_list_frames: Usage: [FRAME_LOW FRAME_HIGH]");
+
+  if (argc == 2)
+    {
+      frame_low = atoi (argv[0]);
+      frame_high = atoi (argv[1]);
+    }
+  else
+    {
+      /* Called with no arguments, it means we want the whole
+         backtrace. */
+      frame_low = -1;
+      frame_high = -1;
+    }
+
+  /* Let's position fi on the frame at which to start the
+     display. Could be the innermost frame if the whole stack needs
+     displaying, or if frame_low is 0. */
+  for (i = 0, fi = get_current_frame ();
+       fi && i < frame_low;
+       i++, fi = get_prev_frame (fi));
+
+  if (fi == NULL)
+    error ("mi_cmd_stack_list_frames: Not enough frames in stack.");
+
+  ui_out_list_begin (uiout, "stack");
+
+  /* Now let;s print the frames up to frame_high, or until there are
+     frames in the stack. */
+  for (;
+       fi && (i <= frame_high || frame_high == -1);
+       i++, fi = get_prev_frame (fi))
+    {
+      QUIT;
+      /* level == i: always print the level 'i'
+         source == LOC_AND_ADDRESS: print the location and the address 
+         always, even for level 0.
+         args == 0: don't print the arguments. */
+      print_frame_info (fi /* frame info */ ,
+                       i /* level */ ,
+                       LOC_AND_ADDRESS /* source */ ,
+                       0 /* args */ );
+    }
+
+  ui_out_list_end (uiout);
+  if (i < frame_high)
+    error ("mi_cmd_stack_list_frames: Not enough frames in stack.");
+
+  return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_stack_info_depth (char *command, char **argv, int argc)
+{
+  int frame_high;
+  int i;
+  struct frame_info *fi;
+
+  if (!target_has_stack)
+    error ("mi_cmd_stack_info_depth: No stack.");
+
+  if (argc > 1)
+    error ("mi_cmd_stack_info_depth: Usage: [MAX_DEPTH]");
+
+  if (argc == 1)
+    frame_high = atoi (argv[0]);
+  else
+    /* Called with no arguments, it means we want the real depth of
+       the stack. */
+    frame_high = -1;
+
+  for (i = 0, fi = get_current_frame ();
+       fi && (i < frame_high || frame_high == -1);
+       i++, fi = get_prev_frame (fi))
+    QUIT;
+
+  ui_out_field_int (uiout, "depth", i);
+
+  return MI_CMD_DONE;
+}
+
+/* Print a list of the locals for the current frame. With argument of
+   0, print only the names, with argument of 1 print also the
+   values. */
+enum mi_cmd_result
+mi_cmd_stack_list_locals (char *command, char **argv, int argc)
+{
+  if (argc != 1)
+    error ("mi_cmd_stack_list_locals: Usage: PRINT_VALUES");
+
+  list_args_or_locals (1, atoi (argv[0]), selected_frame);
+  return MI_CMD_DONE;
+}
+
+/* Print a list of the arguments for the current frame. With argument
+   of 0, print only the names, with argument of 1 print also the
+   values. */
+enum mi_cmd_result
+mi_cmd_stack_list_args (char *command, char **argv, int argc)
+{
+  int frame_low;
+  int frame_high;
+  int i;
+  struct frame_info *fi;
+
+  if (argc < 1 || argc > 3 || argc == 2)
+    error ("mi_cmd_stack_list_args: Usage: PRINT_VALUES [FRAME_LOW FRAME_HIGH]");
+
+  if (argc == 3)
+    {
+      frame_low = atoi (argv[1]);
+      frame_high = atoi (argv[2]);
+    }
+  else
+    {
+      /* Called with no arguments, it means we want args for the whole
+         backtrace. */
+      frame_low = -1;
+      frame_high = -1;
+    }
+
+  /* Let's position fi on the frame at which to start the
+     display. Could be the innermost frame if the whole stack needs
+     displaying, or if frame_low is 0. */
+  for (i = 0, fi = get_current_frame ();
+       fi && i < frame_low;
+       i++, fi = get_prev_frame (fi));
+
+  if (fi == NULL)
+    error ("mi_cmd_stack_list_args: Not enough frames in stack.");
+
+  ui_out_list_begin (uiout, "stack-args");
+
+  /* Now let's print the frames up to frame_high, or until there are
+     frames in the stack. */
+  for (;
+       fi && (i <= frame_high || frame_high == -1);
+       i++, fi = get_prev_frame (fi))
+    {
+      QUIT;
+      ui_out_tuple_begin (uiout, "frame");
+      ui_out_field_int (uiout, "level", i);
+      list_args_or_locals (0, atoi (argv[0]), fi);
+      ui_out_tuple_end (uiout);
+    }
+
+  ui_out_list_end (uiout);
+  if (i < frame_high)
+    error ("mi_cmd_stack_list_args: Not enough frames in stack.");
+
+  return MI_CMD_DONE;
+}
+
+/* Print a list of the locals or the arguments for the currently
+   selected frame.  If the argument passed is 0, printonly the names
+   of the variables, if an argument of 1 is passed, print the values
+   as well. */
+static void
+list_args_or_locals (int locals, int values, struct frame_info *fi)
+{
+  struct block *block;
+  struct symbol *sym;
+  int i, nsyms;
+  static struct ui_stream *stb = NULL;
+
+  stb = ui_out_stream_new (uiout);
+
+  block = get_frame_block (fi, 0);
+
+  ui_out_list_begin (uiout, locals ? "locals" : "args");
+
+  while (block != 0)
+    {
+      ALL_BLOCK_SYMBOLS (block, i, sym)
+       {
+          int print_me = 0;
+
+         switch (SYMBOL_CLASS (sym))
+           {
+           default:
+           case LOC_UNDEF:     /* catches errors        */
+           case LOC_CONST:     /* constant              */
+           case LOC_TYPEDEF:   /* local typedef         */
+           case LOC_LABEL:     /* local label           */
+           case LOC_BLOCK:     /* local function        */
+           case LOC_CONST_BYTES:       /* loc. byte seq.        */
+           case LOC_UNRESOLVED:        /* unresolved static     */
+           case LOC_OPTIMIZED_OUT:     /* optimized out         */
+             print_me = 0;
+             break;
+
+           case LOC_ARG:       /* argument              */
+           case LOC_REF_ARG:   /* reference arg         */
+           case LOC_REGPARM:   /* register arg          */
+           case LOC_REGPARM_ADDR:      /* indirect register arg */
+           case LOC_LOCAL_ARG: /* stack arg             */
+           case LOC_BASEREG_ARG:       /* basereg arg           */
+             if (!locals)
+               print_me = 1;
+             break;
+
+           case LOC_LOCAL:     /* stack local           */
+           case LOC_BASEREG:   /* basereg local         */
+           case LOC_STATIC:    /* static                */
+           case LOC_REGISTER:  /* register              */
+             if (locals)
+               print_me = 1;
+             break;
+           }
+         if (print_me)
+           {
+             if (values)
+               ui_out_tuple_begin (uiout, NULL);
+             ui_out_field_string (uiout, "name", SYMBOL_NAME (sym));
+
+             if (values)
+               {
+                 struct symbol *sym2;
+                 if (!locals)
+                   sym2 = lookup_symbol (SYMBOL_NAME (sym),
+                                         block, VAR_NAMESPACE,
+                                         (int *) NULL,
+                                         (struct symtab **) NULL);
+                 else
+                   sym2 = sym;
+                 print_variable_value (sym2, fi, stb->stream);
+                 ui_out_field_stream (uiout, "value", stb);
+                 ui_out_tuple_end (uiout);
+               }
+           }
+       }
+      if (BLOCK_FUNCTION (block))
+       break;
+      else
+       block = BLOCK_SUPERBLOCK (block);
+    }
+  ui_out_list_end (uiout);
+  ui_out_stream_delete (stb);
+}
+
+enum mi_cmd_result
+mi_cmd_stack_select_frame (char *command, char **argv, int argc)
+{
+  if (!target_has_stack)
+    error ("mi_cmd_stack_select_frame: No stack.");
+
+  if (argc > 1)
+    error ("mi_cmd_stack_select_frame: Usage: [FRAME_SPEC]");
+
+  /* with no args, don't change frame */
+  if (argc == 0)
+    select_frame_command_wrapper (0, 1 /* not used */ );
+  else
+    select_frame_command_wrapper (argv[0], 1 /* not used */ );
+  return MI_CMD_DONE;
+}
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
new file mode 100644 (file)
index 0000000..9c5e49f
--- /dev/null
@@ -0,0 +1,1011 @@
+/* GDB routines for manipulating objfiles.
+
+   Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002 Free Software Foundation, Inc.
+
+   Contributed by Cygnus Support, using pieces from other GDB modules.
+
+   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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This file contains support routines for creating, manipulating, and
+   destroying objfile structures. */
+
+#include "defs.h"
+#include "bfd.h"               /* Binary File Description */
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "target.h"
+#include "bcache.h"
+
+#include <sys/types.h>
+#include "gdb_stat.h"
+#include <fcntl.h>
+#include "gdb_obstack.h"
+#include "gdb_string.h"
+
+#include "breakpoint.h"
+
+/* Prototypes for local functions */
+
+#if defined(USE_MMALLOC) && defined(HAVE_MMAP)
+
+#include "mmalloc.h"
+
+static int open_existing_mapped_file (char *, long, int);
+
+static int open_mapped_file (char *filename, long mtime, int flags);
+
+static PTR map_to_file (int);
+
+#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */
+
+static void add_to_objfile_sections (bfd *, sec_ptr, PTR);
+
+/* Externally visible variables that are owned by this module.
+   See declarations in objfile.h for more info. */
+
+struct objfile *object_files;  /* Linked list of all objfiles */
+struct objfile *current_objfile;       /* For symbol file being read in */
+struct objfile *symfile_objfile;       /* Main symbol table loaded from */
+struct objfile *rt_common_objfile;     /* For runtime common symbols */
+
+int mapped_symbol_files;       /* Try to use mapped symbol files */
+
+/* Locate all mappable sections of a BFD file. 
+   objfile_p_char is a char * to get it through
+   bfd_map_over_sections; we cast it back to its proper type.  */
+
+#ifndef TARGET_KEEP_SECTION
+#define TARGET_KEEP_SECTION(ASECT)     0
+#endif
+
+/* Called via bfd_map_over_sections to build up the section table that
+   the objfile references.  The objfile contains pointers to the start
+   of the table (objfile->sections) and to the first location after
+   the end of the table (objfile->sections_end). */
+
+static void
+add_to_objfile_sections (bfd *abfd, sec_ptr asect, PTR objfile_p_char)
+{
+  struct objfile *objfile = (struct objfile *) objfile_p_char;
+  struct obj_section section;
+  flagword aflag;
+
+  aflag = bfd_get_section_flags (abfd, asect);
+
+  if (!(aflag & SEC_ALLOC) && !(TARGET_KEEP_SECTION (asect)))
+    return;
+
+  if (0 == bfd_section_size (abfd, asect))
+    return;
+  section.offset = 0;
+  section.objfile = objfile;
+  section.the_bfd_section = asect;
+  section.ovly_mapped = 0;
+  section.addr = bfd_section_vma (abfd, asect);
+  section.endaddr = section.addr + bfd_section_size (abfd, asect);
+  obstack_grow (&objfile->psymbol_obstack, (char *) &section, sizeof (section));
+  objfile->sections_end = (struct obj_section *) (((unsigned long) objfile->sections_end) + 1);
+}
+
+/* Builds a section table for OBJFILE.
+   Returns 0 if OK, 1 on error (in which case bfd_error contains the
+   error).
+
+   Note that while we are building the table, which goes into the
+   psymbol obstack, we hijack the sections_end pointer to instead hold
+   a count of the number of sections.  When bfd_map_over_sections
+   returns, this count is used to compute the pointer to the end of
+   the sections table, which then overwrites the count.
+
+   Also note that the OFFSET and OVLY_MAPPED in each table entry
+   are initialized to zero.
+
+   Also note that if anything else writes to the psymbol obstack while
+   we are building the table, we're pretty much hosed. */
+
+int
+build_objfile_section_table (struct objfile *objfile)
+{
+  /* objfile->sections can be already set when reading a mapped symbol
+     file.  I believe that we do need to rebuild the section table in
+     this case (we rebuild other things derived from the bfd), but we
+     can't free the old one (it's in the psymbol_obstack).  So we just
+     waste some memory.  */
+
+  objfile->sections_end = 0;
+  bfd_map_over_sections (objfile->obfd, add_to_objfile_sections, (char *) objfile);
+  objfile->sections = (struct obj_section *)
+    obstack_finish (&objfile->psymbol_obstack);
+  objfile->sections_end = objfile->sections + (unsigned long) objfile->sections_end;
+  return (0);
+}
+
+/* Given a pointer to an initialized bfd (ABFD) and some flag bits
+   allocate a new objfile struct, fill it in as best we can, link it
+   into the list of all known objfiles, and return a pointer to the
+   new objfile struct.
+
+   The FLAGS word contains various bits (OBJF_*) that can be taken as
+   requests for specific operations, like trying to open a mapped
+   version of the objfile (OBJF_MAPPED).  Other bits like
+   OBJF_SHARED are simply copied through to the new objfile flags
+   member. */
+
+struct objfile *
+allocate_objfile (bfd *abfd, int flags)
+{
+  struct objfile *objfile = NULL;
+  struct objfile *last_one = NULL;
+
+  if (mapped_symbol_files)
+    flags |= OBJF_MAPPED;
+
+#if defined(USE_MMALLOC) && defined(HAVE_MMAP)
+  if (abfd != NULL)
+    {
+
+      /* If we can support mapped symbol files, try to open/reopen the
+         mapped file that corresponds to the file from which we wish to
+         read symbols.  If the objfile is to be mapped, we must malloc
+         the structure itself using the mmap version, and arrange that
+         all memory allocation for the objfile uses the mmap routines.
+         If we are reusing an existing mapped file, from which we get
+         our objfile pointer, we have to make sure that we update the
+         pointers to the alloc/free functions in the obstack, in case
+         these functions have moved within the current gdb.  */
+
+      int fd;
+
+      fd = open_mapped_file (bfd_get_filename (abfd), bfd_get_mtime (abfd),
+                            flags);
+      if (fd >= 0)
+       {
+         PTR md;
+
+         if ((md = map_to_file (fd)) == NULL)
+           {
+             close (fd);
+           }
+         else if ((objfile = (struct objfile *) mmalloc_getkey (md, 0)) != NULL)
+           {
+             /* Update memory corruption handler function addresses. */
+             init_malloc (md);
+             objfile->md = md;
+             objfile->mmfd = fd;
+             /* Update pointers to functions to *our* copies */
+             obstack_chunkfun (&objfile->psymbol_cache.cache, xmmalloc);
+             obstack_freefun (&objfile->psymbol_cache.cache, xmfree);
+             obstack_chunkfun (&objfile->macro_cache.cache, xmmalloc);
+             obstack_freefun (&objfile->macro_cache.cache, xmfree);
+             obstack_chunkfun (&objfile->psymbol_obstack, xmmalloc);
+             obstack_freefun (&objfile->psymbol_obstack, xmfree);
+             obstack_chunkfun (&objfile->symbol_obstack, xmmalloc);
+             obstack_freefun (&objfile->symbol_obstack, xmfree);
+             obstack_chunkfun (&objfile->type_obstack, xmmalloc);
+             obstack_freefun (&objfile->type_obstack, xmfree);
+             /* If already in objfile list, unlink it. */
+             unlink_objfile (objfile);
+             /* Forget things specific to a particular gdb, may have changed. */
+             objfile->sf = NULL;
+           }
+         else
+           {
+
+             /* Set up to detect internal memory corruption.  MUST be
+                done before the first malloc.  See comments in
+                init_malloc() and mmcheck().  */
+
+             init_malloc (md);
+
+             objfile = (struct objfile *)
+               xmmalloc (md, sizeof (struct objfile));
+             memset (objfile, 0, sizeof (struct objfile));
+             objfile->md = md;
+             objfile->mmfd = fd;
+             objfile->flags |= OBJF_MAPPED;
+             mmalloc_setkey (objfile->md, 0, objfile);
+             obstack_specify_allocation_with_arg (&objfile->psymbol_cache.cache,
+                                                  0, 0, xmmalloc, xmfree,
+                                                  objfile->md);
+             obstack_specify_allocation_with_arg (&objfile->macro_cache.cache,
+                                                  0, 0, xmmalloc, xmfree,
+                                                  objfile->md);
+             obstack_specify_allocation_with_arg (&objfile->psymbol_obstack,
+                                                  0, 0, xmmalloc, xmfree,
+                                                  objfile->md);
+             obstack_specify_allocation_with_arg (&objfile->symbol_obstack,
+                                                  0, 0, xmmalloc, xmfree,
+                                                  objfile->md);
+             obstack_specify_allocation_with_arg (&objfile->type_obstack,
+                                                  0, 0, xmmalloc, xmfree,
+                                                  objfile->md);
+           }
+       }
+
+      if ((flags & OBJF_MAPPED) && (objfile == NULL))
+       {
+         warning ("symbol table for '%s' will not be mapped",
+                  bfd_get_filename (abfd));
+         flags &= ~OBJF_MAPPED;
+       }
+    }
+#else /* !defined(USE_MMALLOC) || !defined(HAVE_MMAP) */
+
+  if (flags & OBJF_MAPPED)
+    {
+      warning ("mapped symbol tables are not supported on this machine; missing or broken mmap().");
+
+      /* Turn off the global flag so we don't try to do mapped symbol tables
+         any more, which shuts up gdb unless the user specifically gives the
+         "mapped" keyword again. */
+
+      mapped_symbol_files = 0;
+      flags &= ~OBJF_MAPPED;
+    }
+
+#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */
+
+  /* If we don't support mapped symbol files, didn't ask for the file to be
+     mapped, or failed to open the mapped file for some reason, then revert
+     back to an unmapped objfile. */
+
+  if (objfile == NULL)
+    {
+      objfile = (struct objfile *) xmalloc (sizeof (struct objfile));
+      memset (objfile, 0, sizeof (struct objfile));
+      objfile->md = NULL;
+      objfile->psymbol_cache = bcache_xmalloc ();
+      objfile->macro_cache = bcache_xmalloc ();
+      obstack_specify_allocation (&objfile->psymbol_obstack, 0, 0, xmalloc,
+                                 xfree);
+      obstack_specify_allocation (&objfile->symbol_obstack, 0, 0, xmalloc,
+                                 xfree);
+      obstack_specify_allocation (&objfile->type_obstack, 0, 0, xmalloc,
+                                 xfree);
+      flags &= ~OBJF_MAPPED;
+    }
+
+  /* Update the per-objfile information that comes from the bfd, ensuring
+     that any data that is reference is saved in the per-objfile data
+     region. */
+
+  objfile->obfd = abfd;
+  if (objfile->name != NULL)
+    {
+      xmfree (objfile->md, objfile->name);
+    }
+  if (abfd != NULL)
+    {
+      objfile->name = mstrsave (objfile->md, bfd_get_filename (abfd));
+      objfile->mtime = bfd_get_mtime (abfd);
+
+      /* Build section table.  */
+
+      if (build_objfile_section_table (objfile))
+       {
+         error ("Can't find the file sections in `%s': %s",
+                objfile->name, bfd_errmsg (bfd_get_error ()));
+       }
+    }
+
+  /* Initialize the section indexes for this objfile, so that we can
+     later detect if they are used w/o being properly assigned to. */
+
+    objfile->sect_index_text = -1;
+    objfile->sect_index_data = -1;
+    objfile->sect_index_bss = -1;
+    objfile->sect_index_rodata = -1;
+
+  /* Add this file onto the tail of the linked list of other such files. */
+
+  objfile->next = NULL;
+  if (object_files == NULL)
+    object_files = objfile;
+  else
+    {
+      for (last_one = object_files;
+          last_one->next;
+          last_one = last_one->next);
+      last_one->next = objfile;
+    }
+
+  /* Save passed in flag bits. */
+  objfile->flags |= flags;
+
+  return (objfile);
+}
+
+/* Put OBJFILE at the front of the list.  */
+
+void
+objfile_to_front (struct objfile *objfile)
+{
+  struct objfile **objp;
+  for (objp = &object_files; *objp != NULL; objp = &((*objp)->next))
+    {
+      if (*objp == objfile)
+       {
+         /* Unhook it from where it is.  */
+         *objp = objfile->next;
+         /* Put it in the front.  */
+         objfile->next = object_files;
+         object_files = objfile;
+         break;
+       }
+    }
+}
+
+/* Unlink OBJFILE from the list of known objfiles, if it is found in the
+   list.
+
+   It is not a bug, or error, to call this function if OBJFILE is not known
+   to be in the current list.  This is done in the case of mapped objfiles,
+   for example, just to ensure that the mapped objfile doesn't appear twice
+   in the list.  Since the list is threaded, linking in a mapped objfile
+   twice would create a circular list.
+
+   If OBJFILE turns out to be in the list, we zap it's NEXT pointer after
+   unlinking it, just to ensure that we have completely severed any linkages
+   between the OBJFILE and the list. */
+
+void
+unlink_objfile (struct objfile *objfile)
+{
+  struct objfile **objpp;
+
+  for (objpp = &object_files; *objpp != NULL; objpp = &((*objpp)->next))
+    {
+      if (*objpp == objfile)
+       {
+         *objpp = (*objpp)->next;
+         objfile->next = NULL;
+         return;
+       }
+    }
+
+  internal_error (__FILE__, __LINE__,
+                 "unlink_objfile: objfile already unlinked");
+}
+
+
+/* Destroy an objfile and all the symtabs and psymtabs under it.  Note
+   that as much as possible is allocated on the symbol_obstack and
+   psymbol_obstack, so that the memory can be efficiently freed.
+
+   Things which we do NOT free because they are not in malloc'd memory
+   or not in memory specific to the objfile include:
+
+   objfile -> sf
+
+   FIXME:  If the objfile is using reusable symbol information (via mmalloc),
+   then we need to take into account the fact that more than one process
+   may be using the symbol information at the same time (when mmalloc is
+   extended to support cooperative locking).  When more than one process
+   is using the mapped symbol info, we need to be more careful about when
+   we free objects in the reusable area. */
+
+void
+free_objfile (struct objfile *objfile)
+{
+  /* First do any symbol file specific actions required when we are
+     finished with a particular symbol file.  Note that if the objfile
+     is using reusable symbol information (via mmalloc) then each of
+     these routines is responsible for doing the correct thing, either
+     freeing things which are valid only during this particular gdb
+     execution, or leaving them to be reused during the next one. */
+
+  if (objfile->sf != NULL)
+    {
+      (*objfile->sf->sym_finish) (objfile);
+    }
+
+  /* We always close the bfd. */
+
+  if (objfile->obfd != NULL)
+    {
+      char *name = bfd_get_filename (objfile->obfd);
+      if (!bfd_close (objfile->obfd))
+       warning ("cannot close \"%s\": %s",
+                name, bfd_errmsg (bfd_get_error ()));
+      xfree (name);
+    }
+
+  /* Remove it from the chain of all objfiles. */
+
+  unlink_objfile (objfile);
+
+  /* If we are going to free the runtime common objfile, mark it
+     as unallocated.  */
+
+  if (objfile == rt_common_objfile)
+    rt_common_objfile = NULL;
+
+  /* Before the symbol table code was redone to make it easier to
+     selectively load and remove information particular to a specific
+     linkage unit, gdb used to do these things whenever the monolithic
+     symbol table was blown away.  How much still needs to be done
+     is unknown, but we play it safe for now and keep each action until
+     it is shown to be no longer needed. */
+
+  /* I *think* all our callers call clear_symtab_users.  If so, no need
+     to call this here.  */
+  clear_pc_function_cache ();
+
+  /* The last thing we do is free the objfile struct itself for the
+     non-reusable case, or detach from the mapped file for the
+     reusable case.  Note that the mmalloc_detach or the xmfree() is
+     the last thing we can do with this objfile. */
+
+#if defined(USE_MMALLOC) && defined(HAVE_MMAP)
+
+  if (objfile->flags & OBJF_MAPPED)
+    {
+      /* Remember the fd so we can close it.  We can't close it before
+         doing the detach, and after the detach the objfile is gone. */
+      int mmfd;
+
+      mmfd = objfile->mmfd;
+      mmalloc_detach (objfile->md);
+      objfile = NULL;
+      close (mmfd);
+    }
+
+#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */
+
+  /* If we still have an objfile, then either we don't support reusable
+     objfiles or this one was not reusable.  So free it normally. */
+
+  if (objfile != NULL)
+    {
+      if (objfile->name != NULL)
+       {
+         xmfree (objfile->md, objfile->name);
+       }
+      if (objfile->global_psymbols.list)
+       xmfree (objfile->md, objfile->global_psymbols.list);
+      if (objfile->static_psymbols.list)
+       xmfree (objfile->md, objfile->static_psymbols.list);
+      /* Free the obstacks for non-reusable objfiles */
+      bcache_xfree (objfile->psymbol_cache);
+      bcache_xfree (objfile->macro_cache);
+      obstack_free (&objfile->psymbol_obstack, 0);
+      obstack_free (&objfile->symbol_obstack, 0);
+      obstack_free (&objfile->type_obstack, 0);
+      xmfree (objfile->md, objfile);
+      objfile = NULL;
+    }
+}
+
+static void
+do_free_objfile_cleanup (void *obj)
+{
+  free_objfile (obj);
+}
+
+struct cleanup *
+make_cleanup_free_objfile (struct objfile *obj)
+{
+  return make_cleanup (do_free_objfile_cleanup, obj);
+}
+
+/* Free all the object files at once and clean up their users.  */
+
+void
+free_all_objfiles (void)
+{
+  struct objfile *objfile, *temp;
+
+  ALL_OBJFILES_SAFE (objfile, temp)
+  {
+    free_objfile (objfile);
+  }
+  clear_symtab_users ();
+}
+\f
+/* Relocate OBJFILE to NEW_OFFSETS.  There should be OBJFILE->NUM_SECTIONS
+   entries in new_offsets.  */
+void
+objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
+{
+  struct section_offsets *delta =
+    (struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS);
+
+  {
+    int i;
+    int something_changed = 0;
+    for (i = 0; i < objfile->num_sections; ++i)
+      {
+       delta->offsets[i] =
+         ANOFFSET (new_offsets, i) - ANOFFSET (objfile->section_offsets, i);
+       if (ANOFFSET (delta, i) != 0)
+         something_changed = 1;
+      }
+    if (!something_changed)
+      return;
+  }
+
+  /* OK, get all the symtabs.  */
+  {
+    struct symtab *s;
+
+    ALL_OBJFILE_SYMTABS (objfile, s)
+    {
+      struct linetable *l;
+      struct blockvector *bv;
+      int i;
+
+      /* First the line table.  */
+      l = LINETABLE (s);
+      if (l)
+       {
+         for (i = 0; i < l->nitems; ++i)
+           l->item[i].pc += ANOFFSET (delta, s->block_line_section);
+       }
+
+      /* Don't relocate a shared blockvector more than once.  */
+      if (!s->primary)
+       continue;
+
+      bv = BLOCKVECTOR (s);
+      for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i)
+       {
+         struct block *b;
+         struct symbol *sym;
+         int j;
+
+         b = BLOCKVECTOR_BLOCK (bv, i);
+         BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
+         BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
+
+         ALL_BLOCK_SYMBOLS (b, j, sym)
+           {
+             fixup_symbol_section (sym, objfile);
+
+             /* The RS6000 code from which this was taken skipped
+                any symbols in STRUCT_NAMESPACE or UNDEF_NAMESPACE.
+                But I'm leaving out that test, on the theory that
+                they can't possibly pass the tests below.  */
+             if ((SYMBOL_CLASS (sym) == LOC_LABEL
+                  || SYMBOL_CLASS (sym) == LOC_STATIC
+                  || SYMBOL_CLASS (sym) == LOC_INDIRECT)
+                 && SYMBOL_SECTION (sym) >= 0)
+               {
+                 SYMBOL_VALUE_ADDRESS (sym) +=
+                   ANOFFSET (delta, SYMBOL_SECTION (sym));
+               }
+#ifdef MIPS_EFI_SYMBOL_NAME
+             /* Relocate Extra Function Info for ecoff.  */
+
+             else if (SYMBOL_CLASS (sym) == LOC_CONST
+                      && SYMBOL_NAMESPACE (sym) == LABEL_NAMESPACE
+                      && strcmp (SYMBOL_NAME (sym), MIPS_EFI_SYMBOL_NAME) == 0)
+               ecoff_relocate_efi (sym, ANOFFSET (delta,
+                                                  s->block_line_section));
+#endif
+           }
+       }
+    }
+  }
+
+  {
+    struct partial_symtab *p;
+
+    ALL_OBJFILE_PSYMTABS (objfile, p)
+    {
+      p->textlow += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+      p->texthigh += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+    }
+  }
+
+  {
+    struct partial_symbol **psym;
+
+    for (psym = objfile->global_psymbols.list;
+        psym < objfile->global_psymbols.next;
+        psym++)
+      {
+       fixup_psymbol_section (*psym, objfile);
+       if (SYMBOL_SECTION (*psym) >= 0)
+         SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta,
+                                                   SYMBOL_SECTION (*psym));
+      }
+    for (psym = objfile->static_psymbols.list;
+        psym < objfile->static_psymbols.next;
+        psym++)
+      {
+       fixup_psymbol_section (*psym, objfile);
+       if (SYMBOL_SECTION (*psym) >= 0)
+         SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta,
+                                                   SYMBOL_SECTION (*psym));
+      }
+  }
+
+  {
+    struct minimal_symbol *msym;
+    ALL_OBJFILE_MSYMBOLS (objfile, msym)
+      if (SYMBOL_SECTION (msym) >= 0)
+      SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym));
+  }
+  /* Relocating different sections by different amounts may cause the symbols
+     to be out of order.  */
+  msymbols_sort (objfile);
+
+  {
+    int i;
+    for (i = 0; i < objfile->num_sections; ++i)
+      (objfile->section_offsets)->offsets[i] = ANOFFSET (new_offsets, i);
+  }
+
+  if (objfile->ei.entry_point != ~(CORE_ADDR) 0)
+    {
+      /* Relocate ei.entry_point with its section offset, use SECT_OFF_TEXT
+        only as a fallback.  */
+      struct obj_section *s;
+      s = find_pc_section (objfile->ei.entry_point);
+      if (s)
+        objfile->ei.entry_point += ANOFFSET (delta, s->the_bfd_section->index);
+      else
+        objfile->ei.entry_point += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+    }
+
+  {
+    struct obj_section *s;
+    bfd *abfd;
+
+    abfd = objfile->obfd;
+
+    ALL_OBJFILE_OSECTIONS (objfile, s)
+      {
+       int idx = s->the_bfd_section->index;
+       
+       s->addr += ANOFFSET (delta, idx);
+       s->endaddr += ANOFFSET (delta, idx);
+      }
+  }
+
+  if (objfile->ei.entry_func_lowpc != INVALID_ENTRY_LOWPC)
+    {
+      objfile->ei.entry_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+      objfile->ei.entry_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+    }
+
+  if (objfile->ei.entry_file_lowpc != INVALID_ENTRY_LOWPC)
+    {
+      objfile->ei.entry_file_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+      objfile->ei.entry_file_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+    }
+
+  if (objfile->ei.main_func_lowpc != INVALID_ENTRY_LOWPC)
+    {
+      objfile->ei.main_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+      objfile->ei.main_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+    }
+
+  /* Relocate breakpoints as necessary, after things are relocated. */
+  breakpoint_re_set ();
+}
+\f
+/* Many places in gdb want to test just to see if we have any partial
+   symbols available.  This function returns zero if none are currently
+   available, nonzero otherwise. */
+
+int
+have_partial_symbols (void)
+{
+  struct objfile *ofp;
+
+  ALL_OBJFILES (ofp)
+  {
+    if (ofp->psymtabs != NULL)
+      {
+       return 1;
+      }
+  }
+  return 0;
+}
+
+/* Many places in gdb want to test just to see if we have any full
+   symbols available.  This function returns zero if none are currently
+   available, nonzero otherwise. */
+
+int
+have_full_symbols (void)
+{
+  struct objfile *ofp;
+
+  ALL_OBJFILES (ofp)
+  {
+    if (ofp->symtabs != NULL)
+      {
+       return 1;
+      }
+  }
+  return 0;
+}
+
+
+/* This operations deletes all objfile entries that represent solibs that
+   weren't explicitly loaded by the user, via e.g., the add-symbol-file
+   command.
+ */
+void
+objfile_purge_solibs (void)
+{
+  struct objfile *objf;
+  struct objfile *temp;
+
+  ALL_OBJFILES_SAFE (objf, temp)
+  {
+    /* We assume that the solib package has been purged already, or will
+       be soon.
+     */
+    if (!(objf->flags & OBJF_USERLOADED) && (objf->flags & OBJF_SHARED))
+      free_objfile (objf);
+  }
+}
+
+
+/* Many places in gdb want to test just to see if we have any minimal
+   symbols available.  This function returns zero if none are currently
+   available, nonzero otherwise. */
+
+int
+have_minimal_symbols (void)
+{
+  struct objfile *ofp;
+
+  ALL_OBJFILES (ofp)
+  {
+    if (ofp->msymbols != NULL)
+      {
+       return 1;
+      }
+  }
+  return 0;
+}
+
+#if defined(USE_MMALLOC) && defined(HAVE_MMAP)
+
+/* Given the name of a mapped symbol file in SYMSFILENAME, and the timestamp
+   of the corresponding symbol file in MTIME, try to open an existing file
+   with the name SYMSFILENAME and verify it is more recent than the base
+   file by checking it's timestamp against MTIME.
+
+   If SYMSFILENAME does not exist (or can't be stat'd), simply returns -1.
+
+   If SYMSFILENAME does exist, but is out of date, we check to see if the
+   user has specified creation of a mapped file.  If so, we don't issue
+   any warning message because we will be creating a new mapped file anyway,
+   overwriting the old one.  If not, then we issue a warning message so that
+   the user will know why we aren't using this existing mapped symbol file.
+   In either case, we return -1.
+
+   If SYMSFILENAME does exist and is not out of date, but can't be opened for
+   some reason, then prints an appropriate system error message and returns -1.
+
+   Otherwise, returns the open file descriptor.  */
+
+static int
+open_existing_mapped_file (char *symsfilename, long mtime, int flags)
+{
+  int fd = -1;
+  struct stat sbuf;
+
+  if (stat (symsfilename, &sbuf) == 0)
+    {
+      if (sbuf.st_mtime < mtime)
+       {
+         if (!(flags & OBJF_MAPPED))
+           {
+             warning ("mapped symbol file `%s' is out of date, ignored it",
+                      symsfilename);
+           }
+       }
+      else if ((fd = open (symsfilename, O_RDWR)) < 0)
+       {
+         if (error_pre_print)
+           {
+             printf_unfiltered (error_pre_print);
+           }
+         print_sys_errmsg (symsfilename, errno);
+       }
+    }
+  return (fd);
+}
+
+/* Look for a mapped symbol file that corresponds to FILENAME and is more
+   recent than MTIME.  If MAPPED is nonzero, the user has asked that gdb
+   use a mapped symbol file for this file, so create a new one if one does
+   not currently exist.
+
+   If found, then return an open file descriptor for the file, otherwise
+   return -1.
+
+   This routine is responsible for implementing the policy that generates
+   the name of the mapped symbol file from the name of a file containing
+   symbols that gdb would like to read.  Currently this policy is to append
+   ".syms" to the name of the file.
+
+   This routine is also responsible for implementing the policy that
+   determines where the mapped symbol file is found (the search path).
+   This policy is that when reading an existing mapped file, a file of
+   the correct name in the current directory takes precedence over a
+   file of the correct name in the same directory as the symbol file.
+   When creating a new mapped file, it is always created in the current
+   directory.  This helps to minimize the chances of a user unknowingly
+   creating big mapped files in places like /bin and /usr/local/bin, and
+   allows a local copy to override a manually installed global copy (in
+   /bin for example).  */
+
+static int
+open_mapped_file (char *filename, long mtime, int flags)
+{
+  int fd;
+  char *symsfilename;
+
+  /* First try to open an existing file in the current directory, and
+     then try the directory where the symbol file is located. */
+
+  symsfilename = concat ("./", lbasename (filename), ".syms", (char *) NULL);
+  if ((fd = open_existing_mapped_file (symsfilename, mtime, flags)) < 0)
+    {
+      xfree (symsfilename);
+      symsfilename = concat (filename, ".syms", (char *) NULL);
+      fd = open_existing_mapped_file (symsfilename, mtime, flags);
+    }
+
+  /* If we don't have an open file by now, then either the file does not
+     already exist, or the base file has changed since it was created.  In
+     either case, if the user has specified use of a mapped file, then
+     create a new mapped file, truncating any existing one.  If we can't
+     create one, print a system error message saying why we can't.
+
+     By default the file is rw for everyone, with the user's umask taking
+     care of turning off the permissions the user wants off. */
+
+  if ((fd < 0) && (flags & OBJF_MAPPED))
+    {
+      xfree (symsfilename);
+      symsfilename = concat ("./", lbasename (filename), ".syms",
+                            (char *) NULL);
+      if ((fd = open (symsfilename, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
+       {
+         if (error_pre_print)
+           {
+             printf_unfiltered (error_pre_print);
+           }
+         print_sys_errmsg (symsfilename, errno);
+       }
+    }
+
+  xfree (symsfilename);
+  return (fd);
+}
+
+static PTR
+map_to_file (int fd)
+{
+  PTR md;
+  CORE_ADDR mapto;
+
+  md = mmalloc_attach (fd, (PTR) 0);
+  if (md != NULL)
+    {
+      mapto = (CORE_ADDR) mmalloc_getkey (md, 1);
+      md = mmalloc_detach (md);
+      if (md != NULL)
+       {
+         /* FIXME: should figure out why detach failed */
+         md = NULL;
+       }
+      else if (mapto != (CORE_ADDR) NULL)
+       {
+         /* This mapping file needs to be remapped at "mapto" */
+         md = mmalloc_attach (fd, (PTR) mapto);
+       }
+      else
+       {
+         /* This is a freshly created mapping file. */
+         mapto = (CORE_ADDR) mmalloc_findbase (20 * 1024 * 1024);
+         if (mapto != 0)
+           {
+             /* To avoid reusing the freshly created mapping file, at the 
+                address selected by mmap, we must truncate it before trying
+                to do an attach at the address we want. */
+             ftruncate (fd, 0);
+             md = mmalloc_attach (fd, (PTR) mapto);
+             if (md != NULL)
+               {
+                 mmalloc_setkey (md, 1, (PTR) mapto);
+               }
+           }
+       }
+    }
+  return (md);
+}
+
+#endif /* defined(USE_MMALLOC) && defined(HAVE_MMAP) */
+
+/* Returns a section whose range includes PC and SECTION, 
+   or NULL if none found.  Note the distinction between the return type, 
+   struct obj_section (which is defined in gdb), and the input type
+   struct sec (which is a bfd-defined data type).  The obj_section
+   contains a pointer to the bfd struct sec section.  */
+
+struct obj_section *
+find_pc_sect_section (CORE_ADDR pc, struct sec *section)
+{
+  struct obj_section *s;
+  struct objfile *objfile;
+
+  ALL_OBJSECTIONS (objfile, s)
+    if ((section == 0 || section == s->the_bfd_section) &&
+       s->addr <= pc && pc < s->endaddr)
+      return (s);
+
+  return (NULL);
+}
+
+/* Returns a section whose range includes PC or NULL if none found. 
+   Backward compatibility, no section.  */
+
+struct obj_section *
+find_pc_section (CORE_ADDR pc)
+{
+  return find_pc_sect_section (pc, find_pc_mapped_section (pc));
+}
+
+
+/* In SVR4, we recognize a trampoline by it's section name. 
+   That is, if the pc is in a section named ".plt" then we are in
+   a trampoline.  */
+
+int
+in_plt_section (CORE_ADDR pc, char *name)
+{
+  struct obj_section *s;
+  int retval = 0;
+
+  s = find_pc_section (pc);
+
+  retval = (s != NULL
+           && s->the_bfd_section->name != NULL
+           && STREQ (s->the_bfd_section->name, ".plt"));
+  return (retval);
+}
+
+/* Return nonzero if NAME is in the import list of OBJFILE.  Else
+   return zero.  */
+
+int
+is_in_import_list (char *name, struct objfile *objfile)
+{
+  register int i;
+
+  if (!objfile || !name || !*name)
+    return 0;
+
+  for (i = 0; i < objfile->import_list_size; i++)
+    if (objfile->import_list[i] && STREQ (name, objfile->import_list[i]))
+      return 1;
+  return 0;
+}
+
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
new file mode 100644 (file)
index 0000000..8542b8a
--- /dev/null
@@ -0,0 +1,2572 @@
+/* Print values for GNU debugger GDB.
+
+   Copyright 1986, 1987, 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.
+
+   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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include "frame.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "language.h"
+#include "expression.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "demangle.h"
+#include "valprint.h"
+#include "annotate.h"
+#include "symfile.h"           /* for overlay functions */
+#include "objfiles.h"          /* ditto */
+#include "completer.h"         /* for completion functions */
+#include "ui-out.h"
+#include "gdb_assert.h"
+
+extern int asm_demangle;       /* Whether to demangle syms in asm printouts */
+extern int addressprint;       /* Whether to print hex addresses in HLL " */
+
+struct format_data
+  {
+    int count;
+    char format;
+    char size;
+  };
+
+/* Last specified output format.  */
+
+static char last_format = 'x';
+
+/* Last specified examination size.  'b', 'h', 'w' or `q'.  */
+
+static char last_size = 'w';
+
+/* Default address to examine next.  */
+
+static CORE_ADDR next_address;
+
+/* Default section to examine next. */
+
+static asection *next_section;
+
+/* Last address examined.  */
+
+static CORE_ADDR last_examine_address;
+
+/* Contents of last address examined.
+   This is not valid past the end of the `x' command!  */
+
+static struct value *last_examine_value;
+
+/* Largest offset between a symbolic value and an address, that will be
+   printed as `0x1234 <symbol+offset>'.  */
+
+static unsigned int max_symbolic_offset = UINT_MAX;
+
+/* Append the source filename and linenumber of the symbol when
+   printing a symbolic value as `<symbol at filename:linenum>' if set.  */
+static int print_symbol_filename = 0;
+
+/* Number of auto-display expression currently being displayed.
+   So that we can disable it if we get an error or a signal within it.
+   -1 when not doing one.  */
+
+int current_display_number;
+
+/* Flag to low-level print routines that this value is being printed
+   in an epoch window.  We'd like to pass this as a parameter, but
+   every routine would need to take it.  Perhaps we can encapsulate
+   this in the I/O stream once we have GNU stdio. */
+
+int inspect_it = 0;
+
+struct display
+  {
+    /* Chain link to next auto-display item.  */
+    struct display *next;
+    /* Expression to be evaluated and displayed.  */
+    struct expression *exp;
+    /* Item number of this auto-display item.  */
+    int number;
+    /* Display format specified.  */
+    struct format_data format;
+    /* Innermost block required by this expression when evaluated */
+    struct block *block;
+    /* Status of this display (enabled or disabled) */
+    int enabled_p;
+  };
+
+/* Chain of expressions whose values should be displayed
+   automatically each time the program stops.  */
+
+static struct display *display_chain;
+
+static int display_number;
+
+/* Prototypes for exported functions. */
+
+void output_command (char *, int);
+
+void _initialize_printcmd (void);
+
+/* Prototypes for local functions. */
+
+static void delete_display (int);
+
+static void enable_display (char *, int);
+
+static void disable_display_command (char *, int);
+
+static void disassemble_command (char *, int);
+
+static void printf_command (char *, int);
+
+static void print_frame_nameless_args (struct frame_info *, long,
+                                      int, int, struct ui_file *);
+
+static void display_info (char *, int);
+
+static void do_one_display (struct display *);
+
+static void undisplay_command (char *, int);
+
+static void free_display (struct display *);
+
+static void display_command (char *, int);
+
+void x_command (char *, int);
+
+static void address_info (char *, int);
+
+static void set_command (char *, int);
+
+static void call_command (char *, int);
+
+static void inspect_command (char *, int);
+
+static void print_command (char *, int);
+
+static void print_command_1 (char *, int, int);
+
+static void validate_format (struct format_data, char *);
+
+static void do_examine (struct format_data, CORE_ADDR addr,
+                       asection * section);
+
+static void print_formatted (struct value *, int, int, struct ui_file *);
+
+static struct format_data decode_format (char **, int, int);
+
+static int print_insn (CORE_ADDR, struct ui_file *);
+
+static void sym_info (char *, int);
+\f
+
+/* Decode a format specification.  *STRING_PTR should point to it.
+   OFORMAT and OSIZE are used as defaults for the format and size
+   if none are given in the format specification.
+   If OSIZE is zero, then the size field of the returned value
+   should be set only if a size is explicitly specified by the
+   user.
+   The structure returned describes all the data
+   found in the specification.  In addition, *STRING_PTR is advanced
+   past the specification and past all whitespace following it.  */
+
+static struct format_data
+decode_format (char **string_ptr, int oformat, int osize)
+{
+  struct format_data val;
+  register char *p = *string_ptr;
+
+  val.format = '?';
+  val.size = '?';
+  val.count = 1;
+
+  if (*p >= '0' && *p <= '9')
+    val.count = atoi (p);
+  while (*p >= '0' && *p <= '9')
+    p++;
+
+  /* Now process size or format letters that follow.  */
+
+  while (1)
+    {
+      if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g')
+       val.size = *p++;
+      else if (*p >= 'a' && *p <= 'z')
+       val.format = *p++;
+      else
+       break;
+    }
+
+  while (*p == ' ' || *p == '\t')
+    p++;
+  *string_ptr = p;
+
+  /* Set defaults for format and size if not specified.  */
+  if (val.format == '?')
+    {
+      if (val.size == '?')
+       {
+         /* Neither has been specified.  */
+         val.format = oformat;
+         val.size = osize;
+       }
+      else
+       /* If a size is specified, any format makes a reasonable
+          default except 'i'.  */
+       val.format = oformat == 'i' ? 'x' : oformat;
+    }
+  else if (val.size == '?')
+    switch (val.format)
+      {
+      case 'a':
+      case 's':
+       /* Pick the appropriate size for an address.  */
+       if (TARGET_PTR_BIT == 64)
+         val.size = osize ? 'g' : osize;
+       else if (TARGET_PTR_BIT == 32)
+         val.size = osize ? 'w' : osize;
+       else if (TARGET_PTR_BIT == 16)
+         val.size = osize ? 'h' : osize;
+       else
+         /* Bad value for TARGET_PTR_BIT */
+         internal_error (__FILE__, __LINE__, "failed internal consistency check");
+       break;
+      case 'f':
+       /* Floating point has to be word or giantword.  */
+       if (osize == 'w' || osize == 'g')
+         val.size = osize;
+       else
+         /* Default it to giantword if the last used size is not
+            appropriate.  */
+         val.size = osize ? 'g' : osize;
+       break;
+      case 'c':
+       /* Characters default to one byte.  */
+       val.size = osize ? 'b' : osize;
+       break;
+      default:
+       /* The default is the size most recently specified.  */
+       val.size = osize;
+      }
+
+  return val;
+}
+\f
+/* Print value VAL on stream according to FORMAT, a letter or 0.
+   Do not end with a newline.
+   0 means print VAL according to its own type.
+   SIZE is the letter for the size of datum being printed.
+   This is used to pad hex numbers so they line up.  */
+
+static void
+print_formatted (struct value *val, register int format, int size,
+                struct ui_file *stream)
+{
+  struct type *type = check_typedef (VALUE_TYPE (val));
+  int len = TYPE_LENGTH (type);
+
+  if (VALUE_LVAL (val) == lval_memory)
+    {
+      next_address = VALUE_ADDRESS (val) + len;
+      next_section = VALUE_BFD_SECTION (val);
+    }
+
+  switch (format)
+    {
+    case 's':
+      /* FIXME: Need to handle wchar_t's here... */
+      next_address = VALUE_ADDRESS (val)
+       + val_print_string (VALUE_ADDRESS (val), -1, 1, stream);
+      next_section = VALUE_BFD_SECTION (val);
+      break;
+
+    case 'i':
+      /* The old comment says
+         "Force output out, print_insn not using _filtered".
+         I'm not completely sure what that means, I suspect most print_insn
+         now do use _filtered, so I guess it's obsolete.
+         --Yes, it does filter now, and so this is obsolete.  -JB  */
+
+      /* We often wrap here if there are long symbolic names.  */
+      wrap_here ("    ");
+      next_address = VALUE_ADDRESS (val)
+       + print_insn (VALUE_ADDRESS (val), stream);
+      next_section = VALUE_BFD_SECTION (val);
+      break;
+
+    default:
+      if (format == 0
+         || TYPE_CODE (type) == TYPE_CODE_ARRAY
+         || TYPE_CODE (type) == TYPE_CODE_STRING
+         || TYPE_CODE (type) == TYPE_CODE_STRUCT
+         || TYPE_CODE (type) == TYPE_CODE_UNION)
+       /* If format is 0, use the 'natural' format for
+        * that type of value.  If the type is non-scalar,
+        * we have to use language rules to print it as
+        * a series of scalars.
+        */
+       value_print (val, stream, format, Val_pretty_default);
+      else
+       /* User specified format, so don't look to the
+        * the type to tell us what to do.
+        */
+       print_scalar_formatted (VALUE_CONTENTS (val), type,
+                               format, size, stream);
+    }
+}
+
+/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR,
+   according to letters FORMAT and SIZE on STREAM.
+   FORMAT may not be zero.  Formats s and i are not supported at this level.
+
+   This is how the elements of an array or structure are printed
+   with a format.  */
+
+void
+print_scalar_formatted (char *valaddr, struct type *type, int format, int size,
+                       struct ui_file *stream)
+{
+  LONGEST val_long;
+  unsigned int len = TYPE_LENGTH (type);
+
+  if (len > sizeof (LONGEST)
+      && (format == 't'
+         || format == 'c'
+         || format == 'o'
+         || format == 'u'
+         || format == 'd'
+         || format == 'x'))
+    {
+      if (!TYPE_UNSIGNED (type)
+         || !extract_long_unsigned_integer (valaddr, len, &val_long))
+       {
+         /* We can't print it normally, but we can print it in hex.
+            Printing it in the wrong radix is more useful than saying
+            "use /x, you dummy".  */
+         /* FIXME:  we could also do octal or binary if that was the
+            desired format.  */
+         /* FIXME:  we should be using the size field to give us a
+            minimum field width to print.  */
+
+         if (format == 'o')
+           print_octal_chars (stream, valaddr, len);
+         else if (format == 'd')
+           print_decimal_chars (stream, valaddr, len);
+         else if (format == 't')
+           print_binary_chars (stream, valaddr, len);
+         else
+           /* replace with call to print_hex_chars? Looks
+              like val_print_type_code_int is redoing
+              work.  - edie */
+
+           val_print_type_code_int (type, valaddr, stream);
+
+         return;
+       }
+
+      /* If we get here, extract_long_unsigned_integer set val_long.  */
+    }
+  else if (format != 'f')
+    val_long = unpack_long (type, valaddr);
+
+  /* If the value is a pointer, and pointers and addresses are not the
+     same, then at this point, the value's length (in target bytes) is
+     TARGET_ADDR_BIT/TARGET_CHAR_BIT, not TYPE_LENGTH (type).  */
+  if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    len = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
+
+  /* If we are printing it as unsigned, truncate it in case it is actually
+     a negative signed value (e.g. "print/u (short)-1" should print 65535
+     (if shorts are 16 bits) instead of 4294967295).  */
+  if (format != 'd')
+    {
+      if (len < sizeof (LONGEST))
+       val_long &= ((LONGEST) 1 << HOST_CHAR_BIT * len) - 1;
+    }
+
+  switch (format)
+    {
+    case 'x':
+      if (!size)
+       {
+         /* no size specified, like in print.  Print varying # of digits. */
+         print_longest (stream, 'x', 1, val_long);
+       }
+      else
+       switch (size)
+         {
+         case 'b':
+         case 'h':
+         case 'w':
+         case 'g':
+           print_longest (stream, size, 1, val_long);
+           break;
+         default:
+           error ("Undefined output size \"%c\".", size);
+         }
+      break;
+
+    case 'd':
+      print_longest (stream, 'd', 1, val_long);
+      break;
+
+    case 'u':
+      print_longest (stream, 'u', 0, val_long);
+      break;
+
+    case 'o':
+      if (val_long)
+       print_longest (stream, 'o', 1, val_long);
+      else
+       fprintf_filtered (stream, "0");
+      break;
+
+    case 'a':
+      {
+       CORE_ADDR addr = unpack_pointer (type, valaddr);
+       print_address (addr, stream);
+      }
+      break;
+
+    case 'c':
+      value_print (value_from_longest (builtin_type_true_char, val_long),
+                  stream, 0, Val_pretty_default);
+      break;
+
+    case 'f':
+      if (len == TYPE_LENGTH (builtin_type_float))
+        type = builtin_type_float;
+      else if (len == TYPE_LENGTH (builtin_type_double))
+        type = builtin_type_double;
+      else if (len == TYPE_LENGTH (builtin_type_long_double))
+        type = builtin_type_long_double;
+      print_floating (valaddr, type, stream);
+      break;
+
+    case 0:
+      internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+    case 't':
+      /* Binary; 't' stands for "two".  */
+      {
+       char bits[8 * (sizeof val_long) + 1];
+       char buf[8 * (sizeof val_long) + 32];
+       char *cp = bits;
+       int width;
+
+       if (!size)
+         width = 8 * (sizeof val_long);
+       else
+         switch (size)
+           {
+           case 'b':
+             width = 8;
+             break;
+           case 'h':
+             width = 16;
+             break;
+           case 'w':
+             width = 32;
+             break;
+           case 'g':
+             width = 64;
+             break;
+           default:
+             error ("Undefined output size \"%c\".", size);
+           }
+
+       bits[width] = '\0';
+       while (width-- > 0)
+         {
+           bits[width] = (val_long & 1) ? '1' : '0';
+           val_long >>= 1;
+         }
+       if (!size)
+         {
+           while (*cp && *cp == '0')
+             cp++;
+           if (*cp == '\0')
+             cp--;
+         }
+       strcpy (buf, local_binary_format_prefix ());
+       strcat (buf, cp);
+       strcat (buf, local_binary_format_suffix ());
+       fprintf_filtered (stream, buf);
+      }
+      break;
+
+    default:
+      error ("Undefined output format \"%c\".", format);
+    }
+}
+
+/* Specify default address for `x' command.
+   `info lines' uses this.  */
+
+void
+set_next_address (CORE_ADDR addr)
+{
+  next_address = addr;
+
+  /* Make address available to the user as $_.  */
+  set_internalvar (lookup_internalvar ("_"),
+                  value_from_pointer (lookup_pointer_type (builtin_type_void),
+                                      addr));
+}
+
+/* Optionally print address ADDR symbolically as <SYMBOL+OFFSET> on STREAM,
+   after LEADIN.  Print nothing if no symbolic name is found nearby.
+   Optionally also print source file and line number, if available.
+   DO_DEMANGLE controls whether to print a symbol in its native "raw" form,
+   or to interpret it as a possible C++ name and convert it back to source
+   form.  However note that DO_DEMANGLE can be overridden by the specific
+   settings of the demangle and asm_demangle variables.  */
+
+void
+print_address_symbolic (CORE_ADDR addr, struct ui_file *stream, int do_demangle,
+                       char *leadin)
+{
+  char *name = NULL;
+  char *filename = NULL;
+  int unmapped = 0;
+  int offset = 0;
+  int line = 0;
+
+  /* throw away both name and filename */
+  struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &name);
+  make_cleanup (free_current_contents, &filename);
+
+  if (build_address_symbolic (addr, do_demangle, &name, &offset, &filename, &line, &unmapped))
+    {
+      do_cleanups (cleanup_chain);
+      return;
+    }
+
+  fputs_filtered (leadin, stream);
+  if (unmapped)
+    fputs_filtered ("<*", stream);
+  else
+    fputs_filtered ("<", stream);
+  fputs_filtered (name, stream);
+  if (offset != 0)
+    fprintf_filtered (stream, "+%u", (unsigned int) offset);
+
+  /* Append source filename and line number if desired.  Give specific
+     line # of this addr, if we have it; else line # of the nearest symbol.  */
+  if (print_symbol_filename && filename != NULL)
+    {
+      if (line != -1)
+       fprintf_filtered (stream, " at %s:%d", filename, line);
+      else
+       fprintf_filtered (stream, " in %s", filename);
+    }
+  if (unmapped)
+    fputs_filtered ("*>", stream);
+  else
+    fputs_filtered (">", stream);
+
+  do_cleanups (cleanup_chain);
+}
+
+/* Given an address ADDR return all the elements needed to print the
+   address in a symbolic form. NAME can be mangled or not depending
+   on DO_DEMANGLE (and also on the asm_demangle global variable,
+   manipulated via ''set print asm-demangle''). Return 0 in case of
+   success, when all the info in the OUT paramters is valid. Return 1
+   otherwise. */
+int
+build_address_symbolic (CORE_ADDR addr,  /* IN */
+                       int do_demangle, /* IN */
+                       char **name,     /* OUT */
+                       int *offset,     /* OUT */
+                       char **filename, /* OUT */
+                       int *line,       /* OUT */
+                       int *unmapped)   /* OUT */
+{
+  struct minimal_symbol *msymbol;
+  struct symbol *symbol;
+  struct symtab *symtab = 0;
+  CORE_ADDR name_location = 0;
+  asection *section = 0;
+  char *name_temp = "";
+  
+  /* Let's say it is unmapped. */
+  *unmapped = 0;
+
+  /* Determine if the address is in an overlay, and whether it is
+     mapped. */
+  if (overlay_debugging)
+    {
+      section = find_pc_overlay (addr);
+      if (pc_in_unmapped_range (addr, section))
+       {
+         *unmapped = 1;
+         addr = overlay_mapped_address (addr, section);
+       }
+    }
+
+  /* On some targets, add in extra "flag" bits to PC for
+     disassembly.  This should ensure that "rounding errors" in
+     symbol addresses that are masked for disassembly favour the
+     the correct symbol. */
+
+#ifdef GDB_TARGET_UNMASK_DISAS_PC
+  addr = GDB_TARGET_UNMASK_DISAS_PC (addr);
+#endif
+
+  /* First try to find the address in the symbol table, then
+     in the minsyms.  Take the closest one.  */
+
+  /* This is defective in the sense that it only finds text symbols.  So
+     really this is kind of pointless--we should make sure that the
+     minimal symbols have everything we need (by changing that we could
+     save some memory, but for many debug format--ELF/DWARF or
+     anything/stabs--it would be inconvenient to eliminate those minimal
+     symbols anyway).  */
+  msymbol = lookup_minimal_symbol_by_pc_section (addr, section);
+  symbol = find_pc_sect_function (addr, section);
+
+  if (symbol)
+    {
+      name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (symbol));
+      if (do_demangle)
+       name_temp = SYMBOL_SOURCE_NAME (symbol);
+      else
+       name_temp = SYMBOL_LINKAGE_NAME (symbol);
+    }
+
+  if (msymbol != NULL)
+    {
+      if (SYMBOL_VALUE_ADDRESS (msymbol) > name_location || symbol == NULL)
+       {
+         /* The msymbol is closer to the address than the symbol;
+            use the msymbol instead.  */
+         symbol = 0;
+         symtab = 0;
+         name_location = SYMBOL_VALUE_ADDRESS (msymbol);
+         if (do_demangle)
+           name_temp = SYMBOL_SOURCE_NAME (msymbol);
+         else
+           name_temp = SYMBOL_LINKAGE_NAME (msymbol);
+       }
+    }
+  if (symbol == NULL && msymbol == NULL)
+    return 1;
+
+  /* On some targets, mask out extra "flag" bits from PC for handsome
+     disassembly. */
+
+#ifdef GDB_TARGET_MASK_DISAS_PC
+  name_location = GDB_TARGET_MASK_DISAS_PC (name_location);
+  addr = GDB_TARGET_MASK_DISAS_PC (addr);
+#endif
+
+  /* If the nearest symbol is too far away, don't print anything symbolic.  */
+
+  /* For when CORE_ADDR is larger than unsigned int, we do math in
+     CORE_ADDR.  But when we detect unsigned wraparound in the
+     CORE_ADDR math, we ignore this test and print the offset,
+     because addr+max_symbolic_offset has wrapped through the end
+     of the address space back to the beginning, giving bogus comparison.  */
+  if (addr > name_location + max_symbolic_offset
+      && name_location + max_symbolic_offset > name_location)
+    return 1;
+
+  *offset = addr - name_location;
+
+  *name = xstrdup (name_temp);
+
+  if (print_symbol_filename)
+    {
+      struct symtab_and_line sal;
+
+      sal = find_pc_sect_line (addr, section, 0);
+
+      if (sal.symtab)
+       {
+         *filename = xstrdup (sal.symtab->filename);
+         *line = sal.line;
+       }
+      else if (symtab && symbol && symbol->line)
+       {
+         *filename = xstrdup (symtab->filename);
+         *line = symbol->line;
+       }
+      else if (symtab)
+       {
+         *filename = xstrdup (symtab->filename);
+         *line = -1;
+       }
+    }
+  return 0;
+}
+
+/* Print address ADDR on STREAM.  USE_LOCAL means the same thing as for
+   print_longest.  */
+void
+print_address_numeric (CORE_ADDR addr, int use_local, struct ui_file *stream)
+{
+  /* Truncate address to the size of a target address, avoiding shifts
+     larger or equal than the width of a CORE_ADDR.  The local
+     variable ADDR_BIT stops the compiler reporting a shift overflow
+     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
+     some ADDRESS_TO_PRINTABLE() be used to do the conversion?  */
+
+  int addr_bit = TARGET_ADDR_BIT;
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+    addr &= ((CORE_ADDR) 1 << addr_bit) - 1;
+  print_longest (stream, 'x', use_local, (ULONGEST) addr);
+}
+
+/* Print address ADDR symbolically on STREAM.
+   First print it as a number.  Then perhaps print
+   <SYMBOL + OFFSET> after the number.  */
+
+void
+print_address (CORE_ADDR addr, struct ui_file *stream)
+{
+  print_address_numeric (addr, 1, stream);
+  print_address_symbolic (addr, stream, asm_demangle, " ");
+}
+
+/* Print address ADDR symbolically on STREAM.  Parameter DEMANGLE
+   controls whether to print the symbolic name "raw" or demangled.
+   Global setting "addressprint" controls whether to print hex address
+   or not.  */
+
+void
+print_address_demangle (CORE_ADDR addr, struct ui_file *stream, int do_demangle)
+{
+  if (addr == 0)
+    {
+      fprintf_filtered (stream, "0");
+    }
+  else if (addressprint)
+    {
+      print_address_numeric (addr, 1, stream);
+      print_address_symbolic (addr, stream, do_demangle, " ");
+    }
+  else
+    {
+      print_address_symbolic (addr, stream, do_demangle, "");
+    }
+}
+\f
+
+/* These are the types that $__ will get after an examine command of one
+   of these sizes.  */
+
+static struct type *examine_i_type;
+
+static struct type *examine_b_type;
+static struct type *examine_h_type;
+static struct type *examine_w_type;
+static struct type *examine_g_type;
+
+/* Examine data at address ADDR in format FMT.
+   Fetch it from memory and print on gdb_stdout.  */
+
+static void
+do_examine (struct format_data fmt, CORE_ADDR addr, asection *sect)
+{
+  register char format = 0;
+  register char size;
+  register int count = 1;
+  struct type *val_type = NULL;
+  register int i;
+  register int maxelts;
+
+  format = fmt.format;
+  size = fmt.size;
+  count = fmt.count;
+  next_address = addr;
+  next_section = sect;
+
+  /* String or instruction format implies fetch single bytes
+     regardless of the specified size.  */
+  if (format == 's' || format == 'i')
+    size = 'b';
+
+  if (format == 'i')
+    val_type = examine_i_type;
+  else if (size == 'b')
+    val_type = examine_b_type;
+  else if (size == 'h')
+    val_type = examine_h_type;
+  else if (size == 'w')
+    val_type = examine_w_type;
+  else if (size == 'g')
+    val_type = examine_g_type;
+
+  maxelts = 8;
+  if (size == 'w')
+    maxelts = 4;
+  if (size == 'g')
+    maxelts = 2;
+  if (format == 's' || format == 'i')
+    maxelts = 1;
+
+  /* Print as many objects as specified in COUNT, at most maxelts per line,
+     with the address of the next one at the start of each line.  */
+
+  while (count > 0)
+    {
+      QUIT;
+      print_address (next_address, gdb_stdout);
+      printf_filtered (":");
+      for (i = maxelts;
+          i > 0 && count > 0;
+          i--, count--)
+       {
+         printf_filtered ("\t");
+         /* Note that print_formatted sets next_address for the next
+            object.  */
+         last_examine_address = next_address;
+
+         if (last_examine_value)
+           value_free (last_examine_value);
+
+         /* The value to be displayed is not fetched greedily.
+            Instead, to avoid the posibility of a fetched value not
+            being used, its retreval is delayed until the print code
+            uses it.  When examining an instruction stream, the
+            disassembler will perform its own memory fetch using just
+            the address stored in LAST_EXAMINE_VALUE.  FIXME: Should
+            the disassembler be modified so that LAST_EXAMINE_VALUE
+            is left with the byte sequence from the last complete
+            instruction fetched from memory? */
+         last_examine_value = value_at_lazy (val_type, next_address, sect);
+
+         if (last_examine_value)
+           release_value (last_examine_value);
+
+         print_formatted (last_examine_value, format, size, gdb_stdout);
+       }
+      printf_filtered ("\n");
+      gdb_flush (gdb_stdout);
+    }
+}
+\f
+static void
+validate_format (struct format_data fmt, char *cmdname)
+{
+  if (fmt.size != 0)
+    error ("Size letters are meaningless in \"%s\" command.", cmdname);
+  if (fmt.count != 1)
+    error ("Item count other than 1 is meaningless in \"%s\" command.",
+          cmdname);
+  if (fmt.format == 'i' || fmt.format == 's')
+    error ("Format letter \"%c\" is meaningless in \"%s\" command.",
+          fmt.format, cmdname);
+}
+
+/*  Evaluate string EXP as an expression in the current language and
+   print the resulting value.  EXP may contain a format specifier as the
+   first argument ("/x myvar" for example, to print myvar in hex).
+ */
+
+static void
+print_command_1 (char *exp, int inspect, int voidprint)
+{
+  struct expression *expr;
+  register struct cleanup *old_chain = 0;
+  register char format = 0;
+  struct value *val;
+  struct format_data fmt;
+  int cleanup = 0;
+
+  /* Pass inspect flag to the rest of the print routines in a global (sigh). */
+  inspect_it = inspect;
+
+  if (exp && *exp == '/')
+    {
+      exp++;
+      fmt = decode_format (&exp, last_format, 0);
+      validate_format (fmt, "print");
+      last_format = format = fmt.format;
+    }
+  else
+    {
+      fmt.count = 1;
+      fmt.format = 0;
+      fmt.size = 0;
+    }
+
+  if (exp && *exp)
+    {
+      struct type *type;
+      expr = parse_expression (exp);
+      old_chain = make_cleanup (free_current_contents, &expr);
+      cleanup = 1;
+      val = evaluate_expression (expr);
+    }
+  else
+    val = access_value_history (0);
+
+  if (voidprint || (val && VALUE_TYPE (val) &&
+                   TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_VOID))
+    {
+      int histindex = record_latest_value (val);
+
+      if (histindex >= 0)
+       annotate_value_history_begin (histindex, VALUE_TYPE (val));
+      else
+       annotate_value_begin (VALUE_TYPE (val));
+
+      if (inspect)
+       printf_unfiltered ("\031(gdb-makebuffer \"%s\"  %d '(\"", exp, histindex);
+      else if (histindex >= 0)
+       printf_filtered ("$%d = ", histindex);
+
+      if (histindex >= 0)
+       annotate_value_history_value ();
+
+      print_formatted (val, format, fmt.size, gdb_stdout);
+      printf_filtered ("\n");
+
+      if (histindex >= 0)
+       annotate_value_history_end ();
+      else
+       annotate_value_end ();
+
+      if (inspect)
+       printf_unfiltered ("\") )\030");
+    }
+
+  if (cleanup)
+    do_cleanups (old_chain);
+  inspect_it = 0;              /* Reset print routines to normal */
+}
+
+/* ARGSUSED */
+static void
+print_command (char *exp, int from_tty)
+{
+  print_command_1 (exp, 0, 1);
+}
+
+/* Same as print, except in epoch, it gets its own window */
+/* ARGSUSED */
+static void
+inspect_command (char *exp, int from_tty)
+{
+  extern int epoch_interface;
+
+  print_command_1 (exp, epoch_interface, 1);
+}
+
+/* Same as print, except it doesn't print void results. */
+/* ARGSUSED */
+static void
+call_command (char *exp, int from_tty)
+{
+  print_command_1 (exp, 0, 0);
+}
+
+/* ARGSUSED */
+void
+output_command (char *exp, int from_tty)
+{
+  struct expression *expr;
+  register struct cleanup *old_chain;
+  register char format = 0;
+  struct value *val;
+  struct format_data fmt;
+
+  if (exp && *exp == '/')
+    {
+      exp++;
+      fmt = decode_format (&exp, 0, 0);
+      validate_format (fmt, "output");
+      format = fmt.format;
+    }
+
+  expr = parse_expression (exp);
+  old_chain = make_cleanup (free_current_contents, &expr);
+
+  val = evaluate_expression (expr);
+
+  annotate_value_begin (VALUE_TYPE (val));
+
+  print_formatted (val, format, fmt.size, gdb_stdout);
+
+  annotate_value_end ();
+
+  wrap_here ("");
+  gdb_flush (gdb_stdout);
+
+  do_cleanups (old_chain);
+}
+
+/* ARGSUSED */
+static void
+set_command (char *exp, int from_tty)
+{
+  struct expression *expr = parse_expression (exp);
+  register struct cleanup *old_chain =
+    make_cleanup (free_current_contents, &expr);
+  evaluate_expression (expr);
+  do_cleanups (old_chain);
+}
+
+/* ARGSUSED */
+static void
+sym_info (char *arg, int from_tty)
+{
+  struct minimal_symbol *msymbol;
+  struct objfile *objfile;
+  struct obj_section *osect;
+  asection *sect;
+  CORE_ADDR addr, sect_addr;
+  int matches = 0;
+  unsigned int offset;
+
+  if (!arg)
+    error_no_arg ("address");
+
+  addr = parse_and_eval_address (arg);
+  ALL_OBJSECTIONS (objfile, osect)
+  {
+    sect = osect->the_bfd_section;
+    sect_addr = overlay_mapped_address (addr, sect);
+
+    if (osect->addr <= sect_addr && sect_addr < osect->endaddr &&
+       (msymbol = lookup_minimal_symbol_by_pc_section (sect_addr, sect)))
+      {
+       matches = 1;
+       offset = sect_addr - SYMBOL_VALUE_ADDRESS (msymbol);
+       if (offset)
+         printf_filtered ("%s + %u in ",
+                          SYMBOL_SOURCE_NAME (msymbol), offset);
+       else
+         printf_filtered ("%s in ",
+                          SYMBOL_SOURCE_NAME (msymbol));
+       if (pc_in_unmapped_range (addr, sect))
+         printf_filtered ("load address range of ");
+       if (section_is_overlay (sect))
+         printf_filtered ("%s overlay ",
+                          section_is_mapped (sect) ? "mapped" : "unmapped");
+       printf_filtered ("section %s", sect->name);
+       printf_filtered ("\n");
+      }
+  }
+  if (matches == 0)
+    printf_filtered ("No symbol matches %s.\n", arg);
+}
+
+/* ARGSUSED */
+static void
+address_info (char *exp, int from_tty)
+{
+  register struct symbol *sym;
+  register struct minimal_symbol *msymbol;
+  register long val;
+  register long basereg;
+  asection *section;
+  CORE_ADDR load_addr;
+  int is_a_field_of_this;      /* C++: lookup_symbol sets this to nonzero
+                                  if exp is a field of `this'. */
+
+  if (exp == 0)
+    error ("Argument required.");
+
+  sym = lookup_symbol (exp, get_selected_block (0), VAR_NAMESPACE,
+                      &is_a_field_of_this, (struct symtab **) NULL);
+  if (sym == NULL)
+    {
+      if (is_a_field_of_this)
+       {
+         printf_filtered ("Symbol \"");
+         fprintf_symbol_filtered (gdb_stdout, exp,
+                                  current_language->la_language, DMGL_ANSI);
+         printf_filtered ("\" is a field of the local class variable `this'\n");
+         return;
+       }
+
+      msymbol = lookup_minimal_symbol (exp, NULL, NULL);
+
+      if (msymbol != NULL)
+       {
+         load_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+
+         printf_filtered ("Symbol \"");
+         fprintf_symbol_filtered (gdb_stdout, exp,
+                                  current_language->la_language, DMGL_ANSI);
+         printf_filtered ("\" is at ");
+         print_address_numeric (load_addr, 1, gdb_stdout);
+         printf_filtered (" in a file compiled without debugging");
+         section = SYMBOL_BFD_SECTION (msymbol);
+         if (section_is_overlay (section))
+           {
+             load_addr = overlay_unmapped_address (load_addr, section);
+             printf_filtered (",\n -- loaded at ");
+             print_address_numeric (load_addr, 1, gdb_stdout);
+             printf_filtered (" in overlay section %s", section->name);
+           }
+         printf_filtered (".\n");
+       }
+      else
+       error ("No symbol \"%s\" in current context.", exp);
+      return;
+    }
+
+  printf_filtered ("Symbol \"");
+  fprintf_symbol_filtered (gdb_stdout, SYMBOL_NAME (sym),
+                          current_language->la_language, DMGL_ANSI);
+  printf_filtered ("\" is ");
+  val = SYMBOL_VALUE (sym);
+  basereg = SYMBOL_BASEREG (sym);
+  section = SYMBOL_BFD_SECTION (sym);
+
+  switch (SYMBOL_CLASS (sym))
+    {
+    case LOC_CONST:
+    case LOC_CONST_BYTES:
+      printf_filtered ("constant");
+      break;
+
+    case LOC_LABEL:
+      printf_filtered ("a label at address ");
+      print_address_numeric (load_addr = SYMBOL_VALUE_ADDRESS (sym),
+                            1, gdb_stdout);
+      if (section_is_overlay (section))
+       {
+         load_addr = overlay_unmapped_address (load_addr, section);
+         printf_filtered (",\n -- loaded at ");
+         print_address_numeric (load_addr, 1, gdb_stdout);
+         printf_filtered (" in overlay section %s", section->name);
+       }
+      break;
+
+    case LOC_REGISTER:
+      printf_filtered ("a variable in register %s", REGISTER_NAME (val));
+      break;
+
+    case LOC_STATIC:
+      printf_filtered ("static storage at address ");
+      print_address_numeric (load_addr = SYMBOL_VALUE_ADDRESS (sym),
+                            1, gdb_stdout);
+      if (section_is_overlay (section))
+       {
+         load_addr = overlay_unmapped_address (load_addr, section);
+         printf_filtered (",\n -- loaded at ");
+         print_address_numeric (load_addr, 1, gdb_stdout);
+         printf_filtered (" in overlay section %s", section->name);
+       }
+      break;
+
+    case LOC_INDIRECT:
+      printf_filtered ("external global (indirect addressing), at address *(");
+      print_address_numeric (load_addr = SYMBOL_VALUE_ADDRESS (sym),
+                            1, gdb_stdout);
+      printf_filtered (")");
+      if (section_is_overlay (section))
+       {
+         load_addr = overlay_unmapped_address (load_addr, section);
+         printf_filtered (",\n -- loaded at ");
+         print_address_numeric (load_addr, 1, gdb_stdout);
+         printf_filtered (" in overlay section %s", section->name);
+       }
+      break;
+
+    case LOC_REGPARM:
+      printf_filtered ("an argument in register %s", REGISTER_NAME (val));
+      break;
+
+    case LOC_REGPARM_ADDR:
+      printf_filtered ("address of an argument in register %s", REGISTER_NAME (val));
+      break;
+
+    case LOC_ARG:
+      printf_filtered ("an argument at offset %ld", val);
+      break;
+
+    case LOC_LOCAL_ARG:
+      printf_filtered ("an argument at frame offset %ld", val);
+      break;
+
+    case LOC_LOCAL:
+      printf_filtered ("a local variable at frame offset %ld", val);
+      break;
+
+    case LOC_REF_ARG:
+      printf_filtered ("a reference argument at offset %ld", val);
+      break;
+
+    case LOC_BASEREG:
+      printf_filtered ("a variable at offset %ld from register %s",
+                      val, REGISTER_NAME (basereg));
+      break;
+
+    case LOC_BASEREG_ARG:
+      printf_filtered ("an argument at offset %ld from register %s",
+                      val, REGISTER_NAME (basereg));
+      break;
+
+    case LOC_TYPEDEF:
+      printf_filtered ("a typedef");
+      break;
+
+    case LOC_BLOCK:
+      printf_filtered ("a function at address ");
+#ifdef GDB_TARGET_MASK_DISAS_PC
+      print_address_numeric
+       (load_addr = GDB_TARGET_MASK_DISAS_PC (BLOCK_START (SYMBOL_BLOCK_VALUE (sym))),
+        1, gdb_stdout);
+#else
+      print_address_numeric (load_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)),
+                            1, gdb_stdout);
+#endif
+      if (section_is_overlay (section))
+       {
+         load_addr = overlay_unmapped_address (load_addr, section);
+         printf_filtered (",\n -- loaded at ");
+         print_address_numeric (load_addr, 1, gdb_stdout);
+         printf_filtered (" in overlay section %s", section->name);
+       }
+      break;
+
+    case LOC_UNRESOLVED:
+      {
+       struct minimal_symbol *msym;
+
+       msym = lookup_minimal_symbol (SYMBOL_NAME (sym), NULL, NULL);
+       if (msym == NULL)
+         printf_filtered ("unresolved");
+       else
+         {
+           section = SYMBOL_BFD_SECTION (msym);
+           printf_filtered ("static storage at address ");
+           print_address_numeric (load_addr = SYMBOL_VALUE_ADDRESS (msym),
+                                  1, gdb_stdout);
+           if (section_is_overlay (section))
+             {
+               load_addr = overlay_unmapped_address (load_addr, section);
+               printf_filtered (",\n -- loaded at ");
+               print_address_numeric (load_addr, 1, gdb_stdout);
+               printf_filtered (" in overlay section %s", section->name);
+             }
+         }
+      }
+      break;
+
+    case LOC_THREAD_LOCAL_STATIC:
+      printf_filtered (
+                       "a thread-local variable at offset %ld from the thread base register %s",
+                       val, REGISTER_NAME (basereg));
+      break;
+
+    case LOC_OPTIMIZED_OUT:
+      printf_filtered ("optimized out");
+      break;
+
+    default:
+      printf_filtered ("of unknown (botched) type");
+      break;
+    }
+  printf_filtered (".\n");
+}
+\f
+void
+x_command (char *exp, int from_tty)
+{
+  struct expression *expr;
+  struct format_data fmt;
+  struct cleanup *old_chain;
+  struct value *val;
+
+  fmt.format = last_format;
+  fmt.size = last_size;
+  fmt.count = 1;
+
+  if (exp && *exp == '/')
+    {
+      exp++;
+      fmt = decode_format (&exp, last_format, last_size);
+    }
+
+  /* If we have an expression, evaluate it and use it as the address.  */
+
+  if (exp != 0 && *exp != 0)
+    {
+      expr = parse_expression (exp);
+      /* Cause expression not to be there any more
+         if this command is repeated with Newline.
+         But don't clobber a user-defined command's definition.  */
+      if (from_tty)
+       *exp = 0;
+      old_chain = make_cleanup (free_current_contents, &expr);
+      val = evaluate_expression (expr);
+      if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF)
+       val = value_ind (val);
+      /* In rvalue contexts, such as this, functions are coerced into
+         pointers to functions.  This makes "x/i main" work.  */
+      if (/* last_format == 'i'  && */ 
+         TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC
+          && VALUE_LVAL (val) == lval_memory)
+       next_address = VALUE_ADDRESS (val);
+      else
+       next_address = value_as_address (val);
+      if (VALUE_BFD_SECTION (val))
+       next_section = VALUE_BFD_SECTION (val);
+      do_cleanups (old_chain);
+    }
+
+  do_examine (fmt, next_address, next_section);
+
+  /* If the examine succeeds, we remember its size and format for next time.  */
+  last_size = fmt.size;
+  last_format = fmt.format;
+
+  /* Set a couple of internal variables if appropriate. */
+  if (last_examine_value)
+    {
+      /* Make last address examined available to the user as $_.  Use
+         the correct pointer type.  */
+      struct type *pointer_type
+       = lookup_pointer_type (VALUE_TYPE (last_examine_value));
+      set_internalvar (lookup_internalvar ("_"),
+                      value_from_pointer (pointer_type,
+                                          last_examine_address));
+
+      /* Make contents of last address examined available to the user as $__. */
+      /* If the last value has not been fetched from memory then don't
+         fetch it now - instead mark it by voiding the $__ variable. */
+      if (VALUE_LAZY (last_examine_value))
+       set_internalvar (lookup_internalvar ("__"),
+                        allocate_value (builtin_type_void));
+      else
+       set_internalvar (lookup_internalvar ("__"), last_examine_value);
+    }
+}
+\f
+
+/* Add an expression to the auto-display chain.
+   Specify the expression.  */
+
+static void
+display_command (char *exp, int from_tty)
+{
+  struct format_data fmt;
+  register struct expression *expr;
+  register struct display *new;
+  int display_it = 1;
+
+#if defined(TUI)
+  if (tui_version && *exp == '$')
+    display_it = (tui_set_layout (exp) == TUI_FAILURE);
+#endif
+
+  if (display_it)
+    {
+      if (exp == 0)
+       {
+         do_displays ();
+         return;
+       }
+
+      if (*exp == '/')
+       {
+         exp++;
+         fmt = decode_format (&exp, 0, 0);
+         if (fmt.size && fmt.format == 0)
+           fmt.format = 'x';
+         if (fmt.format == 'i' || fmt.format == 's')
+           fmt.size = 'b';
+       }
+      else
+       {
+         fmt.format = 0;
+         fmt.size = 0;
+         fmt.count = 0;
+       }
+
+      innermost_block = 0;
+      expr = parse_expression (exp);
+
+      new = (struct display *) xmalloc (sizeof (struct display));
+
+      new->exp = expr;
+      new->block = innermost_block;
+      new->next = display_chain;
+      new->number = ++display_number;
+      new->format = fmt;
+      new->enabled_p = 1;
+      display_chain = new;
+
+      if (from_tty && target_has_execution)
+       do_one_display (new);
+
+      dont_repeat ();
+    }
+}
+
+static void
+free_display (struct display *d)
+{
+  xfree (d->exp);
+  xfree (d);
+}
+
+/* Clear out the display_chain.
+   Done when new symtabs are loaded, since this invalidates
+   the types stored in many expressions.  */
+
+void
+clear_displays (void)
+{
+  register struct display *d;
+
+  while ((d = display_chain) != NULL)
+    {
+      xfree (d->exp);
+      display_chain = d->next;
+      xfree (d);
+    }
+}
+
+/* Delete the auto-display number NUM.  */
+
+static void
+delete_display (int num)
+{
+  register struct display *d1, *d;
+
+  if (!display_chain)
+    error ("No display number %d.", num);
+
+  if (display_chain->number == num)
+    {
+      d1 = display_chain;
+      display_chain = d1->next;
+      free_display (d1);
+    }
+  else
+    for (d = display_chain;; d = d->next)
+      {
+       if (d->next == 0)
+         error ("No display number %d.", num);
+       if (d->next->number == num)
+         {
+           d1 = d->next;
+           d->next = d1->next;
+           free_display (d1);
+           break;
+         }
+      }
+}
+
+/* Delete some values from the auto-display chain.
+   Specify the element numbers.  */
+
+static void
+undisplay_command (char *args, int from_tty)
+{
+  register char *p = args;
+  register char *p1;
+  register int num;
+
+  if (args == 0)
+    {
+      if (query ("Delete all auto-display expressions? "))
+       clear_displays ();
+      dont_repeat ();
+      return;
+    }
+
+  while (*p)
+    {
+      p1 = p;
+      while (*p1 >= '0' && *p1 <= '9')
+       p1++;
+      if (*p1 && *p1 != ' ' && *p1 != '\t')
+       error ("Arguments must be display numbers.");
+
+      num = atoi (p);
+
+      delete_display (num);
+
+      p = p1;
+      while (*p == ' ' || *p == '\t')
+       p++;
+    }
+  dont_repeat ();
+}
+
+/* Display a single auto-display.  
+   Do nothing if the display cannot be printed in the current context,
+   or if the display is disabled. */
+
+static void
+do_one_display (struct display *d)
+{
+  int within_current_scope;
+
+  if (d->enabled_p == 0)
+    return;
+
+  if (d->block)
+    within_current_scope = contained_in (get_selected_block (0), d->block);
+  else
+    within_current_scope = 1;
+  if (!within_current_scope)
+    return;
+
+  current_display_number = d->number;
+
+  annotate_display_begin ();
+  printf_filtered ("%d", d->number);
+  annotate_display_number_end ();
+  printf_filtered (": ");
+  if (d->format.size)
+    {
+      CORE_ADDR addr;
+      struct value *val;
+
+      annotate_display_format ();
+
+      printf_filtered ("x/");
+      if (d->format.count != 1)
+       printf_filtered ("%d", d->format.count);
+      printf_filtered ("%c", d->format.format);
+      if (d->format.format != 'i' && d->format.format != 's')
+       printf_filtered ("%c", d->format.size);
+      printf_filtered (" ");
+
+      annotate_display_expression ();
+
+      print_expression (d->exp, gdb_stdout);
+      annotate_display_expression_end ();
+
+      if (d->format.count != 1)
+       printf_filtered ("\n");
+      else
+       printf_filtered ("  ");
+
+      val = evaluate_expression (d->exp);
+      addr = value_as_address (val);
+      if (d->format.format == 'i')
+       addr = ADDR_BITS_REMOVE (addr);
+
+      annotate_display_value ();
+
+      do_examine (d->format, addr, VALUE_BFD_SECTION (val));
+    }
+  else
+    {
+      annotate_display_format ();
+
+      if (d->format.format)
+       printf_filtered ("/%c ", d->format.format);
+
+      annotate_display_expression ();
+
+      print_expression (d->exp, gdb_stdout);
+      annotate_display_expression_end ();
+
+      printf_filtered (" = ");
+
+      annotate_display_expression ();
+
+      print_formatted (evaluate_expression (d->exp),
+                      d->format.format, d->format.size, gdb_stdout);
+      printf_filtered ("\n");
+    }
+
+  annotate_display_end ();
+
+  gdb_flush (gdb_stdout);
+  current_display_number = -1;
+}
+
+/* Display all of the values on the auto-display chain which can be
+   evaluated in the current scope.  */
+
+void
+do_displays (void)
+{
+  register struct display *d;
+
+  for (d = display_chain; d; d = d->next)
+    do_one_display (d);
+}
+
+/* Delete the auto-display which we were in the process of displaying.
+   This is done when there is an error or a signal.  */
+
+void
+disable_display (int num)
+{
+  register struct display *d;
+
+  for (d = display_chain; d; d = d->next)
+    if (d->number == num)
+      {
+       d->enabled_p = 0;
+       return;
+      }
+  printf_unfiltered ("No display number %d.\n", num);
+}
+
+void
+disable_current_display (void)
+{
+  if (current_display_number >= 0)
+    {
+      disable_display (current_display_number);
+      fprintf_unfiltered (gdb_stderr, "Disabling display %d to avoid infinite recursion.\n",
+                         current_display_number);
+    }
+  current_display_number = -1;
+}
+
+static void
+display_info (char *ignore, int from_tty)
+{
+  register struct display *d;
+
+  if (!display_chain)
+    printf_unfiltered ("There are no auto-display expressions now.\n");
+  else
+    printf_filtered ("Auto-display expressions now in effect:\n\
+Num Enb Expression\n");
+
+  for (d = display_chain; d; d = d->next)
+    {
+      printf_filtered ("%d:   %c  ", d->number, "ny"[(int) d->enabled_p]);
+      if (d->format.size)
+       printf_filtered ("/%d%c%c ", d->format.count, d->format.size,
+                        d->format.format);
+      else if (d->format.format)
+       printf_filtered ("/%c ", d->format.format);
+      print_expression (d->exp, gdb_stdout);
+      if (d->block && !contained_in (get_selected_block (0), d->block))
+       printf_filtered (" (cannot be evaluated in the current context)");
+      printf_filtered ("\n");
+      gdb_flush (gdb_stdout);
+    }
+}
+
+static void
+enable_display (char *args, int from_tty)
+{
+  register char *p = args;
+  register char *p1;
+  register int num;
+  register struct display *d;
+
+  if (p == 0)
+    {
+      for (d = display_chain; d; d = d->next)
+       d->enabled_p = 1;
+    }
+  else
+    while (*p)
+      {
+       p1 = p;
+       while (*p1 >= '0' && *p1 <= '9')
+         p1++;
+       if (*p1 && *p1 != ' ' && *p1 != '\t')
+         error ("Arguments must be display numbers.");
+
+       num = atoi (p);
+
+       for (d = display_chain; d; d = d->next)
+         if (d->number == num)
+           {
+             d->enabled_p = 1;
+             goto win;
+           }
+       printf_unfiltered ("No display number %d.\n", num);
+      win:
+       p = p1;
+       while (*p == ' ' || *p == '\t')
+         p++;
+      }
+}
+
+/* ARGSUSED */
+static void
+disable_display_command (char *args, int from_tty)
+{
+  register char *p = args;
+  register char *p1;
+  register struct display *d;
+
+  if (p == 0)
+    {
+      for (d = display_chain; d; d = d->next)
+       d->enabled_p = 0;
+    }
+  else
+    while (*p)
+      {
+       p1 = p;
+       while (*p1 >= '0' && *p1 <= '9')
+         p1++;
+       if (*p1 && *p1 != ' ' && *p1 != '\t')
+         error ("Arguments must be display numbers.");
+
+       disable_display (atoi (p));
+
+       p = p1;
+       while (*p == ' ' || *p == '\t')
+         p++;
+      }
+}
+\f
+
+/* Print the value in stack frame FRAME of a variable
+   specified by a struct symbol.  */
+
+void
+print_variable_value (struct symbol *var, struct frame_info *frame,
+                     struct ui_file *stream)
+{
+  struct value *val = read_var_value (var, frame);
+
+  value_print (val, stream, 0, Val_pretty_default);
+}
+
+/* Print the arguments of a stack frame, given the function FUNC
+   running in that frame (as a symbol), the info on the frame,
+   and the number of args according to the stack frame (or -1 if unknown).  */
+
+/* References here and elsewhere to "number of args according to the
+   stack frame" appear in all cases to refer to "number of ints of args
+   according to the stack frame".  At least for VAX, i386, isi.  */
+
+void
+print_frame_args (struct symbol *func, struct frame_info *fi, int num,
+                 struct ui_file *stream)
+{
+  struct block *b = NULL;
+  int first = 1;
+  register int i;
+  register struct symbol *sym;
+  struct value *val;
+  /* Offset of next stack argument beyond the one we have seen that is
+     at the highest offset.
+     -1 if we haven't come to a stack argument yet.  */
+  long highest_offset = -1;
+  int arg_size;
+  /* Number of ints of arguments that we have printed so far.  */
+  int args_printed = 0;
+  struct cleanup *old_chain, *list_chain;
+  struct ui_stream *stb;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  if (func)
+    {
+      b = SYMBOL_BLOCK_VALUE (func);
+      /* Function blocks are order sensitive, and thus should not be
+        hashed.  */
+      gdb_assert (BLOCK_HASHTABLE (b) == 0);
+
+      ALL_BLOCK_SYMBOLS (b, i, sym)
+        {
+         QUIT;
+
+         /* Keep track of the highest stack argument offset seen, and
+            skip over any kinds of symbols we don't care about.  */
+
+         switch (SYMBOL_CLASS (sym))
+           {
+           case LOC_ARG:
+           case LOC_REF_ARG:
+             {
+               long current_offset = SYMBOL_VALUE (sym);
+               arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym));
+
+               /* Compute address of next argument by adding the size of
+                  this argument and rounding to an int boundary.  */
+               current_offset =
+                 ((current_offset + arg_size + sizeof (int) - 1)
+                  & ~(sizeof (int) - 1));
+
+               /* If this is the highest offset seen yet, set highest_offset.  */
+               if (highest_offset == -1
+                   || (current_offset > highest_offset))
+                 highest_offset = current_offset;
+
+               /* Add the number of ints we're about to print to args_printed.  */
+               args_printed += (arg_size + sizeof (int) - 1) / sizeof (int);
+             }
+
+             /* We care about types of symbols, but don't need to keep track of
+                stack offsets in them.  */
+           case LOC_REGPARM:
+           case LOC_REGPARM_ADDR:
+           case LOC_LOCAL_ARG:
+           case LOC_BASEREG_ARG:
+             break;
+
+           /* Other types of symbols we just skip over.  */
+           default:
+             continue;
+           }
+
+         /* We have to look up the symbol because arguments can have
+            two entries (one a parameter, one a local) and the one we
+            want is the local, which lookup_symbol will find for us.
+            This includes gcc1 (not gcc2) on the sparc when passing a
+            small structure and gcc2 when the argument type is float
+            and it is passed as a double and converted to float by
+            the prologue (in the latter case the type of the LOC_ARG
+            symbol is double and the type of the LOC_LOCAL symbol is
+            float).  */
+         /* But if the parameter name is null, don't try it.
+            Null parameter names occur on the RS/6000, for traceback tables.
+            FIXME, should we even print them?  */
+
+         if (*SYMBOL_NAME (sym))
+           {
+             struct symbol *nsym;
+             nsym = lookup_symbol
+               (SYMBOL_NAME (sym),
+                b, VAR_NAMESPACE, (int *) NULL, (struct symtab **) NULL);
+             if (SYMBOL_CLASS (nsym) == LOC_REGISTER)
+               {
+                 /* There is a LOC_ARG/LOC_REGISTER pair.  This means that
+                    it was passed on the stack and loaded into a register,
+                    or passed in a register and stored in a stack slot.
+                    GDB 3.x used the LOC_ARG; GDB 4.0-4.11 used the LOC_REGISTER.
+
+                    Reasons for using the LOC_ARG:
+                    (1) because find_saved_registers may be slow for remote
+                    debugging,
+                    (2) because registers are often re-used and stack slots
+                    rarely (never?) are.  Therefore using the stack slot is
+                    much less likely to print garbage.
+
+                    Reasons why we might want to use the LOC_REGISTER:
+                    (1) So that the backtrace prints the same value as
+                    "print foo".  I see no compelling reason why this needs
+                    to be the case; having the backtrace print the value which
+                    was passed in, and "print foo" print the value as modified
+                    within the called function, makes perfect sense to me.
+
+                    Additional note:  It might be nice if "info args" displayed
+                    both values.
+                    One more note:  There is a case with sparc structure passing
+                    where we need to use the LOC_REGISTER, but this is dealt with
+                    by creating a single LOC_REGPARM in symbol reading.  */
+
+                 /* Leave sym (the LOC_ARG) alone.  */
+                 ;
+               }
+             else
+               sym = nsym;
+           }
+
+         /* Print the current arg.  */
+         if (!first)
+           ui_out_text (uiout, ", ");
+         ui_out_wrap_hint (uiout, "    ");
+
+         annotate_arg_begin ();
+
+         list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+         fprintf_symbol_filtered (stb->stream, SYMBOL_SOURCE_NAME (sym),
+                                  SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
+         ui_out_field_stream (uiout, "name", stb);
+         annotate_arg_name_end ();
+         ui_out_text (uiout, "=");
+
+         /* Avoid value_print because it will deref ref parameters.  We just
+            want to print their addresses.  Print ??? for args whose address
+            we do not know.  We pass 2 as "recurse" to val_print because our
+            standard indentation here is 4 spaces, and val_print indents
+            2 for each recurse.  */
+         val = read_var_value (sym, fi);
+
+         annotate_arg_value (val == NULL ? NULL : VALUE_TYPE (val));
+
+         if (val)
+           {
+             val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
+                        VALUE_ADDRESS (val),
+                        stb->stream, 0, 0, 2, Val_no_prettyprint);
+             ui_out_field_stream (uiout, "value", stb);
+           }
+         else
+           ui_out_text (uiout, "???");
+
+         /* Invoke ui_out_tuple_end.  */
+         do_cleanups (list_chain);
+
+         annotate_arg_end ();
+
+         first = 0;
+       }
+    }
+
+  /* Don't print nameless args in situations where we don't know
+     enough about the stack to find them.  */
+  if (num != -1)
+    {
+      long start;
+
+      if (highest_offset == -1)
+       start = FRAME_ARGS_SKIP;
+      else
+       start = highest_offset;
+
+      print_frame_nameless_args (fi, start, num - args_printed,
+                                first, stream);
+    }
+  do_cleanups (old_chain);
+}
+
+/* Print nameless args on STREAM.
+   FI is the frameinfo for this frame, START is the offset
+   of the first nameless arg, and NUM is the number of nameless args to
+   print.  FIRST is nonzero if this is the first argument (not just
+   the first nameless arg).  */
+
+static void
+print_frame_nameless_args (struct frame_info *fi, long start, int num,
+                          int first, struct ui_file *stream)
+{
+  int i;
+  CORE_ADDR argsaddr;
+  long arg_value;
+
+  for (i = 0; i < num; i++)
+    {
+      QUIT;
+#ifdef NAMELESS_ARG_VALUE
+      NAMELESS_ARG_VALUE (fi, start, &arg_value);
+#else
+      argsaddr = FRAME_ARGS_ADDRESS (fi);
+      if (!argsaddr)
+       return;
+
+      arg_value = read_memory_integer (argsaddr + start, sizeof (int));
+#endif
+
+      if (!first)
+       fprintf_filtered (stream, ", ");
+
+#ifdef PRINT_NAMELESS_INTEGER
+      PRINT_NAMELESS_INTEGER (stream, arg_value);
+#else
+#ifdef PRINT_TYPELESS_INTEGER
+      PRINT_TYPELESS_INTEGER (stream, builtin_type_int, (LONGEST) arg_value);
+#else
+      fprintf_filtered (stream, "%ld", arg_value);
+#endif /* PRINT_TYPELESS_INTEGER */
+#endif /* PRINT_NAMELESS_INTEGER */
+      first = 0;
+      start += sizeof (int);
+    }
+}
+\f
+/* ARGSUSED */
+static void
+printf_command (char *arg, int from_tty)
+{
+  register char *f = NULL;
+  register char *s = arg;
+  char *string = NULL;
+  struct value **val_args;
+  char *substrings;
+  char *current_substring;
+  int nargs = 0;
+  int allocated_args = 20;
+  struct cleanup *old_cleanups;
+
+  val_args = (struct value **) xmalloc (allocated_args
+                                       * sizeof (struct value *));
+  old_cleanups = make_cleanup (free_current_contents, &val_args);
+
+  if (s == 0)
+    error_no_arg ("format-control string and values to print");
+
+  /* Skip white space before format string */
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  /* A format string should follow, enveloped in double quotes */
+  if (*s++ != '"')
+    error ("Bad format string, missing '\"'.");
+
+  /* Parse the format-control string and copy it into the string STRING,
+     processing some kinds of escape sequence.  */
+
+  f = string = (char *) alloca (strlen (s) + 1);
+
+  while (*s != '"')
+    {
+      int c = *s++;
+      switch (c)
+       {
+       case '\0':
+         error ("Bad format string, non-terminated '\"'.");
+
+       case '\\':
+         switch (c = *s++)
+           {
+           case '\\':
+             *f++ = '\\';
+             break;
+           case 'a':
+             *f++ = '\a';
+             break;
+           case 'b':
+             *f++ = '\b';
+             break;
+           case 'f':
+             *f++ = '\f';
+             break;
+           case 'n':
+             *f++ = '\n';
+             break;
+           case 'r':
+             *f++ = '\r';
+             break;
+           case 't':
+             *f++ = '\t';
+             break;
+           case 'v':
+             *f++ = '\v';
+             break;
+           case '"':
+             *f++ = '"';
+             break;
+           default:
+             /* ??? TODO: handle other escape sequences */
+             error ("Unrecognized escape character \\%c in format string.",
+                    c);
+           }
+         break;
+
+       default:
+         *f++ = c;
+       }
+    }
+
+  /* Skip over " and following space and comma.  */
+  s++;
+  *f++ = '\0';
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (*s != ',' && *s != 0)
+    error ("Invalid argument syntax");
+
+  if (*s == ',')
+    s++;
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  /* Need extra space for the '\0's.  Doubling the size is sufficient.  */
+  substrings = alloca (strlen (string) * 2);
+  current_substring = substrings;
+
+  {
+    /* Now scan the string for %-specs and see what kinds of args they want.
+       argclass[I] classifies the %-specs so we can give printf_filtered
+       something of the right size.  */
+
+    enum argclass
+      {
+       no_arg, int_arg, string_arg, double_arg, long_long_arg
+      };
+    enum argclass *argclass;
+    enum argclass this_argclass;
+    char *last_arg;
+    int nargs_wanted;
+    int lcount;
+    int i;
+
+    argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass);
+    nargs_wanted = 0;
+    f = string;
+    last_arg = string;
+    while (*f)
+      if (*f++ == '%')
+       {
+         lcount = 0;
+         while (strchr ("0123456789.hlL-+ #", *f))
+           {
+             if (*f == 'l' || *f == 'L')
+               lcount++;
+             f++;
+           }
+         switch (*f)
+           {
+           case 's':
+             this_argclass = string_arg;
+             break;
+
+           case 'e':
+           case 'f':
+           case 'g':
+             this_argclass = double_arg;
+             break;
+
+           case '*':
+             error ("`*' not supported for precision or width in printf");
+
+           case 'n':
+             error ("Format specifier `n' not supported in printf");
+
+           case '%':
+             this_argclass = no_arg;
+             break;
+
+           default:
+             if (lcount > 1)
+               this_argclass = long_long_arg;
+             else
+               this_argclass = int_arg;
+             break;
+           }
+         f++;
+         if (this_argclass != no_arg)
+           {
+             strncpy (current_substring, last_arg, f - last_arg);
+             current_substring += f - last_arg;
+             *current_substring++ = '\0';
+             last_arg = f;
+             argclass[nargs_wanted++] = this_argclass;
+           }
+       }
+
+    /* Now, parse all arguments and evaluate them.
+       Store the VALUEs in VAL_ARGS.  */
+
+    while (*s != '\0')
+      {
+       char *s1;
+       if (nargs == allocated_args)
+         val_args = (struct value **) xrealloc ((char *) val_args,
+                                                (allocated_args *= 2)
+                                                * sizeof (struct value *));
+       s1 = s;
+       val_args[nargs] = parse_to_comma_and_eval (&s1);
+
+       /* If format string wants a float, unchecked-convert the value to
+          floating point of the same size */
+
+       if (argclass[nargs] == double_arg)
+         {
+           struct type *type = VALUE_TYPE (val_args[nargs]);
+           if (TYPE_LENGTH (type) == sizeof (float))
+               VALUE_TYPE (val_args[nargs]) = builtin_type_float;
+           if (TYPE_LENGTH (type) == sizeof (double))
+               VALUE_TYPE (val_args[nargs]) = builtin_type_double;
+         }
+       nargs++;
+       s = s1;
+       if (*s == ',')
+         s++;
+      }
+
+    if (nargs != nargs_wanted)
+      error ("Wrong number of arguments for specified format-string");
+
+    /* Now actually print them.  */
+    current_substring = substrings;
+    for (i = 0; i < nargs; i++)
+      {
+       switch (argclass[i])
+         {
+         case string_arg:
+           {
+             char *str;
+             CORE_ADDR tem;
+             int j;
+             tem = value_as_address (val_args[i]);
+
+             /* This is a %s argument.  Find the length of the string.  */
+             for (j = 0;; j++)
+               {
+                 char c;
+                 QUIT;
+                 read_memory (tem + j, &c, 1);
+                 if (c == 0)
+                   break;
+               }
+
+             /* Copy the string contents into a string inside GDB.  */
+             str = (char *) alloca (j + 1);
+             if (j != 0)
+               read_memory (tem, str, j);
+             str[j] = 0;
+
+             printf_filtered (current_substring, str);
+           }
+           break;
+         case double_arg:
+           {
+             double val = value_as_double (val_args[i]);
+             printf_filtered (current_substring, val);
+             break;
+           }
+         case long_long_arg:
+#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
+           {
+             long long val = value_as_long (val_args[i]);
+             printf_filtered (current_substring, val);
+             break;
+           }
+#else
+           error ("long long not supported in printf");
+#endif
+         case int_arg:
+           {
+             /* FIXME: there should be separate int_arg and long_arg.  */
+             long val = value_as_long (val_args[i]);
+             printf_filtered (current_substring, val);
+             break;
+           }
+         default:              /* purecov: deadcode */
+           error ("internal error in printf_command");         /* purecov: deadcode */
+         }
+       /* Skip to the next substring.  */
+       current_substring += strlen (current_substring) + 1;
+      }
+    /* Print the portion of the format string after the last argument.  */
+    printf_filtered (last_arg);
+  }
+  do_cleanups (old_cleanups);
+}
+\f
+/* Dump a specified section of assembly code.  With no command line
+   arguments, this command will dump the assembly code for the
+   function surrounding the pc value in the selected frame.  With one
+   argument, it will dump the assembly code surrounding that pc value.
+   Two arguments are interpeted as bounds within which to dump
+   assembly.  */
+
+/* ARGSUSED */
+static void
+disassemble_command (char *arg, int from_tty)
+{
+  CORE_ADDR low, high;
+  char *name;
+  CORE_ADDR pc, pc_masked;
+  char *space_index;
+#if 0
+  asection *section;
+#endif
+
+  name = NULL;
+  if (!arg)
+    {
+      if (!selected_frame)
+       error ("No frame selected.\n");
+
+      pc = get_frame_pc (selected_frame);
+      if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+       error ("No function contains program counter for selected frame.\n");
+#if defined(TUI)
+      else if (tui_version)
+       low = tuiGetLowDisassemblyAddress (low, pc);
+#endif
+      low += FUNCTION_START_OFFSET;
+    }
+  else if (!(space_index = (char *) strchr (arg, ' ')))
+    {
+      /* One argument.  */
+      pc = parse_and_eval_address (arg);
+      if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+       error ("No function contains specified address.\n");
+#if defined(TUI)
+      else if (tui_version)
+       low = tuiGetLowDisassemblyAddress (low, pc);
+#endif
+      low += FUNCTION_START_OFFSET;
+    }
+  else
+    {
+      /* Two arguments.  */
+      *space_index = '\0';
+      low = parse_and_eval_address (arg);
+      high = parse_and_eval_address (space_index + 1);
+    }
+
+#if defined(TUI)
+  if (!tui_is_window_visible (DISASSEM_WIN))
+#endif
+    {
+      printf_filtered ("Dump of assembler code ");
+      if (name != NULL)
+       {
+         printf_filtered ("for function %s:\n", name);
+       }
+      else
+       {
+         printf_filtered ("from ");
+         print_address_numeric (low, 1, gdb_stdout);
+         printf_filtered (" to ");
+         print_address_numeric (high, 1, gdb_stdout);
+         printf_filtered (":\n");
+       }
+
+      /* Dump the specified range.  */
+      pc = low;
+
+#ifdef GDB_TARGET_MASK_DISAS_PC
+      pc_masked = GDB_TARGET_MASK_DISAS_PC (pc);
+#else
+      pc_masked = pc;
+#endif
+
+      while (pc_masked < high)
+       {
+         QUIT;
+         print_address (pc_masked, gdb_stdout);
+         printf_filtered (":\t");
+         /* We often wrap here if there are long symbolic names.  */
+         wrap_here ("    ");
+         pc += print_insn (pc, gdb_stdout);
+         printf_filtered ("\n");
+
+#ifdef GDB_TARGET_MASK_DISAS_PC
+         pc_masked = GDB_TARGET_MASK_DISAS_PC (pc);
+#else
+         pc_masked = pc;
+#endif
+       }
+      printf_filtered ("End of assembler dump.\n");
+      gdb_flush (gdb_stdout);
+    }
+#if defined(TUI)
+  else
+    {
+      tui_show_assembly (low);
+    }
+#endif
+}
+
+/* Print the instruction at address MEMADDR in debugged memory,
+   on STREAM.  Returns length of the instruction, in bytes.  */
+
+static int
+print_insn (CORE_ADDR memaddr, struct ui_file *stream)
+{
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    TARGET_PRINT_INSN_INFO->endian = BFD_ENDIAN_BIG;
+  else
+    TARGET_PRINT_INSN_INFO->endian = BFD_ENDIAN_LITTLE;
+
+  if (TARGET_ARCHITECTURE != NULL)
+    TARGET_PRINT_INSN_INFO->mach = TARGET_ARCHITECTURE->mach;
+  /* else: should set .mach=0 but some disassemblers don't grok this */
+
+  TARGET_PRINT_INSN_INFO->stream = stream;
+
+  return TARGET_PRINT_INSN (memaddr, TARGET_PRINT_INSN_INFO);
+}
+\f
+
+void
+_initialize_printcmd (void)
+{
+  struct cmd_list_element *c;
+
+  current_display_number = -1;
+
+  add_info ("address", address_info,
+           "Describe where symbol SYM is stored.");
+
+  add_info ("symbol", sym_info,
+           "Describe what symbol is at location ADDR.\n\
+Only for symbols with fixed locations (global or static scope).");
+
+  add_com ("x", class_vars, x_command,
+          concat ("Examine memory: x/FMT ADDRESS.\n\
+ADDRESS is an expression for the memory address to examine.\n\
+FMT is a repeat count followed by a format letter and a size letter.\n\
+Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\
+  t(binary), f(float), a(address), i(instruction), c(char) and s(string).\n",
+                  "Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\
+The specified number of objects of the specified size are printed\n\
+according to the format.\n\n\
+Defaults for format and size letters are those previously used.\n\
+Default count is 1.  Default address is following last thing printed\n\
+with this command or \"print\".", NULL));
+
+  c = add_com ("disassemble", class_vars, disassemble_command,
+              "Disassemble a specified section of memory.\n\
+Default is the function surrounding the pc of the selected frame.\n\
+With a single argument, the function surrounding that address is dumped.\n\
+Two arguments are taken as a range of memory to dump.");
+  set_cmd_completer (c, location_completer);
+  if (xdb_commands)
+    add_com_alias ("va", "disassemble", class_xdb, 0);
+
+#if 0
+  add_com ("whereis", class_vars, whereis_command,
+          "Print line number and file of definition of variable.");
+#endif
+
+  add_info ("display", display_info,
+           "Expressions to display when program stops, with code numbers.");
+
+  add_cmd ("undisplay", class_vars, undisplay_command,
+          "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+\"delete display\" has the same effect as this command.\n\
+Do \"info display\" to see current list of code numbers.",
+          &cmdlist);
+
+  add_com ("display", class_vars, display_command,
+          "Print value of expression EXP each time the program stops.\n\
+/FMT may be used before EXP as in the \"print\" command.\n\
+/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\
+as in the \"x\" command, and then EXP is used to get the address to examine\n\
+and examining is done as in the \"x\" command.\n\n\
+With no argument, display all currently requested auto-display expressions.\n\
+Use \"undisplay\" to cancel display requests previously made."
+    );
+
+  add_cmd ("display", class_vars, enable_display,
+          "Enable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to resume displaying.\n\
+No argument means enable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &enablelist);
+
+  add_cmd ("display", class_vars, disable_display_command,
+          "Disable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means disable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &disablelist);
+
+  add_cmd ("display", class_vars, undisplay_command,
+          "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &deletelist);
+
+  add_com ("printf", class_vars, printf_command,
+          "printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\
+This is useful for formatted output in user-defined commands.");
+
+  add_com ("output", class_vars, output_command,
+          "Like \"print\" but don't put in value history and don't print newline.\n\
+This is useful in user-defined commands.");
+
+  add_prefix_cmd ("set", class_vars, set_command,
+                 concat ("Evaluate expression EXP and assign result to variable VAR, using assignment\n\
+syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\
+example).  VAR may be a debugger \"convenience\" variable (names starting\n\
+with $), a register (a few standard names starting with $), or an actual\n\
+variable in the program being debugged.  EXP is any valid expression.\n",
+                         "Use \"set variable\" for variables with names identical to set subcommands.\n\
+\nWith a subcommand, this command modifies parts of the gdb environment.\n\
+You can see these environment settings with the \"show\" command.", NULL),
+                 &setlist, "set ", 1, &cmdlist);
+  if (dbx_commands)
+    add_com ("assign", class_vars, set_command, concat ("Evaluate expression \
+EXP and assign result to variable VAR, using assignment\n\
+syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\
+example).  VAR may be a debugger \"convenience\" variable (names starting\n\
+with $), a register (a few standard names starting with $), or an actual\n\
+variable in the program being debugged.  EXP is any valid expression.\n",
+                                                       "Use \"set variable\" for variables with names identical to set subcommands.\n\
+\nWith a subcommand, this command modifies parts of the gdb environment.\n\
+You can see these environment settings with the \"show\" command.", NULL));
+
+  /* "call" is the same as "set", but handy for dbx users to call fns. */
+  c = add_com ("call", class_vars, call_command,
+              "Call a function in the program.\n\
+The argument is the function name and arguments, in the notation of the\n\
+current working language.  The result is printed and saved in the value\n\
+history, if it is not void.");
+  set_cmd_completer (c, location_completer);
+
+  add_cmd ("variable", class_vars, set_command,
+          "Evaluate expression EXP and assign result to variable VAR, using assignment\n\
+syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\
+example).  VAR may be a debugger \"convenience\" variable (names starting\n\
+with $), a register (a few standard names starting with $), or an actual\n\
+variable in the program being debugged.  EXP is any valid expression.\n\
+This may usually be abbreviated to simply \"set\".",
+          &setlist);
+
+  c = add_com ("print", class_vars, print_command,
+          concat ("Print value of expression EXP.\n\
+Variables accessible are those of the lexical environment of the selected\n\
+stack frame, plus all those whose scope is global or an entire file.\n\
+\n\
+$NUM gets previous value number NUM.  $ and $$ are the last two values.\n\
+$$NUM refers to NUM'th value back from the last one.\n\
+Names starting with $ refer to registers (with the values they would have\n",
+                  "if the program were to return to the stack frame now selected, restoring\n\
+all registers saved by frames farther in) or else to debugger\n\
+\"convenience\" variables (any such name not a known register).\n\
+Use assignment expressions to give values to convenience variables.\n",
+                  "\n\
+{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\
+@ is a binary operator for treating consecutive data objects\n\
+anywhere in memory as an array.  FOO@NUM gives an array whose first\n\
+element is FOO, whose second element is stored in the space following\n\
+where FOO is stored, etc.  FOO must be an expression whose value\n\
+resides in memory.\n",
+                  "\n\
+EXP may be preceded with /FMT, where FMT is a format letter\n\
+but no count or size letter (see \"x\" command).", NULL));
+  set_cmd_completer (c, location_completer);
+  add_com_alias ("p", "print", class_vars, 1);
+
+  c = add_com ("inspect", class_vars, inspect_command,
+          "Same as \"print\" command, except that if you are running in the epoch\n\
+environment, the value is printed in its own window.");
+  set_cmd_completer (c, location_completer);
+
+  add_show_from_set (
+                add_set_cmd ("max-symbolic-offset", no_class, var_uinteger,
+                             (char *) &max_symbolic_offset,
+       "Set the largest offset that will be printed in <symbol+1234> form.",
+                             &setprintlist),
+                     &showprintlist);
+  add_show_from_set (
+                     add_set_cmd ("symbol-filename", no_class, var_boolean,
+                                  (char *) &print_symbol_filename,
+          "Set printing of source filename and line number with <symbol>.",
+                                  &setprintlist),
+                     &showprintlist);
+
+  /* For examine/instruction a single byte quantity is specified as
+     the data.  This avoids problems with value_at_lazy() requiring a
+     valid data type (and rejecting VOID). */
+  examine_i_type = init_type (TYPE_CODE_INT, 1, 0, "examine_i_type", NULL);
+
+  examine_b_type = init_type (TYPE_CODE_INT, 1, 0, "examine_b_type", NULL);
+  examine_h_type = init_type (TYPE_CODE_INT, 2, 0, "examine_h_type", NULL);
+  examine_w_type = init_type (TYPE_CODE_INT, 4, 0, "examine_w_type", NULL);
+  examine_g_type = init_type (TYPE_CODE_INT, 8, 0, "examine_g_type", NULL);
+
+}
diff --git a/gdb/stack.c b/gdb/stack.c
new file mode 100644 (file)
index 0000000..4f41531
--- /dev/null
@@ -0,0 +1,2023 @@
+/* Print and select stack frames for GDB, the GNU debugger.
+
+   Copyright 1986, 1987, 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.
+
+   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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <ctype.h>
+#include "defs.h"
+#include "gdb_string.h"
+#include "value.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "language.h"
+#include "frame.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "source.h"
+#include "breakpoint.h"
+#include "demangle.h"
+#include "inferior.h"
+#include "annotate.h"
+#include "ui-out.h"
+
+/* Prototypes for exported functions. */
+
+void args_info (char *, int);
+
+void locals_info (char *, int);
+
+void (*selected_frame_level_changed_hook) (int);
+
+void _initialize_stack (void);
+
+/* Prototypes for local functions. */
+
+static void return_command (char *, int);
+
+static void down_command (char *, int);
+
+static void down_silently_base (char *);
+
+static void down_silently_command (char *, int);
+
+static void up_command (char *, int);
+
+static void up_silently_base (char *);
+
+static void up_silently_command (char *, int);
+
+void frame_command (char *, int);
+
+static void current_frame_command (char *, int);
+
+static void select_frame_command (char *, int);
+
+static void print_frame_arg_vars (struct frame_info *, struct ui_file *);
+
+static void catch_info (char *, int);
+
+static void args_plus_locals_info (char *, int);
+
+static void print_frame_label_vars (struct frame_info *, int,
+                                   struct ui_file *);
+
+static void print_frame_local_vars (struct frame_info *, int,
+                                   struct ui_file *);
+
+static int print_block_frame_labels (struct block *, int *,
+                                    struct ui_file *);
+
+static int print_block_frame_locals (struct block *,
+                                    struct frame_info *,
+                                    int,
+                                    struct ui_file *);
+
+static void print_frame (struct frame_info *fi, 
+                        int level, 
+                        int source, 
+                        int args, 
+                        struct symtab_and_line sal);
+
+static void print_frame_info_base (struct frame_info *, int, int, int);
+
+static void print_stack_frame_base (struct frame_info *, int, int);
+
+static void backtrace_command (char *, int);
+
+struct frame_info *parse_frame_specification (char *);
+
+static void frame_info (char *, int);
+
+extern int addressprint;       /* Print addresses, or stay symbolic only? */
+
+/* The "selected" stack frame is used by default for local and arg access.
+   May be zero, for no selected frame.  */
+
+struct frame_info *selected_frame;
+
+/* Level of the selected frame:
+   0 for innermost, 1 for its caller, ...
+   or -1 for frame specified by address with no defined level.  */
+
+/* Level of the selected frame: 0 for innermost, 1 for its caller, ...
+   or -1 for NULL frame.  */
+
+int
+frame_relative_level (struct frame_info *fi)
+{
+  if (fi == NULL)
+    return -1;
+  else
+    return fi->level;
+}
+
+/* Zero means do things normally; we are interacting directly with the
+   user.  One means print the full filename and linenumber when a
+   frame is printed, and do so in a format emacs18/emacs19.22 can
+   parse.  Two means print similar annotations, but in many more
+   cases and in a slightly different syntax.  */
+
+int annotation_level = 0;
+\f
+
+struct print_stack_frame_args
+  {
+    struct frame_info *fi;
+    int level;
+    int source;
+    int args;
+  };
+
+static int print_stack_frame_base_stub (char *);
+
+/* Show and print the frame arguments.
+   Pass the args the way catch_errors wants them.  */
+static int show_and_print_stack_frame_stub (void *args);
+static int
+show_and_print_stack_frame_stub (void *args)
+{
+  struct print_stack_frame_args *p = (struct print_stack_frame_args *) args;
+
+  print_frame_info (p->fi, p->level, p->source, p->args);
+
+  return 0;
+}
+
+/* Show or print the frame arguments.
+   Pass the args the way catch_errors wants them.  */
+static int print_stack_frame_stub (void *args);
+static int
+print_stack_frame_stub (void *args)
+{
+  struct print_stack_frame_args *p = (struct print_stack_frame_args *) args;
+
+  print_frame_info_base (p->fi, p->level, p->source, p->args);
+  return 0;
+}
+
+/* Print a stack frame briefly.  FRAME_INFI should be the frame info
+   and LEVEL should be its level in the stack (or -1 for level not
+   defined). */
+
+/* Pass the args the way catch_errors wants them.  */
+static int
+print_stack_frame_base_stub (char *args)
+{
+  struct print_stack_frame_args *p = (struct print_stack_frame_args *) args;
+
+  print_frame_info_base (p->fi, p->level, p->source, p->args);
+  return 0;
+}
+
+/* print the frame arguments to the terminal.  
+   Pass the args the way catch_errors wants them.  */
+static int print_only_stack_frame_stub (void *);
+static int
+print_only_stack_frame_stub (void *args)
+{
+  struct print_stack_frame_args *p = (struct print_stack_frame_args *) args;
+
+  print_frame_info_base (p->fi, p->level, p->source, p->args);
+  return 0;
+}
+
+/* Print a stack frame briefly.  FRAME_INFI should be the frame info
+   and LEVEL should be its level in the stack (or -1 for level not defined).
+   This prints the level, the function executing, the arguments,
+   and the file name and line number.
+   If the pc is not at the beginning of the source line,
+   the actual pc is printed at the beginning.
+
+   If SOURCE is 1, print the source line as well.
+   If SOURCE is -1, print ONLY the source line.  */
+
+static void
+print_stack_frame_base (struct frame_info *fi, int level, int source)
+{
+  struct print_stack_frame_args args;
+
+  args.fi = fi;
+  args.level = level;
+  args.source = source;
+  args.args = 1;
+
+  catch_errors (print_stack_frame_stub, &args, "", RETURN_MASK_ALL);
+}
+
+/* Show and print a stack frame briefly.  FRAME_INFI should be the frame info
+   and LEVEL should be its level in the stack (or -1 for level not defined).
+   This prints the level, the function executing, the arguments,
+   and the file name and line number.
+   If the pc is not at the beginning of the source line,
+   the actual pc is printed at the beginning.
+
+   If SOURCE is 1, print the source line as well.
+   If SOURCE is -1, print ONLY the source line.  */
+
+void
+show_and_print_stack_frame (struct frame_info *fi, int level, int source)
+{
+  struct print_stack_frame_args args;
+
+  args.fi = fi;
+  args.level = level;
+  args.source = source;
+  args.args = 1;
+
+  catch_errors (show_and_print_stack_frame_stub, &args, "", RETURN_MASK_ALL);
+}
+
+
+/* Show or print a stack frame briefly.  FRAME_INFI should be the frame info
+   and LEVEL should be its level in the stack (or -1 for level not defined).
+   This prints the level, the function executing, the arguments,
+   and the file name and line number.
+   If the pc is not at the beginning of the source line,
+   the actual pc is printed at the beginning.
+
+   If SOURCE is 1, print the source line as well.
+   If SOURCE is -1, print ONLY the source line.  */
+
+void
+print_stack_frame (struct frame_info *fi, int level, int source)
+{
+  struct print_stack_frame_args args;
+
+  args.fi = fi;
+  args.level = level;
+  args.source = source;
+  args.args = 1;
+
+  catch_errors (print_stack_frame_stub, (char *) &args, "", RETURN_MASK_ALL);
+}
+
+/* Print a stack frame briefly.  FRAME_INFI should be the frame info
+   and LEVEL should be its level in the stack (or -1 for level not defined).
+   This prints the level, the function executing, the arguments,
+   and the file name and line number.
+   If the pc is not at the beginning of the source line,
+   the actual pc is printed at the beginning.
+
+   If SOURCE is 1, print the source line as well.
+   If SOURCE is -1, print ONLY the source line.  */
+
+void
+print_only_stack_frame (struct frame_info *fi, int level, int source)
+{
+  struct print_stack_frame_args args;
+
+  args.fi = fi;
+  args.level = level;
+  args.source = source;
+  args.args = 1;
+
+  catch_errors (print_only_stack_frame_stub, &args, "", RETURN_MASK_ALL);
+}
+
+struct print_args_args
+{
+  struct symbol *func;
+  struct frame_info *fi;
+  struct ui_file *stream;
+};
+
+static int print_args_stub (PTR);
+
+/* Pass the args the way catch_errors wants them.  */
+
+static int
+print_args_stub (PTR args)
+{
+  int numargs;
+  struct print_args_args *p = (struct print_args_args *) args;
+
+  numargs = FRAME_NUM_ARGS (p->fi);
+  print_frame_args (p->func, p->fi, numargs, p->stream);
+  return 0;
+}
+
+/* Print information about a frame for frame "fi" at level "level".
+   Used in "where" output, also used to emit breakpoint or step
+   messages.  
+   LEVEL is the level of the frame, or -1 if it is the
+   innermost frame but we don't want to print the level.  
+   The meaning of the SOURCE argument is: 
+   SRC_LINE: Print only source line
+   LOCATION: Print only location 
+   LOC_AND_SRC: Print location and source line.  */
+
+static void
+print_frame_info_base (struct frame_info *fi, int level, int source, int args)
+{
+  struct symtab_and_line sal;
+  int source_print;
+  int location_print;
+
+#if 0
+  char buf[MAX_REGISTER_RAW_SIZE];
+  CORE_ADDR sp;
+
+  /* On the 68k, this spends too much time in m68k_find_saved_regs.  */
+
+  /* Get the value of SP_REGNUM relative to the frame.  */
+  get_saved_register (buf, (int *) NULL, (CORE_ADDR *) NULL,
+                   FRAME_INFO_ID (fi), SP_REGNUM, (enum lval_type *) NULL);
+  sp = extract_address (buf, REGISTER_RAW_SIZE (SP_REGNUM));
+
+  /* This is not a perfect test, because if a function alloca's some
+     memory, puts some code there, and then jumps into it, then the test
+     will succeed even though there is no call dummy.  Probably best is
+     to check for a bp_call_dummy breakpoint.  */
+  if (PC_IN_CALL_DUMMY (fi->pc, sp, fi->frame))
+#else
+  if (frame_in_dummy (fi))
+#endif
+    {
+      annotate_frame_begin (level == -1 ? 0 : level, fi->pc);
+
+      /* Do this regardless of SOURCE because we don't have any source
+         to list for this frame.  */
+      if (level >= 0)
+       printf_filtered ("#%-2d ", level);
+      annotate_function_call ();
+      printf_filtered ("<function called from gdb>\n");
+      annotate_frame_end ();
+      return;
+    }
+  if (fi->signal_handler_caller)
+    {
+      annotate_frame_begin (level == -1 ? 0 : level, fi->pc);
+
+      /* Do this regardless of SOURCE because we don't have any source
+         to list for this frame.  */
+      if (level >= 0)
+       printf_filtered ("#%-2d ", level);
+      annotate_signal_handler_caller ();
+      printf_filtered ("<signal handler called>\n");
+      annotate_frame_end ();
+      return;
+    }
+
+  /* If fi is not the innermost frame, that normally means that fi->pc
+     points to *after* the call instruction, and we want to get the line
+     containing the call, never the next line.  But if the next frame is
+     a signal_handler_caller or a dummy frame, then the next frame was
+     not entered as the result of a call, and we want to get the line
+     containing fi->pc.  */
+  sal =
+    find_pc_line (fi->pc,
+                 fi->next != NULL
+                 && !fi->next->signal_handler_caller
+                 && !frame_in_dummy (fi->next));
+
+  location_print = (source == LOCATION 
+                   || source == LOC_AND_ADDRESS
+                   || source == SRC_AND_LOC);
+
+  if (location_print || !sal.symtab)
+    print_frame (fi, level, source, args, sal);
+
+  source_print = (source == SRC_LINE || source == SRC_AND_LOC);
+
+  if (sal.symtab)
+    set_current_source_symtab_and_line (&sal);
+
+  if (source_print && sal.symtab)
+    {
+      struct symtab_and_line cursal;
+      int done = 0;
+      int mid_statement = (source == SRC_LINE) && (fi->pc != sal.pc);
+
+      if (annotation_level)
+       done = identify_source_line (sal.symtab, sal.line, mid_statement,
+                                    fi->pc);
+      if (!done)
+       {
+         if (print_frame_info_listing_hook)
+           print_frame_info_listing_hook (sal.symtab, sal.line, sal.line + 1, 0);
+         else
+           {
+             /* We used to do this earlier, but that is clearly
+                wrong. This function is used by many different
+                parts of gdb, including normal_stop in infrun.c,
+                which uses this to print out the current PC
+                when we stepi/nexti into the middle of a source
+                line. Only the command line really wants this
+                behavior. Other UIs probably would like the
+                ability to decide for themselves if it is desired. */
+             if (addressprint && mid_statement)
+               {
+                 ui_out_field_core_addr (uiout, "addr", fi->pc);
+                 ui_out_text (uiout, "\t");
+               }
+
+             print_source_lines (sal.symtab, sal.line, sal.line + 1, 0);
+           }
+       }
+      cursal = get_current_or_default_source_symtab_and_line ();
+      cursal.line = max (sal.line - get_lines_to_list () / 2, 1);
+      set_current_source_symtab_and_line (&cursal);
+    }
+
+  if (source != 0)
+    set_default_breakpoint (1, fi->pc, sal.symtab, sal.line);
+
+  annotate_frame_end ();
+
+  gdb_flush (gdb_stdout);
+}
+
+static void
+print_frame (struct frame_info *fi, 
+            int level, 
+            int source, 
+            int args, 
+            struct symtab_and_line sal)
+{
+  struct symbol *func;
+  register char *funname = 0;
+  enum language funlang = language_unknown;
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+  struct cleanup *list_chain;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  func = find_pc_function (frame_address_in_block (fi));
+  if (func)
+    {
+      /* In certain pathological cases, the symtabs give the wrong
+         function (when we are in the first function in a file which
+         is compiled without debugging symbols, the previous function
+         is compiled with debugging symbols, and the "foo.o" symbol
+         that is supposed to tell us where the file with debugging symbols
+         ends has been truncated by ar because it is longer than 15
+         characters).  This also occurs if the user uses asm() to create
+         a function but not stabs for it (in a file compiled -g).
+
+         So look in the minimal symbol tables as well, and if it comes
+         up with a larger address for the function use that instead.
+         I don't think this can ever cause any problems; there shouldn't
+         be any minimal symbols in the middle of a function; if this is
+         ever changed many parts of GDB will need to be changed (and we'll
+         create a find_pc_minimal_function or some such).  */
+
+      struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (frame_address_in_block (fi));
+      if (msymbol != NULL
+         && (SYMBOL_VALUE_ADDRESS (msymbol)
+             > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
+       {
+#if 0
+         /* There is no particular reason to think the line number
+            information is wrong.  Someone might have just put in
+            a label with asm() but left the line numbers alone.  */
+         /* In this case we have no way of knowing the source file
+            and line number, so don't print them.  */
+         sal.symtab = 0;
+#endif
+         /* We also don't know anything about the function besides
+            its address and name.  */
+         func = 0;
+         funname = SYMBOL_NAME (msymbol);
+         funlang = SYMBOL_LANGUAGE (msymbol);
+       }
+      else
+       {
+         /* I'd like to use SYMBOL_SOURCE_NAME() here, to display the
+            demangled name that we already have stored in the symbol
+            table, but we stored a version with DMGL_PARAMS turned
+            on, and here we don't want to display parameters. So call
+            the demangler again, with DMGL_ANSI only. (Yes, I know
+            that printf_symbol_filtered() will again try to demangle
+            the name on the fly, but the issue is that if
+            cplus_demangle() fails here, it'll fail there too. So we
+            want to catch the failure ("demangled==NULL" case below)
+            here, while we still have our hands on the function
+            symbol.) */
+         char *demangled;
+         funname = SYMBOL_NAME (func);
+         funlang = SYMBOL_LANGUAGE (func);
+         if (funlang == language_cplus)
+           {
+             demangled = cplus_demangle (funname, DMGL_ANSI);
+             if (demangled == NULL)
+               /* If the demangler fails, try the demangled name from
+                  the symbol table. This'll have parameters, but
+                  that's preferable to diplaying a mangled name. */
+               funname = SYMBOL_SOURCE_NAME (func);
+           }
+       }
+    }
+  else
+    {
+      struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (frame_address_in_block (fi));
+      if (msymbol != NULL)
+       {
+         funname = SYMBOL_NAME (msymbol);
+         funlang = SYMBOL_LANGUAGE (msymbol);
+       }
+    }
+
+  annotate_frame_begin (level == -1 ? 0 : level, fi->pc);
+
+  list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
+
+  if (level >= 0)
+    {
+      ui_out_text (uiout, "#");
+      ui_out_field_fmt (uiout, "level", "%-2d", level);
+      ui_out_spaces (uiout, 1);
+    }
+  if (addressprint)
+    if (fi->pc != sal.pc || !sal.symtab || source == LOC_AND_ADDRESS)
+      {
+       annotate_frame_address ();
+       ui_out_field_core_addr (uiout, "addr", fi->pc);
+       annotate_frame_address_end ();
+       ui_out_text (uiout, " in ");
+      }
+  annotate_frame_function_name ();
+  fprintf_symbol_filtered (stb->stream, funname ? funname : "??", funlang,
+                          DMGL_ANSI);
+  ui_out_field_stream (uiout, "func", stb);
+  ui_out_wrap_hint (uiout, "   ");
+  annotate_frame_args ();
+      
+  ui_out_text (uiout, " (");
+  if (args)
+    {
+      struct print_args_args args;
+      struct cleanup *args_list_chain;
+      args.fi = fi;
+      args.func = func;
+      args.stream = gdb_stdout;
+      args_list_chain = make_cleanup_ui_out_list_begin_end (uiout, "args");
+      catch_errors (print_args_stub, &args, "", RETURN_MASK_ALL);
+      /* FIXME: args must be a list. If one argument is a string it will
+                have " that will not be properly escaped.  */
+      /* Invoke ui_out_tuple_end.  */
+      do_cleanups (args_list_chain);
+      QUIT;
+    }
+  ui_out_text (uiout, ")");
+  if (sal.symtab && sal.symtab->filename)
+    {
+      annotate_frame_source_begin ();
+      ui_out_wrap_hint (uiout, "   ");
+      ui_out_text (uiout, " at ");
+      annotate_frame_source_file ();
+      ui_out_field_string (uiout, "file", sal.symtab->filename);
+      annotate_frame_source_file_end ();
+      ui_out_text (uiout, ":");
+      annotate_frame_source_line ();
+      ui_out_field_int (uiout, "line", sal.line);
+      annotate_frame_source_end ();
+    }
+
+#ifdef PC_SOLIB
+  if (!funname || (!sal.symtab || !sal.symtab->filename))
+    {
+      char *lib = PC_SOLIB (fi->pc);
+      if (lib)
+       {
+         annotate_frame_where ();
+         ui_out_wrap_hint (uiout, "  ");
+         ui_out_text (uiout, " from ");
+         ui_out_field_string (uiout, "from", lib);
+       }
+    }
+#endif /* PC_SOLIB */
+
+  /* do_cleanups will call ui_out_tuple_end() for us.  */
+  do_cleanups (list_chain);
+  ui_out_text (uiout, "\n");
+  do_cleanups (old_chain);
+}
+\f
+
+/* Show or print the frame info.  If this is the tui, it will be shown in 
+   the source display */
+void
+print_frame_info (struct frame_info *fi, register int level, int source,
+                 int args)
+{
+  print_frame_info_base (fi, level, source, args);
+}
+
+/* Show the frame info.  If this is the tui, it will be shown in 
+   the source display otherwise, nothing is done */
+void
+show_stack_frame (struct frame_info *fi)
+{
+}
+\f
+
+/* Read a frame specification in whatever the appropriate format is.
+   Call error() if the specification is in any way invalid (i.e.
+   this function never returns NULL).  */
+
+struct frame_info *
+parse_frame_specification (char *frame_exp)
+{
+  int numargs = 0;
+#define        MAXARGS 4
+  CORE_ADDR args[MAXARGS];
+  int level;
+
+  if (frame_exp)
+    {
+      char *addr_string, *p;
+      struct cleanup *tmp_cleanup;
+
+      while (*frame_exp == ' ')
+       frame_exp++;
+
+      while (*frame_exp)
+       {
+         if (numargs > MAXARGS)
+           error ("Too many args in frame specification");
+         /* Parse an argument.  */
+         for (p = frame_exp; *p && *p != ' '; p++)
+           ;
+         addr_string = savestring (frame_exp, p - frame_exp);
+
+         {
+           struct value *vp;
+
+           tmp_cleanup = make_cleanup (xfree, addr_string);
+
+           /* NOTE: we call parse_and_eval and then both
+              value_as_long and value_as_address rather than calling
+              parse_and_eval_long and parse_and_eval_address because
+              of the issue of potential side effects from evaluating
+              the expression.  */
+           vp = parse_and_eval (addr_string);
+           if (numargs == 0)
+             level = value_as_long (vp);
+
+           args[numargs++] = value_as_address (vp);
+           do_cleanups (tmp_cleanup);
+         }
+
+         /* Skip spaces, move to possible next arg.  */
+         while (*p == ' ')
+           p++;
+         frame_exp = p;
+       }
+    }
+
+  switch (numargs)
+    {
+    case 0:
+      if (selected_frame == NULL)
+       error ("No selected frame.");
+      return selected_frame;
+      /* NOTREACHED */
+    case 1:
+      {
+       struct frame_info *fid =
+       find_relative_frame (get_current_frame (), &level);
+       struct frame_info *tfid;
+
+       if (level == 0)
+         /* find_relative_frame was successful */
+         return fid;
+
+       /* If SETUP_ARBITRARY_FRAME is defined, then frame specifications
+          take at least 2 addresses.  It is important to detect this case
+          here so that "frame 100" does not give a confusing error message
+          like "frame specification requires two addresses".  This of course
+          does not solve the "frame 100" problem for machines on which
+          a frame specification can be made with one address.  To solve
+          that, we need a new syntax for a specifying a frame by address.
+          I think the cleanest syntax is $frame(0x45) ($frame(0x23,0x45) for
+          two args, etc.), but people might think that is too much typing,
+          so I guess *0x23,0x45 would be a possible alternative (commas
+          really should be used instead of spaces to delimit; using spaces
+          normally works in an expression).  */
+#ifdef SETUP_ARBITRARY_FRAME
+       error ("No frame %s", paddr_d (args[0]));
+#endif
+
+       /* If (s)he specifies the frame with an address, he deserves what
+          (s)he gets.  Still, give the highest one that matches.  */
+
+       for (fid = get_current_frame ();
+            fid && fid->frame != args[0];
+            fid = get_prev_frame (fid))
+         ;
+
+       if (fid)
+         while ((tfid = get_prev_frame (fid)) &&
+                (tfid->frame == args[0]))
+           fid = tfid;
+
+       /* We couldn't identify the frame as an existing frame, but
+          perhaps we can create one with a single argument.  */
+      }
+
+    default:
+#ifdef SETUP_ARBITRARY_FRAME
+      return SETUP_ARBITRARY_FRAME (numargs, args);
+#else
+      /* Usual case.  Do it here rather than have everyone supply
+         a SETUP_ARBITRARY_FRAME that does this.  */
+      if (numargs == 1)
+       return create_new_frame (args[0], 0);
+      error ("Too many args in frame specification");
+#endif
+      /* NOTREACHED */
+    }
+  /* NOTREACHED */
+}
+
+/* FRAME_ARGS_ADDRESS_CORRECT is just like FRAME_ARGS_ADDRESS except
+   that if it is unsure about the answer, it returns 0
+   instead of guessing (this happens on the VAX and i960, for example).
+
+   On most machines, we never have to guess about the args address,
+   so FRAME_ARGS_ADDRESS{,_CORRECT} are the same.  */
+#if !defined (FRAME_ARGS_ADDRESS_CORRECT)
+#define FRAME_ARGS_ADDRESS_CORRECT FRAME_ARGS_ADDRESS
+#endif
+
+/* Print verbosely the selected frame or the frame at address ADDR.
+   This means absolutely all information in the frame is printed.  */
+
+static void
+frame_info (char *addr_exp, int from_tty)
+{
+  struct frame_info *fi;
+  struct symtab_and_line sal;
+  struct symbol *func;
+  struct symtab *s;
+  struct frame_info *calling_frame_info;
+  int i, count, numregs;
+  char *funname = 0;
+  enum language funlang = language_unknown;
+
+  if (!target_has_stack)
+    error ("No stack.");
+
+  fi = parse_frame_specification (addr_exp);
+  if (fi == NULL)
+    error ("Invalid frame specified.");
+
+  sal = find_pc_line (fi->pc,
+                     fi->next != NULL
+                     && !fi->next->signal_handler_caller
+                     && !frame_in_dummy (fi->next));
+  func = get_frame_function (fi);
+  s = find_pc_symtab (fi->pc);
+  if (func)
+    {
+      /* I'd like to use SYMBOL_SOURCE_NAME() here, to display
+       * the demangled name that we already have stored in
+       * the symbol table, but we stored a version with
+       * DMGL_PARAMS turned on, and here we don't want
+       * to display parameters. So call the demangler again,
+       * with DMGL_ANSI only. RT
+       * (Yes, I know that printf_symbol_filtered() will
+       * again try to demangle the name on the fly, but
+       * the issue is that if cplus_demangle() fails here,
+       * it'll fail there too. So we want to catch the failure
+       * ("demangled==NULL" case below) here, while we still
+       * have our hands on the function symbol.)
+       */
+      char *demangled;
+      funname = SYMBOL_NAME (func);
+      funlang = SYMBOL_LANGUAGE (func);
+      if (funlang == language_cplus)
+       {
+         demangled = cplus_demangle (funname, DMGL_ANSI);
+         /* If the demangler fails, try the demangled name
+          * from the symbol table. This'll have parameters,
+          * but that's preferable to diplaying a mangled name.
+          */
+         if (demangled == NULL)
+           funname = SYMBOL_SOURCE_NAME (func);
+       }
+    }
+  else
+    {
+      register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc);
+      if (msymbol != NULL)
+       {
+         funname = SYMBOL_NAME (msymbol);
+         funlang = SYMBOL_LANGUAGE (msymbol);
+       }
+    }
+  calling_frame_info = get_prev_frame (fi);
+
+  if (!addr_exp && frame_relative_level (selected_frame) >= 0)
+    {
+      printf_filtered ("Stack level %d, frame at ",
+                      frame_relative_level (selected_frame));
+      print_address_numeric (fi->frame, 1, gdb_stdout);
+      printf_filtered (":\n");
+    }
+  else
+    {
+      printf_filtered ("Stack frame at ");
+      print_address_numeric (fi->frame, 1, gdb_stdout);
+      printf_filtered (":\n");
+    }
+  printf_filtered (" %s = ", REGISTER_NAME (PC_REGNUM));
+  print_address_numeric (fi->pc, 1, gdb_stdout);
+
+  wrap_here ("   ");
+  if (funname)
+    {
+      printf_filtered (" in ");
+      fprintf_symbol_filtered (gdb_stdout, funname, funlang,
+                              DMGL_ANSI | DMGL_PARAMS);
+    }
+  wrap_here ("   ");
+  if (sal.symtab)
+    printf_filtered (" (%s:%d)", sal.symtab->filename, sal.line);
+  puts_filtered ("; ");
+  wrap_here ("    ");
+  printf_filtered ("saved %s ", REGISTER_NAME (PC_REGNUM));
+  print_address_numeric (FRAME_SAVED_PC (fi), 1, gdb_stdout);
+  printf_filtered ("\n");
+
+  {
+    int frameless;
+    frameless = FRAMELESS_FUNCTION_INVOCATION (fi);
+    if (frameless)
+      printf_filtered (" (FRAMELESS),");
+  }
+
+  if (calling_frame_info)
+    {
+      printf_filtered (" called by frame at ");
+      print_address_numeric (calling_frame_info->frame, 1, gdb_stdout);
+    }
+  if (fi->next && calling_frame_info)
+    puts_filtered (",");
+  wrap_here ("   ");
+  if (fi->next)
+    {
+      printf_filtered (" caller of frame at ");
+      print_address_numeric (fi->next->frame, 1, gdb_stdout);
+    }
+  if (fi->next || calling_frame_info)
+    puts_filtered ("\n");
+  if (s)
+    printf_filtered (" source language %s.\n", language_str (s->language));
+
+#ifdef PRINT_EXTRA_FRAME_INFO
+  PRINT_EXTRA_FRAME_INFO (fi);
+#endif
+
+  {
+    /* Address of the argument list for this frame, or 0.  */
+    CORE_ADDR arg_list = FRAME_ARGS_ADDRESS_CORRECT (fi);
+    /* Number of args for this frame, or -1 if unknown.  */
+    int numargs;
+
+    if (arg_list == 0)
+      printf_filtered (" Arglist at unknown address.\n");
+    else
+      {
+       printf_filtered (" Arglist at ");
+       print_address_numeric (arg_list, 1, gdb_stdout);
+       printf_filtered (",");
+
+       numargs = FRAME_NUM_ARGS (fi);
+       if (numargs < 0)
+         puts_filtered (" args: ");
+       else if (numargs == 0)
+         puts_filtered (" no args.");
+       else if (numargs == 1)
+         puts_filtered (" 1 arg: ");
+       else
+         printf_filtered (" %d args: ", numargs);
+       print_frame_args (func, fi, numargs, gdb_stdout);
+       puts_filtered ("\n");
+      }
+  }
+  {
+    /* Address of the local variables for this frame, or 0.  */
+    CORE_ADDR arg_list = FRAME_LOCALS_ADDRESS (fi);
+
+    if (arg_list == 0)
+      printf_filtered (" Locals at unknown address,");
+    else
+      {
+       printf_filtered (" Locals at ");
+       print_address_numeric (arg_list, 1, gdb_stdout);
+       printf_filtered (",");
+      }
+  }
+
+  if (fi->saved_regs == NULL)
+    FRAME_INIT_SAVED_REGS (fi);
+  /* Print as much information as possible on the location of all the
+     registers.  */
+  {
+    enum lval_type lval;
+    int optimized;
+    CORE_ADDR addr;
+    int realnum;
+    int count;
+    int i;
+    int need_nl = 1;
+
+    /* The sp is special; what's displayed isn't the save address, but
+       the value of the previous frame's sp.  This is a legacy thing,
+       at one stage the frame cached the previous frame's SP instead
+       of its address, hence it was easiest to just display the cached
+       value.  */
+    if (SP_REGNUM >= 0)
+      {
+       /* Find out the location of the saved stack pointer with out
+           actually evaluating it.  */
+       frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
+                              &realnum, NULL);
+       if (!optimized && lval == not_lval)
+         {
+           void *value = alloca (MAX_REGISTER_RAW_SIZE);
+           CORE_ADDR sp;
+           frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
+                                  &realnum, value);
+           sp = extract_address (value, REGISTER_RAW_SIZE (SP_REGNUM));
+           printf_filtered (" Previous frame's sp is ");
+           print_address_numeric (sp, 1, gdb_stdout);
+           printf_filtered ("\n");
+           need_nl = 0;
+         }
+       else if (!optimized && lval == lval_memory)
+         {
+           printf_filtered (" Previous frame's sp at ");
+           print_address_numeric (addr, 1, gdb_stdout);
+           printf_filtered ("\n");
+           need_nl = 0;
+         }
+       else if (!optimized && lval == lval_register)
+         {
+           printf_filtered (" Previous frame's sp in %s\n",
+                            REGISTER_NAME (realnum));
+           need_nl = 0;
+         }
+       /* else keep quiet.  */
+      }
+
+    count = 0;
+    numregs = NUM_REGS + NUM_PSEUDO_REGS;
+    for (i = 0; i < numregs; i++)
+      if (i != SP_REGNUM)
+       {
+         /* Find out the location of the saved register without
+             fetching the corresponding value.  */
+         frame_register_unwind (fi, i, &optimized, &lval, &addr, &realnum,
+                                NULL);
+         /* For moment, only display registers that were saved on the
+            stack.  */
+         if (!optimized && lval == lval_memory)
+           {
+             if (count == 0)
+               puts_filtered (" Saved registers:\n ");
+             else
+               puts_filtered (",");
+             wrap_here (" ");
+             printf_filtered (" %s at ", REGISTER_NAME (i));
+             print_address_numeric (addr, 1, gdb_stdout);
+             count++;
+           }
+       }
+    if (count || need_nl)
+      puts_filtered ("\n");
+  }
+}
+
+#if 0
+/* Set a limit on the number of frames printed by default in a
+   backtrace.  */
+
+static int backtrace_limit;
+
+static void
+set_backtrace_limit_command (char *count_exp, int from_tty)
+{
+  int count = parse_and_eval_long (count_exp);
+
+  if (count < 0)
+    error ("Negative argument not meaningful as backtrace limit.");
+
+  backtrace_limit = count;
+}
+
+static void
+backtrace_limit_info (char *arg, int from_tty)
+{
+  if (arg)
+    error ("\"Info backtrace-limit\" takes no arguments.");
+
+  printf_unfiltered ("Backtrace limit: %d.\n", backtrace_limit);
+}
+#endif
+
+/* Print briefly all stack frames or just the innermost COUNT frames.  */
+
+static void backtrace_command_1 (char *count_exp, int show_locals,
+                                int from_tty);
+static void
+backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
+{
+  struct frame_info *fi;
+  register int count;
+  register int i;
+  register struct frame_info *trailing;
+  register int trailing_level;
+
+  if (!target_has_stack)
+    error ("No stack.");
+
+  /* The following code must do two things.  First, it must
+     set the variable TRAILING to the frame from which we should start
+     printing.  Second, it must set the variable count to the number
+     of frames which we should print, or -1 if all of them.  */
+  trailing = get_current_frame ();
+
+  /* The target can be in a state where there is no valid frames
+     (e.g., just connected). */
+  if (trailing == NULL)
+    error ("No stack.");
+
+  trailing_level = 0;
+  if (count_exp)
+    {
+      count = parse_and_eval_long (count_exp);
+      if (count < 0)
+       {
+         struct frame_info *current;
+
+         count = -count;
+
+         current = trailing;
+         while (current && count--)
+           {
+             QUIT;
+             current = get_prev_frame (current);
+           }
+
+         /* Will stop when CURRENT reaches the top of the stack.  TRAILING
+            will be COUNT below it.  */
+         while (current)
+           {
+             QUIT;
+             trailing = get_prev_frame (trailing);
+             current = get_prev_frame (current);
+             trailing_level++;
+           }
+
+         count = -1;
+       }
+    }
+  else
+    count = -1;
+
+  if (info_verbose)
+    {
+      struct partial_symtab *ps;
+
+      /* Read in symbols for all of the frames.  Need to do this in
+         a separate pass so that "Reading in symbols for xxx" messages
+         don't screw up the appearance of the backtrace.  Also
+         if people have strong opinions against reading symbols for
+         backtrace this may have to be an option.  */
+      i = count;
+      for (fi = trailing;
+          fi != NULL && i--;
+          fi = get_prev_frame (fi))
+       {
+         QUIT;
+         ps = find_pc_psymtab (frame_address_in_block (fi));
+         if (ps)
+           PSYMTAB_TO_SYMTAB (ps);     /* Force syms to come in */
+       }
+    }
+
+  for (i = 0, fi = trailing;
+       fi && count--;
+       i++, fi = get_prev_frame (fi))
+    {
+      QUIT;
+
+      /* Don't use print_stack_frame; if an error() occurs it probably
+         means further attempts to backtrace would fail (on the other
+         hand, perhaps the code does or could be fixed to make sure
+         the frame->prev field gets set to NULL in that case).  */
+      print_frame_info_base (fi, trailing_level + i, 0, 1);
+      if (show_locals)
+       print_frame_local_vars (fi, 1, gdb_stdout);
+    }
+
+  /* If we've stopped before the end, mention that.  */
+  if (fi && from_tty)
+    printf_filtered ("(More stack frames follow...)\n");
+}
+
+static void
+backtrace_command (char *arg, int from_tty)
+{
+  struct cleanup *old_chain = (struct cleanup *) NULL;
+  char **argv = (char **) NULL;
+  int argIndicatingFullTrace = (-1), totArgLen = 0, argc = 0;
+  char *argPtr = arg;
+
+  if (arg != (char *) NULL)
+    {
+      int i;
+
+      argv = buildargv (arg);
+      old_chain = make_cleanup_freeargv (argv);
+      argc = 0;
+      for (i = 0; (argv[i] != (char *) NULL); i++)
+       {
+         unsigned int j;
+
+         for (j = 0; (j < strlen (argv[i])); j++)
+           argv[i][j] = tolower (argv[i][j]);
+
+         if (argIndicatingFullTrace < 0 && subset_compare (argv[i], "full"))
+           argIndicatingFullTrace = argc;
+         else
+           {
+             argc++;
+             totArgLen += strlen (argv[i]);
+           }
+       }
+      totArgLen += argc;
+      if (argIndicatingFullTrace >= 0)
+       {
+         if (totArgLen > 0)
+           {
+             argPtr = (char *) xmalloc (totArgLen + 1);
+             if (!argPtr)
+               nomem (0);
+             else
+               {
+                 memset (argPtr, 0, totArgLen + 1);
+                 for (i = 0; (i < (argc + 1)); i++)
+                   {
+                     if (i != argIndicatingFullTrace)
+                       {
+                         strcat (argPtr, argv[i]);
+                         strcat (argPtr, " ");
+                       }
+                   }
+               }
+           }
+         else
+           argPtr = (char *) NULL;
+       }
+    }
+
+  backtrace_command_1 (argPtr, (argIndicatingFullTrace >= 0), from_tty);
+
+  if (argIndicatingFullTrace >= 0 && totArgLen > 0)
+    xfree (argPtr);
+
+  if (old_chain)
+    do_cleanups (old_chain);
+}
+
+static void backtrace_full_command (char *arg, int from_tty);
+static void
+backtrace_full_command (char *arg, int from_tty)
+{
+  backtrace_command_1 (arg, 1, from_tty);
+}
+\f
+
+/* Print the local variables of a block B active in FRAME.
+   Return 1 if any variables were printed; 0 otherwise.  */
+
+static int
+print_block_frame_locals (struct block *b, register struct frame_info *fi,
+                         int num_tabs, register struct ui_file *stream)
+{
+  register int i, j;
+  register struct symbol *sym;
+  register int values_printed = 0;
+
+  ALL_BLOCK_SYMBOLS (b, i, sym)
+    {
+      switch (SYMBOL_CLASS (sym))
+       {
+       case LOC_LOCAL:
+       case LOC_REGISTER:
+       case LOC_STATIC:
+       case LOC_BASEREG:
+         values_printed = 1;
+         for (j = 0; j < num_tabs; j++)
+           fputs_filtered ("\t", stream);
+         fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+         fputs_filtered (" = ", stream);
+         print_variable_value (sym, fi, stream);
+         fprintf_filtered (stream, "\n");
+         break;
+
+       default:
+         /* Ignore symbols which are not locals.  */
+         break;
+       }
+    }
+  return values_printed;
+}
+
+/* Same, but print labels.  */
+
+static int
+print_block_frame_labels (struct block *b, int *have_default,
+                         register struct ui_file *stream)
+{
+  register int i;
+  register struct symbol *sym;
+  register int values_printed = 0;
+
+  ALL_BLOCK_SYMBOLS (b, i, sym)
+    {
+      if (STREQ (SYMBOL_NAME (sym), "default"))
+       {
+         if (*have_default)
+           continue;
+         *have_default = 1;
+       }
+      if (SYMBOL_CLASS (sym) == LOC_LABEL)
+       {
+         struct symtab_and_line sal;
+         sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0);
+         values_printed = 1;
+         fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+         if (addressprint)
+           {
+             fprintf_filtered (stream, " ");
+             print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, stream);
+           }
+         fprintf_filtered (stream, " in file %s, line %d\n",
+                           sal.symtab->filename, sal.line);
+       }
+    }
+  return values_printed;
+}
+
+/* Print on STREAM all the local variables in frame FRAME,
+   including all the blocks active in that frame
+   at its current pc.
+
+   Returns 1 if the job was done,
+   or 0 if nothing was printed because we have no info
+   on the function running in FRAME.  */
+
+static void
+print_frame_local_vars (register struct frame_info *fi, register int num_tabs,
+                       register struct ui_file *stream)
+{
+  register struct block *block = get_frame_block (fi, 0);
+  register int values_printed = 0;
+
+  if (block == 0)
+    {
+      fprintf_filtered (stream, "No symbol table info available.\n");
+      return;
+    }
+
+  while (block != 0)
+    {
+      if (print_block_frame_locals (block, fi, num_tabs, stream))
+       values_printed = 1;
+      /* After handling the function's top-level block, stop.
+         Don't continue to its superblock, the block of
+         per-file symbols.  */
+      if (BLOCK_FUNCTION (block))
+       break;
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  if (!values_printed)
+    {
+      fprintf_filtered (stream, "No locals.\n");
+    }
+}
+
+/* Same, but print labels.  */
+
+static void
+print_frame_label_vars (register struct frame_info *fi, int this_level_only,
+                       register struct ui_file *stream)
+{
+  register struct blockvector *bl;
+  register struct block *block = get_frame_block (fi, 0);
+  register int values_printed = 0;
+  int index, have_default = 0;
+  char *blocks_printed;
+  CORE_ADDR pc = fi->pc;
+
+  if (block == 0)
+    {
+      fprintf_filtered (stream, "No symbol table info available.\n");
+      return;
+    }
+
+  bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
+  blocks_printed = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+  memset (blocks_printed, 0, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+
+  while (block != 0)
+    {
+      CORE_ADDR end = BLOCK_END (block) - 4;
+      int last_index;
+
+      if (bl != blockvector_for_pc (end, &index))
+       error ("blockvector blotch");
+      if (BLOCKVECTOR_BLOCK (bl, index) != block)
+       error ("blockvector botch");
+      last_index = BLOCKVECTOR_NBLOCKS (bl);
+      index += 1;
+
+      /* Don't print out blocks that have gone by.  */
+      while (index < last_index
+            && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
+       index++;
+
+      while (index < last_index
+            && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
+       {
+         if (blocks_printed[index] == 0)
+           {
+             if (print_block_frame_labels (BLOCKVECTOR_BLOCK (bl, index), &have_default, stream))
+               values_printed = 1;
+             blocks_printed[index] = 1;
+           }
+         index++;
+       }
+      if (have_default)
+       return;
+      if (values_printed && this_level_only)
+       return;
+
+      /* After handling the function's top-level block, stop.
+         Don't continue to its superblock, the block of
+         per-file symbols.  */
+      if (BLOCK_FUNCTION (block))
+       break;
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  if (!values_printed && !this_level_only)
+    {
+      fprintf_filtered (stream, "No catches.\n");
+    }
+}
+
+/* ARGSUSED */
+void
+locals_info (char *args, int from_tty)
+{
+  if (!selected_frame)
+    error ("No frame selected.");
+  print_frame_local_vars (selected_frame, 0, gdb_stdout);
+}
+
+static void
+catch_info (char *ignore, int from_tty)
+{
+  struct symtab_and_line *sal;
+
+  /* Check for target support for exception handling */
+  sal = target_enable_exception_callback (EX_EVENT_CATCH, 1);
+  if (sal)
+    {
+      /* Currently not handling this */
+      /* Ideally, here we should interact with the C++ runtime
+         system to find the list of active handlers, etc. */
+      fprintf_filtered (gdb_stdout, "Info catch not supported with this target/compiler combination.\n");
+#if 0
+      if (!selected_frame)
+       error ("No frame selected.");
+#endif
+    }
+  else
+    {
+      /* Assume g++ compiled code -- old v 4.16 behaviour */
+      if (!selected_frame)
+       error ("No frame selected.");
+
+      print_frame_label_vars (selected_frame, 0, gdb_stdout);
+    }
+}
+
+static void
+print_frame_arg_vars (register struct frame_info *fi,
+                     register struct ui_file *stream)
+{
+  struct symbol *func = get_frame_function (fi);
+  register struct block *b;
+  register int i;
+  register struct symbol *sym, *sym2;
+  register int values_printed = 0;
+
+  if (func == 0)
+    {
+      fprintf_filtered (stream, "No symbol table info available.\n");
+      return;
+    }
+
+  b = SYMBOL_BLOCK_VALUE (func);
+  ALL_BLOCK_SYMBOLS (b, i, sym)
+    {
+      switch (SYMBOL_CLASS (sym))
+       {
+       case LOC_ARG:
+       case LOC_LOCAL_ARG:
+       case LOC_REF_ARG:
+       case LOC_REGPARM:
+       case LOC_REGPARM_ADDR:
+       case LOC_BASEREG_ARG:
+         values_printed = 1;
+         fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+         fputs_filtered (" = ", stream);
+
+         /* We have to look up the symbol because arguments can have
+            two entries (one a parameter, one a local) and the one we
+            want is the local, which lookup_symbol will find for us.
+            This includes gcc1 (not gcc2) on the sparc when passing a
+            small structure and gcc2 when the argument type is float
+            and it is passed as a double and converted to float by
+            the prologue (in the latter case the type of the LOC_ARG
+            symbol is double and the type of the LOC_LOCAL symbol is
+            float).  There are also LOC_ARG/LOC_REGISTER pairs which
+            are not combined in symbol-reading.  */
+
+         sym2 = lookup_symbol (SYMBOL_NAME (sym),
+                  b, VAR_NAMESPACE, (int *) NULL, (struct symtab **) NULL);
+         print_variable_value (sym2, fi, stream);
+         fprintf_filtered (stream, "\n");
+         break;
+
+       default:
+         /* Don't worry about things which aren't arguments.  */
+         break;
+       }
+    }
+  if (!values_printed)
+    {
+      fprintf_filtered (stream, "No arguments.\n");
+    }
+}
+
+void
+args_info (char *ignore, int from_tty)
+{
+  if (!selected_frame)
+    error ("No frame selected.");
+  print_frame_arg_vars (selected_frame, gdb_stdout);
+}
+
+
+static void
+args_plus_locals_info (char *ignore, int from_tty)
+{
+  args_info (ignore, from_tty);
+  locals_info (ignore, from_tty);
+}
+\f
+
+/* Select frame FI (or NULL - to invalidate the current frame).  */
+
+void
+select_frame (struct frame_info *fi)
+{
+  register struct symtab *s;
+
+  selected_frame = fi;
+  /* NOTE: cagney/2002-05-04: FI can be NULL.  This occures when the
+     frame is being invalidated.  */
+  if (selected_frame_level_changed_hook)
+    selected_frame_level_changed_hook (frame_relative_level (fi));
+
+  /* FIXME: kseitz/2002-08-28: It would be nice to call
+     selected_frame_level_changed_event right here, but due to limitations
+     in the current interfaces, we would end up flooding UIs with events
+     because select_frame is used extensively internally.
+
+     Once we have frame-parameterized frame (and frame-related) commands,
+     the event notification can be moved here, since this function will only
+     be called when the users selected frame is being changed. */
+
+  /* Ensure that symbols for this frame are read in.  Also, determine the
+     source language of this frame, and switch to it if desired.  */
+  if (fi)
+    {
+      s = find_pc_symtab (fi->pc);
+      if (s
+         && s->language != current_language->la_language
+         && s->language != language_unknown
+         && language_mode == language_mode_auto)
+       {
+         set_language (s->language);
+       }
+    }
+}
+\f
+
+/* Select frame FI.  Also print the stack frame and show the source if
+   this is the tui version.  */
+static void
+select_and_print_frame (struct frame_info *fi)
+{
+  select_frame (fi);
+  if (fi)
+    {
+      print_stack_frame (fi, frame_relative_level (fi), 1);
+    }
+}
+\f
+/* Return the symbol-block in which the selected frame is executing.
+   Can return zero under various legitimate circumstances.
+
+   If ADDR_IN_BLOCK is non-zero, set *ADDR_IN_BLOCK to the relevant
+   code address within the block returned.  We use this to decide
+   which macros are in scope.  */
+
+struct block *
+get_selected_block (CORE_ADDR *addr_in_block)
+{
+  if (!target_has_stack)
+    return 0;
+
+  if (!selected_frame)
+    return get_current_block (addr_in_block);
+  return get_frame_block (selected_frame, addr_in_block);
+}
+
+/* Find a frame a certain number of levels away from FRAME.
+   LEVEL_OFFSET_PTR points to an int containing the number of levels.
+   Positive means go to earlier frames (up); negative, the reverse.
+   The int that contains the number of levels is counted toward
+   zero as the frames for those levels are found.
+   If the top or bottom frame is reached, that frame is returned,
+   but the final value of *LEVEL_OFFSET_PTR is nonzero and indicates
+   how much farther the original request asked to go.  */
+
+struct frame_info *
+find_relative_frame (register struct frame_info *frame,
+                    register int *level_offset_ptr)
+{
+  register struct frame_info *prev;
+  register struct frame_info *frame1;
+
+  /* Going up is simple: just do get_prev_frame enough times
+     or until initial frame is reached.  */
+  while (*level_offset_ptr > 0)
+    {
+      prev = get_prev_frame (frame);
+      if (prev == 0)
+       break;
+      (*level_offset_ptr)--;
+      frame = prev;
+    }
+  /* Going down is just as simple.  */
+  if (*level_offset_ptr < 0)
+    {
+      while (*level_offset_ptr < 0)
+       {
+         frame1 = get_next_frame (frame);
+         if (!frame1)
+           break;
+         frame = frame1;
+         (*level_offset_ptr)++;
+       }
+    }
+  return frame;
+}
+
+/* The "select_frame" command.  With no arg, NOP.
+   With arg LEVEL_EXP, select the frame at level LEVEL if it is a
+   valid level.  Otherwise, treat level_exp as an address expression
+   and select it.  See parse_frame_specification for more info on proper
+   frame expressions. */
+
+/* ARGSUSED */
+void
+select_frame_command_wrapper (char *level_exp, int from_tty)
+{
+  select_frame_command (level_exp, from_tty);
+}
+
+static void
+select_frame_command (char *level_exp, int from_tty)
+{
+  struct frame_info *frame;
+  int level = frame_relative_level (selected_frame);
+
+  if (!target_has_stack)
+    error ("No stack.");
+
+  frame = parse_frame_specification (level_exp);
+
+  select_frame (frame);
+  if (level != frame_relative_level (selected_frame))
+    selected_frame_level_changed_event (frame_relative_level (selected_frame));
+}
+
+/* The "frame" command.  With no arg, print selected frame briefly.
+   With arg, behaves like select_frame and then prints the selected
+   frame.  */
+
+void
+frame_command (char *level_exp, int from_tty)
+{
+  select_frame_command (level_exp, from_tty);
+  show_and_print_stack_frame (selected_frame,
+                             frame_relative_level (selected_frame), 1);
+}
+
+/* The XDB Compatibility command to print the current frame. */
+
+static void
+current_frame_command (char *level_exp, int from_tty)
+{
+  if (target_has_stack == 0 || selected_frame == 0)
+    error ("No stack.");
+  print_only_stack_frame (selected_frame,
+                         frame_relative_level (selected_frame), 1);
+}
+
+/* Select the frame up one or COUNT stack levels
+   from the previously selected frame, and print it briefly.  */
+
+/* ARGSUSED */
+static void
+up_silently_base (char *count_exp)
+{
+  register struct frame_info *fi;
+  int count = 1, count1;
+  if (count_exp)
+    count = parse_and_eval_long (count_exp);
+  count1 = count;
+
+  if (target_has_stack == 0 || selected_frame == 0)
+    error ("No stack.");
+
+  fi = find_relative_frame (selected_frame, &count1);
+  if (count1 != 0 && count_exp == 0)
+    error ("Initial frame selected; you cannot go up.");
+  select_frame (fi);
+  selected_frame_level_changed_event (frame_relative_level (selected_frame));
+}
+
+static void
+up_silently_command (char *count_exp, int from_tty)
+{
+  up_silently_base (count_exp);
+}
+
+static void
+up_command (char *count_exp, int from_tty)
+{
+  up_silently_base (count_exp);
+  show_and_print_stack_frame (selected_frame,
+                             frame_relative_level (selected_frame), 1);
+}
+
+/* Select the frame down one or COUNT stack levels
+   from the previously selected frame, and print it briefly.  */
+
+/* ARGSUSED */
+static void
+down_silently_base (char *count_exp)
+{
+  register struct frame_info *frame;
+  int count = -1, count1;
+  if (count_exp)
+    count = -parse_and_eval_long (count_exp);
+  count1 = count;
+
+  if (target_has_stack == 0 || selected_frame == 0)
+    error ("No stack.");
+
+  frame = find_relative_frame (selected_frame, &count1);
+  if (count1 != 0 && count_exp == 0)
+    {
+
+      /* We only do this if count_exp is not specified.  That way "down"
+         means to really go down (and let me know if that is
+         impossible), but "down 9999" can be used to mean go all the way
+         down without getting an error.  */
+
+      error ("Bottom (i.e., innermost) frame selected; you cannot go down.");
+    }
+
+  select_frame (frame);
+  selected_frame_level_changed_event (frame_relative_level (selected_frame));
+}
+
+/* ARGSUSED */
+static void
+down_silently_command (char *count_exp, int from_tty)
+{
+  down_silently_base (count_exp);
+}
+
+static void
+down_command (char *count_exp, int from_tty)
+{
+  down_silently_base (count_exp);
+  show_and_print_stack_frame (selected_frame,
+                             frame_relative_level (selected_frame), 1);
+}
+\f
+void
+return_command_wrapper (char *retval_exp, int from_tty)
+{
+  return_command (retval_exp, from_tty);
+}
+
+static void
+return_command (char *retval_exp, int from_tty)
+{
+  struct symbol *thisfun;
+  CORE_ADDR selected_frame_addr;
+  CORE_ADDR selected_frame_pc;
+  struct frame_info *frame;
+  struct value *return_value = NULL;
+
+  if (selected_frame == NULL)
+    error ("No selected frame.");
+  thisfun = get_frame_function (selected_frame);
+  selected_frame_addr = FRAME_FP (selected_frame);
+  selected_frame_pc = selected_frame->pc;
+
+  /* Compute the return value (if any -- possibly getting errors here).  */
+
+  if (retval_exp)
+    {
+      struct type *return_type = NULL;
+
+      return_value = parse_and_eval (retval_exp);
+
+      /* Cast return value to the return type of the function.  */
+      if (thisfun != NULL)
+       return_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (thisfun));
+      if (return_type == NULL)
+       return_type = builtin_type_int;
+      return_value = value_cast (return_type, return_value);
+
+      /* Make sure we have fully evaluated it, since
+         it might live in the stack frame we're about to pop.  */
+      if (VALUE_LAZY (return_value))
+       value_fetch_lazy (return_value);
+    }
+
+  /* If interactive, require confirmation.  */
+
+  if (from_tty)
+    {
+      if (thisfun != 0)
+       {
+         if (!query ("Make %s return now? ", SYMBOL_SOURCE_NAME (thisfun)))
+           {
+             error ("Not confirmed.");
+             /* NOTREACHED */
+           }
+       }
+      else if (!query ("Make selected stack frame return now? "))
+       error ("Not confirmed.");
+    }
+
+  /* Do the real work.  Pop until the specified frame is current.  We
+     use this method because the selected_frame is not valid after
+     a POP_FRAME.  The pc comparison makes this work even if the
+     selected frame shares its fp with another frame.  */
+
+  while (selected_frame_addr != (frame = get_current_frame ())->frame
+        || selected_frame_pc != frame->pc)
+    POP_FRAME;
+
+  /* Then pop that frame.  */
+
+  POP_FRAME;
+
+  /* Compute the return value (if any) and store in the place
+     for return values.  */
+
+  if (retval_exp)
+    set_return_value (return_value);
+
+  /* If we are at the end of a call dummy now, pop the dummy frame too.  */
+
+  if (CALL_DUMMY_HAS_COMPLETED (read_pc(), read_sp (),
+                               FRAME_FP (get_current_frame ())))
+    POP_FRAME;
+
+  /* If interactive, print the frame that is now current.  */
+
+  if (from_tty)
+    frame_command ("0", 1);
+  else
+    select_frame_command ("0", 0);
+}
+
+/* Sets the scope to input function name, provided that the
+   function is within the current stack frame */
+
+struct function_bounds
+{
+  CORE_ADDR low, high;
+};
+
+static void func_command (char *arg, int from_tty);
+static void
+func_command (char *arg, int from_tty)
+{
+  struct frame_info *fp;
+  int found = 0;
+  struct symtabs_and_lines sals;
+  int i;
+  int level = 1;
+  struct function_bounds *func_bounds = (struct function_bounds *) NULL;
+
+  if (arg != (char *) NULL)
+    return;
+
+  fp = parse_frame_specification ("0");
+  sals = decode_line_spec (arg, 1);
+  func_bounds = (struct function_bounds *) xmalloc (
+                             sizeof (struct function_bounds) * sals.nelts);
+  for (i = 0; (i < sals.nelts && !found); i++)
+    {
+      if (sals.sals[i].pc == (CORE_ADDR) 0 ||
+         find_pc_partial_function (sals.sals[i].pc,
+                                   (char **) NULL,
+                                   &func_bounds[i].low,
+                                   &func_bounds[i].high) == 0)
+       {
+         func_bounds[i].low =
+           func_bounds[i].high = (CORE_ADDR) NULL;
+       }
+    }
+
+  do
+    {
+      for (i = 0; (i < sals.nelts && !found); i++)
+       found = (fp->pc >= func_bounds[i].low &&
+                fp->pc < func_bounds[i].high);
+      if (!found)
+       {
+         level = 1;
+         fp = find_relative_frame (fp, &level);
+       }
+    }
+  while (!found && level == 0);
+
+  if (func_bounds)
+    xfree (func_bounds);
+
+  if (!found)
+    printf_filtered ("'%s' not within current stack frame.\n", arg);
+  else if (fp != selected_frame)
+    select_and_print_frame (fp);
+}
+
+/* Gets the language of the current frame.  */
+
+enum language
+get_frame_language (void)
+{
+  register struct symtab *s;
+  enum language flang;         /* The language of the current frame */
+
+  if (selected_frame)
+    {
+      s = find_pc_symtab (selected_frame->pc);
+      if (s)
+       flang = s->language;
+      else
+       flang = language_unknown;
+    }
+  else
+    flang = language_unknown;
+
+  return flang;
+}
+\f
+void
+_initialize_stack (void)
+{
+#if 0
+  backtrace_limit = 30;
+#endif
+
+  add_com ("return", class_stack, return_command,
+          "Make selected stack frame return to its caller.\n\
+Control remains in the debugger, but when you continue\n\
+execution will resume in the frame above the one now selected.\n\
+If an argument is given, it is an expression for the value to return.");
+
+  add_com ("up", class_stack, up_command,
+          "Select and print stack frame that called this one.\n\
+An argument says how many frames up to go.");
+  add_com ("up-silently", class_support, up_silently_command,
+          "Same as the `up' command, but does not print anything.\n\
+This is useful in command scripts.");
+
+  add_com ("down", class_stack, down_command,
+          "Select and print stack frame called by this one.\n\
+An argument says how many frames down to go.");
+  add_com_alias ("do", "down", class_stack, 1);
+  add_com_alias ("dow", "down", class_stack, 1);
+  add_com ("down-silently", class_support, down_silently_command,
+          "Same as the `down' command, but does not print anything.\n\
+This is useful in command scripts.");
+
+  add_com ("frame", class_stack, frame_command,
+          "Select and print a stack frame.\n\
+With no argument, print the selected stack frame.  (See also \"info frame\").\n\
+An argument specifies the frame to select.\n\
+It can be a stack frame number or the address of the frame.\n\
+With argument, nothing is printed if input is coming from\n\
+a command file or a user-defined command.");
+
+  add_com_alias ("f", "frame", class_stack, 1);
+
+  if (xdb_commands)
+    {
+      add_com ("L", class_stack, current_frame_command,
+              "Print the current stack frame.\n");
+      add_com_alias ("V", "frame", class_stack, 1);
+    }
+  add_com ("select-frame", class_stack, select_frame_command,
+          "Select a stack frame without printing anything.\n\
+An argument specifies the frame to select.\n\
+It can be a stack frame number or the address of the frame.\n");
+
+  add_com ("backtrace", class_stack, backtrace_command,
+          "Print backtrace of all stack frames, or innermost COUNT frames.\n\
+With a negative argument, print outermost -COUNT frames.\n\
+Use of the 'full' qualifier also prints the values of the local variables.\n");
+  add_com_alias ("bt", "backtrace", class_stack, 0);
+  if (xdb_commands)
+    {
+      add_com_alias ("t", "backtrace", class_stack, 0);
+      add_com ("T", class_stack, backtrace_full_command,
+              "Print backtrace of all stack frames, or innermost COUNT frames \n\
+and the values of the local variables.\n\
+With a negative argument, print outermost -COUNT frames.\n\
+Usage: T <count>\n");
+    }
+
+  add_com_alias ("where", "backtrace", class_alias, 0);
+  add_info ("stack", backtrace_command,
+           "Backtrace of the stack, or innermost COUNT frames.");
+  add_info_alias ("s", "stack", 1);
+  add_info ("frame", frame_info,
+           "All about selected stack frame, or frame at ADDR.");
+  add_info_alias ("f", "frame", 1);
+  add_info ("locals", locals_info,
+           "Local variables of current stack frame.");
+  add_info ("args", args_info,
+           "Argument variables of current stack frame.");
+  if (xdb_commands)
+    add_com ("l", class_info, args_plus_locals_info,
+            "Argument and local variables of current stack frame.");
+
+  if (dbx_commands)
+    add_com ("func", class_stack, func_command,
+      "Select the stack frame that contains <func>.\nUsage: func <name>\n");
+
+  add_info ("catch", catch_info,
+           "Exceptions that can be caught in the current stack frame.");
+
+#if 0
+  add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command,
+  "Specify maximum number of frames for \"backtrace\" to print by default.",
+          &setlist);
+  add_info ("backtrace-limit", backtrace_limit_info,
+     "The maximum number of frames for \"backtrace\" to print by default.");
+#endif
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
new file mode 100644 (file)
index 0000000..2d12f31
--- /dev/null
@@ -0,0 +1,2812 @@
+/* Tracing functionality for remote targets in custom GDB protocol
+
+   Copyright 1997, 1998, 1999, 2000, 2001, 2002 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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "symtab.h"
+#include "frame.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "gdbcmd.h"
+#include "value.h"
+#include "target.h"
+#include "language.h"
+#include "gdb_string.h"
+#include "inferior.h"
+#include "tracepoint.h"
+#include "remote.h"
+#include "linespec.h"
+#include "regcache.h"
+#include "completer.h"
+#include "gdb-events.h"
+
+#include "ax.h"
+#include "ax-gdb.h"
+
+/* readline include files */
+#include <readline/readline.h>
+#include <readline/history.h>
+
+/* readline defines this.  */
+#undef savestring
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* maximum length of an agent aexpression.
+   this accounts for the fact that packets are limited to 400 bytes
+   (which includes everything -- including the checksum), and assumes
+   the worst case of maximum length for each of the pieces of a
+   continuation packet.
+
+   NOTE: expressions get mem2hex'ed otherwise this would be twice as
+   large.  (400 - 31)/2 == 184 */
+#define MAX_AGENT_EXPR_LEN     184
+
+
+extern void (*readline_begin_hook) (char *, ...);
+extern char *(*readline_hook) (char *);
+extern void (*readline_end_hook) (void);
+extern void x_command (char *, int);
+extern int addressprint;       /* Print machine addresses? */
+
+/* GDB commands implemented in other modules:
+ */  
+
+extern void output_command (char *, int);
+extern void registers_info (char *, int);
+extern void args_info (char *, int);
+extern void locals_info (char *, int);
+
+
+/* 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
+
+/* 
+   Tracepoint.c:
+
+   This module defines the following debugger commands:
+   trace            : set a tracepoint on a function, line, or address.
+   info trace       : list all debugger-defined tracepoints.
+   delete trace     : delete one or more tracepoints.
+   enable trace     : enable one or more tracepoints.
+   disable trace    : disable one or more tracepoints.
+   actions          : specify actions to be taken at a tracepoint.
+   passcount        : specify a pass count for a tracepoint.
+   tstart           : start a trace experiment.
+   tstop            : stop a trace experiment.
+   tstatus          : query the status of a trace experiment.
+   tfind            : find a trace frame in the trace buffer.
+   tdump            : print everything collected at the current tracepoint.
+   save-tracepoints : write tracepoint setup into a file.
+
+   This module defines the following user-visible debugger variables:
+   $trace_frame : sequence number of trace frame currently being debugged.
+   $trace_line  : source line of trace frame currently being debugged.
+   $trace_file  : source file of trace frame currently being debugged.
+   $tracepoint  : tracepoint number of trace frame currently being debugged.
+ */
+
+
+/* ======= Important global variables: ======= */
+
+/* Chain of all tracepoints defined.  */
+struct tracepoint *tracepoint_chain;
+
+/* Number of last tracepoint made.  */
+static int tracepoint_count;
+
+/* Number of last traceframe collected.  */
+static int traceframe_number;
+
+/* Tracepoint for last traceframe collected.  */
+static int tracepoint_number;
+
+/* Symbol for function for last traceframe collected */
+static struct symbol *traceframe_fun;
+
+/* Symtab and line for last traceframe collected */
+static struct symtab_and_line traceframe_sal;
+
+/* Tracing command lists */
+static struct cmd_list_element *tfindlist;
+
+/* ======= Important command functions: ======= */
+static void trace_command (char *, int);
+static void tracepoints_info (char *, int);
+static void delete_trace_command (char *, int);
+static void enable_trace_command (char *, int);
+static void disable_trace_command (char *, int);
+static void trace_pass_command (char *, int);
+static void trace_actions_command (char *, int);
+static void trace_start_command (char *, int);
+static void trace_stop_command (char *, int);
+static void trace_status_command (char *, int);
+static void trace_find_command (char *, int);
+static void trace_find_pc_command (char *, int);
+static void trace_find_tracepoint_command (char *, int);
+static void trace_find_line_command (char *, int);
+static void trace_find_range_command (char *, int);
+static void trace_find_outside_command (char *, int);
+static void tracepoint_save_command (char *, int);
+static void trace_dump_command (char *, int);
+
+/* support routines */
+static void trace_mention (struct tracepoint *);
+
+struct collection_list;
+static void add_aexpr (struct collection_list *, struct agent_expr *);
+static unsigned char *mem2hex (unsigned char *, unsigned char *, int);
+static void add_register (struct collection_list *collection,
+                         unsigned int regno);
+static struct cleanup *make_cleanup_free_actions (struct tracepoint *t);
+static void free_actions_list (char **actions_list);
+static void free_actions_list_cleanup_wrapper (void *);
+
+extern void _initialize_tracepoint (void);
+
+/* Utility: returns true if "target remote" */
+static int
+target_is_remote (void)
+{
+  if (current_target.to_shortname &&
+      strcmp (current_target.to_shortname, "remote") == 0)
+    return 1;
+  else
+    return 0;
+}
+
+/* Utility: generate error from an incoming stub packet.  */
+static void
+trace_error (char *buf)
+{
+  if (*buf++ != 'E')
+    return;                    /* not an error msg */
+  switch (*buf)
+    {
+    case '1':                  /* malformed packet error */
+      if (*++buf == '0')       /*   general case: */
+       error ("tracepoint.c: error in outgoing packet.");
+      else
+       error ("tracepoint.c: error in outgoing packet at field #%ld.",
+              strtol (buf, NULL, 16));
+    case '2':
+      error ("trace API error 0x%s.", ++buf);
+    default:
+      error ("Target returns error code '%s'.", buf);
+    }
+}
+
+/* Utility: wait for reply from stub, while accepting "O" packets */
+static char *
+remote_get_noisy_reply (char *buf,
+                       long sizeof_buf)
+{
+  do                           /* loop on reply from remote stub */
+    {
+      QUIT;                    /* allow user to bail out with ^C */
+      getpkt (buf, sizeof_buf, 0);
+      if (buf[0] == 0)
+       error ("Target does not support this command.");
+      else if (buf[0] == 'E')
+       trace_error (buf);
+      else if (buf[0] == 'O' &&
+              buf[1] != 'K')
+       remote_console_output (buf + 1);        /* 'O' message from stub */
+      else
+       return buf;             /* here's the actual reply */
+    }
+  while (1);
+}
+
+/* Set tracepoint count to NUM.  */
+static void
+set_tracepoint_count (int num)
+{
+  tracepoint_count = num;
+  set_internalvar (lookup_internalvar ("tpnum"),
+                  value_from_longest (builtin_type_int, (LONGEST) num));
+}
+
+/* Set traceframe number to NUM.  */
+static void
+set_traceframe_num (int num)
+{
+  traceframe_number = num;
+  set_internalvar (lookup_internalvar ("trace_frame"),
+                  value_from_longest (builtin_type_int, (LONGEST) num));
+}
+
+/* Set tracepoint number to NUM.  */
+static void
+set_tracepoint_num (int num)
+{
+  tracepoint_number = num;
+  set_internalvar (lookup_internalvar ("tracepoint"),
+                  value_from_longest (builtin_type_int, (LONGEST) num));
+}
+
+/* Set externally visible debug variables for querying/printing
+   the traceframe context (line, function, file) */
+
+static void
+set_traceframe_context (CORE_ADDR trace_pc)
+{
+  static struct type *func_string, *file_string;
+  static struct type *func_range, *file_range;
+  struct value *func_val;
+  struct value *file_val;
+  static struct type *charstar;
+  int len;
+
+  if (charstar == (struct type *) NULL)
+    charstar = lookup_pointer_type (builtin_type_char);
+
+  if (trace_pc == -1)          /* cease debugging any trace buffers */
+    {
+      traceframe_fun = 0;
+      traceframe_sal.pc = traceframe_sal.line = 0;
+      traceframe_sal.symtab = NULL;
+      set_internalvar (lookup_internalvar ("trace_func"),
+                      value_from_pointer (charstar, (LONGEST) 0));
+      set_internalvar (lookup_internalvar ("trace_file"),
+                      value_from_pointer (charstar, (LONGEST) 0));
+      set_internalvar (lookup_internalvar ("trace_line"),
+                      value_from_pointer (builtin_type_int, (LONGEST) - 1));
+      return;
+    }
+
+  /* save as globals for internal use */
+  traceframe_sal = find_pc_line (trace_pc, 0);
+  traceframe_fun = find_pc_function (trace_pc);
+
+  /* save linenumber as "$trace_line", a debugger variable visible to users */
+  set_internalvar (lookup_internalvar ("trace_line"),
+                  value_from_longest (builtin_type_int,
+                                      (LONGEST) traceframe_sal.line));
+
+  /* save func name as "$trace_func", a debugger variable visible to users */
+  if (traceframe_fun == NULL ||
+      SYMBOL_NAME (traceframe_fun) == NULL)
+    set_internalvar (lookup_internalvar ("trace_func"),
+                    value_from_pointer (charstar, (LONGEST) 0));
+  else
+    {
+      len = strlen (SYMBOL_NAME (traceframe_fun));
+      func_range = create_range_type (func_range,
+                                     builtin_type_int, 0, len - 1);
+      func_string = create_array_type (func_string,
+                                      builtin_type_char, func_range);
+      func_val = allocate_value (func_string);
+      VALUE_TYPE (func_val) = func_string;
+      memcpy (VALUE_CONTENTS_RAW (func_val),
+             SYMBOL_NAME (traceframe_fun),
+             len);
+      func_val->modifiable = 0;
+      set_internalvar (lookup_internalvar ("trace_func"), func_val);
+    }
+
+  /* save file name as "$trace_file", a debugger variable visible to users */
+  if (traceframe_sal.symtab == NULL ||
+      traceframe_sal.symtab->filename == NULL)
+    set_internalvar (lookup_internalvar ("trace_file"),
+                    value_from_pointer (charstar, (LONGEST) 0));
+  else
+    {
+      len = strlen (traceframe_sal.symtab->filename);
+      file_range = create_range_type (file_range,
+                                     builtin_type_int, 0, len - 1);
+      file_string = create_array_type (file_string,
+                                      builtin_type_char, file_range);
+      file_val = allocate_value (file_string);
+      VALUE_TYPE (file_val) = file_string;
+      memcpy (VALUE_CONTENTS_RAW (file_val),
+             traceframe_sal.symtab->filename,
+             len);
+      file_val->modifiable = 0;
+      set_internalvar (lookup_internalvar ("trace_file"), file_val);
+    }
+}
+
+/* Low level routine to set a tracepoint.
+   Returns the tracepoint object so caller can set other things.
+   Does not set the tracepoint number!
+   Does not print anything.
+
+   ==> This routine should not be called if there is a chance of later
+   error(); otherwise it leaves a bogus tracepoint on the chain.  Validate
+   your arguments BEFORE calling this routine!  */
+
+static struct tracepoint *
+set_raw_tracepoint (struct symtab_and_line sal)
+{
+  register struct tracepoint *t, *tc;
+  struct cleanup *old_chain;
+
+  t = (struct tracepoint *) xmalloc (sizeof (struct tracepoint));
+  old_chain = make_cleanup (xfree, t);
+  memset (t, 0, sizeof (*t));
+  t->address = sal.pc;
+  if (sal.symtab == NULL)
+    t->source_file = NULL;
+  else
+    t->source_file = savestring (sal.symtab->filename,
+                                strlen (sal.symtab->filename));
+
+  t->section = sal.section;
+  t->language = current_language->la_language;
+  t->input_radix = input_radix;
+  t->line_number = sal.line;
+  t->enabled_p = 1;
+  t->next = 0;
+  t->step_count = 0;
+  t->pass_count = 0;
+  t->addr_string = NULL;
+
+  /* Add this tracepoint to the end of the chain
+     so that a list of tracepoints will come out in order
+     of increasing numbers.  */
+
+  tc = tracepoint_chain;
+  if (tc == 0)
+    tracepoint_chain = t;
+  else
+    {
+      while (tc->next)
+       tc = tc->next;
+      tc->next = t;
+    }
+  discard_cleanups (old_chain);
+  return t;
+}
+
+/* Set a tracepoint according to ARG (function, linenum or *address) */
+static void
+trace_command (char *arg, int from_tty)
+{
+  char **canonical = (char **) NULL;
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  struct tracepoint *t;
+  char *addr_start = 0, *addr_end = 0;
+  int i;
+
+  if (!arg || !*arg)
+    error ("trace command requires an argument");
+
+  if (from_tty && info_verbose)
+    printf_filtered ("TRACE %s\n", arg);
+
+  addr_start = arg;
+  sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, &canonical);
+  addr_end = arg;
+  if (!sals.nelts)
+    return;                    /* ??? Presumably decode_line_1 has already warned? */
+
+  /* Resolve all line numbers to PC's */
+  for (i = 0; i < sals.nelts; i++)
+    resolve_sal_pc (&sals.sals[i]);
+
+  /* Now set all the tracepoints.  */
+  for (i = 0; i < sals.nelts; i++)
+    {
+      sal = sals.sals[i];
+
+      t = set_raw_tracepoint (sal);
+      set_tracepoint_count (tracepoint_count + 1);
+      t->number = tracepoint_count;
+
+      /* If a canonical line spec is needed use that instead of the
+         command string.  */
+      if (canonical != (char **) NULL && canonical[i] != NULL)
+       t->addr_string = canonical[i];
+      else if (addr_start)
+       t->addr_string = savestring (addr_start, addr_end - addr_start);
+
+      trace_mention (t);
+    }
+
+  if (sals.nelts > 1)
+    {
+      printf_filtered ("Multiple tracepoints were set.\n");
+      printf_filtered ("Use 'delete trace' to delete unwanted tracepoints.\n");
+    }
+}
+
+/* Tell the user we have just set a tracepoint TP. */
+
+static void
+trace_mention (struct tracepoint *tp)
+{
+  printf_filtered ("Tracepoint %d", tp->number);
+
+  if (addressprint || (tp->source_file == NULL))
+    {
+      printf_filtered (" at ");
+      print_address_numeric (tp->address, 1, gdb_stdout);
+    }
+  if (tp->source_file)
+    printf_filtered (": file %s, line %d.",
+                    tp->source_file, tp->line_number);
+
+  printf_filtered ("\n");
+}
+
+/* Print information on tracepoint number TPNUM_EXP, or all if omitted.  */
+
+static void
+tracepoints_info (char *tpnum_exp, int from_tty)
+{
+  struct tracepoint *t;
+  struct action_line *action;
+  int found_a_tracepoint = 0;
+  char wrap_indent[80];
+  struct symbol *sym;
+  int tpnum = -1;
+
+  if (tpnum_exp)
+    tpnum = parse_and_eval_long (tpnum_exp);
+
+  ALL_TRACEPOINTS (t)
+    if (tpnum == -1 || tpnum == t->number)
+    {
+      extern int addressprint; /* print machine addresses? */
+
+      if (!found_a_tracepoint++)
+       {
+         printf_filtered ("Num Enb ");
+         if (addressprint)
+           {
+             if (TARGET_ADDR_BIT <= 32)
+               printf_filtered ("Address    ");
+             else
+               printf_filtered ("Address            ");
+           }
+         printf_filtered ("PassC StepC What\n");
+       }
+      strcpy (wrap_indent, "                           ");
+      if (addressprint)
+       {
+         if (TARGET_ADDR_BIT <= 32)
+           strcat (wrap_indent, "           ");
+         else
+           strcat (wrap_indent, "                   ");
+       }
+
+      printf_filtered ("%-3d %-3s ", t->number,
+                      t->enabled_p ? "y" : "n");
+      if (addressprint)
+       {
+         char *tmp;
+
+         if (TARGET_ADDR_BIT <= 32)
+           tmp = local_hex_string_custom (t->address
+                                          & (CORE_ADDR) 0xffffffff, 
+                                          "08l");
+         else
+           tmp = local_hex_string_custom (t->address, "016l");
+
+         printf_filtered ("%s ", tmp);
+       }
+      printf_filtered ("%-5d %-5ld ", t->pass_count, t->step_count);
+
+      if (t->source_file)
+       {
+         sym = find_pc_sect_function (t->address, t->section);
+         if (sym)
+           {
+             fputs_filtered ("in ", gdb_stdout);
+             fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
+             wrap_here (wrap_indent);
+             fputs_filtered (" at ", gdb_stdout);
+           }
+         fputs_filtered (t->source_file, gdb_stdout);
+         printf_filtered (":%d", t->line_number);
+       }
+      else
+       print_address_symbolic (t->address, gdb_stdout, demangle, " ");
+
+      printf_filtered ("\n");
+      if (t->actions)
+       {
+         printf_filtered ("  Actions for tracepoint %d: \n", t->number);
+         for (action = t->actions; action; action = action->next)
+           {
+             printf_filtered ("\t%s\n", action->action);
+           }
+       }
+    }
+  if (!found_a_tracepoint)
+    {
+      if (tpnum == -1)
+       printf_filtered ("No tracepoints.\n");
+      else
+       printf_filtered ("No tracepoint number %d.\n", tpnum);
+    }
+}
+
+/* Optimization: the code to parse an enable, disable, or delete TP command
+   is virtually identical except for whether it performs an enable, disable,
+   or delete.  Therefore I've combined them into one function with an opcode.
+ */
+enum tracepoint_opcode
+{
+  enable_op,
+  disable_op,
+  delete_op
+};
+
+/* This function implements enable, disable and delete commands. */
+static void
+tracepoint_operation (struct tracepoint *t, int from_tty,
+                     enum tracepoint_opcode opcode)
+{
+  struct tracepoint *t2;
+
+  if (t == NULL)       /* no tracepoint operand */
+    return;
+
+  switch (opcode)
+    {
+    case enable_op:
+      t->enabled_p = 1;
+      tracepoint_modify_event (t->number);
+      break;
+    case disable_op:
+      t->enabled_p = 0;
+      tracepoint_modify_event (t->number);
+      break;
+    case delete_op:
+      if (tracepoint_chain == t)
+       tracepoint_chain = t->next;
+
+      ALL_TRACEPOINTS (t2)
+       if (t2->next == t)
+       {
+         tracepoint_delete_event (t2->number);
+         t2->next = t->next;
+         break;
+       }
+
+      if (t->addr_string)
+       xfree (t->addr_string);
+      if (t->source_file)
+       xfree (t->source_file);
+      if (t->actions)
+       free_actions (t);
+
+      xfree (t);
+      break;
+    }
+}
+
+/* Utility: parse a tracepoint number and look it up in the list.
+   If MULTI_P is true, there might be a range of tracepoints in ARG.
+   if OPTIONAL_P is true, then if the argument is missing, the most
+   recent tracepoint (tracepoint_count) is returned.  */
+struct tracepoint *
+get_tracepoint_by_number (char **arg, int multi_p, int optional_p)
+{
+  struct tracepoint *t;
+  int tpnum;
+  char *instring = arg == NULL ? NULL : *arg;
+
+  if (arg == NULL || *arg == NULL || ! **arg)
+    {
+      if (optional_p)
+       tpnum = tracepoint_count;
+      else
+       error_no_arg ("tracepoint number");
+    }
+  else
+    tpnum = multi_p ? get_number_or_range (arg) : get_number (arg);
+
+  if (tpnum <= 0)
+    {
+      if (instring && *instring)
+       printf_filtered ("bad tracepoint number at or near '%s'\n", instring);
+      else
+       printf_filtered ("Tracepoint argument missing and no previous tracepoint\n");
+      return NULL;
+    }
+
+  ALL_TRACEPOINTS (t)
+    if (t->number == tpnum)
+    {
+      return t;
+    }
+
+  /* FIXME: if we are in the middle of a range we don't want to give
+     a message.  The current interface to get_number_or_range doesn't
+     allow us to discover this.  */
+  printf_unfiltered ("No tracepoint number %d.\n", tpnum);
+  return NULL;
+}
+
+/* Utility: parse a list of tracepoint numbers, and call a func for each. */
+static void
+map_args_over_tracepoints (char *args, int from_tty,
+                          enum tracepoint_opcode opcode)
+{
+  struct tracepoint *t, *tmp;
+
+  if (args == 0 || *args == 0) /* do them all */
+    ALL_TRACEPOINTS_SAFE (t, tmp)
+      tracepoint_operation (t, from_tty, opcode);
+  else
+    while (*args)
+      {
+       QUIT;                   /* give user option to bail out with ^C */
+       t = get_tracepoint_by_number (&args, 1, 0);
+       tracepoint_operation (t, from_tty, opcode);
+       while (*args == ' ' || *args == '\t')
+         args++;
+      }
+}
+
+/* The 'enable trace' command enables tracepoints.  Not supported by all targets.  */
+static void
+enable_trace_command (char *args, int from_tty)
+{
+  dont_repeat ();
+  map_args_over_tracepoints (args, from_tty, enable_op);
+}
+
+/* The 'disable trace' command enables tracepoints.  Not supported by all targets.  */
+static void
+disable_trace_command (char *args, int from_tty)
+{
+  dont_repeat ();
+  map_args_over_tracepoints (args, from_tty, disable_op);
+}
+
+/* Remove a tracepoint (or all if no argument) */
+static void
+delete_trace_command (char *args, int from_tty)
+{
+  dont_repeat ();
+  if (!args || !*args)         /* No args implies all tracepoints; */
+    if (from_tty)              /* confirm only if from_tty... */
+      if (tracepoint_chain)    /* and if there are tracepoints to delete! */
+       if (!query ("Delete all tracepoints? "))
+         return;
+
+  map_args_over_tracepoints (args, from_tty, delete_op);
+}
+
+/* Set passcount for tracepoint.
+
+   First command argument is passcount, second is tracepoint number.
+   If tracepoint number omitted, apply to most recently defined.
+   Also accepts special argument "all".  */
+
+static void
+trace_pass_command (char *args, int from_tty)
+{
+  struct tracepoint *t1 = (struct tracepoint *) -1, *t2;
+  unsigned int count;
+  int all = 0;
+
+  if (args == 0 || *args == 0)
+    error ("passcount command requires an argument (count + optional TP num)");
+
+  count = strtoul (args, &args, 10);   /* count comes first, then TP num */
+
+  while (*args && isspace ((int) *args))
+    args++;
+
+  if (*args && strncasecmp (args, "all", 3) == 0)
+    {
+      args += 3;                       /* skip special argument "all" */
+      all = 1;
+      if (*args)
+       error ("Junk at end of arguments.");
+    }
+  else
+    t1 = get_tracepoint_by_number (&args, 1, 1);
+
+  do
+    {
+      if (t1)
+       {
+         ALL_TRACEPOINTS (t2)
+           if (t1 == (struct tracepoint *) -1 || t1 == t2)
+             {
+               t2->pass_count = count;
+               tracepoint_modify_event (t2->number);
+               if (from_tty)
+                 printf_filtered ("Setting tracepoint %d's passcount to %d\n",
+                                  t2->number, count);
+             }
+         if (! all && *args)
+           t1 = get_tracepoint_by_number (&args, 1, 0);
+       }
+    }
+  while (*args);
+}
+
+/* ACTIONS functions: */
+
+/* Prototypes for action-parsing utility commands  */
+static void read_actions (struct tracepoint *);
+
+/* The three functions:
+   collect_pseudocommand, 
+   while_stepping_pseudocommand, and 
+   end_actions_pseudocommand
+   are placeholders for "commands" that are actually ONLY to be used
+   within a tracepoint action list.  If the actual function is ever called,
+   it means that somebody issued the "command" at the top level,
+   which is always an error.  */
+
+static void
+end_actions_pseudocommand (char *args, int from_tty)
+{
+  error ("This command cannot be used at the top level.");
+}
+
+static void
+while_stepping_pseudocommand (char *args, int from_tty)
+{
+  error ("This command can only be used in a tracepoint actions list.");
+}
+
+static void
+collect_pseudocommand (char *args, int from_tty)
+{
+  error ("This command can only be used in a tracepoint actions list.");
+}
+
+/* Enter a list of actions for a tracepoint.  */
+static void
+trace_actions_command (char *args, int from_tty)
+{
+  struct tracepoint *t;
+  char tmpbuf[128];
+  char *end_msg = "End with a line saying just \"end\".";
+
+  t = get_tracepoint_by_number (&args, 0, 1);
+  if (t)
+    {
+      sprintf (tmpbuf, "Enter actions for tracepoint %d, one per line.",
+              t->number);
+
+      if (from_tty)
+       {
+         if (readline_begin_hook)
+           (*readline_begin_hook) ("%s  %s\n", tmpbuf, end_msg);
+         else if (input_from_terminal_p ())
+           printf_filtered ("%s\n%s\n", tmpbuf, end_msg);
+       }
+
+      free_actions (t);
+      t->step_count = 0;       /* read_actions may set this */
+      read_actions (t);
+
+      if (readline_end_hook)
+       (*readline_end_hook) ();
+      /* tracepoints_changed () */
+    }
+  /* else just return */
+}
+
+/* worker function */
+static void
+read_actions (struct tracepoint *t)
+{
+  char *line;
+  char *prompt1 = "> ", *prompt2 = "  > ";
+  char *prompt = prompt1;
+  enum actionline_type linetype;
+  extern FILE *instream;
+  struct action_line *next = NULL, *temp;
+  struct cleanup *old_chain;
+
+  /* Control-C quits instantly if typed while in this loop
+     since it should not wait until the user types a newline.  */
+  immediate_quit++;
+  /* FIXME: kettenis/20010823: Something is wrong here.  In this file
+     STOP_SIGNAL is never defined.  So this code has been left out, at
+     least for quite a while now.  Replacing STOP_SIGNAL with SIGTSTP
+     leads to compilation failures since the variable job_control
+     isn't declared.  Leave this alone for now.  */
+#ifdef STOP_SIGNAL
+  if (job_control)
+    {
+      if (event_loop_p)
+       signal (STOP_SIGNAL, handle_stop_sig);
+      else
+       signal (STOP_SIGNAL, stop_sig);
+    }
+#endif
+  old_chain = make_cleanup_free_actions (t);
+  while (1)
+    {
+      /* Make sure that all output has been output.  Some machines may let
+         you get away with leaving out some of the gdb_flush, but not all.  */
+      wrap_here ("");
+      gdb_flush (gdb_stdout);
+      gdb_flush (gdb_stderr);
+
+      if (readline_hook && instream == NULL)
+       line = (*readline_hook) (prompt);
+      else if (instream == stdin && ISATTY (instream))
+       {
+         line = gdb_readline_wrapper (prompt);
+         if (line && *line)    /* add it to command history */
+           add_history (line);
+       }
+      else
+       line = gdb_readline (0);
+
+      linetype = validate_actionline (&line, t);
+      if (linetype == BADLINE)
+       continue;               /* already warned -- collect another line */
+
+      temp = xmalloc (sizeof (struct action_line));
+      temp->next = NULL;
+      temp->action = line;
+
+      if (next == NULL)                /* first action for this tracepoint? */
+       t->actions = next = temp;
+      else
+       {
+         next->next = temp;
+         next = temp;
+       }
+
+      if (linetype == STEPPING)        /* begin "while-stepping" */
+       {
+         if (prompt == prompt2)
+           {
+             warning ("Already processing 'while-stepping'");
+             continue;
+           }
+         else
+           prompt = prompt2;   /* change prompt for stepping actions */
+       }
+      else if (linetype == END)
+       {
+         if (prompt == prompt2)
+           {
+             prompt = prompt1; /* end of single-stepping actions */
+           }
+         else
+           {                   /* end of actions */
+             if (t->actions->next == NULL)
+               {
+                 /* an "end" all by itself with no other actions means
+                    this tracepoint has no actions.  Discard empty list. */
+                 free_actions (t);
+               }
+             break;
+           }
+       }
+    }
+#ifdef STOP_SIGNAL
+  if (job_control)
+    signal (STOP_SIGNAL, SIG_DFL);
+#endif
+  immediate_quit--;
+  discard_cleanups (old_chain);
+}
+
+/* worker function */
+enum actionline_type
+validate_actionline (char **line, struct tracepoint *t)
+{
+  struct cmd_list_element *c;
+  struct expression *exp = NULL;
+  struct cleanup *old_chain = NULL;
+  char *p;
+
+  for (p = *line; isspace ((int) *p);)
+    p++;
+
+  /* symbol lookup etc. */
+  if (*p == '\0')              /* empty line: just prompt for another line. */
+    return BADLINE;
+
+  if (*p == '#')               /* comment line */
+    return GENERIC;
+
+  c = lookup_cmd (&p, cmdlist, "", -1, 1);
+  if (c == 0)
+    {
+      warning ("'%s' is not an action that I know, or is ambiguous.", p);
+      return BADLINE;
+    }
+
+  if (cmd_cfunc_eq (c, collect_pseudocommand))
+    {
+      struct agent_expr *aexpr;
+      struct agent_reqs areqs;
+
+      do
+       {                       /* repeat over a comma-separated list */
+         QUIT;                 /* allow user to bail out with ^C */
+         while (isspace ((int) *p))
+           p++;
+
+         if (*p == '$')        /* look for special pseudo-symbols */
+           {
+             if ((0 == strncasecmp ("reg", p + 1, 3)) ||
+                 (0 == strncasecmp ("arg", p + 1, 3)) ||
+                 (0 == strncasecmp ("loc", p + 1, 3)))
+               {
+                 p = strchr (p, ',');
+                 continue;
+               }
+             /* else fall thru, treat p as an expression and parse it! */
+           }
+         exp = parse_exp_1 (&p, block_for_pc (t->address), 1);
+         old_chain = make_cleanup (free_current_contents, &exp);
+
+         if (exp->elts[0].opcode == OP_VAR_VALUE)
+           {
+             if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
+               {
+                 warning ("constant %s (value %ld) will not be collected.",
+                          SYMBOL_NAME (exp->elts[2].symbol),
+                          SYMBOL_VALUE (exp->elts[2].symbol));
+                 return BADLINE;
+               }
+             else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT)
+               {
+                 warning ("%s is optimized away and cannot be collected.",
+                          SYMBOL_NAME (exp->elts[2].symbol));
+                 return BADLINE;
+               }
+           }
+
+         /* we have something to collect, make sure that the expr to
+            bytecode translator can handle it and that it's not too long */
+         aexpr = gen_trace_for_expr (t->address, exp);
+         make_cleanup_free_agent_expr (aexpr);
+
+         if (aexpr->len > MAX_AGENT_EXPR_LEN)
+           error ("expression too complicated, try simplifying");
+
+         ax_reqs (aexpr, &areqs);
+         (void) make_cleanup (xfree, areqs.reg_mask);
+
+         if (areqs.flaw != agent_flaw_none)
+           error ("malformed expression");
+
+         if (areqs.min_height < 0)
+           error ("gdb: Internal error: expression has min height < 0");
+
+         if (areqs.max_height > 20)
+           error ("expression too complicated, try simplifying");
+
+         do_cleanups (old_chain);
+       }
+      while (p && *p++ == ',');
+      return GENERIC;
+    }
+  else if (cmd_cfunc_eq (c, while_stepping_pseudocommand))
+    {
+      char *steparg;           /* in case warning is necessary */
+
+      while (isspace ((int) *p))
+       p++;
+      steparg = p;
+
+      if (*p == '\0' ||
+         (t->step_count = strtol (p, &p, 0)) == 0)
+       {
+         warning ("'%s': bad step-count; command ignored.", *line);
+         return BADLINE;
+       }
+      return STEPPING;
+    }
+  else if (cmd_cfunc_eq (c, end_actions_pseudocommand))
+    return END;
+  else
+    {
+      warning ("'%s' is not a supported tracepoint action.", *line);
+      return BADLINE;
+    }
+}
+
+/* worker function */
+void
+free_actions (struct tracepoint *t)
+{
+  struct action_line *line, *next;
+
+  for (line = t->actions; line; line = next)
+    {
+      next = line->next;
+      if (line->action)
+       xfree (line->action);
+      xfree (line);
+    }
+  t->actions = NULL;
+}
+
+static void
+do_free_actions_cleanup (void *t)
+{
+  free_actions (t);
+}
+
+static struct cleanup *
+make_cleanup_free_actions (struct tracepoint *t)
+{
+  return make_cleanup (do_free_actions_cleanup, t);
+}
+
+struct memrange
+{
+  int type;            /* 0 for absolute memory range, else basereg number */
+  bfd_signed_vma start;
+  bfd_signed_vma end;
+};
+
+struct collection_list
+  {
+    unsigned char regs_mask[8];        /* room for up to 256 regs */
+    long listsize;
+    long next_memrange;
+    struct memrange *list;
+    long aexpr_listsize;       /* size of array pointed to by expr_list elt */
+    long next_aexpr_elt;
+    struct agent_expr **aexpr_list;
+
+  }
+tracepoint_list, stepping_list;
+
+/* MEMRANGE functions: */
+
+static int memrange_cmp (const void *, const void *);
+
+/* compare memranges for qsort */
+static int
+memrange_cmp (const void *va, const void *vb)
+{
+  const struct memrange *a = va, *b = vb;
+
+  if (a->type < b->type)
+    return -1;
+  if (a->type > b->type)
+    return 1;
+  if (a->type == 0)
+    {
+      if ((bfd_vma) a->start < (bfd_vma) b->start)
+       return -1;
+      if ((bfd_vma) a->start > (bfd_vma) b->start)
+       return 1;
+    }
+  else
+    {
+      if (a->start < b->start)
+       return -1;
+      if (a->start > b->start)
+       return 1;
+    }
+  return 0;
+}
+
+/* Sort the memrange list using qsort, and merge adjacent memranges */
+static void
+memrange_sortmerge (struct collection_list *memranges)
+{
+  int a, b;
+
+  qsort (memranges->list, memranges->next_memrange,
+        sizeof (struct memrange), memrange_cmp);
+  if (memranges->next_memrange > 0)
+    {
+      for (a = 0, b = 1; b < memranges->next_memrange; b++)
+       {
+         if (memranges->list[a].type == memranges->list[b].type &&
+             memranges->list[b].start - memranges->list[a].end <=
+             MAX_REGISTER_VIRTUAL_SIZE)
+           {
+             /* memrange b starts before memrange a ends; merge them.  */
+             if (memranges->list[b].end > memranges->list[a].end)
+               memranges->list[a].end = memranges->list[b].end;
+             continue;         /* next b, same a */
+           }
+         a++;                  /* next a */
+         if (a != b)
+           memcpy (&memranges->list[a], &memranges->list[b],
+                   sizeof (struct memrange));
+       }
+      memranges->next_memrange = a + 1;
+    }
+}
+
+/* Add a register to a collection list */
+static void
+add_register (struct collection_list *collection, unsigned int regno)
+{
+  if (info_verbose)
+    printf_filtered ("collect register %d\n", regno);
+  if (regno > (8 * sizeof (collection->regs_mask)))
+    error ("Internal: register number %d too large for tracepoint",
+          regno);
+  collection->regs_mask[regno / 8] |= 1 << (regno % 8);
+}
+
+/* Add a memrange to a collection list */
+static void
+add_memrange (struct collection_list *memranges, int type, bfd_signed_vma base,
+             unsigned long len)
+{
+  if (info_verbose)
+    {
+      printf_filtered ("(%d,", type);
+      printf_vma (base);
+      printf_filtered (",%ld)\n", len);
+    }
+
+  /* type: 0 == memory, n == basereg */
+  memranges->list[memranges->next_memrange].type = type;
+  /* base: addr if memory, offset if reg relative. */
+  memranges->list[memranges->next_memrange].start = base;
+  /* len: we actually save end (base + len) for convenience */
+  memranges->list[memranges->next_memrange].end = base + len;
+  memranges->next_memrange++;
+  if (memranges->next_memrange >= memranges->listsize)
+    {
+      memranges->listsize *= 2;
+      memranges->list = xrealloc (memranges->list,
+                                 memranges->listsize);
+    }
+
+  if (type != -1)              /* better collect the base register! */
+    add_register (memranges, type);
+}
+
+/* Add a symbol to a collection list */
+static void
+collect_symbol (struct collection_list *collect, struct symbol *sym,
+               long frame_regno, long frame_offset)
+{
+  unsigned long len;
+  unsigned int reg;
+  bfd_signed_vma offset;
+
+  len = TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym)));
+  switch (SYMBOL_CLASS (sym))
+    {
+    default:
+      printf_filtered ("%s: don't know symbol class %d\n",
+                      SYMBOL_NAME (sym), SYMBOL_CLASS (sym));
+      break;
+    case LOC_CONST:
+      printf_filtered ("constant %s (value %ld) will not be collected.\n",
+                      SYMBOL_NAME (sym), SYMBOL_VALUE (sym));
+      break;
+    case LOC_STATIC:
+      offset = SYMBOL_VALUE_ADDRESS (sym);
+      if (info_verbose)
+       {
+         char tmp[40];
+
+         sprintf_vma (tmp, offset);
+         printf_filtered ("LOC_STATIC %s: collect %ld bytes at %s.\n",
+                          SYMBOL_NAME (sym), len, tmp /* address */);
+       }
+      add_memrange (collect, -1, offset, len); /* 0 == memory */
+      break;
+    case LOC_REGISTER:
+    case LOC_REGPARM:
+      reg = SYMBOL_VALUE (sym);
+      if (info_verbose)
+       printf_filtered ("LOC_REG[parm] %s: ", SYMBOL_NAME (sym));
+      add_register (collect, reg);
+      /* check for doubles stored in two registers */
+      /* FIXME: how about larger types stored in 3 or more regs? */
+      if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FLT &&
+         len > REGISTER_RAW_SIZE (reg))
+       add_register (collect, reg + 1);
+      break;
+    case LOC_REF_ARG:
+      printf_filtered ("Sorry, don't know how to do LOC_REF_ARG yet.\n");
+      printf_filtered ("       (will not collect %s)\n",
+                      SYMBOL_NAME (sym));
+      break;
+    case LOC_ARG:
+      reg = frame_regno;
+      offset = frame_offset + SYMBOL_VALUE (sym);
+      if (info_verbose)
+       {
+         printf_filtered ("LOC_LOCAL %s: Collect %ld bytes at offset ",
+                          SYMBOL_NAME (sym), len);
+         printf_vma (offset);
+         printf_filtered (" from frame ptr reg %d\n", reg);
+       }
+      add_memrange (collect, reg, offset, len);
+      break;
+    case LOC_REGPARM_ADDR:
+      reg = SYMBOL_VALUE (sym);
+      offset = 0;
+      if (info_verbose)
+       {
+         printf_filtered ("LOC_REGPARM_ADDR %s: Collect %ld bytes at offset ",
+                          SYMBOL_NAME (sym), len);
+         printf_vma (offset);
+         printf_filtered (" from reg %d\n", reg);
+       }
+      add_memrange (collect, reg, offset, len);
+      break;
+    case LOC_LOCAL:
+    case LOC_LOCAL_ARG:
+      reg = frame_regno;
+      offset = frame_offset + SYMBOL_VALUE (sym);
+      if (info_verbose)
+       {
+         printf_filtered ("LOC_LOCAL %s: Collect %ld bytes at offset ",
+                          SYMBOL_NAME (sym), len);
+         printf_vma (offset);
+         printf_filtered (" from frame ptr reg %d\n", reg);
+       }
+      add_memrange (collect, reg, offset, len);
+      break;
+    case LOC_BASEREG:
+    case LOC_BASEREG_ARG:
+      reg = SYMBOL_BASEREG (sym);
+      offset = SYMBOL_VALUE (sym);
+      if (info_verbose)
+       {
+         printf_filtered ("LOC_BASEREG %s: collect %ld bytes at offset ",
+                          SYMBOL_NAME (sym), len);
+         printf_vma (offset);
+         printf_filtered (" from basereg %d\n", reg);
+       }
+      add_memrange (collect, reg, offset, len);
+      break;
+    case LOC_UNRESOLVED:
+      printf_filtered ("Don't know LOC_UNRESOLVED %s\n", SYMBOL_NAME (sym));
+      break;
+    case LOC_OPTIMIZED_OUT:
+      printf_filtered ("%s has been optimized out of existence.\n",
+                      SYMBOL_NAME (sym));
+      break;
+    }
+}
+
+/* Add all locals (or args) symbols to collection list */
+static void
+add_local_symbols (struct collection_list *collect, CORE_ADDR pc,
+                  long frame_regno, long frame_offset, int type)
+{
+  struct symbol *sym;
+  struct block *block;
+  int i, count = 0;
+
+  block = block_for_pc (pc);
+  while (block != 0)
+    {
+      QUIT;                    /* allow user to bail out with ^C */
+      ALL_BLOCK_SYMBOLS (block, i, sym)
+       {
+         switch (SYMBOL_CLASS (sym))
+           {
+           default:
+             warning ("don't know how to trace local symbol %s", 
+                      SYMBOL_NAME (sym));
+           case LOC_LOCAL:
+           case LOC_STATIC:
+           case LOC_REGISTER:
+           case LOC_BASEREG:
+             if (type == 'L')  /* collecting Locals */
+               {
+                 count++;
+                 collect_symbol (collect, sym, frame_regno, frame_offset);
+               }
+             break;
+           case LOC_ARG:
+           case LOC_LOCAL_ARG:
+           case LOC_REF_ARG:
+           case LOC_REGPARM:
+           case LOC_REGPARM_ADDR:
+           case LOC_BASEREG_ARG:
+             if (type == 'A')  /* collecting Arguments */
+               {
+                 count++;
+                 collect_symbol (collect, sym, frame_regno, frame_offset);
+               }
+           }
+       }
+      if (BLOCK_FUNCTION (block))
+       break;
+      else
+       block = BLOCK_SUPERBLOCK (block);
+    }
+  if (count == 0)
+    warning ("No %s found in scope.", type == 'L' ? "locals" : "args");
+}
+
+/* worker function */
+static void
+clear_collection_list (struct collection_list *list)
+{
+  int ndx;
+
+  list->next_memrange = 0;
+  for (ndx = 0; ndx < list->next_aexpr_elt; ndx++)
+    {
+      free_agent_expr (list->aexpr_list[ndx]);
+      list->aexpr_list[ndx] = NULL;
+    }
+  list->next_aexpr_elt = 0;
+  memset (list->regs_mask, 0, sizeof (list->regs_mask));
+}
+
+/* reduce a collection list to string form (for gdb protocol) */
+static char **
+stringify_collection_list (struct collection_list *list, char *string)
+{
+  char temp_buf[2048];
+  char tmp2[40];
+  int count;
+  int ndx = 0;
+  char *(*str_list)[];
+  char *end;
+  long i;
+
+  count = 1 + list->next_memrange + list->next_aexpr_elt + 1;
+  str_list = (char *(*)[]) xmalloc (count * sizeof (char *));
+
+  for (i = sizeof (list->regs_mask) - 1; i > 0; i--)
+    if (list->regs_mask[i] != 0)       /* skip leading zeroes in regs_mask */
+      break;
+  if (list->regs_mask[i] != 0) /* prepare to send regs_mask to the stub */
+    {
+      if (info_verbose)
+       printf_filtered ("\nCollecting registers (mask): 0x");
+      end = temp_buf;
+      *end++ = 'R';
+      for (; i >= 0; i--)
+       {
+         QUIT;                 /* allow user to bail out with ^C */
+         if (info_verbose)
+           printf_filtered ("%02X", list->regs_mask[i]);
+         sprintf (end, "%02X", list->regs_mask[i]);
+         end += 2;
+       }
+      (*str_list)[ndx] = savestring (temp_buf, end - temp_buf);
+      ndx++;
+    }
+  if (info_verbose)
+    printf_filtered ("\n");
+  if (list->next_memrange > 0 && info_verbose)
+    printf_filtered ("Collecting memranges: \n");
+  for (i = 0, count = 0, end = temp_buf; i < list->next_memrange; i++)
+    {
+      QUIT;                    /* allow user to bail out with ^C */
+      sprintf_vma (tmp2, list->list[i].start);
+      if (info_verbose)
+       {
+         printf_filtered ("(%d, %s, %ld)\n", 
+                          list->list[i].type, 
+                          tmp2, 
+                          (long) (list->list[i].end - list->list[i].start));
+       }
+      if (count + 27 > MAX_AGENT_EXPR_LEN)
+       {
+         (*str_list)[ndx] = savestring (temp_buf, count);
+         ndx++;
+         count = 0;
+         end = temp_buf;
+       }
+
+      sprintf (end, "M%X,%s,%lX", 
+              list->list[i].type,
+              tmp2,
+              (long) (list->list[i].end - list->list[i].start));
+
+      count += strlen (end);
+      end += count;
+    }
+
+  for (i = 0; i < list->next_aexpr_elt; i++)
+    {
+      QUIT;                    /* allow user to bail out with ^C */
+      if ((count + 10 + 2 * list->aexpr_list[i]->len) > MAX_AGENT_EXPR_LEN)
+       {
+         (*str_list)[ndx] = savestring (temp_buf, count);
+         ndx++;
+         count = 0;
+         end = temp_buf;
+       }
+      sprintf (end, "X%08X,", list->aexpr_list[i]->len);
+      end += 10;               /* 'X' + 8 hex digits + ',' */
+      count += 10;
+
+      end = mem2hex (list->aexpr_list[i]->buf, end, list->aexpr_list[i]->len);
+      count += 2 * list->aexpr_list[i]->len;
+    }
+
+  if (count != 0)
+    {
+      (*str_list)[ndx] = savestring (temp_buf, count);
+      ndx++;
+      count = 0;
+      end = temp_buf;
+    }
+  (*str_list)[ndx] = NULL;
+
+  if (ndx == 0)
+    return NULL;
+  else
+    return *str_list;
+}
+
+static void
+free_actions_list_cleanup_wrapper (void *al)
+{
+  free_actions_list (al);
+}
+
+static void
+free_actions_list (char **actions_list)
+{
+  int ndx;
+
+  if (actions_list == 0)
+    return;
+
+  for (ndx = 0; actions_list[ndx]; ndx++)
+    xfree (actions_list[ndx]);
+
+  xfree (actions_list);
+}
+
+/* render all actions into gdb protocol */
+static void
+encode_actions (struct tracepoint *t, char ***tdp_actions,
+               char ***stepping_actions)
+{
+  static char tdp_buff[2048], step_buff[2048];
+  char *action_exp;
+  struct expression *exp = NULL;
+  struct action_line *action;
+  int i;
+  struct value *tempval;
+  struct collection_list *collect;
+  struct cmd_list_element *cmd;
+  struct agent_expr *aexpr;
+  int frame_reg;
+  LONGEST frame_offset;
+
+
+  clear_collection_list (&tracepoint_list);
+  clear_collection_list (&stepping_list);
+  collect = &tracepoint_list;
+
+  *tdp_actions = NULL;
+  *stepping_actions = NULL;
+
+  TARGET_VIRTUAL_FRAME_POINTER (t->address, &frame_reg, &frame_offset);
+
+  for (action = t->actions; action; action = action->next)
+    {
+      QUIT;                    /* allow user to bail out with ^C */
+      action_exp = action->action;
+      while (isspace ((int) *action_exp))
+       action_exp++;
+
+      if (*action_exp == '#')  /* comment line */
+       return;
+
+      cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
+      if (cmd == 0)
+       error ("Bad action list item: %s", action_exp);
+
+      if (cmd_cfunc_eq (cmd, collect_pseudocommand))
+       {
+         do
+           {                   /* repeat over a comma-separated list */
+             QUIT;             /* allow user to bail out with ^C */
+             while (isspace ((int) *action_exp))
+               action_exp++;
+
+             if (0 == strncasecmp ("$reg", action_exp, 4))
+               {
+                 for (i = 0; i < NUM_REGS; i++)
+                   add_register (collect, i);
+                 action_exp = strchr (action_exp, ',');        /* more? */
+               }
+             else if (0 == strncasecmp ("$arg", action_exp, 4))
+               {
+                 add_local_symbols (collect,
+                                    t->address,
+                                    frame_reg,
+                                    frame_offset,
+                                    'A');
+                 action_exp = strchr (action_exp, ',');        /* more? */
+               }
+             else if (0 == strncasecmp ("$loc", action_exp, 4))
+               {
+                 add_local_symbols (collect,
+                                    t->address,
+                                    frame_reg,
+                                    frame_offset,
+                                    'L');
+                 action_exp = strchr (action_exp, ',');        /* more? */
+               }
+             else
+               {
+                 unsigned long addr, len;
+                 struct cleanup *old_chain = NULL;
+                 struct cleanup *old_chain1 = NULL;
+                 struct agent_reqs areqs;
+
+                 exp = parse_exp_1 (&action_exp, 
+                                    block_for_pc (t->address), 1);
+                 old_chain = make_cleanup (free_current_contents, &exp);
+
+                 switch (exp->elts[0].opcode)
+                   {
+                   case OP_REGISTER:
+                     i = exp->elts[1].longconst;
+                     if (info_verbose)
+                       printf_filtered ("OP_REGISTER: ");
+                     add_register (collect, i);
+                     break;
+
+                   case UNOP_MEMVAL:
+                     /* safe because we know it's a simple expression */
+                     tempval = evaluate_expression (exp);
+                     addr = VALUE_ADDRESS (tempval) + VALUE_OFFSET (tempval);
+                     len = TYPE_LENGTH (check_typedef (exp->elts[1].type));
+                     add_memrange (collect, -1, addr, len);
+                     break;
+
+                   case OP_VAR_VALUE:
+                     collect_symbol (collect,
+                                     exp->elts[2].symbol,
+                                     frame_reg,
+                                     frame_offset);
+                     break;
+
+                   default:    /* full-fledged expression */
+                     aexpr = gen_trace_for_expr (t->address, exp);
+
+                     old_chain1 = make_cleanup_free_agent_expr (aexpr);
+
+                     ax_reqs (aexpr, &areqs);
+                     if (areqs.flaw != agent_flaw_none)
+                       error ("malformed expression");
+
+                     if (areqs.min_height < 0)
+                       error ("gdb: Internal error: expression has min height < 0");
+                     if (areqs.max_height > 20)
+                       error ("expression too complicated, try simplifying");
+
+                     discard_cleanups (old_chain1);
+                     add_aexpr (collect, aexpr);
+
+                     /* take care of the registers */
+                     if (areqs.reg_mask_len > 0)
+                       {
+                         int ndx1;
+                         int ndx2;
+
+                         for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+                           {
+                             QUIT;     /* allow user to bail out with ^C */
+                             if (areqs.reg_mask[ndx1] != 0)
+                               {
+                                 /* assume chars have 8 bits */
+                                 for (ndx2 = 0; ndx2 < 8; ndx2++)
+                                   if (areqs.reg_mask[ndx1] & (1 << ndx2))
+                                     /* it's used -- record it */
+                                     add_register (collect, ndx1 * 8 + ndx2);
+                               }
+                           }
+                       }
+                     break;
+                   }           /* switch */
+                 do_cleanups (old_chain);
+               }               /* do */
+           }
+         while (action_exp && *action_exp++ == ',');
+       }                       /* if */
+      else if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+       {
+         collect = &stepping_list;
+       }
+      else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
+       {
+         if (collect == &stepping_list)        /* end stepping actions */
+           collect = &tracepoint_list;
+         else
+           break;              /* end tracepoint actions */
+       }
+    }                          /* for */
+  memrange_sortmerge (&tracepoint_list);
+  memrange_sortmerge (&stepping_list);
+
+  *tdp_actions = stringify_collection_list (&tracepoint_list, tdp_buff);
+  *stepping_actions = stringify_collection_list (&stepping_list, step_buff);
+}
+
+static void
+add_aexpr (struct collection_list *collect, struct agent_expr *aexpr)
+{
+  if (collect->next_aexpr_elt >= collect->aexpr_listsize)
+    {
+      collect->aexpr_list =
+       xrealloc (collect->aexpr_list,
+               2 * collect->aexpr_listsize * sizeof (struct agent_expr *));
+      collect->aexpr_listsize *= 2;
+    }
+  collect->aexpr_list[collect->next_aexpr_elt] = aexpr;
+  collect->next_aexpr_elt++;
+}
+
+static char target_buf[2048];
+
+/* Set "transparent" memory ranges
+
+   Allow trace mechanism to treat text-like sections
+   (and perhaps all read-only sections) transparently, 
+   i.e. don't reject memory requests from these address ranges
+   just because they haven't been collected.  */
+
+static void
+remote_set_transparent_ranges (void)
+{
+  extern bfd *exec_bfd;
+  asection *s;
+  bfd_size_type size;
+  bfd_vma lma;
+  int anysecs = 0;
+
+  if (!exec_bfd)
+    return;                    /* no information to give. */
+
+  strcpy (target_buf, "QTro");
+  for (s = exec_bfd->sections; s; s = s->next)
+    {
+      char tmp1[40], tmp2[40];
+
+      if ((s->flags & SEC_LOAD) == 0 ||
+      /* (s->flags & SEC_CODE)     == 0 || */
+         (s->flags & SEC_READONLY) == 0)
+       continue;
+
+      anysecs = 1;
+      lma = s->lma;
+      size = bfd_get_section_size_before_reloc (s);
+      sprintf_vma (tmp1, lma);
+      sprintf_vma (tmp2, lma + size);
+      sprintf (target_buf + strlen (target_buf), 
+              ":%s,%s", tmp1, tmp2);
+    }
+  if (anysecs)
+    {
+      putpkt (target_buf);
+      getpkt (target_buf, sizeof (target_buf), 0);
+    }
+}
+
+/* tstart command:
+
+   Tell target to clear any previous trace experiment.
+   Walk the list of tracepoints, and send them (and their actions)
+   to the target.  If no errors, 
+   Tell target to start a new trace experiment.  */
+
+static void
+trace_start_command (char *args, int from_tty)
+{                              /* STUB_COMM MOSTLY_IMPLEMENTED */
+  struct tracepoint *t;
+  char buf[2048];
+  char **tdp_actions;
+  char **stepping_actions;
+  int ndx;
+  struct cleanup *old_chain = NULL;
+
+  dont_repeat ();              /* like "run", dangerous to repeat accidentally */
+
+  if (target_is_remote ())
+    {
+      putpkt ("QTinit");
+      remote_get_noisy_reply (target_buf, sizeof (target_buf));
+      if (strcmp (target_buf, "OK"))
+       error ("Target does not support this command.");
+
+      ALL_TRACEPOINTS (t)
+      {
+       char tmp[40];
+
+       sprintf_vma (tmp, t->address);
+       sprintf (buf, "QTDP:%x:%s:%c:%lx:%x", t->number, tmp, /* address */
+                t->enabled_p ? 'E' : 'D',
+                t->step_count, t->pass_count);
+
+       if (t->actions)
+         strcat (buf, "-");
+       putpkt (buf);
+       remote_get_noisy_reply (target_buf, sizeof (target_buf));
+       if (strcmp (target_buf, "OK"))
+         error ("Target does not support tracepoints.");
+
+       if (t->actions)
+         {
+           encode_actions (t, &tdp_actions, &stepping_actions);
+           old_chain = make_cleanup (free_actions_list_cleanup_wrapper,
+                                     tdp_actions);
+           (void) make_cleanup (free_actions_list_cleanup_wrapper,
+                                stepping_actions);
+
+           /* do_single_steps (t); */
+           if (tdp_actions)
+             {
+               for (ndx = 0; tdp_actions[ndx]; ndx++)
+                 {
+                   QUIT;       /* allow user to bail out with ^C */
+                   sprintf (buf, "QTDP:-%x:%s:%s%c",
+                            t->number, tmp, /* address */
+                            tdp_actions[ndx],
+                            ((tdp_actions[ndx + 1] || stepping_actions)
+                             ? '-' : 0));
+                   putpkt (buf);
+                   remote_get_noisy_reply (target_buf, sizeof (target_buf));
+                   if (strcmp (target_buf, "OK"))
+                     error ("Error on target while setting tracepoints.");
+                 }
+             }
+           if (stepping_actions)
+             {
+               for (ndx = 0; stepping_actions[ndx]; ndx++)
+                 {
+                   QUIT;       /* allow user to bail out with ^C */
+                   sprintf (buf, "QTDP:-%x:%s:%s%s%s",
+                            t->number, tmp, /* address */
+                            ((ndx == 0) ? "S" : ""),
+                            stepping_actions[ndx],
+                            (stepping_actions[ndx + 1] ? "-" : ""));
+                   putpkt (buf);
+                   remote_get_noisy_reply (target_buf, sizeof (target_buf));
+                   if (strcmp (target_buf, "OK"))
+                     error ("Error on target while setting tracepoints.");
+                 }
+             }
+
+           do_cleanups (old_chain);
+         }
+      }
+      /* Tell target to treat text-like sections as transparent */
+      remote_set_transparent_ranges ();
+      /* Now insert traps and begin collecting data */
+      putpkt ("QTStart");
+      remote_get_noisy_reply (target_buf, sizeof (target_buf));
+      if (strcmp (target_buf, "OK"))
+       error ("Bogus reply from target: %s", target_buf);
+      set_traceframe_num (-1); /* all old traceframes invalidated */
+      set_tracepoint_num (-1);
+      set_traceframe_context (-1);
+      trace_running_p = 1;
+      if (trace_start_stop_hook)
+       trace_start_stop_hook (1, from_tty);
+
+    }
+  else
+    error ("Trace can only be run on remote targets.");
+}
+
+/* tstop command */
+static void
+trace_stop_command (char *args, int from_tty)
+{                              /* STUB_COMM IS_IMPLEMENTED */
+  if (target_is_remote ())
+    {
+      putpkt ("QTStop");
+      remote_get_noisy_reply (target_buf, sizeof (target_buf));
+      if (strcmp (target_buf, "OK"))
+       error ("Bogus reply from target: %s", target_buf);
+      trace_running_p = 0;
+      if (trace_start_stop_hook)
+       trace_start_stop_hook (0, from_tty);
+    }
+  else
+    error ("Trace can only be run on remote targets.");
+}
+
+unsigned long trace_running_p;
+
+/* tstatus command */
+static void
+trace_status_command (char *args, int from_tty)
+{                              /* STUB_COMM IS_IMPLEMENTED */
+  if (target_is_remote ())
+    {
+      putpkt ("qTStatus");
+      remote_get_noisy_reply (target_buf, sizeof (target_buf));
+
+      if (target_buf[0] != 'T' ||
+         (target_buf[1] != '0' && target_buf[1] != '1'))
+       error ("Bogus reply from target: %s", target_buf);
+
+      /* exported for use by the GUI */
+      trace_running_p = (target_buf[1] == '1');
+    }
+  else
+    error ("Trace can only be run on remote targets.");
+}
+
+/* Worker function for the various flavors of the tfind command */
+static void
+finish_tfind_command (char *msg,
+                     long sizeof_msg,
+                     int from_tty)
+{
+  int target_frameno = -1, target_tracept = -1;
+  CORE_ADDR old_frame_addr;
+  struct symbol *old_func;
+  char *reply;
+
+  old_frame_addr = FRAME_FP (get_current_frame ());
+  old_func = find_pc_function (read_pc ());
+
+  putpkt (msg);
+  reply = remote_get_noisy_reply (msg, sizeof_msg);
+
+  while (reply && *reply)
+    switch (*reply)
+      {
+      case 'F':
+       if ((target_frameno = (int) strtol (++reply, &reply, 16)) == -1)
+         {
+           /* A request for a non-existant trace frame has failed.
+              Our response will be different, depending on FROM_TTY:
+
+              If FROM_TTY is true, meaning that this command was 
+              typed interactively by the user, then give an error
+              and DO NOT change the state of traceframe_number etc.
+
+              However if FROM_TTY is false, meaning that we're either
+              in a script, a loop, or a user-defined command, then 
+              DON'T give an error, but DO change the state of
+              traceframe_number etc. to invalid.
+
+              The rationalle is that if you typed the command, you
+              might just have committed a typo or something, and you'd
+              like to NOT lose your current debugging state.  However
+              if you're in a user-defined command or especially in a
+              loop, then you need a way to detect that the command
+              failed WITHOUT aborting.  This allows you to write
+              scripts that search thru the trace buffer until the end,
+              and then continue on to do something else.  */
+
+           if (from_tty)
+             error ("Target failed to find requested trace frame.");
+           else
+             {
+               if (info_verbose)
+                 printf_filtered ("End of trace buffer.\n");
+               /* The following will not recurse, since it's special-cased */
+               trace_find_command ("-1", from_tty);
+               reply = NULL;   /* break out of loop, 
+                                  (avoid recursive nonsense) */
+             }
+         }
+       break;
+      case 'T':
+       if ((target_tracept = (int) strtol (++reply, &reply, 16)) == -1)
+         error ("Target failed to find requested trace frame.");
+       break;
+      case 'O':                /* "OK"? */
+       if (reply[1] == 'K' && reply[2] == '\0')
+         reply += 2;
+       else
+         error ("Bogus reply from target: %s", reply);
+       break;
+      default:
+       error ("Bogus reply from target: %s", reply);
+      }
+
+  flush_cached_frames ();
+  registers_changed ();
+  select_frame (get_current_frame ());
+  set_traceframe_num (target_frameno);
+  set_tracepoint_num (target_tracept);
+  if (target_frameno == -1)
+    set_traceframe_context (-1);
+  else
+    set_traceframe_context (read_pc ());
+
+  if (from_tty)
+    {
+      int source_only;
+
+      /* NOTE: in immitation of the step command, try to determine
+         whether we have made a transition from one function to another.
+         If so, we'll print the "stack frame" (ie. the new function and
+         it's arguments) -- otherwise we'll just show the new source line.
+
+         This determination is made by checking (1) whether the current
+         function has changed, and (2) whether the current FP has changed.
+         Hack: if the FP wasn't collected, either at the current or the
+         previous frame, assume that the FP has NOT changed.  */
+
+      if (old_func == find_pc_function (read_pc ()) &&
+         (old_frame_addr == 0 ||
+          FRAME_FP (get_current_frame ()) == 0 ||
+          old_frame_addr == FRAME_FP (get_current_frame ())))
+       source_only = -1;
+      else
+       source_only = 1;
+
+      print_stack_frame (selected_frame, frame_relative_level (selected_frame),
+                        source_only);
+      do_displays ();
+    }
+}
+
+/* trace_find_command takes a trace frame number n, 
+   sends "QTFrame:<n>" to the target, 
+   and accepts a reply that may contain several optional pieces
+   of information: a frame number, a tracepoint number, and an
+   indication of whether this is a trap frame or a stepping frame.
+
+   The minimal response is just "OK" (which indicates that the 
+   target does not give us a frame number or a tracepoint number).
+   Instead of that, the target may send us a string containing
+   any combination of:
+   F<hexnum>    (gives the selected frame number)
+   T<hexnum>    (gives the selected tracepoint number)
+ */
+
+/* tfind command */
+static void
+trace_find_command (char *args, int from_tty)
+{                              /* STUB_COMM PART_IMPLEMENTED */
+  /* this should only be called with a numeric argument */
+  int frameno = -1;
+
+  if (target_is_remote ())
+    {
+      if (trace_find_hook)
+       trace_find_hook (args, from_tty);
+
+      if (args == 0 || *args == 0)
+       {                       /* TFIND with no args means find NEXT trace frame. */
+         if (traceframe_number == -1)
+           frameno = 0;        /* "next" is first one */
+         else
+           frameno = traceframe_number + 1;
+       }
+      else if (0 == strcmp (args, "-"))
+       {
+         if (traceframe_number == -1)
+           error ("not debugging trace buffer");
+         else if (from_tty && traceframe_number == 0)
+           error ("already at start of trace buffer");
+
+         frameno = traceframe_number - 1;
+       }
+      else
+       frameno = parse_and_eval_long (args);
+
+      if (frameno < -1)
+       error ("invalid input (%d is less than zero)", frameno);
+
+      sprintf (target_buf, "QTFrame:%x", frameno);
+      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+    }
+  else
+    error ("Trace can only be run on remote targets.");
+}
+
+/* tfind end */
+static void
+trace_find_end_command (char *args, int from_tty)
+{
+  trace_find_command ("-1", from_tty);
+}
+
+/* tfind none */
+static void
+trace_find_none_command (char *args, int from_tty)
+{
+  trace_find_command ("-1", from_tty);
+}
+
+/* tfind start */
+static void
+trace_find_start_command (char *args, int from_tty)
+{
+  trace_find_command ("0", from_tty);
+}
+
+/* tfind pc command */
+static void
+trace_find_pc_command (char *args, int from_tty)
+{                              /* STUB_COMM PART_IMPLEMENTED */
+  CORE_ADDR pc;
+  char tmp[40];
+
+  if (target_is_remote ())
+    {
+      if (args == 0 || *args == 0)
+       pc = read_pc ();        /* default is current pc */
+      else
+       pc = parse_and_eval_address (args);
+
+      sprintf_vma (tmp, pc);
+      sprintf (target_buf, "QTFrame:pc:%s", tmp);
+      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+    }
+  else
+    error ("Trace can only be run on remote targets.");
+}
+
+/* tfind tracepoint command */
+static void
+trace_find_tracepoint_command (char *args, int from_tty)
+{                              /* STUB_COMM PART_IMPLEMENTED */
+  int tdp;
+
+  if (target_is_remote ())
+    {
+      if (args == 0 || *args == 0)
+       {
+         if (tracepoint_number == -1)
+           error ("No current tracepoint -- please supply an argument.");
+         else
+           tdp = tracepoint_number;    /* default is current TDP */
+       }
+      else
+       tdp = parse_and_eval_long (args);
+
+      sprintf (target_buf, "QTFrame:tdp:%x", tdp);
+      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+    }
+  else
+    error ("Trace can only be run on remote targets.");
+}
+
+/* TFIND LINE command:
+
+   This command will take a sourceline for argument, just like BREAK
+   or TRACE (ie. anything that "decode_line_1" can handle).  
+
+   With no argument, this command will find the next trace frame 
+   corresponding to a source line OTHER THAN THE CURRENT ONE.  */
+
+static void
+trace_find_line_command (char *args, int from_tty)
+{                              /* STUB_COMM PART_IMPLEMENTED */
+  static CORE_ADDR start_pc, end_pc;
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  struct cleanup *old_chain;
+  char   startpc_str[40], endpc_str[40];
+
+  if (target_is_remote ())
+    {
+      if (args == 0 || *args == 0)
+       {
+         sal = find_pc_line ((get_current_frame ())->pc, 0);
+         sals.nelts = 1;
+         sals.sals = (struct symtab_and_line *)
+           xmalloc (sizeof (struct symtab_and_line));
+         sals.sals[0] = sal;
+       }
+      else
+       {
+         sals = decode_line_spec (args, 1);
+         sal = sals.sals[0];
+       }
+
+      old_chain = make_cleanup (xfree, sals.sals);
+      if (sal.symtab == 0)
+       {
+         printf_filtered ("TFIND: No line number information available");
+         if (sal.pc != 0)
+           {
+             /* This is useful for "info line *0x7f34".  If we can't tell the
+                user about a source line, at least let them have the symbolic
+                address.  */
+             printf_filtered (" for address ");
+             wrap_here ("  ");
+             print_address (sal.pc, gdb_stdout);
+             printf_filtered (";\n -- will attempt to find by PC. \n");
+           }
+         else
+           {
+             printf_filtered (".\n");
+             return;           /* no line, no PC; what can we do? */
+           }
+       }
+      else if (sal.line > 0
+              && find_line_pc_range (sal, &start_pc, &end_pc))
+       {
+         if (start_pc == end_pc)
+           {
+             printf_filtered ("Line %d of \"%s\"",
+                              sal.line, sal.symtab->filename);
+             wrap_here ("  ");
+             printf_filtered (" is at address ");
+             print_address (start_pc, gdb_stdout);
+             wrap_here ("  ");
+             printf_filtered (" but contains no code.\n");
+             sal = find_pc_line (start_pc, 0);
+             if (sal.line > 0 &&
+                 find_line_pc_range (sal, &start_pc, &end_pc) &&
+                 start_pc != end_pc)
+               printf_filtered ("Attempting to find line %d instead.\n",
+                                sal.line);
+             else
+               error ("Cannot find a good line.");
+           }
+       }
+      else
+       /* Is there any case in which we get here, and have an address
+          which the user would want to see?  If we have debugging symbols
+          and no line numbers?  */
+       error ("Line number %d is out of range for \"%s\".\n",
+              sal.line, sal.symtab->filename);
+
+      sprintf_vma (startpc_str, start_pc);
+      sprintf_vma (endpc_str, end_pc - 1);
+      if (args && *args)       /* find within range of stated line */
+       sprintf (target_buf, "QTFrame:range:%s:%s", startpc_str, endpc_str);
+      else                     /* find OUTSIDE OF range of CURRENT line */
+       sprintf (target_buf, "QTFrame:outside:%s:%s", startpc_str, endpc_str);
+      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+      do_cleanups (old_chain);
+    }
+  else
+    error ("Trace can only be run on remote targets.");
+}
+
+/* tfind range command */
+static void
+trace_find_range_command (char *args, int from_tty)
+{
+  static CORE_ADDR start, stop;
+  char start_str[40], stop_str[40];
+  char *tmp;
+
+  if (target_is_remote ())
+    {
+      if (args == 0 || *args == 0)
+       {               /* XXX FIXME: what should default behavior be? */
+         printf_filtered ("Usage: tfind range <startaddr>,<endaddr>\n");
+         return;
+       }
+
+      if (0 != (tmp = strchr (args, ',')))
+       {
+         *tmp++ = '\0';        /* terminate start address */
+         while (isspace ((int) *tmp))
+           tmp++;
+         start = parse_and_eval_address (args);
+         stop = parse_and_eval_address (tmp);
+       }
+      else
+       {                       /* no explicit end address? */
+         start = parse_and_eval_address (args);
+         stop = start + 1;     /* ??? */
+       }
+
+      sprintf_vma (start_str, start);
+      sprintf_vma (stop_str, stop);
+      sprintf (target_buf, "QTFrame:range:%s:%s", start_str, stop_str);
+      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+    }
+  else
+    error ("Trace can only be run on remote targets.");
+}
+
+/* tfind outside command */
+static void
+trace_find_outside_command (char *args, int from_tty)
+{
+  CORE_ADDR start, stop;
+  char start_str[40], stop_str[40];
+  char *tmp;
+
+  if (target_is_remote ())
+    {
+      if (args == 0 || *args == 0)
+       {               /* XXX FIXME: what should default behavior be? */
+         printf_filtered ("Usage: tfind outside <startaddr>,<endaddr>\n");
+         return;
+       }
+
+      if (0 != (tmp = strchr (args, ',')))
+       {
+         *tmp++ = '\0';        /* terminate start address */
+         while (isspace ((int) *tmp))
+           tmp++;
+         start = parse_and_eval_address (args);
+         stop = parse_and_eval_address (tmp);
+       }
+      else
+       {                       /* no explicit end address? */
+         start = parse_and_eval_address (args);
+         stop = start + 1;     /* ??? */
+       }
+
+      sprintf_vma (start_str, start);
+      sprintf_vma (stop_str, stop);
+      sprintf (target_buf, "QTFrame:outside:%s:%s", start_str, stop_str);
+      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
+    }
+  else
+    error ("Trace can only be run on remote targets.");
+}
+
+/* save-tracepoints command */
+static void
+tracepoint_save_command (char *args, int from_tty)
+{
+  struct tracepoint *tp;
+  struct action_line *line;
+  FILE *fp;
+  char *i1 = "    ", *i2 = "      ";
+  char *indent, *actionline, *pathname;
+  char tmp[40];
+
+  if (args == 0 || *args == 0)
+    error ("Argument required (file name in which to save tracepoints");
+
+  if (tracepoint_chain == 0)
+    {
+      warning ("save-tracepoints: no tracepoints to save.\n");
+      return;
+    }
+
+  pathname = tilde_expand (args);
+  if (!(fp = fopen (pathname, "w")))
+    error ("Unable to open file '%s' for saving tracepoints (%s)",
+          args, safe_strerror (errno));
+  xfree (pathname);
+  
+  ALL_TRACEPOINTS (tp)
+  {
+    if (tp->addr_string)
+      fprintf (fp, "trace %s\n", tp->addr_string);
+    else
+      {
+       sprintf_vma (tmp, tp->address);
+       fprintf (fp, "trace *0x%s\n", tmp);
+      }
+
+    if (tp->pass_count)
+      fprintf (fp, "  passcount %d\n", tp->pass_count);
+
+    if (tp->actions)
+      {
+       fprintf (fp, "  actions\n");
+       indent = i1;
+       for (line = tp->actions; line; line = line->next)
+         {
+           struct cmd_list_element *cmd;
+
+           QUIT;               /* allow user to bail out with ^C */
+           actionline = line->action;
+           while (isspace ((int) *actionline))
+             actionline++;
+
+           fprintf (fp, "%s%s\n", indent, actionline);
+           if (*actionline != '#')     /* skip for comment lines */
+             {
+               cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
+               if (cmd == 0)
+                 error ("Bad action list item: %s", actionline);
+               if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+                 indent = i2;
+               else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
+                 indent = i1;
+             }
+         }
+      }
+  }
+  fclose (fp);
+  if (from_tty)
+    printf_filtered ("Tracepoints saved to file '%s'.\n", args);
+  return;
+}
+
+/* info scope command: list the locals for a scope.  */
+static void
+scope_info (char *args, int from_tty)
+{
+  struct symtabs_and_lines sals;
+  struct symbol *sym;
+  struct minimal_symbol *msym;
+  struct block *block;
+  char **canonical, *symname, *save_args = args;
+  int i, j, count = 0;
+
+  if (args == 0 || *args == 0)
+    error ("requires an argument (function, line or *addr) to define a scope");
+
+  sals = decode_line_1 (&args, 1, NULL, 0, &canonical);
+  if (sals.nelts == 0)
+    return;                    /* presumably decode_line_1 has already warned */
+
+  /* Resolve line numbers to PC */
+  resolve_sal_pc (&sals.sals[0]);
+  block = block_for_pc (sals.sals[0].pc);
+
+  while (block != 0)
+    {
+      QUIT;                    /* allow user to bail out with ^C */
+      ALL_BLOCK_SYMBOLS (block, i, sym)
+       {
+         QUIT;                 /* allow user to bail out with ^C */
+         if (count == 0)
+           printf_filtered ("Scope for %s:\n", save_args);
+         count++;
+
+         symname = SYMBOL_NAME (sym);
+         if (symname == NULL || *symname == '\0')
+           continue;           /* probably botched, certainly useless */
+
+         printf_filtered ("Symbol %s is ", symname);
+         switch (SYMBOL_CLASS (sym))
+           {
+           default:
+           case LOC_UNDEF:     /* messed up symbol? */
+             printf_filtered ("a bogus symbol, class %d.\n",
+                              SYMBOL_CLASS (sym));
+             count--;          /* don't count this one */
+             continue;
+           case LOC_CONST:
+             printf_filtered ("a constant with value %ld (0x%lx)",
+                              SYMBOL_VALUE (sym), SYMBOL_VALUE (sym));
+             break;
+           case LOC_CONST_BYTES:
+             printf_filtered ("constant bytes: ");
+             if (SYMBOL_TYPE (sym))
+               for (j = 0; j < TYPE_LENGTH (SYMBOL_TYPE (sym)); j++)
+                 fprintf_filtered (gdb_stdout, " %02x",
+                                   (unsigned) SYMBOL_VALUE_BYTES (sym)[j]);
+             break;
+           case LOC_STATIC:
+             printf_filtered ("in static storage at address ");
+             print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
+             break;
+           case LOC_REGISTER:
+             printf_filtered ("a local variable in register $%s",
+                              REGISTER_NAME (SYMBOL_VALUE (sym)));
+             break;
+           case LOC_ARG:
+           case LOC_LOCAL_ARG:
+             printf_filtered ("an argument at stack/frame offset %ld",
+                              SYMBOL_VALUE (sym));
+             break;
+           case LOC_LOCAL:
+             printf_filtered ("a local variable at frame offset %ld",
+                              SYMBOL_VALUE (sym));
+             break;
+           case LOC_REF_ARG:
+             printf_filtered ("a reference argument at offset %ld",
+                              SYMBOL_VALUE (sym));
+             break;
+           case LOC_REGPARM:
+             printf_filtered ("an argument in register $%s",
+                              REGISTER_NAME (SYMBOL_VALUE (sym)));
+             break;
+           case LOC_REGPARM_ADDR:
+             printf_filtered ("the address of an argument, in register $%s",
+                              REGISTER_NAME (SYMBOL_VALUE (sym)));
+             break;
+           case LOC_TYPEDEF:
+             printf_filtered ("a typedef.\n");
+             continue;
+           case LOC_LABEL:
+             printf_filtered ("a label at address ");
+             print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
+             break;
+           case LOC_BLOCK:
+             printf_filtered ("a function at address ");
+             print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)), 1,
+                                    gdb_stdout);
+             break;
+           case LOC_BASEREG:
+             printf_filtered ("a variable at offset %ld from register $%s",
+                              SYMBOL_VALUE (sym),
+                              REGISTER_NAME (SYMBOL_BASEREG (sym)));
+             break;
+           case LOC_BASEREG_ARG:
+             printf_filtered ("an argument at offset %ld from register $%s",
+                              SYMBOL_VALUE (sym),
+                              REGISTER_NAME (SYMBOL_BASEREG (sym)));
+             break;
+           case LOC_UNRESOLVED:
+             msym = lookup_minimal_symbol (SYMBOL_NAME (sym), NULL, NULL);
+             if (msym == NULL)
+               printf_filtered ("Unresolved Static");
+             else
+               {
+                 printf_filtered ("static storage at address ");
+                 print_address_numeric (SYMBOL_VALUE_ADDRESS (msym), 1,
+                                        gdb_stdout);
+               }
+             break;
+           case LOC_OPTIMIZED_OUT:
+             printf_filtered ("optimized out.\n");
+             continue;
+           }
+         if (SYMBOL_TYPE (sym))
+           printf_filtered (", length %d.\n",
+                          TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym))));
+       }
+      if (BLOCK_FUNCTION (block))
+       break;
+      else
+       block = BLOCK_SUPERBLOCK (block);
+    }
+  if (count <= 0)
+    printf_filtered ("Scope for %s contains no locals or arguments.\n",
+                    save_args);
+}
+
+/* worker function (cleanup) */
+static void
+replace_comma (void *data)
+{
+  char *comma = data;
+  *comma = ',';
+}
+
+/* tdump command */
+static void
+trace_dump_command (char *args, int from_tty)
+{
+  struct tracepoint *t;
+  struct action_line *action;
+  char *action_exp, *next_comma;
+  struct cleanup *old_cleanups;
+  int stepping_actions = 0;
+  int stepping_frame = 0;
+
+  if (!target_is_remote ())
+    {
+      error ("Trace can only be run on remote targets.");
+      return;
+    }
+
+  if (tracepoint_number == -1)
+    {
+      warning ("No current trace frame.");
+      return;
+    }
+
+  ALL_TRACEPOINTS (t)
+    if (t->number == tracepoint_number)
+    break;
+
+  if (t == NULL)
+    error ("No known tracepoint matches 'current' tracepoint #%d.",
+          tracepoint_number);
+
+  old_cleanups = make_cleanup (null_cleanup, NULL);
+
+  printf_filtered ("Data collected at tracepoint %d, trace frame %d:\n",
+                  tracepoint_number, traceframe_number);
+
+  /* The current frame is a trap frame if the frame PC is equal
+     to the tracepoint PC.  If not, then the current frame was
+     collected during single-stepping.  */
+
+  stepping_frame = (t->address != read_pc ());
+
+  for (action = t->actions; action; action = action->next)
+    {
+      struct cmd_list_element *cmd;
+
+      QUIT;                    /* allow user to bail out with ^C */
+      action_exp = action->action;
+      while (isspace ((int) *action_exp))
+       action_exp++;
+
+      /* The collection actions to be done while stepping are
+         bracketed by the commands "while-stepping" and "end".  */
+
+      if (*action_exp == '#')  /* comment line */
+       continue;
+
+      cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
+      if (cmd == 0)
+       error ("Bad action list item: %s", action_exp);
+
+      if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+       stepping_actions = 1;
+      else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
+       stepping_actions = 0;
+      else if (cmd_cfunc_eq (cmd, collect_pseudocommand))
+       {
+         /* Display the collected data.
+            For the trap frame, display only what was collected at the trap.
+            Likewise for stepping frames, display only what was collected
+            while stepping.  This means that the two boolean variables,
+            STEPPING_FRAME and STEPPING_ACTIONS should be equal.  */
+         if (stepping_frame == stepping_actions)
+           {
+             do
+               {               /* repeat over a comma-separated list */
+                 QUIT;         /* allow user to bail out with ^C */
+                 if (*action_exp == ',')
+                   action_exp++;
+                 while (isspace ((int) *action_exp))
+                   action_exp++;
+
+                 next_comma = strchr (action_exp, ',');
+
+                 if (0 == strncasecmp (action_exp, "$reg", 4))
+                   registers_info (NULL, from_tty);
+                 else if (0 == strncasecmp (action_exp, "$loc", 4))
+                   locals_info (NULL, from_tty);
+                 else if (0 == strncasecmp (action_exp, "$arg", 4))
+                   args_info (NULL, from_tty);
+                 else
+                   {           /* variable */
+                     if (next_comma)
+                       {
+                         make_cleanup (replace_comma, next_comma);
+                         *next_comma = '\0';
+                       }
+                     printf_filtered ("%s = ", action_exp);
+                     output_command (action_exp, from_tty);
+                     printf_filtered ("\n");
+                   }
+                 if (next_comma)
+                   *next_comma = ',';
+                 action_exp = next_comma;
+               }
+             while (action_exp && *action_exp == ',');
+           }
+       }
+    }
+  discard_cleanups (old_cleanups);
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null)
+ * "stolen" from sparc-stub.c
+ */
+
+static const char hexchars[] = "0123456789abcdef";
+
+static unsigned char *
+mem2hex (unsigned char *mem, unsigned char *buf, int count)
+{
+  unsigned char ch;
+
+  while (count-- > 0)
+    {
+      ch = *mem++;
+
+      *buf++ = hexchars[ch >> 4];
+      *buf++ = hexchars[ch & 0xf];
+    }
+
+  *buf = 0;
+
+  return buf;
+}
+
+int
+get_traceframe_number (void)
+{
+  return traceframe_number;
+}
+
+
+/* module initialization */
+void
+_initialize_tracepoint (void)
+{
+  struct cmd_list_element *c;
+
+  tracepoint_chain = 0;
+  tracepoint_count = 0;
+  traceframe_number = -1;
+  tracepoint_number = -1;
+
+  set_internalvar (lookup_internalvar ("tpnum"),
+                  value_from_longest (builtin_type_int, (LONGEST) 0));
+  set_internalvar (lookup_internalvar ("trace_frame"),
+                  value_from_longest (builtin_type_int, (LONGEST) - 1));
+
+  if (tracepoint_list.list == NULL)
+    {
+      tracepoint_list.listsize = 128;
+      tracepoint_list.list = xmalloc
+       (tracepoint_list.listsize * sizeof (struct memrange));
+    }
+  if (tracepoint_list.aexpr_list == NULL)
+    {
+      tracepoint_list.aexpr_listsize = 128;
+      tracepoint_list.aexpr_list = xmalloc
+       (tracepoint_list.aexpr_listsize * sizeof (struct agent_expr *));
+    }
+
+  if (stepping_list.list == NULL)
+    {
+      stepping_list.listsize = 128;
+      stepping_list.list = xmalloc
+       (stepping_list.listsize * sizeof (struct memrange));
+    }
+
+  if (stepping_list.aexpr_list == NULL)
+    {
+      stepping_list.aexpr_listsize = 128;
+      stepping_list.aexpr_list = xmalloc
+       (stepping_list.aexpr_listsize * sizeof (struct agent_expr *));
+    }
+
+  add_info ("scope", scope_info,
+           "List the variables local to a scope");
+
+  add_cmd ("tracepoints", class_trace, NULL,
+          "Tracing of program execution without stopping the program.",
+          &cmdlist);
+
+  add_info ("tracepoints", tracepoints_info,
+           "Status of tracepoints, or tracepoint number NUMBER.\n\
+Convenience variable \"$tpnum\" contains the number of the\n\
+last tracepoint set.");
+
+  add_info_alias ("tp", "tracepoints", 1);
+
+  c = add_com ("save-tracepoints", class_trace, tracepoint_save_command,
+              "Save current tracepoint definitions as a script.\n\
+Use the 'source' command in another debug session to restore them.");
+  set_cmd_completer (c, filename_completer);
+
+  add_com ("tdump", class_trace, trace_dump_command,
+          "Print everything collected at the current tracepoint.");
+
+  add_prefix_cmd ("tfind", class_trace, trace_find_command,
+                 "Select a trace frame;\n\
+No argument means forward by one frame; '-' meand backward by one frame.",
+                 &tfindlist, "tfind ", 1, &cmdlist);
+
+  add_cmd ("outside", class_trace, trace_find_outside_command,
+          "Select a trace frame whose PC is outside the given \
+range.\nUsage: tfind outside addr1, addr2",
+          &tfindlist);
+
+  add_cmd ("range", class_trace, trace_find_range_command,
+          "Select a trace frame whose PC is in the given range.\n\
+Usage: tfind range addr1,addr2",
+          &tfindlist);
+
+  add_cmd ("line", class_trace, trace_find_line_command,
+          "Select a trace frame by source line.\n\
+Argument can be a line number (with optional source file), \n\
+a function name, or '*' followed by an address.\n\
+Default argument is 'the next source line that was traced'.",
+          &tfindlist);
+
+  add_cmd ("tracepoint", class_trace, trace_find_tracepoint_command,
+          "Select a trace frame by tracepoint number.\n\
+Default is the tracepoint for the current trace frame.",
+          &tfindlist);
+
+  add_cmd ("pc", class_trace, trace_find_pc_command,
+          "Select a trace frame by PC.\n\
+Default is the current PC, or the PC of the current trace frame.",
+          &tfindlist);
+
+  add_cmd ("end", class_trace, trace_find_end_command,
+          "Synonym for 'none'.\n\
+De-select any trace frame and resume 'live' debugging.",
+          &tfindlist);
+
+  add_cmd ("none", class_trace, trace_find_none_command,
+          "De-select any trace frame and resume 'live' debugging.",
+          &tfindlist);
+
+  add_cmd ("start", class_trace, trace_find_start_command,
+          "Select the first trace frame in the trace buffer.",
+          &tfindlist);
+
+  add_com ("tstatus", class_trace, trace_status_command,
+          "Display the status of the current trace data collection.");
+
+  add_com ("tstop", class_trace, trace_stop_command,
+          "Stop trace data collection.");
+
+  add_com ("tstart", class_trace, trace_start_command,
+          "Start trace data collection.");
+
+  add_com ("passcount", class_trace, trace_pass_command,
+          "Set the passcount for a tracepoint.\n\
+The trace will end when the tracepoint has been passed 'count' times.\n\
+Usage: passcount COUNT TPNUM, where TPNUM may also be \"all\";\n\
+if TPNUM is omitted, passcount refers to the last tracepoint defined.");
+
+  add_com ("end", class_trace, end_actions_pseudocommand,
+          "Ends a list of commands or actions.\n\
+Several GDB commands allow you to enter a list of commands or actions.\n\
+Entering \"end\" on a line by itself is the normal way to terminate\n\
+such a list.\n\n\
+Note: the \"end\" command cannot be used at the gdb prompt.");
+
+  add_com ("while-stepping", class_trace, while_stepping_pseudocommand,
+          "Specify single-stepping behavior at a tracepoint.\n\
+Argument is number of instructions to trace in single-step mode\n\
+following the tracepoint.  This command is normally followed by\n\
+one or more \"collect\" commands, to specify what to collect\n\
+while single-stepping.\n\n\
+Note: this command can only be used in a tracepoint \"actions\" list.");
+
+  add_com_alias ("ws", "while-stepping", class_alias, 0);
+  add_com_alias ("stepping", "while-stepping", class_alias, 0);
+
+  add_com ("collect", class_trace, collect_pseudocommand,
+          "Specify one or more data items to be collected at a tracepoint.\n\
+Accepts a comma-separated list of (one or more) expressions.  GDB will\n\
+collect all data (variables, registers) referenced by that expression.\n\
+Also accepts the following special arguments:\n\
+    $regs   -- all registers.\n\
+    $args   -- all function arguments.\n\
+    $locals -- all variables local to the block/function scope.\n\
+Note: this command can only be used in a tracepoint \"actions\" list.");
+
+  add_com ("actions", class_trace, trace_actions_command,
+          "Specify the actions to be taken at a tracepoint.\n\
+Tracepoint actions may include collecting of specified data, \n\
+single-stepping, or enabling/disabling other tracepoints, \n\
+depending on target's capabilities.");
+
+  add_cmd ("tracepoints", class_trace, delete_trace_command,
+          "Delete specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means delete all tracepoints.",
+          &deletelist);
+
+  add_cmd ("tracepoints", class_trace, disable_trace_command,
+          "Disable specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means disable all tracepoints.",
+          &disablelist);
+
+  add_cmd ("tracepoints", class_trace, enable_trace_command,
+          "Enable specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means enable all tracepoints.",
+          &enablelist);
+
+  c = add_com ("trace", class_trace, trace_command,
+              "Set a tracepoint at a specified line or function or address.\n\
+Argument may be a line number, function name, or '*' plus an address.\n\
+For a line number or function, trace at the start of its code.\n\
+If an address is specified, trace at that exact address.\n\n\
+Do \"help tracepoints\" for info on other tracepoint commands.");
+  set_cmd_completer (c, location_completer);
+
+  add_com_alias ("tp", "trace", class_alias, 0);
+  add_com_alias ("tr", "trace", class_alias, 1);
+  add_com_alias ("tra", "trace", class_alias, 1);
+  add_com_alias ("trac", "trace", class_alias, 1);
+}
diff --git a/gdb/valops.c b/gdb/valops.c
new file mode 100644 (file)
index 0000000..eaf4295
--- /dev/null
@@ -0,0 +1,3536 @@
+/* Perform non-arithmetic operations on values, for GDB.
+   Copyright 1986, 1987, 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.
+
+   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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "demangle.h"
+#include "language.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "cp-abi.h"
+
+#include <errno.h>
+#include "gdb_string.h"
+#include "gdb_assert.h"
+
+/* Flag indicating HP compilers were used; needed to correctly handle some
+   value operations with HP aCC code/runtime. */
+extern int hp_som_som_object_present;
+
+extern int overload_debug;
+/* Local functions.  */
+
+static int typecmp (int staticp, int varargs, int nargs,
+                   struct field t1[], struct value *t2[]);
+
+static CORE_ADDR find_function_addr (struct value *, struct type **);
+static struct value *value_arg_coerce (struct value *, struct type *, int);
+
+
+static CORE_ADDR value_push (CORE_ADDR, struct value *);
+
+static struct value *search_struct_field (char *, struct value *, int,
+                                     struct type *, int);
+
+static struct value *search_struct_method (char *, struct value **,
+                                      struct value **,
+                                      int, int *, struct type *);
+
+static int check_field_in (struct type *, const char *);
+
+static CORE_ADDR allocate_space_in_inferior (int);
+
+static struct value *cast_into_complex (struct type *, struct value *);
+
+static struct fn_field *find_method_list (struct value ** argp, char *method,
+                                         int offset,
+                                         struct type *type, int *num_fns,
+                                         struct type **basetype,
+                                         int *boffset);
+
+void _initialize_valops (void);
+
+/* Flag for whether we want to abandon failed expression evals by default.  */
+
+#if 0
+static int auto_abandon = 0;
+#endif
+
+int overload_resolution = 0;
+
+/* This boolean tells what gdb should do if a signal is received while in
+   a function called from gdb (call dummy).  If set, gdb unwinds the stack
+   and restore the context to what as it was before the call.
+   The default is to stop in the frame where the signal was received. */
+
+int unwind_on_signal_p = 0;
+\f
+
+
+/* Find the address of function name NAME in the inferior.  */
+
+struct value *
+find_function_in_inferior (const char *name)
+{
+  register struct symbol *sym;
+  sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0, NULL);
+  if (sym != NULL)
+    {
+      if (SYMBOL_CLASS (sym) != LOC_BLOCK)
+       {
+         error ("\"%s\" exists in this program but is not a function.",
+                name);
+       }
+      return value_of_variable (sym, NULL);
+    }
+  else
+    {
+      struct minimal_symbol *msymbol = lookup_minimal_symbol (name, NULL, NULL);
+      if (msymbol != NULL)
+       {
+         struct type *type;
+         CORE_ADDR maddr;
+         type = lookup_pointer_type (builtin_type_char);
+         type = lookup_function_type (type);
+         type = lookup_pointer_type (type);
+         maddr = SYMBOL_VALUE_ADDRESS (msymbol);
+         return value_from_pointer (type, maddr);
+       }
+      else
+       {
+         if (!target_has_execution)
+           error ("evaluation of this expression requires the target program to be active");
+         else
+           error ("evaluation of this expression requires the program to have a function \"%s\".", name);
+       }
+    }
+}
+
+/* Allocate NBYTES of space in the inferior using the inferior's malloc
+   and return a value that is a pointer to the allocated space. */
+
+struct value *
+value_allocate_space_in_inferior (int len)
+{
+  struct value *blocklen;
+  struct value *val = find_function_in_inferior (NAME_OF_MALLOC);
+
+  blocklen = value_from_longest (builtin_type_int, (LONGEST) len);
+  val = call_function_by_hand (val, 1, &blocklen);
+  if (value_logical_not (val))
+    {
+      if (!target_has_execution)
+       error ("No memory available to program now: you need to start the target first");
+      else
+       error ("No memory available to program: call to malloc failed");
+    }
+  return val;
+}
+
+static CORE_ADDR
+allocate_space_in_inferior (int len)
+{
+  return value_as_long (value_allocate_space_in_inferior (len));
+}
+
+/* Cast value ARG2 to type TYPE and return as a value.
+   More general than a C cast: accepts any two types of the same length,
+   and if ARG2 is an lvalue it can be cast into anything at all.  */
+/* In C++, casts may change pointer or object representations.  */
+
+struct value *
+value_cast (struct type *type, struct value *arg2)
+{
+  register enum type_code code1;
+  register enum type_code code2;
+  register int scalar;
+  struct type *type2;
+
+  int convert_to_boolean = 0;
+
+  if (VALUE_TYPE (arg2) == type)
+    return arg2;
+
+  CHECK_TYPEDEF (type);
+  code1 = TYPE_CODE (type);
+  COERCE_REF (arg2);
+  type2 = check_typedef (VALUE_TYPE (arg2));
+
+  /* A cast to an undetermined-length array_type, such as (TYPE [])OBJECT,
+     is treated like a cast to (TYPE [N])OBJECT,
+     where N is sizeof(OBJECT)/sizeof(TYPE). */
+  if (code1 == TYPE_CODE_ARRAY)
+    {
+      struct type *element_type = TYPE_TARGET_TYPE (type);
+      unsigned element_length = TYPE_LENGTH (check_typedef (element_type));
+      if (element_length > 0
+       && TYPE_ARRAY_UPPER_BOUND_TYPE (type) == BOUND_CANNOT_BE_DETERMINED)
+       {
+         struct type *range_type = TYPE_INDEX_TYPE (type);
+         int val_length = TYPE_LENGTH (type2);
+         LONGEST low_bound, high_bound, new_length;
+         if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0)
+           low_bound = 0, high_bound = 0;
+         new_length = val_length / element_length;
+         if (val_length % element_length != 0)
+           warning ("array element type size does not divide object size in cast");
+         /* FIXME-type-allocation: need a way to free this type when we are
+            done with it.  */
+         range_type = create_range_type ((struct type *) NULL,
+                                         TYPE_TARGET_TYPE (range_type),
+                                         low_bound,
+                                         new_length + low_bound - 1);
+         VALUE_TYPE (arg2) = create_array_type ((struct type *) NULL,
+                                                element_type, range_type);
+         return arg2;
+       }
+    }
+
+  if (current_language->c_style_arrays
+      && TYPE_CODE (type2) == TYPE_CODE_ARRAY)
+    arg2 = value_coerce_array (arg2);
+
+  if (TYPE_CODE (type2) == TYPE_CODE_FUNC)
+    arg2 = value_coerce_function (arg2);
+
+  type2 = check_typedef (VALUE_TYPE (arg2));
+  COERCE_VARYING_ARRAY (arg2, type2);
+  code2 = TYPE_CODE (type2);
+
+  if (code1 == TYPE_CODE_COMPLEX)
+    return cast_into_complex (type, arg2);
+  if (code1 == TYPE_CODE_BOOL)
+    {
+      code1 = TYPE_CODE_INT;
+      convert_to_boolean = 1;
+    }
+  if (code1 == TYPE_CODE_CHAR)
+    code1 = TYPE_CODE_INT;
+  if (code2 == TYPE_CODE_BOOL || code2 == TYPE_CODE_CHAR)
+    code2 = TYPE_CODE_INT;
+
+  scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT
+           || code2 == TYPE_CODE_ENUM || code2 == TYPE_CODE_RANGE);
+
+  if (code1 == TYPE_CODE_STRUCT
+      && code2 == TYPE_CODE_STRUCT
+      && TYPE_NAME (type) != 0)
+    {
+      /* Look in the type of the source to see if it contains the
+         type of the target as a superclass.  If so, we'll need to
+         offset the object in addition to changing its type.  */
+      struct value *v = search_struct_field (type_name_no_tag (type),
+                                        arg2, 0, type2, 1);
+      if (v)
+       {
+         VALUE_TYPE (v) = type;
+         return v;
+       }
+    }
+  if (code1 == TYPE_CODE_FLT && scalar)
+    return value_from_double (type, value_as_double (arg2));
+  else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM
+           || code1 == TYPE_CODE_RANGE)
+          && (scalar || code2 == TYPE_CODE_PTR))
+    {
+      LONGEST longest;
+
+      if (hp_som_som_object_present && /* if target compiled by HP aCC */
+         (code2 == TYPE_CODE_PTR))
+       {
+         unsigned int *ptr;
+         struct value *retvalp;
+
+         switch (TYPE_CODE (TYPE_TARGET_TYPE (type2)))
+           {
+             /* With HP aCC, pointers to data members have a bias */
+           case TYPE_CODE_MEMBER:
+             retvalp = value_from_longest (type, value_as_long (arg2));
+             /* force evaluation */
+             ptr = (unsigned int *) VALUE_CONTENTS (retvalp);
+             *ptr &= ~0x20000000;      /* zap 29th bit to remove bias */
+             return retvalp;
+
+             /* While pointers to methods don't really point to a function */
+           case TYPE_CODE_METHOD:
+             error ("Pointers to methods not supported with HP aCC");
+
+           default:
+             break;            /* fall out and go to normal handling */
+           }
+       }
+
+      /* When we cast pointers to integers, we mustn't use
+         POINTER_TO_ADDRESS to find the address the pointer
+         represents, as value_as_long would.  GDB should evaluate
+         expressions just as the compiler would --- and the compiler
+         sees a cast as a simple reinterpretation of the pointer's
+         bits.  */
+      if (code2 == TYPE_CODE_PTR)
+        longest = extract_unsigned_integer (VALUE_CONTENTS (arg2),
+                                            TYPE_LENGTH (type2));
+      else
+        longest = value_as_long (arg2);
+      return value_from_longest (type, convert_to_boolean ?
+                                (LONGEST) (longest ? 1 : 0) : longest);
+    }
+  else if (code1 == TYPE_CODE_PTR && (code2 == TYPE_CODE_INT  ||
+                                     code2 == TYPE_CODE_ENUM ||
+                                     code2 == TYPE_CODE_RANGE))
+    {
+      /* TYPE_LENGTH (type) is the length of a pointer, but we really
+        want the length of an address! -- we are really dealing with
+        addresses (i.e., gdb representations) not pointers (i.e.,
+        target representations) here.
+
+        This allows things like "print *(int *)0x01000234" to work
+        without printing a misleading message -- which would
+        otherwise occur when dealing with a target having two byte
+        pointers and four byte addresses.  */
+
+      int addr_bit = TARGET_ADDR_BIT;
+
+      LONGEST longest = value_as_long (arg2);
+      if (addr_bit < sizeof (LONGEST) * HOST_CHAR_BIT)
+       {
+         if (longest >= ((LONGEST) 1 << addr_bit)
+             || longest <= -((LONGEST) 1 << addr_bit))
+           warning ("value truncated");
+       }
+      return value_from_longest (type, longest);
+    }
+  else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2))
+    {
+      if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
+       {
+         struct type *t1 = check_typedef (TYPE_TARGET_TYPE (type));
+         struct type *t2 = check_typedef (TYPE_TARGET_TYPE (type2));
+         if (TYPE_CODE (t1) == TYPE_CODE_STRUCT
+             && TYPE_CODE (t2) == TYPE_CODE_STRUCT
+             && !value_logical_not (arg2))
+           {
+             struct value *v;
+
+             /* Look in the type of the source to see if it contains the
+                type of the target as a superclass.  If so, we'll need to
+                offset the pointer rather than just change its type.  */
+             if (TYPE_NAME (t1) != NULL)
+               {
+                 v = search_struct_field (type_name_no_tag (t1),
+                                          value_ind (arg2), 0, t2, 1);
+                 if (v)
+                   {
+                     v = value_addr (v);
+                     VALUE_TYPE (v) = type;
+                     return v;
+                   }
+               }
+
+             /* Look in the type of the target to see if it contains the
+                type of the source as a superclass.  If so, we'll need to
+                offset the pointer rather than just change its type.
+                FIXME: This fails silently with virtual inheritance.  */
+             if (TYPE_NAME (t2) != NULL)
+               {
+                 v = search_struct_field (type_name_no_tag (t2),
+                                      value_zero (t1, not_lval), 0, t1, 1);
+                 if (v)
+                   {
+                      CORE_ADDR addr2 = value_as_address (arg2);
+                      addr2 -= (VALUE_ADDRESS (v)
+                                + VALUE_OFFSET (v)
+                                + VALUE_EMBEDDED_OFFSET (v));
+                      return value_from_pointer (type, addr2);
+                   }
+               }
+           }
+         /* No superclass found, just fall through to change ptr type.  */
+       }
+      VALUE_TYPE (arg2) = type;
+      arg2 = value_change_enclosing_type (arg2, type);
+      VALUE_POINTED_TO_OFFSET (arg2) = 0;      /* pai: chk_val */
+      return arg2;
+    }
+  /* OBSOLETE else if (chill_varying_type (type)) */
+  /* OBSOLETE   { */
+  /* OBSOLETE     struct type *range1, *range2, *eltype1, *eltype2; */
+  /* OBSOLETE     struct value *val; */
+  /* OBSOLETE     int count1, count2; */
+  /* OBSOLETE     LONGEST low_bound, high_bound; */
+  /* OBSOLETE     char *valaddr, *valaddr_data; */
+  /* OBSOLETE     *//* For lint warning about eltype2 possibly uninitialized: */
+  /* OBSOLETE     eltype2 = NULL; */
+  /* OBSOLETE     if (code2 == TYPE_CODE_BITSTRING) */
+  /* OBSOLETE       error ("not implemented: converting bitstring to varying type"); */
+  /* OBSOLETE     if ((code2 != TYPE_CODE_ARRAY && code2 != TYPE_CODE_STRING) */
+  /* OBSOLETE         || (eltype1 = check_typedef (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 1))), */
+  /* OBSOLETE       eltype2 = check_typedef (TYPE_TARGET_TYPE (type2)), */
+  /* OBSOLETE                                (TYPE_LENGTH (eltype1) != TYPE_LENGTH (eltype2) */
+  /* OBSOLETE     *//*|| TYPE_CODE (eltype1) != TYPE_CODE (eltype2) *//* ))) */
+  /* OBSOLETE      error ("Invalid conversion to varying type"); */
+  /* OBSOLETE     range1 = TYPE_FIELD_TYPE (TYPE_FIELD_TYPE (type, 1), 0); */
+  /* OBSOLETE     range2 = TYPE_FIELD_TYPE (type2, 0); */
+  /* OBSOLETE     if (get_discrete_bounds (range1, &low_bound, &high_bound) < 0) */
+  /* OBSOLETE       count1 = -1; */
+  /* OBSOLETE     else */
+  /* OBSOLETE       count1 = high_bound - low_bound + 1; */
+  /* OBSOLETE     if (get_discrete_bounds (range2, &low_bound, &high_bound) < 0) */
+  /* OBSOLETE       count1 = -1, count2 = 0;   *//* To force error before */
+  /* OBSOLETE     else */
+  /* OBSOLETE       count2 = high_bound - low_bound + 1; */
+  /* OBSOLETE     if (count2 > count1) */
+  /* OBSOLETE       error ("target varying type is too small"); */
+  /* OBSOLETE     val = allocate_value (type); */
+  /* OBSOLETE     valaddr = VALUE_CONTENTS_RAW (val); */
+  /* OBSOLETE     valaddr_data = valaddr + TYPE_FIELD_BITPOS (type, 1) / 8; */
+  /* OBSOLETE     *//* Set val's __var_length field to count2. */
+  /* OBSOLETE     store_signed_integer (valaddr, TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)), */
+  /* OBSOLETE      count2); */
+  /* OBSOLETE     *//* Set the __var_data field to count2 elements copied from arg2. */
+  /* OBSOLETE     memcpy (valaddr_data, VALUE_CONTENTS (arg2), */
+  /* OBSOLETE      count2 * TYPE_LENGTH (eltype2)); */
+  /* OBSOLETE     *//* Zero the rest of the __var_data field of val. */
+  /* OBSOLETE     memset (valaddr_data + count2 * TYPE_LENGTH (eltype2), '\0', */
+  /* OBSOLETE      (count1 - count2) * TYPE_LENGTH (eltype2)); */
+  /* OBSOLETE     return val; */
+  /* OBSOLETE   } */
+  else if (VALUE_LVAL (arg2) == lval_memory)
+    {
+      return value_at_lazy (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2),
+                           VALUE_BFD_SECTION (arg2));
+    }
+  else if (code1 == TYPE_CODE_VOID)
+    {
+      return value_zero (builtin_type_void, not_lval);
+    }
+  else
+    {
+      error ("Invalid cast.");
+      return 0;
+    }
+}
+
+/* Create a value of type TYPE that is zero, and return it.  */
+
+struct value *
+value_zero (struct type *type, enum lval_type lv)
+{
+  struct value *val = allocate_value (type);
+
+  memset (VALUE_CONTENTS (val), 0, TYPE_LENGTH (check_typedef (type)));
+  VALUE_LVAL (val) = lv;
+
+  return val;
+}
+
+/* Return a value with type TYPE located at ADDR.
+
+   Call value_at only if the data needs to be fetched immediately;
+   if we can be 'lazy' and defer the fetch, perhaps indefinately, call
+   value_at_lazy instead.  value_at_lazy simply records the address of
+   the data and sets the lazy-evaluation-required flag.  The lazy flag
+   is tested in the VALUE_CONTENTS macro, which is used if and when
+   the contents are actually required.
+
+   Note: value_at does *NOT* handle embedded offsets; perform such
+   adjustments before or after calling it. */
+
+struct value *
+value_at (struct type *type, CORE_ADDR addr, asection *sect)
+{
+  struct value *val;
+
+  if (TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID)
+    error ("Attempt to dereference a generic pointer.");
+
+  val = allocate_value (type);
+
+  read_memory (addr, VALUE_CONTENTS_ALL_RAW (val), TYPE_LENGTH (type));
+
+  VALUE_LVAL (val) = lval_memory;
+  VALUE_ADDRESS (val) = addr;
+  VALUE_BFD_SECTION (val) = sect;
+
+  return val;
+}
+
+/* Return a lazy value with type TYPE located at ADDR (cf. value_at).  */
+
+struct value *
+value_at_lazy (struct type *type, CORE_ADDR addr, asection *sect)
+{
+  struct value *val;
+
+  if (TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID)
+    error ("Attempt to dereference a generic pointer.");
+
+  val = allocate_value (type);
+
+  VALUE_LVAL (val) = lval_memory;
+  VALUE_ADDRESS (val) = addr;
+  VALUE_LAZY (val) = 1;
+  VALUE_BFD_SECTION (val) = sect;
+
+  return val;
+}
+
+/* Called only from the VALUE_CONTENTS and VALUE_CONTENTS_ALL macros,
+   if the current data for a variable needs to be loaded into
+   VALUE_CONTENTS(VAL).  Fetches the data from the user's process, and
+   clears the lazy flag to indicate that the data in the buffer is valid.
+
+   If the value is zero-length, we avoid calling read_memory, which would
+   abort.  We mark the value as fetched anyway -- all 0 bytes of it.
+
+   This function returns a value because it is used in the VALUE_CONTENTS
+   macro as part of an expression, where a void would not work.  The
+   value is ignored.  */
+
+int
+value_fetch_lazy (struct value *val)
+{
+  CORE_ADDR addr = VALUE_ADDRESS (val) + VALUE_OFFSET (val);
+  int length = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (val));
+
+  struct type *type = VALUE_TYPE (val);
+  if (length)
+    read_memory (addr, VALUE_CONTENTS_ALL_RAW (val), length);
+
+  VALUE_LAZY (val) = 0;
+  return 0;
+}
+
+
+/* Store the contents of FROMVAL into the location of TOVAL.
+   Return a new value with the location of TOVAL and contents of FROMVAL.  */
+
+struct value *
+value_assign (struct value *toval, struct value *fromval)
+{
+  register struct type *type;
+  struct value *val;
+  char *raw_buffer = (char*) alloca (MAX_REGISTER_RAW_SIZE);
+  int use_buffer = 0;
+
+  if (!toval->modifiable)
+    error ("Left operand of assignment is not a modifiable lvalue.");
+
+  COERCE_REF (toval);
+
+  type = VALUE_TYPE (toval);
+  if (VALUE_LVAL (toval) != lval_internalvar)
+    fromval = value_cast (type, fromval);
+  else
+    COERCE_ARRAY (fromval);
+  CHECK_TYPEDEF (type);
+
+  /* If TOVAL is a special machine register requiring conversion
+     of program values to a special raw format,
+     convert FROMVAL's contents now, with result in `raw_buffer',
+     and set USE_BUFFER to the number of bytes to write.  */
+
+  if (VALUE_REGNO (toval) >= 0)
+    {
+      int regno = VALUE_REGNO (toval);
+      if (CONVERT_REGISTER_P (regno))
+       {
+         struct type *fromtype = check_typedef (VALUE_TYPE (fromval));
+         VALUE_TO_REGISTER (fromtype, regno, VALUE_CONTENTS (fromval), raw_buffer);
+         use_buffer = REGISTER_RAW_SIZE (regno);
+       }
+    }
+
+  switch (VALUE_LVAL (toval))
+    {
+    case lval_internalvar:
+      set_internalvar (VALUE_INTERNALVAR (toval), fromval);
+      val = value_copy (VALUE_INTERNALVAR (toval)->value);
+      val = value_change_enclosing_type (val, VALUE_ENCLOSING_TYPE (fromval));
+      VALUE_EMBEDDED_OFFSET (val) = VALUE_EMBEDDED_OFFSET (fromval);
+      VALUE_POINTED_TO_OFFSET (val) = VALUE_POINTED_TO_OFFSET (fromval);
+      return val;
+
+    case lval_internalvar_component:
+      set_internalvar_component (VALUE_INTERNALVAR (toval),
+                                VALUE_OFFSET (toval),
+                                VALUE_BITPOS (toval),
+                                VALUE_BITSIZE (toval),
+                                fromval);
+      break;
+
+    case lval_memory:
+      {
+       char *dest_buffer;
+       CORE_ADDR changed_addr;
+       int changed_len;
+
+       if (VALUE_BITSIZE (toval))
+         {
+           char buffer[sizeof (LONGEST)];
+           /* We assume that the argument to read_memory is in units of
+              host chars.  FIXME:  Is that correct?  */
+           changed_len = (VALUE_BITPOS (toval)
+                          + VALUE_BITSIZE (toval)
+                          + HOST_CHAR_BIT - 1)
+             / HOST_CHAR_BIT;
+
+           if (changed_len > (int) sizeof (LONGEST))
+             error ("Can't handle bitfields which don't fit in a %d bit word.",
+                    (int) sizeof (LONGEST) * HOST_CHAR_BIT);
+
+           read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                        buffer, changed_len);
+           modify_field (buffer, value_as_long (fromval),
+                         VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+           changed_addr = VALUE_ADDRESS (toval) + VALUE_OFFSET (toval);
+           dest_buffer = buffer;
+         }
+       else if (use_buffer)
+         {
+           changed_addr = VALUE_ADDRESS (toval) + VALUE_OFFSET (toval);
+           changed_len = use_buffer;
+           dest_buffer = raw_buffer;
+         }
+       else
+         {
+           changed_addr = VALUE_ADDRESS (toval) + VALUE_OFFSET (toval);
+           changed_len = TYPE_LENGTH (type);
+           dest_buffer = VALUE_CONTENTS (fromval);
+         }
+
+       write_memory (changed_addr, dest_buffer, changed_len);
+       if (memory_changed_hook)
+         memory_changed_hook (changed_addr, changed_len);
+       target_changed_event ();
+      }
+      break;
+
+    case lval_register:
+      if (VALUE_BITSIZE (toval))
+       {
+         char buffer[sizeof (LONGEST)];
+         int len =
+               REGISTER_RAW_SIZE (VALUE_REGNO (toval)) - VALUE_OFFSET (toval);
+
+         if (len > (int) sizeof (LONGEST))
+           error ("Can't handle bitfields in registers larger than %d bits.",
+                  (int) sizeof (LONGEST) * HOST_CHAR_BIT);
+
+         if (VALUE_BITPOS (toval) + VALUE_BITSIZE (toval)
+             > len * HOST_CHAR_BIT)
+           /* Getting this right would involve being very careful about
+              byte order.  */
+           error ("Can't assign to bitfields that cross register "
+                  "boundaries.");
+
+         read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                              buffer, len);
+         modify_field (buffer, value_as_long (fromval),
+                       VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+         write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                               buffer, len);
+       }
+      else if (use_buffer)
+       write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                             raw_buffer, use_buffer);
+      else
+       {
+         /* Do any conversion necessary when storing this type to more
+            than one register.  */
+#ifdef REGISTER_CONVERT_FROM_TYPE
+         memcpy (raw_buffer, VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+         REGISTER_CONVERT_FROM_TYPE (VALUE_REGNO (toval), type, raw_buffer);
+         write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                               raw_buffer, TYPE_LENGTH (type));
+#else
+         write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                             VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+#endif
+       }
+
+      target_changed_event ();
+
+      /* Assigning to the stack pointer, frame pointer, and other
+         (architecture and calling convention specific) registers may
+         cause the frame cache to be out of date.  We just do this
+         on all assignments to registers for simplicity; I doubt the slowdown
+         matters.  */
+      reinit_frame_cache ();
+      break;
+
+    case lval_reg_frame_relative:
+      {
+       /* value is stored in a series of registers in the frame
+          specified by the structure.  Copy that value out, modify
+          it, and copy it back in.  */
+       int amount_to_copy = (VALUE_BITSIZE (toval) ? 1 : TYPE_LENGTH (type));
+       int reg_size = REGISTER_RAW_SIZE (VALUE_FRAME_REGNUM (toval));
+       int byte_offset = VALUE_OFFSET (toval) % reg_size;
+       int reg_offset = VALUE_OFFSET (toval) / reg_size;
+       int amount_copied;
+
+       /* Make the buffer large enough in all cases.  */
+       /* FIXME (alloca): Not safe for very large data types. */
+       char *buffer = (char *) alloca (amount_to_copy
+                                       + sizeof (LONGEST)
+                                       + MAX_REGISTER_RAW_SIZE);
+
+       int regno;
+       struct frame_info *frame;
+
+       /* Figure out which frame this is in currently.  */
+       for (frame = get_current_frame ();
+            frame && FRAME_FP (frame) != VALUE_FRAME (toval);
+            frame = get_prev_frame (frame))
+         ;
+
+       if (!frame)
+         error ("Value being assigned to is no longer active.");
+
+       amount_to_copy += (reg_size - amount_to_copy % reg_size);
+
+       /* Copy it out.  */
+       for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
+             amount_copied = 0);
+            amount_copied < amount_to_copy;
+            amount_copied += reg_size, regno++)
+         {
+           get_saved_register (buffer + amount_copied,
+                               (int *) NULL, (CORE_ADDR *) NULL,
+                               frame, regno, (enum lval_type *) NULL);
+         }
+
+       /* Modify what needs to be modified.  */
+       if (VALUE_BITSIZE (toval))
+         modify_field (buffer + byte_offset,
+                       value_as_long (fromval),
+                       VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+       else if (use_buffer)
+         memcpy (buffer + byte_offset, raw_buffer, use_buffer);
+       else
+         memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval),
+                 TYPE_LENGTH (type));
+
+       /* Copy it back.  */
+       for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
+             amount_copied = 0);
+            amount_copied < amount_to_copy;
+            amount_copied += reg_size, regno++)
+         {
+           enum lval_type lval;
+           CORE_ADDR addr;
+           int optim;
+
+           /* Just find out where to put it.  */
+           get_saved_register ((char *) NULL,
+                               &optim, &addr, frame, regno, &lval);
+
+           if (optim)
+             error ("Attempt to assign to a value that was optimized out.");
+           if (lval == lval_memory)
+             write_memory (addr, buffer + amount_copied, reg_size);
+           else if (lval == lval_register)
+             write_register_bytes (addr, buffer + amount_copied, reg_size);
+           else
+             error ("Attempt to assign to an unmodifiable value.");
+         }
+
+       if (register_changed_hook)
+         register_changed_hook (-1);
+       target_changed_event ();
+      }
+      break;
+
+
+    default:
+      error ("Left operand of assignment is not an lvalue.");
+    }
+
+  /* If the field does not entirely fill a LONGEST, then zero the sign bits.
+     If the field is signed, and is negative, then sign extend. */
+  if ((VALUE_BITSIZE (toval) > 0)
+      && (VALUE_BITSIZE (toval) < 8 * (int) sizeof (LONGEST)))
+    {
+      LONGEST fieldval = value_as_long (fromval);
+      LONGEST valmask = (((ULONGEST) 1) << VALUE_BITSIZE (toval)) - 1;
+
+      fieldval &= valmask;
+      if (!TYPE_UNSIGNED (type) && (fieldval & (valmask ^ (valmask >> 1))))
+       fieldval |= ~valmask;
+
+      fromval = value_from_longest (type, fieldval);
+    }
+
+  val = value_copy (toval);
+  memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS (fromval),
+         TYPE_LENGTH (type));
+  VALUE_TYPE (val) = type;
+  val = value_change_enclosing_type (val, VALUE_ENCLOSING_TYPE (fromval));
+  VALUE_EMBEDDED_OFFSET (val) = VALUE_EMBEDDED_OFFSET (fromval);
+  VALUE_POINTED_TO_OFFSET (val) = VALUE_POINTED_TO_OFFSET (fromval);
+
+  return val;
+}
+
+/* Extend a value VAL to COUNT repetitions of its type.  */
+
+struct value *
+value_repeat (struct value *arg1, int count)
+{
+  struct value *val;
+
+  if (VALUE_LVAL (arg1) != lval_memory)
+    error ("Only values in memory can be extended with '@'.");
+  if (count < 1)
+    error ("Invalid number %d of repetitions.", count);
+
+  val = allocate_repeat_value (VALUE_ENCLOSING_TYPE (arg1), count);
+
+  read_memory (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1),
+              VALUE_CONTENTS_ALL_RAW (val),
+              TYPE_LENGTH (VALUE_ENCLOSING_TYPE (val)));
+  VALUE_LVAL (val) = lval_memory;
+  VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1);
+
+  return val;
+}
+
+struct value *
+value_of_variable (struct symbol *var, struct block *b)
+{
+  struct value *val;
+  struct frame_info *frame = NULL;
+
+  if (!b)
+    frame = NULL;              /* Use selected frame.  */
+  else if (symbol_read_needs_frame (var))
+    {
+      frame = block_innermost_frame (b);
+      if (!frame)
+       {
+         if (BLOCK_FUNCTION (b)
+             && SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)))
+           error ("No frame is currently executing in block %s.",
+                  SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)));
+         else
+           error ("No frame is currently executing in specified block");
+       }
+    }
+
+  val = read_var_value (var, frame);
+  if (!val)
+    error ("Address of symbol \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var));
+
+  return val;
+}
+
+/* Given a value which is an array, return a value which is a pointer to its
+   first element, regardless of whether or not the array has a nonzero lower
+   bound.
+
+   FIXME:  A previous comment here indicated that this routine should be
+   substracting the array's lower bound.  It's not clear to me that this
+   is correct.  Given an array subscripting operation, it would certainly
+   work to do the adjustment here, essentially computing:
+
+   (&array[0] - (lowerbound * sizeof array[0])) + (index * sizeof array[0])
+
+   However I believe a more appropriate and logical place to account for
+   the lower bound is to do so in value_subscript, essentially computing:
+
+   (&array[0] + ((index - lowerbound) * sizeof array[0]))
+
+   As further evidence consider what would happen with operations other
+   than array subscripting, where the caller would get back a value that
+   had an address somewhere before the actual first element of the array,
+   and the information about the lower bound would be lost because of
+   the coercion to pointer type.
+ */
+
+struct value *
+value_coerce_array (struct value *arg1)
+{
+  register struct type *type = check_typedef (VALUE_TYPE (arg1));
+
+  if (VALUE_LVAL (arg1) != lval_memory)
+    error ("Attempt to take address of value not located in memory.");
+
+  return value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+                            (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+}
+
+/* Given a value which is a function, return a value which is a pointer
+   to it.  */
+
+struct value *
+value_coerce_function (struct value *arg1)
+{
+  struct value *retval;
+
+  if (VALUE_LVAL (arg1) != lval_memory)
+    error ("Attempt to take address of value not located in memory.");
+
+  retval = value_from_pointer (lookup_pointer_type (VALUE_TYPE (arg1)),
+                              (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+  VALUE_BFD_SECTION (retval) = VALUE_BFD_SECTION (arg1);
+  return retval;
+}
+
+/* Return a pointer value for the object for which ARG1 is the contents.  */
+
+struct value *
+value_addr (struct value *arg1)
+{
+  struct value *arg2;
+
+  struct type *type = check_typedef (VALUE_TYPE (arg1));
+  if (TYPE_CODE (type) == TYPE_CODE_REF)
+    {
+      /* Copy the value, but change the type from (T&) to (T*).
+         We keep the same location information, which is efficient,
+         and allows &(&X) to get the location containing the reference. */
+      arg2 = value_copy (arg1);
+      VALUE_TYPE (arg2) = lookup_pointer_type (TYPE_TARGET_TYPE (type));
+      return arg2;
+    }
+  if (TYPE_CODE (type) == TYPE_CODE_FUNC)
+    return value_coerce_function (arg1);
+
+  if (VALUE_LVAL (arg1) != lval_memory)
+    error ("Attempt to take address of value not located in memory.");
+
+  /* Get target memory address */
+  arg2 = value_from_pointer (lookup_pointer_type (VALUE_TYPE (arg1)),
+                            (VALUE_ADDRESS (arg1)
+                             + VALUE_OFFSET (arg1)
+                             + VALUE_EMBEDDED_OFFSET (arg1)));
+
+  /* This may be a pointer to a base subobject; so remember the
+     full derived object's type ... */
+  arg2 = value_change_enclosing_type (arg2, lookup_pointer_type (VALUE_ENCLOSING_TYPE (arg1)));
+  /* ... and also the relative position of the subobject in the full object */
+  VALUE_POINTED_TO_OFFSET (arg2) = VALUE_EMBEDDED_OFFSET (arg1);
+  VALUE_BFD_SECTION (arg2) = VALUE_BFD_SECTION (arg1);
+  return arg2;
+}
+
+/* Given a value of a pointer type, apply the C unary * operator to it.  */
+
+struct value *
+value_ind (struct value *arg1)
+{
+  struct type *base_type;
+  struct value *arg2;
+
+  COERCE_ARRAY (arg1);
+
+  base_type = check_typedef (VALUE_TYPE (arg1));
+
+  if (TYPE_CODE (base_type) == TYPE_CODE_MEMBER)
+    error ("not implemented: member types in value_ind");
+
+  /* Allow * on an integer so we can cast it to whatever we want.
+     This returns an int, which seems like the most C-like thing
+     to do.  "long long" variables are rare enough that
+     BUILTIN_TYPE_LONGEST would seem to be a mistake.  */
+  if (TYPE_CODE (base_type) == TYPE_CODE_INT)
+    return value_at_lazy (builtin_type_int,
+                         (CORE_ADDR) value_as_long (arg1),
+                         VALUE_BFD_SECTION (arg1));
+  else if (TYPE_CODE (base_type) == TYPE_CODE_PTR)
+    {
+      struct type *enc_type;
+      /* We may be pointing to something embedded in a larger object */
+      /* Get the real type of the enclosing object */
+      enc_type = check_typedef (VALUE_ENCLOSING_TYPE (arg1));
+      enc_type = TYPE_TARGET_TYPE (enc_type);
+      /* Retrieve the enclosing object pointed to */
+      arg2 = value_at_lazy (enc_type,
+                  value_as_address (arg1) - VALUE_POINTED_TO_OFFSET (arg1),
+                           VALUE_BFD_SECTION (arg1));
+      /* Re-adjust type */
+      VALUE_TYPE (arg2) = TYPE_TARGET_TYPE (base_type);
+      /* Add embedding info */
+      arg2 = value_change_enclosing_type (arg2, enc_type);
+      VALUE_EMBEDDED_OFFSET (arg2) = VALUE_POINTED_TO_OFFSET (arg1);
+
+      /* We may be pointing to an object of some derived type */
+      arg2 = value_full_object (arg2, NULL, 0, 0, 0);
+      return arg2;
+    }
+
+  error ("Attempt to take contents of a non-pointer value.");
+  return 0;                    /* For lint -- never reached */
+}
+\f
+/* Pushing small parts of stack frames.  */
+
+/* Push one word (the size of object that a register holds).  */
+
+CORE_ADDR
+push_word (CORE_ADDR sp, ULONGEST word)
+{
+  register int len = REGISTER_SIZE;
+  char *buffer = alloca (MAX_REGISTER_RAW_SIZE);
+
+  store_unsigned_integer (buffer, len, word);
+  if (INNER_THAN (1, 2))
+    {
+      /* stack grows downward */
+      sp -= len;
+      write_memory (sp, buffer, len);
+    }
+  else
+    {
+      /* stack grows upward */
+      write_memory (sp, buffer, len);
+      sp += len;
+    }
+
+  return sp;
+}
+
+/* Push LEN bytes with data at BUFFER.  */
+
+CORE_ADDR
+push_bytes (CORE_ADDR sp, char *buffer, int len)
+{
+  if (INNER_THAN (1, 2))
+    {
+      /* stack grows downward */
+      sp -= len;
+      write_memory (sp, buffer, len);
+    }
+  else
+    {
+      /* stack grows upward */
+      write_memory (sp, buffer, len);
+      sp += len;
+    }
+
+  return sp;
+}
+
+#ifndef PARM_BOUNDARY
+#define PARM_BOUNDARY (0)
+#endif
+
+/* Push onto the stack the specified value VALUE.  Pad it correctly for
+   it to be an argument to a function.  */
+
+static CORE_ADDR
+value_push (register CORE_ADDR sp, struct value *arg)
+{
+  register int len = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (arg));
+  register int container_len = len;
+  register int offset;
+
+  /* How big is the container we're going to put this value in?  */
+  if (PARM_BOUNDARY)
+    container_len = ((len + PARM_BOUNDARY / TARGET_CHAR_BIT - 1)
+                    & ~(PARM_BOUNDARY / TARGET_CHAR_BIT - 1));
+
+  /* Are we going to put it at the high or low end of the container?  */
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    offset = container_len - len;
+  else
+    offset = 0;
+
+  if (INNER_THAN (1, 2))
+    {
+      /* stack grows downward */
+      sp -= container_len;
+      write_memory (sp + offset, VALUE_CONTENTS_ALL (arg), len);
+    }
+  else
+    {
+      /* stack grows upward */
+      write_memory (sp + offset, VALUE_CONTENTS_ALL (arg), len);
+      sp += container_len;
+    }
+
+  return sp;
+}
+
+CORE_ADDR
+default_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+                       int struct_return, CORE_ADDR struct_addr)
+{
+  /* ASSERT ( !struct_return); */
+  int i;
+  for (i = nargs - 1; i >= 0; i--)
+    sp = value_push (sp, args[i]);
+  return sp;
+}
+
+
+/* Functions to use for the COERCE_FLOAT_TO_DOUBLE gdbarch method.
+
+   How you should pass arguments to a function depends on whether it
+   was defined in K&R style or prototype style.  If you define a
+   function using the K&R syntax that takes a `float' argument, then
+   callers must pass that argument as a `double'.  If you define the
+   function using the prototype syntax, then you must pass the
+   argument as a `float', with no promotion.
+
+   Unfortunately, on certain older platforms, the debug info doesn't
+   indicate reliably how each function was defined.  A function type's
+   TYPE_FLAG_PROTOTYPED flag may be clear, even if the function was
+   defined in prototype style.  When calling a function whose
+   TYPE_FLAG_PROTOTYPED flag is clear, GDB consults the
+   COERCE_FLOAT_TO_DOUBLE gdbarch method to decide what to do.
+
+   For modern targets, it is proper to assume that, if the prototype
+   flag is clear, that can be trusted: `float' arguments should be
+   promoted to `double'.  You should register the function
+   `standard_coerce_float_to_double' to get this behavior.
+
+   For some older targets, if the prototype flag is clear, that
+   doesn't tell us anything.  So we guess that, if we don't have a
+   type for the formal parameter (i.e., the first argument to
+   COERCE_FLOAT_TO_DOUBLE is null), then we should promote it;
+   otherwise, we should leave it alone.  The function
+   `default_coerce_float_to_double' provides this behavior; it is the
+   default value, for compatibility with older configurations.  */
+int
+default_coerce_float_to_double (struct type *formal, struct type *actual)
+{
+  return formal == NULL;
+}
+
+
+int
+standard_coerce_float_to_double (struct type *formal, struct type *actual)
+{
+  return 1;
+}
+
+
+/* Perform the standard coercions that are specified
+   for arguments to be passed to C functions.
+
+   If PARAM_TYPE is non-NULL, it is the expected parameter type.
+   IS_PROTOTYPED is non-zero if the function declaration is prototyped.  */
+
+static struct value *
+value_arg_coerce (struct value *arg, struct type *param_type,
+                 int is_prototyped)
+{
+  register struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+  register struct type *type
+    = param_type ? check_typedef (param_type) : arg_type;
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_REF:
+      if (TYPE_CODE (arg_type) != TYPE_CODE_REF
+         && TYPE_CODE (arg_type) != TYPE_CODE_PTR)
+       {
+         arg = value_addr (arg);
+         VALUE_TYPE (arg) = param_type;
+         return arg;
+       }
+      break;
+    case TYPE_CODE_INT:
+    case TYPE_CODE_CHAR:
+    case TYPE_CODE_BOOL:
+    case TYPE_CODE_ENUM:
+      /* If we don't have a prototype, coerce to integer type if necessary.  */
+      if (!is_prototyped)
+       {
+         if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+           type = builtin_type_int;
+       }
+      /* Currently all target ABIs require at least the width of an integer
+         type for an argument.  We may have to conditionalize the following
+         type coercion for future targets.  */
+      if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
+       type = builtin_type_int;
+      break;
+    case TYPE_CODE_FLT:
+      /* FIXME: We should always convert floats to doubles in the
+         non-prototyped case.  As many debugging formats include
+         no information about prototyping, we have to live with
+         COERCE_FLOAT_TO_DOUBLE for now.  */
+      if (!is_prototyped && COERCE_FLOAT_TO_DOUBLE (param_type, arg_type))
+       {
+         if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_double))
+           type = builtin_type_double;
+         else if (TYPE_LENGTH (type) > TYPE_LENGTH (builtin_type_double))
+           type = builtin_type_long_double;
+       }
+      break;
+    case TYPE_CODE_FUNC:
+      type = lookup_pointer_type (type);
+      break;
+    case TYPE_CODE_ARRAY:
+      /* Arrays are coerced to pointers to their first element, unless
+         they are vectors, in which case we want to leave them alone,
+         because they are passed by value.  */
+      if (current_language->c_style_arrays)
+       if (!TYPE_VECTOR (type))
+         type = lookup_pointer_type (TYPE_TARGET_TYPE (type));
+      break;
+    case TYPE_CODE_UNDEF:
+    case TYPE_CODE_PTR:
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_VOID:
+    case TYPE_CODE_SET:
+    case TYPE_CODE_RANGE:
+    case TYPE_CODE_STRING:
+    case TYPE_CODE_BITSTRING:
+    case TYPE_CODE_ERROR:
+    case TYPE_CODE_MEMBER:
+    case TYPE_CODE_METHOD:
+    case TYPE_CODE_COMPLEX:
+    default:
+      break;
+    }
+
+  return value_cast (type, arg);
+}
+
+/* Determine a function's address and its return type from its value.
+   Calls error() if the function is not valid for calling.  */
+
+static CORE_ADDR
+find_function_addr (struct value *function, struct type **retval_type)
+{
+  register struct type *ftype = check_typedef (VALUE_TYPE (function));
+  register enum type_code code = TYPE_CODE (ftype);
+  struct type *value_type;
+  CORE_ADDR funaddr;
+
+  /* If it's a member function, just look at the function
+     part of it.  */
+
+  /* Determine address to call.  */
+  if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
+    {
+      funaddr = VALUE_ADDRESS (function);
+      value_type = TYPE_TARGET_TYPE (ftype);
+    }
+  else if (code == TYPE_CODE_PTR)
+    {
+      funaddr = value_as_address (function);
+      ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
+      if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
+         || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+       {
+         funaddr = CONVERT_FROM_FUNC_PTR_ADDR (funaddr);
+         value_type = TYPE_TARGET_TYPE (ftype);
+       }
+      else
+       value_type = builtin_type_int;
+    }
+  else if (code == TYPE_CODE_INT)
+    {
+      /* Handle the case of functions lacking debugging info.
+         Their values are characters since their addresses are char */
+      if (TYPE_LENGTH (ftype) == 1)
+       funaddr = value_as_address (value_addr (function));
+      else
+       /* Handle integer used as address of a function.  */
+       funaddr = (CORE_ADDR) value_as_long (function);
+
+      value_type = builtin_type_int;
+    }
+  else
+    error ("Invalid data type for function to be called.");
+
+  *retval_type = value_type;
+  return funaddr;
+}
+
+/* All this stuff with a dummy frame may seem unnecessarily complicated
+   (why not just save registers in GDB?).  The purpose of pushing a dummy
+   frame which looks just like a real frame is so that if you call a
+   function and then hit a breakpoint (get a signal, etc), "backtrace"
+   will look right.  Whether the backtrace needs to actually show the
+   stack at the time the inferior function was called is debatable, but
+   it certainly needs to not display garbage.  So if you are contemplating
+   making dummy frames be different from normal frames, consider that.  */
+
+/* Perform a function call in the inferior.
+   ARGS is a vector of values of arguments (NARGS of them).
+   FUNCTION is a value, the function to be called.
+   Returns a value representing what the function returned.
+   May fail to return, if a breakpoint or signal is hit
+   during the execution of the function.
+
+   ARGS is modified to contain coerced values. */
+
+static struct value *
+hand_function_call (struct value *function, int nargs, struct value **args)
+{
+  register CORE_ADDR sp;
+  register int i;
+  int rc;
+  CORE_ADDR start_sp;
+  /* CALL_DUMMY is an array of words (REGISTER_SIZE), but each word
+     is in host byte order.  Before calling FIX_CALL_DUMMY, we byteswap it
+     and remove any extra bytes which might exist because ULONGEST is
+     bigger than REGISTER_SIZE.
+
+     NOTE: This is pretty wierd, as the call dummy is actually a
+     sequence of instructions.  But CISC machines will have
+     to pack the instructions into REGISTER_SIZE units (and
+     so will RISC machines for which INSTRUCTION_SIZE is not
+     REGISTER_SIZE).
+
+     NOTE: This is pretty stupid.  CALL_DUMMY should be in strict
+     target byte order. */
+
+  static ULONGEST *dummy;
+  int sizeof_dummy1;
+  char *dummy1;
+  CORE_ADDR old_sp;
+  struct type *value_type;
+  unsigned char struct_return;
+  CORE_ADDR struct_addr = 0;
+  struct regcache *retbuf;
+  struct cleanup *retbuf_cleanup;
+  struct inferior_status *inf_status;
+  struct cleanup *inf_status_cleanup;
+  CORE_ADDR funaddr;
+  int using_gcc;               /* Set to version of gcc in use, or zero if not gcc */
+  CORE_ADDR real_pc;
+  struct type *param_type = NULL;
+  struct type *ftype = check_typedef (SYMBOL_TYPE (function));
+  int n_method_args = 0;
+
+  dummy = alloca (SIZEOF_CALL_DUMMY_WORDS);
+  sizeof_dummy1 = REGISTER_SIZE * SIZEOF_CALL_DUMMY_WORDS / sizeof (ULONGEST);
+  dummy1 = alloca (sizeof_dummy1);
+  memcpy (dummy, CALL_DUMMY_WORDS, SIZEOF_CALL_DUMMY_WORDS);
+
+  if (!target_has_execution)
+    noprocess ();
+
+  /* Create a cleanup chain that contains the retbuf (buffer
+     containing the register values).  This chain is create BEFORE the
+     inf_status chain so that the inferior status can cleaned up
+     (restored or discarded) without having the retbuf freed.  */
+  retbuf = regcache_xmalloc (current_gdbarch);
+  retbuf_cleanup = make_cleanup_regcache_xfree (retbuf);
+
+  /* A cleanup for the inferior status.  Create this AFTER the retbuf
+     so that this can be discarded or applied without interfering with
+     the regbuf.  */
+  inf_status = save_inferior_status (1);
+  inf_status_cleanup = make_cleanup_restore_inferior_status (inf_status);
+
+  /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers
+     (and POP_FRAME for restoring them).  (At least on most machines)
+     they are saved on the stack in the inferior.  */
+  PUSH_DUMMY_FRAME;
+
+  old_sp = read_sp ();
+
+  /* Ensure that the initial SP is correctly aligned.  */
+  if (gdbarch_frame_align_p (current_gdbarch))
+    {
+      /* NOTE: cagney/2002-09-18:
+
+        On a RISC architecture, a void parameterless generic dummy
+        frame (i.e., no parameters, no result) typically does not
+        need to push anything the stack and hence can leave SP and
+        FP.  Similarly, a framelss (possibly leaf) function does not
+        push anything on the stack and, hence, that too can leave FP
+        and SP unchanged.  As a consequence, a sequence of void
+        parameterless generic dummy frame calls to frameless
+        functions will create a sequence of effectively identical
+        frames (SP, FP and TOS and PC the same).  This, not
+        suprisingly, results in what appears to be a stack in an
+        infinite loop --- when GDB tries to find a generic dummy
+        frame on the internal dummy frame stack, it will always find
+        the first one.
+
+        To avoid this problem, the code below always grows the stack.
+        That way, two dummy frames can never be identical.  It does
+        burn a few bytes of stack but that is a small price to pay
+        :-).  */
+      sp = gdbarch_frame_align (current_gdbarch, old_sp);
+      if (sp == old_sp)
+       {
+         if (INNER_THAN (1, 2))
+           /* Stack grows down.  */
+           sp = gdbarch_frame_align (current_gdbarch, old_sp - 1);
+         else
+           /* Stack grows up.  */
+           sp = gdbarch_frame_align (current_gdbarch, old_sp + 1);
+       }
+      gdb_assert ((INNER_THAN (1, 2) && sp <= old_sp)
+                 || (INNER_THAN (2, 1) && sp >= old_sp));
+    }
+  else
+    /* FIXME: cagney/2002-09-18: Hey, you loose!  Who knows how badly
+       aligned the SP is!  Further, per comment above, if the generic
+       dummy frame ends up empty (because nothing is pushed) GDB won't
+       be able to correctly perform back traces.  If a target is
+       having trouble with backtraces, first thing to do is add
+       FRAME_ALIGN() to its architecture vector.  After that, try
+       adding SAVE_DUMMY_FRAME_TOS() and modifying FRAME_CHAIN so that
+       when the next outer frame is a generic dummy, it returns the
+       current frame's base.  */
+    sp = old_sp;
+
+  if (INNER_THAN (1, 2))
+    {
+      /* Stack grows down */
+      sp -= sizeof_dummy1;
+      start_sp = sp;
+    }
+  else
+    {
+      /* Stack grows up */
+      start_sp = sp;
+      sp += sizeof_dummy1;
+    }
+
+  /* NOTE: cagney/2002-09-10: Don't bother re-adjusting the stack
+     after allocating space for the call dummy.  A target can specify
+     a SIZEOF_DUMMY1 (via SIZEOF_CALL_DUMMY_WORDS) such that all local
+     alignment requirements are met.  */
+
+  funaddr = find_function_addr (function, &value_type);
+  CHECK_TYPEDEF (value_type);
+
+  {
+    struct block *b = block_for_pc (funaddr);
+    /* If compiled without -g, assume GCC 2.  */
+    using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
+  }
+
+  /* Are we returning a value using a structure return or a normal
+     value return? */
+
+  struct_return = using_struct_return (function, funaddr, value_type,
+                                      using_gcc);
+
+  /* Create a call sequence customized for this function
+     and the number of arguments for it.  */
+  for (i = 0; i < (int) (SIZEOF_CALL_DUMMY_WORDS / sizeof (dummy[0])); i++)
+    store_unsigned_integer (&dummy1[i * REGISTER_SIZE],
+                           REGISTER_SIZE,
+                           (ULONGEST) dummy[i]);
+
+#ifdef GDB_TARGET_IS_HPPA
+  real_pc = FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
+                           value_type, using_gcc);
+#else
+  FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
+                 value_type, using_gcc);
+  real_pc = start_sp;
+#endif
+
+  if (CALL_DUMMY_LOCATION == ON_STACK)
+    {
+      write_memory (start_sp, (char *) dummy1, sizeof_dummy1);
+      if (USE_GENERIC_DUMMY_FRAMES)
+       generic_save_call_dummy_addr (start_sp, start_sp + sizeof_dummy1);
+    }
+
+  if (CALL_DUMMY_LOCATION == BEFORE_TEXT_END)
+    {
+      /* Convex Unix prohibits executing in the stack segment. */
+      /* Hope there is empty room at the top of the text segment. */
+      extern CORE_ADDR text_end;
+      static int checked = 0;
+      if (!checked)
+       for (start_sp = text_end - sizeof_dummy1; start_sp < text_end; ++start_sp)
+         if (read_memory_integer (start_sp, 1) != 0)
+           error ("text segment full -- no place to put call");
+      checked = 1;
+      sp = old_sp;
+      real_pc = text_end - sizeof_dummy1;
+      write_memory (real_pc, (char *) dummy1, sizeof_dummy1);
+      if (USE_GENERIC_DUMMY_FRAMES)
+       generic_save_call_dummy_addr (real_pc, real_pc + sizeof_dummy1);
+    }
+
+  if (CALL_DUMMY_LOCATION == AFTER_TEXT_END)
+    {
+      extern CORE_ADDR text_end;
+      int errcode;
+      sp = old_sp;
+      real_pc = text_end;
+      errcode = target_write_memory (real_pc, (char *) dummy1, sizeof_dummy1);
+      if (errcode != 0)
+       error ("Cannot write text segment -- call_function failed");
+      if (USE_GENERIC_DUMMY_FRAMES)
+       generic_save_call_dummy_addr (real_pc, real_pc + sizeof_dummy1);
+    }
+
+  if (CALL_DUMMY_LOCATION == AT_ENTRY_POINT)
+    {
+      real_pc = funaddr;
+      if (USE_GENERIC_DUMMY_FRAMES)
+       /* NOTE: cagney/2002-04-13: The entry point is going to be
+           modified with a single breakpoint.  */
+       generic_save_call_dummy_addr (CALL_DUMMY_ADDRESS (),
+                                     CALL_DUMMY_ADDRESS () + 1);
+    }
+
+#ifdef lint
+  sp = old_sp;                 /* It really is used, for some ifdef's... */
+#endif
+
+  if (nargs < TYPE_NFIELDS (ftype))
+    error ("too few arguments in function call");
+
+  for (i = nargs - 1; i >= 0; i--)
+    {
+      int prototyped;
+
+      /* FIXME drow/2002-05-31: Should just always mark methods as
+        prototyped.  Can we respect TYPE_VARARGS?  Probably not.  */
+      if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+       prototyped = 1;
+      else
+       prototyped = TYPE_PROTOTYPED (ftype);
+
+      if (i < TYPE_NFIELDS (ftype))
+       args[i] = value_arg_coerce (args[i], TYPE_FIELD_TYPE (ftype, i),
+                                   prototyped);
+      else
+       args[i] = value_arg_coerce (args[i], NULL, 0);
+
+      /*elz: this code is to handle the case in which the function to be called
+         has a pointer to function as parameter and the corresponding actual argument
+         is the address of a function and not a pointer to function variable.
+         In aCC compiled code, the calls through pointers to functions (in the body
+         of the function called by hand) are made via $$dyncall_external which
+         requires some registers setting, this is taken care of if we call
+         via a function pointer variable, but not via a function address.
+         In cc this is not a problem. */
+
+      if (using_gcc == 0)
+       if (param_type && TYPE_CODE (ftype) != TYPE_CODE_METHOD)
+         /* if this parameter is a pointer to function */
+         if (TYPE_CODE (param_type) == TYPE_CODE_PTR)
+           if (TYPE_CODE (TYPE_TARGET_TYPE (param_type)) == TYPE_CODE_FUNC)
+             /* elz: FIXME here should go the test about the compiler used
+                to compile the target. We want to issue the error
+                message only if the compiler used was HP's aCC.
+                If we used HP's cc, then there is no problem and no need
+                to return at this point */
+             if (using_gcc == 0)       /* && compiler == aCC */
+               /* go see if the actual parameter is a variable of type
+                  pointer to function or just a function */
+               if (args[i]->lval == not_lval)
+                 {
+                   char *arg_name;
+                   if (find_pc_partial_function ((CORE_ADDR) args[i]->aligner.contents[0], &arg_name, NULL, NULL))
+                     error ("\
+You cannot use function <%s> as argument. \n\
+You must use a pointer to function type variable. Command ignored.", arg_name);
+                 }
+    }
+
+  if (REG_STRUCT_HAS_ADDR_P ())
+    {
+      /* This is a machine like the sparc, where we may need to pass a
+        pointer to the structure, not the structure itself.  */
+      for (i = nargs - 1; i >= 0; i--)
+       {
+         struct type *arg_type = check_typedef (VALUE_TYPE (args[i]));
+         if ((TYPE_CODE (arg_type) == TYPE_CODE_STRUCT
+              || TYPE_CODE (arg_type) == TYPE_CODE_UNION
+              || TYPE_CODE (arg_type) == TYPE_CODE_ARRAY
+              || TYPE_CODE (arg_type) == TYPE_CODE_STRING
+              || TYPE_CODE (arg_type) == TYPE_CODE_BITSTRING
+              || TYPE_CODE (arg_type) == TYPE_CODE_SET
+              || (TYPE_CODE (arg_type) == TYPE_CODE_FLT
+                  && TYPE_LENGTH (arg_type) > 8)
+              )
+             && REG_STRUCT_HAS_ADDR (using_gcc, arg_type))
+           {
+             CORE_ADDR addr;
+             int len;          /*  = TYPE_LENGTH (arg_type); */
+             int aligned_len;
+             arg_type = check_typedef (VALUE_ENCLOSING_TYPE (args[i]));
+             len = TYPE_LENGTH (arg_type);
+
+             if (STACK_ALIGN_P ())
+               /* MVS 11/22/96: I think at least some of this
+                  stack_align code is really broken.  Better to let
+                  PUSH_ARGUMENTS adjust the stack in a target-defined
+                  manner.  */
+               aligned_len = STACK_ALIGN (len);
+             else
+               aligned_len = len;
+             if (INNER_THAN (1, 2))
+               {
+                 /* stack grows downward */
+                 sp -= aligned_len;
+                 /* ... so the address of the thing we push is the
+                    stack pointer after we push it.  */
+                 addr = sp;
+               }
+             else
+               {
+                 /* The stack grows up, so the address of the thing
+                    we push is the stack pointer before we push it.  */
+                 addr = sp;
+                 sp += aligned_len;
+               }
+             /* Push the structure.  */
+             write_memory (addr, VALUE_CONTENTS_ALL (args[i]), len);
+             /* The value we're going to pass is the address of the
+                thing we just pushed.  */
+             /*args[i] = value_from_longest (lookup_pointer_type (value_type),
+               (LONGEST) addr); */
+             args[i] = value_from_pointer (lookup_pointer_type (arg_type),
+                                           addr);
+           }
+       }
+    }
+
+
+  /* Reserve space for the return structure to be written on the
+     stack, if necessary.  Make certain that the value is correctly
+     aligned. */
+
+  if (struct_return)
+    {
+      int len = TYPE_LENGTH (value_type);
+      if (STACK_ALIGN_P ())
+       /* MVS 11/22/96: I think at least some of this stack_align
+          code is really broken.  Better to let PUSH_ARGUMENTS adjust
+          the stack in a target-defined manner.  */
+       len = STACK_ALIGN (len);
+      if (INNER_THAN (1, 2))
+       {
+         /* Stack grows downward.  Align STRUCT_ADDR and SP after
+             making space for the return value.  */
+         sp -= len;
+         if (gdbarch_frame_align_p (current_gdbarch))
+           sp = gdbarch_frame_align (current_gdbarch, sp);
+         struct_addr = sp;
+       }
+      else
+       {
+         /* Stack grows upward.  Align the frame, allocate space, and
+             then again, re-align the frame??? */
+         if (gdbarch_frame_align_p (current_gdbarch))
+           sp = gdbarch_frame_align (current_gdbarch, sp);
+         struct_addr = sp;
+         sp += len;
+         if (gdbarch_frame_align_p (current_gdbarch))
+           sp = gdbarch_frame_align (current_gdbarch, sp);
+       }
+    }
+
+  /* elz: on HPPA no need for this extra alignment, maybe it is needed
+     on other architectures. This is because all the alignment is
+     taken care of in the above code (ifdef REG_STRUCT_HAS_ADDR) and
+     in hppa_push_arguments */
+  if (EXTRA_STACK_ALIGNMENT_NEEDED)
+    {
+      /* MVS 11/22/96: I think at least some of this stack_align code
+        is really broken.  Better to let PUSH_ARGUMENTS adjust the
+        stack in a target-defined manner.  */
+      if (STACK_ALIGN_P () && INNER_THAN (1, 2))
+       {
+         /* If stack grows down, we must leave a hole at the top. */
+         int len = 0;
+
+         for (i = nargs - 1; i >= 0; i--)
+           len += TYPE_LENGTH (VALUE_ENCLOSING_TYPE (args[i]));
+         if (CALL_DUMMY_STACK_ADJUST_P)
+           len += CALL_DUMMY_STACK_ADJUST;
+         sp -= STACK_ALIGN (len) - len;
+       }
+    }
+
+  sp = PUSH_ARGUMENTS (nargs, args, sp, struct_return, struct_addr);
+
+  if (PUSH_RETURN_ADDRESS_P ())
+    /* for targets that use no CALL_DUMMY */
+    /* There are a number of targets now which actually don't write
+       any CALL_DUMMY instructions into the target, but instead just
+       save the machine state, push the arguments, and jump directly
+       to the callee function.  Since this doesn't actually involve
+       executing a JSR/BSR instruction, the return address must be set
+       up by hand, either by pushing onto the stack or copying into a
+       return-address register as appropriate.  Formerly this has been
+       done in PUSH_ARGUMENTS, but that's overloading its
+       functionality a bit, so I'm making it explicit to do it here.  */
+    sp = PUSH_RETURN_ADDRESS (real_pc, sp);
+
+  if (STACK_ALIGN_P () && !INNER_THAN (1, 2))
+    {
+      /* If stack grows up, we must leave a hole at the bottom, note
+         that sp already has been advanced for the arguments!  */
+      if (CALL_DUMMY_STACK_ADJUST_P)
+       sp += CALL_DUMMY_STACK_ADJUST;
+      sp = STACK_ALIGN (sp);
+    }
+
+/* XXX This seems wrong.  For stacks that grow down we shouldn't do
+   anything here!  */
+  /* MVS 11/22/96: I think at least some of this stack_align code is
+     really broken.  Better to let PUSH_ARGUMENTS adjust the stack in
+     a target-defined manner.  */
+  if (CALL_DUMMY_STACK_ADJUST_P)
+    if (INNER_THAN (1, 2))
+      {
+       /* stack grows downward */
+       sp -= CALL_DUMMY_STACK_ADJUST;
+      }
+
+  /* Store the address at which the structure is supposed to be
+     written.  Note that this (and the code which reserved the space
+     above) assumes that gcc was used to compile this function.  Since
+     it doesn't cost us anything but space and if the function is pcc
+     it will ignore this value, we will make that assumption.
+
+     Also note that on some machines (like the sparc) pcc uses a
+     convention like gcc's.  */
+
+  if (struct_return)
+    STORE_STRUCT_RETURN (struct_addr, sp);
+
+  /* Write the stack pointer.  This is here because the statements above
+     might fool with it.  On SPARC, this write also stores the register
+     window into the right place in the new stack frame, which otherwise
+     wouldn't happen.  (See store_inferior_registers in sparc-nat.c.)  */
+  write_sp (sp);
+
+  if (SAVE_DUMMY_FRAME_TOS_P ())
+    SAVE_DUMMY_FRAME_TOS (sp);
+
+  {
+    char *name;
+    struct symbol *symbol;
+
+    name = NULL;
+    symbol = find_pc_function (funaddr);
+    if (symbol)
+      {
+       name = SYMBOL_SOURCE_NAME (symbol);
+      }
+    else
+      {
+       /* Try the minimal symbols.  */
+       struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr);
+
+       if (msymbol)
+         {
+           name = SYMBOL_SOURCE_NAME (msymbol);
+         }
+      }
+    if (name == NULL)
+      {
+       char format[80];
+       sprintf (format, "at %s", local_hex_format ());
+       name = alloca (80);
+       /* FIXME-32x64: assumes funaddr fits in a long.  */
+       sprintf (name, format, (unsigned long) funaddr);
+      }
+
+    /* Execute the stack dummy routine, calling FUNCTION.
+       When it is done, discard the empty frame
+       after storing the contents of all regs into retbuf.  */
+    rc = run_stack_dummy (real_pc + CALL_DUMMY_START_OFFSET, retbuf);
+
+    if (rc == 1)
+      {
+       /* We stopped inside the FUNCTION because of a random signal.
+          Further execution of the FUNCTION is not allowed. */
+
+        if (unwind_on_signal_p)
+         {
+           /* The user wants the context restored. */
+
+            /* We must get back to the frame we were before the dummy call. */
+            POP_FRAME;
+
+           /* FIXME: Insert a bunch of wrap_here; name can be very long if it's
+              a C++ name with arguments and stuff.  */
+           error ("\
+The program being debugged was signaled while in a function called from GDB.\n\
+GDB has restored the context to what it was before the call.\n\
+To change this behavior use \"set unwindonsignal off\"\n\
+Evaluation of the expression containing the function (%s) will be abandoned.",
+                  name);
+         }
+       else
+         {
+           /* The user wants to stay in the frame where we stopped (default).*/
+
+           /* If we restored the inferior status (via the cleanup),
+              we would print a spurious error message (Unable to
+              restore previously selected frame), would write the
+              registers from the inf_status (which is wrong), and
+              would do other wrong things.  */
+           discard_cleanups (inf_status_cleanup);
+           discard_inferior_status (inf_status);
+
+           /* FIXME: Insert a bunch of wrap_here; name can be very long if it's
+              a C++ name with arguments and stuff.  */
+           error ("\
+The program being debugged was signaled while in a function called from GDB.\n\
+GDB remains in the frame where the signal was received.\n\
+To change this behavior use \"set unwindonsignal on\"\n\
+Evaluation of the expression containing the function (%s) will be abandoned.",
+                  name);
+         }
+      }
+
+    if (rc == 2)
+      {
+       /* We hit a breakpoint inside the FUNCTION. */
+
+       /* If we restored the inferior status (via the cleanup), we
+          would print a spurious error message (Unable to restore
+          previously selected frame), would write the registers from
+          the inf_status (which is wrong), and would do other wrong
+          things.  */
+       discard_cleanups (inf_status_cleanup);
+       discard_inferior_status (inf_status);
+
+       /* The following error message used to say "The expression
+          which contained the function call has been discarded."  It
+          is a hard concept to explain in a few words.  Ideally, GDB
+          would be able to resume evaluation of the expression when
+          the function finally is done executing.  Perhaps someday
+          this will be implemented (it would not be easy).  */
+
+       /* FIXME: Insert a bunch of wrap_here; name can be very long if it's
+          a C++ name with arguments and stuff.  */
+       error ("\
+The program being debugged stopped while in a function called from GDB.\n\
+When the function (%s) is done executing, GDB will silently\n\
+stop (instead of continuing to evaluate the expression containing\n\
+the function call).", name);
+      }
+
+    /* If we get here the called FUNCTION run to completion. */
+
+    /* Restore the inferior status, via its cleanup.  At this stage,
+       leave the RETBUF alone.  */
+    do_cleanups (inf_status_cleanup);
+
+    /* Figure out the value returned by the function.  */
+    /* elz: I defined this new macro for the hppa architecture only.
+       this gives us a way to get the value returned by the function
+       from the stack, at the same address we told the function to put
+       it.  We cannot assume on the pa that r28 still contains the
+       address of the returned structure. Usually this will be
+       overwritten by the callee.  I don't know about other
+       architectures, so I defined this macro */
+#ifdef VALUE_RETURNED_FROM_STACK
+    if (struct_return)
+      {
+       do_cleanups (retbuf_cleanup);
+       return VALUE_RETURNED_FROM_STACK (value_type, struct_addr);
+      }
+#endif
+    /* NOTE: cagney/2002-09-10: Only when the stack has been correctly
+       aligned (using frame_align()) do we can trust STRUCT_ADDR and
+       fetch the return value direct from the stack.  This lack of
+       trust comes about because legacy targets have a nasty habit of
+       silently, and local to PUSH_ARGUMENTS(), moving STRUCT_ADDR.
+       For such targets, just hope that value_being_returned() can
+       find the adjusted value.  */
+    if (struct_return && gdbarch_frame_align_p (current_gdbarch))
+      {
+        struct value *retval = value_at (value_type, struct_addr, NULL);
+        do_cleanups (retbuf_cleanup);
+        return retval;
+      }
+    else
+      {
+       struct value *retval = value_being_returned (value_type, retbuf,
+                                                    struct_return);
+       do_cleanups (retbuf_cleanup);
+       return retval;
+      }
+  }
+}
+
+struct value *
+call_function_by_hand (struct value *function, int nargs, struct value **args)
+{
+  if (CALL_DUMMY_P)
+    {
+      return hand_function_call (function, nargs, args);
+    }
+  else
+    {
+      error ("Cannot invoke functions on this machine.");
+    }
+}
+\f
+
+
+/* Create a value for an array by allocating space in the inferior, copying
+   the data into that space, and then setting up an array value.
+
+   The array bounds are set from LOWBOUND and HIGHBOUND, and the array is
+   populated from the values passed in ELEMVEC.
+
+   The element type of the array is inherited from the type of the
+   first element, and all elements must have the same size (though we
+   don't currently enforce any restriction on their types). */
+
+struct value *
+value_array (int lowbound, int highbound, struct value **elemvec)
+{
+  int nelem;
+  int idx;
+  unsigned int typelength;
+  struct value *val;
+  struct type *rangetype;
+  struct type *arraytype;
+  CORE_ADDR addr;
+
+  /* Validate that the bounds are reasonable and that each of the elements
+     have the same size. */
+
+  nelem = highbound - lowbound + 1;
+  if (nelem <= 0)
+    {
+      error ("bad array bounds (%d, %d)", lowbound, highbound);
+    }
+  typelength = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (elemvec[0]));
+  for (idx = 1; idx < nelem; idx++)
+    {
+      if (TYPE_LENGTH (VALUE_ENCLOSING_TYPE (elemvec[idx])) != typelength)
+       {
+         error ("array elements must all be the same size");
+       }
+    }
+
+  rangetype = create_range_type ((struct type *) NULL, builtin_type_int,
+                                lowbound, highbound);
+  arraytype = create_array_type ((struct type *) NULL,
+                             VALUE_ENCLOSING_TYPE (elemvec[0]), rangetype);
+
+  if (!current_language->c_style_arrays)
+    {
+      val = allocate_value (arraytype);
+      for (idx = 0; idx < nelem; idx++)
+       {
+         memcpy (VALUE_CONTENTS_ALL_RAW (val) + (idx * typelength),
+                 VALUE_CONTENTS_ALL (elemvec[idx]),
+                 typelength);
+       }
+      VALUE_BFD_SECTION (val) = VALUE_BFD_SECTION (elemvec[0]);
+      return val;
+    }
+
+  /* Allocate space to store the array in the inferior, and then initialize
+     it by copying in each element.  FIXME:  Is it worth it to create a
+     local buffer in which to collect each value and then write all the
+     bytes in one operation? */
+
+  addr = allocate_space_in_inferior (nelem * typelength);
+  for (idx = 0; idx < nelem; idx++)
+    {
+      write_memory (addr + (idx * typelength), VALUE_CONTENTS_ALL (elemvec[idx]),
+                   typelength);
+    }
+
+  /* Create the array type and set up an array value to be evaluated lazily. */
+
+  val = value_at_lazy (arraytype, addr, VALUE_BFD_SECTION (elemvec[0]));
+  return (val);
+}
+
+/* Create a value for a string constant by allocating space in the inferior,
+   copying the data into that space, and returning the address with type
+   TYPE_CODE_STRING.  PTR points to the string constant data; LEN is number
+   of characters.
+   Note that string types are like array of char types with a lower bound of
+   zero and an upper bound of LEN - 1.  Also note that the string may contain
+   embedded null bytes. */
+
+struct value *
+value_string (char *ptr, int len)
+{
+  struct value *val;
+  int lowbound = current_language->string_lower_bound;
+  struct type *rangetype = create_range_type ((struct type *) NULL,
+                                             builtin_type_int,
+                                             lowbound, len + lowbound - 1);
+  struct type *stringtype
+  = create_string_type ((struct type *) NULL, rangetype);
+  CORE_ADDR addr;
+
+  if (current_language->c_style_arrays == 0)
+    {
+      val = allocate_value (stringtype);
+      memcpy (VALUE_CONTENTS_RAW (val), ptr, len);
+      return val;
+    }
+
+
+  /* Allocate space to store the string in the inferior, and then
+     copy LEN bytes from PTR in gdb to that address in the inferior. */
+
+  addr = allocate_space_in_inferior (len);
+  write_memory (addr, ptr, len);
+
+  val = value_at_lazy (stringtype, addr, NULL);
+  return (val);
+}
+
+struct value *
+value_bitstring (char *ptr, int len)
+{
+  struct value *val;
+  struct type *domain_type = create_range_type (NULL, builtin_type_int,
+                                               0, len - 1);
+  struct type *type = create_set_type ((struct type *) NULL, domain_type);
+  TYPE_CODE (type) = TYPE_CODE_BITSTRING;
+  val = allocate_value (type);
+  memcpy (VALUE_CONTENTS_RAW (val), ptr, TYPE_LENGTH (type));
+  return val;
+}
+\f
+/* See if we can pass arguments in T2 to a function which takes arguments
+   of types T1.  T1 is a list of NARGS arguments, and T2 is a NULL-terminated
+   vector.  If some arguments need coercion of some sort, then the coerced
+   values are written into T2.  Return value is 0 if the arguments could be
+   matched, or the position at which they differ if not.
+
+   STATICP is nonzero if the T1 argument list came from a
+   static member function.  T2 will still include the ``this'' pointer,
+   but it will be skipped.
+
+   For non-static member functions, we ignore the first argument,
+   which is the type of the instance variable.  This is because we want
+   to handle calls with objects from derived classes.  This is not
+   entirely correct: we should actually check to make sure that a
+   requested operation is type secure, shouldn't we?  FIXME.  */
+
+static int
+typecmp (int staticp, int varargs, int nargs,
+        struct field t1[], struct value *t2[])
+{
+  int i;
+
+  if (t2 == 0)
+    internal_error (__FILE__, __LINE__, "typecmp: no argument list");
+
+  /* Skip ``this'' argument if applicable.  T2 will always include THIS.  */
+  if (staticp)
+    t2 ++;
+
+  for (i = 0;
+       (i < nargs) && TYPE_CODE (t1[i].type) != TYPE_CODE_VOID;
+       i++)
+    {
+      struct type *tt1, *tt2;
+
+      if (!t2[i])
+       return i + 1;
+
+      tt1 = check_typedef (t1[i].type);
+      tt2 = check_typedef (VALUE_TYPE (t2[i]));
+
+      if (TYPE_CODE (tt1) == TYPE_CODE_REF
+      /* We should be doing hairy argument matching, as below.  */
+         && (TYPE_CODE (check_typedef (TYPE_TARGET_TYPE (tt1))) == TYPE_CODE (tt2)))
+       {
+         if (TYPE_CODE (tt2) == TYPE_CODE_ARRAY)
+           t2[i] = value_coerce_array (t2[i]);
+         else
+           t2[i] = value_addr (t2[i]);
+         continue;
+       }
+
+      /* djb - 20000715 - Until the new type structure is in the
+        place, and we can attempt things like implicit conversions,
+        we need to do this so you can take something like a map<const
+        char *>, and properly access map["hello"], because the
+        argument to [] will be a reference to a pointer to a char,
+        and the argument will be a pointer to a char. */
+      while ( TYPE_CODE(tt1) == TYPE_CODE_REF ||
+             TYPE_CODE (tt1) == TYPE_CODE_PTR)
+       {
+         tt1 = check_typedef( TYPE_TARGET_TYPE(tt1) );
+       }
+      while ( TYPE_CODE(tt2) == TYPE_CODE_ARRAY ||
+             TYPE_CODE(tt2) == TYPE_CODE_PTR ||
+             TYPE_CODE(tt2) == TYPE_CODE_REF)
+       {
+         tt2 = check_typedef( TYPE_TARGET_TYPE(tt2) );
+       }
+      if (TYPE_CODE (tt1) == TYPE_CODE (tt2))
+       continue;
+      /* Array to pointer is a `trivial conversion' according to the ARM.  */
+
+      /* We should be doing much hairier argument matching (see section 13.2
+         of the ARM), but as a quick kludge, just check for the same type
+         code.  */
+      if (TYPE_CODE (t1[i].type) != TYPE_CODE (VALUE_TYPE (t2[i])))
+       return i + 1;
+    }
+  if (varargs || t2[i] == NULL)
+    return 0;
+  return i + 1;
+}
+
+/* Helper function used by value_struct_elt to recurse through baseclasses.
+   Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes,
+   and search in it assuming it has (class) type TYPE.
+   If found, return value, else return NULL.
+
+   If LOOKING_FOR_BASECLASS, then instead of looking for struct fields,
+   look for a baseclass named NAME.  */
+
+static struct value *
+search_struct_field (char *name, struct value *arg1, int offset,
+                    register struct type *type, int looking_for_baseclass)
+{
+  int i;
+  int nbases = TYPE_N_BASECLASSES (type);
+
+  CHECK_TYPEDEF (type);
+
+  if (!looking_for_baseclass)
+    for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--)
+      {
+       char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+       if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
+         {
+           struct value *v;
+           if (TYPE_FIELD_STATIC (type, i))
+             {
+               v = value_static_field (type, i);
+               if (v == 0)
+                 error ("field %s is nonexistent or has been optimised out",
+                        name);
+             }
+           else
+             {
+               v = value_primitive_field (arg1, offset, i, type);
+               if (v == 0)
+                 error ("there is no field named %s", name);
+             }
+           return v;
+         }
+
+       if (t_field_name
+           && (t_field_name[0] == '\0'
+               || (TYPE_CODE (type) == TYPE_CODE_UNION
+                   && (strcmp_iw (t_field_name, "else") == 0))))
+         {
+           struct type *field_type = TYPE_FIELD_TYPE (type, i);
+           if (TYPE_CODE (field_type) == TYPE_CODE_UNION
+               || TYPE_CODE (field_type) == TYPE_CODE_STRUCT)
+             {
+               /* Look for a match through the fields of an anonymous union,
+                  or anonymous struct.  C++ provides anonymous unions.
+
+                  In the GNU Chill (OBSOLETE) implementation of
+                  variant record types, each <alternative field> has
+                  an (anonymous) union type, each member of the union
+                  represents a <variant alternative>.  Each <variant
+                  alternative> is represented as a struct, with a
+                  member for each <variant field>.  */
+
+               struct value *v;
+               int new_offset = offset;
+
+               /* This is pretty gross.  In G++, the offset in an
+                  anonymous union is relative to the beginning of the
+                  enclosing struct.  In the GNU Chill (OBSOLETE)
+                  implementation of variant records, the bitpos is
+                  zero in an anonymous union field, so we have to add
+                  the offset of the union here. */
+               if (TYPE_CODE (field_type) == TYPE_CODE_STRUCT
+                   || (TYPE_NFIELDS (field_type) > 0
+                       && TYPE_FIELD_BITPOS (field_type, 0) == 0))
+                 new_offset += TYPE_FIELD_BITPOS (type, i) / 8;
+
+               v = search_struct_field (name, arg1, new_offset, field_type,
+                                        looking_for_baseclass);
+               if (v)
+                 return v;
+             }
+         }
+      }
+
+  for (i = 0; i < nbases; i++)
+    {
+      struct value *v;
+      struct type *basetype = check_typedef (TYPE_BASECLASS (type, i));
+      /* If we are looking for baseclasses, this is what we get when we
+         hit them.  But it could happen that the base part's member name
+         is not yet filled in.  */
+      int found_baseclass = (looking_for_baseclass
+                            && TYPE_BASECLASS_NAME (type, i) != NULL
+                            && (strcmp_iw (name, TYPE_BASECLASS_NAME (type, i)) == 0));
+
+      if (BASETYPE_VIA_VIRTUAL (type, i))
+       {
+         int boffset;
+         struct value *v2 = allocate_value (basetype);
+
+         boffset = baseclass_offset (type, i,
+                                     VALUE_CONTENTS (arg1) + offset,
+                                     VALUE_ADDRESS (arg1)
+                                     + VALUE_OFFSET (arg1) + offset);
+         if (boffset == -1)
+           error ("virtual baseclass botch");
+
+         /* The virtual base class pointer might have been clobbered by the
+            user program. Make sure that it still points to a valid memory
+            location.  */
+
+         boffset += offset;
+         if (boffset < 0 || boffset >= TYPE_LENGTH (type))
+           {
+             CORE_ADDR base_addr;
+
+             base_addr = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1) + boffset;
+             if (target_read_memory (base_addr, VALUE_CONTENTS_RAW (v2),
+                                     TYPE_LENGTH (basetype)) != 0)
+               error ("virtual baseclass botch");
+             VALUE_LVAL (v2) = lval_memory;
+             VALUE_ADDRESS (v2) = base_addr;
+           }
+         else
+           {
+             VALUE_LVAL (v2) = VALUE_LVAL (arg1);
+             VALUE_ADDRESS (v2) = VALUE_ADDRESS (arg1);
+             VALUE_OFFSET (v2) = VALUE_OFFSET (arg1) + boffset;
+             if (VALUE_LAZY (arg1))
+               VALUE_LAZY (v2) = 1;
+             else
+               memcpy (VALUE_CONTENTS_RAW (v2),
+                       VALUE_CONTENTS_RAW (arg1) + boffset,
+                       TYPE_LENGTH (basetype));
+           }
+
+         if (found_baseclass)
+           return v2;
+         v = search_struct_field (name, v2, 0, TYPE_BASECLASS (type, i),
+                                  looking_for_baseclass);
+       }
+      else if (found_baseclass)
+       v = value_primitive_field (arg1, offset, i, type);
+      else
+       v = search_struct_field (name, arg1,
+                              offset + TYPE_BASECLASS_BITPOS (type, i) / 8,
+                                basetype, looking_for_baseclass);
+      if (v)
+       return v;
+    }
+  return NULL;
+}
+
+
+/* Return the offset (in bytes) of the virtual base of type BASETYPE
+ * in an object pointed to by VALADDR (on the host), assumed to be of
+ * type TYPE.  OFFSET is number of bytes beyond start of ARG to start
+ * looking (in case VALADDR is the contents of an enclosing object).
+ *
+ * This routine recurses on the primary base of the derived class because
+ * the virtual base entries of the primary base appear before the other
+ * virtual base entries.
+ *
+ * If the virtual base is not found, a negative integer is returned.
+ * The magnitude of the negative integer is the number of entries in
+ * the virtual table to skip over (entries corresponding to various
+ * ancestral classes in the chain of primary bases).
+ *
+ * Important: This assumes the HP / Taligent C++ runtime
+ * conventions. Use baseclass_offset() instead to deal with g++
+ * conventions.  */
+
+void
+find_rt_vbase_offset (struct type *type, struct type *basetype, char *valaddr,
+                     int offset, int *boffset_p, int *skip_p)
+{
+  int boffset;                 /* offset of virtual base */
+  int index;                   /* displacement to use in virtual table */
+  int skip;
+
+  struct value *vp;
+  CORE_ADDR vtbl;              /* the virtual table pointer */
+  struct type *pbc;            /* the primary base class */
+
+  /* Look for the virtual base recursively in the primary base, first.
+   * This is because the derived class object and its primary base
+   * subobject share the primary virtual table.  */
+
+  boffset = 0;
+  pbc = TYPE_PRIMARY_BASE (type);
+  if (pbc)
+    {
+      find_rt_vbase_offset (pbc, basetype, valaddr, offset, &boffset, &skip);
+      if (skip < 0)
+       {
+         *boffset_p = boffset;
+         *skip_p = -1;
+         return;
+       }
+    }
+  else
+    skip = 0;
+
+
+  /* Find the index of the virtual base according to HP/Taligent
+     runtime spec. (Depth-first, left-to-right.)  */
+  index = virtual_base_index_skip_primaries (basetype, type);
+
+  if (index < 0)
+    {
+      *skip_p = skip + virtual_base_list_length_skip_primaries (type);
+      *boffset_p = 0;
+      return;
+    }
+
+  /* pai: FIXME -- 32x64 possible problem */
+  /* First word (4 bytes) in object layout is the vtable pointer */
+  vtbl = *(CORE_ADDR *) (valaddr + offset);
+
+  /* Before the constructor is invoked, things are usually zero'd out. */
+  if (vtbl == 0)
+    error ("Couldn't find virtual table -- object may not be constructed yet.");
+
+
+  /* Find virtual base's offset -- jump over entries for primary base
+   * ancestors, then use the index computed above.  But also adjust by
+   * HP_ACC_VBASE_START for the vtable slots before the start of the
+   * virtual base entries.  Offset is negative -- virtual base entries
+   * appear _before_ the address point of the virtual table. */
+
+  /* pai: FIXME -- 32x64 problem, if word = 8 bytes, change multiplier
+     & use long type */
+
+  /* epstein : FIXME -- added param for overlay section. May not be correct */
+  vp = value_at (builtin_type_int, vtbl + 4 * (-skip - index - HP_ACC_VBASE_START), NULL);
+  boffset = value_as_long (vp);
+  *skip_p = -1;
+  *boffset_p = boffset;
+  return;
+}
+
+
+/* Helper function used by value_struct_elt to recurse through baseclasses.
+   Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes,
+   and search in it assuming it has (class) type TYPE.
+   If found, return value, else if name matched and args not return (value)-1,
+   else return NULL. */
+
+static struct value *
+search_struct_method (char *name, struct value **arg1p,
+                     struct value **args, int offset,
+                     int *static_memfuncp, register struct type *type)
+{
+  int i;
+  struct value *v;
+  int name_matched = 0;
+  char dem_opname[64];
+
+  CHECK_TYPEDEF (type);
+  for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
+    {
+      char *t_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
+      /* FIXME!  May need to check for ARM demangling here */
+      if (strncmp (t_field_name, "__", 2) == 0 ||
+         strncmp (t_field_name, "op", 2) == 0 ||
+         strncmp (t_field_name, "type", 4) == 0)
+       {
+         if (cplus_demangle_opname (t_field_name, dem_opname, DMGL_ANSI))
+           t_field_name = dem_opname;
+         else if (cplus_demangle_opname (t_field_name, dem_opname, 0))
+           t_field_name = dem_opname;
+       }
+      if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
+       {
+         int j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1;
+         struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+         name_matched = 1;
+
+         check_stub_method_group (type, i);
+         if (j > 0 && args == 0)
+           error ("cannot resolve overloaded method `%s': no arguments supplied", name);
+         else if (j == 0 && args == 0)
+           {
+             v = value_fn_field (arg1p, f, j, type, offset);
+             if (v != NULL)
+               return v;
+           }
+         else
+           while (j >= 0)
+             {
+               if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j),
+                             TYPE_VARARGS (TYPE_FN_FIELD_TYPE (f, j)),
+                             TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (f, j)),
+                             TYPE_FN_FIELD_ARGS (f, j), args))
+                 {
+                   if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+                     return value_virtual_fn_field (arg1p, f, j, type, offset);
+                   if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp)
+                     *static_memfuncp = 1;
+                   v = value_fn_field (arg1p, f, j, type, offset);
+                   if (v != NULL)
+                     return v;       
+                 }
+               j--;
+             }
+       }
+    }
+
+  for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+    {
+      int base_offset;
+
+      if (BASETYPE_VIA_VIRTUAL (type, i))
+       {
+         if (TYPE_HAS_VTABLE (type))
+           {
+             /* HP aCC compiled type, search for virtual base offset
+                according to HP/Taligent runtime spec.  */
+             int skip;
+             find_rt_vbase_offset (type, TYPE_BASECLASS (type, i),
+                                   VALUE_CONTENTS_ALL (*arg1p),
+                                   offset + VALUE_EMBEDDED_OFFSET (*arg1p),
+                                   &base_offset, &skip);
+             if (skip >= 0)
+               error ("Virtual base class offset not found in vtable");
+           }
+         else
+           {
+             struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i));
+             char *base_valaddr;
+
+             /* The virtual base class pointer might have been clobbered by the
+                user program. Make sure that it still points to a valid memory
+                location.  */
+
+             if (offset < 0 || offset >= TYPE_LENGTH (type))
+               {
+                 base_valaddr = (char *) alloca (TYPE_LENGTH (baseclass));
+                 if (target_read_memory (VALUE_ADDRESS (*arg1p)
+                                         + VALUE_OFFSET (*arg1p) + offset,
+                                         base_valaddr,
+                                         TYPE_LENGTH (baseclass)) != 0)
+                   error ("virtual baseclass botch");
+               }
+             else
+               base_valaddr = VALUE_CONTENTS (*arg1p) + offset;
+
+             base_offset =
+               baseclass_offset (type, i, base_valaddr,
+                                 VALUE_ADDRESS (*arg1p)
+                                 + VALUE_OFFSET (*arg1p) + offset);
+             if (base_offset == -1)
+               error ("virtual baseclass botch");
+           }
+       }
+      else
+       {
+         base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8;
+       }
+      v = search_struct_method (name, arg1p, args, base_offset + offset,
+                               static_memfuncp, TYPE_BASECLASS (type, i));
+      if (v == (struct value *) - 1)
+       {
+         name_matched = 1;
+       }
+      else if (v)
+       {
+/* FIXME-bothner:  Why is this commented out?  Why is it here?  */
+/*        *arg1p = arg1_tmp; */
+         return v;
+       }
+    }
+  if (name_matched)
+    return (struct value *) - 1;
+  else
+    return NULL;
+}
+
+/* Given *ARGP, a value of type (pointer to a)* structure/union,
+   extract the component named NAME from the ultimate target structure/union
+   and return it as a value with its appropriate type.
+   ERR is used in the error message if *ARGP's type is wrong.
+
+   C++: ARGS is a list of argument types to aid in the selection of
+   an appropriate method. Also, handle derived types.
+
+   STATIC_MEMFUNCP, if non-NULL, points to a caller-supplied location
+   where the truthvalue of whether the function that was resolved was
+   a static member function or not is stored.
+
+   ERR is an error message to be printed in case the field is not found.  */
+
+struct value *
+value_struct_elt (struct value **argp, struct value **args,
+                 char *name, int *static_memfuncp, char *err)
+{
+  register struct type *t;
+  struct value *v;
+
+  COERCE_ARRAY (*argp);
+
+  t = check_typedef (VALUE_TYPE (*argp));
+
+  /* Follow pointers until we get to a non-pointer.  */
+
+  while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+    {
+      *argp = value_ind (*argp);
+      /* Don't coerce fn pointer to fn and then back again!  */
+      if (TYPE_CODE (VALUE_TYPE (*argp)) != TYPE_CODE_FUNC)
+       COERCE_ARRAY (*argp);
+      t = check_typedef (VALUE_TYPE (*argp));
+    }
+
+  if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
+    error ("not implemented: member type in value_struct_elt");
+
+  if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+      && TYPE_CODE (t) != TYPE_CODE_UNION)
+    error ("Attempt to extract a component of a value that is not a %s.", err);
+
+  /* Assume it's not, unless we see that it is.  */
+  if (static_memfuncp)
+    *static_memfuncp = 0;
+
+  if (!args)
+    {
+      /* if there are no arguments ...do this...  */
+
+      /* Try as a field first, because if we succeed, there
+         is less work to be done.  */
+      v = search_struct_field (name, *argp, 0, t, 0);
+      if (v)
+       return v;
+
+      /* C++: If it was not found as a data field, then try to
+         return it as a pointer to a method.  */
+
+      if (destructor_name_p (name, t))
+       error ("Cannot get value of destructor");
+
+      v = search_struct_method (name, argp, args, 0, static_memfuncp, t);
+
+      if (v == (struct value *) - 1)
+       error ("Cannot take address of a method");
+      else if (v == 0)
+       {
+         if (TYPE_NFN_FIELDS (t))
+           error ("There is no member or method named %s.", name);
+         else
+           error ("There is no member named %s.", name);
+       }
+      return v;
+    }
+
+  if (destructor_name_p (name, t))
+    {
+      if (!args[1])
+       {
+         /* Destructors are a special case.  */
+         int m_index, f_index;
+
+         v = NULL;
+         if (get_destructor_fn_field (t, &m_index, &f_index))
+           {
+             v = value_fn_field (NULL, TYPE_FN_FIELDLIST1 (t, m_index),
+                                 f_index, NULL, 0);
+           }
+         if (v == NULL)
+           error ("could not find destructor function named %s.", name);
+         else
+           return v;
+       }
+      else
+       {
+         error ("destructor should not have any argument");
+       }
+    }
+  else
+    v = search_struct_method (name, argp, args, 0, static_memfuncp, t);
+  
+  if (v == (struct value *) - 1)
+    {
+      error ("One of the arguments you tried to pass to %s could not be converted to what the function wants.", name);
+    }
+  else if (v == 0)
+    {
+      /* See if user tried to invoke data as function.  If so,
+         hand it back.  If it's not callable (i.e., a pointer to function),
+         gdb should give an error.  */
+      v = search_struct_field (name, *argp, 0, t, 0);
+    }
+
+  if (!v)
+    error ("Structure has no component named %s.", name);
+  return v;
+}
+
+/* Search through the methods of an object (and its bases)
+ * to find a specified method. Return the pointer to the
+ * fn_field list of overloaded instances.
+ * Helper function for value_find_oload_list.
+ * ARGP is a pointer to a pointer to a value (the object)
+ * METHOD is a string containing the method name
+ * OFFSET is the offset within the value
+ * TYPE is the assumed type of the object
+ * NUM_FNS is the number of overloaded instances
+ * BASETYPE is set to the actual type of the subobject where the method is found
+ * BOFFSET is the offset of the base subobject where the method is found */
+
+static struct fn_field *
+find_method_list (struct value **argp, char *method, int offset,
+                 struct type *type, int *num_fns,
+                 struct type **basetype, int *boffset)
+{
+  int i;
+  struct fn_field *f;
+  CHECK_TYPEDEF (type);
+
+  *num_fns = 0;
+
+  /* First check in object itself */
+  for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
+    {
+      /* pai: FIXME What about operators and type conversions? */
+      char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
+      if (fn_field_name && (strcmp_iw (fn_field_name, method) == 0))
+       {
+         int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
+         struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+
+         *num_fns = len;
+         *basetype = type;
+         *boffset = offset;
+
+         /* Resolve any stub methods.  */
+         check_stub_method_group (type, i);
+
+         return f;
+       }
+    }
+
+  /* Not found in object, check in base subobjects */
+  for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+    {
+      int base_offset;
+      if (BASETYPE_VIA_VIRTUAL (type, i))
+       {
+         if (TYPE_HAS_VTABLE (type))
+           {
+             /* HP aCC compiled type, search for virtual base offset
+              * according to HP/Taligent runtime spec.  */
+             int skip;
+             find_rt_vbase_offset (type, TYPE_BASECLASS (type, i),
+                                   VALUE_CONTENTS_ALL (*argp),
+                                   offset + VALUE_EMBEDDED_OFFSET (*argp),
+                                   &base_offset, &skip);
+             if (skip >= 0)
+               error ("Virtual base class offset not found in vtable");
+           }
+         else
+           {
+             /* probably g++ runtime model */
+             base_offset = VALUE_OFFSET (*argp) + offset;
+             base_offset =
+               baseclass_offset (type, i,
+                                 VALUE_CONTENTS (*argp) + base_offset,
+                                 VALUE_ADDRESS (*argp) + base_offset);
+             if (base_offset == -1)
+               error ("virtual baseclass botch");
+           }
+       }
+      else
+       /* non-virtual base, simply use bit position from debug info */
+       {
+         base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8;
+       }
+      f = find_method_list (argp, method, base_offset + offset,
+                           TYPE_BASECLASS (type, i), num_fns, basetype,
+                           boffset);
+      if (f)
+       return f;
+    }
+  return NULL;
+}
+
+/* Return the list of overloaded methods of a specified name.
+ * ARGP is a pointer to a pointer to a value (the object)
+ * METHOD is the method name
+ * OFFSET is the offset within the value contents
+ * NUM_FNS is the number of overloaded instances
+ * BASETYPE is set to the type of the base subobject that defines the method
+ * BOFFSET is the offset of the base subobject which defines the method */
+
+struct fn_field *
+value_find_oload_method_list (struct value **argp, char *method, int offset,
+                             int *num_fns, struct type **basetype,
+                             int *boffset)
+{
+  struct type *t;
+
+  t = check_typedef (VALUE_TYPE (*argp));
+
+  /* code snarfed from value_struct_elt */
+  while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+    {
+      *argp = value_ind (*argp);
+      /* Don't coerce fn pointer to fn and then back again!  */
+      if (TYPE_CODE (VALUE_TYPE (*argp)) != TYPE_CODE_FUNC)
+       COERCE_ARRAY (*argp);
+      t = check_typedef (VALUE_TYPE (*argp));
+    }
+
+  if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
+    error ("Not implemented: member type in value_find_oload_lis");
+
+  if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+      && TYPE_CODE (t) != TYPE_CODE_UNION)
+    error ("Attempt to extract a component of a value that is not a struct or union");
+
+  return find_method_list (argp, method, 0, t, num_fns, basetype, boffset);
+}
+
+/* Given an array of argument types (ARGTYPES) (which includes an
+   entry for "this" in the case of C++ methods), the number of
+   arguments NARGS, the NAME of a function whether it's a method or
+   not (METHOD), and the degree of laxness (LAX) in conforming to
+   overload resolution rules in ANSI C++, find the best function that
+   matches on the argument types according to the overload resolution
+   rules.
+
+   In the case of class methods, the parameter OBJ is an object value
+   in which to search for overloaded methods.
+
+   In the case of non-method functions, the parameter FSYM is a symbol
+   corresponding to one of the overloaded functions.
+
+   Return value is an integer: 0 -> good match, 10 -> debugger applied
+   non-standard coercions, 100 -> incompatible.
+
+   If a method is being searched for, VALP will hold the value.
+   If a non-method is being searched for, SYMP will hold the symbol for it.
+
+   If a method is being searched for, and it is a static method,
+   then STATICP will point to a non-zero value.
+
+   Note: This function does *not* check the value of
+   overload_resolution.  Caller must check it to see whether overload
+   resolution is permitted.
+ */
+
+int
+find_overload_match (struct type **arg_types, int nargs, char *name, int method,
+                    int lax, struct value **objp, struct symbol *fsym,
+                    struct value **valp, struct symbol **symp, int *staticp)
+{
+  int nparms;
+  struct type **parm_types;
+  int champ_nparms = 0;
+  struct value *obj = (objp ? *objp : NULL);
+
+  short oload_champ = -1;      /* Index of best overloaded function */
+  short oload_ambiguous = 0;   /* Current ambiguity state for overload resolution */
+  /* 0 => no ambiguity, 1 => two good funcs, 2 => incomparable funcs */
+  short oload_ambig_champ = -1;        /* 2nd contender for best match */
+  short oload_non_standard = 0;        /* did we have to use non-standard conversions? */
+  short oload_incompatible = 0;        /* are args supplied incompatible with any function? */
+
+  struct badness_vector *bv;   /* A measure of how good an overloaded instance is */
+  struct badness_vector *oload_champ_bv = NULL;                /* The measure for the current best match */
+
+  struct value *temp = obj;
+  struct fn_field *fns_ptr = NULL;     /* For methods, the list of overloaded methods */
+  struct symbol **oload_syms = NULL;   /* For non-methods, the list of overloaded function symbols */
+  int num_fns = 0;             /* Number of overloaded instances being considered */
+  struct type *basetype = NULL;
+  int boffset;
+  register int jj;
+  register int ix;
+  int static_offset;
+  struct cleanup *cleanups = NULL;
+
+  char *obj_type_name = NULL;
+  char *func_name = NULL;
+
+  /* Get the list of overloaded methods or functions */
+  if (method)
+    {
+      obj_type_name = TYPE_NAME (VALUE_TYPE (obj));
+      /* Hack: evaluate_subexp_standard often passes in a pointer
+         value rather than the object itself, so try again */
+      if ((!obj_type_name || !*obj_type_name) &&
+         (TYPE_CODE (VALUE_TYPE (obj)) == TYPE_CODE_PTR))
+       obj_type_name = TYPE_NAME (TYPE_TARGET_TYPE (VALUE_TYPE (obj)));
+
+      fns_ptr = value_find_oload_method_list (&temp, name, 0,
+                                             &num_fns,
+                                             &basetype, &boffset);
+      if (!fns_ptr || !num_fns)
+       error ("Couldn't find method %s%s%s",
+              obj_type_name,
+              (obj_type_name && *obj_type_name) ? "::" : "",
+              name);
+      /* If we are dealing with stub method types, they should have
+        been resolved by find_method_list via value_find_oload_method_list
+        above.  */
+      gdb_assert (TYPE_DOMAIN_TYPE (fns_ptr[0].type) != NULL);
+    }
+  else
+    {
+      int i = -1;
+      func_name = cplus_demangle (SYMBOL_NAME (fsym), DMGL_NO_OPTS);
+
+      /* If the name is NULL this must be a C-style function.
+         Just return the same symbol. */
+      if (!func_name)
+        {
+         *symp = fsym;
+          return 0;
+        }
+
+      oload_syms = make_symbol_overload_list (fsym);
+      cleanups = make_cleanup (xfree, oload_syms);
+      while (oload_syms[++i])
+       num_fns++;
+      if (!num_fns)
+       error ("Couldn't find function %s", func_name);
+    }
+
+  oload_champ_bv = NULL;
+
+  /* Consider each candidate in turn */
+  for (ix = 0; ix < num_fns; ix++)
+    {
+      static_offset = 0;
+      if (method)
+       {
+         if (TYPE_FN_FIELD_STATIC_P (fns_ptr, ix))
+           static_offset = 1;
+         nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
+       }
+      else
+       {
+         /* If it's not a method, this is the proper place */
+         nparms=TYPE_NFIELDS(SYMBOL_TYPE(oload_syms[ix]));
+       }
+
+      /* Prepare array of parameter types */
+      parm_types = (struct type **) xmalloc (nparms * (sizeof (struct type *)));
+      for (jj = 0; jj < nparms; jj++)
+       parm_types[jj] = (method
+                         ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
+                         : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]), jj));
+
+      /* Compare parameter types to supplied argument types.  Skip THIS for
+         static methods.  */
+      bv = rank_function (parm_types, nparms, arg_types + static_offset,
+                         nargs - static_offset);
+
+      if (!oload_champ_bv)
+       {
+         oload_champ_bv = bv;
+         oload_champ = 0;
+         champ_nparms = nparms;
+       }
+      else
+       /* See whether current candidate is better or worse than previous best */
+       switch (compare_badness (bv, oload_champ_bv))
+         {
+         case 0:
+           oload_ambiguous = 1;        /* top two contenders are equally good */
+           oload_ambig_champ = ix;
+           break;
+         case 1:
+           oload_ambiguous = 2;        /* incomparable top contenders */
+           oload_ambig_champ = ix;
+           break;
+         case 2:
+           oload_champ_bv = bv;        /* new champion, record details */
+           oload_ambiguous = 0;
+           oload_champ = ix;
+           oload_ambig_champ = -1;
+           champ_nparms = nparms;
+           break;
+         case 3:
+         default:
+           break;
+         }
+      xfree (parm_types);
+      if (overload_debug)
+       {
+         if (method)
+           fprintf_filtered (gdb_stderr,"Overloaded method instance %s, # of parms %d\n", fns_ptr[ix].physname, nparms);
+         else
+           fprintf_filtered (gdb_stderr,"Overloaded function instance %s # of parms %d\n", SYMBOL_DEMANGLED_NAME (oload_syms[ix]), nparms);
+         for (jj = 0; jj < nargs - static_offset; jj++)
+           fprintf_filtered (gdb_stderr,"...Badness @ %d : %d\n", jj, bv->rank[jj]);
+         fprintf_filtered (gdb_stderr,"Overload resolution champion is %d, ambiguous? %d\n", oload_champ, oload_ambiguous);
+       }
+    }                          /* end loop over all candidates */
+  /* NOTE: dan/2000-03-10: Seems to be a better idea to just pick one
+     if they have the exact same goodness. This is because there is no
+     way to differentiate based on return type, which we need to in
+     cases like overloads of .begin() <It's both const and non-const> */
+#if 0
+  if (oload_ambiguous)
+    {
+      if (method)
+       error ("Cannot resolve overloaded method %s%s%s to unique instance; disambiguate by specifying function signature",
+              obj_type_name,
+              (obj_type_name && *obj_type_name) ? "::" : "",
+              name);
+      else
+       error ("Cannot resolve overloaded function %s to unique instance; disambiguate by specifying function signature",
+              func_name);
+    }
+#endif
+
+  /* Check how bad the best match is.  */
+  static_offset = 0;
+  if (method && TYPE_FN_FIELD_STATIC_P (fns_ptr, oload_champ))
+    static_offset = 1;
+  for (ix = 1; ix <= nargs - static_offset; ix++)
+    {
+      if (oload_champ_bv->rank[ix] >= 100)
+       oload_incompatible = 1; /* truly mismatched types */
+
+      else if (oload_champ_bv->rank[ix] >= 10)
+       oload_non_standard = 1; /* non-standard type conversions needed */
+    }
+  if (oload_incompatible)
+    {
+      if (method)
+       error ("Cannot resolve method %s%s%s to any overloaded instance",
+              obj_type_name,
+              (obj_type_name && *obj_type_name) ? "::" : "",
+              name);
+      else
+       error ("Cannot resolve function %s to any overloaded instance",
+              func_name);
+    }
+  else if (oload_non_standard)
+    {
+      if (method)
+       warning ("Using non-standard conversion to match method %s%s%s to supplied arguments",
+                obj_type_name,
+                (obj_type_name && *obj_type_name) ? "::" : "",
+                name);
+      else
+       warning ("Using non-standard conversion to match function %s to supplied arguments",
+                func_name);
+    }
+
+  if (method)
+    {
+      if (staticp && TYPE_FN_FIELD_STATIC_P (fns_ptr, oload_champ))
+       *staticp = 1;
+      else if (staticp)
+       *staticp = 0;
+      if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, oload_champ))
+       *valp = value_virtual_fn_field (&temp, fns_ptr, oload_champ, basetype, boffset);
+      else
+       *valp = value_fn_field (&temp, fns_ptr, oload_champ, basetype, boffset);
+    }
+  else
+    {
+      *symp = oload_syms[oload_champ];
+      xfree (func_name);
+    }
+
+  if (objp)
+    {
+      if (TYPE_CODE (VALUE_TYPE (temp)) != TYPE_CODE_PTR
+         && TYPE_CODE (VALUE_TYPE (*objp)) == TYPE_CODE_PTR)
+       {
+         temp = value_addr (temp);
+       }
+      *objp = temp;
+    }
+  if (cleanups != NULL)
+    do_cleanups (cleanups);
+
+  return oload_incompatible ? 100 : (oload_non_standard ? 10 : 0);
+}
+
+/* C++: return 1 is NAME is a legitimate name for the destructor
+   of type TYPE.  If TYPE does not have a destructor, or
+   if NAME is inappropriate for TYPE, an error is signaled.  */
+int
+destructor_name_p (const char *name, const struct type *type)
+{
+  /* destructors are a special case.  */
+
+  if (name[0] == '~')
+    {
+      char *dname = type_name_no_tag (type);
+      char *cp = strchr (dname, '<');
+      unsigned int len;
+
+      /* Do not compare the template part for template classes.  */
+      if (cp == NULL)
+       len = strlen (dname);
+      else
+       len = cp - dname;
+      if (strlen (name + 1) != len || !STREQN (dname, name + 1, len))
+       error ("name of destructor must equal name of class");
+      else
+       return 1;
+    }
+  return 0;
+}
+
+/* Helper function for check_field: Given TYPE, a structure/union,
+   return 1 if the component named NAME from the ultimate
+   target structure/union is defined, otherwise, return 0. */
+
+static int
+check_field_in (register struct type *type, const char *name)
+{
+  register int i;
+
+  for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+    {
+      char *t_field_name = TYPE_FIELD_NAME (type, i);
+      if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
+       return 1;
+    }
+
+  /* C++: If it was not found as a data field, then try to
+     return it as a pointer to a method.  */
+
+  /* Destructors are a special case.  */
+  if (destructor_name_p (name, type))
+    {
+      int m_index, f_index;
+
+      return get_destructor_fn_field (type, &m_index, &f_index);
+    }
+
+  for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
+    {
+      if (strcmp_iw (TYPE_FN_FIELDLIST_NAME (type, i), name) == 0)
+       return 1;
+    }
+
+  for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+    if (check_field_in (TYPE_BASECLASS (type, i), name))
+      return 1;
+
+  return 0;
+}
+
+
+/* C++: Given ARG1, a value of type (pointer to a)* structure/union,
+   return 1 if the component named NAME from the ultimate
+   target structure/union is defined, otherwise, return 0.  */
+
+int
+check_field (struct value *arg1, const char *name)
+{
+  register struct type *t;
+
+  COERCE_ARRAY (arg1);
+
+  t = VALUE_TYPE (arg1);
+
+  /* Follow pointers until we get to a non-pointer.  */
+
+  for (;;)
+    {
+      CHECK_TYPEDEF (t);
+      if (TYPE_CODE (t) != TYPE_CODE_PTR && TYPE_CODE (t) != TYPE_CODE_REF)
+       break;
+      t = TYPE_TARGET_TYPE (t);
+    }
+
+  if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
+    error ("not implemented: member type in check_field");
+
+  if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+      && TYPE_CODE (t) != TYPE_CODE_UNION)
+    error ("Internal error: `this' is not an aggregate");
+
+  return check_field_in (t, name);
+}
+
+/* C++: Given an aggregate type CURTYPE, and a member name NAME,
+   return the address of this member as a "pointer to member"
+   type.  If INTYPE is non-null, then it will be the type
+   of the member we are looking for.  This will help us resolve
+   "pointers to member functions".  This function is used
+   to resolve user expressions of the form "DOMAIN::NAME".  */
+
+struct value *
+value_struct_elt_for_reference (struct type *domain, int offset,
+                               struct type *curtype, char *name,
+                               struct type *intype)
+{
+  register struct type *t = curtype;
+  register int i;
+  struct value *v;
+
+  if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+      && TYPE_CODE (t) != TYPE_CODE_UNION)
+    error ("Internal error: non-aggregate type to value_struct_elt_for_reference");
+
+  for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--)
+    {
+      char *t_field_name = TYPE_FIELD_NAME (t, i);
+
+      if (t_field_name && STREQ (t_field_name, name))
+       {
+         if (TYPE_FIELD_STATIC (t, i))
+           {
+             v = value_static_field (t, i);
+             if (v == NULL)
+               error ("static field %s has been optimized out",
+                      name);
+             return v;
+           }
+         if (TYPE_FIELD_PACKED (t, i))
+           error ("pointers to bitfield members not allowed");
+
+         return value_from_longest
+           (lookup_reference_type (lookup_member_type (TYPE_FIELD_TYPE (t, i),
+                                                       domain)),
+            offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
+       }
+    }
+
+  /* C++: If it was not found as a data field, then try to
+     return it as a pointer to a method.  */
+
+  /* Destructors are a special case.  */
+  if (destructor_name_p (name, t))
+    {
+      error ("member pointers to destructors not implemented yet");
+    }
+
+  /* Perform all necessary dereferencing.  */
+  while (intype && TYPE_CODE (intype) == TYPE_CODE_PTR)
+    intype = TYPE_TARGET_TYPE (intype);
+
+  for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+    {
+      char *t_field_name = TYPE_FN_FIELDLIST_NAME (t, i);
+      char dem_opname[64];
+
+      if (strncmp (t_field_name, "__", 2) == 0 ||
+         strncmp (t_field_name, "op", 2) == 0 ||
+         strncmp (t_field_name, "type", 4) == 0)
+       {
+         if (cplus_demangle_opname (t_field_name, dem_opname, DMGL_ANSI))
+           t_field_name = dem_opname;
+         else if (cplus_demangle_opname (t_field_name, dem_opname, 0))
+           t_field_name = dem_opname;
+       }
+      if (t_field_name && STREQ (t_field_name, name))
+       {
+         int j = TYPE_FN_FIELDLIST_LENGTH (t, i);
+         struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+         check_stub_method_group (t, i);
+
+         if (intype == 0 && j > 1)
+           error ("non-unique member `%s' requires type instantiation", name);
+         if (intype)
+           {
+             while (j--)
+               if (TYPE_FN_FIELD_TYPE (f, j) == intype)
+                 break;
+             if (j < 0)
+               error ("no member function matches that type instantiation");
+           }
+         else
+           j = 0;
+
+         if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+           {
+             return value_from_longest
+               (lookup_reference_type
+                (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
+                                     domain)),
+                (LONGEST) METHOD_PTR_FROM_VOFFSET (TYPE_FN_FIELD_VOFFSET (f, j)));
+           }
+         else
+           {
+             struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+                                               0, VAR_NAMESPACE, 0, NULL);
+             if (s == NULL)
+               {
+                 v = 0;
+               }
+             else
+               {
+                 v = read_var_value (s, 0);
+#if 0
+                 VALUE_TYPE (v) = lookup_reference_type
+                   (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
+                                        domain));
+#endif
+               }
+             return v;
+           }
+       }
+    }
+  for (i = TYPE_N_BASECLASSES (t) - 1; i >= 0; i--)
+    {
+      struct value *v;
+      int base_offset;
+
+      if (BASETYPE_VIA_VIRTUAL (t, i))
+       base_offset = 0;
+      else
+       base_offset = TYPE_BASECLASS_BITPOS (t, i) / 8;
+      v = value_struct_elt_for_reference (domain,
+                                         offset + base_offset,
+                                         TYPE_BASECLASS (t, i),
+                                         name,
+                                         intype);
+      if (v)
+       return v;
+    }
+  return 0;
+}
+
+
+/* Given a pointer value V, find the real (RTTI) type
+   of the object it points to.
+   Other parameters FULL, TOP, USING_ENC as with value_rtti_type()
+   and refer to the values computed for the object pointed to. */
+
+struct type *
+value_rtti_target_type (struct value *v, int *full, int *top, int *using_enc)
+{
+  struct value *target;
+
+  target = value_ind (v);
+
+  return value_rtti_type (target, full, top, using_enc);
+}
+
+/* Given a value pointed to by ARGP, check its real run-time type, and
+   if that is different from the enclosing type, create a new value
+   using the real run-time type as the enclosing type (and of the same
+   type as ARGP) and return it, with the embedded offset adjusted to
+   be the correct offset to the enclosed object
+   RTYPE is the type, and XFULL, XTOP, and XUSING_ENC are the other
+   parameters, computed by value_rtti_type(). If these are available,
+   they can be supplied and a second call to value_rtti_type() is avoided.
+   (Pass RTYPE == NULL if they're not available */
+
+struct value *
+value_full_object (struct value *argp, struct type *rtype, int xfull, int xtop,
+                  int xusing_enc)
+{
+  struct type *real_type;
+  int full = 0;
+  int top = -1;
+  int using_enc = 0;
+  struct value *new_val;
+
+  if (rtype)
+    {
+      real_type = rtype;
+      full = xfull;
+      top = xtop;
+      using_enc = xusing_enc;
+    }
+  else
+    real_type = value_rtti_type (argp, &full, &top, &using_enc);
+
+  /* If no RTTI data, or if object is already complete, do nothing */
+  if (!real_type || real_type == VALUE_ENCLOSING_TYPE (argp))
+    return argp;
+
+  /* If we have the full object, but for some reason the enclosing
+     type is wrong, set it *//* pai: FIXME -- sounds iffy */
+  if (full)
+    {
+      argp = value_change_enclosing_type (argp, real_type);
+      return argp;
+    }
+
+  /* Check if object is in memory */
+  if (VALUE_LVAL (argp) != lval_memory)
+    {
+      warning ("Couldn't retrieve complete object of RTTI type %s; object may be in register(s).", TYPE_NAME (real_type));
+
+      return argp;
+    }
+
+  /* All other cases -- retrieve the complete object */
+  /* Go back by the computed top_offset from the beginning of the object,
+     adjusting for the embedded offset of argp if that's what value_rtti_type
+     used for its computation. */
+  new_val = value_at_lazy (real_type, VALUE_ADDRESS (argp) - top +
+                          (using_enc ? 0 : VALUE_EMBEDDED_OFFSET (argp)),
+                          VALUE_BFD_SECTION (argp));
+  VALUE_TYPE (new_val) = VALUE_TYPE (argp);
+  VALUE_EMBEDDED_OFFSET (new_val) = using_enc ? top + VALUE_EMBEDDED_OFFSET (argp) : top;
+  return new_val;
+}
+
+
+
+
+/* C++: return the value of the class instance variable, if one exists.
+   Flag COMPLAIN signals an error if the request is made in an
+   inappropriate context.  */
+
+struct value *
+value_of_this (int complain)
+{
+  struct symbol *func, *sym;
+  struct block *b;
+  int i;
+  static const char funny_this[] = "this";
+  struct value *this;
+
+  if (selected_frame == 0)
+    {
+      if (complain)
+       error ("no frame selected");
+      else
+       return 0;
+    }
+
+  func = get_frame_function (selected_frame);
+  if (!func)
+    {
+      if (complain)
+       error ("no `this' in nameless context");
+      else
+       return 0;
+    }
+
+  b = SYMBOL_BLOCK_VALUE (func);
+  i = BLOCK_NSYMS (b);
+  if (i <= 0)
+    {
+      if (complain)
+       error ("no args, no `this'");
+      else
+       return 0;
+    }
+
+  /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER
+     symbol instead of the LOC_ARG one (if both exist).  */
+  sym = lookup_block_symbol (b, funny_this, NULL, VAR_NAMESPACE);
+  if (sym == NULL)
+    {
+      if (complain)
+       error ("current stack frame not in method");
+      else
+       return NULL;
+    }
+
+  this = read_var_value (sym, selected_frame);
+  if (this == 0 && complain)
+    error ("`this' argument at unknown address");
+  return this;
+}
+
+/* Create a slice (sub-string, sub-array) of ARRAY, that is LENGTH elements
+   long, starting at LOWBOUND.  The result has the same lower bound as
+   the original ARRAY.  */
+
+struct value *
+value_slice (struct value *array, int lowbound, int length)
+{
+  struct type *slice_range_type, *slice_type, *range_type;
+  LONGEST lowerbound, upperbound, offset;
+  struct value *slice;
+  struct type *array_type;
+  array_type = check_typedef (VALUE_TYPE (array));
+  COERCE_VARYING_ARRAY (array, array_type);
+  if (TYPE_CODE (array_type) != TYPE_CODE_ARRAY
+      && TYPE_CODE (array_type) != TYPE_CODE_STRING
+      && TYPE_CODE (array_type) != TYPE_CODE_BITSTRING)
+    error ("cannot take slice of non-array");
+  range_type = TYPE_INDEX_TYPE (array_type);
+  if (get_discrete_bounds (range_type, &lowerbound, &upperbound) < 0)
+    error ("slice from bad array or bitstring");
+  if (lowbound < lowerbound || length < 0
+      || lowbound + length - 1 > upperbound)
+    /* OBSOLETE Chill allows zero-length strings but not arrays. */
+    /* OBSOLETE || (current_language->la_language == language_chill */
+    /* OBSOLETE && length == 0 && TYPE_CODE (array_type) == TYPE_CODE_ARRAY)) */
+    error ("slice out of range");
+  /* FIXME-type-allocation: need a way to free this type when we are
+     done with it.  */
+  slice_range_type = create_range_type ((struct type *) NULL,
+                                       TYPE_TARGET_TYPE (range_type),
+                                       lowbound, lowbound + length - 1);
+  if (TYPE_CODE (array_type) == TYPE_CODE_BITSTRING)
+    {
+      int i;
+      slice_type = create_set_type ((struct type *) NULL, slice_range_type);
+      TYPE_CODE (slice_type) = TYPE_CODE_BITSTRING;
+      slice = value_zero (slice_type, not_lval);
+      for (i = 0; i < length; i++)
+       {
+         int element = value_bit_index (array_type,
+                                        VALUE_CONTENTS (array),
+                                        lowbound + i);
+         if (element < 0)
+           error ("internal error accessing bitstring");
+         else if (element > 0)
+           {
+             int j = i % TARGET_CHAR_BIT;
+             if (BITS_BIG_ENDIAN)
+               j = TARGET_CHAR_BIT - 1 - j;
+             VALUE_CONTENTS_RAW (slice)[i / TARGET_CHAR_BIT] |= (1 << j);
+           }
+       }
+      /* We should set the address, bitssize, and bitspos, so the clice
+         can be used on the LHS, but that may require extensions to
+         value_assign.  For now, just leave as a non_lval.  FIXME.  */
+    }
+  else
+    {
+      struct type *element_type = TYPE_TARGET_TYPE (array_type);
+      offset
+       = (lowbound - lowerbound) * TYPE_LENGTH (check_typedef (element_type));
+      slice_type = create_array_type ((struct type *) NULL, element_type,
+                                     slice_range_type);
+      TYPE_CODE (slice_type) = TYPE_CODE (array_type);
+      slice = allocate_value (slice_type);
+      if (VALUE_LAZY (array))
+       VALUE_LAZY (slice) = 1;
+      else
+       memcpy (VALUE_CONTENTS (slice), VALUE_CONTENTS (array) + offset,
+               TYPE_LENGTH (slice_type));
+      if (VALUE_LVAL (array) == lval_internalvar)
+       VALUE_LVAL (slice) = lval_internalvar_component;
+      else
+       VALUE_LVAL (slice) = VALUE_LVAL (array);
+      VALUE_ADDRESS (slice) = VALUE_ADDRESS (array);
+      VALUE_OFFSET (slice) = VALUE_OFFSET (array) + offset;
+    }
+  return slice;
+}
+
+/* Assuming OBSOLETE chill_varying_type (VARRAY) is true, return an
+   equivalent value as a fixed-length array. */
+
+struct value *
+varying_to_slice (struct value *varray)
+{
+  struct type *vtype = check_typedef (VALUE_TYPE (varray));
+  LONGEST length = unpack_long (TYPE_FIELD_TYPE (vtype, 0),
+                               VALUE_CONTENTS (varray)
+                               + TYPE_FIELD_BITPOS (vtype, 0) / 8);
+  return value_slice (value_primitive_field (varray, 0, 1, vtype), 0, length);
+}
+
+/* Create a value for a FORTRAN complex number.  Currently most of
+   the time values are coerced to COMPLEX*16 (i.e. a complex number
+   composed of 2 doubles.  This really should be a smarter routine
+   that figures out precision inteligently as opposed to assuming
+   doubles. FIXME: fmb */
+
+struct value *
+value_literal_complex (struct value *arg1, struct value *arg2, struct type *type)
+{
+  struct value *val;
+  struct type *real_type = TYPE_TARGET_TYPE (type);
+
+  val = allocate_value (type);
+  arg1 = value_cast (real_type, arg1);
+  arg2 = value_cast (real_type, arg2);
+
+  memcpy (VALUE_CONTENTS_RAW (val),
+         VALUE_CONTENTS (arg1), TYPE_LENGTH (real_type));
+  memcpy (VALUE_CONTENTS_RAW (val) + TYPE_LENGTH (real_type),
+         VALUE_CONTENTS (arg2), TYPE_LENGTH (real_type));
+  return val;
+}
+
+/* Cast a value into the appropriate complex data type. */
+
+static struct value *
+cast_into_complex (struct type *type, struct value *val)
+{
+  struct type *real_type = TYPE_TARGET_TYPE (type);
+  if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_COMPLEX)
+    {
+      struct type *val_real_type = TYPE_TARGET_TYPE (VALUE_TYPE (val));
+      struct value *re_val = allocate_value (val_real_type);
+      struct value *im_val = allocate_value (val_real_type);
+
+      memcpy (VALUE_CONTENTS_RAW (re_val),
+             VALUE_CONTENTS (val), TYPE_LENGTH (val_real_type));
+      memcpy (VALUE_CONTENTS_RAW (im_val),
+             VALUE_CONTENTS (val) + TYPE_LENGTH (val_real_type),
+             TYPE_LENGTH (val_real_type));
+
+      return value_literal_complex (re_val, im_val, type);
+    }
+  else if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT
+          || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT)
+    return value_literal_complex (val, value_zero (real_type, not_lval), type);
+  else
+    error ("cannot cast non-number to complex");
+}
+
+void
+_initialize_valops (void)
+{
+#if 0
+  add_show_from_set
+    (add_set_cmd ("abandon", class_support, var_boolean, (char *) &auto_abandon,
+                 "Set automatic abandonment of expressions upon failure.",
+                 &setlist),
+     &showlist);
+#endif
+
+  add_show_from_set
+    (add_set_cmd ("overload-resolution", class_support, var_boolean, (char *) &overload_resolution,
+                 "Set overload resolution in evaluating C++ functions.",
+                 &setlist),
+     &showlist);
+  overload_resolution = 1;
+
+  add_show_from_set (
+  add_set_cmd ("unwindonsignal", no_class, var_boolean,
+              (char *) &unwind_on_signal_p,
+"Set unwinding of stack if a signal is received while in a call dummy.\n\
+The unwindonsignal lets the user determine what gdb should do if a signal\n\
+is received while in a function called from gdb (call dummy).  If set, gdb\n\
+unwinds the stack and restore the context to what as it was before the call.\n\
+The default is to stop in the frame where the signal was received.", &setlist),
+                    &showlist);
+}