daily update
[binutils.git] / binutils / strings.c
blob00cfb6dc66963c76d67b98bd9464b861ca0162b1
1 /* strings -- print the strings of printable characters in files
2 Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
4 Free Software Foundation, Inc.
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, or (at your option)
9 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 /* Usage: strings [options] file...
23 Options:
24 --all
26 - Do not scan only the initialized data section of object files.
28 --print-file-name
29 -f Print the name of the file before each string.
31 --bytes=min-len
32 -n min-len
33 -min-len Print graphic char sequences, MIN-LEN or more bytes long,
34 that are followed by a NUL or a newline. Default is 4.
36 --radix={o,x,d}
37 -t {o,x,d} Print the offset within the file before each string,
38 in octal/hex/decimal.
40 -o Like -to. (Some other implementations have -o like -to,
41 others like -td. We chose one arbitrarily.)
43 --encoding={s,S,b,l,B,L}
44 -e {s,S,b,l,B,L}
45 Select character encoding: 7-bit-character, 8-bit-character,
46 bigendian 16-bit, littleendian 16-bit, bigendian 32-bit,
47 littleendian 32-bit.
49 --target=BFDNAME
50 -T {bfdname}
51 Specify a non-default object file format.
53 --help
54 -h Print the usage message on the standard output.
56 --version
58 -v Print the program version number.
60 Written by Richard Stallman <rms@gnu.ai.mit.edu>
61 and David MacKenzie <djm@gnu.ai.mit.edu>. */
63 #include "sysdep.h"
64 #include "bfd.h"
65 #include "getopt.h"
66 #include "libiberty.h"
67 #include "safe-ctype.h"
68 #include <sys/stat.h>
69 #include "bucomm.h"
71 #define STRING_ISGRAPHIC(c) \
72 ( (c) >= 0 \
73 && (c) <= 255 \
74 && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127)))
76 #ifndef errno
77 extern int errno;
78 #endif
80 /* The BFD section flags that identify an initialized data section. */
81 #define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
83 /* Radix for printing addresses (must be 8, 10 or 16). */
84 static int address_radix;
86 /* Minimum length of sequence of graphic chars to trigger output. */
87 static int string_min;
89 /* TRUE means print address within file for each string. */
90 static bfd_boolean print_addresses;
92 /* TRUE means print filename for each string. */
93 static bfd_boolean print_filenames;
95 /* TRUE means for object files scan only the data section. */
96 static bfd_boolean datasection_only;
98 /* TRUE if we found an initialized data section in the current file. */
99 static bfd_boolean got_a_section;
101 /* The BFD object file format. */
102 static char *target;
104 /* The character encoding format. */
105 static char encoding;
106 static int encoding_bytes;
108 static struct option long_options[] =
110 {"all", no_argument, NULL, 'a'},
111 {"print-file-name", no_argument, NULL, 'f'},
112 {"bytes", required_argument, NULL, 'n'},
113 {"radix", required_argument, NULL, 't'},
114 {"encoding", required_argument, NULL, 'e'},
115 {"target", required_argument, NULL, 'T'},
116 {"help", no_argument, NULL, 'h'},
117 {"version", no_argument, NULL, 'v'},
118 {NULL, 0, NULL, 0}
121 /* Records the size of a named file so that we
122 do not repeatedly run bfd_stat() on it. */
124 typedef struct
126 const char * filename;
127 bfd_size_type filesize;
128 } filename_and_size_t;
130 static void strings_a_section (bfd *, asection *, void *);
131 static bfd_boolean strings_object_file (const char *);
132 static bfd_boolean strings_file (char *file);
133 static void print_strings (const char *, FILE *, file_ptr, int, int, char *);
134 static void usage (FILE *, int);
135 static long get_char (FILE *, file_ptr *, int *, char **);
137 int main (int, char **);
140 main (int argc, char **argv)
142 int optc;
143 int exit_status = 0;
144 bfd_boolean files_given = FALSE;
145 char *s;
146 int numeric_opt = 0;
148 #if defined (HAVE_SETLOCALE)
149 setlocale (LC_ALL, "");
150 #endif
151 bindtextdomain (PACKAGE, LOCALEDIR);
152 textdomain (PACKAGE);
154 program_name = argv[0];
155 xmalloc_set_program_name (program_name);
157 expandargv (&argc, &argv);
159 string_min = 4;
160 print_addresses = FALSE;
161 print_filenames = FALSE;
162 datasection_only = TRUE;
163 target = NULL;
164 encoding = 's';
166 while ((optc = getopt_long (argc, argv, "afhHn:ot:e:T:Vv0123456789",
167 long_options, (int *) 0)) != EOF)
169 switch (optc)
171 case 'a':
172 datasection_only = FALSE;
173 break;
175 case 'f':
176 print_filenames = TRUE;
177 break;
179 case 'H':
180 case 'h':
181 usage (stdout, 0);
183 case 'n':
184 string_min = (int) strtoul (optarg, &s, 0);
185 if (s != NULL && *s != 0)
186 fatal (_("invalid integer argument %s"), optarg);
187 break;
189 case 'o':
190 print_addresses = TRUE;
191 address_radix = 8;
192 break;
194 case 't':
195 print_addresses = TRUE;
196 if (optarg[1] != '\0')
197 usage (stderr, 1);
198 switch (optarg[0])
200 case 'o':
201 address_radix = 8;
202 break;
204 case 'd':
205 address_radix = 10;
206 break;
208 case 'x':
209 address_radix = 16;
210 break;
212 default:
213 usage (stderr, 1);
215 break;
217 case 'T':
218 target = optarg;
219 break;
221 case 'e':
222 if (optarg[1] != '\0')
223 usage (stderr, 1);
224 encoding = optarg[0];
225 break;
227 case 'V':
228 case 'v':
229 print_version ("strings");
230 break;
232 case '?':
233 usage (stderr, 1);
235 default:
236 numeric_opt = optind;
237 break;
241 if (numeric_opt != 0)
243 string_min = (int) strtoul (argv[numeric_opt - 1] + 1, &s, 0);
244 if (s != NULL && *s != 0)
245 fatal (_("invalid integer argument %s"), argv[numeric_opt - 1] + 1);
247 if (string_min < 1)
248 fatal (_("invalid minimum string length %d"), string_min);
250 switch (encoding)
252 case 'S':
253 case 's':
254 encoding_bytes = 1;
255 break;
256 case 'b':
257 case 'l':
258 encoding_bytes = 2;
259 break;
260 case 'B':
261 case 'L':
262 encoding_bytes = 4;
263 break;
264 default:
265 usage (stderr, 1);
268 bfd_init ();
269 set_default_bfd_target ();
271 if (optind >= argc)
273 datasection_only = FALSE;
274 SET_BINARY (fileno (stdin));
275 print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
276 files_given = TRUE;
278 else
280 for (; optind < argc; ++optind)
282 if (strcmp (argv[optind], "-") == 0)
283 datasection_only = FALSE;
284 else
286 files_given = TRUE;
287 exit_status |= strings_file (argv[optind]) == FALSE;
292 if (!files_given)
293 usage (stderr, 1);
295 return (exit_status);
298 /* Scan section SECT of the file ABFD, whose printable name is in
299 ARG->filename and whose size might be in ARG->filesize. If it
300 contains initialized data set `got_a_section' and print the
301 strings in it.
303 FIXME: We ought to be able to return error codes/messages for
304 certain conditions. */
306 static void
307 strings_a_section (bfd *abfd, asection *sect, void *arg)
309 filename_and_size_t * filename_and_sizep;
310 bfd_size_type *filesizep;
311 bfd_size_type sectsize;
312 void *mem;
314 if ((sect->flags & DATA_FLAGS) != DATA_FLAGS)
315 return;
317 sectsize = bfd_get_section_size (sect);
319 if (sectsize <= 0)
320 return;
322 /* Get the size of the file. This might have been cached for us. */
323 filename_and_sizep = (filename_and_size_t *) arg;
324 filesizep = & filename_and_sizep->filesize;
326 if (*filesizep == 0)
328 struct stat st;
330 if (bfd_stat (abfd, &st))
331 return;
333 /* Cache the result so that we do not repeatedly stat this file. */
334 *filesizep = st.st_size;
337 /* Compare the size of the section against the size of the file.
338 If the section is bigger then the file must be corrupt and
339 we should not try dumping it. */
340 if (sectsize >= *filesizep)
341 return;
343 mem = xmalloc (sectsize);
345 if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sectsize))
347 got_a_section = TRUE;
349 print_strings (filename_and_sizep->filename, NULL, sect->filepos,
350 0, sectsize, (char *) mem);
353 free (mem);
356 /* Scan all of the sections in FILE, and print the strings
357 in the initialized data section(s).
359 Return TRUE if successful,
360 FALSE if not (such as if FILE is not an object file). */
362 static bfd_boolean
363 strings_object_file (const char *file)
365 filename_and_size_t filename_and_size;
366 bfd *abfd;
368 abfd = bfd_openr (file, target);
370 if (abfd == NULL)
371 /* Treat the file as a non-object file. */
372 return FALSE;
374 /* This call is mainly for its side effect of reading in the sections.
375 We follow the traditional behavior of `strings' in that we don't
376 complain if we don't recognize a file to be an object file. */
377 if (!bfd_check_format (abfd, bfd_object))
379 bfd_close (abfd);
380 return FALSE;
383 got_a_section = FALSE;
384 filename_and_size.filename = file;
385 filename_and_size.filesize = 0;
386 bfd_map_over_sections (abfd, strings_a_section, & filename_and_size);
388 if (!bfd_close (abfd))
390 bfd_nonfatal (file);
391 return FALSE;
394 return got_a_section;
397 /* Print the strings in FILE. Return TRUE if ok, FALSE if an error occurs. */
399 static bfd_boolean
400 strings_file (char *file)
402 struct stat st;
404 /* get_file_size does not support non-S_ISREG files. */
406 if (stat (file, &st) < 0)
408 if (errno == ENOENT)
409 non_fatal (_("'%s': No such file"), file);
410 else
411 non_fatal (_("Warning: could not locate '%s'. reason: %s"),
412 file, strerror (errno));
413 return FALSE;
416 /* If we weren't told to scan the whole file,
417 try to open it as an object file and only look at
418 initialized data sections. If that fails, fall back to the
419 whole file. */
420 if (!datasection_only || !strings_object_file (file))
422 FILE *stream;
424 stream = fopen (file, FOPEN_RB);
425 if (stream == NULL)
427 fprintf (stderr, "%s: ", program_name);
428 perror (file);
429 return FALSE;
432 print_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
434 if (fclose (stream) == EOF)
436 fprintf (stderr, "%s: ", program_name);
437 perror (file);
438 return FALSE;
442 return TRUE;
445 /* Read the next character, return EOF if none available.
446 Assume that STREAM is positioned so that the next byte read
447 is at address ADDRESS in the file.
449 If STREAM is NULL, do not read from it.
450 The caller can supply a buffer of characters
451 to be processed before the data in STREAM.
452 MAGIC is the address of the buffer and
453 MAGICCOUNT is how many characters are in it. */
455 static long
456 get_char (FILE *stream, file_ptr *address, int *magiccount, char **magic)
458 int c, i;
459 long r = EOF;
460 unsigned char buf[4];
462 for (i = 0; i < encoding_bytes; i++)
464 if (*magiccount)
466 (*magiccount)--;
467 c = *(*magic)++;
469 else
471 if (stream == NULL)
472 return EOF;
474 /* Only use getc_unlocked if we found a declaration for it.
475 Otherwise, libc is not thread safe by default, and we
476 should not use it. */
478 #if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_GETC_UNLOCKED
479 c = getc_unlocked (stream);
480 #else
481 c = getc (stream);
482 #endif
483 if (c == EOF)
484 return EOF;
487 (*address)++;
488 buf[i] = c;
491 switch (encoding)
493 case 'S':
494 case 's':
495 r = buf[0];
496 break;
497 case 'b':
498 r = (buf[0] << 8) | buf[1];
499 break;
500 case 'l':
501 r = buf[0] | (buf[1] << 8);
502 break;
503 case 'B':
504 r = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
505 ((long) buf[2] << 8) | buf[3];
506 break;
507 case 'L':
508 r = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
509 ((long) buf[3] << 24);
510 break;
513 if (r == EOF)
514 return 0;
516 return r;
519 /* Find the strings in file FILENAME, read from STREAM.
520 Assume that STREAM is positioned so that the next byte read
521 is at address ADDRESS in the file.
522 Stop reading at address STOP_POINT in the file, if nonzero.
524 If STREAM is NULL, do not read from it.
525 The caller can supply a buffer of characters
526 to be processed before the data in STREAM.
527 MAGIC is the address of the buffer and
528 MAGICCOUNT is how many characters are in it.
529 Those characters come at address ADDRESS and the data in STREAM follow. */
531 static void
532 print_strings (const char *filename, FILE *stream, file_ptr address,
533 int stop_point, int magiccount, char *magic)
535 char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
537 while (1)
539 file_ptr start;
540 int i;
541 long c;
543 /* See if the next `string_min' chars are all graphic chars. */
544 tryline:
545 if (stop_point && address >= stop_point)
546 break;
547 start = address;
548 for (i = 0; i < string_min; i++)
550 c = get_char (stream, &address, &magiccount, &magic);
551 if (c == EOF)
552 return;
553 if (! STRING_ISGRAPHIC (c))
554 /* Found a non-graphic. Try again starting with next char. */
555 goto tryline;
556 buf[i] = c;
559 /* We found a run of `string_min' graphic characters. Print up
560 to the next non-graphic character. */
562 if (print_filenames)
563 printf ("%s: ", filename);
564 if (print_addresses)
565 switch (address_radix)
567 case 8:
568 #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
569 if (sizeof (start) > sizeof (long))
571 #ifndef __MSVCRT__
572 printf ("%7llo ", (unsigned long long) start);
573 #else
574 printf ("%7I64o ", (unsigned long long) start);
575 #endif
577 else
578 #elif !BFD_HOST_64BIT_LONG
579 if (start != (unsigned long) start)
580 printf ("++%7lo ", (unsigned long) start);
581 else
582 #endif
583 printf ("%7lo ", (unsigned long) start);
584 break;
586 case 10:
587 #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
588 if (sizeof (start) > sizeof (long))
590 #ifndef __MSVCRT__
591 printf ("%7lld ", (unsigned long long) start);
592 #else
593 printf ("%7I64d ", (unsigned long long) start);
594 #endif
596 else
597 #elif !BFD_HOST_64BIT_LONG
598 if (start != (unsigned long) start)
599 printf ("++%7ld ", (unsigned long) start);
600 else
601 #endif
602 printf ("%7ld ", (long) start);
603 break;
605 case 16:
606 #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
607 if (sizeof (start) > sizeof (long))
609 #ifndef __MSVCRT__
610 printf ("%7llx ", (unsigned long long) start);
611 #else
612 printf ("%7I64x ", (unsigned long long) start);
613 #endif
615 else
616 #elif !BFD_HOST_64BIT_LONG
617 if (start != (unsigned long) start)
618 printf ("%lx%8.8lx ", (unsigned long) (start >> 32),
619 (unsigned long) (start & 0xffffffff));
620 else
621 #endif
622 printf ("%7lx ", (unsigned long) start);
623 break;
626 buf[i] = '\0';
627 fputs (buf, stdout);
629 while (1)
631 c = get_char (stream, &address, &magiccount, &magic);
632 if (c == EOF)
633 break;
634 if (! STRING_ISGRAPHIC (c))
635 break;
636 putchar (c);
639 putchar ('\n');
643 static void
644 usage (FILE *stream, int status)
646 fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
647 fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n"));
648 fprintf (stream, _(" The options are:\n\
649 -a - --all Scan the entire file, not just the data section\n\
650 -f --print-file-name Print the name of the file before each string\n\
651 -n --bytes=[number] Locate & print any NUL-terminated sequence of at\n\
652 -<number> least [number] characters (default 4).\n\
653 -t --radix={o,d,x} Print the location of the string in base 8, 10 or 16\n\
654 -o An alias for --radix=o\n\
655 -T --target=<BFDNAME> Specify the binary file format\n\
656 -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\
657 s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
658 @<file> Read options from <file>\n\
659 -h --help Display this information\n\
660 -v -V --version Print the program's version number\n"));
661 list_supported_targets (program_name, stream);
662 if (REPORT_BUGS_TO[0] && status == 0)
663 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
664 exit (status);