readelf sprintf optimisation
[binutils-gdb.git] / binutils / bucomm.c
blobc268fd3d913d38ea2d8acc358c63f931ef0714df
1 /* bucomm.c -- Bin Utils COMmon code.
2 Copyright (C) 1991-2023 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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.
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.
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. */
21 /* We might put this in a library someday so it could be dynamically
22 loaded, but for now it's not necessary. */
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"
32 /* Error reporting. */
34 char *program_name;
36 void
37 bfd_nonfatal (const char *string)
39 const char *errmsg;
40 enum bfd_error err = bfd_get_error ();
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);
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:
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. */
65 void
66 bfd_nonfatal_message (const char *filename,
67 const bfd *abfd,
68 const asection *section,
69 const char *format, ...)
71 const char *errmsg;
72 const char *section_name;
73 enum bfd_error err = bfd_get_error ();
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);
83 if (abfd)
85 if (!filename)
86 filename = bfd_get_archive_filename (abfd);
87 if (section)
88 section_name = bfd_section_name (section);
90 if (section_name)
91 fprintf (stderr, ": %s[%s]", filename, section_name);
92 else
93 fprintf (stderr, ": %s", filename);
95 if (format)
97 va_list args;
98 va_start (args, format);
99 fprintf (stderr, ": ");
100 vfprintf (stderr, format, args);
101 va_end (args);
103 fprintf (stderr, ": %s\n", errmsg);
106 void
107 bfd_fatal (const char *string)
109 bfd_nonfatal (string);
110 xexit (1);
113 void
114 report (const char * format, va_list args)
116 fflush (stdout);
117 fprintf (stderr, "%s: ", program_name);
118 vfprintf (stderr, format, args);
119 putc ('\n', stderr);
122 void
123 fatal (const char *format, ...)
125 va_list args;
127 va_start (args, format);
129 report (format, args);
130 va_end (args);
131 xexit (1);
134 void
135 non_fatal (const char *format, ...)
137 va_list args;
139 va_start (args, format);
141 report (format, args);
142 va_end (args);
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. */
149 void *
150 bfd_xalloc (bfd *abfd, size_t size)
152 void *ret = bfd_alloc (abfd, size);
153 if (ret == NULL)
154 bfd_fatal (NULL);
155 return ret;
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. */
163 void
164 set_default_bfd_target (void)
166 /* The macro TARGET is defined by Makefile. */
167 const char *target = TARGET;
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 ()));
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. */
178 void
179 list_matching_formats (char **matching)
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);
190 /* List the supported targets. */
192 void
193 list_supported_targets (const char *name, FILE *f)
195 int t;
196 const char **targ_names;
198 if (name == NULL)
199 fprintf (f, _("Supported targets:"));
200 else
201 fprintf (f, _("%s: supported targets:"), name);
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);
210 /* List the supported architectures. */
212 void
213 list_supported_architectures (const char *name, FILE *f)
215 const char ** arch;
216 const char ** arches;
218 if (name == NULL)
219 fprintf (f, _("Supported architectures:"));
220 else
221 fprintf (f, _("%s: supported architectures:"), name);
223 for (arch = arches = bfd_arch_list (); *arch; arch++)
224 fprintf (f, " %s", *arch);
225 fprintf (f, "\n");
226 free (arches);
229 static const char *
230 endian_string (enum bfd_endian endian)
232 switch (endian)
234 case BFD_ENDIAN_BIG: return _("big endian");
235 case BFD_ENDIAN_LITTLE: return _("little endian");
236 default: return _("endianness unknown");
240 /* Data passed to do_display_target and other target iterators. */
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;
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. */
264 static int
265 do_display_target (const bfd_target *targ, void *data)
267 struct display_target *param = (struct display_target *) data;
268 bfd *abfd;
269 size_t amt;
271 param->count += 1;
272 amt = param->count * sizeof (*param->info);
273 if (param->alloc < amt)
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;
281 param->info[param->count - 1].name = targ->name;
283 printf (_("%s\n (header %s, data %s)\n"), targ->name,
284 endian_string (targ->header_byteorder),
285 endian_string (targ->byteorder));
287 abfd = bfd_openw (param->filename, targ->name);
288 if (abfd == NULL)
290 bfd_nonfatal (param->filename);
291 param->error = 1;
293 else if (!bfd_set_format (abfd, bfd_object))
295 if (bfd_get_error () != bfd_error_invalid_operation)
297 bfd_nonfatal (targ->name);
298 param->error = 1;
301 else
303 enum bfd_architecture a;
305 for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
306 if (bfd_set_arch_mach (abfd, a, 0))
308 printf (" %s\n", bfd_printable_arch_mach (a, 0));
309 param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1;
312 if (abfd != NULL)
313 bfd_close_all_done (abfd);
315 return param->error;
318 static void
319 display_target_list (struct display_target *arg)
321 arg->filename = make_temp_file (NULL);
322 arg->error = 0;
323 arg->count = 0;
324 arg->alloc = 0;
325 arg->info = NULL;
327 bfd_iterate_over_targets (do_display_target, arg);
329 unlink (arg->filename);
330 free (arg->filename);
333 /* Calculate how many targets we can print across the page. */
335 static int
336 do_info_size (int targ, int width, const struct display_target *arg)
338 while (targ < arg->count)
340 width -= strlen (arg->info[targ].name) + 1;
341 if (width < 0)
342 return targ;
343 ++targ;
345 return targ;
348 /* Print header of target names. */
350 static void
351 do_info_header (int targ, int stop_targ, const struct display_target *arg)
353 while (targ != stop_targ)
354 printf ("%s ", arg->info[targ++].name);
357 /* Print a table row. */
359 static void
360 do_info_row (int targ, int stop_targ, enum bfd_architecture a,
361 const struct display_target *arg)
363 while (targ != stop_targ)
365 if (arg->info[targ].arch[a - bfd_arch_obscure - 1])
366 fputs (arg->info[targ].name, stdout);
367 else
369 int l = strlen (arg->info[targ].name);
370 while (l--)
371 putchar ('-');
373 ++targ;
374 if (targ != stop_targ)
375 putchar (' ');
379 /* Print tables of all the target-architecture combinations that
380 BFD has been configured to support. */
382 static void
383 display_target_tables (const struct display_target *arg)
385 const char *columns;
386 int width, start_targ, stop_targ;
387 enum bfd_architecture arch;
388 int longest_arch = 0;
390 for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
392 const char *s = bfd_printable_arch_mach (arch, 0);
393 int len = strlen (s);
394 if (len > longest_arch)
395 longest_arch = len;
398 width = 0;
399 columns = getenv ("COLUMNS");
400 if (columns != NULL)
401 width = atoi (columns);
402 if (width == 0)
403 width = 80;
405 for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ)
407 stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg);
409 printf ("\n%*s", longest_arch + 1, " ");
410 do_info_header (start_targ, stop_targ, arg);
411 putchar ('\n');
413 for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
415 if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0)
417 printf ("%*s ", longest_arch,
418 bfd_printable_arch_mach (arch, 0));
420 do_info_row (start_targ, stop_targ, arch, arg);
421 putchar ('\n');
428 display_info (void)
430 struct display_target arg;
432 printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
434 display_target_list (&arg);
435 if (!arg.error)
436 display_target_tables (&arg);
438 return arg.error;
441 /* Display the archive header for an element as if it were an ls -l listing:
443 Mode User\tGroup\tSize\tDate Name */
445 void
446 print_arelt_descr (FILE *file, bfd *abfd, bool verbose, bool offsets)
448 struct stat buf;
450 if (verbose)
452 if (bfd_stat_arch_elt (abfd, &buf) == 0)
454 char modebuf[11];
455 char timebuf[40];
456 time_t when = buf.st_mtime;
457 const char *ctime_result = (const char *) ctime (&when);
459 /* PR binutils/17605: Check for corrupt time values. */
460 if (ctime_result == NULL)
461 sprintf (timebuf, _("<time data corrupt>"));
462 else
463 /* POSIX format: skip weekday and seconds from ctime output. */
464 sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
466 mode_string (buf.st_mode, modebuf);
467 modebuf[10] = '\0';
468 /* POSIX 1003.2/D11 says to skip first character (entry type). */
469 fprintf (file, "%s %ld/%ld %6" PRIu64 " %s ", modebuf + 1,
470 (long) buf.st_uid, (long) buf.st_gid,
471 (uint64_t) buf.st_size, timebuf);
475 fprintf (file, "%s", bfd_get_filename (abfd));
477 if (offsets)
479 if (bfd_is_thin_archive (abfd) && abfd->proxy_origin)
480 fprintf (file, " 0x%lx", (unsigned long) abfd->proxy_origin);
481 else if (!bfd_is_thin_archive (abfd) && abfd->origin)
482 fprintf (file, " 0x%lx", (unsigned long) abfd->origin);
485 fprintf (file, "\n");
488 /* Return a path for a new temporary file in the same directory
489 as file PATH. */
491 static char *
492 template_in_dir (const char *path)
494 #define template "stXXXXXX"
495 const char *slash = strrchr (path, '/');
496 char *tmpname;
497 size_t len;
499 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
501 /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
502 char *bslash = strrchr (path, '\\');
504 if (slash == NULL || (bslash != NULL && bslash > slash))
505 slash = bslash;
506 if (slash == NULL && path[0] != '\0' && path[1] == ':')
507 slash = path + 1;
509 #endif
511 if (slash != (char *) NULL)
513 len = slash - path;
514 tmpname = (char *) xmalloc (len + sizeof (template) + 2);
515 memcpy (tmpname, path, len);
517 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
518 /* If tmpname is "X:", appending a slash will make it a root
519 directory on drive X, which is NOT the same as the current
520 directory on drive X. */
521 if (len == 2 && tmpname[1] == ':')
522 tmpname[len++] = '.';
523 #endif
524 tmpname[len++] = '/';
526 else
528 tmpname = (char *) xmalloc (sizeof (template));
529 len = 0;
532 memcpy (tmpname + len, template, sizeof (template));
533 return tmpname;
534 #undef template
537 /* Return the name of a created temporary file in the same directory
538 as FILENAME. */
540 char *
541 make_tempname (const char *filename, int *ofd)
543 char *tmpname = template_in_dir (filename);
544 int fd;
546 #ifdef HAVE_MKSTEMP
547 fd = mkstemp (tmpname);
548 #else
549 tmpname = mktemp (tmpname);
550 if (tmpname == NULL)
551 fd = -1;
552 else
553 fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600);
554 #endif
555 if (fd == -1)
557 free (tmpname);
558 bfd_set_error (bfd_error_system_call);
559 return NULL;
561 *ofd = fd;
562 return tmpname;
565 /* Return the name of a created temporary directory inside the
566 directory containing FILENAME. */
568 char *
569 make_tempdir (const char *filename)
571 char *tmpname = template_in_dir (filename);
572 char *ret;
574 #ifdef HAVE_MKDTEMP
575 ret = mkdtemp (tmpname);
576 #else
577 ret = mktemp (tmpname);
578 #if defined (_WIN32) && !defined (__CYGWIN32__)
579 if (mkdir (tmpname) != 0)
580 ret = NULL;
581 #else
582 if (mkdir (tmpname, 0700) != 0)
583 ret = NULL;
584 #endif
585 #endif
586 if (ret == NULL)
588 free (tmpname);
589 bfd_set_error (bfd_error_system_call);
591 return ret;
594 /* Parse a string into a VMA, with a fatal error if it can't be
595 parsed. */
597 bfd_vma
598 parse_vma (const char *s, const char *arg)
600 bfd_vma ret;
601 const char *end;
603 ret = bfd_scan_vma (s, &end, 0);
605 if (*end != '\0')
606 fatal (_("%s: bad number: %s"), arg, s);
608 return ret;
611 /* Returns the size of the named file. If the file does not
612 exist, or if it is not a real file, then a suitable non-fatal
613 error message is printed and (off_t) -1 is returned. */
615 off_t
616 get_file_size (const char * file_name)
618 struct stat statbuf;
620 if (file_name == NULL)
621 return (off_t) -1;
623 if (stat (file_name, &statbuf) < 0)
625 if (errno == ENOENT)
626 non_fatal (_("'%s': No such file"), file_name);
627 else
628 non_fatal (_("Warning: could not locate '%s'. reason: %s"),
629 file_name, strerror (errno));
631 else if (S_ISDIR (statbuf.st_mode))
632 non_fatal (_("Warning: '%s' is a directory"), file_name);
633 else if (! S_ISREG (statbuf.st_mode))
634 non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
635 else if (statbuf.st_size < 0)
636 non_fatal (_("Warning: '%s' has negative size, probably it is too large"),
637 file_name);
638 #if defined (_WIN32) && !defined (__CYGWIN__)
639 else if (statbuf.st_size == 0)
641 /* MS-Windows 'stat' reports the null device as a regular file;
642 fix that. */
643 int fd = open (file_name, O_RDONLY | O_BINARY);
644 if (isatty (fd))
646 close (fd);
647 non_fatal (_("Warning: '%s' is not an ordinary file"),
648 /* libtool wants to see /dev/null in the output. */
649 strcasecmp (file_name, "nul") ? file_name : "/dev/null");
652 #endif
653 else
654 return statbuf.st_size;
656 return (off_t) -1;
659 /* Return the filename in a static buffer. */
661 const char *
662 bfd_get_archive_filename (const bfd *abfd)
664 static size_t curr = 0;
665 static char *buf;
666 size_t needed;
668 assert (abfd != NULL);
670 if (abfd->my_archive == NULL
671 || bfd_is_thin_archive (abfd->my_archive))
672 return bfd_get_filename (abfd);
674 needed = (strlen (bfd_get_filename (abfd->my_archive))
675 + strlen (bfd_get_filename (abfd)) + 3);
676 if (needed > curr)
678 if (curr)
679 free (buf);
680 curr = needed + (needed >> 1);
681 buf = (char *) xmalloc (curr);
683 sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
684 bfd_get_filename (abfd));
685 return buf;
688 /* Returns TRUE iff PATHNAME, a filename of an archive member,
689 is valid for writing. For security reasons absolute paths
690 and paths containing /../ are not allowed. See PR 17533. */
692 bool
693 is_valid_archive_path (char const * pathname)
695 const char * n = pathname;
697 if (IS_ABSOLUTE_PATH (n))
698 return false;
700 while (*n)
702 if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n)))
703 return false;
705 while (*n && ! IS_DIR_SEPARATOR (*n))
706 n++;
707 while (IS_DIR_SEPARATOR (*n))
708 n++;
711 return true;