GDB (API)
/home/stan/gdb/src/gdb/complaints.c
Go to the documentation of this file.
00001 /* Support for complaint handling during symbol reading in GDB.
00002 
00003    Copyright (C) 1990-2013 Free Software Foundation, Inc.
00004 
00005    This file is part of GDB.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 3 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00019 
00020 #include "defs.h"
00021 #include "complaints.h"
00022 #include "gdb_assert.h"
00023 #include "command.h"
00024 #include "gdbcmd.h"
00025 
00026 extern void _initialize_complaints (void);
00027 
00028 /* Should each complaint message be self explanatory, or should we
00029    assume that a series of complaints is being produced?  */
00030 
00031 /* case 1: First message of a series that must
00032    start off with explanation.  case 2: Subsequent message of a series
00033    that needs no explanation (the user already knows we have a problem
00034    so we can just state our piece).  */
00035 enum complaint_series {
00036   /* Isolated self explanatory message.  */
00037   ISOLATED_MESSAGE,
00038   /* First message of a series, includes an explanation.  */
00039   FIRST_MESSAGE,
00040   /* First message of a series, but does not need to include any sort
00041      of explanation.  */
00042   SHORT_FIRST_MESSAGE,
00043   /* Subsequent message of a series that needs no explanation (the
00044      user already knows we have a problem so we can just state our
00045      piece).  */
00046   SUBSEQUENT_MESSAGE
00047 };
00048 
00049 /* Structure to manage complaints about symbol file contents.  */
00050 
00051 struct complain
00052 {
00053   const char *file;
00054   int line;
00055   const char *fmt;
00056   int counter;
00057   struct complain *next;
00058 };
00059 
00060 /* The explanatory message that should accompany the complaint.  The
00061    message is in two parts - pre and post - that are printed around
00062    the complaint text.  */
00063 struct explanation
00064 {
00065   const char *prefix;
00066   const char *postfix;
00067 };
00068 
00069 struct complaints
00070 {
00071   struct complain *root;
00072 
00073   /* Should each complaint be self explanatory, or should we assume
00074      that a series of complaints is being produced?  case 0: Isolated
00075      self explanatory message.  case 1: First message of a series that
00076      must start off with explanation.  case 2: Subsequent message of a
00077      series that needs no explanation (the user already knows we have
00078      a problem so we can just state our piece).  */
00079   int series;
00080 
00081   /* The explanatory messages that should accompany the complaint.
00082      NOTE: cagney/2002-08-14: In a desperate attempt at being vaguely
00083      i18n friendly, this is an array of two messages.  When present,
00084      the PRE and POST EXPLANATION[SERIES] are used to wrap the
00085      message.  */
00086   const struct explanation *explanation;
00087 };
00088 
00089 static struct complain complaint_sentinel;
00090 
00091 /* The symbol table complaint table.  */
00092 
00093 static struct explanation symfile_explanations[] = {
00094   { "During symbol reading, ", "." },
00095   { "During symbol reading...", "..."},
00096   { "", "..."},
00097   { "", "..."},
00098   { NULL, NULL }
00099 };
00100 
00101 static struct complaints symfile_complaint_book = {
00102   &complaint_sentinel,
00103   0,
00104   symfile_explanations
00105 };
00106 struct complaints *symfile_complaints = &symfile_complaint_book;
00107 
00108 /* Wrapper function to, on-demand, fill in a complaints object.  */
00109 
00110 static struct complaints *
00111 get_complaints (struct complaints **c)
00112 {
00113   if ((*c) != NULL)
00114     return (*c);
00115   (*c) = XMALLOC (struct complaints);
00116   (*c)->root = &complaint_sentinel;
00117   (*c)->series = ISOLATED_MESSAGE;
00118   (*c)->explanation = NULL;
00119   return (*c);
00120 }
00121 
00122 static struct complain * ATTRIBUTE_PRINTF (4, 0)
00123 find_complaint (struct complaints *complaints, const char *file,
00124                 int line, const char *fmt)
00125 {
00126   struct complain *complaint;
00127 
00128   /* Find the complaint in the table.  A more efficient search
00129      algorithm (based on hash table or something) could be used.  But
00130      that can wait until someone shows evidence that this lookup is
00131      a real bottle neck.  */
00132   for (complaint = complaints->root;
00133        complaint != NULL;
00134        complaint = complaint->next)
00135     {
00136       if (complaint->fmt == fmt
00137           && complaint->file == file
00138           && complaint->line == line)
00139         return complaint;
00140     }
00141 
00142   /* Oops not seen before, fill in a new complaint.  */
00143   complaint = XMALLOC (struct complain);
00144   complaint->fmt = fmt;
00145   complaint->file = file;
00146   complaint->line = line;
00147   complaint->counter = 0;
00148   complaint->next = NULL;
00149 
00150   /* File it, return it.  */
00151   complaint->next = complaints->root;
00152   complaints->root = complaint;
00153   return complaint;
00154 }
00155 
00156 
00157 /* How many complaints about a particular thing should be printed
00158    before we stop whining about it?  Default is no whining at all,
00159    since so many systems have ill-constructed symbol files.  */
00160 
00161 static int stop_whining = 0;
00162 
00163 /* Print a complaint, and link the complaint block into a chain for
00164    later handling.  */
00165 
00166 static void ATTRIBUTE_PRINTF (4, 0)
00167 vcomplaint (struct complaints **c, const char *file, 
00168             int line, const char *fmt,
00169             va_list args)
00170 {
00171   struct complaints *complaints = get_complaints (c);
00172   struct complain *complaint = find_complaint (complaints, file, 
00173                                                line, fmt);
00174   enum complaint_series series;
00175 
00176   gdb_assert (complaints != NULL);
00177 
00178   complaint->counter++;
00179   if (complaint->counter > stop_whining)
00180     return;
00181 
00182   if (info_verbose)
00183     series = SUBSEQUENT_MESSAGE;
00184   else
00185     series = complaints->series;
00186 
00187   if (complaint->file != NULL)
00188     internal_vwarning (complaint->file, complaint->line, 
00189                        complaint->fmt, args);
00190   else if (deprecated_warning_hook)
00191     (*deprecated_warning_hook) (complaint->fmt, args);
00192   else
00193     {
00194       if (complaints->explanation == NULL)
00195         /* A [v]warning() call always appends a newline.  */
00196         vwarning (complaint->fmt, args);
00197       else
00198         {
00199           char *msg;
00200           struct cleanup *cleanups;
00201           msg = xstrvprintf (complaint->fmt, args);
00202           cleanups = make_cleanup (xfree, msg);
00203           wrap_here ("");
00204           if (series != SUBSEQUENT_MESSAGE)
00205             begin_line ();
00206           /* XXX: i18n */
00207           fprintf_filtered (gdb_stderr, "%s%s%s",
00208                             complaints->explanation[series].prefix, msg,
00209                             complaints->explanation[series].postfix);
00210           /* Force a line-break after any isolated message.  For the
00211              other cases, clear_complaints() takes care of any missing
00212              trailing newline, the wrap_here() is just a hint.  */
00213           if (series == ISOLATED_MESSAGE)
00214             /* It would be really nice to use begin_line() here.
00215                Unfortunately that function doesn't track GDB_STDERR and
00216                consequently will sometimes supress a line when it
00217                shouldn't.  */
00218             fputs_filtered ("\n", gdb_stderr);
00219           else
00220             wrap_here ("");
00221           do_cleanups (cleanups);
00222         }
00223     }
00224 
00225   switch (series)
00226     {
00227     case ISOLATED_MESSAGE:
00228       break;
00229     case FIRST_MESSAGE:
00230       complaints->series = SUBSEQUENT_MESSAGE;
00231       break;
00232     case SUBSEQUENT_MESSAGE:
00233     case SHORT_FIRST_MESSAGE:
00234       complaints->series = SUBSEQUENT_MESSAGE;
00235       break;
00236     }
00237 
00238   /* If GDB dumps core, we'd like to see the complaints first.
00239      Presumably GDB will not be sending so many complaints that this
00240      becomes a performance hog.  */
00241 
00242   gdb_flush (gdb_stderr);
00243 }
00244 
00245 void
00246 complaint (struct complaints **complaints, const char *fmt, ...)
00247 {
00248   va_list args;
00249 
00250   va_start (args, fmt);
00251   vcomplaint (complaints, NULL/*file*/, 0/*line*/, fmt, args);
00252   va_end (args);
00253 }
00254 
00255 void
00256 internal_complaint (struct complaints **complaints, const char *file,
00257                     int line, const char *fmt, ...)
00258 {
00259   va_list args;
00260   va_start (args, fmt);
00261   vcomplaint (complaints, file, line, fmt, args);
00262   va_end (args);
00263 }
00264 
00265 /* Clear out / initialize all complaint counters that have ever been
00266    incremented.  If LESS_VERBOSE is 1, be less verbose about
00267    successive complaints, since the messages are appearing all
00268    together during a command that is reporting a contiguous block of
00269    complaints (rather than being interleaved with other messages).  If
00270    noisy is 1, we are in a noisy command, and our caller will print
00271    enough context for the user to figure it out.  */
00272 
00273 void
00274 clear_complaints (struct complaints **c, int less_verbose, int noisy)
00275 {
00276   struct complaints *complaints = get_complaints (c);
00277   struct complain *p;
00278 
00279   for (p = complaints->root; p != NULL; p = p->next)
00280     {
00281       p->counter = 0;
00282     }
00283 
00284   switch (complaints->series)
00285     {
00286     case FIRST_MESSAGE:
00287       /* Haven't yet printed anything.  */
00288       break;
00289     case SHORT_FIRST_MESSAGE:
00290       /* Haven't yet printed anything.  */
00291       break;
00292     case ISOLATED_MESSAGE:
00293       /* The code above, always forces a line-break.  No need to do it
00294          here.  */
00295       break;
00296     case SUBSEQUENT_MESSAGE:
00297       /* It would be really nice to use begin_line() here.
00298          Unfortunately that function doesn't track GDB_STDERR and
00299          consequently will sometimes supress a line when it
00300          shouldn't.  */
00301       fputs_unfiltered ("\n", gdb_stderr);
00302       break;
00303     default:
00304       internal_error (__FILE__, __LINE__, _("bad switch"));
00305     }
00306 
00307   if (!less_verbose)
00308     complaints->series = ISOLATED_MESSAGE;
00309   else if (!noisy)
00310     complaints->series = FIRST_MESSAGE;
00311   else
00312     complaints->series = SHORT_FIRST_MESSAGE;
00313 }
00314 
00315 static void
00316 complaints_show_value (struct ui_file *file, int from_tty,
00317                        struct cmd_list_element *cmd, const char *value)
00318 {
00319   fprintf_filtered (file, _("Max number of complaints about incorrect"
00320                             " symbols is %s.\n"),
00321                     value);
00322 }
00323 
00324 void
00325 _initialize_complaints (void)
00326 {
00327   add_setshow_zinteger_cmd ("complaints", class_support, 
00328                             &stop_whining, _("\
00329 Set max number of complaints about incorrect symbols."), _("\
00330 Show max number of complaints about incorrect symbols."), NULL,
00331                             NULL, complaints_show_value,
00332                             &setlist, &showlist);
00333 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines