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_zinteger_cmd ("complaints", class_support, &stop_whining, "\ 315 Set max number of complaints about incorrect symbols.", "\ 316 Show max number of complaints about incorrect symbols.", NULL, "\ 317 Max number of complaints about incorrect symbols is %s.", 318 NULL, NULL, 319 &setlist, &showlist); 320 321 } 322