1 /* bucomm.c -- Bin Utils COMmon code. 2 Copyright (C) 1991-2022 Free Software Foundation, Inc. 3 4 This file is part of GNU Binutils. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 19 02110-1301, USA. */ 20 21 /* We might put this in a library someday so it could be dynamically 22 loaded, but for now it's not necessary. */ 23 24 #include "sysdep.h" 25 #include "bfd.h" 26 #include "libiberty.h" 27 #include "filenames.h" 28 #include <time.h> 29 #include <assert.h> 30 #include "bucomm.h" 31 32 /* Error reporting. */ 33 34 char *program_name; 35 36 void 37 bfd_nonfatal (const char *string) 38 { 39 const char *errmsg; 40 enum bfd_error err = bfd_get_error (); 41 42 if (err == bfd_error_no_error) 43 errmsg = _("cause of error unknown"); 44 else 45 errmsg = bfd_errmsg (err); 46 fflush (stdout); 47 if (string) 48 fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); 49 else 50 fprintf (stderr, "%s: %s\n", program_name, errmsg); 51 } 52 53 /* Issue a non fatal error message. FILENAME, or if NULL then BFD, 54 are used to indicate the problematic file. SECTION, if non NULL, 55 is used to provide a section name. If FORMAT is non-null, then it 56 is used to print additional information via vfprintf. Finally the 57 bfd error message is printed. In summary, error messages are of 58 one of the following forms: 59 60 PROGRAM: file: bfd-error-message 61 PROGRAM: file[section]: bfd-error-message 62 PROGRAM: file: printf-message: bfd-error-message 63 PROGRAM: file[section]: printf-message: bfd-error-message. */ 64 65 void 66 bfd_nonfatal_message (const char *filename, 67 const bfd *abfd, 68 const asection *section, 69 const char *format, ...) 70 { 71 const char *errmsg; 72 const char *section_name; 73 enum bfd_error err = bfd_get_error (); 74 75 if (err == bfd_error_no_error) 76 errmsg = _("cause of error unknown"); 77 else 78 errmsg = bfd_errmsg (err); 79 fflush (stdout); 80 section_name = NULL; 81 fprintf (stderr, "%s", program_name); 82 83 if (abfd) 84 { 85 if (!filename) 86 filename = bfd_get_archive_filename (abfd); 87 if (section) 88 section_name = bfd_section_name (section); 89 } 90 if (section_name) 91 fprintf (stderr, ": %s[%s]", filename, section_name); 92 else 93 fprintf (stderr, ": %s", filename); 94 95 if (format) 96 { 97 va_list args; 98 va_start (args, format); 99 fprintf (stderr, ": "); 100 vfprintf (stderr, format, args); 101 va_end (args); 102 } 103 fprintf (stderr, ": %s\n", errmsg); 104 } 105 106 void 107 bfd_fatal (const char *string) 108 { 109 bfd_nonfatal (string); 110 xexit (1); 111 } 112 113 void 114 report (const char * format, va_list args) 115 { 116 fflush (stdout); 117 fprintf (stderr, "%s: ", program_name); 118 vfprintf (stderr, format, args); 119 putc ('\n', stderr); 120 } 121 122 void 123 fatal (const char *format, ...) 124 { 125 va_list args; 126 127 va_start (args, format); 128 129 report (format, args); 130 va_end (args); 131 xexit (1); 132 } 133 134 void 135 non_fatal (const char *format, ...) 136 { 137 va_list args; 138 139 va_start (args, format); 140 141 report (format, args); 142 va_end (args); 143 } 144 145 /* Like xmalloc except that ABFD's objalloc memory is returned. 146 Use objalloc_free_block to free this memory and all more recently 147 allocated, or more usually, leave it to bfd_close to free. */ 148 149 void * 150 bfd_xalloc (bfd *abfd, size_t size) 151 { 152 void *ret = bfd_alloc (abfd, size); 153 if (ret == NULL) 154 bfd_fatal (NULL); 155 return ret; 156 } 157 158 /* Set the default BFD target based on the configured target. Doing 159 this permits the binutils to be configured for a particular target, 160 and linked against a shared BFD library which was configured for a 161 different target. */ 162 163 void 164 set_default_bfd_target (void) 165 { 166 /* The macro TARGET is defined by Makefile. */ 167 const char *target = TARGET; 168 169 if (! bfd_set_default_target (target)) 170 fatal (_("can't set BFD default target to `%s': %s"), 171 target, bfd_errmsg (bfd_get_error ())); 172 } 173 174 /* After a FALSE return from bfd_check_format_matches with 175 bfd_get_error () == bfd_error_file_ambiguously_recognized, print 176 the possible matching targets and free the list of targets. */ 177 178 void 179 list_matching_formats (char **matching) 180 { 181 fflush (stdout); 182 fprintf (stderr, _("%s: Matching formats:"), program_name); 183 char **p = matching; 184 while (*p) 185 fprintf (stderr, " %s", *p++); 186 free (matching); 187 fputc ('\n', stderr); 188 } 189 190 /* List the supported targets. */ 191 192 void 193 list_supported_targets (const char *name, FILE *f) 194 { 195 int t; 196 const char **targ_names; 197 198 if (name == NULL) 199 fprintf (f, _("Supported targets:")); 200 else 201 fprintf (f, _("%s: supported targets:"), name); 202 203 targ_names = bfd_target_list (); 204 for (t = 0; targ_names[t] != NULL; t++) 205 fprintf (f, " %s", targ_names[t]); 206 fprintf (f, "\n"); 207 free (targ_names); 208 } 209 210 /* List the supported architectures. */ 211 212 void 213 list_supported_architectures (const char *name, FILE *f) 214 { 215 const char ** arch; 216 const char ** arches; 217 218 if (name == NULL) 219 fprintf (f, _("Supported architectures:")); 220 else 221 fprintf (f, _("%s: supported architectures:"), name); 222 223 for (arch = arches = bfd_arch_list (); *arch; arch++) 224 fprintf (f, " %s", *arch); 225 fprintf (f, "\n"); 226 free (arches); 227 } 228 229 static const char * 230 endian_string (enum bfd_endian endian) 231 { 232 switch (endian) 233 { 234 case BFD_ENDIAN_BIG: return _("big endian"); 235 case BFD_ENDIAN_LITTLE: return _("little endian"); 236 default: return _("endianness unknown"); 237 } 238 } 239 240 /* Data passed to do_display_target and other target iterators. */ 241 242 struct display_target { 243 /* Temp file. */ 244 char *filename; 245 /* Return status. */ 246 int error; 247 /* Number of targets. */ 248 int count; 249 /* Size of info in bytes. */ 250 size_t alloc; 251 /* Per-target info. */ 252 struct { 253 /* Target name. */ 254 const char *name; 255 /* Non-zero if target/arch combination supported. */ 256 unsigned char arch[bfd_arch_last - bfd_arch_obscure - 1]; 257 } *info; 258 }; 259 260 /* List the targets that BFD is configured to support, each followed 261 by its endianness and the architectures it supports. Also build 262 info about target/archs. */ 263 264 static int 265 do_display_target (const bfd_target *targ, void *data) 266 { 267 struct display_target *param = (struct display_target *) data; 268 bfd *abfd; 269 size_t amt; 270 271 param->count += 1; 272 amt = param->count * sizeof (*param->info); 273 if (param->alloc < amt) 274 { 275 size_t size = ((param->count < 64 ? 64 : param->count) 276 * sizeof (*param->info) * 2); 277 param->info = xrealloc (param->info, size); 278 memset ((char *) param->info + param->alloc, 0, size - param->alloc); 279 param->alloc = size; 280 } 281 param->info[param->count - 1].name = targ->name; 282 283 printf (_("%s\n (header %s, data %s)\n"), targ->name, 284 endian_string (targ->header_byteorder), 285 endian_string (targ->byteorder)); 286 287 abfd = bfd_openw (param->filename, targ->name); 288 if (abfd == NULL) 289 { 290 bfd_nonfatal (param->filename); 291 param->error = 1; 292 } 293 else if (!bfd_set_format (abfd, bfd_object)) 294 { 295 if (bfd_get_error () != bfd_error_invalid_operation) 296 { 297 bfd_nonfatal (targ->name); 298 param->error = 1; 299 } 300 } 301 else 302 { 303 enum bfd_architecture a; 304 305 for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) 306 if (bfd_set_arch_mach (abfd, a, 0)) 307 { 308 printf (" %s\n", bfd_printable_arch_mach (a, 0)); 309 param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1; 310 } 311 } 312 if (abfd != NULL) 313 bfd_close_all_done (abfd); 314 315 return param->error; 316 } 317 318 static void 319 display_target_list (struct display_target *arg) 320 { 321 arg->filename = make_temp_file (NULL); 322 arg->error = 0; 323 arg->count = 0; 324 arg->alloc = 0; 325 arg->info = NULL; 326 327 bfd_iterate_over_targets (do_display_target, arg); 328 329 unlink (arg->filename); 330 free (arg->filename); 331 } 332 333 /* Calculate how many targets we can print across the page. */ 334 335 static int 336 do_info_size (int targ, int width, const struct display_target *arg) 337 { 338 while (targ < arg->count) 339 { 340 width -= strlen (arg->info[targ].name) + 1; 341 if (width < 0) 342 return targ; 343 ++targ; 344 } 345 return targ; 346 } 347 348 /* Print header of target names. */ 349 350 static void 351 do_info_header (int targ, int stop_targ, const struct display_target *arg) 352 { 353 while (targ != stop_targ) 354 printf ("%s ", arg->info[targ++].name); 355 } 356 357 /* Print a table row. */ 358 359 static void 360 do_info_row (int targ, int stop_targ, enum bfd_architecture a, 361 const struct display_target *arg) 362 { 363 while (targ != stop_targ) 364 { 365 if (arg->info[targ].arch[a - bfd_arch_obscure - 1]) 366 fputs (arg->info[targ].name, stdout); 367 else 368 { 369 int l = strlen (arg->info[targ].name); 370 while (l--) 371 putchar ('-'); 372 } 373 ++targ; 374 if (targ != stop_targ) 375 putchar (' '); 376 } 377 } 378 379 /* Print tables of all the target-architecture combinations that 380 BFD has been configured to support. */ 381 382 static void 383 display_target_tables (const struct display_target *arg) 384 { 385 const char *columns; 386 int width, start_targ, stop_targ; 387 enum bfd_architecture arch; 388 int longest_arch = 0; 389 390 for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++) 391 { 392 const char *s = bfd_printable_arch_mach (arch, 0); 393 int len = strlen (s); 394 if (len > longest_arch) 395 longest_arch = len; 396 } 397 398 width = 0; 399 columns = getenv ("COLUMNS"); 400 if (columns != NULL) 401 width = atoi (columns); 402 if (width == 0) 403 width = 80; 404 405 for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ) 406 { 407 stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg); 408 409 printf ("\n%*s", longest_arch + 1, " "); 410 do_info_header (start_targ, stop_targ, arg); 411 putchar ('\n'); 412 413 for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++) 414 { 415 if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0) 416 { 417 printf ("%*s ", longest_arch, 418 bfd_printable_arch_mach (arch, 0)); 419 420 do_info_row (start_targ, stop_targ, arch, arg); 421 putchar ('\n'); 422 } 423 } 424 } 425 } 426 427 int 428 display_info (void) 429 { 430 struct display_target arg; 431 432 printf (_("BFD header file version %s\n"), BFD_VERSION_STRING); 433 434 display_target_list (&arg); 435 if (!arg.error) 436 display_target_tables (&arg); 437 438 return arg.error; 439 } 440 441 /* Display the archive header for an element as if it were an ls -l listing: 442 443 Mode User\tGroup\tSize\tDate Name */ 444 445 void 446 print_arelt_descr (FILE *file, bfd *abfd, bool verbose, bool offsets) 447 { 448 struct stat buf; 449 450 if (verbose) 451 { 452 if (bfd_stat_arch_elt (abfd, &buf) == 0) 453 { 454 char modebuf[11]; 455 char timebuf[40]; 456 time_t when = buf.st_mtime; 457 const char *ctime_result = (const char *) ctime (&when); 458 bfd_size_type size; 459 460 /* PR binutils/17605: Check for corrupt time values. */ 461 if (ctime_result == NULL) 462 sprintf (timebuf, _("<time data corrupt>")); 463 else 464 /* POSIX format: skip weekday and seconds from ctime output. */ 465 sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); 466 467 mode_string (buf.st_mode, modebuf); 468 modebuf[10] = '\0'; 469 size = buf.st_size; 470 /* POSIX 1003.2/D11 says to skip first character (entry type). */ 471 fprintf (file, "%s %ld/%ld %6" BFD_VMA_FMT "u %s ", modebuf + 1, 472 (long) buf.st_uid, (long) buf.st_gid, 473 size, timebuf); 474 } 475 } 476 477 fprintf (file, "%s", bfd_get_filename (abfd)); 478 479 if (offsets) 480 { 481 if (bfd_is_thin_archive (abfd) && abfd->proxy_origin) 482 fprintf (file, " 0x%lx", (unsigned long) abfd->proxy_origin); 483 else if (!bfd_is_thin_archive (abfd) && abfd->origin) 484 fprintf (file, " 0x%lx", (unsigned long) abfd->origin); 485 } 486 487 fprintf (file, "\n"); 488 } 489 490 /* Return a path for a new temporary file in the same directory 491 as file PATH. */ 492 493 static char * 494 template_in_dir (const char *path) 495 { 496 #define template "stXXXXXX" 497 const char *slash = strrchr (path, '/'); 498 char *tmpname; 499 size_t len; 500 501 #ifdef HAVE_DOS_BASED_FILE_SYSTEM 502 { 503 /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ 504 char *bslash = strrchr (path, '\\'); 505 506 if (slash == NULL || (bslash != NULL && bslash > slash)) 507 slash = bslash; 508 if (slash == NULL && path[0] != '\0' && path[1] == ':') 509 slash = path + 1; 510 } 511 #endif 512 513 if (slash != (char *) NULL) 514 { 515 len = slash - path; 516 tmpname = (char *) xmalloc (len + sizeof (template) + 2); 517 memcpy (tmpname, path, len); 518 519 #ifdef HAVE_DOS_BASED_FILE_SYSTEM 520 /* If tmpname is "X:", appending a slash will make it a root 521 directory on drive X, which is NOT the same as the current 522 directory on drive X. */ 523 if (len == 2 && tmpname[1] == ':') 524 tmpname[len++] = '.'; 525 #endif 526 tmpname[len++] = '/'; 527 } 528 else 529 { 530 tmpname = (char *) xmalloc (sizeof (template)); 531 len = 0; 532 } 533 534 memcpy (tmpname + len, template, sizeof (template)); 535 return tmpname; 536 #undef template 537 } 538 539 /* Return the name of a created temporary file in the same directory 540 as FILENAME. */ 541 542 char * 543 make_tempname (const char *filename, int *ofd) 544 { 545 char *tmpname = template_in_dir (filename); 546 int fd; 547 548 #ifdef HAVE_MKSTEMP 549 fd = mkstemp (tmpname); 550 #else 551 tmpname = mktemp (tmpname); 552 if (tmpname == NULL) 553 fd = -1; 554 else 555 fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600); 556 #endif 557 if (fd == -1) 558 { 559 free (tmpname); 560 return NULL; 561 } 562 *ofd = fd; 563 return tmpname; 564 } 565 566 /* Return the name of a created temporary directory inside the 567 directory containing FILENAME. */ 568 569 char * 570 make_tempdir (const char *filename) 571 { 572 char *tmpname = template_in_dir (filename); 573 char *ret; 574 575 #ifdef HAVE_MKDTEMP 576 ret = mkdtemp (tmpname); 577 #else 578 ret = mktemp (tmpname); 579 #if defined (_WIN32) && !defined (__CYGWIN32__) 580 if (mkdir (tmpname) != 0) 581 ret = NULL; 582 #else 583 if (mkdir (tmpname, 0700) != 0) 584 ret = NULL; 585 #endif 586 #endif 587 if (ret == NULL) 588 free (tmpname); 589 return ret; 590 } 591 592 /* Parse a string into a VMA, with a fatal error if it can't be 593 parsed. */ 594 595 bfd_vma 596 parse_vma (const char *s, const char *arg) 597 { 598 bfd_vma ret; 599 const char *end; 600 601 ret = bfd_scan_vma (s, &end, 0); 602 603 if (*end != '\0') 604 fatal (_("%s: bad number: %s"), arg, s); 605 606 return ret; 607 } 608 609 /* Returns the size of the named file. If the file does not 610 exist, or if it is not a real file, then a suitable non-fatal 611 error message is printed and (off_t) -1 is returned. */ 612 613 off_t 614 get_file_size (const char * file_name) 615 { 616 struct stat statbuf; 617 618 if (file_name == NULL) 619 return (off_t) -1; 620 621 if (stat (file_name, &statbuf) < 0) 622 { 623 if (errno == ENOENT) 624 non_fatal (_("'%s': No such file"), file_name); 625 else 626 non_fatal (_("Warning: could not locate '%s'. reason: %s"), 627 file_name, strerror (errno)); 628 } 629 else if (S_ISDIR (statbuf.st_mode)) 630 non_fatal (_("Warning: '%s' is a directory"), file_name); 631 else if (! S_ISREG (statbuf.st_mode)) 632 { 633 if (!S_ISCHR(statbuf.st_mode)) 634 { 635 non_fatal (_("Warning: '%s' is not an ordinary file"), file_name); 636 return 0; 637 } 638 return statbuf.st_size ? statbuf.st_size : 1; 639 } 640 else if (statbuf.st_size < 0) 641 non_fatal (_("Warning: '%s' has negative size, probably it is too large"), 642 file_name); 643 #if defined (_WIN32) && !defined (__CYGWIN__) 644 else if (statbuf.st_size == 0) 645 { 646 /* MS-Windows 'stat' reports the null device as a regular file; 647 fix that. */ 648 int fd = open (file_name, O_RDONLY | O_BINARY); 649 if (isatty (fd)) 650 { 651 close (fd); 652 non_fatal (_("Warning: '%s' is not an ordinary file"), 653 /* libtool wants to see /dev/null in the output. */ 654 strcasecmp (file_name, "nul") ? file_name : "/dev/null"); 655 } 656 } 657 #endif 658 else 659 return statbuf.st_size; 660 661 return (off_t) -1; 662 } 663 664 /* Return the filename in a static buffer. */ 665 666 const char * 667 bfd_get_archive_filename (const bfd *abfd) 668 { 669 static size_t curr = 0; 670 static char *buf; 671 size_t needed; 672 673 assert (abfd != NULL); 674 675 if (abfd->my_archive == NULL 676 || bfd_is_thin_archive (abfd->my_archive)) 677 return bfd_get_filename (abfd); 678 679 needed = (strlen (bfd_get_filename (abfd->my_archive)) 680 + strlen (bfd_get_filename (abfd)) + 3); 681 if (needed > curr) 682 { 683 if (curr) 684 free (buf); 685 curr = needed + (needed >> 1); 686 buf = (char *) xmalloc (curr); 687 } 688 sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive), 689 bfd_get_filename (abfd)); 690 return buf; 691 } 692 693 /* Returns TRUE iff PATHNAME, a filename of an archive member, 694 is valid for writing. For security reasons absolute paths 695 and paths containing /../ are not allowed. See PR 17533. */ 696 697 bool 698 is_valid_archive_path (char const * pathname) 699 { 700 const char * n = pathname; 701 702 if (IS_ABSOLUTE_PATH (n)) 703 return false; 704 705 while (*n) 706 { 707 if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n))) 708 return false; 709 710 while (*n && ! IS_DIR_SEPARATOR (*n)) 711 n++; 712 while (IS_DIR_SEPARATOR (*n)) 713 n++; 714 } 715 716 return true; 717 } 718