aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobody <>2002-09-20 14:59:00 +0000
committernobody <>2002-09-20 14:59:00 +0000
commit148ea30ef6e624235f31f27ee7a285c7529eb68a (patch)
tree67866d45b0d55da959bcbeef8c472eee3165458d
parent6a0f0bde1408c30460890c262a3b9a18dc569c4d (diff)
downloadgdb-148ea30ef6e624235f31f27ee7a285c7529eb68a.zip
gdb-148ea30ef6e624235f31f27ee7a285c7529eb68a.tar.gz
gdb-148ea30ef6e624235f31f27ee7a285c7529eb68a.tar.bz2
This commit was manufactured by cvs2svn to create branch
'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
-rw-r--r--gdb/breakpoint.c7823
-rw-r--r--gdb/mi/ChangeLog1836
-rw-r--r--gdb/mi/mi-cmd-stack.c309
-rw-r--r--gdb/objfiles.c1011
-rw-r--r--gdb/printcmd.c2572
-rw-r--r--gdb/stack.c2023
-rw-r--r--gdb/tracepoint.c2812
-rw-r--r--gdb/valops.c3536
8 files changed, 21922 insertions, 0 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
new file mode 100644
index 0000000..caa8f1c
--- /dev/null
+++ b/gdb/breakpoint.c
@@ -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;
+
+/* *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;
+}
+
+
+
+/* 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);
+}
+
+/* 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);
+}
+
+
+/* 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;
+}
+
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+
+/* 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");
+ }
+}
+
+/* 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;
+}
+
+
+/* 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");
+}
+
+
+/* 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);
+}
+
+
+/* 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);
+}
+
+#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);
+}
+
+
+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');
+}
+
+/* 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");
+}
+
+/* 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");
+}
+
+/* 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);
+}
+
+/* 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;
+}
+
+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
index 0000000..51d9973
--- /dev/null
+++ b/gdb/mi/ChangeLog
@@ -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.
+
+
+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
index 0000000..b4bae47
--- /dev/null
+++ b/gdb/mi/mi-cmd-stack.c
@@ -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
index 0000000..9c5e49f
--- /dev/null
+++ b/gdb/objfiles.c
@@ -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 ();
+}
+
+/* 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 ();
+}
+
+/* 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
index 0000000..8542b8a
--- /dev/null
+++ b/gdb/printcmd.c
@@ -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);
+
+
+/* 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;
+}
+
+/* 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, "");
+ }
+}
+
+
+/* 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);
+ }
+}
+
+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");
+}
+
+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);
+ }
+}
+
+
+/* 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++;
+ }
+}
+
+
+/* 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);
+ }
+}
+
+/* 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);
+}
+
+/* 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);
+}
+
+
+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
index 0000000..4f41531
--- /dev/null
+++ b/gdb/stack.c
@@ -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;
+
+
+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);
+}
+
+
+/* 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)
+{
+}
+
+
+/* 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);
+}
+
+
+/* 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);
+}
+
+
+/* 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);
+ }
+ }
+}
+
+
+/* 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);
+ }
+}
+
+/* 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);
+}
+
+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;
+}
+
+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
index 0000000..2d12f31
--- /dev/null
+++ b/gdb/tracepoint.c
@@ -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
index 0000000..eaf4295
--- /dev/null
+++ b/gdb/valops.c
@@ -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;
+
+
+
+/* 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 */
+}
+
+/* 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.");
+ }
+}
+
+
+
+/* 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;
+}
+
+/* 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);
+}