Make the strings utility reject directories.
[deliverable/binutils-gdb.git] / binutils / strings.c
1 /* strings -- print the strings of printable characters in files
2 Copyright (C) 1993-2017 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17 02110-1301, USA. */
18 \f
19 /* Usage: strings [options] file...
20
21 Options:
22 --all
23 -a
24 - Scan each file in its entirety.
25
26 --data
27 -d Scan only the initialized data section(s) of object files.
28
29 --print-file-name
30 -f Print the name of the file before each string.
31
32 --bytes=min-len
33 -n min-len
34 -min-len Print graphic char sequences, MIN-LEN or more bytes long,
35 that are followed by a NUL or a newline. Default is 4.
36
37 --radix={o,x,d}
38 -t {o,x,d} Print the offset within the file before each string,
39 in octal/hex/decimal.
40
41 --include-all-whitespace
42 -w By default tab and space are the only whitepace included in graphic
43 char sequences. This option considers all of isspace() valid.
44
45 -o Like -to. (Some other implementations have -o like -to,
46 others like -td. We chose one arbitrarily.)
47
48 --encoding={s,S,b,l,B,L}
49 -e {s,S,b,l,B,L}
50 Select character encoding: 7-bit-character, 8-bit-character,
51 bigendian 16-bit, littleendian 16-bit, bigendian 32-bit,
52 littleendian 32-bit.
53
54 --target=BFDNAME
55 -T {bfdname}
56 Specify a non-default object file format.
57
58 --output-separator=sep_string
59 -s sep_string String used to separate parsed strings in output.
60 Default is newline.
61
62 --help
63 -h Print the usage message on the standard output.
64
65 --version
66 -V
67 -v Print the program version number.
68
69 Written by Richard Stallman <rms@gnu.ai.mit.edu>
70 and David MacKenzie <djm@gnu.ai.mit.edu>. */
71
72 #include "sysdep.h"
73 #include "bfd.h"
74 #include "getopt.h"
75 #include "libiberty.h"
76 #include "safe-ctype.h"
77 #include "bucomm.h"
78
79 #define STRING_ISGRAPHIC(c) \
80 ( (c) >= 0 \
81 && (c) <= 255 \
82 && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127) \
83 || (include_all_whitespace && ISSPACE (c))) \
84 )
85
86 #ifndef errno
87 extern int errno;
88 #endif
89
90 /* The BFD section flags that identify an initialized data section. */
91 #define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
92
93 /* Radix for printing addresses (must be 8, 10 or 16). */
94 static int address_radix;
95
96 /* Minimum length of sequence of graphic chars to trigger output. */
97 static int string_min;
98
99 /* Whether or not we include all whitespace as a graphic char. */
100 static bfd_boolean include_all_whitespace;
101
102 /* TRUE means print address within file for each string. */
103 static bfd_boolean print_addresses;
104
105 /* TRUE means print filename for each string. */
106 static bfd_boolean print_filenames;
107
108 /* TRUE means for object files scan only the data section. */
109 static bfd_boolean datasection_only;
110
111 /* TRUE if we found an initialized data section in the current file. */
112 static bfd_boolean got_a_section;
113
114 /* The BFD object file format. */
115 static char *target;
116
117 /* The character encoding format. */
118 static char encoding;
119 static int encoding_bytes;
120
121 /* Output string used to separate parsed strings */
122 static char *output_separator;
123
124 static struct option long_options[] =
125 {
126 {"all", no_argument, NULL, 'a'},
127 {"data", no_argument, NULL, 'd'},
128 {"print-file-name", no_argument, NULL, 'f'},
129 {"bytes", required_argument, NULL, 'n'},
130 {"radix", required_argument, NULL, 't'},
131 {"include-all-whitespace", required_argument, NULL, 'w'},
132 {"encoding", required_argument, NULL, 'e'},
133 {"target", required_argument, NULL, 'T'},
134 {"output-separator", required_argument, NULL, 's'},
135 {"help", no_argument, NULL, 'h'},
136 {"version", no_argument, NULL, 'v'},
137 {NULL, 0, NULL, 0}
138 };
139
140 /* Records the size of a named file so that we
141 do not repeatedly run bfd_stat() on it. */
142
143 typedef struct
144 {
145 const char * filename;
146 bfd_size_type filesize;
147 } filename_and_size_t;
148
149 static bfd_boolean strings_file (char *);
150 static void print_strings (const char *, FILE *, file_ptr, int, int, char *);
151 static void usage (FILE *, int) ATTRIBUTE_NORETURN;
152 \f
153 int main (int, char **);
154
155 int
156 main (int argc, char **argv)
157 {
158 int optc;
159 int exit_status = 0;
160 bfd_boolean files_given = FALSE;
161 char *s;
162 int numeric_opt = 0;
163
164 #if defined (HAVE_SETLOCALE)
165 setlocale (LC_ALL, "");
166 #endif
167 bindtextdomain (PACKAGE, LOCALEDIR);
168 textdomain (PACKAGE);
169
170 program_name = argv[0];
171 xmalloc_set_program_name (program_name);
172 bfd_set_error_program_name (program_name);
173
174 expandargv (&argc, &argv);
175
176 string_min = 4;
177 include_all_whitespace = FALSE;
178 print_addresses = FALSE;
179 print_filenames = FALSE;
180 if (DEFAULT_STRINGS_ALL)
181 datasection_only = FALSE;
182 else
183 datasection_only = TRUE;
184 target = NULL;
185 encoding = 's';
186 output_separator = NULL;
187
188 while ((optc = getopt_long (argc, argv, "adfhHn:wot:e:T:s:Vv0123456789",
189 long_options, (int *) 0)) != EOF)
190 {
191 switch (optc)
192 {
193 case 'a':
194 datasection_only = FALSE;
195 break;
196
197 case 'd':
198 datasection_only = TRUE;
199 break;
200
201 case 'f':
202 print_filenames = TRUE;
203 break;
204
205 case 'H':
206 case 'h':
207 usage (stdout, 0);
208
209 case 'n':
210 string_min = (int) strtoul (optarg, &s, 0);
211 if (s != NULL && *s != 0)
212 fatal (_("invalid integer argument %s"), optarg);
213 break;
214
215 case 'w':
216 include_all_whitespace = TRUE;
217 break;
218
219 case 'o':
220 print_addresses = TRUE;
221 address_radix = 8;
222 break;
223
224 case 't':
225 print_addresses = TRUE;
226 if (optarg[1] != '\0')
227 usage (stderr, 1);
228 switch (optarg[0])
229 {
230 case 'o':
231 address_radix = 8;
232 break;
233
234 case 'd':
235 address_radix = 10;
236 break;
237
238 case 'x':
239 address_radix = 16;
240 break;
241
242 default:
243 usage (stderr, 1);
244 }
245 break;
246
247 case 'T':
248 target = optarg;
249 break;
250
251 case 'e':
252 if (optarg[1] != '\0')
253 usage (stderr, 1);
254 encoding = optarg[0];
255 break;
256
257 case 's':
258 output_separator = optarg;
259 break;
260
261 case 'V':
262 case 'v':
263 print_version ("strings");
264 break;
265
266 case '?':
267 usage (stderr, 1);
268
269 default:
270 numeric_opt = optind;
271 break;
272 }
273 }
274
275 if (numeric_opt != 0)
276 {
277 string_min = (int) strtoul (argv[numeric_opt - 1] + 1, &s, 0);
278 if (s != NULL && *s != 0)
279 fatal (_("invalid integer argument %s"), argv[numeric_opt - 1] + 1);
280 }
281 if (string_min < 1)
282 fatal (_("invalid minimum string length %d"), string_min);
283
284 switch (encoding)
285 {
286 case 'S':
287 case 's':
288 encoding_bytes = 1;
289 break;
290 case 'b':
291 case 'l':
292 encoding_bytes = 2;
293 break;
294 case 'B':
295 case 'L':
296 encoding_bytes = 4;
297 break;
298 default:
299 usage (stderr, 1);
300 }
301
302 bfd_init ();
303 set_default_bfd_target ();
304
305 if (optind >= argc)
306 {
307 datasection_only = FALSE;
308 SET_BINARY (fileno (stdin));
309 print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
310 files_given = TRUE;
311 }
312 else
313 {
314 for (; optind < argc; ++optind)
315 {
316 if (strcmp (argv[optind], "-") == 0)
317 datasection_only = FALSE;
318 else
319 {
320 files_given = TRUE;
321 exit_status |= !strings_file (argv[optind]);
322 }
323 }
324 }
325
326 if (!files_given)
327 usage (stderr, 1);
328
329 return (exit_status);
330 }
331 \f
332 /* Scan section SECT of the file ABFD, whose printable name is in
333 ARG->filename and whose size might be in ARG->filesize. If it
334 contains initialized data set `got_a_section' and print the
335 strings in it.
336
337 FIXME: We ought to be able to return error codes/messages for
338 certain conditions. */
339
340 static void
341 strings_a_section (bfd *abfd, asection *sect, void *arg)
342 {
343 filename_and_size_t * filename_and_sizep;
344 bfd_size_type *filesizep;
345 bfd_size_type sectsize;
346 void *mem;
347
348 if ((sect->flags & DATA_FLAGS) != DATA_FLAGS)
349 return;
350
351 sectsize = bfd_get_section_size (sect);
352
353 if (sectsize <= 0)
354 return;
355
356 /* Get the size of the file. This might have been cached for us. */
357 filename_and_sizep = (filename_and_size_t *) arg;
358 filesizep = & filename_and_sizep->filesize;
359
360 if (*filesizep == 0)
361 {
362 struct stat st;
363
364 if (bfd_stat (abfd, &st))
365 return;
366
367 /* Cache the result so that we do not repeatedly stat this file. */
368 *filesizep = st.st_size;
369 }
370
371 /* Compare the size of the section against the size of the file.
372 If the section is bigger then the file must be corrupt and
373 we should not try dumping it. */
374 if (sectsize >= *filesizep)
375 return;
376
377 mem = xmalloc (sectsize);
378
379 if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sectsize))
380 {
381 got_a_section = TRUE;
382
383 print_strings (filename_and_sizep->filename, NULL, sect->filepos,
384 0, sectsize, (char *) mem);
385 }
386
387 free (mem);
388 }
389
390 /* Scan all of the sections in FILE, and print the strings
391 in the initialized data section(s).
392
393 Return TRUE if successful,
394 FALSE if not (such as if FILE is not an object file). */
395
396 static bfd_boolean
397 strings_object_file (const char *file)
398 {
399 filename_and_size_t filename_and_size;
400 bfd *abfd;
401
402 abfd = bfd_openr (file, target);
403
404 if (abfd == NULL)
405 /* Treat the file as a non-object file. */
406 return FALSE;
407
408 /* This call is mainly for its side effect of reading in the sections.
409 We follow the traditional behavior of `strings' in that we don't
410 complain if we don't recognize a file to be an object file. */
411 if (!bfd_check_format (abfd, bfd_object))
412 {
413 bfd_close (abfd);
414 return FALSE;
415 }
416
417 got_a_section = FALSE;
418 filename_and_size.filename = file;
419 filename_and_size.filesize = 0;
420 bfd_map_over_sections (abfd, strings_a_section, & filename_and_size);
421
422 if (!bfd_close (abfd))
423 {
424 bfd_nonfatal (file);
425 return FALSE;
426 }
427
428 return got_a_section;
429 }
430
431 /* Print the strings in FILE. Return TRUE if ok, FALSE if an error occurs. */
432
433 static bfd_boolean
434 strings_file (char *file)
435 {
436 struct stat st;
437
438 /* get_file_size does not support non-S_ISREG files. */
439
440 if (stat (file, &st) < 0)
441 {
442 if (errno == ENOENT)
443 non_fatal (_("'%s': No such file"), file);
444 else
445 non_fatal (_("Warning: could not locate '%s'. reason: %s"),
446 file, strerror (errno));
447 return FALSE;
448 }
449 else if (S_ISDIR (st.st_mode))
450 {
451 non_fatal (_("Warning: '%s' is a directory"), file);
452 return FALSE;
453 }
454
455 /* If we weren't told to scan the whole file,
456 try to open it as an object file and only look at
457 initialized data sections. If that fails, fall back to the
458 whole file. */
459 if (!datasection_only || !strings_object_file (file))
460 {
461 FILE *stream;
462
463 stream = fopen (file, FOPEN_RB);
464 if (stream == NULL)
465 {
466 fprintf (stderr, "%s: ", program_name);
467 perror (file);
468 return FALSE;
469 }
470
471 print_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
472
473 if (fclose (stream) == EOF)
474 {
475 fprintf (stderr, "%s: ", program_name);
476 perror (file);
477 return FALSE;
478 }
479 }
480
481 return TRUE;
482 }
483 \f
484 /* Read the next character, return EOF if none available.
485 Assume that STREAM is positioned so that the next byte read
486 is at address ADDRESS in the file.
487
488 If STREAM is NULL, do not read from it.
489 The caller can supply a buffer of characters
490 to be processed before the data in STREAM.
491 MAGIC is the address of the buffer and
492 MAGICCOUNT is how many characters are in it. */
493
494 static long
495 get_char (FILE *stream, file_ptr *address, int *magiccount, char **magic)
496 {
497 int c, i;
498 long r = 0;
499
500 for (i = 0; i < encoding_bytes; i++)
501 {
502 if (*magiccount)
503 {
504 (*magiccount)--;
505 c = *(*magic)++;
506 }
507 else
508 {
509 if (stream == NULL)
510 return EOF;
511
512 /* Only use getc_unlocked if we found a declaration for it.
513 Otherwise, libc is not thread safe by default, and we
514 should not use it. */
515
516 #if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_GETC_UNLOCKED
517 c = getc_unlocked (stream);
518 #else
519 c = getc (stream);
520 #endif
521 if (c == EOF)
522 return EOF;
523 }
524
525 (*address)++;
526 r = (r << 8) | (c & 0xff);
527 }
528
529 switch (encoding)
530 {
531 default:
532 break;
533 case 'l':
534 r = ((r & 0xff) << 8) | ((r & 0xff00) >> 8);
535 break;
536 case 'L':
537 r = (((r & 0xff) << 24) | ((r & 0xff00) << 8)
538 | ((r & 0xff0000) >> 8) | ((r & 0xff000000) >> 24));
539 break;
540 }
541
542 return r;
543 }
544 \f
545 /* Find the strings in file FILENAME, read from STREAM.
546 Assume that STREAM is positioned so that the next byte read
547 is at address ADDRESS in the file.
548 Stop reading at address STOP_POINT in the file, if nonzero.
549
550 If STREAM is NULL, do not read from it.
551 The caller can supply a buffer of characters
552 to be processed before the data in STREAM.
553 MAGIC is the address of the buffer and
554 MAGICCOUNT is how many characters are in it.
555 Those characters come at address ADDRESS and the data in STREAM follow. */
556
557 static void
558 print_strings (const char *filename, FILE *stream, file_ptr address,
559 int stop_point, int magiccount, char *magic)
560 {
561 char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
562
563 while (1)
564 {
565 file_ptr start;
566 int i;
567 long c;
568
569 /* See if the next `string_min' chars are all graphic chars. */
570 tryline:
571 if (stop_point && address >= stop_point)
572 break;
573 start = address;
574 for (i = 0; i < string_min; i++)
575 {
576 c = get_char (stream, &address, &magiccount, &magic);
577 if (c == EOF)
578 {
579 free (buf);
580 return;
581 }
582 if (! STRING_ISGRAPHIC (c))
583 /* Found a non-graphic. Try again starting with next char. */
584 goto tryline;
585 buf[i] = c;
586 }
587
588 /* We found a run of `string_min' graphic characters. Print up
589 to the next non-graphic character. */
590
591 if (print_filenames)
592 printf ("%s: ", filename);
593 if (print_addresses)
594 switch (address_radix)
595 {
596 case 8:
597 #ifdef HAVE_LONG_LONG
598 if (sizeof (start) > sizeof (long))
599 {
600 # ifndef __MSVCRT__
601 printf ("%7llo ", (unsigned long long) start);
602 # else
603 printf ("%7I64o ", (unsigned long long) start);
604 # endif
605 }
606 else
607 #elif !BFD_HOST_64BIT_LONG
608 if (start != (unsigned long) start)
609 printf ("++%7lo ", (unsigned long) start);
610 else
611 #endif
612 printf ("%7lo ", (unsigned long) start);
613 break;
614
615 case 10:
616 #ifdef HAVE_LONG_LONG
617 if (sizeof (start) > sizeof (long))
618 {
619 # ifndef __MSVCRT__
620 printf ("%7lld ", (unsigned long long) start);
621 # else
622 printf ("%7I64d ", (unsigned long long) start);
623 # endif
624 }
625 else
626 #elif !BFD_HOST_64BIT_LONG
627 if (start != (unsigned long) start)
628 printf ("++%7ld ", (unsigned long) start);
629 else
630 #endif
631 printf ("%7ld ", (long) start);
632 break;
633
634 case 16:
635 #ifdef HAVE_LONG_LONG
636 if (sizeof (start) > sizeof (long))
637 {
638 # ifndef __MSVCRT__
639 printf ("%7llx ", (unsigned long long) start);
640 # else
641 printf ("%7I64x ", (unsigned long long) start);
642 # endif
643 }
644 else
645 #elif !BFD_HOST_64BIT_LONG
646 if (start != (unsigned long) start)
647 printf ("%lx%8.8lx ", (unsigned long) (start >> 32),
648 (unsigned long) (start & 0xffffffff));
649 else
650 #endif
651 printf ("%7lx ", (unsigned long) start);
652 break;
653 }
654
655 buf[i] = '\0';
656 fputs (buf, stdout);
657
658 while (1)
659 {
660 c = get_char (stream, &address, &magiccount, &magic);
661 if (c == EOF)
662 break;
663 if (! STRING_ISGRAPHIC (c))
664 break;
665 putchar (c);
666 }
667
668 if (output_separator)
669 fputs (output_separator, stdout);
670 else
671 putchar ('\n');
672 }
673 free (buf);
674 }
675 \f
676 static void
677 usage (FILE *stream, int status)
678 {
679 fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
680 fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n"));
681 fprintf (stream, _(" The options are:\n"));
682
683 if (DEFAULT_STRINGS_ALL)
684 fprintf (stream, _("\
685 -a - --all Scan the entire file, not just the data section [default]\n\
686 -d --data Only scan the data sections in the file\n"));
687 else
688 fprintf (stream, _("\
689 -a - --all Scan the entire file, not just the data section\n\
690 -d --data Only scan the data sections in the file [default]\n"));
691
692 fprintf (stream, _("\
693 -f --print-file-name Print the name of the file before each string\n\
694 -n --bytes=[number] Locate & print any NUL-terminated sequence of at\n\
695 -<number> least [number] characters (default 4).\n\
696 -t --radix={o,d,x} Print the location of the string in base 8, 10 or 16\n\
697 -w --include-all-whitespace Include all whitespace as valid string characters\n\
698 -o An alias for --radix=o\n\
699 -T --target=<BFDNAME> Specify the binary file format\n\
700 -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\
701 s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
702 -s --output-separator=<string> String used to separate strings in output.\n\
703 @<file> Read options from <file>\n\
704 -h --help Display this information\n\
705 -v -V --version Print the program's version number\n"));
706 list_supported_targets (program_name, stream);
707 if (REPORT_BUGS_TO[0] && status == 0)
708 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
709 exit (status);
710 }
This page took 0.042937 seconds and 5 git commands to generate.