1 /* messages.c - error reporter - 2 Copyright (C) 1987-2024 Free Software Foundation, Inc. 3 This file is part of GAS, the GNU Assembler. 4 5 GAS is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3, or (at your option) 8 any later version. 9 10 GAS is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with GAS; see the file COPYING. If not, write to the Free 17 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 18 02110-1301, USA. */ 19 20 #include "as.h" 21 #include <limits.h> 22 #include <signal.h> 23 24 /* If the system doesn't provide strsignal, we get it defined in 25 libiberty but no declaration is supplied. Because, reasons. */ 26 #if !defined (HAVE_STRSIGNAL) && !defined (strsignal) 27 extern const char *strsignal (int); 28 #endif 29 30 static void identify (const char *); 31 static void as_show_where (void); 32 static void as_warn_internal (const char *, unsigned int, char *); 33 static void as_bad_internal (const char *, unsigned int, char *); 34 static void signal_crash (int) ATTRIBUTE_NORETURN; 35 36 /* Despite the rest of the comments in this file, (FIXME-SOON), 37 here is the current scheme for error messages etc: 38 39 as_fatal() is used when gas is quite confused and 40 continuing the assembly is pointless. In this case we 41 exit immediately with error status. 42 43 as_bad() is used to mark errors that result in what we 44 presume to be a useless object file. Say, we ignored 45 something that might have been vital. If we see any of 46 these, assembly will continue to the end of the source, 47 no object file will be produced, and we will terminate 48 with error status. The new option, -Z, tells us to 49 produce an object file anyway but we still exit with 50 error status. The assumption here is that you don't want 51 this object file but we could be wrong. 52 53 as_warn() is used when we have an error from which we 54 have a plausible error recovery. eg, masking the top 55 bits of a constant that is longer than will fit in the 56 destination. In this case we will continue to assemble 57 the source, although we may have made a bad assumption, 58 and we will produce an object file and return normal exit 59 status (ie, no error). The new option -X tells us to 60 treat all as_warn() errors as as_bad() errors. That is, 61 no object file will be produced and we will exit with 62 error status. The idea here is that we don't kill an 63 entire make because of an error that we knew how to 64 correct. On the other hand, sometimes you might want to 65 stop the make at these points. 66 67 as_tsktsk() is used when we see a minor error for which 68 our error recovery action is almost certainly correct. 69 In this case, we print a message and then assembly 70 continues as though no error occurred. 71 72 as_abort () is used for logic failure (assert or abort, signal). 73 */ 74 75 static void 76 identify (const char *file) 77 { 78 static int identified; 79 80 if (identified) 81 return; 82 identified++; 83 84 if (!file) 85 { 86 unsigned int x; 87 file = as_where (&x); 88 } 89 90 if (file) 91 fprintf (stderr, "%s: ", file); 92 fprintf (stderr, _("Assembler messages:\n")); 93 } 94 95 /* The number of warnings issued. */ 96 static int warning_count; 97 98 int 99 had_warnings (void) 100 { 101 return warning_count; 102 } 103 104 /* Nonzero if we've hit a 'bad error', and should not write an obj file, 105 and exit with a nonzero error code. */ 106 107 static int error_count; 108 109 int 110 had_errors (void) 111 { 112 return error_count; 113 } 114 115 /* Print the current location to stderr. */ 116 117 static void 118 as_show_where (void) 119 { 120 const char *file; 121 unsigned int line; 122 123 file = as_where_top (&line); 124 identify (file); 125 if (file) 126 { 127 if (line != 0) 128 fprintf (stderr, "%s:%u: ", file, line); 129 else 130 fprintf (stderr, "%s: ", file); 131 } 132 } 133 134 /* Send to stderr a string as information, with location data passed in. 135 Note that for now this is not intended for general use. */ 136 137 void 138 as_info_where (const char *file, unsigned int line, unsigned int indent, 139 const char *format, ...) 140 { 141 va_list args; 142 char buffer[2000]; 143 144 va_start (args, format); 145 vsnprintf (buffer, sizeof (buffer), format, args); 146 va_end (args); 147 fprintf (stderr, "%s:%u: %*s%s%s\n", 148 file, line, (int)indent, "", _("Info: "), buffer); 149 } 150 151 /* Send to stderr a string as a warning, and locate warning 152 in input file(s). 153 Please only use this for when we have some recovery action. 154 Please explain in string (which may have '\n's) what recovery was 155 done. */ 156 157 void 158 as_tsktsk (const char *format, ...) 159 { 160 va_list args; 161 162 as_show_where (); 163 va_start (args, format); 164 vfprintf (stderr, format, args); 165 va_end (args); 166 (void) putc ('\n', stderr); 167 as_report_context (); 168 } 169 170 /* The common portion of as_warn and as_warn_where. */ 171 172 static void 173 as_warn_internal (const char *file, unsigned int line, char *buffer) 174 { 175 bool context = false; 176 177 ++warning_count; 178 179 if (file == NULL) 180 { 181 file = as_where_top (&line); 182 context = true; 183 } 184 185 identify (file); 186 if (file) 187 { 188 if (line != 0) 189 fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Warning: "), buffer); 190 else 191 fprintf (stderr, "%s: %s%s\n", file, _("Warning: "), buffer); 192 } 193 else 194 fprintf (stderr, "%s%s\n", _("Warning: "), buffer); 195 196 if (context) 197 as_report_context (); 198 199 #ifndef NO_LISTING 200 listing_warning (buffer); 201 #endif 202 } 203 204 /* Send to stderr a string as a warning, and locate warning 205 in input file(s). 206 Please only use this for when we have some recovery action. 207 Please explain in string (which may have '\n's) what recovery was 208 done. */ 209 210 void 211 as_warn (const char *format, ...) 212 { 213 va_list args; 214 char buffer[2000]; 215 216 if (!flag_no_warnings) 217 { 218 va_start (args, format); 219 vsnprintf (buffer, sizeof (buffer), format, args); 220 va_end (args); 221 as_warn_internal ((char *) NULL, 0, buffer); 222 } 223 } 224 225 /* Like as_warn but the file name and line number are passed in. 226 Unfortunately, we have to repeat the function in order to handle 227 the varargs correctly and portably. */ 228 229 void 230 as_warn_where (const char *file, unsigned int line, const char *format, ...) 231 { 232 va_list args; 233 char buffer[2000]; 234 235 if (!flag_no_warnings) 236 { 237 va_start (args, format); 238 vsnprintf (buffer, sizeof (buffer), format, args); 239 va_end (args); 240 as_warn_internal (file, line, buffer); 241 } 242 } 243 244 /* The common portion of as_bad and as_bad_where. */ 245 246 static void 247 as_bad_internal (const char *file, unsigned int line, char *buffer) 248 { 249 bool context = false; 250 251 ++error_count; 252 253 if (file == NULL) 254 { 255 file = as_where_top (&line); 256 context = true; 257 } 258 259 identify (file); 260 if (file) 261 { 262 if (line != 0) 263 fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Error: "), buffer); 264 else 265 fprintf (stderr, "%s: %s%s\n", file, _("Error: "), buffer); 266 } 267 else 268 fprintf (stderr, "%s%s\n", _("Error: "), buffer); 269 270 if (context) 271 as_report_context (); 272 273 #ifndef NO_LISTING 274 listing_error (buffer); 275 #endif 276 } 277 278 /* Send to stderr a string as a warning, and locate warning in input 279 file(s). Please use when there is no recovery, but we want to 280 continue processing but not produce an object file. 281 Please explain in string (which may have '\n's) what recovery was 282 done. */ 283 284 void 285 as_bad (const char *format, ...) 286 { 287 va_list args; 288 char buffer[2000]; 289 290 va_start (args, format); 291 vsnprintf (buffer, sizeof (buffer), format, args); 292 va_end (args); 293 294 as_bad_internal ((char *) NULL, 0, buffer); 295 } 296 297 /* Like as_bad but the file name and line number are passed in. 298 Unfortunately, we have to repeat the function in order to handle 299 the varargs correctly and portably. */ 300 301 void 302 as_bad_where (const char *file, unsigned int line, const char *format, ...) 303 { 304 va_list args; 305 char buffer[2000]; 306 307 va_start (args, format); 308 vsnprintf (buffer, sizeof (buffer), format, args); 309 va_end (args); 310 311 as_bad_internal (file, line, buffer); 312 } 313 314 /* Send to stderr a string as a fatal message, and print location of 315 error in input file(s). 316 Please only use this for when we DON'T have some recovery action. 317 It xexit()s with a warning status. */ 318 319 void 320 as_fatal (const char *format, ...) 321 { 322 va_list args; 323 324 as_show_where (); 325 va_start (args, format); 326 fprintf (stderr, _("Fatal error: ")); 327 vfprintf (stderr, format, args); 328 (void) putc ('\n', stderr); 329 va_end (args); 330 as_report_context (); 331 /* Delete the output file, if it exists. This will prevent make from 332 thinking that a file was created and hence does not need rebuilding. */ 333 if (out_file_name != NULL) 334 unlink_if_ordinary (out_file_name); 335 xexit (EXIT_FAILURE); 336 } 337 338 /* Indicate internal constency error. 339 Arguments: Filename, line number, optional function name. 340 FILENAME may be NULL, which we use for crash-via-signal. */ 341 342 void 343 as_abort (const char *file, int line, const char *fn) 344 { 345 as_show_where (); 346 347 if (!file) 348 fprintf (stderr, _("Internal error (%s).\n"), fn ? fn : "unknown"); 349 else if (fn) 350 fprintf (stderr, _("Internal error in %s at %s:%d.\n"), fn, file, line); 351 else 352 fprintf (stderr, _("Internal error at %s:%d.\n"), file, line); 353 as_report_context (); 354 355 fprintf (stderr, _("Please report this bug.\n")); 356 357 xexit (EXIT_FAILURE); 358 } 359 360 /* Handler for fatal signals, such as SIGSEGV. */ 361 362 static void 363 signal_crash (int signo) 364 { 365 /* Reset, to prevent unbounded recursion. */ 366 signal (signo, SIG_DFL); 367 368 as_abort (NULL, 0, strsignal (signo)); 369 } 370 371 /* Register signal handlers, for less abrubt crashes. */ 372 373 void 374 signal_init (void) 375 { 376 #ifdef SIGSEGV 377 signal (SIGSEGV, signal_crash); 378 #endif 379 #ifdef SIGILL 380 signal (SIGILL, signal_crash); 381 #endif 382 #ifdef SIGBUS 383 signal (SIGBUS, signal_crash); 384 #endif 385 #ifdef SIGABRT 386 signal (SIGABRT, signal_crash); 387 #endif 388 #if defined SIGIOT && (!defined SIGABRT || SIGABRT != SIGIOT) 389 signal (SIGIOT, signal_crash); 390 #endif 391 #ifdef SIGFPE 392 signal (SIGFPE, signal_crash); 393 #endif 394 } 395 396 /* Support routines. */ 397 398 #define HEX_MAX_THRESHOLD 1024 399 #define HEX_MIN_THRESHOLD -(HEX_MAX_THRESHOLD) 400 401 static void 402 as_internal_value_out_of_range (const char *prefix, 403 offsetT val, 404 offsetT min, 405 offsetT max, 406 const char *file, 407 unsigned line, 408 bool bad) 409 { 410 const char * err; 411 412 if (prefix == NULL) 413 prefix = ""; 414 415 if (val >= min && val <= max) 416 { 417 addressT right = max & -max; 418 419 if (max <= 1) 420 abort (); 421 422 /* xgettext:c-format */ 423 err = _("%s out of domain (%" PRId64 424 " is not a multiple of %" PRId64 ")"); 425 426 if (bad) 427 as_bad_where (file, line, err, prefix, (int64_t) val, (int64_t) right); 428 else 429 as_warn_where (file, line, err, prefix, (int64_t) val, (int64_t) right); 430 } 431 else if ( val < HEX_MAX_THRESHOLD 432 && min < HEX_MAX_THRESHOLD 433 && max < HEX_MAX_THRESHOLD 434 && val > HEX_MIN_THRESHOLD 435 && min > HEX_MIN_THRESHOLD 436 && max > HEX_MIN_THRESHOLD) 437 { 438 /* xgettext:c-format. */ 439 err = _("%s out of range (%" PRId64 440 " is not between %" PRId64 " and %" PRId64 ")"); 441 442 if (bad) 443 as_bad_where (file, line, err, prefix, 444 (int64_t) val, (int64_t) min, (int64_t) max); 445 else 446 as_warn_where (file, line, err, prefix, 447 (int64_t) val, (int64_t) min, (int64_t) max); 448 } 449 else 450 { 451 /* xgettext:c-format. */ 452 err = _("%s out of range (0x%" PRIx64 453 " is not between 0x%" PRIx64 " and 0x%" PRIx64 ")"); 454 455 if (bad) 456 as_bad_where (file, line, err, prefix, 457 (int64_t) val, (int64_t) min, (int64_t) max); 458 else 459 as_warn_where (file, line, err, prefix, 460 (int64_t) val, (int64_t) min, (int64_t) max); 461 } 462 } 463 464 void 465 as_warn_value_out_of_range (const char *prefix, 466 offsetT value, 467 offsetT min, 468 offsetT max, 469 const char *file, 470 unsigned line) 471 { 472 as_internal_value_out_of_range (prefix, value, min, max, file, line, false); 473 } 474 475 void 476 as_bad_value_out_of_range (const char *prefix, 477 offsetT value, 478 offsetT min, 479 offsetT max, 480 const char *file, 481 unsigned line) 482 { 483 as_internal_value_out_of_range (prefix, value, min, max, file, line, true); 484 } 485