This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch/rfc] complaint() -> complaints() rewrite #2


Hello,

This follows up an earler e-mail where I wrote:

Should this be called symtab_complaint(), or perhaphs, should complaint() take an extra parameter (the complaint class) so that other code can use this mechanism?

I've implemented this. In the process I've tried to make the code a little bit more i18n friendly (it was assuming that things read left to right).

Anyway, this is my original description:

The files complaints.[hc] implement a mechanism for supressing warning messages that occure more than a small number of times. GDB's debug readers use this mechanism to supress all but the first few warnings generated when reading an object file.

The current implementation stores the warning message string in a structure vis:

struct complaint argument_complaint = { "Argument '%d'", };

DOUBLEST argument;
complain (&argument_complaint, "argument");
complain (&argument_complaint, argument);
complain (&argument_complaint, &argument);

The problem I see with this is that there is nothing (other than the human eye) checking for consistency between the format string and the call.

I'd like to propose a new complaints interface:

void complaint (const char *fmt, ...);

(with a format printf attribute) so that the compiler (GCC with -Wformat) can check, at build time, the consistency of the format string and its parameter list. To issue the same complaint from multiple points in the code, a wrapper function can be used:

argument_complaint (int argument)
{
complaint ("Argument '%d'", argument);
}

The process of updating the above should flush out a few bugs :-)

This change would help eliminate problems such as:
http://sources.redhat.com/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=211

--

I don't use the most efficient of algorithms when detecting duplicate complaints. But then, I don't know how often complaints are occuring and my objective is to fix the format miss-match.

The complaint() interface should probably be documented along with error() and warning().

--

thoughts?
Andrew



2002-08-14  Andrew Cagney  <ac131313@redhat.com>

	* Makefile.in (complaints.o): Update dependencies.

	* symfile.c (syms_from_objfile): Add symfile_complaints parameter
	to call to clear_complaints.
	(new_symfile_objfile, reread_symbols): Ditto.
	(oldsyms_complaint): Delete.
	(empty_symtab_complaint, unknown_option_complaint): Delete.
	(free_named_symtabs): Use complaint instead of complain.

	* complaints.h: Update copyright.
	(struct complaints): Declare.
	(struct complaint): Make `message' constant.
	(complaint): Declare.
	(complaint_root): Delete declaration.
	(symfile_complaints): Delete declaration.
	(struct complaints): Add opaque declaration.
	(clear_complaints): Add a complaints parameter.

	* complaints.c: Update copyright.
	(enum complaint_series): Define.
	(complaint_root): Delete.
	(struct complaints): Define.
	(complaint_sentinel, symfile_complaint_book): New variables.
	(symfile_explanations, symfile_complaints): New variables.
	New variables.
	(get_complaints): New function.
	(vcomplain): New function.
	(complain): Call vcomplain with symfile_complaint.
	(complaint): New function.
	(clear_complaints): Rewrite.
	(__initialize_complaints): Use add_setshow_command.

Index: testsuite/ChangeLog
2002-08-14  Andrew Cagney  <ac131313@redhat.com>

	* gdb.gdb/complaints.exp: New file.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.236
diff -u -r1.236 Makefile.in
--- Makefile.in	14 Aug 2002 18:13:30 -0000	1.236
+++ Makefile.in	15 Aug 2002 01:32:08 -0000
@@ -1382,7 +1382,8 @@
 	$(buildsym_h) $(gdb_stabs_h) $(stabsread_h) $(complaints_h) \
 	$(target_h) $(gdb_assert_h)
 
-complaints.o: complaints.c $(complaints_h) $(defs_h) $(gdbcmd_h)
+complaints.o: complaints.c $(defs_h) $(complaints_h) $(gdb_assert_h) \
+	$(command_h) $(gdbcmd_h)
 
 # Provide explicit rule/dependency - works for more makes.
 copying.o: $(srcdir)/copying.c $(defs_h) $(gdbcmd_h)
Index: complaints.c
===================================================================
RCS file: /cvs/src/src/gdb/complaints.c,v
retrieving revision 1.6
diff -u -r1.6 complaints.c
--- complaints.c	6 Nov 2001 23:38:14 -0000	1.6
+++ complaints.c	15 Aug 2002 01:32:08 -0000
@@ -1,6 +1,7 @@
 /* Support for complaint handling during symbol reading in GDB.
-   Copyright 1990, 1991, 1992, 1993, 1995, 1998, 1999, 2000
-   Free Software Foundation, Inc.
+
+   Copyright 1990, 1991, 1992, 1993, 1995, 1998, 1999, 2000, 2002 Free
+   Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -21,54 +22,109 @@
 
 #include "defs.h"
 #include "complaints.h"
+#include "gdb_assert.h"
+#include "command.h"
 #include "gdbcmd.h"
 
 extern void _initialize_complaints (void);
 
+/* Should each complaint message be self explanatory, or should we assume that
+   a series of complaints is being produced?  */
+
+/* case 1: First message of a series that must
+   start off with explanation.  case 2: Subsequent message of a series
+   that needs no explanation (the user already knows we have a problem
+   so we can just state our piece).  */
+enum complaint_series {
+  /* Isolated self explanatory message.  */
+  ISOLATED_MESSAGE,
+  /* First message of a series, includes an explanation.  */
+  FIRST_MESSAGE,
+  /* First message of a series, but does not need to include any sort
+     of explanation.  */
+  SHORT_FIRST_MESSAGE,
+  /* Subsequent message of a series that needs no explanation (the
+     user already knows we have a problem so we can just state our
+     piece).  */
+  SUBSEQUENT_MESSAGE
+};
+
 /* Structure to manage complaints about symbol file contents.  */
 
-struct complaint complaint_root[1] =
+struct complaints
 {
-  {
-    (char *) NULL,		/* Complaint message */
-    0,				/* Complaint counter */
-    complaint_root		/* Next complaint. */
-  }
+  struct complaint *root;
+
+  /* Should each complaint be self explanatory, or should we assume
+     that a series of complaints is being produced?  case 0: Isolated
+     self explanatory message.  case 1: First message of a series that
+     must start off with explanation.  case 2: Subsequent message of a
+     series that needs no explanation (the user already knows we have
+     a problem so we can just state our piece).  */
+  int series;
+
+  /* The explanatory messages that should accompany the complaint.
+     NOTE: cagney/2002-08-14: In a desperate attempt at being vaguely
+     i18n friendly, this is an array of two messages.  When present,
+     EXPLANATION[SERIES] is used to wrap the message.  */
+  const char **explanation;
 };
 
-/* How many complaints about a particular thing should be printed before
-   we stop whining about it?  Default is no whining at all, since so many
-   systems have ill-constructed symbol files.  */
+static struct complaint complaint_sentinel;
 
-static unsigned int stop_whining = 0;
+/* The symbol table complaint table.  */
 
-/* Should each complaint be self explanatory, or should we assume that
-   a series of complaints is being produced? 
-   case 0:  self explanatory message.
-   case 1:  First message of a series that must start off with explanation.
-   case 2:  Subsequent message, when user already knows we are reading
-   symbols and we can just state our piece.  */
+static const char *symfile_explanations[] = {
+  "During symbol reading, %s.\n",
+  "During symbol reading...%s...",
+  "%s...",
+  "%s...",
+  NULL
+};
 
-static int complaint_series = 0;
+static struct complaints symfile_complaint_book = {
+  &complaint_sentinel,
+  0,
+  symfile_explanations
+};
+struct complaints *symfile_complaints = &symfile_complaint_book;
 
-
+/* Wrapper function to, on-demand, fill in a complaints object.  */
 
-/* Functions to handle complaints during symbol reading.  */
+static struct complaints *
+get_complaints (struct complaints **c)
+{
+  if ((*c) != NULL)
+    return (*c);
+  (*c) = XMALLOC (struct complaints);
+  (*c)->root = &complaint_sentinel;
+  (*c)->series = ISOLATED_MESSAGE;
+  (*c)->explanation = NULL;
+  return (*c);
+}
 
-/* Print a complaint about the input symbols, and link the complaint block
-   into a chain for later handling.  */
+/* How many complaints about a particular thing should be printed
+   before we stop whining about it?  Default is no whining at all,
+   since so many systems have ill-constructed symbol files.  */
 
-void
-complain (struct complaint *complaint,...)
-{
-  va_list args;
-  va_start (args, complaint);
+static unsigned int stop_whining = 0;
 
+/* Print a complaint, and link the complaint block into a chain for
+   later handling.  */
+
+static void
+vcomplain (struct complaints *complaints, struct complaint *complaint,
+	   va_list args)
+{
+  char *msg;
+  enum complaint_series series;
+  struct cleanup *cleanups;
+  gdb_assert (complaints != NULL);
   complaint->counter++;
   if (complaint->next == NULL)
     {
-      complaint->next = complaint_root->next;
-      complaint_root->next = complaint;
+      complaint->next = complaints->root;
+      complaints->root = complaint;
     }
   if (complaint->counter > stop_whining)
     {
@@ -76,93 +132,126 @@
     }
   wrap_here ("");
 
-  switch (complaint_series + (info_verbose << 1))
-    {
+  xvasprintf (&msg, complaint->message, args);
+  cleanups = make_cleanup (xfree, msg);
 
-      /* Isolated messages, must be self-explanatory.  */
-    case 0:
-      if (warning_hook)
-        (*warning_hook) (complaint->message, args);
+  if (info_verbose)
+    series = SUBSEQUENT_MESSAGE;
+  else
+    series = complaints->series;
+
+  if (warning_hook)
+    (*warning_hook) (complaint->message, args);
+  else
+    {
+      if (series != SUBSEQUENT_MESSAGE)
+	begin_line ();
+      if (complaints->explanation == NULL)
+	fprintf_filtered (gdb_stderr, "%s.\n", msg);
       else
-        {
-          begin_line ();
-          fputs_filtered ("During symbol reading, ", gdb_stderr);
-          wrap_here ("");
-          vfprintf_filtered (gdb_stderr, complaint->message, args);
-          fputs_filtered (".\n", gdb_stderr);
-        }
-      break;
+	fprintf_filtered (gdb_stderr,
+			  complaints->explanation[series],
+			  msg);
+    }
 
-      /* First of a series, without `set verbose'.  */
-    case 1:
-      if (warning_hook)
-        (*warning_hook) (complaint->message, args);
-      else
-        {
-          begin_line ();
-          fputs_filtered ("During symbol reading...", gdb_stderr);
-          vfprintf_filtered (gdb_stderr, complaint->message, args);
-          fputs_filtered ("...", gdb_stderr);
-          wrap_here ("");
-          complaint_series++;
-        }
+  switch (series)
+    {
+    case ISOLATED_MESSAGE:
       break;
+    case FIRST_MESSAGE:
+      complaints->series = SUBSEQUENT_MESSAGE;
+      break;
+    case SUBSEQUENT_MESSAGE:
+    case SHORT_FIRST_MESSAGE:
+      complaints->series = SUBSEQUENT_MESSAGE;
+      break;
+    }
 
-      /* Subsequent messages of a series, or messages under `set verbose'.
-         (We'll already have produced a "Reading in symbols for XXX..."
-         message and will clean up at the end with a newline.)  */
-    default:
-      if (warning_hook)
-        (*warning_hook) (complaint->message, args);
-      else
-        {
-          vfprintf_filtered (gdb_stderr, complaint->message, args);
-          fputs_filtered ("...", gdb_stderr);
-          wrap_here ("");
-        }
-    }
-  /* If GDB dumps core, we'd like to see the complaints first.  Presumably
-     GDB will not be sending so many complaints that this becomes a
-     performance hog.  */
+  wrap_here ("");
+
+  /* If GDB dumps core, we'd like to see the complaints first.
+     Presumably GDB will not be sending so many complaints that this
+     becomes a performance hog.  */
   gdb_flush (gdb_stderr);
+
+  do_cleanups (cleanups);
+}
+
+void
+complain (struct complaint *complaint, ...)
+{
+  va_list args;
+  va_start (args, complaint);
+  vcomplain (get_complaints (&symfile_complaints), complaint, args);
+  va_end (args);
+}
+
+void
+complaint (struct complaints **c, const char *fmt, ...)
+{
+  struct complaints *complaints = get_complaints (c);
+  struct complaint *complaint = complaints->root;
+  va_list args;
+  for (complaint = complaints->root;
+       complaint != NULL;
+       complaint = complaint->next)
+    {
+      if (complaint->message == fmt)
+	break;
+    }
+  if (complaint == NULL)
+    {
+      complaint = XMALLOC (struct complaint);
+      complaint->message = fmt;
+      complaint->counter = 0;
+      complaint->next = NULL;
+    }
+  va_start (args, fmt);
+  vcomplain (complaints, complaint, args);
   va_end (args);
 }
 
-/* Clear out all complaint counters that have ever been incremented.
-   If sym_reading is 1, be less verbose about successive complaints,
-   since the messages are appearing all together during a command that
-   reads symbols (rather than scattered around as psymtabs get fleshed
-   out into symtabs at random times).  If noisy is 1, we are in a
-   noisy symbol reading command, and our caller will print enough
-   context for the user to figure it out.  */
+/* Clear out / initialize all complaint counters that have ever been
+   incremented.  If LESS_VERBOSE is 1, be less verbose about
+   successive complaints, since the messages are appearing all
+   together during a command that is reporting a contiguous block of
+   complaints (rather than being interleaved with other messages).  If
+   noisy is 1, we are in a noisy command, and our caller will print
+   enough context for the user to figure it out.  */
 
 void
-clear_complaints (int sym_reading, int noisy)
+clear_complaints (struct complaints **c, int less_verbose, int noisy)
 {
+  struct complaints *complaints = get_complaints (c);
   struct complaint *p;
 
-  for (p = complaint_root->next; p != complaint_root; p = p->next)
+  for (p = complaints->root; p != NULL; p = p->next)
     {
       p->counter = 0;
     }
 
-  if (!sym_reading && !noisy && complaint_series > 1 && !warning_hook)
+  if (complaints->series > 1 && !warning_hook)
     {
       /* Terminate previous series, since caller won't.  */
       puts_filtered ("\n");
     }
 
-  complaint_series = sym_reading ? 1 + noisy : 0;
+  if (!less_verbose)
+    complaints->series = ISOLATED_MESSAGE;
+  else if (!noisy)
+    complaints->series = FIRST_MESSAGE;
+  else
+    complaints->series = SHORT_FIRST_MESSAGE;
 }
 
 void
 _initialize_complaints (void)
 {
-  add_show_from_set
-    (add_set_cmd ("complaints", class_support, var_zinteger,
-		  (char *) &stop_whining,
-		  "Set max number of complaints about incorrect symbols.",
-		  &setlist),
-     &showlist);
+  add_setshow_cmd ("complaints", class_support, var_zinteger,
+		   &stop_whining,
+		   "Set max number of complaints about incorrect symbols.",
+		   "Show max number of complaints about incorrect symbols.",
+		   NULL, NULL,
+		   &setlist, &showlist);
 
 }
Index: complaints.h
===================================================================
RCS file: /cvs/src/src/gdb/complaints.h,v
retrieving revision 1.3
diff -u -r1.3 complaints.h
--- complaints.h	6 Mar 2001 08:21:06 -0000	1.3
+++ complaints.h	15 Aug 2002 01:32:08 -0000
@@ -1,6 +1,7 @@
 /* Definitions for complaint handling during symbol reading in GDB.
-   Copyright 1990, 1991, 1992, 1995, 1998, 2000
-   Free Software Foundation, Inc.
+
+   Copyright 1990, 1991, 1992, 1995, 1998, 2000, 2002 Free Software
+   Foundation, Inc.
 
    This file is part of GDB.
 
@@ -23,6 +24,31 @@
 #if !defined (COMPLAINTS_H)
 #define COMPLAINTS_H
 
+/* Opaque object used to track the number of complaints of a
+   particular category.  */
+struct complaints;
+
+/* Predefined categories.  */
+extern struct complaints *symfile_complaints;
+
+/* Register a complaint.  */
+extern void complaint (struct complaints **complaints,
+		       const char *fmt, ...) ATTR_FORMAT (printf, 2, 3);
+
+/* Clear out / initialize all complaint counters that have ever been
+   incremented.  If LESS_VERBOSE is 1, be less verbose about
+   successive complaints, since the messages are appearing all
+   together during a command that is reporting a contiguous block of
+   complaints (rather than being interleaved with other messages).  If
+   noisy is 1, we are in a noisy command, and our caller will print
+   enough context for the user to figure it out.  */
+
+extern void clear_complaints (struct complaints **complaints,
+			      int less_verbose, int noisy);
+
+
+/* Legacy interfaces to keep the old code working (until it is all
+   converted to the above).  */
 
 /* Support for complaining about things in the symbol file that aren't
    catastrophic.
@@ -32,22 +58,12 @@
    if verbose, we report how many of each problem we had.  */
 
 struct complaint
-  {
-    char *message;
-    unsigned counter;
-    struct complaint *next;
-  };
-
-/* Root of the chain of complaints that have at some point been issued. 
-   This is used to reset the counters, and/or report the total counts.  */
-
-extern struct complaint complaint_root[1];
-
-/* Functions that handle complaints.  (in complaints.c)  */
+{
+  const char *message;
+  unsigned counter;
+  struct complaint *next;
+};
 
 extern void complain (struct complaint *, ...);
-
-extern void clear_complaints (int, int);
-
 
 #endif /* !defined (COMPLAINTS_H) */
Index: symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.65
diff -u -r1.65 symfile.c
--- symfile.c	1 Aug 2002 17:18:32 -0000	1.65
+++ symfile.c	15 Aug 2002 01:32:09 -0000
@@ -81,21 +81,6 @@
 /* Global variables owned by this file */
 int readnow_symbol_files;	/* Read full symbols immediately */
 
-struct complaint oldsyms_complaint =
-{
-  "Replacing old symbols for `%s'", 0, 0
-};
-
-struct complaint empty_symtab_complaint =
-{
-  "Empty symbol table found for `%s'", 0, 0
-};
-
-struct complaint unknown_option_complaint =
-{
-  "Unknown option `%s' ignored", 0, 0
-};
-
 /* External variables and functions referenced. */
 
 extern void report_transfer_performance (unsigned long, time_t, time_t);
@@ -706,7 +691,7 @@
      initial symbol reading for this file. */
 
   (*objfile->sf->sym_init) (objfile);
-  clear_complaints (1, verbo);
+  clear_complaints (&symfile_complaints, 1, verbo);
 
   (*objfile->sf->sym_offsets) (objfile, addrs);
 
@@ -818,7 +803,7 @@
     }
 
   /* We're done reading the symbol file; finish off complaints.  */
-  clear_complaints (0, verbo);
+  clear_complaints (&symfile_complaints, 0, verbo);
 }
 
 /* Process a symbol file, as either the main file or as a dynamically
@@ -1801,7 +1786,7 @@
 		}
 
 	      (*objfile->sf->sym_init) (objfile);
-	      clear_complaints (1, 1);
+	      clear_complaints (&symfile_complaints, 1, 1);
 	      /* The "mainline" parameter is a hideous hack; I think leaving it
 	         zero is OK since dbxread.c also does what it needs to do if
 	         objfile->global_psymbols.size is 0.  */
@@ -1815,7 +1800,7 @@
 	      objfile->flags |= OBJF_SYMS;
 
 	      /* We're done reading the symbol file; finish off complaints.  */
-	      clear_complaints (0, 1);
+	      clear_complaints (&symfile_complaints, 0, 1);
 
 	      /* Getting new symbols may change our opinion about what is
 	         frameless.  */
@@ -2305,15 +2290,14 @@
 	  || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK))
 	  || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)))
 	{
-	  complain (&oldsyms_complaint, name);
-
+	  complaint ("Replacing old symbols for `%s'", name);
 	  clear_symtab_users_queued++;
 	  make_cleanup (clear_symtab_users_once, 0);
 	  blewit = 1;
 	}
       else
 	{
-	  complain (&empty_symtab_complaint, name);
+	  complaint ("Empty symbol table found for `%s'", name);
 	}
 
       free_symtab (s);
Index: testsuite/gdb.gdb/complaints.exp
===================================================================
RCS file: testsuite/gdb.gdb/complaints.exp
diff -N testsuite/gdb.gdb/complaints.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.gdb/complaints.exp	15 Aug 2002 01:32:10 -0000
@@ -0,0 +1,282 @@
+#   Copyright 2002
+#   Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+# This file was written by Andrew Cagney (cagney at redhat dot com),
+# derived from xfullpath.exp (written by Joel Brobecker), derived from
+# selftest.exp (written by Rob Savoye).
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+# are we on a target board
+if [is_remote target] {
+    return
+}
+
+proc setup_test { executable } {
+    global gdb_prompt
+    global timeout
+
+    # load yourself into the debugger
+    # This can take a relatively long time, particularly for testing where
+    # the executable is being accessed over a network, or where gdb does not
+    # support partial symbols for a particular target and has to load the
+    # entire symbol table.  Set the timeout to 10 minutes, which should be
+    # adequate for most environments (it *has* timed out with 5 min on a
+    # SPARCstation SLC under moderate load, so this isn't unreasonable).
+    # After gdb is started, set the timeout to 30 seconds for the duration
+    # of this test, and then back to the original value.
+
+    set oldtimeout $timeout
+    set timeout 600
+    verbose "Timeout is now $timeout seconds" 2
+    if {[gdb_load $executable] <0} then {
+	set timeout $oldtimeout
+	verbose "Timeout is now $timeout seconds" 2
+	return -1
+    }
+    set timeout $oldtimeout
+    verbose "Timeout is now $timeout seconds" 2
+
+    # Set a breakpoint at main
+    gdb_test "break captured_command_loop" \
+            "Breakpoint.*at.* file.*, line.*" \
+            "breakpoint in captured_command_loop"
+
+    # run yourself
+    # It may take a very long time for the inferior gdb to start (lynx),
+    # so we bump it back up for the duration of this command.
+    set timeout 600
+
+    set description "run until breakpoint at captured_command_loop"
+    send_gdb "run -nw\n"
+    gdb_expect {
+        -re "Starting program.*Breakpoint \[0-9\]+,.*captured_command_loop .data.* at .*main.c:.*$gdb_prompt $" {
+            pass "$description"
+        }
+        -re "Starting program.*Breakpoint \[0-9\]+,.*captured_command_loop .data.*$gdb_prompt $" {
+            xfail "$description (line numbers scrambled?)"
+        }
+        -re "vfork: No more processes.*$gdb_prompt $" {
+            fail "$description (out of virtual memory)"
+            set timeout $oldtimeout
+            verbose "Timeout is now $timeout seconds" 2
+            return -1
+        }
+        -re ".*$gdb_prompt $" {
+            fail "$description"
+            set timeout $oldtimeout
+            verbose "Timeout is now $timeout seconds" 2
+            return -1
+        }
+        timeout {
+            fail "$description (timeout)"
+        }
+    }
+
+    set timeout $oldtimeout
+    verbose "Timeout is now $timeout seconds" 2
+
+    return 0
+}
+
+proc test_isolated_complaints { } {
+
+    global gdb_prompt
+
+    # Unsupress complaints
+    gdb_test "set stop_whining = 2"
+
+    # Prime the system
+    gdb_test "call complaint (&symfile_complaints, \"Register a complaint\")" \
+	    "During symbol reading, Register a complaint."
+
+    # Check that the complaint was inserted and where
+    gdb_test "print symfile_complaints->root->message" \
+	    ".\[0-9\]+ =.*\"Register a complaint\""
+
+    # Re-issue the first message #1
+    gdb_test "call complaint (&symfile_complaints, symfile_complaints->root->message)" \
+	    "During symbol reading, Register a complaint."
+
+    # Check that there is only one thing in the list
+    gdb_test "print symfile_complaints->root->next == &complaint_sentinel" \
+	    ".\[0-9\]+ = 1" "list has one entry"
+
+    # Add a second complaint, expect it
+    gdb_test "call complaint (&symfile_complaints, \"Testing! Testing! Testing!\")" \
+	    "During symbol reading, Testing. Testing. Testing.."
+
+    return 0
+}
+
+proc test_serial_complaints { } {
+
+    global gdb_prompt
+
+    gdb_test_exact "call clear_complaints (&symfile_complaints, 1, 0)" "" "serial start"
+
+    # Prime the system
+    send_gdb "call complaint (&symfile_complaints, \"serial line  1\")\n"
+    gdb_expect {
+	-re "During symbol reading...serial line  1...$gdb_prompt " {
+	    pass "serial line 1"
+	}
+	"$gdb_prompt" {
+	    fail "serial line  1"
+	}
+	timeout {
+	    fail "serial line  1 (timeout)"
+	}
+    }
+
+    # Add a second complaint, expect it
+    send_gdb "call complaint (&symfile_complaints, \"serial line 2\")\n"
+    gdb_expect {
+	-re "serial line 2...$gdb_prompt " {
+	    pass "serial line 2"
+	}
+	"$gdb_prompt" {
+	    fail "serial line 2"
+	}
+	timeout {
+	    fail "serial line 2 (timeout)"
+	}
+    }
+
+    send_gdb "call clear_complaints (&symfile_complaints, 1, 0)\n"
+    gdb_expect {
+	-re "\r\n\r\n$gdb_prompt " {
+	    pass "serial end"
+	}
+	"$gdb_prompt" {
+	    fail "serial end"
+	}
+	timeout {
+	    fail "serial end (timeout)"
+	}
+    }
+
+    return 0
+}
+
+# For short complaints, all are the same
+
+proc test_short_complaints { } {
+
+    global gdb_prompt
+
+    gdb_test_exact "call clear_complaints (&symfile_complaints, 1, 1)" "" "short start"
+
+    # Prime the system
+    send_gdb "call complaint (&symfile_complaints, \"short line 1\")\n"
+    gdb_expect {
+	-re "short line 1...$gdb_prompt " {
+	    pass "short line 1"
+	}
+	"$gdb_prompt" {
+	    fail "short line 1"
+	}
+	timeout {
+	    fail "short line 1 (timeout)"
+	}
+    }
+
+    # Add a second complaint, expect it
+    send_gdb "call complaint (&symfile_complaints, \"short line 2\")\n"
+    gdb_expect {
+	-re "short line 2...$gdb_prompt " {
+	    pass "short line 2"
+	}
+	"$gdb_prompt" {
+	    fail "short line 2"
+	}
+	timeout {
+	    fail "short line 2 (timeout)"
+	}
+    }
+
+    send_gdb "call clear_complaints (&symfile_complaints, 1, 0)\n"
+    gdb_expect {
+	-re "\r\n\r\n$gdb_prompt " {
+	    pass "short end"
+	}
+	"$gdb_prompt" {
+	    fail "short end"
+	}
+	timeout {
+	    fail "short end (timeout)"
+	}
+    }
+
+    return 0
+}
+
+# Find a pathname to a file that we would execute if the shell was asked
+# to run $arg using the current PATH.
+
+proc find_gdb { arg } {
+
+    # If the arg directly specifies an existing executable file, then
+    # simply use it.
+
+    if [file executable $arg] then {
+	return $arg
+    }
+
+    set result [which $arg]
+    if [string match "/" [ string range $result 0 0 ]] then {
+	return $result
+    }
+
+    # If everything fails, just return the unqualified pathname as default
+    # and hope for best.
+
+    return $arg
+}
+
+# Run the test with self.
+# Copy the file executable file in case this OS doesn't like to edit its own
+# text space.
+
+set GDB_FULLPATH [find_gdb $GDB]
+
+# Remove any old copy lying around.
+remote_file host delete x$tool
+
+gdb_start
+
+set file [remote_download host $GDB_FULLPATH x$tool]
+
+set setup_result [setup_test $file ]
+if {$setup_result <0} then {
+    return -1
+}
+
+test_isolated_complaints
+test_serial_complaints
+test_short_complaints
+
+gdb_exit;
+catch "remote_file host delete $file";

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]