Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFC] add 'save-breakpoints' command
@ 2001-12-04 10:21 Klee Dienes
  2001-12-04 10:26 ` Daniel Jacobowitz
                   ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Klee Dienes @ 2001-12-04 10:21 UTC (permalink / raw)
  To: gdb-patches


For a long time, we (the folks at Apple), have been wanting to unify
our source tree with the Cygnus GDB source tree, for all the
free-software reasons I'm sure I don't need enumerate.

Over the past couple of years, we managed to bring our source tree
up-to-date with respect the current Cygnus tree (it used to be based
off of gdb-4.14), executed a copyright assignment, and made a massive
diff available, but the actual work of pushing our changes back to
Cygnus (cleanly and as individual patch files) has always been
prioritized just under "make GDB work well on our platform."

Thankfully, GDB now works pretty well on our platform, so we're
finally getting the time to do the work of merging our changes back
into the Cygnus tree.

We've got a ton of stuff to submit, but as a warm-up, I'm starting
witha relatively minor feature-addition --- a command to save the
current set of breakpoints to a file that can be read in later.  We've
been using this on our platform for a few months now, and folks seem
to like it.  I've also tested the patch against the i386/Linux
testsuite ... nothing appears to break.

My one concern with the patch is that it exports the value of 'set
input-radix' as a GDB convenience variable ($input_radix), so that it
can be accessed from within GDB command scripts.  I tried to come up
with a more generic way of doing this, but all were unsatisfactory
... suggestions on a better way to do this would be appreciated.

To use the command, do 'save-breakpoints <filename>' at any time.  You
can then restore the set of breakpoints thus saved by sourcing the
contents of <filename>.

Thanks for your feedback; hopefully we can keep a steady stream of
patches coming in in the upcoming months.

2001-12-04  Ira L. Ruben  <ira@apple.com>
	Submitted by Klee Dienes <kdienes@apple.com>

	* ui-out.c, ui-out.h: Add ui_out_delete.

	* utils.c, defs.h: Add make_cleanup_ui_out_delete.

	* breakpoint.c (parse_breakpoint_sals): Handle case where address
	is NULL and default_breakpoint_valid to set addr_string to "*pc"
	(sal.pc) to avoid warning from breakpoint_re_set_one().
	(set_raw_breakpoint): init new original_type field.
	(create_breakpoints): Handle new original_type argument.
	(break_command_1): Ditto. 
	(do_captured_breakpoint): Pass new original type to create_breakpoints.
	(break_at_finish_at_depth_command_1): pass original type to
	break_command_1.
	(break_at_finish_command_1): Ditto.
	(break_command): Ditto.
	(future_break_command_1): Ditto.
	(tbreak_command): Ditto.
	(hbreak_command): Ditto.
	(thbreak_command): Ditto.
	(stopin_command): Ditto.
	(stopat_command): Ditto.
	(watch_command_1): Handle new original_type argument.
	(watch_command): Pass new original type to watch_command_1.
	(rwatch_command_wrapper): Ditto.
	(awatch_command): Ditto.
	(ignore_command): Suppress newline if from_tty is false.
	(write_one_breakpoint): new routine for save_breakpoints_command.
	(save_breakpoints_command): Add save-breakpoints command.
	(_initialize_breakpoint): Define save-breakpoints and its aliases.
	
	* breakpoint.h (enum bptype): Add new breakpoint types.
	(struct breakpoint): Add field to recore original breakpoint type.
	
	* main.c (captured_main): Initialize $input_radix and $output_radix.
	These are referenced by a save-breakpoints file to preserve radix
	across the breakpoint restoration.
	
	* tracepoint.c (tracepoint_save_command): Fix fopen error reporting to
	show errno information just like save-breakpoints command.
	
	* valprint.c (set_input_radix_1): Set $input_radix.
	(set_output_radix_1): Set $output_radix.

Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.57
diff -u -r1.57 breakpoint.c
--- breakpoint.c	2001/11/11 16:39:59	1.57
+++ breakpoint.c	2001/12/04 17:59:32
@@ -42,6 +42,10 @@
 #include "linespec.h"
 #include "completer.h"
 #include "gdb.h"
+#include "top.h"
+#include "cli-out.h"
+#include <time.h>
+#include <locale.h>
 #ifdef UI_OUT
 #include "ui-out.h"
 #endif
@@ -89,7 +93,7 @@
 
 static void tbreak_at_finish_command (char *, int);
 
-static void break_command_1 (char *, int, int);
+static void break_command_1 (char *, int, enum bptype, int);
 
 static void mention (struct breakpoint *);
 
@@ -159,7 +163,7 @@
 
 static void thbreak_command (char *, int);
 
-static void watch_command_1 (char *, int, int);
+static void watch_command_1 (char *, int, enum bptype, int);
 
 static void rwatch_command (char *, int);
 
@@ -330,6 +334,12 @@
 		   value_from_longest (builtin_type_int, (LONGEST) num));
 }
 
+int
+get_breakpoint_count (void)
+{
+  return breakpoint_count;
+}
+
 /* Used in run_command to zero the hit count when a new run starts. */
 
 void
@@ -4612,6 +4622,7 @@
 create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
 		    struct expression **cond, char **cond_string,
 		    enum bptype type, enum bpdisp disposition,
+		    enum bptype original_type,
 		    int thread, int ignore_count, int from_tty)
 {
   if (type == bp_hardware_breakpoint)
@@ -4756,7 +4767,7 @@
    second bit : 0 normal breakpoint, 1 hardware breakpoint. */
 
 static void
-break_command_1 (char *arg, int flag, int from_tty)
+break_command_1 (char *arg, int flag, enum bptype original_type, int from_tty)
 {
   int tempflag, hardwareflag;
   struct symtabs_and_lines sals;
@@ -4870,7 +4881,7 @@
 
   create_breakpoints (sals, addr_string, cond, cond_string,
 		      hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
-		      tempflag ? disp_del : disp_donttouch,
+		      tempflag ? disp_del : disp_donttouch, original_type,
 		      thread, ignore_count, from_tty);
 
   if (sals.nelts > 1)
@@ -4982,7 +4993,7 @@
 
   create_breakpoints (sals, addr_string, cond, cond_string,
 		      args->hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
-		      args->tempflag ? disp_del : disp_donttouch,
+		      args->tempflag ? disp_del : disp_donttouch, bp_none,
 		      args->thread, args->ignore_count, 0/*from-tty*/);
 
   /* That's it. Discard the cleanups for data inserted into the
@@ -5076,7 +5087,7 @@
 	    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);
+	  break_command_1 (addr_string, flag, bp_none, from_tty);
 	  xfree (addr_string);
 	}
       else
@@ -5158,7 +5169,7 @@
 	    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);
+	  break_command_1 (break_string, flag, bp_none, from_tty);
 	  xfree (break_string);
 	}
       else
@@ -5225,7 +5236,7 @@
 void
 break_command (char *arg, int from_tty)
 {
-  break_command_1 (arg, 0, from_tty);
+  break_command_1 (arg, 0, bp_breakpoint, from_tty);
 }
 
 static void
@@ -5243,7 +5254,7 @@
 void
 tbreak_command (char *arg, int from_tty)
 {
-  break_command_1 (arg, BP_TEMPFLAG, from_tty);
+  break_command_1 (arg, BP_TEMPFLAG, bp_tbreakpoint, from_tty);
 }
 
 static void
@@ -5255,13 +5266,13 @@
 static void
 hbreak_command (char *arg, int from_tty)
 {
-  break_command_1 (arg, BP_HARDWAREFLAG, from_tty);
+  break_command_1 (arg, BP_HARDWAREFLAG, bp_hardware_breakpoint, from_tty);
 }
 
 static void
 thbreak_command (char *arg, int from_tty)
 {
-  break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty);
+  break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), bp_thbreakpoint, from_tty);
 }
 
 static void
@@ -5302,7 +5313,7 @@
   if (badInput)
     printf_filtered ("Usage: stop in <function | address>\n");
   else
-    break_command_1 (arg, 0, from_tty);
+    break_command_1 (arg, 0, bp_none, from_tty);
 }
 
 static void
@@ -5334,7 +5345,7 @@
   if (badInput)
     printf_filtered ("Usage: stop at <line>\n");
   else
-    break_command_1 (arg, 0, from_tty);
+    break_command_1 (arg, 0, bp_none, from_tty);
 }
 
 /* ARGSUSED */
@@ -5342,7 +5353,7 @@
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
 static void
-watch_command_1 (char *arg, int accessflag, int from_tty)
+watch_command_1 (char *arg, int accessflag, enum bptype original_type, int from_tty)
 {
   struct breakpoint *b;
   struct symtab_and_line sal;
@@ -5603,7 +5614,7 @@
 static void
 watch_command (char *arg, int from_tty)
 {
-  watch_command_1 (arg, hw_write, from_tty);
+  watch_command_1 (arg, hw_write, bp_hardware_watchpoint, from_tty);
 }
 
 #ifdef UI_OUT
@@ -5616,7 +5627,7 @@
 static void
 rwatch_command (char *arg, int from_tty)
 {
-  watch_command_1 (arg, hw_read, from_tty);
+  watch_command_1 (arg, hw_read, bp_read_watchpoint, from_tty);
 }
 
 #ifdef UI_OUT
@@ -5629,7 +5640,7 @@
 static void
 awatch_command (char *arg, int from_tty)
 {
-  watch_command_1 (arg, hw_access, from_tty);
+  watch_command_1 (arg, hw_access, bp_access_watchpoint, from_tty);
 }
 \f
 
@@ -7570,6 +7581,262 @@
 {
   map_breakpoint_numbers (args, enable_delete_breakpoint);
 }
+
+/* Generate a break, watch, or catch command defined by B to the STREAM.
+
+   General worse case example,
+
+     break <address> thread <t> if <expr>
+     commands
+       <command lines...>
+     end
+     ignore $bpnum <count>
+     disable $bpnum
+
+   In addition "set input-radix <r>" may precede the above sequence but
+   that is generated by save_breakpoints_command() which is this
+   function's caller.  */
+
+static void
+write_one_breakpoint (struct breakpoint *b, struct ui_file *stream, struct ui_out *uiout)
+{
+  register struct command_line *l;
+
+  switch (b->type)
+    {
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+    case bp_read_watchpoint:
+    case bp_access_watchpoint:
+      if (b->original_type == bp_none)
+        {
+          if (b->type == bp_read_watchpoint)
+            fprintf_unfiltered (stream, "rwatch %s", b->exp_string);
+          else if (b->type == bp_access_watchpoint)
+            fprintf_unfiltered (stream, "awatch %s", b->exp_string);
+          else
+            fprintf_unfiltered (stream, "watch %s", b->exp_string);
+        }
+      else
+        {
+          if (b->original_type == bp_read_watchpoint)
+            fprintf_unfiltered (stream, "rwatch %s", b->exp_string);
+          else if (b->original_type == bp_access_watchpoint)
+            fprintf_unfiltered (stream, "awatch %s", b->exp_string);
+          else
+            fprintf_unfiltered (stream, "watch %s", b->exp_string);
+        }
+      break;
+
+    case bp_catch_load:
+    case bp_catch_unload:
+      fprintf_unfiltered (stream, "%scatch %sload", b->disposition == disp_del ? "t" : "",
+                                         b->type == bp_catch_unload ? "un" : "");
+      if (b->dll_pathname != NULL)
+        fputs_unfiltered (b->dll_pathname, stream);
+      break;
+
+    case bp_catch_fork:
+      fprintf_unfiltered (stream, "%scatch fork", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_catch_vfork:
+      fprintf_unfiltered (stream, "%scatch vfork", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_catch_exec:
+      fprintf_unfiltered (stream, "%scatch exec", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_catch_catch:
+      fprintf_unfiltered (stream, "%scatch catch", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_catch_throw:
+      fprintf_unfiltered (stream, "%scatch throw", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_breakpoint:
+    case bp_hardware_breakpoint:
+      switch (b->original_type)
+      {
+      case bp_breakpoint:
+        fprintf_unfiltered (stream, "break");
+        break;
+      case bp_hardware_breakpoint:
+        fprintf_unfiltered (stream, "hbreak");
+        break;
+#if 0
+      case bp_fbreakpoint:
+        fprintf_unfiltered (stream, "future-break");
+        break;
+#endif
+      case bp_tbreakpoint:
+        fprintf_unfiltered (stream, "tbreak");
+        break;
+      case bp_thbreakpoint:
+        fprintf_unfiltered (stream, "thbreak");
+        break;
+      case bp_none:
+        if (b->enable_state == bp_shlib_disabled)
+          fputs_unfiltered ("future-", stream);
+        fprintf_unfiltered (stream, "%s%sbreak", b->disposition == disp_del ? "t" : "",
+                             (b->type == bp_hardware_breakpoint) ? "h" : "");
+        break;
+      default:
+	internal_error (__FILE__, __LINE__, "unhandled switch case");
+	break;
+      }
+        
+      if (b->addr_string)
+        {
+          int len = strlen(b->addr_string) - 1;
+          if (b->addr_string[len] == ' ')
+            b->addr_string[len] = 0;
+          else
+            len = 0;
+          fprintf_unfiltered (stream, " %s", b->addr_string);
+          if (len)
+            b->addr_string[len] = ' ';
+        }
+      else if (b->source_file)
+          fprintf_unfiltered (stream, " %s:%d", b->source_file, b->line_number);
+      else
+        fprintf_unfiltered(stream, " %s",
+                           local_hex_string_custom((unsigned long) b->address, "08l"));
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, "unhandled switch case");
+      break;
+    }
+
+  if (b->thread != -1)
+    fprintf_unfiltered (stream, " thread %d", b->thread);
+
+  if (b->cond_string)
+    fprintf_unfiltered (stream, " if %s", b->cond_string);
+  
+  fputc_unfiltered ('\n', stream);
+
+  if ((l = b->commands))
+    {
+      fputs_unfiltered ("commands\n", stream);
+      print_command_lines (uiout, l, 4);
+      fputs_unfiltered ("end\n", stream);
+    }
+
+  if (b->ignore_count)
+    fprintf_unfiltered (stream, "ignore $bpnum %d\n", b->ignore_count);
+    
+  if (b->enable_state == bp_disabled)
+      fputs_unfiltered ("disable $bpnum\n", stream);
+}
+
+static void 
+save_breakpoints_command (char *arg, int from_tty)
+{
+  struct cleanup *cleanups;
+  register struct breakpoint *b;
+  int found_a_breakpoint = 0;
+  int current_radix = -1;
+  int skip;
+  struct ui_file *stream = NULL;
+  struct ui_out *uiout = NULL;
+  time_t t;
+  char **argv;
+  char *pathname, buf[256];
+
+  dont_repeat ();
+  
+  if (arg == NULL)
+    {
+      error ("Arguments missing: file name in which to save breakpoint commands");
+    }
+  else if ((argv = buildargv (arg)) == NULL)
+    {
+      nomem (0);
+    }
+  cleanups = make_cleanup_freeargv (argv);
+
+  pathname = tilde_expand (arg);
+  make_cleanup (xfree, pathname);
+
+  ALL_BREAKPOINTS (b)
+    {
+      /* Filter out non-user breakpoints. */
+      if (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)
+        continue;
+
+      if (! found_a_breakpoint++)
+        {
+	  stream = gdb_fopen (pathname, FOPEN_WT);
+          if (stream == NULL)
+            error ("Unable to open file '%s' for saving breakpoints (%s)",
+		   arg, strerror (errno));
+	  make_cleanup_ui_file_delete (stream);
+	  uiout = cli_out_new (stream);
+	  if (uiout == NULL)
+	    error ("Unable to create cli_out from file for saving breakpoints");
+	  make_cleanup_ui_out_delete (uiout);
+          if (time (&t) != -1)
+            {
+              char *l = setlocale (LC_ALL, NULL);
+              if (l)
+                {
+                  char *orig_locale = strcpy (xmalloc (strlen (l) + 1), l);
+                  setlocale (LC_ALL, "");
+                  if (strftime (buf, sizeof (buf), "%a %b %e %H:%M:%S %Z %Y", localtime (&t)))
+                    fprintf_unfiltered (stream, "# Saved breakpoints file created on %s\n\n", buf);
+                  setlocale (LC_ALL, orig_locale);
+                }
+            }
+          fprintf_unfiltered (stream, "set $current_radix = $input_radix\n"
+			      "set input-radix 012\n\n");
+          current_radix = 10;
+        }
+
+      skip = (b->commands || b->ignore_count || b->enable_state == bp_disabled);
+      if (skip)
+        fputc_unfiltered ('\n', stream);
+
+      if (b->input_radix != current_radix)
+        {
+          current_radix = b->input_radix;
+          fprintf_unfiltered (stream, "set input-radix 0%o\n", current_radix);
+        }
+
+      write_one_breakpoint (b, stream, uiout);
+
+      if (skip && b->next)
+        fputc_unfiltered ('\n', stream);
+    }
+
+  if (! found_a_breakpoint)
+    printf_filtered ("No breakpoints or watchpoints to save.\n");
+  else
+    {
+      fputs_unfiltered ("\n", stream);
+      if (current_radix != 10)
+        fputs_unfiltered ("set input-radix 012\n", stream);
+      fputs_unfiltered ("set input-radix $current_radix\n", stream);
+      if (from_tty)
+        printf_filtered ("Breakpoints saved to file '%s'.\n", arg);
+    }
+
+  do_cleanups (cleanups);
+}
 \f
 /* Use default_breakpoint_'s, or nothing if they aren't valid.  */
 
@@ -7936,6 +8203,16 @@
 hardware.)",
 		   &setlist);
   add_show_from_set (c, &showlist);
+
+  c = add_cmd ("save-breakpoints", class_breakpoint, save_breakpoints_command,
+	       "Save current breakpoint definitions as a script.\n\
+Use the -command option or 'source' command in another debug\n\
+'session to restore them.", &cmdlist);
+  c->completer = filename_completer;
+
+  add_com_alias ("save_breakpoints", "save-breakpoints", class_breakpoint, 1);
+  add_com_alias ("save_bp", "save-breakpoints", class_breakpoint, 1);
+  add_com_alias ("savebp", "save-breakpoints", class_breakpoint, 1);
 
   can_use_hw_watchpoints = 1;
 }
Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.10
diff -u -r1.10 breakpoint.h
--- breakpoint.h	2001/10/20 23:54:29	1.10
+++ breakpoint.h	2001/12/04 17:59:33
@@ -128,9 +128,17 @@
     /* These are catchpoints to implement "catch catch" and "catch throw"
        commands for C++ exception handling. */
     bp_catch_catch,
-    bp_catch_throw
+    bp_catch_throw,
 
+    /* These additional breakpoints are only used to record the original
+       breakpoint command for save-breakpoints.  For example a future
+       break becomes a normal break when hit so if save-breakpoints is
+       done after the break is hit we wouldn't be able to tell what the
+       original command was to write it correcty in the saved file.  */
+    bp_tbreakpoint,
+    bp_thbreakpoint
 
+
   };
 
 /* States of enablement of breakpoint. */
@@ -297,6 +305,9 @@
     char *exec_pathname;
 
     asection *section;
+
+    /* Original type of breakpoint used only for save-breakpoints.  */
+    enum bptype original_type;
   };
 \f
 /* The following stuff is an abstract data type "bpstat" ("breakpoint
@@ -515,6 +526,10 @@
 
 /* Forward declarations for prototypes */
 struct frame_info;
+
+extern void set_breakpoint_count (int);
+
+extern int get_breakpoint_count (void);
 
 extern enum breakpoint_here breakpoint_here_p (CORE_ADDR);
 
Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.66
diff -u -r1.66 defs.h
--- defs.h	2001/12/02 02:57:13	1.66
+++ defs.h	2001/12/04 17:59:35
@@ -544,6 +544,9 @@
 struct ui_file;
 extern struct cleanup *make_cleanup_ui_file_delete (struct ui_file *);
 
+struct ui_out;
+extern struct cleanup *make_cleanup_ui_out_delete (struct ui_out *);
+
 extern struct cleanup *make_cleanup_close (int fd);
 
 extern struct cleanup *make_cleanup_bfd_close (bfd *abfd);
Index: main.c
===================================================================
RCS file: /cvs/src/src/gdb/main.c,v
retrieving revision 1.14
diff -u -r1.14 main.c
--- main.c	2001/11/22 00:23:12	1.14
+++ main.c	2001/12/04 17:59:36
@@ -616,6 +616,17 @@
 	catch_command_errors (source_command, gdbinit, 0, RETURN_MASK_ALL);
       }
 
+  /* These need to be set this late in the initialization to ensure that
+     they are defined for the current environment.  They define the
+     radix variables needed by a save-breakpoints file to preserve the
+     radix across the breakpoints restoration assuming they are restored
+     using the -x (-command) command line options.  */
+     
+  set_internalvar (lookup_internalvar ("input_radix"),
+		   value_from_longest (builtin_type_int, (LONGEST) input_radix));
+  set_internalvar (lookup_internalvar ("output_radix"),
+		   value_from_longest (builtin_type_int, (LONGEST) output_radix));
+
   for (i = 0; i < ncmd; i++)
     {
 #if 0
Index: tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.c,v
retrieving revision 1.28
diff -u -r1.28 tracepoint.c
--- tracepoint.c	2001/11/06 23:38:15	1.28
+++ tracepoint.c	2001/12/04 17:59:39
@@ -2262,7 +2262,7 @@
   struct action_line *line;
   FILE *fp;
   char *i1 = "    ", *i2 = "      ";
-  char *indent, *actionline;
+  char *indent, *actionline, *pathname;
   char tmp[40];
 
   if (args == 0 || *args == 0)
@@ -2274,9 +2274,12 @@
       return;
     }
 
-  if (!(fp = fopen (args, "w")))
-    error ("Unable to open file '%s' for saving tracepoints");
-
+  pathname = tilde_expand (args);
+  if (!(fp = fopen (pathname, "w")))
+    error ("Unable to open file '%s' for saving tracepoints (%s)",
+	   args, strerror (errno));
+  xfree (pathname);
+  
   ALL_TRACEPOINTS (tp)
   {
     if (tp->addr_string)
Index: ui-out.c
===================================================================
RCS file: /cvs/src/src/gdb/ui-out.c,v
retrieving revision 1.18
diff -u -r1.18 ui-out.c
--- ui-out.c	2001/07/06 03:53:11	1.18
+++ ui-out.c	2001/12/04 17:59:40
@@ -1117,6 +1117,14 @@
   return uiout;
 }
 
+void
+ui_out_delete (struct ui_out *uiout)
+{
+  if (uiout->data != NULL)
+    xfree (uiout->data);
+  xfree (uiout);
+}
+
 /* standard gdb initialization hook */
 
 void
Index: ui-out.h
===================================================================
RCS file: /cvs/src/src/gdb/ui-out.h,v
retrieving revision 1.15
diff -u -r1.15 ui-out.h
--- ui-out.h	2001/07/06 03:53:11	1.15
+++ ui-out.h	2001/12/04 17:59:40
@@ -272,4 +272,6 @@
 				  struct ui_out_data *data,
 				  int flags);
 
+extern void ui_out_delete (struct ui_out *uiout);
+
 #endif /* UI_OUT_H */
Index: utils.c
===================================================================
RCS file: /cvs/src/src/gdb/utils.c,v
retrieving revision 1.51
diff -u -r1.51 utils.c
--- utils.c	2001/11/15 18:35:05	1.51
+++ utils.c	2001/12/04 17:59:42
@@ -254,6 +254,18 @@
   return make_my_cleanup (&cleanup_chain, do_ui_file_delete, arg);
 }
 
+static void
+do_ui_out_delete (void *arg)
+{
+  ui_out_delete (arg);
+}
+
+struct cleanup *
+make_cleanup_ui_out_delete (struct ui_out *arg)
+{
+  return make_my_cleanup (&cleanup_chain, do_ui_out_delete, arg);
+}
+
 struct cleanup *
 make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
 		 void *arg)


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-04 10:21 [RFC] add 'save-breakpoints' command Klee Dienes
@ 2001-12-04 10:26 ` Daniel Jacobowitz
  2001-12-04 10:44   ` Klee Dienes
  2001-12-04 11:22 ` Eli Zaretskii
  2001-12-04 14:48 ` Michael Snyder
  2 siblings, 1 reply; 19+ messages in thread
From: Daniel Jacobowitz @ 2001-12-04 10:26 UTC (permalink / raw)
  To: Klee Dienes; +Cc: gdb-patches

On Tue, Dec 04, 2001 at 01:21:25PM -0500, Klee Dienes wrote:
> 
> For a long time, we (the folks at Apple), have been wanting to unify
> our source tree with the Cygnus GDB source tree, for all the
> free-software reasons I'm sure I don't need enumerate.
> 
> Over the past couple of years, we managed to bring our source tree
> up-to-date with respect the current Cygnus tree (it used to be based
> off of gdb-4.14), executed a copyright assignment, and made a massive
> diff available, but the actual work of pushing our changes back to
> Cygnus (cleanly and as individual patch files) has always been
> prioritized just under "make GDB work well on our platform."
> 
> Thankfully, GDB now works pretty well on our platform, so we're
> finally getting the time to do the work of merging our changes back
> into the Cygnus tree.
> 
> We've got a ton of stuff to submit, but as a warm-up, I'm starting
> witha relatively minor feature-addition --- a command to save the
> current set of breakpoints to a file that can be read in later.  We've
> been using this on our platform for a few months now, and folks seem
> to like it.  I've also tested the patch against the i386/Linux
> testsuite ... nothing appears to break.

Disclaimer: I haven't actually read through the patch yet, but the
changelog doesn't seem to mention this.  This is more of a comment to
the list than a comment on the patch.

Do you address the issue of breakpoints which can not be set at a
particular time?  For instance, breakpoints in dlopen()'d modules can
not be reset at the start of the next session.

I'm going to guess that that's out of scope for this patch, but it's
just a flag on my todo list.  It'd be nice to be able to set a
breakpoint even if the symbol isn't immediately resolvable, without
breaking error reporting completely.

-- 
Daniel Jacobowitz                           Carnegie Mellon University
MontaVista Software                         Debian GNU/Linux Developer


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-04 10:26 ` Daniel Jacobowitz
@ 2001-12-04 10:44   ` Klee Dienes
  2001-12-05 14:06     ` Tom Tromey
  0 siblings, 1 reply; 19+ messages in thread
From: Klee Dienes @ 2001-12-04 10:44 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: Klee Dienes, gdb-patches


The way we addressed this in our sources was to add a new
'future-break' command, and modify the way we handle breakpoints that
cannot be inserted.

When our GDB is unable to set a breakpoint that has previously been
set successfuly, it marks the breakpoint as 'shlib_disabled'.  Then
when shared libraries are loaded, GDB goes through the list of
shlib_disabled breakpoints and tries to re-set them.

The 'future-break' command allows one to specify a breakpoint that
starts off as 'shlib_disabled' instead of generating an error if it
can't be set immediately.

I'm not entirely happy with the future-break command, and particularly
with its interaction with the save-breakpoints mechanism (if you set a
breakpoint that is in a shared library after shared libraries have
been loaded, you have to remember to use the future-break command, not
the break command).  This isn't a particularly big problem for us,
since we do decent good job of pre-loading symbols for all our shared
libraries --- but it's enough that I thought it better to treat as a
separate issue from the save-breakpoints command.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-04 10:21 [RFC] add 'save-breakpoints' command Klee Dienes
  2001-12-04 10:26 ` Daniel Jacobowitz
@ 2001-12-04 11:22 ` Eli Zaretskii
  2001-12-04 13:35   ` Klee Dienes
  2001-12-04 14:48 ` Michael Snyder
  2 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2001-12-04 11:22 UTC (permalink / raw)
  To: klee; +Cc: gdb-patches

> Reply-To: Klee Dienes <klee@apple.com>
> Date: Tue, 04 Dec 2001 13:21:25 -0500
> 
> To use the command, do 'save-breakpoints <filename>' at any time.  You
> can then restore the set of breakpoints thus saved by sourcing the
> contents of <filename>.

Thanks!  Please consider writing up some minimal docs for this
functionality, for the gdb.texinfo manual.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-04 11:22 ` Eli Zaretskii
@ 2001-12-04 13:35   ` Klee Dienes
  2001-12-05  0:25     ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Klee Dienes @ 2001-12-04 13:35 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches


> Thanks!  Please consider writing up some minimal docs for this
> functionality, for the gdb.texinfo manual.

Whoops.  How about this:

--- cygnus.pristine/src/gdb/doc/gdb.texinfo     Fri Nov 30 19:27:53 2001
+++ cygnus.patched/src/gdb/doc/gdb.texinfo      Tue Dec  4 16:27:02 2001
@@ -2335,6 +2335,7 @@
 * Set Catchpoints::             Setting catchpoints
 * Delete Breaks::               Deleting breakpoints
 * Disabling::                   Disabling breakpoints
+* Saving::                      Saving breakpoints
 * Conditions::                  Break conditions
 * Break Commands::              Breakpoint command lists
 * Breakpoint Menus::            Breakpoint menus
@@ -2941,6 +2942,22 @@
 breakpoint of its own, but it does not change the state of your other
 breakpoints; see @ref{Continuing and Stepping, ,Continuing and
 stepping}.)
+
+@node Saving
+@subsection Saving breakpoints
+@cindex save breakpoints for future sessions
+
+Sometimes, it can be convenient to save the current set of breakpoints
+for use in a future debugging session:
+
+@table @code
+@kindex save-breakpoints
+@item save-breakpoints
+Save all current breakpoint definitions, together with their
+ignore-counts and command scripts, into the file @file{@var{filename}}.
+To read the saved breakpoint definitions, use the @code{source} command
+(@pxref{Command Files}).
+@end table


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-04 10:21 [RFC] add 'save-breakpoints' command Klee Dienes
  2001-12-04 10:26 ` Daniel Jacobowitz
  2001-12-04 11:22 ` Eli Zaretskii
@ 2001-12-04 14:48 ` Michael Snyder
  2001-12-04 21:11   ` Klee Dienes
  2001-12-11  0:28   ` Klee Dienes
  2 siblings, 2 replies; 19+ messages in thread
From: Michael Snyder @ 2001-12-04 14:48 UTC (permalink / raw)
  To: Klee Dienes; +Cc: gdb-patches

Klee Dienes wrote:

[...]
> We've got a ton of stuff to submit, but as a warm-up, I'm starting
> witha relatively minor feature-addition --- a command to save the
> current set of breakpoints to a file that can be read in later.  We've
> been using this on our platform for a few months now, and folks seem
> to like it.  I've also tested the patch against the i386/Linux
> testsuite ... nothing appears to break.

Klee, 

Could you elaborate a little bit on how this change works with
shlib breakpoints, what the original_type field is for, the 
bp_tbreakpoint type, etc.?  In what circumstances is the 
current breakpoint type different from the original breakpoint type?

Also, a couple of comments on the patch:

There are several mentions of future breaks; you should probably
clean those up until you're ready to submit that feature.

And the changelog says:
>         (set_raw_breakpoint): init new original_type field.

but that change itself doesn't seem to be in the patch.

get_breakpoint_count is defined but never used.


I will say that I like the idea, and the implementation's not bad, 
but I'd like it better without that extra bit of complexity.

Michael


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-04 14:48 ` Michael Snyder
@ 2001-12-04 21:11   ` Klee Dienes
  2001-12-11  0:28   ` Klee Dienes
  1 sibling, 0 replies; 19+ messages in thread
From: Klee Dienes @ 2001-12-04 21:11 UTC (permalink / raw)
  To: Michael Snyder; +Cc: gdb-patches


> Could you elaborate a little bit on how this change works with
> shlib breakpoints, what the original_type field is for, the 
> bp_tbreakpoint type, etc.?  In what circumstances is the 
> current breakpoint type different from the original breakpoint type?

The original_type field is for cases like 'tbreak' or 'thbreak' where
the bp_type gets set simply to 'breakpoint', but we nonethless want
the proper command to be written to the generated file.  In these
cases we just set the original_type field to the appropriate value,
and use that when writing out the command to the file.  It's also used
for non-used specified breakpoints --- in these cases the value is set
to 'bp_none', to indicate that it should not be written to the file.

> There are several mentions of future breaks; you should probably
> clean those up until you're ready to submit that feature.

Actually, upon further reflection, I should probably combine the two
diffs and submit them as one patch.  Let me look into how well that
works out and post a new diff tomorrow.

> get_breakpoint_count is defined but never used.

Whoops.  That's just a function needed by another of our patches that
somehow managed to sneak in.  I'll remove it for now.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-04 13:35   ` Klee Dienes
@ 2001-12-05  0:25     ` Eli Zaretskii
  0 siblings, 0 replies; 19+ messages in thread
From: Eli Zaretskii @ 2001-12-05  0:25 UTC (permalink / raw)
  To: klee; +Cc: gdb-patches

> From: Klee Dienes <klee@apple.com>
> Date: Tue, 04 Dec 2001 16:35:28 -0500
> 
> > Thanks!  Please consider writing up some minimal docs for this
> > functionality, for the gdb.texinfo manual.
> 
> Whoops.  How about this:
> 
> --- cygnus.pristine/src/gdb/doc/gdb.texinfo     Fri Nov 30 19:27:53 2001
> +++ cygnus.patched/src/gdb/doc/gdb.texinfo      Tue Dec  4 16:27:02 2001

Great!  Approved.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-04 10:44   ` Klee Dienes
@ 2001-12-05 14:06     ` Tom Tromey
  0 siblings, 0 replies; 19+ messages in thread
From: Tom Tromey @ 2001-12-05 14:06 UTC (permalink / raw)
  To: Klee Dienes; +Cc: Daniel Jacobowitz, gdb-patches

>>>>> "Klee" == Klee Dienes <klee@apple.com> writes:

Klee> The 'future-break' command allows one to specify a breakpoint
Klee> that starts off as 'shlib_disabled' instead of generating an
Klee> error if it can't be set immediately.

Klee> I'm not entirely happy with the future-break command, and
Klee> particularly with its interaction with the save-breakpoints
Klee> mechanism (if you set a breakpoint that is in a shared library
Klee> after shared libraries have been loaded, you have to remember to
Klee> use the future-break command, not the break command).

Doesn't this mean that programs like Insight would be best advised to
*only* set future breakpoints?  In that case let's just add the
functionality directly to the existing breakpoint commands.

Tom


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-04 14:48 ` Michael Snyder
  2001-12-04 21:11   ` Klee Dienes
@ 2001-12-11  0:28   ` Klee Dienes
  2001-12-11  3:55     ` Eli Zaretskii
  1 sibling, 1 reply; 19+ messages in thread
From: Klee Dienes @ 2001-12-11  0:28 UTC (permalink / raw)
  To: Michael Snyder; +Cc: Klee Dienes, gdb-patches


> There are several mentions of future breaks; you should probably
> clean those up until you're ready to submit that feature.

Rather than try to remove the future-break portions of the
'save-breakpoints' command, and have to re-add them later, it probably
makes more sense to just submit both 'save-breakpoints' and
'future-break' as a combined patch.

In addition to the 'save-breakpoints' support already submitted, this
patch adds a new command 'future-break', that works like break except
that when it encounters an error, instead of returning to top-level,
it saves the expression away and re-tries it every time new symbols or
shared libraries are loaded into the program.  It also adds a '-f'
option to the -break-insert MI command, with similar behavior.


2001-12-04  Klee Dienes <kdienes@apple.com>
	Ira L. Ruben  <ira@apple.com>
	James Ingham <jingham@apple.com>
	
	* ui-out.c, ui-out.h: Add ui_out_delete.

	* utils.c, defs.h: Add make_cleanup_ui_out_delete.

	* mi/mi-cmd-break.c, gdb.h (mi_cmd_break_insert): Add support for
	'-f' (future) flag to '-break-insert'.

	* doc/gdb.textinfo: Add documentation for 'save-breakpoints' and
	'future-break'.
	
	* tracepoint.c (tracepoint_save_command): Fix fopen error reporting to
	show errno information just like save-breakpoints command.

	* main.c (captured_main): Initialize $input_radix and $output_radix.
	These are referenced by a save-breakpoints file to preserve radix
	across the breakpoint restoration.
	
	* valprint.c (set_input_radix_1): Set $input_radix.
	(set_output_radix_1): Set $output_radix.

	* breakpoint.h (struct breakpoint): Add 'original_flags' field to
	store original breakpoint flags.
	
	* breakpoint.c:
	Add BP_FUTUREFLAG as an argument to break_command_1 to specify a
	future-breakpoint.
	(write_one_breakpoint): new routine for save_breakpoints_command.
	(save_breakpoints_command): Add save_breakpoints_command.
	(future_break_command): Add future_break_command..
	(_initialize_breakpoint): Define save-breakpoints and its aliases.
	Define future-break and its aliases. Add 'break <x> if <expr>'
	syntax to the documentation for 'break'.
	(gdb_breakpoint): Pass futureflag to do_captured_breakpoint.
	(create_breakpoints): Pass 'origflags' field to store for use by
	save-breakpoints_command.
	(break_command_1, do_captured_breakpoint): Consolidate shared code
	from break_command_1 into do_captured_breakpoint.  break_command_1
	is now a wrapper around do_captured_breakpoint that also processes
	future-breakpoints.  One side-effect of this is that
	mi_cmd_break_insert will now process 'break <x> if <y>" and "break
	<x> thread <n>" semantics, overriding any other values passed as
	part of the command.  It also requires that break commands with
	both a thread and a condition take the form 'break <x> thread <n>
	if <y>' --- but given the free-form nature of 'if'-expressions,
	this seems like a reasonable restriction.
	(parse_breakpoint_sals): Handle case where address
	is NULL and default_breakpoint_valid to set addr_string to "*pc"
	(sal.pc) to avoid warning from breakpoint_re_set_one().
	(print_one_breakpoint): Print the address string of
        an unset future breakpoint.  This was coming up empty before the
        change.
	(captured_parse_breakpoint_sals): new function, so errors can
	be caught in gdb_breakpoint so I can implement future
	break in the mi.
	(insert_breakpoints): Contain messages for enabling/disabling
	breakpoints to one line.
	(disable_breakpoints_in_shlibs): Ditto.
	breakpoints to one line.
	(re_enable_breakpoints_in_shlibs): Ditto.
	(breakpoint_re_set, breakpoint_re_set_all, breakpoint_update):
	Instead of re-parsing all deferred breakpoints every time 
	breakpoint_re_set is called, increment a generation number.
	When breakpoints need to be up-to-date, call breakpoint_update.
	This prevents unnecessary re-parsing of breakpoint information
	(and massive future-break spam) when multiple shared libraries
	are loaded at the same time.

Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.57
diff -u -r1.57 breakpoint.c
--- breakpoint.c	2001/11/11 16:39:59	1.57
+++ breakpoint.c	2001/12/11 08:17:39
@@ -42,6 +42,10 @@
 #include "linespec.h"
 #include "completer.h"
 #include "gdb.h"
+#include "top.h"
+#include "cli-out.h"
+#include <time.h>
+#include <locale.h>
 #ifdef UI_OUT
 #include "ui-out.h"
 #endif
@@ -720,6 +724,7 @@
   static char message1[] = "Error inserting catchpoint %d:\n";
   static char message[sizeof (message1) + 30];
 
+  breakpoint_update ();
 
   ALL_BREAKPOINTS_SAFE (b, temp)
   {
@@ -780,17 +785,16 @@
 		if (!disabled_breaks)
 		  {
 		    target_terminal_ours_for_output ();
-		    warning ("Cannot insert breakpoint %d:", b->number);
-		    warning ("Temporarily disabling shared library breakpoints:");
+		    printf_filtered ("Temporarily disabling shared library breakpoints:");
 		  }
 		disabled_breaks = 1;
-		warning ("breakpoint #%d ", b->number);
+		printf_filtered (" %d ", b->number);
 	      }
 	    else
 #endif
 	      {
 		target_terminal_ours_for_output ();
-		warning ("Cannot insert breakpoint %d:", b->number);
+		warning ("Cannot insert breakpoint %d; disabling it.", b->number);
 #ifdef ONE_PROCESS_WRITETEXT
 		warning ("The same program may be running in another process.");
 #endif
@@ -1014,6 +1018,8 @@
 	  return_val = val;	/* remember failure */
       }
   }
+  if (disabled_breaks)
+    printf_filtered ("\n");
 
   return return_val;
 }
@@ -2285,6 +2291,7 @@
 
 #define BP_TEMPFLAG 1
 #define BP_HARDWAREFLAG 2
+#define BP_FUTUREFLAG 4
 
 /* Check watchpoint condition.  */
 
@@ -3363,11 +3370,16 @@
 	  ui_out_text (uiout, ":");
 	  ui_out_field_int (uiout, "line", b->line_number);
 	}
-      else
+      else if (b->address != 0)
 	{
-	  print_address_symbolic (b->address, stb->stream, demangle, "");
-	  ui_out_field_stream (uiout, "at", stb);
-	}
+          print_address_symbolic (b->address, stb->stream, demangle, "");
+          ui_out_field_stream (uiout, "at", stb);
+        }
+      else
+        {
+	  /* This prints the user's string from "future break" */
+	  ui_out_field_string (uiout, "future-address", b->addr_string);
+        }
 #else
       if (addressprint)
 	{
@@ -4114,14 +4126,16 @@
 	    if (!disabled_shlib_breaks)
 	      {
 		target_terminal_ours_for_output ();
-		warning ("Temporarily disabling shared library breakpoints:");
+		printf_filtered ("Temporarily disabling shared library breakpoints:");
 	      }
 	    disabled_shlib_breaks = 1;
-	    warning ("breakpoint #%d ", b->number);
+	    printf_filtered (" %d ", b->number);
 	  }
       }
-#endif
   }
+#endif
+  if (!silent && disabled_shlib_breaks)
+    printf_filtered ("\n");
 }
 
 /* Try to reenable any breakpoints in shared libraries.  */
@@ -4129,18 +4143,35 @@
 re_enable_breakpoints_in_shlibs (void)
 {
   struct breakpoint *b;
+  int enabled_shlib_breaks = 0;
+  int silent = 0;
 
   ALL_BREAKPOINTS (b)
     if (b->enable_state == bp_shlib_disabled)
-    {
-      char buf[1];
+      {
+	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;
-    }
-}
+	/* 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; 
+	    if (!silent)  
+	      {  
+		if (!enabled_shlib_breaks)  
+		  {  
+		    target_terminal_ours_for_output ();  
+		    printf_filtered ("Re-enabling shared library breakpoints:");  
+		  }  
+		enabled_shlib_breaks = 1;  
+		printf_filtered (" %d", b->number);  
+	      }  
+	  } 
+      } 
+ 
+  if (!silent && enabled_shlib_breaks)  
+    printf_filtered ("\n");  
+} 
 
 #endif
 
@@ -4612,7 +4643,8 @@
 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)
+		    int origflags, int thread, int ignore_count,
+		    int from_tty)
 {
   if (type == bp_hardware_breakpoint)
     {
@@ -4638,6 +4670,7 @@
 	  describe_other_breakpoints (sal.pc, sal.section);
 	
 	b = set_raw_breakpoint (sal, type);
+	b->original_flags = origflags;
 	set_breakpoint_count (breakpoint_count + 1);
 	b->number = breakpoint_count;
 	b->cond = cond[i];
@@ -4672,6 +4705,7 @@
       if (default_breakpoint_valid)
 	{
 	  struct symtab_and_line sal;
+	  char *s;
 	  INIT_SAL (&sal);		/* initialize to zeroes */
 	  sals->sals = (struct symtab_and_line *)
 	    xmalloc (sizeof (struct symtab_and_line));
@@ -4681,6 +4715,11 @@
 	  sal.section = find_pc_overlay (sal.pc);
 	  sals->sals[0] = sal;
 	  sals->nelts = 1;
+	  /* Supply a "*ADDR" for default case (ADDR is pc value).  */
+	  s = paddr_u (sal.pc);
+	  *addr_string = (char **) xmalloc (sizeof (char **));
+	  **addr_string = (char *) xmalloc (strlen (s) + 2);
+	  sprintf (**addr_string, "*%s", s);
 	}
       else
 	error ("No default breakpoint address now.");
@@ -4751,140 +4790,6 @@
     }
 }
 
-/* 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. */
 
@@ -4894,10 +4799,29 @@
     char *condition;
     int hardwareflag;
     int tempflag;
+    int futureflag;
     int thread;
     int ignore_count;
+    int from_tty;
   };
 
+struct captured_parse_breakpoint_sals_args
+  {
+    char **address;
+    struct symtabs_and_lines *sals;
+    char ***addr_string;
+  };
+
+static int
+captured_parse_breakpoint_sals (void *data)
+{
+  struct captured_parse_breakpoint_sals_args *args
+    = (struct captured_parse_breakpoint_sals_args *) data;
+
+  parse_breakpoint_sals (args->address, args->sals, args->addr_string);
+  return (int) GDB_RC_OK;
+}
+
 static int
 do_captured_breakpoint (void *data)
 {
@@ -4909,8 +4833,14 @@
   int i;
   char **addr_string;
   char **cond_string;
-
   char *address_end;
+  int orig_flags;
+  int rc = GDB_RC_OK;
+
+  orig_flags =
+    (args->hardwareflag ? BP_HARDWAREFLAG : 0)
+    | (args->tempflag ? BP_TEMPFLAG : 0)
+    | (args->futureflag ? BP_FUTUREFLAG : 0);
 
   /* Parse the source and lines spec.  Delay check that the expression
      didn't contain trailing garbage until after cleanups are in
@@ -4919,9 +4849,55 @@
   sals.nelts = 0;
   address_end = args->address;
   addr_string = NULL;
-  parse_breakpoint_sals (&address_end, &sals, &addr_string);
 
-  if (!sals.nelts)
+  if (args->futureflag) 
+    {
+      /* This is gross, but we need to catch errors here, since
+	 that is how we are going to find out that this function
+	 could not be found...  But we don't want to change the
+	 error behavior in the case where we are directly trying
+	 to set a breakpoint.  If only gdb had a reasonable error
+	 handling scheme, rather than this stupid longjmp foolishness!
+      */
+      struct captured_parse_breakpoint_sals_args parse_args;
+      parse_args.address = &address_end;
+      parse_args.sals = &sals;
+      parse_args.addr_string = &addr_string;
+
+      rc = catch_errors (captured_parse_breakpoint_sals, &parse_args,
+		    NULL, RETURN_MASK_ALL);
+    }
+  else
+    {
+      parse_breakpoint_sals (&address_end, &sals, &addr_string);
+    }
+
+  if (args->futureflag && rc != GDB_RC_OK)
+    {
+      if (args->futureflag)
+	{
+	  struct symtab_and_line sal = {0, 0};
+	  struct breakpoint *b = set_raw_breakpoint (sal, bp_breakpoint);
+	  
+	  b->number = ++breakpoint_count;
+	  b->addr_string = savestring (args->address, strlen (args->address));
+	  b->enable_state = bp_shlib_disabled;
+	  b->inserted = 0;
+	  b->ignore_count = args->ignore_count;
+	  b->disposition = args->tempflag ? disp_del : disp_donttouch;
+	  if (args->condition != NULL)
+	    {
+	      b->cond_string = savestring (args->condition, 
+					   strlen (args->condition));
+	    }
+	  b->thread = args->thread;
+	  mention (b);
+	  return GDB_RC_OK;
+	}
+      else
+	return GDB_RC_NONE;
+    }
+  else if (!sals.nelts)
     return GDB_RC_NONE;
 
   /* Create a chain of things at always need to be cleaned up. */
@@ -4941,8 +4917,7 @@
   cond_string = xcalloc (sals.nelts, sizeof (char **));
   make_cleanup (xfree, cond_string);
 
-  /* ----------------------------- SNIP -----------------------------
-     Anything added to the cleanup chain beyond this point is assumed
+  /* 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);
@@ -4959,12 +4934,53 @@
   /* 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);
+  {
+    char *tok = address_end;
+    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_end = cond_start;
+	    while (*cond_end != '\000')
+	      cond_end++;
+	    args->condition = tok;
+	    tok = cond_end;
+	  }
+	else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+	  {
+	    char *tmptok;
+	    
+	    tok = end_tok + 1;
+	    tmptok = tok;
+	    args->thread = strtol (tok, &tok, 0);
+	    if (tok == tmptok)
+	      error ("Junk after thread keyword.");
+	    if (! valid_thread_id (args->thread))
+	      error ("Unknown thread %d\n", args->thread);
+	  }
+	else
+	  error ("Junk at end of arguments.");
+      }
+  }
+  
   /* 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++)
@@ -4982,20 +4998,76 @@
 
   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*/);
+		      args->tempflag ? disp_del : disp_donttouch, orig_flags,
+		      args->thread, args->ignore_count, args->from_tty);
 
+  if (args->from_tty && (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);
+  
   return GDB_RC_OK;
+}    
+
+static void break_command_1 (char *arg, int flags, int from_tty)
+{
+  struct captured_breakpoint_args args;
+  args.address = arg;
+  args.condition = NULL;
+  args.hardwareflag = flags & BP_HARDWAREFLAG;
+  args.tempflag = flags & BP_TEMPFLAG;
+  args.futureflag = flags & BP_FUTUREFLAG;
+  args.thread = -1;
+  args.ignore_count = 0;
+  args.from_tty = from_tty;
+
+  if (args.futureflag)
+    {
+      if (args.tempflag)
+	error ("Future breakpoints may not be specified as temporary.");
+      if (args.hardwareflag)
+	error ("Future breakpoints may not be specified as hardware.");
+    }
+  
+  if (args.futureflag)
+    {
+      enum gdb_rc ret = catch_errors (do_captured_breakpoint,
+				      &args, NULL, RETURN_MASK_ALL);
+      if (ret != GDB_RC_OK)
+	{
+	  struct symtab_and_line sal =
+	    {0, 0};
+	  struct breakpoint *b = set_raw_breakpoint (sal, bp_breakpoint);
+
+	  printf_unfiltered
+	    ("Will attempt to resolve \"%s\" on future dynamic loads.\n", args.address);
+
+	  b->number = ++breakpoint_count;
+	  b->addr_string = savestring (args.address, strlen (args.address));
+	  b->enable_state = bp_shlib_disabled;
+	  b->inserted = 0;
+	  b->disposition = disp_donttouch;
+	  if (modify_breakpoint_hook)
+	    modify_breakpoint_hook (b);
+	}
+    }
+  else
+    {
+      do_captured_breakpoint (&args);
+    }
 }
 
 enum gdb_rc
 gdb_breakpoint (char *address, char *condition,
-		int hardwareflag, int tempflag,
+		int hardwareflag, int tempflag, int futureflag,
 		int thread, int ignore_count)
 {
   struct captured_breakpoint_args args;
@@ -5003,6 +5075,7 @@
   args.condition = condition;
   args.hardwareflag = hardwareflag;
   args.tempflag = tempflag;
+  args.futureflag = futureflag;
   args.thread = thread;
   args.ignore_count = ignore_count;
   return catch_errors (do_captured_breakpoint, &args,
@@ -5223,6 +5296,12 @@
 }
 
 void
+future_break_command (char *arg, int from_tty)
+{
+  break_command_1 (arg, BP_FUTUREFLAG, from_tty);
+}
+
+void
 break_command (char *arg, int from_tty)
 {
   break_command_1 (arg, 0, from_tty);
@@ -5446,6 +5525,7 @@
 
   /* Now set up the breakpoint.  */
   b = set_raw_breakpoint (sal, bp_type);
+  b->original_flags = accessflag;
   set_breakpoint_count (breakpoint_count + 1);
   b->number = breakpoint_count;
   b->disposition = disp_donttouch;
@@ -7187,10 +7267,27 @@
   return 0;
 }
 
-/* Re-set all breakpoints after symbols have been re-loaded.  */
+unsigned int symbol_generation = 1;
+unsigned int breakpoint_generation  = 0;
+
+void breakpoint_update ()
+{
+  if (breakpoint_generation != symbol_generation) {
+    breakpoint_re_set_all ();
+    breakpoint_generation = symbol_generation;
+  }
+}
+
 void
 breakpoint_re_set (void)
 {
+  symbol_generation++;
+}
+
+/* Re-set all breakpoints after symbols have been re-loaded.  */
+void
+breakpoint_re_set_all (void)
+{
   struct breakpoint *b, *temp;
   enum language save_language;
   int save_input_radix;
@@ -7570,6 +7667,241 @@
 {
   map_breakpoint_numbers (args, enable_delete_breakpoint);
 }
+
+/* Generate a break, watch, or catch command defined by B to the STREAM.
+
+   General worse case example,
+
+     break <address> thread <t> if <expr>
+     commands
+       <command lines...>
+     end
+     ignore $bpnum <count>
+     disable $bpnum
+
+   In addition "set input-radix <r>" may precede the above sequence but
+   that is generated by save_breakpoints_command() which is this
+   function's caller.  */
+
+static void
+write_one_breakpoint (struct breakpoint *b, struct ui_file *stream, struct ui_out *uiout)
+{
+  register struct command_line *l;
+
+  switch (b->type)
+    {
+    case bp_watchpoint:
+    case bp_hardware_watchpoint:
+    case bp_read_watchpoint:
+    case bp_access_watchpoint:
+      switch (b->original_flags) 
+	{
+	case hw_read:
+	  fprintf_unfiltered (stream, "rwatch %s", b->exp_string);
+	  break;
+	case hw_access:
+	  fprintf_unfiltered (stream, "awatch %s", b->exp_string);
+	  break;
+	case hw_execute:
+	  internal_error (__FILE__, __LINE__, "execute watchpoints unsupported");
+	  break;
+	case hw_write:
+	default:
+	  fprintf_unfiltered (stream, "watch %s", b->exp_string);
+	  break;
+	}
+      
+    case bp_catch_load:
+    case bp_catch_unload:
+      fprintf_unfiltered (stream, "%scatch %sload", b->disposition == disp_del ? "t" : "",
+                                         b->type == bp_catch_unload ? "un" : "");
+      if (b->dll_pathname != NULL)
+        fputs_unfiltered (b->dll_pathname, stream);
+      break;
+
+    case bp_catch_fork:
+      fprintf_unfiltered (stream, "%scatch fork", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_catch_vfork:
+      fprintf_unfiltered (stream, "%scatch vfork", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_catch_exec:
+      fprintf_unfiltered (stream, "%scatch exec", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_catch_catch:
+      fprintf_unfiltered (stream, "%scatch catch", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_catch_throw:
+      fprintf_unfiltered (stream, "%scatch throw", b->disposition == disp_del ? "t" : "");
+      break;
+
+    case bp_breakpoint:
+    case bp_hardware_breakpoint:
+      {
+	char *hardwareflag, *futureflag, *tempflag;
+	
+	hardwareflag = (b->type == bp_hardware_breakpoint) ? "h" : "";
+	futureflag = ((b->enable_state == bp_shlib_disabled) ||
+		      (b->original_flags & BP_FUTUREFLAG)) ? "future-" : "";
+	tempflag = (b->disposition == disp_del) ? "t" : "";
+
+        fprintf_unfiltered (stream, "%s%s%sbreak", futureflag, tempflag, hardwareflag);
+      
+	if (b->addr_string)
+	  {
+	    int len = strlen(b->addr_string) - 1;
+	    if (b->addr_string[len] == ' ')
+	      b->addr_string[len] = 0;
+	    else
+	      len = 0;
+	    fprintf_unfiltered (stream, " %s", b->addr_string);
+	    if (len)
+	      b->addr_string[len] = ' ';
+	  }
+	else if (b->source_file)
+          fprintf_unfiltered (stream, " %s:%d", b->source_file, b->line_number);
+	else
+	  fprintf_unfiltered(stream, " %s",
+			     local_hex_string_custom((unsigned long) b->address, "08l"));
+      }
+      break;
+
+    default:
+      internal_error (__FILE__, __LINE__, "unhandled switch case");
+      break;
+    }
+
+  if (b->thread != -1)
+    fprintf_unfiltered (stream, " thread %d", b->thread);
+
+  if (b->cond_string)
+    fprintf_unfiltered (stream, " if %s", b->cond_string);
+  
+  fputc_unfiltered ('\n', stream);
+
+  if ((l = b->commands))
+    {
+      fputs_unfiltered ("commands\n", stream);
+      print_command_lines (uiout, l, 4);
+      fputs_unfiltered ("end\n", stream);
+    }
+
+  if (b->ignore_count)
+    fprintf_unfiltered (stream, "ignore $bpnum %d\n", b->ignore_count);
+    
+  if (b->enable_state == bp_disabled)
+      fputs_unfiltered ("disable $bpnum\n", stream);
+}
+
+static void 
+save_breakpoints_command (char *arg, int from_tty)
+{
+  struct cleanup *cleanups;
+  register struct breakpoint *b;
+  int found_a_breakpoint = 0;
+  int current_radix = -1;
+  int skip;
+  struct ui_file *stream = NULL;
+  struct ui_out *uiout = NULL;
+  time_t t;
+  char **argv;
+  char *pathname, buf[256];
+
+  dont_repeat ();
+  
+  if (arg == NULL)
+    {
+      error ("Arguments missing: file name in which to save breakpoint commands");
+    }
+  else if ((argv = buildargv (arg)) == NULL)
+    {
+      nomem (0);
+    }
+  cleanups = make_cleanup_freeargv (argv);
+
+  pathname = tilde_expand (arg);
+  make_cleanup (xfree, pathname);
+
+  ALL_BREAKPOINTS (b)
+    {
+      /* Filter out non-user breakpoints. */
+      if (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)
+        continue;
+
+      if (! found_a_breakpoint++)
+        {
+	  stream = gdb_fopen (pathname, FOPEN_WT);
+          if (stream == NULL)
+            error ("Unable to open file '%s' for saving breakpoints (%s)",
+		   arg, strerror (errno));
+	  make_cleanup_ui_file_delete (stream);
+	  uiout = cli_out_new (stream);
+	  if (uiout == NULL)
+	    error ("Unable to create cli_out from file for saving breakpoints");
+	  make_cleanup_ui_out_delete (uiout);
+          if (time (&t) != -1)
+            {
+              char *l = setlocale (LC_ALL, NULL);
+              if (l)
+                {
+                  char *orig_locale = strcpy (xmalloc (strlen (l) + 1), l);
+                  setlocale (LC_ALL, "");
+                  if (strftime (buf, sizeof (buf), "%a %b %e %H:%M:%S %Z %Y", localtime (&t)))
+                    fprintf_unfiltered (stream, "# Saved breakpoints file created on %s\n\n", buf);
+                  setlocale (LC_ALL, orig_locale);
+                }
+            }
+          fprintf_unfiltered (stream, "set $current_radix = $input_radix\n"
+			      "set input-radix 012\n\n");
+          current_radix = 10;
+        }
+
+      skip = (b->commands || b->ignore_count || b->enable_state == bp_disabled);
+      if (skip)
+        fputc_unfiltered ('\n', stream);
+
+      if (b->input_radix != current_radix)
+        {
+          current_radix = b->input_radix;
+          fprintf_unfiltered (stream, "set input-radix 0%o\n", current_radix);
+        }
+
+      write_one_breakpoint (b, stream, uiout);
+
+      if (skip && b->next)
+        fputc_unfiltered ('\n', stream);
+    }
+
+  if (! found_a_breakpoint)
+    printf_filtered ("No breakpoints or watchpoints to save.\n");
+  else
+    {
+      fputs_unfiltered ("\n", stream);
+      if (current_radix != 10)
+        fputs_unfiltered ("set input-radix 012\n", stream);
+      fputs_unfiltered ("set input-radix $current_radix\n", stream);
+      if (from_tty)
+        printf_filtered ("Breakpoints saved to file '%s'.\n", arg);
+    }
+
+  do_cleanups (cleanups);
+}
 \f
 /* Use default_breakpoint_'s, or nothing if they aren't valid.  */
 
@@ -7757,6 +8089,9 @@
 \n\
 Multiple breakpoints at one place are permitted, and useful if conditional.\n\
 \n\
+break ... if <cond> sets condition <cond> on the breakpoint as it is created.\n\
+braek ... [ if <cond> ] thread <n> makes the breakpoint specific to thread <n>.\n\
+\n\
 Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL));
   c->completer = location_completer;
 
@@ -7765,6 +8100,11 @@
   add_com_alias ("bre", "break", class_run, 1);
   add_com_alias ("brea", "break", class_run, 1);
 
+  add_com ("future-break", class_breakpoint, future_break_command,
+	   "Set breakpoint at expression.  If it can't be done now, attempt it\n"
+	   "again each time code is dynamically loaded.");
+  add_com_alias ("fb", "future-break", class_breakpoint, 2);
+  
   add_com ("xbreak", class_breakpoint, break_at_finish_command,
 	   concat ("Set breakpoint at procedure exit. \n\
 Argument may be function name, or \"*\" and an address.\n\
@@ -7936,6 +8276,12 @@
 hardware.)",
 		   &setlist);
   add_show_from_set (c, &showlist);
+
+  c = add_cmd ("save-breakpoints", class_breakpoint, save_breakpoints_command,
+	       "Save current breakpoint definitions as a script.\n\
+Use the -command option or 'source' command in another debug\n\
+'session to restore them.", &cmdlist);
+  c->completer = filename_completer;
 
   can_use_hw_watchpoints = 1;
 }
Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.10
diff -u -r1.10 breakpoint.h
--- breakpoint.h	2001/10/20 23:54:29	1.10
+++ breakpoint.h	2001/12/11 08:17:40
@@ -297,6 +297,9 @@
     char *exec_pathname;
 
     asection *section;
+
+    /* used for save-breakpoints.  */
+    int original_flags;
   };
 \f
 /* The following stuff is an abstract data type "bpstat" ("breakpoint
@@ -515,6 +518,8 @@
 
 /* Forward declarations for prototypes */
 struct frame_info;
+
+extern void set_breakpoint_count (int);
 
 extern enum breakpoint_here breakpoint_here_p (CORE_ADDR);
 
Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.66
diff -u -r1.66 defs.h
--- defs.h	2001/12/02 02:57:13	1.66
+++ defs.h	2001/12/11 08:17:42
@@ -544,6 +544,9 @@
 struct ui_file;
 extern struct cleanup *make_cleanup_ui_file_delete (struct ui_file *);
 
+struct ui_out;
+extern struct cleanup *make_cleanup_ui_out_delete (struct ui_out *);
+
 extern struct cleanup *make_cleanup_close (int fd);
 
 extern struct cleanup *make_cleanup_bfd_close (bfd *abfd);
Index: gdb.h
===================================================================
RCS file: /cvs/src/src/gdb/gdb.h,v
retrieving revision 1.2
diff -u -r1.2 gdb.h
--- gdb.h	2001/09/18 05:00:49	1.2
+++ gdb.h	2001/12/11 08:17:42
@@ -48,7 +48,7 @@
 
 /* Create a breakpoint at ADDRESS (a GDB source and line). */
 enum gdb_rc gdb_breakpoint (char *address, char *condition,
-			    int hardwareflag, int tempflag,
+			    int hardwareflag, int tempflag, int futureflag,
 			    int thread, int ignore_count);
 
 /* Switch thread and print notification. */
Index: main.c
===================================================================
RCS file: /cvs/src/src/gdb/main.c,v
retrieving revision 1.14
diff -u -r1.14 main.c
--- main.c	2001/11/22 00:23:12	1.14
+++ main.c	2001/12/11 08:17:43
@@ -616,6 +616,17 @@
 	catch_command_errors (source_command, gdbinit, 0, RETURN_MASK_ALL);
       }
 
+  /* These need to be set this late in the initialization to ensure that
+     they are defined for the current environment.  They define the
+     radix variables needed by a save-breakpoints file to preserve the
+     radix across the breakpoints restoration assuming they are restored
+     using the -x (-command) command line options.  */
+     
+  set_internalvar (lookup_internalvar ("input_radix"),
+		   value_from_longest (builtin_type_int, (LONGEST) input_radix));
+  set_internalvar (lookup_internalvar ("output_radix"),
+		   value_from_longest (builtin_type_int, (LONGEST) output_radix));
+
   for (i = 0; i < ncmd; i++)
     {
 #if 0
Index: tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.c,v
retrieving revision 1.28
diff -u -r1.28 tracepoint.c
--- tracepoint.c	2001/11/06 23:38:15	1.28
+++ tracepoint.c	2001/12/11 08:17:46
@@ -2262,7 +2262,7 @@
   struct action_line *line;
   FILE *fp;
   char *i1 = "    ", *i2 = "      ";
-  char *indent, *actionline;
+  char *indent, *actionline, *pathname;
   char tmp[40];
 
   if (args == 0 || *args == 0)
@@ -2274,9 +2274,12 @@
       return;
     }
 
-  if (!(fp = fopen (args, "w")))
-    error ("Unable to open file '%s' for saving tracepoints");
-
+  pathname = tilde_expand (args);
+  if (!(fp = fopen (pathname, "w")))
+    error ("Unable to open file '%s' for saving tracepoints (%s)",
+	   args, strerror (errno));
+  xfree (pathname);
+  
   ALL_TRACEPOINTS (tp)
   {
     if (tp->addr_string)
Index: ui-out.c
===================================================================
RCS file: /cvs/src/src/gdb/ui-out.c,v
retrieving revision 1.18
diff -u -r1.18 ui-out.c
--- ui-out.c	2001/07/06 03:53:11	1.18
+++ ui-out.c	2001/12/11 08:17:47
@@ -1117,6 +1117,14 @@
   return uiout;
 }
 
+void
+ui_out_delete (struct ui_out *uiout)
+{
+  if (uiout->data != NULL)
+    xfree (uiout->data);
+  xfree (uiout);
+}
+
 /* standard gdb initialization hook */
 
 void
Index: ui-out.h
===================================================================
RCS file: /cvs/src/src/gdb/ui-out.h,v
retrieving revision 1.15
diff -u -r1.15 ui-out.h
--- ui-out.h	2001/07/06 03:53:11	1.15
+++ ui-out.h	2001/12/11 08:17:47
@@ -272,4 +272,6 @@
 				  struct ui_out_data *data,
 				  int flags);
 
+extern void ui_out_delete (struct ui_out *uiout);
+
 #endif /* UI_OUT_H */
Index: utils.c
===================================================================
RCS file: /cvs/src/src/gdb/utils.c,v
retrieving revision 1.51
diff -u -r1.51 utils.c
--- utils.c	2001/11/15 18:35:05	1.51
+++ utils.c	2001/12/11 08:17:49
@@ -254,6 +254,18 @@
   return make_my_cleanup (&cleanup_chain, do_ui_file_delete, arg);
 }
 
+static void
+do_ui_out_delete (void *arg)
+{
+  ui_out_delete (arg);
+}
+
+struct cleanup *
+make_cleanup_ui_out_delete (struct ui_out *arg)
+{
+  return make_my_cleanup (&cleanup_chain, do_ui_out_delete, arg);
+}
+
 struct cleanup *
 make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
 		 void *arg)
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.59
diff -u -r1.59 gdb.texinfo
--- gdb.texinfo	2001/11/30 23:03:09	1.59
+++ gdb.texinfo	2001/12/11 08:18:09
@@ -2335,6 +2335,7 @@
 * Set Catchpoints::             Setting catchpoints
 * Delete Breaks::               Deleting breakpoints
 * Disabling::                   Disabling breakpoints
+* Saving::                      Saving breakpoints
 * Conditions::                  Break conditions
 * Break Commands::              Breakpoint command lists
 * Breakpoint Menus::            Breakpoint menus
@@ -2420,6 +2421,14 @@
 above (or no argument) specifying where to break.  @xref{Conditions,
 ,Break conditions}, for more information on breakpoint conditions.
 
+@kindex future-break
+@item future-break @var{args}
+Set a `future' breakpoint.  @var{args} are the same as for the
+@code{hbreak} command and the breakpoint is set in the same way.
+However, if @value{GDBN} is unable to set the breakpoint when the
+command is executed, it will store the expression, and try again to set
+it after any new symbol files or shared libraries are loaded.
+
 @kindex tbreak
 @item tbreak @var{args}
 Set a breakpoint enabled only for one stop.  @var{args} are the
@@ -2941,6 +2950,22 @@
 breakpoint of its own, but it does not change the state of your other
 breakpoints; see @ref{Continuing and Stepping, ,Continuing and
 stepping}.)
+
+@node Saving
+@subsection Saving breakpoints
+@cindex save breakpoints for future sessions
+
+Sometimes, it can be convenient to save the current set of breakpoints
+for use in a future debugging session:
+
+@table @code
+@kindex save-breakpoints
+@item save-breakpoints
+Save all current breakpoint definitions, together with their
+ignore-counts and command scripts, into the file @file{@var{filename}}.
+To read the saved breakpoint definitions, use the @code{source} command
+(@pxref{Command Files}).
+@end table
 
 @node Conditions
 @subsection Break conditions
Index: mi/mi-cmd-break.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-cmd-break.c,v
retrieving revision 1.6
diff -u -r1.6 mi-cmd-break.c
--- mi-cmd-break.c	2001/09/18 05:00:51	1.6
+++ mi-cmd-break.c	2001/12/11 08:18:12
@@ -60,15 +60,17 @@
   {
     REG_BP,
     HW_BP,
+    FUT_BP,
     REGEXP_BP
   };
 
 /* Insert a breakpoint. The type of breakpoint is specified by the
-   first argument: -break-insert <location> --> insert a regular
-   breakpoint.  -break-insert -t <location> --> insert a temporary
-   breakpoint.  -break-insert -h <location> --> insert an hardware
-   breakpoint.  -break-insert -t -h <location> --> insert a temporary
-   hw bp.  
+   first argument:
+   -break-insert <location> --> insert a regular breakpoint.
+   -break-insert -t <location> --> insert a temporary breakpoint.
+   -break-insert -h <location> --> insert an hardware breakpoint.
+   -break-insert -t -h <location> --> insert a temporary hw bp.  
+   -break-insert -f <location> --> insert a future breakpoint.  
    -break-insert -r <regexp> --> insert a bp at functions matching
    <regexp> */
 
@@ -85,13 +87,14 @@
   struct gdb_events *old_hooks;
   enum opt
     {
-      HARDWARE_OPT, TEMP_OPT /*, REGEXP_OPT */ , CONDITION_OPT,
+      HARDWARE_OPT, TEMP_OPT, FUTURE_OPT /*, REGEXP_OPT */ , CONDITION_OPT,
       IGNORE_COUNT_OPT, THREAD_OPT
     };
   static struct mi_opt opts[] =
   {
     {"h", HARDWARE_OPT, 0},
     {"t", TEMP_OPT, 0},
+    {"f", FUTURE_OPT, 0},
     {"c", CONDITION_OPT, 1},
     {"i", IGNORE_COUNT_OPT, 1},
     {"p", THREAD_OPT, 1},
@@ -115,6 +118,9 @@
 	case HARDWARE_OPT:
 	  type = HW_BP;
 	  break;
+	case FUTURE_OPT:
+	  type = FUT_BP;
+	  break;
 #if 0
 	case REGEXP_OPT:
 	  type = REGEXP_BP;
@@ -143,13 +149,12 @@
   switch (type)
     {
     case REG_BP:
-      rc = gdb_breakpoint (address, condition,
-			   0 /*hardwareflag */ , temp_p,
-			   thread, ignore_count);
-      break;
     case HW_BP:
+    case FUT_BP:
       rc = gdb_breakpoint (address, condition,
-			   1 /*hardwareflag */ , temp_p,
+			   (type == REG_BP) ? 0 : 1,
+			   temp_p,
+			   (type == FUT_BP) ? 0 : 1,
 			   thread, ignore_count);
       break;
 #if 0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-11  0:28   ` Klee Dienes
@ 2001-12-11  3:55     ` Eli Zaretskii
  2001-12-11  8:35       ` Klee Dienes
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2001-12-11  3:55 UTC (permalink / raw)
  To: Klee Dienes; +Cc: Michael Snyder, gdb-patches


On Tue, 11 Dec 2001, Klee Dienes wrote:

> In addition to the 'save-breakpoints' support already submitted, this
> patch adds a new command 'future-break', that works like break except
> that when it encounters an error, instead of returning to top-level,

Thanks.

Can we perhaps come up with a better name instead of `future-break'?  It 
doesn't really describe well enough what does this command do, IMHO.  For 
example, if it is possible to put a breakpoint at the time the user 
issues the command, GDB will do that without delays, so the word 
``future'' is inaccurate.

A related question is: maybe we should make all breakpoint commands 
behave like this by default?

> 	* doc/gdb.textinfo: Add documentation for 'save-breakpoints' and
> 	'future-break'.

The changes to the docs are approved, with a few minor comments (see 
below).

> 	* main.c (captured_main): Initialize $input_radix and $output_radix.
> 	These are referenced by a save-breakpoints file to preserve radix
> 	across the breakpoint restoration.

This aspect of save-breakpoints isn't mentioned in the gdb.texinfo 
patch.  Please add it; I think it's important to say that in the manual, 
since the radix has effect on features other than breakpoints.

> +@kindex future-break
> +@item future-break @var{args}
> +Set a `future' breakpoint.  @var{args} are the same as for the
         ^^^^^^^^
This should be either ``future'' or @emph{future}, probably the former.

> +@code{hbreak} command and the breakpoint is set in the same way.

Is it really like hbreak or like break?  That is, does GDB set a 
hardware-assisted breakpoint?  If so, what happens on platforms which 
don't support hbreak?

Also, I'd suggest to add a sentence or two about the situations where 
this command could be useful.

> +@item save-breakpoints
> +Save all current breakpoint definitions, together with their
> +ignore-counts and command scripts, into the file @file{@var{filename}}.

If the command accepts an argument, the file name, the @item above should 
say this:

  @item save-breakpoints @var{filename}


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-11  3:55     ` Eli Zaretskii
@ 2001-12-11  8:35       ` Klee Dienes
  2001-12-11  9:09         ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Klee Dienes @ 2001-12-11  8:35 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Klee Dienes, Michael Snyder, gdb-patches


> A related question is: maybe we should make all breakpoint commands 
> behave like this by default?

My opinion is that we should not.  I consider future-breakpoints as
something to be used only when GDB is for whatever reason unable to
properly load the symbols for something in advance.  In general, I
much-prefer the error-checking behavior of traditional 'break'.

> Can we perhaps come up with a better name instead of `future-break'?  It 
> doesn't really describe well enough what does this command do, IMHO.  For 
> example, if it is possible to put a breakpoint at the time the user 
> issues the command, GDB will do that without delays, so the word 
> ``future'' is inaccurate.

I'd certainly be open to new names, but after years of using
'future-break' and 'fb', it's hard for me to come up with one.  Other
options would be to use a variable such as 'set
defer-breakpoints-on-error 1' to enable the behavior (I tend to think
this is a bit cumbersome), or to add a '--retry' option to the
breakpoint commands.  Does anyone have any suggestions?

>> 	* main.c (captured_main): Initialize $input_radix and $output_radix.
>> 	These are referenced by a save-breakpoints file to preserve radix
>> 	across the breakpoint restoration.

> This aspect of save-breakpoints isn't mentioned in the gdb.texinfo 
> patch.  Please add it; I think it's important to say that in the manual, 
> since the radix has effect on features other than breakpoints.

In case I gave the wrong idea, the reason for the introduction of
these variables was to prevent the save-breakpoint implementation from
changing the default radix.  The idea is that the saved command file
contains commands of the form:

  set $current_radix = $input_radix
  set input-radix 012
  break internal_error
  set input-radix $current_radix

The only reason we need to add $input_radix as a variable is that
there is no good way to use the output of a command as input to
another command; otherwise we'd probably have done something like

  set $current_radix = `show input-radix`

.  I'm certainly willing to document the additional convenience
variables, but I'm not sure where a good section for them would be.
Perhaps in the documentation for 'set input-radix'?



Index: gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.59
diff -u -r1.59 gdb.texinfo
--- gdb.texinfo 2001/11/30 23:03:09     1.59
+++ gdb.texinfo 2001/12/11 16:22:23
@@ -2335,6 +2335,7 @@
 * Set Catchpoints::             Setting catchpoints
 * Delete Breaks::               Deleting breakpoints
 * Disabling::                   Disabling breakpoints
+* Saving::                      Saving breakpoints
 * Conditions::                  Break conditions
 * Break Commands::              Breakpoint command lists
 * Breakpoint Menus::            Breakpoint menus
@@ -2420,6 +2421,18 @@
 above (or no argument) specifying where to break.  @xref{Conditions,
 ,Break conditions}, for more information on breakpoint conditions.
 
+@kindex future-break
+@item future-break @var{args}
+Set a ``future'' breakpoint.  @var{args} are the same as for the
+@code{break} command and the breakpoint is set in the same way.
+However, if @value{GDBN} is unable to set the breakpoint when the
+command is executed, it will store the expression, and try again to set
+it after any new symbol files or shared libraries are loaded.  This
+command is typically used when setting breakpoints in shared libraries
+or plug-ins that are not able to be detected by GDB at start-up (either
+because they are dynamically loaded at run-time, or because GDB is for
+some other reason unable to detect them at start-up).
+
 @kindex tbreak
 @item tbreak @var{args}
 Set a breakpoint enabled only for one stop.  @var{args} are the
@@ -2942,6 +2955,22 @@
 breakpoints; see @ref{Continuing and Stepping, ,Continuing and
 stepping}.)
 
+@node Saving
+@subsection Saving breakpoints
+@cindex save breakpoints for future sessions
+
+Sometimes, it can be convenient to save the current set of breakpoints
+for use in a future debugging session:
+
+@table @code
+@kindex save-breakpoints
+@item save-breakpoints @var{filename}
+Save all current breakpoint definitions, together with their
+ignore-counts and command scripts, into the file @file{@var{filename}}.
+To read the saved breakpoint definitions, use the @code{source} command
+(@pxref{Command Files}).
+@end table
+
 @node Conditions
 @subsection Break conditions
 @cindex conditional breakpoints
@@ -13080,13 +13109,13 @@
 example, any of
 
 @smallexample
-set radix 012
-set radix 10.
-set radix 0xa
+set input-radix 012
+set input-radix 10.
+set input-radix 0xa
 @end smallexample
 
 @noindent
-sets the base to decimal.  On the other hand, @samp{set radix 10}
+sets the base to decimal.  On the other hand, @samp{set input-radix 10}
 leaves the radix unchanged no matter what it was.
 
 @kindex set output-radix
@@ -13103,6 +13132,10 @@
 @item show output-radix
 Display the current default base for numeric display.
 @end table
+
+The current input and output radixes can also be stored and set using
+the @value{GDBN} convenience variables @code{$input_radix} and
+@code{$output_radix}.
 
 @node Messages/Warnings
 @section Optional warnings and messages


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-11  8:35       ` Klee Dienes
@ 2001-12-11  9:09         ` Eli Zaretskii
  2001-12-11 13:23           ` Klee Dienes
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2001-12-11  9:09 UTC (permalink / raw)
  To: klee; +Cc: msnyder, gdb-patches

> From: Klee Dienes <klee@apple.com>
> Date: Tue, 11 Dec 2001 11:34:17 -0500
> 
> .  I'm certainly willing to document the additional convenience
> variables, but I'm not sure where a good section for them would be.

It sounds like I've misread the code: I thought restoring the
breakpoints also sets input-radix for the rest of the session.  But I
understand now that the saved commands undo that effect before the
session continues, is that right?  If so, there's no need to document
anything about that, except, perhaps, saying that the breakpoints,
when restored, will use the same input-radix as when they were
defined.

With that comment, the patch you posted is approved.  Thanks.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-11  9:09         ` Eli Zaretskii
@ 2001-12-11 13:23           ` Klee Dienes
  2001-12-12  0:32             ` Eli Zaretskii
  0 siblings, 1 reply; 19+ messages in thread
From: Klee Dienes @ 2001-12-11 13:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: klee, msnyder, gdb-patches

Eli Zaretskii <eliz@is.elta.co.il> writes:

> session continues, is that right?  If so, there's no need to document
> anything about that, except, perhaps, saying that the breakpoints,
> when restored, will use the same input-radix as when they were
> defined.

I'd say that's not really necessary, since it's really just "saved
breapoints will be restored correctly even if you have an odd
input-radix set," which is what one would generally assume would
happen.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-11 13:23           ` Klee Dienes
@ 2001-12-12  0:32             ` Eli Zaretskii
  2001-12-14 12:45               ` Klee Dienes
  0 siblings, 1 reply; 19+ messages in thread
From: Eli Zaretskii @ 2001-12-12  0:32 UTC (permalink / raw)
  To: Klee Dienes; +Cc: msnyder, gdb-patches


On 11 Dec 2001, Klee Dienes wrote:

> Eli Zaretskii <eliz@is.elta.co.il> writes:
> 
> > session continues, is that right?  If so, there's no need to document
> > anything about that, except, perhaps, saying that the breakpoints,
> > when restored, will use the same input-radix as when they were
> > defined.
> 
> I'd say that's not really necessary

Okay, I don't mind if you leave the text as you suggested originally.

, since it's really just "saved
> breapoints will be restored correctly even if you have an odd
> input-radix set," which is what one would generally assume would
> happen.
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-12  0:32             ` Eli Zaretskii
@ 2001-12-14 12:45               ` Klee Dienes
  2001-12-14 12:50                 ` Daniel Jacobowitz
  0 siblings, 1 reply; 19+ messages in thread
From: Klee Dienes @ 2001-12-14 12:45 UTC (permalink / raw)
  To: gdb-patches


The following patch overlaps a bit with the previous one (it requires
the symnbol_generation support), but otherwise it should be
standalone.  I'm mainly submitting it now because it is required by
some of the Objective-C patches, but is significant enough in it's own
right that I wanted to address any issues with it separately rather
than as part of the Objective-C submission.

There are two primary things changed by the patch:

1) is that functions in the target used by GDB ("malloc",
"scm_lookup_cstr", and later a ton of Objective-C functions) now have
their values cached and re-used unless the symbol table has changed
in-between calls.  This is a performance win overall, and a particular
win when dispatching Objective-C method calls and looking up
Objective-C type information from the runtime.

2) is potentially a bit more controversial.  It adds "expected return
type" support to the target function call interface.  The "expected
return type" is specified using cast syntax; it is ignored if actual
type information for the function is available.  If no type
information is provided for a function, the user is now required to
provide an expected return type using the cast syntax, or get an
error.

Some examples:

(gdb) print fabs (3.0)			(no type information present)
Unable to call function at 0x%lx: no return type information available.
To call this function anyway, you can cast the return type explicitly
(e.g. 'print (float) fabs (3.0)').

(gdb) print (float) fabs (-3.12)	(no type information present)
$1 = 3.11999989

(gdb) print (int) fabs (-3.12)		(no type information present)
$2 = 1074329026
(here, the return value of `fabs' has been interpreted as an int
... not cast to one)

(gdb) print (int) fabs (-3.12)		(type information present)
$3 = -3
(since type information was available, the return value was
interpreted as a float, then cast to an int).

(gdb) print (struct stat) fabs (-3.12)	(no type information present)
Cannot access memory at address 0xf5c28f6
(this causes an error, since the struct return convention is being
misused)

  struct s { int i; int j; };
  struct s f (void) { struct s ss = { 3, 1 }; return ss; }

(gdb) print f ()			(no type information present)
Unable to call function at 0x%lx: no return type information available.
To call this function anyway, you can cast the return type explicitly
(e.g. 'print (float) fabs (3.0)').

(gdb) print (struct s) f (3.0)		(no type information present)
$4 = {i = 3, j = 1}

(gdb) print (float) f (3.0)		(no type information present)
Program received signal SIGSEGV, Segmentation fault.
0x0804841d in f ()
(here we lied to GDB about the return type, causing it to generate
incorrect struct return code).

Compare this to the old behavior:

(gdb) print fabs (3.0)			(no type information present)
$1 = 1074266112
(GDB has no type information available, so it assumes 'int').

(gdb) print (float) fabs (-3.12)	(no type information present)
$2 = 1.07426611e+09
(GDB still assumes the function returns 'int', then casts the result
to a float).

  struct s { int i; int j; };
  struct s f (void) { struct s ss = { 3, 1 }; return ss; }

(gdb) print f ()
Program received signal SIGSEGV, Segmentation fault.
0x0804841d in f ()
(here there is no way out ... no matter what we pass in as the return
value to f(), GDB will generate the calling convention for a function
returning int)

The reason I suggest 2) might be controversial is that the old
behavior can be convenient in the general case.  A lot of functions
*do* return int, and when debugging programs without symbols, it can
be annoying to have to declare the return type, just to make the rare
case when functions return floats/structs behave correctly.  But I'd
argue that it's not *that* big a deal to cast a return value, and
correctness must always take priority.

We've been using a variant of this patch at Apple for a little over a
year; it seems to be working.  The test suite shows four additional
unexpected successes when I run it with this patch, but I figure
that's probably OK.

I haven't included documentation patches ... where (if anywhere) would
you suggest I include them?  I wasn't able to find a compelling spot.
Or perhaps one could argue that the new behavior is simply "correct,"
and the new message you get from print fabs (3.0) is enough.


2001-12-12  Klee Dienes <kdienes@apple.com>

	* breakpoint.c (breakpoint_re_set, breakpoint_re_set_all,
	breakpoint_update): Instead of re-parsing all deferred breakpoints
	every time breakpoint_re_set is called, increment a generation
	number.  When breakpoints need to be up-to-date, call
	breakpoint_update.  This prevents unnecessary re-parsing of
	breakpoint information (and massive future-break spam) when
	multiple shared libraries are loaded at the same time.

	* breakpoint.h: export symbol_generation, breakpoint_update.

	* eval.c (evaluate_subexp_standard): when called with
	EVAL_AVOID_SIDE_EFFECTS, return the passed-in `expect_type' if the
	type of the evaluated expression is unknown.  Also update to use
	the new `call_function_by_hand_expecting_type' interface.

	* gdbtypes.c, gdbtypes.h: add new type
	builtin_type_voidptrfuncptr.

	* parse.c, parse.h: export msym_{text,data,unknown}_symbol_type.
	Make them of type TYPE_CODE_ERROR instead of TYPE_CODE_INT.

	* scm-lang.c (scm_lookup_name): update to use new interface to
	find_function_in_inferior.

	* valops.c (create_cached_function, lookup_cached_function): add.
	These functions create a new data type (a `cached_value'), whose
	purpose is to store the lookup of commonly used symbols GDB needs
	from the inferior.  For example, evaluating the expression 'print
	"hello"' causes GDB to call `malloc' in the target.  Looking up
	the symbol for `malloc' takes a non-trivial amount of time, and
	has no need to be done if the symbols have not changed.
	create/lookup_cached_function allow GDB to cache the results of
	these lookups; re-looking them up only when the symbols have
	changed.
	(find_function_in_inferior): add a default type as second
	argument.  This type will be used for the returned value if no
	type information is available for the function (previously, the
	type was assumed to be (char *) (*).
	(hand_function_call): add new `expect_type' parameter.  This type
	will be used as the return type for the function if no type
	information is available.
	(call_function_by_hand_expecting_type): like
	call_function_by_hand, but uses the new `expect_type' interface to
	hand_function_call.
	(call_function_by_hand): implement as a wrapper to
	call_function_by_hand_expecting_type.
	(value_allocate_space_in_inferior): use new cached_function
	interface.
	(find_function_addr): if asked the return type of a function with
	type TYPE_CODE_ERROR, return TYPE_CODE_ERROR.
	
	* value.h (call_function_by_hand_expecting_type): add.
	(cached_value) add.
	(create_cached_function) add.
	(lookup_cached_function) add.
	(find_function_in_inferior) update to new signature.


Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.57
diff -u -r1.57 breakpoint.c
--- breakpoint.c	2001/11/11 16:39:59	1.57
+++ breakpoint.c	2001/12/14 19:42:15
@@ -70,8 +70,12 @@
 
 static void ignore_command (char *, int);
 
+void breakpoint_update (void);
+
 static int breakpoint_re_set_one (PTR);
 
+static void breakpoint_re_set_all (void);
+
 static void clear_command (char *, int);
 
 static void catch_command (char *, int);
@@ -720,6 +724,7 @@
   static char message1[] = "Error inserting catchpoint %d:\n";
   static char message[sizeof (message1) + 30];
 
+  breakpoint_update ();
 
   ALL_BREAKPOINTS_SAFE (b, temp)
   {
@@ -7187,9 +7192,26 @@
   return 0;
 }
 
-/* Re-set all breakpoints after symbols have been re-loaded.  */
+unsigned int symbol_generation = 1;
+static unsigned int breakpoint_generation = 0;
+
+void breakpoint_update (void)
+{
+  if (breakpoint_generation != symbol_generation) {
+    breakpoint_re_set_all ();
+    breakpoint_generation = symbol_generation;
+  }
+}
+
 void
 breakpoint_re_set (void)
+{
+  symbol_generation++;
+}
+
+/* Re-set all breakpoints after symbols have been re-loaded.  */
+static void
+breakpoint_re_set_all (void)
 {
   struct breakpoint *b, *temp;
   enum language save_language;
Index: gdb/breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.10
diff -u -r1.10 breakpoint.h
--- breakpoint.h	2001/10/20 23:54:29	1.10
+++ breakpoint.h	2001/12/14 19:42:16
@@ -305,6 +305,8 @@
 
 typedef struct bpstats *bpstat;
 
+extern unsigned int symbol_generation;
+
 /* Interface:  */
 /* Clear a bpstat so that it says we are not at any breakpoint.
    Also free any storage that is part of a bpstat.  */
@@ -525,6 +527,8 @@
 extern int breakpoint_thread_match (CORE_ADDR, ptid_t);
 
 extern void until_break_command (char *, int);
+
+extern void breakpoint_update (void);
 
 extern void breakpoint_re_set (void);
 
Index: gdb/eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.17
diff -u -r1.17 eval.c
--- eval.c	2001/12/10 23:05:00	1.17
+++ eval.c	2001/12/14 19:42:18
@@ -928,15 +928,20 @@
 	     gdb isn't asked for it's opinion (ie. through "whatis"),
 	     it won't offer it. */
 
-	  struct type *ftype =
+	  struct type *type =
 	  TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]));
 
-	  if (ftype)
-	    return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])));
+	  if (type)
+	    {
+	      if ((TYPE_CODE (type) == TYPE_CODE_ERROR) && expect_type)
+		return allocate_value (expect_type);
+	      else
+		return allocate_value (type);
+	    }
 	  else
 	    error ("Expression of type other than \"Function returning ...\" used as function");
 	}
-      return call_function_by_hand (argvec[0], nargs, argvec + 1);
+      return call_function_by_hand_expecting_type (argvec[0], expect_type, nargs, argvec + 1);
       /* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve  */
 
     case OP_F77_UNDETERMINED_ARGLIST:
Index: gdb/gdbtypes.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.c,v
retrieving revision 1.34
diff -u -r1.34 gdbtypes.c
--- gdbtypes.c	2001/12/12 02:11:51	1.34
+++ gdbtypes.c	2001/12/14 19:42:22
@@ -96,6 +96,7 @@
 struct type *builtin_type_void_func_ptr;
 struct type *builtin_type_CORE_ADDR;
 struct type *builtin_type_bfd_vma;
+struct type *builtin_type_voidptrfuncptr;
 
 int opaque_type_resolution = 1;
 int overload_debug = 0;
@@ -3208,6 +3209,8 @@
     init_type (TYPE_CODE_INT, TARGET_BFD_VMA_BIT / 8,
 	       TYPE_FLAG_UNSIGNED,
 	       "__bfd_vma", (struct objfile *) NULL);
+  builtin_type_voidptrfuncptr =
+    lookup_pointer_type (lookup_function_type (lookup_pointer_type (builtin_type_void)));
 }
 
 
Index: gdb/gdbtypes.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.h,v
retrieving revision 1.21
diff -u -r1.21 gdbtypes.h
--- gdbtypes.h	2001/12/10 06:17:01	1.21
+++ gdbtypes.h	2001/12/14 19:42:24
@@ -930,6 +930,7 @@
    bit address type even though the TARGET has a 64 bit pointer type
    (cf MIPS). */
 extern struct type *builtin_type_bfd_vma;
+extern struct type *builtin_type_voidptrfuncptr;
 
 /* Explicit sizes - see C9X <intypes.h> for naming scheme */
 extern struct type *builtin_type_int8;
Index: gdb/parse.c
===================================================================
RCS file: /cvs/src/src/gdb/parse.c,v
retrieving revision 1.17
diff -u -r1.17 parse.c
--- parse.c	2001/11/15 01:55:59	1.17
+++ parse.c	2001/12/14 19:42:25
@@ -399,9 +399,9 @@
    based on the language, but they no longer have names like "int", so
    the initial rationale is gone.  */
 
-static struct type *msym_text_symbol_type;
-static struct type *msym_data_symbol_type;
-static struct type *msym_unknown_symbol_type;
+struct type *msym_text_symbol_type;
+struct type *msym_data_symbol_type;
+struct type *msym_unknown_symbol_type;
 
 void
 write_exp_msymbol (struct minimal_symbol *msymbol, 
@@ -1360,12 +1360,12 @@
 
   msym_text_symbol_type =
     init_type (TYPE_CODE_FUNC, 1, 0, "<text variable, no debug info>", NULL);
-  TYPE_TARGET_TYPE (msym_text_symbol_type) = builtin_type_int;
+  TYPE_TARGET_TYPE (msym_text_symbol_type) = builtin_type_error;
   msym_data_symbol_type =
-    init_type (TYPE_CODE_INT, TARGET_INT_BIT / HOST_CHAR_BIT, 0,
+    init_type (TYPE_CODE_ERROR, 0, 0,
 	       "<data variable, no debug info>", NULL);
   msym_unknown_symbol_type =
-    init_type (TYPE_CODE_INT, 1, 0,
+    init_type (TYPE_CODE_ERROR, 0, 0,
 	       "<variable (not text or data), no debug info>",
 	       NULL);
 
Index: gdb/parser-defs.h
===================================================================
RCS file: /cvs/src/src/gdb/parser-defs.h,v
retrieving revision 1.6
diff -u -r1.6 parser-defs.h
--- parser-defs.h	2001/11/15 01:55:59	1.6
+++ parser-defs.h	2001/12/14 19:42:25
@@ -39,6 +39,10 @@
 extern int expout_size;
 extern int expout_ptr;
 
+extern struct type *msym_text_symbol_type;
+extern struct type *msym_data_symbol_type;
+extern struct type *msym_unknown_symbol_type;
+
 /* If this is nonzero, this block is used as the lexical context
    for symbol names.  */
 
Index: gdb/scm-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/scm-lang.c,v
retrieving revision 1.6
diff -u -r1.6 scm-lang.c
--- scm-lang.c	2001/11/10 20:44:38	1.6
+++ scm-lang.c	2001/12/14 19:42:26
@@ -169,7 +169,7 @@
     /* FIXME in this case, we should try lookup_symbol first */
     args[2] = value_from_longest (builtin_type_scm, SCM_EOL);
 
-  func = find_function_in_inferior ("scm_lookup_cstr");
+  func = find_function_in_inferior ("scm_lookup_cstr", builtin_type_voidptrfuncptr);
   val = call_function_by_hand (func, 3, args);
   if (!value_logical_not (val))
     return value_ind (val);
@@ -192,7 +192,7 @@
   write_memory (iaddr, str, len);
   /* FIXME - should find and pass env */
   write_memory (iaddr + len, "", 1);
-  func = find_function_in_inferior ("scm_evstr");
+  func = find_function_in_inferior ("scm_evstr", builtin_type_voidptrfuncptr);
   return call_function_by_hand (func, 1, &addr);
 }
 
Index: gdb/valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.44
diff -u -r1.44 valops.c
--- valops.c	2001/12/12 02:11:52	1.44
+++ valops.c	2001/12/14 19:42:30
@@ -32,6 +32,7 @@
 #include "gdbcmd.h"
 #include "regcache.h"
 #include "cp-abi.h"
+#include "parser-defs.h"
 
 #include <errno.h>
 #include "gdb_string.h"
@@ -88,11 +89,49 @@
 int unwind_on_signal_p = 0;
 \f
 
+cached_value_ptr
+create_cached_function (char *name, struct type *type)
+{
+  cached_value_ptr ptr;
+
+  ptr = (struct cached_value *) xmalloc (sizeof (struct cached_value));
+  ptr->name = xstrdup (name);
+  ptr->type = type;
+  memset (&ptr->val, 0, sizeof (struct value));
+  ptr->generation = (unsigned int) -1;
+
+  return ptr;
+}
+
+value_ptr
+lookup_cached_function (cached_value_ptr cval)
+{
+  value_ptr val = NULL;
+  value_ptr next = NULL;
+
+  if (cval->generation != symbol_generation)
+    {
+      val = find_function_in_inferior (cval->name, cval->type);
+      cval->val = *val;
+      cval->val.next = NULL;
+      cval->generation = symbol_generation;
+    }
+
+  val = allocate_value (cval->val.type);
+  next = val->next;
+  *val = cval->val;
+  val->next = next;
+
+  return val;
+}
 
-/* Find the address of function name NAME in the inferior.  */
+/* Find the address of function name NAME in the inferior.  If no type
+   information is available for NAME, use `type' as the type for the
+   resulting value.
+*/
 
 value_ptr
-find_function_in_inferior (char *name)
+find_function_in_inferior (char *name, struct type *type)
 {
   register struct symbol *sym;
   sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0, NULL);
@@ -110,20 +149,18 @@
       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);
+	  if (type != NULL)
+	    return value_from_longest (type, (LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+	  else
+	    return value_from_longest (lookup_pointer_type (msym_text_symbol_type),
+				       (LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
 	}
       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);
+	    error ("evaluation of this expression requires the program to have a function named \"%s\".", name);
 	}
     }
 }
@@ -135,10 +172,14 @@
 value_allocate_space_in_inferior (int len)
 {
   value_ptr blocklen;
-  register value_ptr val = find_function_in_inferior ("malloc");
+  value_ptr val;
+  static cached_value_ptr fval = NULL;
+  
+  if (fval == NULL) 
+    fval = create_cached_function ("malloc", builtin_type_voidptrfuncptr); 
 
   blocklen = value_from_longest (builtin_type_int, (LONGEST) len);
-  val = call_function_by_hand (val, 1, &blocklen);
+  val = call_function_by_hand (lookup_cached_function (fval), 1, &blocklen);
   if (value_logical_not (val))
     {
       if (!target_has_execution)
@@ -1258,6 +1299,11 @@
 
       value_type = builtin_type_int;
     }
+  else if (code == TYPE_CODE_ERROR)
+    {
+      value_type = builtin_type_error;
+      funaddr = (CORE_ADDR) -1;
+    }
   else
     error ("Invalid data type for function to be called.");
 
@@ -1283,10 +1329,9 @@
 
    ARGS is modified to contain coerced values. */
 
-static value_ptr hand_function_call (value_ptr function, int nargs,
-				     value_ptr * args);
 static value_ptr
-hand_function_call (value_ptr function, int nargs, value_ptr *args)
+hand_function_call (value_ptr function,
+		    struct type *expect_type, int nargs, value_ptr *args)
 {
   register CORE_ADDR sp;
   register int i;
@@ -1333,6 +1378,32 @@
   inf_status = save_inferior_status (1);
   old_chain = make_cleanup_restore_inferior_status (inf_status);
 
+  funaddr = find_function_addr (function, &value_type);
+  CHECK_TYPEDEF (value_type);
+  
+  if ((value_type == NULL) || (value_type->code == TYPE_CODE_ERROR))
+    value_type = expect_type;
+  
+  if ((value_type == NULL) || (value_type->code == TYPE_CODE_ERROR))
+    error ("Unable to call function at 0x%lx: no return type information available.\n"
+           "To call this function anyway, you can cast the return type explicitly\n"
+	   "(e.g. 'print (float) fabs (3.0)')",
+           (unsigned long) funaddr);
+
+  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);
+
   /* 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.  */
@@ -1353,21 +1424,6 @@
       sp += sizeof_dummy1;
     }
 
-  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++)
@@ -1785,16 +1841,24 @@
 }
 
 value_ptr
-call_function_by_hand (value_ptr function, int nargs, value_ptr *args)
+call_function_by_hand_expecting_type (value_ptr function, 
+				      struct type *expect_type,
+				      int nargs, value_ptr *args)
 {
   if (CALL_DUMMY_P)
     {
-      return hand_function_call (function, nargs, args);
+      return hand_function_call (function, expect_type, nargs, args);
     }
   else
     {
       error ("Cannot invoke functions on this machine.");
     }
+}
+
+value_ptr
+call_function_by_hand (value_ptr function, int nargs, value_ptr *args)
+{
+  call_function_by_hand_expecting_type (function, NULL, nargs, args);
 }
 \f
 
Index: gdb/value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.22
diff -u -r1.22 value.h
--- value.h	2001/10/16 01:58:07	1.22
+++ value.h	2001/12/14 19:42:31
@@ -551,6 +551,10 @@
 
 extern value_ptr call_function_by_hand (value_ptr, int, value_ptr *);
 
+extern value_ptr call_function_by_hand_expecting_type (value_ptr,
+						       struct type *, int,
+						       value_ptr *);
+
 extern int default_coerce_float_to_double (struct type *, struct type *);
 
 extern int standard_coerce_float_to_double (struct type *, struct type *);
@@ -559,8 +563,21 @@
 
 extern void find_rt_vbase_offset (struct type *, struct type *, char *, int,
 				  int *, int *);
+
+struct cached_value
+{
+  char *name;
+  struct type *type;
+  struct value val;
+  unsigned int generation;
+};
+typedef struct cached_value *cached_value_ptr;
+
+extern cached_value_ptr create_cached_function (char *, struct type *);
+
+extern value_ptr lookup_cached_function (cached_value_ptr cval);
 
-extern value_ptr find_function_in_inferior (char *);
+extern value_ptr find_function_in_inferior (char *, struct type *);
 
 extern value_ptr value_allocate_space_in_inferior (int);
 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-14 12:45               ` Klee Dienes
@ 2001-12-14 12:50                 ` Daniel Jacobowitz
  2001-12-18  1:42                   ` Klee Dienes
  0 siblings, 1 reply; 19+ messages in thread
From: Daniel Jacobowitz @ 2001-12-14 12:50 UTC (permalink / raw)
  To: Klee Dienes; +Cc: gdb-patches

On Fri, Dec 14, 2001 at 03:44:03PM -0500, Klee Dienes wrote:
> We've been using a variant of this patch at Apple for a little over a
> year; it seems to be working.  The test suite shows four additional
> unexpected successes when I run it with this patch, but I figure
> that's probably OK.

That's odd; the testsuite is mostly (entirely?) compiled with debug
information.  Which are they?

-- 
Daniel Jacobowitz                           Carnegie Mellon University
MontaVista Software                         Debian GNU/Linux Developer


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
  2001-12-14 12:50                 ` Daniel Jacobowitz
@ 2001-12-18  1:42                   ` Klee Dienes
  0 siblings, 0 replies; 19+ messages in thread
From: Klee Dienes @ 2001-12-18  1:42 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: Klee Dienes, gdb-patches


On Fri, Dec 14, 2001 at 03:44:03PM -0500, Klee Dienes wrote:
>> We've been using a variant of this patch at Apple for a little over a
>> year; it seems to be working.  The test suite shows four additional
>> unexpected successes when I run it with this patch, but I figure
>> that's probably OK.
>
> That's odd; the testsuite is mostly (entirely?) compiled with debug
> information.  Which are they?

Ah, you caught me.  The 4 XPASSES were the result of mild version skew
between the times I did the 'cvs update' on the two source trees; they
were unrelated to the code changes.

In fact, when I ran the test suite correctly I discovered a number of
failed tests due to output changes (since now GDB is less aggressive
about guessing the type about symbols without debugging information).

After applying the following patch, I now get identical output from
the test suite before- and after-patch.


Index: gdb/testsuite/gdb.asm/asm-source.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.asm/asm-source.exp,v
retrieving revision 1.14
diff -u -r1.14 asm-source.exp
--- asm-source.exp	2001/12/13 13:42:19	1.14
+++ asm-source.exp	2001/12/18 09:19:04
@@ -206,10 +206,12 @@
 	"Make selected stack frame return now\?.*" "y"
 
 # See if we can look at a global variable
-gdb_test "print globalvar" ".* = 11" "look at global variable"
+gdb_test "print globalvar" ".* = (11|<unknown type>)" "look at global variable"
+gdb_test "print (int) globalvar" ".* = 11" "look at global variable"
 
 # See if we can look at a static variable
-gdb_test "print staticvar" ".* = 5" "look at static variable"
+gdb_test "print staticvar" ".* = (5|<unknown type>)" "look at static variable"
+gdb_test "print (int) staticvar" ".* = 5" "look at static variable"
 
 # See if we can look at a static function
 gdb_test "disassem foostatic" ".*<foostatic>:.*End of assembler dump." \
Index: gdb/testsuite/gdb.base/nodebug.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/nodebug.exp,v
retrieving revision 1.2
diff -u -r1.2 nodebug.exp
--- nodebug.exp	2001/03/06 08:21:50	1.2
+++ nodebug.exp	2001/12/18 09:19:04
@@ -77,23 +77,24 @@
     gdb_test "whatis top" \
 	"(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))"
     if {!$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "ptype top" "(short|int) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
+    gdb_test "ptype top" "(short|int|<unknown type>) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
     
     if {!$gcc_compiled} then { setup_xfail "mips-sgi-irix5*" }
     setup_xfail "mips-sgi-irix6*"
     gdb_test "p middle" \
-	"\{(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))\} \[0-9a-fx]* <middle(\\(int\\)|)>"
+	"\{(<(text variable|function), no debug info>|<unknown type>|short \\(int\\)|short \\(\\))\} \[0-9a-fx]* <middle(\\(int\\)|)>"
     if {!$gcc_compiled} then { setup_xfail "mips-sgi-irix5*" }
     setup_xfail "mips-sgi-irix6*"
     gdb_test "whatis middle" \
-	"(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))"
+	"(<(text variable|function), no debug info>|<unknown type>|short \\(int\\)|short \\(\\))"
     setup_xfail "mips-sgi-irix6*"
-    gdb_test "ptype middle" "(short|int) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
+    gdb_test "ptype middle" "(short|int|<unknown type>) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
     
-    gdb_test "p dataglobal" "= 3"
+    gdb_test "p dataglobal" "(= 3|<unknown type>)"
+    gdb_test "p (int) dataglobal" "= 3"
     gdb_test "whatis dataglobal" \
-	"<(data variable|variable), no debug info>|int"
-    gdb_test "ptype dataglobal" "<(data variable|variable), no debug info>|int"
+	"<(data variable|variable), no debug info>|<unknown type>|int"
+    gdb_test "ptype dataglobal" "<(data variable|variable), no debug info>|<unknown type>|int"
     
     # The only symbol xcoff puts out for statics is for the TOC entry.
     # Possible, but hairy, for gdb to deal.  Right now it doesn't, it
@@ -102,37 +103,40 @@
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "p datalocal" "= 4"
+    gdb_test "p datalocal" "(= 4|<unknown type>)"
+    gdb_test "p (int) datalocal" "4"
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "whatis datalocal" "<(data variable|variable), no debug info>"
+    gdb_test "whatis datalocal" "<(data variable|variable), no debug info>|<unknown type>"
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "ptype datalocal" "<(data variable|variable), no debug info>"
+    gdb_test "ptype datalocal" "<(data variable|variable), no debug info>|<unknown type>"
     
-    gdb_test "p bssglobal" "= 0"
-    gdb_test "whatis bssglobal" "<(data variable|variable), no debug info>|int"
-    gdb_test "ptype bssglobal" "<(data variable|variable), no debug info>|int"
+    gdb_test "p bssglobal" "(= 0|<unknown type>)"
+    gdb_test "p (int) bssglobal" "= 0"
+    gdb_test "whatis bssglobal" "<(data variable|variable), no debug info>|<unknown type>|int"
+    gdb_test "ptype bssglobal" "<(data variable|variable), no debug info>|<unknown type>|int"
     
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "p bsslocal" "= 0"
+    gdb_test "p bsslocal" "(= 0|<unknown type>)"
+    gdb_test "p (int) bsslocal" "= 0"
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "whatis bsslocal" "<(data variable|variable), no debug info>"
+    gdb_test "whatis bsslocal" "<(data variable|variable), no debug info>|<unknown type>"
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "ptype bsslocal" "<(data variable|variable), no debug info>"
+    gdb_test "ptype bsslocal" "<(data variable|variable), no debug info>|<unknown type>"
     
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
     gdb_test "backtrace 10" "#0.*inner.*#1.*middle.*#2.*top.*#3.*main.*" \
@@ -167,7 +171,9 @@
 	    # We need to up this because this can be really slow on some boards.
 	    # (malloc() is called as part of the test).
 	    set timeout 60;    
-	    gdb_test {p/c array_index("abcdef",2)} " = 99 'c'"
+	    gdb_test {p/c (int) array_index("abcdef",2)} " = 99 'c'"
+	    gdb_test {p/c array_index("abcdef",2)} \
+	        "Unable to call function .* no return type information available.*"
 	}
     }
     



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [RFC] add 'save-breakpoints' command
       [not found] <1007594419.30359.ezmlm@sources.redhat.com>
@ 2001-12-05 17:39 ` Jim Ingham
  0 siblings, 0 replies; 19+ messages in thread
From: Jim Ingham @ 2001-12-05 17:39 UTC (permalink / raw)
  To: GDB Patches

Project Builder (Apple's IDE which runs on top of gdb) only sets future
breakpoints, and Insight could easily do that.

The big difference between break and future break is that if you mistype a
name in future-break, you won't get an error.  You do get some console
output telling you that it didn't work, but this is not the same in scripts,
for instance.  This is a semantic change in how break works, and for that
reason I hesitate to just convert break to future break...

What do other folks think?

Jim

> 
>>>>>> "Klee" == Klee Dienes <klee@apple.com> writes:
> 
> Klee> The 'future-break' command allows one to specify a breakpoint
> Klee> that starts off as 'shlib_disabled' instead of generating an
> Klee> error if it can't be set immediately.
> 
> Klee> I'm not entirely happy with the future-break command, and
> Klee> particularly with its interaction with the save-breakpoints
> Klee> mechanism (if you set a breakpoint that is in a shared library
> Klee> after shared libraries have been loaded, you have to remember to
> Klee> use the future-break command, not the break command).
> 
> Doesn't this mean that programs like Insight would be best advised to
> *only* set future breakpoints?  In that case let's just add the
> functionality directly to the existing breakpoint commands.
> 
> Tom

-- 
+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==
Jim Ingham                              jingham@apple.com
Developer Tools - gdb


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2001-12-18  9:42 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-12-04 10:21 [RFC] add 'save-breakpoints' command Klee Dienes
2001-12-04 10:26 ` Daniel Jacobowitz
2001-12-04 10:44   ` Klee Dienes
2001-12-05 14:06     ` Tom Tromey
2001-12-04 11:22 ` Eli Zaretskii
2001-12-04 13:35   ` Klee Dienes
2001-12-05  0:25     ` Eli Zaretskii
2001-12-04 14:48 ` Michael Snyder
2001-12-04 21:11   ` Klee Dienes
2001-12-11  0:28   ` Klee Dienes
2001-12-11  3:55     ` Eli Zaretskii
2001-12-11  8:35       ` Klee Dienes
2001-12-11  9:09         ` Eli Zaretskii
2001-12-11 13:23           ` Klee Dienes
2001-12-12  0:32             ` Eli Zaretskii
2001-12-14 12:45               ` Klee Dienes
2001-12-14 12:50                 ` Daniel Jacobowitz
2001-12-18  1:42                   ` Klee Dienes
     [not found] <1007594419.30359.ezmlm@sources.redhat.com>
2001-12-05 17:39 ` Jim Ingham

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox