119370Spst/* Support for complaint handling during symbol reading in GDB. 219370Spst 3130803Smarcel Copyright 1990, 1991, 1992, 1993, 1995, 1998, 1999, 2000, 2002 Free 4130803Smarcel Software Foundation, Inc. 5130803Smarcel 698944Sobrien This file is part of GDB. 719370Spst 898944Sobrien This program is free software; you can redistribute it and/or modify 998944Sobrien it under the terms of the GNU General Public License as published by 1098944Sobrien the Free Software Foundation; either version 2 of the License, or 1198944Sobrien (at your option) any later version. 1219370Spst 1398944Sobrien This program is distributed in the hope that it will be useful, 1498944Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1598944Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1698944Sobrien GNU General Public License for more details. 1719370Spst 1898944Sobrien You should have received a copy of the GNU General Public License 1998944Sobrien along with this program; if not, write to the Free Software 2098944Sobrien Foundation, Inc., 59 Temple Place - Suite 330, 2198944Sobrien Boston, MA 02111-1307, USA. */ 2219370Spst 2319370Spst#include "defs.h" 2419370Spst#include "complaints.h" 25130803Smarcel#include "gdb_assert.h" 26130803Smarcel#include "command.h" 2719370Spst#include "gdbcmd.h" 2819370Spst 2998944Sobrienextern void _initialize_complaints (void); 3098944Sobrien 31130803Smarcel/* Should each complaint message be self explanatory, or should we assume that 32130803Smarcel a series of complaints is being produced? */ 33130803Smarcel 34130803Smarcel/* case 1: First message of a series that must 35130803Smarcel start off with explanation. case 2: Subsequent message of a series 36130803Smarcel that needs no explanation (the user already knows we have a problem 37130803Smarcel so we can just state our piece). */ 38130803Smarcelenum complaint_series { 39130803Smarcel /* Isolated self explanatory message. */ 40130803Smarcel ISOLATED_MESSAGE, 41130803Smarcel /* First message of a series, includes an explanation. */ 42130803Smarcel FIRST_MESSAGE, 43130803Smarcel /* First message of a series, but does not need to include any sort 44130803Smarcel of explanation. */ 45130803Smarcel SHORT_FIRST_MESSAGE, 46130803Smarcel /* Subsequent message of a series that needs no explanation (the 47130803Smarcel user already knows we have a problem so we can just state our 48130803Smarcel piece). */ 49130803Smarcel SUBSEQUENT_MESSAGE 50130803Smarcel}; 51130803Smarcel 5219370Spst/* Structure to manage complaints about symbol file contents. */ 5319370Spst 54130803Smarcelstruct complain 5598944Sobrien{ 56130803Smarcel const char *file; 57130803Smarcel int line; 58130803Smarcel const char *fmt; 59130803Smarcel int counter; 60130803Smarcel struct complain *next; 6119370Spst}; 6219370Spst 63130803Smarcel/* The explanatory message that should accompany the complaint. The 64130803Smarcel message is in two parts - pre and post - that are printed around 65130803Smarcel the complaint text. */ 66130803Smarcelstruct explanation 67130803Smarcel{ 68130803Smarcel const char *prefix; 69130803Smarcel const char *postfix; 70130803Smarcel}; 7119370Spst 72130803Smarcelstruct complaints 73130803Smarcel{ 74130803Smarcel struct complain *root; 7519370Spst 76130803Smarcel /* Should each complaint be self explanatory, or should we assume 77130803Smarcel that a series of complaints is being produced? case 0: Isolated 78130803Smarcel self explanatory message. case 1: First message of a series that 79130803Smarcel must start off with explanation. case 2: Subsequent message of a 80130803Smarcel series that needs no explanation (the user already knows we have 81130803Smarcel a problem so we can just state our piece). */ 82130803Smarcel int series; 8319370Spst 84130803Smarcel /* The explanatory messages that should accompany the complaint. 85130803Smarcel NOTE: cagney/2002-08-14: In a desperate attempt at being vaguely 86130803Smarcel i18n friendly, this is an array of two messages. When present, 87130803Smarcel the PRE and POST EXPLANATION[SERIES] are used to wrap the 88130803Smarcel message. */ 89130803Smarcel const struct explanation *explanation; 90130803Smarcel}; 9119370Spst 92130803Smarcelstatic struct complain complaint_sentinel; 9319370Spst 94130803Smarcel/* The symbol table complaint table. */ 9519370Spst 96130803Smarcelstatic struct explanation symfile_explanations[] = { 97130803Smarcel { "During symbol reading, ", "." }, 98130803Smarcel { "During symbol reading...", "..."}, 99130803Smarcel { "", "..."}, 100130803Smarcel { "", "..."}, 101130803Smarcel { NULL, NULL } 102130803Smarcel}; 10319370Spst 104130803Smarcelstatic struct complaints symfile_complaint_book = { 105130803Smarcel &complaint_sentinel, 106130803Smarcel 0, 107130803Smarcel symfile_explanations 108130803Smarcel}; 109130803Smarcelstruct complaints *symfile_complaints = &symfile_complaint_book; 110130803Smarcel 111130803Smarcel/* Wrapper function to, on-demand, fill in a complaints object. */ 112130803Smarcel 113130803Smarcelstatic struct complaints * 114130803Smarcelget_complaints (struct complaints **c) 11519370Spst{ 116130803Smarcel if ((*c) != NULL) 117130803Smarcel return (*c); 118130803Smarcel (*c) = XMALLOC (struct complaints); 119130803Smarcel (*c)->root = &complaint_sentinel; 120130803Smarcel (*c)->series = ISOLATED_MESSAGE; 121130803Smarcel (*c)->explanation = NULL; 122130803Smarcel return (*c); 123130803Smarcel} 12419370Spst 125130803Smarcelstatic struct complain * 126130803Smarcelfind_complaint (struct complaints *complaints, const char *file, 127130803Smarcel int line, const char *fmt) 128130803Smarcel{ 129130803Smarcel struct complain *complaint; 130130803Smarcel 131130803Smarcel /* Find the complaint in the table. A more efficient search 132130803Smarcel algorithm (based on hash table or something) could be used. But 133130803Smarcel that can wait until someone shows evidence that this lookup is 134130803Smarcel a real bottle neck. */ 135130803Smarcel for (complaint = complaints->root; 136130803Smarcel complaint != NULL; 137130803Smarcel complaint = complaint->next) 13819370Spst { 139130803Smarcel if (complaint->fmt == fmt 140130803Smarcel && complaint->file == file 141130803Smarcel && complaint->line == line) 142130803Smarcel return complaint; 14319370Spst } 144130803Smarcel 145130803Smarcel /* Oops not seen before, fill in a new complaint. */ 146130803Smarcel complaint = XMALLOC (struct complain); 147130803Smarcel complaint->fmt = fmt; 148130803Smarcel complaint->file = file; 149130803Smarcel complaint->line = line; 150130803Smarcel complaint->counter = 0; 151130803Smarcel complaint->next = NULL; 152130803Smarcel 153130803Smarcel /* File it, return it. */ 154130803Smarcel complaint->next = complaints->root; 155130803Smarcel complaints->root = complaint; 156130803Smarcel return complaint; 157130803Smarcel} 158130803Smarcel 159130803Smarcel 160130803Smarcel/* How many complaints about a particular thing should be printed 161130803Smarcel before we stop whining about it? Default is no whining at all, 162130803Smarcel since so many systems have ill-constructed symbol files. */ 163130803Smarcel 164130803Smarcelstatic unsigned int stop_whining = 0; 165130803Smarcel 166130803Smarcel/* Print a complaint, and link the complaint block into a chain for 167130803Smarcel later handling. */ 168130803Smarcel 169130803Smarcelstatic void 170130803Smarcelvcomplaint (struct complaints **c, const char *file, int line, const char *fmt, 171130803Smarcel va_list args) 172130803Smarcel{ 173130803Smarcel struct complaints *complaints = get_complaints (c); 174130803Smarcel struct complain *complaint = find_complaint (complaints, file, line, fmt); 175130803Smarcel enum complaint_series series; 176130803Smarcel gdb_assert (complaints != NULL); 177130803Smarcel 178130803Smarcel complaint->counter++; 17998944Sobrien if (complaint->counter > stop_whining) 180130803Smarcel return; 181130803Smarcel 182130803Smarcel if (info_verbose) 183130803Smarcel series = SUBSEQUENT_MESSAGE; 184130803Smarcel else 185130803Smarcel series = complaints->series; 186130803Smarcel 187130803Smarcel if (complaint->file != NULL) 188130803Smarcel internal_vwarning (complaint->file, complaint->line, complaint->fmt, args); 189130803Smarcel else if (warning_hook) 190130803Smarcel (*warning_hook) (complaint->fmt, args); 191130803Smarcel else 19219370Spst { 193130803Smarcel if (complaints->explanation == NULL) 194130803Smarcel /* A [v]warning() call always appends a newline. */ 195130803Smarcel vwarning (complaint->fmt, args); 196130803Smarcel else 197130803Smarcel { 198130803Smarcel char *msg; 199130803Smarcel struct cleanup *cleanups; 200130803Smarcel xvasprintf (&msg, complaint->fmt, args); 201130803Smarcel cleanups = make_cleanup (xfree, msg); 202130803Smarcel wrap_here (""); 203130803Smarcel if (series != SUBSEQUENT_MESSAGE) 204130803Smarcel begin_line (); 205130803Smarcel fprintf_filtered (gdb_stderr, "%s%s%s", 206130803Smarcel complaints->explanation[series].prefix, msg, 207130803Smarcel complaints->explanation[series].postfix); 208130803Smarcel /* Force a line-break after any isolated message. For the 209130803Smarcel other cases, clear_complaints() takes care of any missing 210130803Smarcel trailing newline, the wrap_here() is just a hint. */ 211130803Smarcel if (series == ISOLATED_MESSAGE) 212130803Smarcel /* It would be really nice to use begin_line() here. 213130803Smarcel Unfortunately that function doesn't track GDB_STDERR and 214130803Smarcel consequently will sometimes supress a line when it 215130803Smarcel shouldn't. */ 216130803Smarcel fputs_filtered ("\n", gdb_stderr); 217130803Smarcel else 218130803Smarcel wrap_here (""); 219130803Smarcel do_cleanups (cleanups); 220130803Smarcel } 22119370Spst } 22219370Spst 223130803Smarcel switch (series) 22419370Spst { 225130803Smarcel case ISOLATED_MESSAGE: 22698944Sobrien break; 227130803Smarcel case FIRST_MESSAGE: 228130803Smarcel complaints->series = SUBSEQUENT_MESSAGE; 22998944Sobrien break; 230130803Smarcel case SUBSEQUENT_MESSAGE: 231130803Smarcel case SHORT_FIRST_MESSAGE: 232130803Smarcel complaints->series = SUBSEQUENT_MESSAGE; 233130803Smarcel break; 234130803Smarcel } 23519370Spst 236130803Smarcel /* If GDB dumps core, we'd like to see the complaints first. 237130803Smarcel Presumably GDB will not be sending so many complaints that this 238130803Smarcel becomes a performance hog. */ 239130803Smarcel 24098944Sobrien gdb_flush (gdb_stderr); 241130803Smarcel} 242130803Smarcel 243130803Smarcelvoid 244130803Smarcelcomplaint (struct complaints **complaints, const char *fmt, ...) 245130803Smarcel{ 246130803Smarcel va_list args; 247130803Smarcel va_start (args, fmt); 248130803Smarcel vcomplaint (complaints, NULL/*file*/, 0/*line*/, fmt, args); 24919370Spst va_end (args); 25019370Spst} 25119370Spst 252130803Smarcelvoid 253130803Smarcelinternal_complaint (struct complaints **complaints, const char *file, 254130803Smarcel int line, const char *fmt, ...) 255130803Smarcel{ 256130803Smarcel va_list args; 257130803Smarcel va_start (args, fmt); 258130803Smarcel vcomplaint (complaints, file, line, fmt, args); 259130803Smarcel va_end (args); 260130803Smarcel} 26119370Spst 262130803Smarcel/* Clear out / initialize all complaint counters that have ever been 263130803Smarcel incremented. If LESS_VERBOSE is 1, be less verbose about 264130803Smarcel successive complaints, since the messages are appearing all 265130803Smarcel together during a command that is reporting a contiguous block of 266130803Smarcel complaints (rather than being interleaved with other messages). If 267130803Smarcel noisy is 1, we are in a noisy command, and our caller will print 268130803Smarcel enough context for the user to figure it out. */ 269130803Smarcel 27019370Spstvoid 271130803Smarcelclear_complaints (struct complaints **c, int less_verbose, int noisy) 27219370Spst{ 273130803Smarcel struct complaints *complaints = get_complaints (c); 274130803Smarcel struct complain *p; 27519370Spst 276130803Smarcel for (p = complaints->root; p != NULL; p = p->next) 27719370Spst { 27898944Sobrien p->counter = 0; 27919370Spst } 28019370Spst 281130803Smarcel switch (complaints->series) 28219370Spst { 283130803Smarcel case FIRST_MESSAGE: 284130803Smarcel /* Haven't yet printed anything. */ 285130803Smarcel break; 286130803Smarcel case SHORT_FIRST_MESSAGE: 287130803Smarcel /* Haven't yet printed anything. */ 288130803Smarcel break; 289130803Smarcel case ISOLATED_MESSAGE: 290130803Smarcel /* The code above, always forces a line-break. No need to do it 291130803Smarcel here. */ 292130803Smarcel break; 293130803Smarcel case SUBSEQUENT_MESSAGE: 294130803Smarcel /* It would be really nice to use begin_line() here. 295130803Smarcel Unfortunately that function doesn't track GDB_STDERR and 296130803Smarcel consequently will sometimes supress a line when it shouldn't. */ 297130803Smarcel fputs_unfiltered ("\n", gdb_stderr); 298130803Smarcel break; 299130803Smarcel default: 300130803Smarcel internal_error (__FILE__, __LINE__, "bad switch"); 30119370Spst } 30219370Spst 303130803Smarcel if (!less_verbose) 304130803Smarcel complaints->series = ISOLATED_MESSAGE; 305130803Smarcel else if (!noisy) 306130803Smarcel complaints->series = FIRST_MESSAGE; 307130803Smarcel else 308130803Smarcel complaints->series = SHORT_FIRST_MESSAGE; 30919370Spst} 31019370Spst 31119370Spstvoid 31298944Sobrien_initialize_complaints (void) 31319370Spst{ 314130803Smarcel add_setshow_cmd ("complaints", class_support, var_zinteger, 315130803Smarcel &stop_whining, 316130803Smarcel "Set max number of complaints about incorrect symbols.", 317130803Smarcel "Show max number of complaints about incorrect symbols.", 318130803Smarcel NULL, NULL, 319130803Smarcel &setlist, &showlist); 32019370Spst 32119370Spst} 322