new file
[binutils.git] / binutils / strings.c
blob8a0f01192c1aea87a33e02a6c93f0b90f7ec94a7
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 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
18 02110-1301, USA. */
20 /* Usage: strings [options] file...
22 Options:
23 --all
25 - Do not scan only the initialized data section of object files.
27 --print-file-name
28 -f Print the name of the file before each string.
30 --bytes=min-len
31 -n min-len
32 -min-len Print graphic char sequences, MIN-LEN or more bytes long,
33 that are followed by a NUL or a newline. Default is 4.
35 --radix={o,x,d}
36 -t {o,x,d} Print the offset within the file before each string,
37 in octal/hex/decimal.
39 -o Like -to. (Some other implementations have -o like -to,
40 others like -td. We chose one arbitrarily.)
42 --encoding={s,S,b,l,B,L}
43 -e {s,S,b,l,B,L}
44 Select character encoding: 7-bit-character, 8-bit-character,
45 bigendian 16-bit, littleendian 16-bit, bigendian 32-bit,
46 littleendian 32-bit.
48 --target=BFDNAME
49 -T {bfdname}
50 Specify a non-default object file format.
52 --help
53 -h Print the usage message on the standard output.
55 --version
56 -v Print the program version number.
58 Written by Richard Stallman <rms@gnu.ai.mit.edu>
59 and David MacKenzie <djm@gnu.ai.mit.edu>. */
61 #include "sysdep.h"
62 #include "bfd.h"
63 #include "getopt.h"
64 #include "libiberty.h"
65 #include "safe-ctype.h"
66 #include <sys/stat.h>
67 #include "bucomm.h"
69 #define STRING_ISGRAPHIC(c) \
70 ( (c) >= 0 \
71 && (c) <= 255 \
72 && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127)))
74 #ifndef errno
75 extern int errno;
76 #endif
78 /* The BFD section flags that identify an initialized data section. */
79 #define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
81 #ifdef HAVE_FOPEN64
82 typedef off64_t file_off;
83 #define file_open(s,m) fopen64(s, m)
84 #else
85 typedef off_t file_off;
86 #define file_open(s,m) fopen(s, m)
87 #endif
88 #ifdef HAVE_STAT64
89 typedef struct stat64 statbuf;
90 #define file_stat(f,s) stat64(f, s)
91 #else
92 typedef struct stat statbuf;
93 #define file_stat(f,s) stat(f, s)
94 #endif
96 /* Radix for printing addresses (must be 8, 10 or 16). */
97 static int address_radix;
99 /* Minimum length of sequence of graphic chars to trigger output. */
100 static int string_min;
102 /* TRUE means print address within file for each string. */
103 static bfd_boolean print_addresses;
105 /* TRUE means print filename for each string. */
106 static bfd_boolean print_filenames;
108 /* TRUE means for object files scan only the data section. */
109 static bfd_boolean datasection_only;
111 /* TRUE if we found an initialized data section in the current file. */
112 static bfd_boolean got_a_section;
114 /* The BFD object file format. */
115 static char *target;
117 /* The character encoding format. */
118 static char encoding;
119 static int encoding_bytes;
121 static struct option long_options[] =
123 {"all", no_argument, NULL, 'a'},
124 {"print-file-name", no_argument, NULL, 'f'},
125 {"bytes", required_argument, NULL, 'n'},
126 {"radix", required_argument, NULL, 't'},
127 {"encoding", required_argument, NULL, 'e'},
128 {"target", required_argument, NULL, 'T'},
129 {"help", no_argument, NULL, 'h'},
130 {"version", no_argument, NULL, 'v'},
131 {NULL, 0, NULL, 0}
134 /* Records the size of a named file so that we
135 do not repeatedly run bfd_stat() on it. */
137 typedef struct
139 const char * filename;
140 bfd_size_type filesize;
141 } filename_and_size_t;
143 static void strings_a_section (bfd *, asection *, void *);
144 static bfd_boolean strings_object_file (const char *);
145 static bfd_boolean strings_file (char *file);
146 static void print_strings (const char *, FILE *, file_off, int, int, char *);
147 static void usage (FILE *, int);
148 static long get_char (FILE *, file_off *, int *, char **);
150 int main (int, char **);
153 main (int argc, char **argv)
155 int optc;
156 int exit_status = 0;
157 bfd_boolean files_given = FALSE;
159 #if defined (HAVE_SETLOCALE)
160 setlocale (LC_ALL, "");
161 #endif
162 bindtextdomain (PACKAGE, LOCALEDIR);
163 textdomain (PACKAGE);
165 program_name = argv[0];
166 xmalloc_set_program_name (program_name);
168 expandargv (&argc, &argv);
170 string_min = 4;
171 print_addresses = FALSE;
172 print_filenames = FALSE;
173 datasection_only = TRUE;
174 target = NULL;
175 encoding = 's';
177 while ((optc = getopt_long (argc, argv, "afhHn:ot:e:T:Vv0123456789",
178 long_options, (int *) 0)) != EOF)
180 switch (optc)
182 case 'a':
183 datasection_only = FALSE;
184 break;
186 case 'f':
187 print_filenames = TRUE;
188 break;
190 case 'H':
191 case 'h':
192 usage (stdout, 0);
194 case 'n':
195 string_min = (int) strtoul (optarg, NULL, 0);
196 break;
198 case 'o':
199 print_addresses = TRUE;
200 address_radix = 8;
201 break;
203 case 't':
204 print_addresses = TRUE;
205 if (optarg[1] != '\0')
206 usage (stderr, 1);
207 switch (optarg[0])
209 case 'o':
210 address_radix = 8;
211 break;
213 case 'd':
214 address_radix = 10;
215 break;
217 case 'x':
218 address_radix = 16;
219 break;
221 default:
222 usage (stderr, 1);
224 break;
226 case 'T':
227 target = optarg;
228 break;
230 case 'e':
231 if (optarg[1] != '\0')
232 usage (stderr, 1);
233 encoding = optarg[0];
234 break;
236 case 'V':
237 case 'v':
238 print_version ("strings");
239 break;
241 case '?':
242 usage (stderr, 1);
244 default:
245 string_min = (int) strtoul (argv[optind - 1] + 1, NULL, 0);
246 break;
250 if (string_min < 1)
251 fatal (_("invalid minimum string length %d"), string_min);
253 switch (encoding)
255 case 'S':
256 case 's':
257 encoding_bytes = 1;
258 break;
259 case 'b':
260 case 'l':
261 encoding_bytes = 2;
262 break;
263 case 'B':
264 case 'L':
265 encoding_bytes = 4;
266 break;
267 default:
268 usage (stderr, 1);
271 bfd_init ();
272 set_default_bfd_target ();
274 if (optind >= argc)
276 datasection_only = FALSE;
277 SET_BINARY (fileno (stdin));
278 print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
279 files_given = TRUE;
281 else
283 for (; optind < argc; ++optind)
285 if (strcmp (argv[optind], "-") == 0)
286 datasection_only = FALSE;
287 else
289 files_given = TRUE;
290 exit_status |= strings_file (argv[optind]) == FALSE;
295 if (!files_given)
296 usage (stderr, 1);
298 return (exit_status);
301 /* Scan section SECT of the file ABFD, whose printable name is in
302 ARG->filename and whose size might be in ARG->filesize. If it
303 contains initialized data set `got_a_section' and print the
304 strings in it.
306 FIXME: We ought to be able to return error codes/messages for
307 certain conditions. */
309 static void
310 strings_a_section (bfd *abfd, asection *sect, void *arg)
312 filename_and_size_t * filename_and_sizep;
313 bfd_size_type *filesizep;
314 bfd_size_type sectsize;
315 void *mem;
317 if ((sect->flags & DATA_FLAGS) != DATA_FLAGS)
318 return;
320 sectsize = bfd_get_section_size (sect);
322 if (sectsize <= 0)
323 return;
325 /* Get the size of the file. This might have been cached for us. */
326 filename_and_sizep = (filename_and_size_t *) arg;
327 filesizep = & filename_and_sizep->filesize;
329 if (*filesizep == 0)
331 struct stat st;
333 if (bfd_stat (abfd, &st))
334 return;
336 /* Cache the result so that we do not repeatedly stat this file. */
337 *filesizep = st.st_size;
340 /* Compare the size of the section against the size of the file.
341 If the section is bigger then the file must be corrupt and
342 we should not try dumping it. */
343 if (sectsize >= *filesizep)
344 return;
346 mem = xmalloc (sectsize);
348 if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sectsize))
350 got_a_section = TRUE;
352 print_strings (filename_and_sizep->filename, NULL, sect->filepos,
353 0, sectsize, mem);
356 free (mem);
359 /* Scan all of the sections in FILE, and print the strings
360 in the initialized data section(s).
362 Return TRUE if successful,
363 FALSE if not (such as if FILE is not an object file). */
365 static bfd_boolean
366 strings_object_file (const char *file)
368 filename_and_size_t filename_and_size;
369 bfd *abfd;
371 abfd = bfd_openr (file, target);
373 if (abfd == NULL)
374 /* Treat the file as a non-object file. */
375 return FALSE;
377 /* This call is mainly for its side effect of reading in the sections.
378 We follow the traditional behavior of `strings' in that we don't
379 complain if we don't recognize a file to be an object file. */
380 if (!bfd_check_format (abfd, bfd_object))
382 bfd_close (abfd);
383 return FALSE;
386 got_a_section = FALSE;
387 filename_and_size.filename = file;
388 filename_and_size.filesize = 0;
389 bfd_map_over_sections (abfd, strings_a_section, & filename_and_size);
391 if (!bfd_close (abfd))
393 bfd_nonfatal (file);
394 return FALSE;
397 return got_a_section;
400 /* Print the strings in FILE. Return TRUE if ok, FALSE if an error occurs. */
402 static bfd_boolean
403 strings_file (char *file)
405 statbuf st;
407 if (file_stat (file, &st) < 0)
409 if (errno == ENOENT)
410 non_fatal (_("'%s': No such file"), file);
411 else
412 non_fatal (_("Warning: could not locate '%s'. reason: %s"),
413 file, strerror (errno));
414 return FALSE;
417 /* If we weren't told to scan the whole file,
418 try to open it as an object file and only look at
419 initialized data sections. If that fails, fall back to the
420 whole file. */
421 if (!datasection_only || !strings_object_file (file))
423 FILE *stream;
425 stream = file_open (file, FOPEN_RB);
426 if (stream == NULL)
428 fprintf (stderr, "%s: ", program_name);
429 perror (file);
430 return FALSE;
433 print_strings (file, stream, (file_off) 0, 0, 0, (char *) 0);
435 if (fclose (stream) == EOF)
437 fprintf (stderr, "%s: ", program_name);
438 perror (file);
439 return FALSE;
443 return TRUE;
446 /* Read the next character, return EOF if none available.
447 Assume that STREAM is positioned so that the next byte read
448 is at address ADDRESS in the file.
450 If STREAM is NULL, do not read from it.
451 The caller can supply a buffer of characters
452 to be processed before the data in STREAM.
453 MAGIC is the address of the buffer and
454 MAGICCOUNT is how many characters are in it. */
456 static long
457 get_char (FILE *stream, file_off *address, int *magiccount, char **magic)
459 int c, i;
460 long r = EOF;
461 unsigned char buf[4];
463 for (i = 0; i < encoding_bytes; i++)
465 if (*magiccount)
467 (*magiccount)--;
468 c = *(*magic)++;
470 else
472 if (stream == NULL)
473 return EOF;
475 /* Only use getc_unlocked if we found a declaration for it.
476 Otherwise, libc is not thread safe by default, and we
477 should not use it. */
479 #if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_GETC_UNLOCKED
480 c = getc_unlocked (stream);
481 #else
482 c = getc (stream);
483 #endif
484 if (c == EOF)
485 return EOF;
488 (*address)++;
489 buf[i] = c;
492 switch (encoding)
494 case 'S':
495 case 's':
496 r = buf[0];
497 break;
498 case 'b':
499 r = (buf[0] << 8) | buf[1];
500 break;
501 case 'l':
502 r = buf[0] | (buf[1] << 8);
503 break;
504 case 'B':
505 r = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
506 ((long) buf[2] << 8) | buf[3];
507 break;
508 case 'L':
509 r = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
510 ((long) buf[3] << 24);
511 break;
514 if (r == EOF)
515 return 0;
517 return r;
520 /* Find the strings in file FILENAME, read from STREAM.
521 Assume that STREAM is positioned so that the next byte read
522 is at address ADDRESS in the file.
523 Stop reading at address STOP_POINT in the file, if nonzero.
525 If STREAM is NULL, do not read from it.
526 The caller can supply a buffer of characters
527 to be processed before the data in STREAM.
528 MAGIC is the address of the buffer and
529 MAGICCOUNT is how many characters are in it.
530 Those characters come at address ADDRESS and the data in STREAM follow. */
532 static void
533 print_strings (const char *filename, FILE *stream, file_off address,
534 int stop_point, int magiccount, char *magic)
536 char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
538 while (1)
540 file_off start;
541 int i;
542 long c;
544 /* See if the next `string_min' chars are all graphic chars. */
545 tryline:
546 if (stop_point && address >= stop_point)
547 break;
548 start = address;
549 for (i = 0; i < string_min; i++)
551 c = get_char (stream, &address, &magiccount, &magic);
552 if (c == EOF)
553 return;
554 if (! STRING_ISGRAPHIC (c))
555 /* Found a non-graphic. Try again starting with next char. */
556 goto tryline;
557 buf[i] = c;
560 /* We found a run of `string_min' graphic characters. Print up
561 to the next non-graphic character. */
563 if (print_filenames)
564 printf ("%s: ", filename);
565 if (print_addresses)
566 switch (address_radix)
568 case 8:
569 #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
570 if (sizeof (start) > sizeof (long))
572 #ifndef __MSVCRT__
573 printf ("%7llo ", (unsigned long long) start);
574 #else
575 printf ("%7I64o ", (unsigned long long) start);
576 #endif
578 else
579 #elif !BFD_HOST_64BIT_LONG
580 if (start != (unsigned long) start)
581 printf ("++%7lo ", (unsigned long) start);
582 else
583 #endif
584 printf ("%7lo ", (unsigned long) start);
585 break;
587 case 10:
588 #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
589 if (sizeof (start) > sizeof (long))
591 #ifndef __MSVCRT__
592 printf ("%7lld ", (unsigned long long) start);
593 #else
594 printf ("%7I64d ", (unsigned long long) start);
595 #endif
597 else
598 #elif !BFD_HOST_64BIT_LONG
599 if (start != (unsigned long) start)
600 printf ("++%7ld ", (unsigned long) start);
601 else
602 #endif
603 printf ("%7ld ", (long) start);
604 break;
606 case 16:
607 #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
608 if (sizeof (start) > sizeof (long))
610 #ifndef __MSVCRT__
611 printf ("%7llx ", (unsigned long long) start);
612 #else
613 printf ("%7I64x ", (unsigned long long) start);
614 #endif
616 else
617 #elif !BFD_HOST_64BIT_LONG
618 if (start != (unsigned long) start)
619 printf ("%lx%8.8lx ", (unsigned long) (start >> 32),
620 (unsigned long) (start & 0xffffffff));
621 else
622 #endif
623 printf ("%7lx ", (unsigned long) start);
624 break;
627 buf[i] = '\0';
628 fputs (buf, stdout);
630 while (1)
632 c = get_char (stream, &address, &magiccount, &magic);
633 if (c == EOF)
634 break;
635 if (! STRING_ISGRAPHIC (c))
636 break;
637 putchar (c);
640 putchar ('\n');
644 static void
645 usage (FILE *stream, int status)
647 fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
648 fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n"));
649 fprintf (stream, _(" The options are:\n\
650 -a - --all Scan the entire file, not just the data section\n\
651 -f --print-file-name Print the name of the file before each string\n\
652 -n --bytes=[number] Locate & print any NUL-terminated sequence of at\n\
653 -<number> least [number] characters (default 4).\n\
654 -t --radix={o,d,x} Print the location of the string in base 8, 10 or 16\n\
655 -o An alias for --radix=o\n\
656 -T --target=<BFDNAME> Specify the binary file format\n\
657 -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\
658 s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
659 @<file> Read options from <file>\n\
660 -h --help Display this information\n\
661 -v --version Print the program's version number\n"));
662 list_supported_targets (program_name, stream);
663 if (REPORT_BUGS_TO[0] && status == 0)
664 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
665 exit (status);