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