133965Sjdp/* bucomm.c -- Bin Utils COMmon code. 2218822Sdim Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 3218822Sdim 2003, 2006, 2007 460484Sobrien Free Software Foundation, Inc. 533965Sjdp 633965Sjdp This file is part of GNU Binutils. 733965Sjdp 833965Sjdp This program is free software; you can redistribute it and/or modify 933965Sjdp it under the terms of the GNU General Public License as published by 1033965Sjdp the Free Software Foundation; either version 2 of the License, or 1133965Sjdp (at your option) any later version. 1233965Sjdp 1333965Sjdp This program is distributed in the hope that it will be useful, 1433965Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1533965Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1633965Sjdp GNU General Public License for more details. 1733965Sjdp 1833965Sjdp You should have received a copy of the GNU General Public License 1933965Sjdp along with this program; if not, write to the Free Software 20218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 21218822Sdim 02110-1301, USA. */ 2233965Sjdp 2333965Sjdp/* We might put this in a library someday so it could be dynamically 2433965Sjdp loaded, but for now it's not necessary. */ 2533965Sjdp 26218822Sdim#include "sysdep.h" 2733965Sjdp#include "bfd.h" 2833965Sjdp#include "libiberty.h" 2961843Sobrien#include "filenames.h" 30130561Sobrien#include "libbfd.h" 3133965Sjdp 3233965Sjdp#include <sys/stat.h> 3333965Sjdp#include <time.h> /* ctime, maybe time_t */ 34218822Sdim#include <assert.h> 35218822Sdim#include "bucomm.h" 3633965Sjdp 3733965Sjdp#ifndef HAVE_TIME_T_IN_TIME_H 3833965Sjdp#ifndef HAVE_TIME_T_IN_TYPES_H 3933965Sjdptypedef long time_t; 4033965Sjdp#endif 4133965Sjdp#endif 42130561Sobrien 43130561Sobrienstatic const char * endian_string (enum bfd_endian); 44130561Sobrienstatic int display_target_list (void); 45130561Sobrienstatic int display_info_table (int, int); 46130561Sobrienstatic int display_target_tables (void); 4733965Sjdp 48130561Sobrien/* Error reporting. */ 4933965Sjdp 5033965Sjdpchar *program_name; 5133965Sjdp 5233965Sjdpvoid 53130561Sobrienbfd_nonfatal (const char *string) 5433965Sjdp{ 55104834Sobrien const char *errmsg = bfd_errmsg (bfd_get_error ()); 5633965Sjdp 5733965Sjdp if (string) 5833965Sjdp fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); 5933965Sjdp else 6033965Sjdp fprintf (stderr, "%s: %s\n", program_name, errmsg); 6133965Sjdp} 6233965Sjdp 6333965Sjdpvoid 64130561Sobrienbfd_fatal (const char *string) 6533965Sjdp{ 6633965Sjdp bfd_nonfatal (string); 6733965Sjdp xexit (1); 6833965Sjdp} 6933965Sjdp 7060484Sobrienvoid 71130561Sobrienreport (const char * format, va_list args) 7260484Sobrien{ 7360484Sobrien fprintf (stderr, "%s: ", program_name); 7460484Sobrien vfprintf (stderr, format, args); 7560484Sobrien putc ('\n', stderr); 7660484Sobrien} 7760484Sobrien 7833965Sjdpvoid 7989857Sobrienfatal VPARAMS ((const char *format, ...)) 8033965Sjdp{ 8189857Sobrien VA_OPEN (args, format); 8289857Sobrien VA_FIXEDARG (args, const char *, format); 8333965Sjdp 8460484Sobrien report (format, args); 8589857Sobrien VA_CLOSE (args); 8633965Sjdp xexit (1); 8733965Sjdp} 8860484Sobrien 8960484Sobrienvoid 9089857Sobriennon_fatal VPARAMS ((const char *format, ...)) 9160484Sobrien{ 9289857Sobrien VA_OPEN (args, format); 9389857Sobrien VA_FIXEDARG (args, const char *, format); 9460484Sobrien 9560484Sobrien report (format, args); 9689857Sobrien VA_CLOSE (args); 9760484Sobrien} 9833965Sjdp 9933965Sjdp/* Set the default BFD target based on the configured target. Doing 10033965Sjdp this permits the binutils to be configured for a particular target, 10133965Sjdp and linked against a shared BFD library which was configured for a 10233965Sjdp different target. */ 10333965Sjdp 10433965Sjdpvoid 105130561Sobrienset_default_bfd_target (void) 10633965Sjdp{ 10733965Sjdp /* The macro TARGET is defined by Makefile. */ 10833965Sjdp const char *target = TARGET; 10933965Sjdp 11033965Sjdp if (! bfd_set_default_target (target)) 11160484Sobrien fatal (_("can't set BFD default target to `%s': %s"), 11260484Sobrien target, bfd_errmsg (bfd_get_error ())); 11333965Sjdp} 11433965Sjdp 115130561Sobrien/* After a FALSE return from bfd_check_format_matches with 11633965Sjdp bfd_get_error () == bfd_error_file_ambiguously_recognized, print 11733965Sjdp the possible matching targets. */ 11833965Sjdp 11933965Sjdpvoid 120130561Sobrienlist_matching_formats (char **p) 12133965Sjdp{ 12260484Sobrien fprintf (stderr, _("%s: Matching formats:"), program_name); 12333965Sjdp while (*p) 12460484Sobrien fprintf (stderr, " %s", *p++); 12560484Sobrien fputc ('\n', stderr); 12633965Sjdp} 12733965Sjdp 12833965Sjdp/* List the supported targets. */ 12933965Sjdp 13033965Sjdpvoid 131130561Sobrienlist_supported_targets (const char *name, FILE *f) 13233965Sjdp{ 13333965Sjdp int t; 134107492Sobrien const char **targ_names = bfd_target_list (); 13533965Sjdp 13633965Sjdp if (name == NULL) 13760484Sobrien fprintf (f, _("Supported targets:")); 13833965Sjdp else 13960484Sobrien fprintf (f, _("%s: supported targets:"), name); 140107492Sobrien 141107492Sobrien for (t = 0; targ_names[t] != NULL; t++) 142107492Sobrien fprintf (f, " %s", targ_names[t]); 14333965Sjdp fprintf (f, "\n"); 144107492Sobrien free (targ_names); 14533965Sjdp} 14689857Sobrien 14789857Sobrien/* List the supported architectures. */ 14889857Sobrien 14989857Sobrienvoid 150130561Sobrienlist_supported_architectures (const char *name, FILE *f) 15189857Sobrien{ 152130561Sobrien const char **arch; 15389857Sobrien 15489857Sobrien if (name == NULL) 15589857Sobrien fprintf (f, _("Supported architectures:")); 15689857Sobrien else 15789857Sobrien fprintf (f, _("%s: supported architectures:"), name); 15889857Sobrien 15989857Sobrien for (arch = bfd_arch_list (); *arch; arch++) 16089857Sobrien fprintf (f, " %s", *arch); 16189857Sobrien fprintf (f, "\n"); 16289857Sobrien} 16333965Sjdp 164130561Sobrien/* The length of the longest architecture name + 1. */ 165130561Sobrien#define LONGEST_ARCH sizeof ("powerpc:common") 166130561Sobrien 167130561Sobrienstatic const char * 168130561Sobrienendian_string (enum bfd_endian endian) 169130561Sobrien{ 170130561Sobrien switch (endian) 171130561Sobrien { 172130561Sobrien case BFD_ENDIAN_BIG: return "big endian"; 173130561Sobrien case BFD_ENDIAN_LITTLE: return "little endian"; 174130561Sobrien default: return "endianness unknown"; 175130561Sobrien } 176130561Sobrien} 177130561Sobrien 178130561Sobrien/* List the targets that BFD is configured to support, each followed 179130561Sobrien by its endianness and the architectures it supports. */ 180130561Sobrien 181130561Sobrienstatic int 182130561Sobriendisplay_target_list (void) 183130561Sobrien{ 184130561Sobrien char *dummy_name; 185130561Sobrien int t; 186130561Sobrien int ret = 1; 187130561Sobrien 188130561Sobrien dummy_name = make_temp_file (NULL); 189130561Sobrien for (t = 0; bfd_target_vector[t]; t++) 190130561Sobrien { 191130561Sobrien const bfd_target *p = bfd_target_vector[t]; 192130561Sobrien bfd *abfd = bfd_openw (dummy_name, p->name); 193218822Sdim enum bfd_architecture a; 194130561Sobrien 195130561Sobrien printf ("%s\n (header %s, data %s)\n", p->name, 196130561Sobrien endian_string (p->header_byteorder), 197130561Sobrien endian_string (p->byteorder)); 198130561Sobrien 199130561Sobrien if (abfd == NULL) 200130561Sobrien { 201130561Sobrien bfd_nonfatal (dummy_name); 202130561Sobrien ret = 0; 203130561Sobrien continue; 204130561Sobrien } 205130561Sobrien 206130561Sobrien if (! bfd_set_format (abfd, bfd_object)) 207130561Sobrien { 208130561Sobrien if (bfd_get_error () != bfd_error_invalid_operation) 209130561Sobrien { 210130561Sobrien bfd_nonfatal (p->name); 211130561Sobrien ret = 0; 212130561Sobrien } 213130561Sobrien bfd_close_all_done (abfd); 214130561Sobrien continue; 215130561Sobrien } 216130561Sobrien 217218822Sdim for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) 218130561Sobrien if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0)) 219130561Sobrien printf (" %s\n", 220130561Sobrien bfd_printable_arch_mach ((enum bfd_architecture) a, 0)); 221130561Sobrien bfd_close_all_done (abfd); 222130561Sobrien } 223130561Sobrien unlink (dummy_name); 224130561Sobrien free (dummy_name); 225130561Sobrien 226130561Sobrien return ret; 227130561Sobrien} 228130561Sobrien 229130561Sobrien/* Print a table showing which architectures are supported for entries 230130561Sobrien FIRST through LAST-1 of bfd_target_vector (targets across, 231130561Sobrien architectures down). */ 232130561Sobrien 233130561Sobrienstatic int 234130561Sobriendisplay_info_table (int first, int last) 235130561Sobrien{ 236130561Sobrien int t; 237130561Sobrien int ret = 1; 238130561Sobrien char *dummy_name; 239218822Sdim enum bfd_architecture a; 240130561Sobrien 241130561Sobrien /* Print heading of target names. */ 242130561Sobrien printf ("\n%*s", (int) LONGEST_ARCH, " "); 243130561Sobrien for (t = first; t < last && bfd_target_vector[t]; t++) 244130561Sobrien printf ("%s ", bfd_target_vector[t]->name); 245130561Sobrien putchar ('\n'); 246130561Sobrien 247130561Sobrien dummy_name = make_temp_file (NULL); 248218822Sdim for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) 249130561Sobrien if (strcmp (bfd_printable_arch_mach (a, 0), "UNKNOWN!") != 0) 250130561Sobrien { 251130561Sobrien printf ("%*s ", (int) LONGEST_ARCH - 1, 252130561Sobrien bfd_printable_arch_mach (a, 0)); 253130561Sobrien for (t = first; t < last && bfd_target_vector[t]; t++) 254130561Sobrien { 255130561Sobrien const bfd_target *p = bfd_target_vector[t]; 256130561Sobrien bfd_boolean ok = TRUE; 257130561Sobrien bfd *abfd = bfd_openw (dummy_name, p->name); 258130561Sobrien 259130561Sobrien if (abfd == NULL) 260130561Sobrien { 261130561Sobrien bfd_nonfatal (p->name); 262130561Sobrien ret = 0; 263130561Sobrien ok = FALSE; 264130561Sobrien } 265130561Sobrien 266130561Sobrien if (ok) 267130561Sobrien { 268130561Sobrien if (! bfd_set_format (abfd, bfd_object)) 269130561Sobrien { 270130561Sobrien if (bfd_get_error () != bfd_error_invalid_operation) 271130561Sobrien { 272130561Sobrien bfd_nonfatal (p->name); 273130561Sobrien ret = 0; 274130561Sobrien } 275130561Sobrien ok = FALSE; 276130561Sobrien } 277130561Sobrien } 278130561Sobrien 279130561Sobrien if (ok) 280130561Sobrien { 281130561Sobrien if (! bfd_set_arch_mach (abfd, a, 0)) 282130561Sobrien ok = FALSE; 283130561Sobrien } 284130561Sobrien 285130561Sobrien if (ok) 286130561Sobrien printf ("%s ", p->name); 287130561Sobrien else 288130561Sobrien { 289130561Sobrien int l = strlen (p->name); 290130561Sobrien while (l--) 291130561Sobrien putchar ('-'); 292130561Sobrien putchar (' '); 293130561Sobrien } 294130561Sobrien if (abfd != NULL) 295130561Sobrien bfd_close_all_done (abfd); 296130561Sobrien } 297130561Sobrien putchar ('\n'); 298130561Sobrien } 299130561Sobrien unlink (dummy_name); 300130561Sobrien free (dummy_name); 301130561Sobrien 302130561Sobrien return ret; 303130561Sobrien} 304130561Sobrien 305130561Sobrien/* Print tables of all the target-architecture combinations that 306130561Sobrien BFD has been configured to support. */ 307130561Sobrien 308130561Sobrienstatic int 309130561Sobriendisplay_target_tables (void) 310130561Sobrien{ 311130561Sobrien int t; 312130561Sobrien int columns; 313130561Sobrien int ret = 1; 314130561Sobrien char *colum; 315130561Sobrien 316130561Sobrien columns = 0; 317130561Sobrien colum = getenv ("COLUMNS"); 318130561Sobrien if (colum != NULL) 319130561Sobrien columns = atoi (colum); 320130561Sobrien if (columns == 0) 321130561Sobrien columns = 80; 322130561Sobrien 323130561Sobrien t = 0; 324130561Sobrien while (bfd_target_vector[t] != NULL) 325130561Sobrien { 326130561Sobrien int oldt = t, wid; 327130561Sobrien 328130561Sobrien wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1; 329130561Sobrien ++t; 330130561Sobrien while (wid < columns && bfd_target_vector[t] != NULL) 331130561Sobrien { 332130561Sobrien int newwid; 333130561Sobrien 334130561Sobrien newwid = wid + strlen (bfd_target_vector[t]->name) + 1; 335130561Sobrien if (newwid >= columns) 336130561Sobrien break; 337130561Sobrien wid = newwid; 338130561Sobrien ++t; 339130561Sobrien } 340130561Sobrien if (! display_info_table (oldt, t)) 341130561Sobrien ret = 0; 342130561Sobrien } 343130561Sobrien 344130561Sobrien return ret; 345130561Sobrien} 346130561Sobrien 347130561Sobrienint 348130561Sobriendisplay_info (void) 349130561Sobrien{ 350130561Sobrien printf (_("BFD header file version %s\n"), BFD_VERSION_STRING); 351130561Sobrien if (! display_target_list () || ! display_target_tables ()) 352130561Sobrien return 1; 353130561Sobrien else 354130561Sobrien return 0; 355130561Sobrien} 356130561Sobrien 35733965Sjdp/* Display the archive header for an element as if it were an ls -l listing: 35833965Sjdp 35933965Sjdp Mode User\tGroup\tSize\tDate Name */ 36033965Sjdp 36133965Sjdpvoid 362130561Sobrienprint_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose) 36333965Sjdp{ 36433965Sjdp struct stat buf; 36533965Sjdp 36633965Sjdp if (verbose) 36733965Sjdp { 36833965Sjdp if (bfd_stat_arch_elt (abfd, &buf) == 0) 36933965Sjdp { 37033965Sjdp char modebuf[11]; 37133965Sjdp char timebuf[40]; 37233965Sjdp time_t when = buf.st_mtime; 373104834Sobrien const char *ctime_result = (const char *) ctime (&when); 37433965Sjdp 37533965Sjdp /* POSIX format: skip weekday and seconds from ctime output. */ 37633965Sjdp sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); 37733965Sjdp 37833965Sjdp mode_string (buf.st_mode, modebuf); 37933965Sjdp modebuf[10] = '\0'; 38033965Sjdp /* POSIX 1003.2/D11 says to skip first character (entry type). */ 38133965Sjdp fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1, 38233965Sjdp (long) buf.st_uid, (long) buf.st_gid, 38333965Sjdp (long) buf.st_size, timebuf); 38433965Sjdp } 38533965Sjdp } 38633965Sjdp 38733965Sjdp fprintf (file, "%s\n", bfd_get_filename (abfd)); 38833965Sjdp} 38933965Sjdp 390218822Sdim/* Return a path for a new temporary file in the same directory 391218822Sdim as file PATH. */ 39233965Sjdp 393218822Sdimstatic char * 394218822Sdimtemplate_in_dir (const char *path) 39533965Sjdp{ 396218822Sdim#define template "stXXXXXX" 397218822Sdim const char *slash = strrchr (path, '/'); 39833965Sjdp char *tmpname; 399218822Sdim size_t len; 40033965Sjdp 40161843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM 40261843Sobrien { 40361843Sobrien /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ 404218822Sdim char *bslash = strrchr (path, '\\'); 405218822Sdim 40677298Sobrien if (slash == NULL || (bslash != NULL && bslash > slash)) 40761843Sobrien slash = bslash; 408218822Sdim if (slash == NULL && path[0] != '\0' && path[1] == ':') 409218822Sdim slash = path + 1; 41061843Sobrien } 41138889Sjdp#endif 41238889Sjdp 41333965Sjdp if (slash != (char *) NULL) 41433965Sjdp { 415218822Sdim len = slash - path; 416218822Sdim tmpname = xmalloc (len + sizeof (template) + 2); 417218822Sdim memcpy (tmpname, path, len); 41838889Sjdp 41961843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM 42061843Sobrien /* If tmpname is "X:", appending a slash will make it a root 42161843Sobrien directory on drive X, which is NOT the same as the current 42261843Sobrien directory on drive X. */ 423218822Sdim if (len == 2 && tmpname[1] == ':') 424218822Sdim tmpname[len++] = '.'; 42561843Sobrien#endif 426218822Sdim tmpname[len++] = '/'; 42733965Sjdp } 42833965Sjdp else 42933965Sjdp { 43033965Sjdp tmpname = xmalloc (sizeof (template)); 431218822Sdim len = 0; 43233965Sjdp } 433218822Sdim 434218822Sdim memcpy (tmpname + len, template, sizeof (template)); 43533965Sjdp return tmpname; 436218822Sdim#undef template 43733965Sjdp} 43833965Sjdp 439218822Sdim/* Return the name of a created temporary file in the same directory 440218822Sdim as FILENAME. */ 441218822Sdim 442218822Sdimchar * 443218822Sdimmake_tempname (char *filename) 444218822Sdim{ 445218822Sdim char *tmpname = template_in_dir (filename); 446218822Sdim int fd; 447218822Sdim 448218822Sdim#ifdef HAVE_MKSTEMP 449218822Sdim fd = mkstemp (tmpname); 450218822Sdim#else 451218822Sdim tmpname = mktemp (tmpname); 452218822Sdim if (tmpname == NULL) 453218822Sdim return NULL; 454218822Sdim fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600); 455218822Sdim#endif 456218822Sdim if (fd == -1) 457218822Sdim return NULL; 458218822Sdim close (fd); 459218822Sdim return tmpname; 460218822Sdim} 461218822Sdim 462218822Sdim/* Return the name of a created temporary directory inside the 463218822Sdim directory containing FILENAME. */ 464218822Sdim 465218822Sdimchar * 466218822Sdimmake_tempdir (char *filename) 467218822Sdim{ 468218822Sdim char *tmpname = template_in_dir (filename); 469218822Sdim 470218822Sdim#ifdef HAVE_MKDTEMP 471218822Sdim return mkdtemp (tmpname); 472218822Sdim#else 473218822Sdim tmpname = mktemp (tmpname); 474218822Sdim if (tmpname == NULL) 475218822Sdim return NULL; 476218822Sdim#if defined (_WIN32) && !defined (__CYGWIN32__) 477218822Sdim if (mkdir (tmpname) != 0) 478218822Sdim return NULL; 479218822Sdim#else 480218822Sdim if (mkdir (tmpname, 0700) != 0) 481218822Sdim return NULL; 482218822Sdim#endif 483218822Sdim return tmpname; 484218822Sdim#endif 485218822Sdim} 486218822Sdim 48733965Sjdp/* Parse a string into a VMA, with a fatal error if it can't be 48833965Sjdp parsed. */ 48933965Sjdp 49033965Sjdpbfd_vma 491130561Sobrienparse_vma (const char *s, const char *arg) 49233965Sjdp{ 49333965Sjdp bfd_vma ret; 49433965Sjdp const char *end; 49533965Sjdp 49633965Sjdp ret = bfd_scan_vma (s, &end, 0); 497104834Sobrien 49833965Sjdp if (*end != '\0') 49960484Sobrien fatal (_("%s: bad number: %s"), arg, s); 50060484Sobrien 50133965Sjdp return ret; 50233965Sjdp} 503130561Sobrien 504130561Sobrien/* Returns the size of the named file. If the file does not 505130561Sobrien exist, or if it is not a real file, then a suitable non-fatal 506130561Sobrien error message is printed and zero is returned. */ 507130561Sobrien 508130561Sobrienoff_t 509130561Sobrienget_file_size (const char * file_name) 510130561Sobrien{ 511130561Sobrien struct stat statbuf; 512130561Sobrien 513130561Sobrien if (stat (file_name, &statbuf) < 0) 514130561Sobrien { 515130561Sobrien if (errno == ENOENT) 516130561Sobrien non_fatal (_("'%s': No such file"), file_name); 517130561Sobrien else 518130561Sobrien non_fatal (_("Warning: could not locate '%s'. reason: %s"), 519130561Sobrien file_name, strerror (errno)); 520130561Sobrien } 521130561Sobrien else if (! S_ISREG (statbuf.st_mode)) 522130561Sobrien non_fatal (_("Warning: '%s' is not an ordinary file"), file_name); 523130561Sobrien else 524130561Sobrien return statbuf.st_size; 525130561Sobrien 526130561Sobrien return 0; 527130561Sobrien} 528218822Sdim 529218822Sdim/* Return the filename in a static buffer. */ 530218822Sdim 531218822Sdimconst char * 532218822Sdimbfd_get_archive_filename (bfd *abfd) 533218822Sdim{ 534218822Sdim static size_t curr = 0; 535218822Sdim static char *buf; 536218822Sdim size_t needed; 537218822Sdim 538218822Sdim assert (abfd != NULL); 539218822Sdim 540218822Sdim if (!abfd->my_archive) 541218822Sdim return bfd_get_filename (abfd); 542218822Sdim 543218822Sdim needed = (strlen (bfd_get_filename (abfd->my_archive)) 544218822Sdim + strlen (bfd_get_filename (abfd)) + 3); 545218822Sdim if (needed > curr) 546218822Sdim { 547218822Sdim if (curr) 548218822Sdim free (buf); 549218822Sdim curr = needed + (needed >> 1); 550218822Sdim buf = bfd_malloc (curr); 551218822Sdim /* If we can't malloc, fail safe by returning just the file name. 552218822Sdim This function is only used when building error messages. */ 553218822Sdim if (!buf) 554218822Sdim { 555218822Sdim curr = 0; 556218822Sdim return bfd_get_filename (abfd); 557218822Sdim } 558218822Sdim } 559218822Sdim sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive), 560218822Sdim bfd_get_filename (abfd)); 561218822Sdim return buf; 562218822Sdim} 563