Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5217 | serge | 1 | /* bucomm.c -- Bin Utils COMmon code. |
2 | Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, |
||
3 | 2003, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |
||
4 | Free Software Foundation, Inc. |
||
5 | |||
6 | This file is part of GNU Binutils. |
||
7 | |||
8 | This program is free software; you can redistribute it and/or modify |
||
9 | it under the terms of the GNU General Public License as published by |
||
10 | the Free Software Foundation; either version 3 of the License, or |
||
11 | (at your option) any later version. |
||
12 | |||
13 | This program is distributed in the hope that it will be useful, |
||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | GNU General Public License for more details. |
||
17 | |||
18 | You should have received a copy of the GNU General Public License |
||
19 | along with this program; if not, write to the Free Software |
||
20 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA |
||
21 | 02110-1301, USA. */ |
||
22 | |||
23 | /* We might put this in a library someday so it could be dynamically |
||
24 | loaded, but for now it's not necessary. */ |
||
25 | |||
26 | #include "sysdep.h" |
||
27 | #include "bfd.h" |
||
28 | #include "libiberty.h" |
||
29 | #include "filenames.h" |
||
30 | #include "libbfd.h" |
||
31 | |||
32 | #include |
||
33 | #include |
||
34 | #include "bucomm.h" |
||
35 | |||
36 | #ifndef HAVE_TIME_T_IN_TIME_H |
||
37 | #ifndef HAVE_TIME_T_IN_TYPES_H |
||
38 | typedef long time_t; |
||
39 | #endif |
||
40 | #endif |
||
41 | |||
42 | static const char * endian_string (enum bfd_endian); |
||
43 | static int display_target_list (void); |
||
44 | static int display_info_table (int, int); |
||
45 | static int display_target_tables (void); |
||
46 | |||
47 | /* Error reporting. */ |
||
48 | |||
49 | char *program_name; |
||
50 | |||
51 | void |
||
52 | bfd_nonfatal (const char *string) |
||
53 | { |
||
54 | const char *errmsg; |
||
55 | |||
56 | errmsg = bfd_errmsg (bfd_get_error ()); |
||
57 | fflush (stdout); |
||
58 | if (string) |
||
59 | fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); |
||
60 | else |
||
61 | fprintf (stderr, "%s: %s\n", program_name, errmsg); |
||
62 | } |
||
63 | |||
64 | /* Issue a non fatal error message. FILENAME, or if NULL then BFD, |
||
65 | are used to indicate the problematic file. SECTION, if non NULL, |
||
66 | is used to provide a section name. If FORMAT is non-null, then it |
||
67 | is used to print additional information via vfprintf. Finally the |
||
68 | bfd error message is printed. In summary, error messages are of |
||
69 | one of the following forms: |
||
70 | |||
71 | PROGRAM:file: bfd-error-message |
||
72 | PROGRAM:file[section]: bfd-error-message |
||
73 | PROGRAM:file: printf-message: bfd-error-message |
||
74 | PROGRAM:file[section]: printf-message: bfd-error-message. */ |
||
75 | |||
76 | void |
||
77 | bfd_nonfatal_message (const char *filename, |
||
78 | const bfd *abfd, |
||
79 | const asection *section, |
||
80 | const char *format, ...) |
||
81 | { |
||
82 | const char *errmsg; |
||
83 | const char *section_name; |
||
84 | va_list args; |
||
85 | |||
86 | errmsg = bfd_errmsg (bfd_get_error ()); |
||
87 | fflush (stdout); |
||
88 | section_name = NULL; |
||
89 | va_start (args, format); |
||
90 | fprintf (stderr, "%s", program_name); |
||
91 | |||
92 | if (abfd) |
||
93 | { |
||
94 | if (!filename) |
||
95 | filename = bfd_get_archive_filename (abfd); |
||
96 | if (section) |
||
97 | section_name = bfd_get_section_name (abfd, section); |
||
98 | } |
||
99 | if (section_name) |
||
100 | fprintf (stderr, ":%s[%s]", filename, section_name); |
||
101 | else |
||
102 | fprintf (stderr, ":%s", filename); |
||
103 | |||
104 | if (format) |
||
105 | { |
||
106 | fprintf (stderr, ": "); |
||
107 | vfprintf (stderr, format, args); |
||
108 | } |
||
109 | fprintf (stderr, ": %s\n", errmsg); |
||
110 | va_end (args); |
||
111 | } |
||
112 | |||
113 | void |
||
114 | bfd_fatal (const char *string) |
||
115 | { |
||
116 | bfd_nonfatal (string); |
||
117 | xexit (1); |
||
118 | } |
||
119 | |||
120 | void |
||
121 | report (const char * format, va_list args) |
||
122 | { |
||
123 | fflush (stdout); |
||
124 | fprintf (stderr, "%s: ", program_name); |
||
125 | vfprintf (stderr, format, args); |
||
126 | putc ('\n', stderr); |
||
127 | } |
||
128 | |||
129 | void |
||
130 | fatal VPARAMS ((const char *format, ...)) |
||
131 | { |
||
132 | VA_OPEN (args, format); |
||
133 | VA_FIXEDARG (args, const char *, format); |
||
134 | |||
135 | report (format, args); |
||
136 | VA_CLOSE (args); |
||
137 | xexit (1); |
||
138 | } |
||
139 | |||
140 | void |
||
141 | non_fatal VPARAMS ((const char *format, ...)) |
||
142 | { |
||
143 | VA_OPEN (args, format); |
||
144 | VA_FIXEDARG (args, const char *, format); |
||
145 | |||
146 | report (format, args); |
||
147 | VA_CLOSE (args); |
||
148 | } |
||
149 | |||
150 | /* Set the default BFD target based on the configured target. Doing |
||
151 | this permits the binutils to be configured for a particular target, |
||
152 | and linked against a shared BFD library which was configured for a |
||
153 | different target. */ |
||
154 | |||
155 | void |
||
156 | set_default_bfd_target (void) |
||
157 | { |
||
158 | /* The macro TARGET is defined by Makefile. */ |
||
159 | const char *target = TARGET; |
||
160 | |||
161 | if (! bfd_set_default_target (target)) |
||
162 | fatal (_("can't set BFD default target to `%s': %s"), |
||
163 | target, bfd_errmsg (bfd_get_error ())); |
||
164 | } |
||
165 | |||
166 | /* After a FALSE return from bfd_check_format_matches with |
||
167 | bfd_get_error () == bfd_error_file_ambiguously_recognized, print |
||
168 | the possible matching targets. */ |
||
169 | |||
170 | void |
||
171 | list_matching_formats (char **p) |
||
172 | { |
||
173 | fflush (stdout); |
||
174 | fprintf (stderr, _("%s: Matching formats:"), program_name); |
||
175 | while (*p) |
||
176 | fprintf (stderr, " %s", *p++); |
||
177 | fputc ('\n', stderr); |
||
178 | } |
||
179 | |||
180 | /* List the supported targets. */ |
||
181 | |||
182 | void |
||
183 | list_supported_targets (const char *name, FILE *f) |
||
184 | { |
||
185 | int t; |
||
186 | const char **targ_names; |
||
187 | |||
188 | if (name == NULL) |
||
189 | fprintf (f, _("Supported targets:")); |
||
190 | else |
||
191 | fprintf (f, _("%s: supported targets:"), name); |
||
192 | |||
193 | targ_names = bfd_target_list (); |
||
194 | for (t = 0; targ_names[t] != NULL; t++) |
||
195 | fprintf (f, " %s", targ_names[t]); |
||
196 | fprintf (f, "\n"); |
||
197 | free (targ_names); |
||
198 | } |
||
199 | |||
200 | /* List the supported architectures. */ |
||
201 | |||
202 | void |
||
203 | list_supported_architectures (const char *name, FILE *f) |
||
204 | { |
||
205 | const char ** arch; |
||
206 | const char ** arches; |
||
207 | |||
208 | if (name == NULL) |
||
209 | fprintf (f, _("Supported architectures:")); |
||
210 | else |
||
211 | fprintf (f, _("%s: supported architectures:"), name); |
||
212 | |||
213 | for (arch = arches = bfd_arch_list (); *arch; arch++) |
||
214 | fprintf (f, " %s", *arch); |
||
215 | fprintf (f, "\n"); |
||
216 | free (arches); |
||
217 | } |
||
218 | |||
219 | /* The length of the longest architecture name + 1. */ |
||
220 | #define LONGEST_ARCH sizeof ("powerpc:common") |
||
221 | |||
222 | static const char * |
||
223 | endian_string (enum bfd_endian endian) |
||
224 | { |
||
225 | switch (endian) |
||
226 | { |
||
227 | case BFD_ENDIAN_BIG: return _("big endian"); |
||
228 | case BFD_ENDIAN_LITTLE: return _("little endian"); |
||
229 | default: return _("endianness unknown"); |
||
230 | } |
||
231 | } |
||
232 | |||
233 | /* List the targets that BFD is configured to support, each followed |
||
234 | by its endianness and the architectures it supports. */ |
||
235 | |||
236 | static int |
||
237 | display_target_list (void) |
||
238 | { |
||
239 | char *dummy_name; |
||
240 | int t; |
||
241 | int ret = 1; |
||
242 | |||
243 | dummy_name = make_temp_file (NULL); |
||
244 | for (t = 0; bfd_target_vector[t]; t++) |
||
245 | { |
||
246 | const bfd_target *p = bfd_target_vector[t]; |
||
247 | bfd *abfd = bfd_openw (dummy_name, p->name); |
||
248 | int a; |
||
249 | |||
250 | printf (_("%s\n (header %s, data %s)\n"), p->name, |
||
251 | endian_string (p->header_byteorder), |
||
252 | endian_string (p->byteorder)); |
||
253 | |||
254 | if (abfd == NULL) |
||
255 | { |
||
256 | bfd_nonfatal (dummy_name); |
||
257 | ret = 0; |
||
258 | continue; |
||
259 | } |
||
260 | |||
261 | if (! bfd_set_format (abfd, bfd_object)) |
||
262 | { |
||
263 | if (bfd_get_error () != bfd_error_invalid_operation) |
||
264 | { |
||
265 | bfd_nonfatal (p->name); |
||
266 | ret = 0; |
||
267 | } |
||
268 | bfd_close_all_done (abfd); |
||
269 | continue; |
||
270 | } |
||
271 | |||
272 | for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) |
||
273 | if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0)) |
||
274 | printf (" %s\n", |
||
275 | bfd_printable_arch_mach ((enum bfd_architecture) a, 0)); |
||
276 | bfd_close_all_done (abfd); |
||
277 | } |
||
278 | unlink (dummy_name); |
||
279 | free (dummy_name); |
||
280 | |||
281 | return ret; |
||
282 | } |
||
283 | |||
284 | /* Print a table showing which architectures are supported for entries |
||
285 | FIRST through LAST-1 of bfd_target_vector (targets across, |
||
286 | architectures down). */ |
||
287 | |||
288 | static int |
||
289 | display_info_table (int first, int last) |
||
290 | { |
||
291 | int t; |
||
292 | int ret = 1; |
||
293 | char *dummy_name; |
||
294 | int a; |
||
295 | |||
296 | /* Print heading of target names. */ |
||
297 | printf ("\n%*s", (int) LONGEST_ARCH, " "); |
||
298 | for (t = first; t < last && bfd_target_vector[t]; t++) |
||
299 | printf ("%s ", bfd_target_vector[t]->name); |
||
300 | putchar ('\n'); |
||
301 | |||
302 | dummy_name = make_temp_file (NULL); |
||
303 | for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) |
||
304 | if (strcmp (bfd_printable_arch_mach ((enum bfd_architecture) a, 0), |
||
305 | "UNKNOWN!") != 0) |
||
306 | { |
||
307 | printf ("%*s ", (int) LONGEST_ARCH - 1, |
||
308 | bfd_printable_arch_mach ((enum bfd_architecture) a, 0)); |
||
309 | for (t = first; t < last && bfd_target_vector[t]; t++) |
||
310 | { |
||
311 | const bfd_target *p = bfd_target_vector[t]; |
||
312 | bfd_boolean ok = TRUE; |
||
313 | bfd *abfd = bfd_openw (dummy_name, p->name); |
||
314 | |||
315 | if (abfd == NULL) |
||
316 | { |
||
317 | bfd_nonfatal (p->name); |
||
318 | ret = 0; |
||
319 | ok = FALSE; |
||
320 | } |
||
321 | |||
322 | if (ok) |
||
323 | { |
||
324 | if (! bfd_set_format (abfd, bfd_object)) |
||
325 | { |
||
326 | if (bfd_get_error () != bfd_error_invalid_operation) |
||
327 | { |
||
328 | bfd_nonfatal (p->name); |
||
329 | ret = 0; |
||
330 | } |
||
331 | ok = FALSE; |
||
332 | } |
||
333 | } |
||
334 | |||
335 | if (ok) |
||
336 | { |
||
337 | if (! bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0)) |
||
338 | ok = FALSE; |
||
339 | } |
||
340 | |||
341 | if (ok) |
||
342 | printf ("%s ", p->name); |
||
343 | else |
||
344 | { |
||
345 | int l = strlen (p->name); |
||
346 | while (l--) |
||
347 | putchar ('-'); |
||
348 | putchar (' '); |
||
349 | } |
||
350 | if (abfd != NULL) |
||
351 | bfd_close_all_done (abfd); |
||
352 | } |
||
353 | putchar ('\n'); |
||
354 | } |
||
355 | unlink (dummy_name); |
||
356 | free (dummy_name); |
||
357 | |||
358 | return ret; |
||
359 | } |
||
360 | |||
361 | /* Print tables of all the target-architecture combinations that |
||
362 | BFD has been configured to support. */ |
||
363 | |||
364 | static int |
||
365 | display_target_tables (void) |
||
366 | { |
||
367 | int t; |
||
368 | int columns; |
||
369 | int ret = 1; |
||
370 | char *colum; |
||
371 | |||
372 | columns = 0; |
||
373 | colum = getenv ("COLUMNS"); |
||
374 | if (colum != NULL) |
||
375 | columns = atoi (colum); |
||
376 | if (columns == 0) |
||
377 | columns = 80; |
||
378 | |||
379 | t = 0; |
||
380 | while (bfd_target_vector[t] != NULL) |
||
381 | { |
||
382 | int oldt = t, wid; |
||
383 | |||
384 | wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1; |
||
385 | ++t; |
||
386 | while (wid < columns && bfd_target_vector[t] != NULL) |
||
387 | { |
||
388 | int newwid; |
||
389 | |||
390 | newwid = wid + strlen (bfd_target_vector[t]->name) + 1; |
||
391 | if (newwid >= columns) |
||
392 | break; |
||
393 | wid = newwid; |
||
394 | ++t; |
||
395 | } |
||
396 | if (! display_info_table (oldt, t)) |
||
397 | ret = 0; |
||
398 | } |
||
399 | |||
400 | return ret; |
||
401 | } |
||
402 | |||
403 | int |
||
404 | display_info (void) |
||
405 | { |
||
406 | printf (_("BFD header file version %s\n"), BFD_VERSION_STRING); |
||
407 | if (! display_target_list () || ! display_target_tables ()) |
||
408 | return 1; |
||
409 | else |
||
410 | return 0; |
||
411 | } |
||
412 | |||
413 | /* Display the archive header for an element as if it were an ls -l listing: |
||
414 | |||
415 | Mode User\tGroup\tSize\tDate Name */ |
||
416 | |||
417 | void |
||
418 | print_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose) |
||
419 | { |
||
420 | struct stat buf; |
||
421 | |||
422 | if (verbose) |
||
423 | { |
||
424 | if (bfd_stat_arch_elt (abfd, &buf) == 0) |
||
425 | { |
||
426 | char modebuf[11]; |
||
427 | char timebuf[40]; |
||
428 | time_t when = buf.st_mtime; |
||
429 | const char *ctime_result = (const char *) ctime (&when); |
||
430 | bfd_size_type size; |
||
431 | |||
432 | /* POSIX format: skip weekday and seconds from ctime output. */ |
||
433 | sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); |
||
434 | |||
435 | mode_string (buf.st_mode, modebuf); |
||
436 | modebuf[10] = '\0'; |
||
437 | size = buf.st_size; |
||
438 | /* POSIX 1003.2/D11 says to skip first character (entry type). */ |
||
439 | fprintf (file, "%s %ld/%ld %6" BFD_VMA_FMT "u %s ", modebuf + 1, |
||
440 | (long) buf.st_uid, (long) buf.st_gid, |
||
441 | size, timebuf); |
||
442 | } |
||
443 | } |
||
444 | |||
445 | fprintf (file, "%s\n", bfd_get_filename (abfd)); |
||
446 | } |
||
447 | |||
448 | /* Return a path for a new temporary file in the same directory |
||
449 | as file PATH. */ |
||
450 | |||
451 | static char * |
||
452 | template_in_dir (const char *path) |
||
453 | { |
||
454 | #define template "stXXXXXX" |
||
455 | const char *slash = strrchr (path, '/'); |
||
456 | char *tmpname; |
||
457 | size_t len; |
||
458 | |||
459 | #ifdef HAVE_DOS_BASED_FILE_SYSTEM |
||
460 | { |
||
461 | /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ |
||
462 | char *bslash = strrchr (path, '\\'); |
||
463 | |||
464 | if (slash == NULL || (bslash != NULL && bslash > slash)) |
||
465 | slash = bslash; |
||
466 | if (slash == NULL && path[0] != '\0' && path[1] == ':') |
||
467 | slash = path + 1; |
||
468 | } |
||
469 | #endif |
||
470 | |||
471 | if (slash != (char *) NULL) |
||
472 | { |
||
473 | len = slash - path; |
||
474 | tmpname = (char *) xmalloc (len + sizeof (template) + 2); |
||
475 | memcpy (tmpname, path, len); |
||
476 | |||
477 | #ifdef HAVE_DOS_BASED_FILE_SYSTEM |
||
478 | /* If tmpname is "X:", appending a slash will make it a root |
||
479 | directory on drive X, which is NOT the same as the current |
||
480 | directory on drive X. */ |
||
481 | if (len == 2 && tmpname[1] == ':') |
||
482 | tmpname[len++] = '.'; |
||
483 | #endif |
||
484 | tmpname[len++] = '/'; |
||
485 | } |
||
486 | else |
||
487 | { |
||
488 | tmpname = (char *) xmalloc (sizeof (template)); |
||
489 | len = 0; |
||
490 | } |
||
491 | |||
492 | memcpy (tmpname + len, template, sizeof (template)); |
||
493 | return tmpname; |
||
494 | #undef template |
||
495 | } |
||
496 | |||
497 | /* Return the name of a created temporary file in the same directory |
||
498 | as FILENAME. */ |
||
499 | |||
500 | char * |
||
501 | make_tempname (char *filename) |
||
502 | { |
||
503 | char *tmpname = template_in_dir (filename); |
||
504 | int fd; |
||
505 | |||
506 | #ifdef HAVE_MKSTEMP |
||
507 | fd = mkstemp (tmpname); |
||
508 | #else |
||
509 | tmpname = mktemp (tmpname); |
||
510 | if (tmpname == NULL) |
||
511 | return NULL; |
||
512 | fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600); |
||
513 | #endif |
||
514 | if (fd == -1) |
||
515 | { |
||
516 | free (tmpname); |
||
517 | return NULL; |
||
518 | } |
||
519 | close (fd); |
||
520 | return tmpname; |
||
521 | } |
||
522 | |||
523 | /* Return the name of a created temporary directory inside the |
||
524 | directory containing FILENAME. */ |
||
525 | |||
526 | char * |
||
527 | make_tempdir (char *filename) |
||
528 | { |
||
529 | char *tmpname = template_in_dir (filename); |
||
530 | |||
531 | /* |
||
532 | #ifdef HAVE_MKDTEMP |
||
533 | return mkdtemp (tmpname); |
||
534 | #else |
||
535 | tmpname = mktemp (tmpname); |
||
536 | if (tmpname == NULL) |
||
537 | return NULL; |
||
538 | #if defined (_WIN32) && !defined (__CYGWIN32__) |
||
539 | if (mkdir (tmpname) != 0) |
||
540 | return NULL; |
||
541 | #else |
||
542 | if (mkdir (tmpname, 0700) != 0) |
||
543 | return NULL; |
||
544 | #endif |
||
545 | return tmpname; |
||
546 | #endif |
||
547 | */ |
||
548 | return NULL; |
||
549 | } |
||
550 | |||
551 | /* Parse a string into a VMA, with a fatal error if it can't be |
||
552 | parsed. */ |
||
553 | |||
554 | bfd_vma |
||
555 | parse_vma (const char *s, const char *arg) |
||
556 | { |
||
557 | bfd_vma ret; |
||
558 | const char *end; |
||
559 | |||
560 | ret = bfd_scan_vma (s, &end, 0); |
||
561 | |||
562 | if (*end != '\0') |
||
563 | fatal (_("%s: bad number: %s"), arg, s); |
||
564 | |||
565 | return ret; |
||
566 | } |
||
567 | |||
568 | /* Returns the size of the named file. If the file does not |
||
569 | exist, or if it is not a real file, then a suitable non-fatal |
||
570 | error message is printed and (off_t) -1 is returned. */ |
||
571 | |||
572 | off_t |
||
573 | get_file_size (const char * file_name) |
||
574 | { |
||
575 | struct stat statbuf; |
||
576 | |||
577 | if (stat (file_name, &statbuf) < 0) |
||
578 | { |
||
579 | if (errno == ENOENT) |
||
580 | non_fatal (_("'%s': No such file"), file_name); |
||
581 | else |
||
582 | non_fatal (_("Warning: could not locate '%s'. reason: %s"), |
||
583 | file_name, strerror (errno)); |
||
584 | } |
||
585 | else if (! S_ISREG (statbuf.st_mode)) |
||
586 | non_fatal (_("Warning: '%s' is not an ordinary file"), file_name); |
||
587 | else if (statbuf.st_size < 0) |
||
588 | non_fatal (_("Warning: '%s' has negative size, probably it is too large"), |
||
589 | file_name); |
||
590 | else |
||
591 | return statbuf.st_size; |
||
592 | |||
593 | return (off_t) -1; |
||
594 | } |
||
595 | |||
596 | /* Return the filename in a static buffer. */ |
||
597 | |||
598 | const char * |
||
599 | bfd_get_archive_filename (const bfd *abfd) |
||
600 | { |
||
601 | static size_t curr = 0; |
||
602 | static char *buf; |
||
603 | size_t needed; |
||
604 | |||
605 | assert (abfd != NULL); |
||
606 | |||
607 | if (!abfd->my_archive) |
||
608 | return bfd_get_filename (abfd); |
||
609 | |||
610 | needed = (strlen (bfd_get_filename (abfd->my_archive)) |
||
611 | + strlen (bfd_get_filename (abfd)) + 3); |
||
612 | if (needed > curr) |
||
613 | { |
||
614 | if (curr) |
||
615 | free (buf); |
||
616 | curr = needed + (needed >> 1); |
||
617 | buf = (char *) bfd_malloc (curr); |
||
618 | /* If we can't malloc, fail safe by returning just the file name. |
||
619 | This function is only used when building error messages. */ |
||
620 | if (!buf) |
||
621 | { |
||
622 | curr = 0; |
||
623 | return bfd_get_filename (abfd); |
||
624 | } |
||
625 | } |
||
626 | sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive), |
||
627 | bfd_get_filename (abfd)); |
||
628 | return buf; |
||
629 | }>>>>>>> |