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