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