1 /* bucomm.c -- Bin Utils COMmon code.
2    Copyright (C) 1991-2024 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
bfd_nonfatal(const char * string)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
bfd_nonfatal_message(const char * filename,const bfd * abfd,const asection * section,const char * format,...)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
bfd_fatal(const char * string)107 bfd_fatal (const char *string)
108 {
109   bfd_nonfatal (string);
110   xexit (1);
111 }
112 
113 void
report(const char * format,va_list args)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
fatal(const char * format,...)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
non_fatal(const char * format,...)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 *
bfd_xalloc(bfd * abfd,size_t size)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
set_default_bfd_target(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
list_matching_formats(char ** matching)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
list_supported_targets(const char * name,FILE * f)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
list_supported_architectures(const char * name,FILE * f)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 *
endian_string(enum bfd_endian endian)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
do_display_target(const bfd_target * targ,void * data)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
display_target_list(struct display_target * arg)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
do_info_size(int targ,int width,const struct display_target * arg)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
do_info_header(int targ,int stop_targ,const struct display_target * arg)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
do_info_row(int targ,int stop_targ,enum bfd_architecture a,const struct display_target * arg)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
display_target_tables(const struct display_target * arg)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
display_info(void)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
print_arelt_descr(FILE * file,bfd * abfd,bool verbose,bool offsets)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 *
template_in_dir(const char * path)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 *
make_tempname(const char * filename,int * ofd)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 *
make_tempdir(const char * filename)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
parse_vma(const char * s,const char * arg)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
get_file_size(const char * file_name)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     {
635       if (!S_ISCHR(statbuf.st_mode))
636           {
637             non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
638             return 0;
639           }
640       return statbuf.st_size ? statbuf.st_size : 1;
641     }
642   else if (statbuf.st_size < 0)
643     non_fatal (_("Warning: '%s' has negative size, probably it is too large"),
644                file_name);
645 #if defined (_WIN32) && !defined (__CYGWIN__)
646   else if (statbuf.st_size == 0)
647     {
648       /* MS-Windows 'stat' reports the null device as a regular file;
649            fix that.  */
650       int fd = open (file_name, O_RDONLY | O_BINARY);
651       if (isatty (fd))
652           {
653             close (fd);
654             non_fatal (_("Warning: '%s' is not an ordinary file"),
655                          /* libtool wants to see /dev/null in the output.  */
656                          strcasecmp (file_name, "nul") ? file_name : "/dev/null");
657           }
658     }
659 #endif
660   else
661     return statbuf.st_size;
662 
663   return (off_t) -1;
664 }
665 
666 /* Return the filename in a static buffer.  */
667 
668 const char *
bfd_get_archive_filename(const bfd * abfd)669 bfd_get_archive_filename (const bfd *abfd)
670 {
671   static size_t curr = 0;
672   static char *buf;
673   size_t needed;
674 
675   assert (abfd != NULL);
676 
677   if (abfd->my_archive == NULL
678       || bfd_is_thin_archive (abfd->my_archive))
679     return bfd_get_filename (abfd);
680 
681   needed = (strlen (bfd_get_filename (abfd->my_archive))
682               + strlen (bfd_get_filename (abfd)) + 3);
683   if (needed > curr)
684     {
685       if (curr)
686           free (buf);
687       curr = needed + (needed >> 1);
688       buf = (char *) xmalloc (curr);
689     }
690   sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
691              bfd_get_filename (abfd));
692   return buf;
693 }
694 
695 /* Returns TRUE iff PATHNAME, a filename of an archive member,
696    is valid for writing.  For security reasons absolute paths
697    and paths containing /../ are not allowed.  See PR 17533.  */
698 
699 bool
is_valid_archive_path(char const * pathname)700 is_valid_archive_path (char const * pathname)
701 {
702   const char * n = pathname;
703 
704   if (IS_ABSOLUTE_PATH (n))
705     return false;
706 
707   while (*n)
708     {
709       if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n)))
710           return false;
711 
712       while (*n && ! IS_DIR_SEPARATOR (*n))
713           n++;
714       while (IS_DIR_SEPARATOR (*n))
715           n++;
716     }
717 
718   return true;
719 }
720