]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - binutils/bucomm.c
2.41 Release sources
[thirdparty/binutils-gdb.git] / binutils / bucomm.c
1 /* bucomm.c -- Bin Utils COMmon code.
2 Copyright (C) 1991-2023 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 \f
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 \f
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 \f
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 \f
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
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);
465
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);
472 }
473 }
474
475 fprintf (file, "%s", bfd_get_filename (abfd));
476
477 if (offsets)
478 {
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);
483 }
484
485 fprintf (file, "\n");
486 }
487
488 /* Return a path for a new temporary file in the same directory
489 as file PATH. */
490
491 static char *
492 template_in_dir (const char *path)
493 {
494 #define template "stXXXXXX"
495 const char *slash = strrchr (path, '/');
496 char *tmpname;
497 size_t len;
498
499 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
500 {
501 /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
502 char *bslash = strrchr (path, '\\');
503
504 if (slash == NULL || (bslash != NULL && bslash > slash))
505 slash = bslash;
506 if (slash == NULL && path[0] != '\0' && path[1] == ':')
507 slash = path + 1;
508 }
509 #endif
510
511 if (slash != (char *) NULL)
512 {
513 len = slash - path;
514 tmpname = (char *) xmalloc (len + sizeof (template) + 2);
515 memcpy (tmpname, path, len);
516
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++] = '/';
525 }
526 else
527 {
528 tmpname = (char *) xmalloc (sizeof (template));
529 len = 0;
530 }
531
532 memcpy (tmpname + len, template, sizeof (template));
533 return tmpname;
534 #undef template
535 }
536
537 /* Return the name of a created temporary file in the same directory
538 as FILENAME. */
539
540 char *
541 make_tempname (const char *filename, int *ofd)
542 {
543 char *tmpname = template_in_dir (filename);
544 int fd;
545
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)
556 {
557 free (tmpname);
558 bfd_set_error (bfd_error_system_call);
559 return NULL;
560 }
561 *ofd = fd;
562 return tmpname;
563 }
564
565 /* Return the name of a created temporary directory inside the
566 directory containing FILENAME. */
567
568 char *
569 make_tempdir (const char *filename)
570 {
571 char *tmpname = template_in_dir (filename);
572 char *ret;
573
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)
587 {
588 free (tmpname);
589 bfd_set_error (bfd_error_system_call);
590 }
591 return ret;
592 }
593
594 /* Parse a string into a VMA, with a fatal error if it can't be
595 parsed. */
596
597 bfd_vma
598 parse_vma (const char *s, const char *arg)
599 {
600 bfd_vma ret;
601 const char *end;
602
603 ret = bfd_scan_vma (s, &end, 0);
604
605 if (*end != '\0')
606 fatal (_("%s: bad number: %s"), arg, s);
607
608 return ret;
609 }
610
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. */
614
615 off_t
616 get_file_size (const char * file_name)
617 {
618 struct stat statbuf;
619
620 if (file_name == NULL)
621 return (off_t) -1;
622
623 if (stat (file_name, &statbuf) < 0)
624 {
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));
630 }
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)
640 {
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))
645 {
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");
650 }
651 }
652 #endif
653 else
654 return statbuf.st_size;
655
656 return (off_t) -1;
657 }
658
659 /* Return the filename in a static buffer. */
660
661 const char *
662 bfd_get_archive_filename (const bfd *abfd)
663 {
664 static size_t curr = 0;
665 static char *buf;
666 size_t needed;
667
668 assert (abfd != NULL);
669
670 if (abfd->my_archive == NULL
671 || bfd_is_thin_archive (abfd->my_archive))
672 return bfd_get_filename (abfd);
673
674 needed = (strlen (bfd_get_filename (abfd->my_archive))
675 + strlen (bfd_get_filename (abfd)) + 3);
676 if (needed > curr)
677 {
678 if (curr)
679 free (buf);
680 curr = needed + (needed >> 1);
681 buf = (char *) xmalloc (curr);
682 }
683 sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
684 bfd_get_filename (abfd));
685 return buf;
686 }
687
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. */
691
692 bool
693 is_valid_archive_path (char const * pathname)
694 {
695 const char * n = pathname;
696
697 if (IS_ABSOLUTE_PATH (n))
698 return false;
699
700 while (*n)
701 {
702 if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n)))
703 return false;
704
705 while (*n && ! IS_DIR_SEPARATOR (*n))
706 n++;
707 while (IS_DIR_SEPARATOR (*n))
708 n++;
709 }
710
711 return true;
712 }