2004-07-28 Andrew Cagney <cagney@gnu.org>
[platform/upstream/binutils.git] / gdb / complaints.c
1 /* Support for complaint handling during symbol reading in GDB.
2
3    Copyright 1990, 1991, 1992, 1993, 1995, 1998, 1999, 2000, 2002,
4    2004 Free Software Foundation, Inc.
5
6    This file is part of GDB.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330,
21    Boston, MA 02111-1307, USA.  */
22
23 #include "defs.h"
24 #include "complaints.h"
25 #include "gdb_assert.h"
26 #include "command.h"
27 #include "gdbcmd.h"
28
29 extern void _initialize_complaints (void);
30
31 /* Should each complaint message be self explanatory, or should we assume that
32    a series of complaints is being produced?  */
33
34 /* case 1: First message of a series that must
35    start off with explanation.  case 2: Subsequent message of a series
36    that needs no explanation (the user already knows we have a problem
37    so we can just state our piece).  */
38 enum complaint_series {
39   /* Isolated self explanatory message.  */
40   ISOLATED_MESSAGE,
41   /* First message of a series, includes an explanation.  */
42   FIRST_MESSAGE,
43   /* First message of a series, but does not need to include any sort
44      of explanation.  */
45   SHORT_FIRST_MESSAGE,
46   /* Subsequent message of a series that needs no explanation (the
47      user already knows we have a problem so we can just state our
48      piece).  */
49   SUBSEQUENT_MESSAGE
50 };
51
52 /* Structure to manage complaints about symbol file contents.  */
53
54 struct complain
55 {
56   const char *file;
57   int line;
58   const char *fmt;
59   int counter;
60   struct complain *next;
61 };
62
63 /* The explanatory message that should accompany the complaint.  The
64    message is in two parts - pre and post - that are printed around
65    the complaint text.  */
66 struct explanation
67 {
68   const char *prefix;
69   const char *postfix;
70 };
71
72 struct complaints
73 {
74   struct complain *root;
75
76   /* Should each complaint be self explanatory, or should we assume
77      that a series of complaints is being produced?  case 0: Isolated
78      self explanatory message.  case 1: First message of a series that
79      must start off with explanation.  case 2: Subsequent message of a
80      series that needs no explanation (the user already knows we have
81      a problem so we can just state our piece).  */
82   int series;
83
84   /* The explanatory messages that should accompany the complaint.
85      NOTE: cagney/2002-08-14: In a desperate attempt at being vaguely
86      i18n friendly, this is an array of two messages.  When present,
87      the PRE and POST EXPLANATION[SERIES] are used to wrap the
88      message.  */
89   const struct explanation *explanation;
90 };
91
92 static struct complain complaint_sentinel;
93
94 /* The symbol table complaint table.  */
95
96 static struct explanation symfile_explanations[] = {
97   { "During symbol reading, ", "." },
98   { "During symbol reading...", "..."},
99   { "", "..."},
100   { "", "..."},
101   { NULL, NULL }
102 };
103
104 static struct complaints symfile_complaint_book = {
105   &complaint_sentinel,
106   0,
107   symfile_explanations
108 };
109 struct complaints *symfile_complaints = &symfile_complaint_book;
110
111 /* Wrapper function to, on-demand, fill in a complaints object.  */
112
113 static struct complaints *
114 get_complaints (struct complaints **c)
115 {
116   if ((*c) != NULL)
117     return (*c);
118   (*c) = XMALLOC (struct complaints);
119   (*c)->root = &complaint_sentinel;
120   (*c)->series = ISOLATED_MESSAGE;
121   (*c)->explanation = NULL;
122   return (*c);
123 }
124
125 static struct complain *
126 find_complaint (struct complaints *complaints, const char *file,
127                 int line, const char *fmt)
128 {
129   struct complain *complaint;
130
131   /* Find the complaint in the table.  A more efficient search
132      algorithm (based on hash table or something) could be used.  But
133      that can wait until someone shows evidence that this lookup is
134      a real bottle neck.  */
135   for (complaint = complaints->root;
136        complaint != NULL;
137        complaint = complaint->next)
138     {
139       if (complaint->fmt == fmt
140           && complaint->file == file
141           && complaint->line == line)
142         return complaint;
143     }
144
145   /* Oops not seen before, fill in a new complaint.  */
146   complaint = XMALLOC (struct complain);
147   complaint->fmt = fmt;
148   complaint->file = file;
149   complaint->line = line;
150   complaint->counter = 0;
151   complaint->next = NULL;
152
153   /* File it, return it.  */
154   complaint->next = complaints->root;
155   complaints->root = complaint;
156   return complaint;
157 }
158
159
160 /* How many complaints about a particular thing should be printed
161    before we stop whining about it?  Default is no whining at all,
162    since so many systems have ill-constructed symbol files.  */
163
164 static unsigned int stop_whining = 0;
165
166 /* Print a complaint, and link the complaint block into a chain for
167    later handling.  */
168
169 static void
170 vcomplaint (struct complaints **c, const char *file, int line, const char *fmt,
171             va_list args)
172 {
173   struct complaints *complaints = get_complaints (c);
174   struct complain *complaint = find_complaint (complaints, file, line, fmt);
175   enum complaint_series series;
176   gdb_assert (complaints != NULL);
177
178   complaint->counter++;
179   if (complaint->counter > stop_whining)
180     return;
181
182   if (info_verbose)
183     series = SUBSEQUENT_MESSAGE;
184   else
185     series = complaints->series;
186
187   if (complaint->file != NULL)
188     internal_vwarning (complaint->file, complaint->line, complaint->fmt, args);
189   else if (deprecated_warning_hook)
190     (*deprecated_warning_hook) (complaint->fmt, args);
191   else
192     {
193       if (complaints->explanation == NULL)
194         /* A [v]warning() call always appends a newline.  */
195         vwarning (complaint->fmt, args);
196       else
197         {
198           char *msg;
199           struct cleanup *cleanups;
200           msg = xstrvprintf (complaint->fmt, args);
201           cleanups = make_cleanup (xfree, msg);
202           wrap_here ("");
203           if (series != SUBSEQUENT_MESSAGE)
204             begin_line ();
205           fprintf_filtered (gdb_stderr, "%s%s%s",
206                             complaints->explanation[series].prefix, msg,
207                             complaints->explanation[series].postfix);
208           /* Force a line-break after any isolated message.  For the
209              other cases, clear_complaints() takes care of any missing
210              trailing newline, the wrap_here() is just a hint.  */
211           if (series == ISOLATED_MESSAGE)
212             /* It would be really nice to use begin_line() here.
213                Unfortunately that function doesn't track GDB_STDERR and
214                consequently will sometimes supress a line when it
215                shouldn't.  */
216             fputs_filtered ("\n", gdb_stderr);
217           else
218             wrap_here ("");
219           do_cleanups (cleanups);
220         }
221     }
222
223   switch (series)
224     {
225     case ISOLATED_MESSAGE:
226       break;
227     case FIRST_MESSAGE:
228       complaints->series = SUBSEQUENT_MESSAGE;
229       break;
230     case SUBSEQUENT_MESSAGE:
231     case SHORT_FIRST_MESSAGE:
232       complaints->series = SUBSEQUENT_MESSAGE;
233       break;
234     }
235
236   /* If GDB dumps core, we'd like to see the complaints first.
237      Presumably GDB will not be sending so many complaints that this
238      becomes a performance hog.  */
239
240   gdb_flush (gdb_stderr);
241 }
242
243 void
244 complaint (struct complaints **complaints, const char *fmt, ...)
245 {
246   va_list args;
247   va_start (args, fmt);
248   vcomplaint (complaints, NULL/*file*/, 0/*line*/, fmt, args);
249   va_end (args);
250 }
251
252 void
253 internal_complaint (struct complaints **complaints, const char *file,
254                     int line, const char *fmt, ...)
255 {
256   va_list args;
257   va_start (args, fmt);
258   vcomplaint (complaints, file, line, fmt, args);
259   va_end (args);
260 }
261
262 /* Clear out / initialize all complaint counters that have ever been
263    incremented.  If LESS_VERBOSE is 1, be less verbose about
264    successive complaints, since the messages are appearing all
265    together during a command that is reporting a contiguous block of
266    complaints (rather than being interleaved with other messages).  If
267    noisy is 1, we are in a noisy command, and our caller will print
268    enough context for the user to figure it out.  */
269
270 void
271 clear_complaints (struct complaints **c, int less_verbose, int noisy)
272 {
273   struct complaints *complaints = get_complaints (c);
274   struct complain *p;
275
276   for (p = complaints->root; p != NULL; p = p->next)
277     {
278       p->counter = 0;
279     }
280
281   switch (complaints->series)
282     {
283     case FIRST_MESSAGE:
284       /* Haven't yet printed anything.  */
285       break;
286     case SHORT_FIRST_MESSAGE:
287       /* Haven't yet printed anything.  */
288       break;
289     case ISOLATED_MESSAGE:
290       /* The code above, always forces a line-break.  No need to do it
291          here.  */
292       break;
293     case SUBSEQUENT_MESSAGE:
294       /* It would be really nice to use begin_line() here.
295          Unfortunately that function doesn't track GDB_STDERR and
296          consequently will sometimes supress a line when it shouldn't.  */
297       fputs_unfiltered ("\n", gdb_stderr);
298       break;
299     default:
300       internal_error (__FILE__, __LINE__, "bad switch");
301     }
302
303   if (!less_verbose)
304     complaints->series = ISOLATED_MESSAGE;
305   else if (!noisy)
306     complaints->series = FIRST_MESSAGE;
307   else
308     complaints->series = SHORT_FIRST_MESSAGE;
309 }
310
311 void
312 _initialize_complaints (void)
313 {
314   add_setshow_cmd ("complaints", class_support, var_zinteger,
315                    &stop_whining, "\
316 Set max number of complaints about incorrect symbols.", "\
317 Show max number of complaints about incorrect symbols.", "\
318 Set to zero to disable incorrect symbol complaints.", "\
319 Max number of complaints about incorrect symbols is %s.",
320                    NULL, NULL,
321                    &setlist, &showlist);
322
323 }