1/* bucomm.c -- Bin Utils COMmon code. 2 Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003 3 Free Software Foundation, Inc. 4 5 This file is part of GNU Binutils. 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 2 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, write to the Free Software 19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 20 02110-1301, USA. */ 21 22/* We might put this in a library someday so it could be dynamically 23 loaded, but for now it's not necessary. */ 24 25#include "bfd.h" 26#include "bfdver.h" 27#include "libiberty.h" 28#include "bucomm.h" 29#include "filenames.h" 30#include "libbfd.h" 31 32#include <sys/stat.h> 33#include <time.h> /* ctime, maybe time_t */ 34#include <assert.h> 35 36#ifndef HAVE_TIME_T_IN_TIME_H 37#ifndef HAVE_TIME_T_IN_TYPES_H 38typedef long time_t; 39#endif 40#endif 41 42static const char * endian_string (enum bfd_endian); 43static int display_target_list (void); 44static int display_info_table (int, int); 45static int display_target_tables (void); 46 47/* Error reporting. */ 48 49char *program_name; 50 51void 52bfd_nonfatal (const char *string) 53{ 54 const char *errmsg = bfd_errmsg (bfd_get_error ()); 55 56 if (string) 57 fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); 58 else 59 fprintf (stderr, "%s: %s\n", program_name, errmsg); 60} 61 62void 63bfd_fatal (const char *string) 64{ 65 bfd_nonfatal (string); 66 xexit (1); 67} 68 69void 70report (const char * format, va_list args) 71{ 72 fprintf (stderr, "%s: ", program_name); 73 vfprintf (stderr, format, args); 74 putc ('\n', stderr); 75} 76 77void 78fatal VPARAMS ((const char *format, ...)) 79{ 80 VA_OPEN (args, format); 81 VA_FIXEDARG (args, const char *, format); 82 83 report (format, args); 84 VA_CLOSE (args); 85 xexit (1); 86} 87 88void 89non_fatal VPARAMS ((const char *format, ...)) 90{ 91 VA_OPEN (args, format); 92 VA_FIXEDARG (args, const char *, format); 93 94 report (format, args); 95 VA_CLOSE (args); 96} 97 98/* Set the default BFD target based on the configured target. Doing 99 this permits the binutils to be configured for a particular target, 100 and linked against a shared BFD library which was configured for a 101 different target. */ 102 103void 104set_default_bfd_target (void) 105{ 106 /* The macro TARGET is defined by Makefile. */ 107 const char *target = TARGET; 108 109 if (! bfd_set_default_target (target)) 110 fatal (_("can't set BFD default target to `%s': %s"), 111 target, bfd_errmsg (bfd_get_error ())); 112} 113 114/* After a FALSE return from bfd_check_format_matches with 115 bfd_get_error () == bfd_error_file_ambiguously_recognized, print 116 the possible matching targets. */ 117 118void 119list_matching_formats (char **p) 120{ 121 fprintf (stderr, _("%s: Matching formats:"), program_name); 122 while (*p) 123 fprintf (stderr, " %s", *p++); 124 fputc ('\n', stderr); 125} 126 127/* List the supported targets. */ 128 129void 130list_supported_targets (const char *name, FILE *f) 131{ 132 int t; 133 const char **targ_names = bfd_target_list (); 134 135 if (name == NULL) 136 fprintf (f, _("Supported targets:")); 137 else 138 fprintf (f, _("%s: supported targets:"), name); 139 140 for (t = 0; targ_names[t] != NULL; t++) 141 fprintf (f, " %s", targ_names[t]); 142 fprintf (f, "\n"); 143 free (targ_names); 144} 145 146/* List the supported architectures. */ 147 148void 149list_supported_architectures (const char *name, FILE *f) 150{ 151 const char **arch; 152 153 if (name == NULL) 154 fprintf (f, _("Supported architectures:")); 155 else 156 fprintf (f, _("%s: supported architectures:"), name); 157 158 for (arch = bfd_arch_list (); *arch; arch++) 159 fprintf (f, " %s", *arch); 160 fprintf (f, "\n"); 161} 162 163/* The length of the longest architecture name + 1. */ 164#define LONGEST_ARCH sizeof ("powerpc:common") 165 166static const char * 167endian_string (enum bfd_endian endian) 168{ 169 switch (endian) 170 { 171 case BFD_ENDIAN_BIG: return "big endian"; 172 case BFD_ENDIAN_LITTLE: return "little endian"; 173 default: return "endianness unknown"; 174 } 175} 176 177/* List the targets that BFD is configured to support, each followed 178 by its endianness and the architectures it supports. */ 179 180static int 181display_target_list (void) 182{ 183 char *dummy_name; 184 int t; 185 int ret = 1; 186 187 dummy_name = make_temp_file (NULL); 188 for (t = 0; bfd_target_vector[t]; t++) 189 { 190 const bfd_target *p = bfd_target_vector[t]; 191 bfd *abfd = bfd_openw (dummy_name, p->name); 192 enum bfd_architecture a; 193 194 printf ("%s\n (header %s, data %s)\n", p->name, 195 endian_string (p->header_byteorder), 196 endian_string (p->byteorder)); 197 198 if (abfd == NULL) 199 { 200 bfd_nonfatal (dummy_name); 201 ret = 0; 202 continue; 203 } 204 205 if (! bfd_set_format (abfd, bfd_object)) 206 { 207 if (bfd_get_error () != bfd_error_invalid_operation) 208 { 209 bfd_nonfatal (p->name); 210 ret = 0; 211 } 212 bfd_close_all_done (abfd); 213 continue; 214 } 215 216 for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) 217 if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0)) 218 printf (" %s\n", 219 bfd_printable_arch_mach ((enum bfd_architecture) a, 0)); 220 bfd_close_all_done (abfd); 221 } 222 unlink (dummy_name); 223 free (dummy_name); 224 225 return ret; 226} 227 228/* Print a table showing which architectures are supported for entries 229 FIRST through LAST-1 of bfd_target_vector (targets across, 230 architectures down). */ 231 232static int 233display_info_table (int first, int last) 234{ 235 int t; 236 int ret = 1; 237 char *dummy_name; 238 enum bfd_architecture a; 239 240 /* Print heading of target names. */ 241 printf ("\n%*s", (int) LONGEST_ARCH, " "); 242 for (t = first; t < last && bfd_target_vector[t]; t++) 243 printf ("%s ", bfd_target_vector[t]->name); 244 putchar ('\n'); 245 246 dummy_name = make_temp_file (NULL); 247 for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) 248 if (strcmp (bfd_printable_arch_mach (a, 0), "UNKNOWN!") != 0) 249 { 250 printf ("%*s ", (int) LONGEST_ARCH - 1, 251 bfd_printable_arch_mach (a, 0)); 252 for (t = first; t < last && bfd_target_vector[t]; t++) 253 { 254 const bfd_target *p = bfd_target_vector[t]; 255 bfd_boolean ok = TRUE; 256 bfd *abfd = bfd_openw (dummy_name, p->name); 257 258 if (abfd == NULL) 259 { 260 bfd_nonfatal (p->name); 261 ret = 0; 262 ok = FALSE; 263 } 264 265 if (ok) 266 { 267 if (! bfd_set_format (abfd, bfd_object)) 268 { 269 if (bfd_get_error () != bfd_error_invalid_operation) 270 { 271 bfd_nonfatal (p->name); 272 ret = 0; 273 } 274 ok = FALSE; 275 } 276 } 277 278 if (ok) 279 { 280 if (! bfd_set_arch_mach (abfd, a, 0)) 281 ok = FALSE; 282 } 283 284 if (ok) 285 printf ("%s ", p->name); 286 else 287 { 288 int l = strlen (p->name); 289 while (l--) 290 putchar ('-'); 291 putchar (' '); 292 } 293 if (abfd != NULL) 294 bfd_close_all_done (abfd); 295 } 296 putchar ('\n'); 297 } 298 unlink (dummy_name); 299 free (dummy_name); 300 301 return ret; 302} 303 304/* Print tables of all the target-architecture combinations that 305 BFD has been configured to support. */ 306 307static int 308display_target_tables (void) 309{ 310 int t; 311 int columns; 312 int ret = 1; 313 char *colum; 314 315 columns = 0; 316 colum = getenv ("COLUMNS"); 317 if (colum != NULL) 318 columns = atoi (colum); 319 if (columns == 0) 320 columns = 80; 321 322 t = 0; 323 while (bfd_target_vector[t] != NULL) 324 { 325 int oldt = t, wid; 326 327 wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1; 328 ++t; 329 while (wid < columns && bfd_target_vector[t] != NULL) 330 { 331 int newwid; 332 333 newwid = wid + strlen (bfd_target_vector[t]->name) + 1; 334 if (newwid >= columns) 335 break; 336 wid = newwid; 337 ++t; 338 } 339 if (! display_info_table (oldt, t)) 340 ret = 0; 341 } 342 343 return ret; 344} 345 346int 347display_info (void) 348{ 349 printf (_("BFD header file version %s\n"), BFD_VERSION_STRING); 350 if (! display_target_list () || ! display_target_tables ()) 351 return 1; 352 else 353 return 0; 354} 355 356/* Display the archive header for an element as if it were an ls -l listing: 357 358 Mode User\tGroup\tSize\tDate Name */ 359 360void 361print_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose) 362{ 363 struct stat buf; 364 365 if (verbose) 366 { 367 if (bfd_stat_arch_elt (abfd, &buf) == 0) 368 { 369 char modebuf[11]; 370 char timebuf[40]; 371 time_t when = buf.st_mtime; 372 const char *ctime_result = (const char *) ctime (&when); 373 374 /* POSIX format: skip weekday and seconds from ctime output. */ 375 sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); 376 377 mode_string (buf.st_mode, modebuf); 378 modebuf[10] = '\0'; 379 /* POSIX 1003.2/D11 says to skip first character (entry type). */ 380 fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1, 381 (long) buf.st_uid, (long) buf.st_gid, 382 (long) buf.st_size, timebuf); 383 } 384 } 385 386 fprintf (file, "%s\n", bfd_get_filename (abfd)); 387} 388 389/* Return the name of a temporary file in the same directory as FILENAME. */ 390 391char * 392make_tempname (char *filename) 393{ 394 static char template[] = "stXXXXXX"; 395 char *tmpname; 396 char *slash = strrchr (filename, '/'); 397 398#ifdef HAVE_DOS_BASED_FILE_SYSTEM 399 { 400 /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ 401 char *bslash = strrchr (filename, '\\'); 402 if (slash == NULL || (bslash != NULL && bslash > slash)) 403 slash = bslash; 404 if (slash == NULL && filename[0] != '\0' && filename[1] == ':') 405 slash = filename + 1; 406 } 407#endif 408 409 if (slash != (char *) NULL) 410 { 411 char c; 412 413 c = *slash; 414 *slash = 0; 415 tmpname = xmalloc (strlen (filename) + sizeof (template) + 2); 416 strcpy (tmpname, filename); 417#ifdef HAVE_DOS_BASED_FILE_SYSTEM 418 /* If tmpname is "X:", appending a slash will make it a root 419 directory on drive X, which is NOT the same as the current 420 directory on drive X. */ 421 if (tmpname[1] == ':' && tmpname[2] == '\0') 422 strcat (tmpname, "."); 423#endif 424 strcat (tmpname, "/"); 425 strcat (tmpname, template); 426 mktemp (tmpname); 427 *slash = c; 428 } 429 else 430 { 431 tmpname = xmalloc (sizeof (template)); 432 strcpy (tmpname, template); 433 mktemp (tmpname); 434 } 435 return tmpname; 436} 437 438/* Parse a string into a VMA, with a fatal error if it can't be 439 parsed. */ 440 441bfd_vma 442parse_vma (const char *s, const char *arg) 443{ 444 bfd_vma ret; 445 const char *end; 446 447 ret = bfd_scan_vma (s, &end, 0); 448 449 if (*end != '\0') 450 fatal (_("%s: bad number: %s"), arg, s); 451 452 return ret; 453} 454 455/* Returns the size of the named file. If the file does not 456 exist, or if it is not a real file, then a suitable non-fatal 457 error message is printed and zero is returned. */ 458 459off_t 460get_file_size (const char * file_name) 461{ 462 struct stat statbuf; 463 464 if (stat (file_name, &statbuf) < 0) 465 { 466 if (errno == ENOENT) 467 non_fatal (_("'%s': No such file"), file_name); 468 else 469 non_fatal (_("Warning: could not locate '%s'. reason: %s"), 470 file_name, strerror (errno)); 471 } 472 else if (! S_ISREG (statbuf.st_mode)) 473 non_fatal (_("Warning: '%s' is not an ordinary file"), file_name); 474 else 475 return statbuf.st_size; 476 477 return 0; 478} 479 480/* Return the filename in a static buffer. */ 481 482const char * 483bfd_get_archive_filename (bfd *abfd) 484{ 485 static size_t curr = 0; 486 static char *buf; 487 size_t needed; 488 489 assert (abfd != NULL); 490 491 if (!abfd->my_archive) 492 return bfd_get_filename (abfd); 493 494 needed = (strlen (bfd_get_filename (abfd->my_archive)) 495 + strlen (bfd_get_filename (abfd)) + 3); 496 if (needed > curr) 497 { 498 if (curr) 499 free (buf); 500 curr = needed + (needed >> 1); 501 buf = bfd_malloc (curr); 502 /* If we can't malloc, fail safe by returning just the file name. 503 This function is only used when building error messages. */ 504 if (!buf) 505 { 506 curr = 0; 507 return bfd_get_filename (abfd); 508 } 509 } 510 sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive), 511 bfd_get_filename (abfd)); 512 return buf; 513} 514