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