* strings.c (statbuf): New typedef.
[binutils-gdb.git] / binutils / strings.c
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 Free Software Foundation, Inc.
4
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 2, or (at your option)
8 any later version.
9
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.
14
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., 59 Temple Place - Suite 330, Boston, MA
18 02111-1307, USA. */
19 \f
20 /* Usage: strings [options] file...
21
22 Options:
23 --all
24 -a
25 - Do not scan only the initialized data section of object files.
26
27 --print-file-name
28 -f Print the name of the file before each string.
29
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.
34
35 --radix={o,x,d}
36 -t {o,x,d} Print the offset within the file before each string,
37 in octal/hex/decimal.
38
39 -o Like -to. (Some other implementations have -o like -to,
40 others like -td. We chose one arbitrarily.)
41
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.
47
48 --target=BFDNAME
49 Specify a non-default object file format.
50
51 --help
52 -h Print the usage message on the standard output.
53
54 --version
55 -v Print the program version number.
56
57 Written by Richard Stallman <rms@gnu.ai.mit.edu>
58 and David MacKenzie <djm@gnu.ai.mit.edu>. */
59
60 #ifdef HAVE_CONFIG_H
61 #include "config.h"
62 #endif
63 #include "bfd.h"
64 #include <stdio.h>
65 #include "getopt.h"
66 #include <errno.h>
67 #include "bucomm.h"
68 #include "libiberty.h"
69 #include "safe-ctype.h"
70
71 /* Some platforms need to put stdin into binary mode, to read
72 binary files. */
73 #ifdef HAVE_SETMODE
74 #ifndef O_BINARY
75 #ifdef _O_BINARY
76 #define O_BINARY _O_BINARY
77 #define setmode _setmode
78 #else
79 #define O_BINARY 0
80 #endif
81 #endif
82 #if O_BINARY
83 #include <io.h>
84 #define SET_BINARY(f) do { if (!isatty (f)) setmode (f,O_BINARY); } while (0)
85 #endif
86 #endif
87
88 #define STRING_ISGRAPHIC(c) \
89 ( (c) >= 0 \
90 && (c) <= 255 \
91 && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127)))
92
93 #ifndef errno
94 extern int errno;
95 #endif
96
97 /* The BFD section flags that identify an initialized data section. */
98 #define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
99
100 #ifdef HAVE_FOPEN64
101 typedef off64_t file_off;
102 #define file_open(s,m) fopen64(s, m)
103 #else
104 typedef off_t file_off;
105 #define file_open(s,m) fopen(s, m)
106 #endif
107 #ifdef HAVE_STAT64
108 typedef struct stat64 statbuf;
109 #define file_stat(f,s) stat64(f, s)
110 #else
111 typedef struct stat statbuf;
112 #define file_stat(f,s) stat(f, s)
113 #endif
114
115 /* Radix for printing addresses (must be 8, 10 or 16). */
116 static int address_radix;
117
118 /* Minimum length of sequence of graphic chars to trigger output. */
119 static int string_min;
120
121 /* TRUE means print address within file for each string. */
122 static bfd_boolean print_addresses;
123
124 /* TRUE means print filename for each string. */
125 static bfd_boolean print_filenames;
126
127 /* TRUE means for object files scan only the data section. */
128 static bfd_boolean datasection_only;
129
130 /* TRUE if we found an initialized data section in the current file. */
131 static bfd_boolean got_a_section;
132
133 /* The BFD object file format. */
134 static char *target;
135
136 /* The character encoding format. */
137 static char encoding;
138 static int encoding_bytes;
139
140 static struct option long_options[] =
141 {
142 {"all", no_argument, NULL, 'a'},
143 {"print-file-name", no_argument, NULL, 'f'},
144 {"bytes", required_argument, NULL, 'n'},
145 {"radix", required_argument, NULL, 't'},
146 {"encoding", required_argument, NULL, 'e'},
147 {"target", required_argument, NULL, 'T'},
148 {"help", no_argument, NULL, 'h'},
149 {"version", no_argument, NULL, 'v'},
150 {NULL, 0, NULL, 0}
151 };
152
153 static void strings_a_section (bfd *, asection *, void *);
154 static bfd_boolean strings_object_file (const char *);
155 static bfd_boolean strings_file (char *file);
156 static int integer_arg (char *s);
157 static void print_strings (const char *, FILE *, file_off, int, int, char *);
158 static void usage (FILE *, int);
159 static long get_char (FILE *, file_off *, int *, char **);
160 \f
161 int main (int, char **);
162
163 int
164 main (int argc, char **argv)
165 {
166 int optc;
167 int exit_status = 0;
168 bfd_boolean files_given = FALSE;
169
170 #if defined (HAVE_SETLOCALE)
171 setlocale (LC_ALL, "");
172 #endif
173 bindtextdomain (PACKAGE, LOCALEDIR);
174 textdomain (PACKAGE);
175
176 program_name = argv[0];
177 xmalloc_set_program_name (program_name);
178 string_min = -1;
179 print_addresses = FALSE;
180 print_filenames = FALSE;
181 datasection_only = TRUE;
182 target = NULL;
183 encoding = 's';
184
185 while ((optc = getopt_long (argc, argv, "afhHn:ot:e:Vv0123456789",
186 long_options, (int *) 0)) != EOF)
187 {
188 switch (optc)
189 {
190 case 'a':
191 datasection_only = FALSE;
192 break;
193
194 case 'f':
195 print_filenames = TRUE;
196 break;
197
198 case 'H':
199 case 'h':
200 usage (stdout, 0);
201
202 case 'n':
203 string_min = integer_arg (optarg);
204 if (string_min < 1)
205 fatal (_("invalid number %s"), optarg);
206 break;
207
208 case 'o':
209 print_addresses = TRUE;
210 address_radix = 8;
211 break;
212
213 case 't':
214 print_addresses = TRUE;
215 if (optarg[1] != '\0')
216 usage (stderr, 1);
217 switch (optarg[0])
218 {
219 case 'o':
220 address_radix = 8;
221 break;
222
223 case 'd':
224 address_radix = 10;
225 break;
226
227 case 'x':
228 address_radix = 16;
229 break;
230
231 default:
232 usage (stderr, 1);
233 }
234 break;
235
236 case 'T':
237 target = optarg;
238 break;
239
240 case 'e':
241 if (optarg[1] != '\0')
242 usage (stderr, 1);
243 encoding = optarg[0];
244 break;
245
246 case 'V':
247 case 'v':
248 print_version ("strings");
249 break;
250
251 case '?':
252 usage (stderr, 1);
253
254 default:
255 if (string_min < 0)
256 string_min = optc - '0';
257 else
258 string_min = string_min * 10 + optc - '0';
259 break;
260 }
261 }
262
263 if (string_min < 0)
264 string_min = 4;
265
266 switch (encoding)
267 {
268 case 'S':
269 case 's':
270 encoding_bytes = 1;
271 break;
272 case 'b':
273 case 'l':
274 encoding_bytes = 2;
275 break;
276 case 'B':
277 case 'L':
278 encoding_bytes = 4;
279 break;
280 default:
281 usage (stderr, 1);
282 }
283
284 bfd_init ();
285 set_default_bfd_target ();
286
287 if (optind >= argc)
288 {
289 datasection_only = FALSE;
290 #ifdef SET_BINARY
291 SET_BINARY (fileno (stdin));
292 #endif
293 print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
294 files_given = TRUE;
295 }
296 else
297 {
298 for (; optind < argc; ++optind)
299 {
300 if (strcmp (argv[optind], "-") == 0)
301 datasection_only = FALSE;
302 else
303 {
304 files_given = TRUE;
305 exit_status |= strings_file (argv[optind]) == FALSE;
306 }
307 }
308 }
309
310 if (!files_given)
311 usage (stderr, 1);
312
313 return (exit_status);
314 }
315 \f
316 /* Scan section SECT of the file ABFD, whose printable name is FILE.
317 If it contains initialized data,
318 set `got_a_section' and print the strings in it. */
319
320 static void
321 strings_a_section (bfd *abfd, asection *sect, void *filearg)
322 {
323 const char *file = (const char *) filearg;
324
325 if ((sect->flags & DATA_FLAGS) == DATA_FLAGS)
326 {
327 bfd_size_type sz = bfd_get_section_size (sect);
328 void *mem = xmalloc (sz);
329
330 if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sz))
331 {
332 got_a_section = TRUE;
333 print_strings (file, (FILE *) NULL, sect->filepos, 0, sz, mem);
334 }
335 free (mem);
336 }
337 }
338
339 /* Scan all of the sections in FILE, and print the strings
340 in the initialized data section(s).
341
342 Return TRUE if successful,
343 FALSE if not (such as if FILE is not an object file). */
344
345 static bfd_boolean
346 strings_object_file (const char *file)
347 {
348 bfd *abfd = bfd_openr (file, target);
349
350 if (abfd == NULL)
351 /* Treat the file as a non-object file. */
352 return FALSE;
353
354 /* This call is mainly for its side effect of reading in the sections.
355 We follow the traditional behavior of `strings' in that we don't
356 complain if we don't recognize a file to be an object file. */
357 if (!bfd_check_format (abfd, bfd_object))
358 {
359 bfd_close (abfd);
360 return FALSE;
361 }
362
363 got_a_section = FALSE;
364 bfd_map_over_sections (abfd, strings_a_section, (void *) file);
365
366 if (!bfd_close (abfd))
367 {
368 bfd_nonfatal (file);
369 return FALSE;
370 }
371
372 return got_a_section;
373 }
374
375 /* Print the strings in FILE. Return TRUE if ok, FALSE if an error occurs. */
376
377 static bfd_boolean
378 strings_file (char *file)
379 {
380 statbuf st;
381
382 if (file_stat (file, &st) < 0)
383 {
384 if (errno == ENOENT)
385 non_fatal (_("'%s': No such file"), file);
386 else
387 non_fatal (_("Warning: could not locate '%s'. reason: %s"),
388 file, strerror (errno));
389 return FALSE;
390 }
391
392 /* If we weren't told to scan the whole file,
393 try to open it as an object file and only look at
394 initialized data sections. If that fails, fall back to the
395 whole file. */
396 if (!datasection_only || !strings_object_file (file))
397 {
398 FILE *stream;
399
400 stream = file_open (file, FOPEN_RB);
401 if (stream == NULL)
402 {
403 fprintf (stderr, "%s: ", program_name);
404 perror (file);
405 return FALSE;
406 }
407
408 print_strings (file, stream, (file_off) 0, 0, 0, (char *) 0);
409
410 if (fclose (stream) == EOF)
411 {
412 fprintf (stderr, "%s: ", program_name);
413 perror (file);
414 return FALSE;
415 }
416 }
417
418 return TRUE;
419 }
420 \f
421 /* Read the next character, return EOF if none available.
422 Assume that STREAM is positioned so that the next byte read
423 is at address ADDRESS in the file.
424
425 If STREAM is NULL, do not read from it.
426 The caller can supply a buffer of characters
427 to be processed before the data in STREAM.
428 MAGIC is the address of the buffer and
429 MAGICCOUNT is how many characters are in it. */
430
431 static long
432 get_char (FILE *stream, file_off *address, int *magiccount, char **magic)
433 {
434 int c, i;
435 long r = EOF;
436 unsigned char buf[4];
437
438 for (i = 0; i < encoding_bytes; i++)
439 {
440 if (*magiccount)
441 {
442 (*magiccount)--;
443 c = *(*magic)++;
444 }
445 else
446 {
447 if (stream == NULL)
448 return EOF;
449 #ifdef HAVE_GETC_UNLOCKED
450 c = getc_unlocked (stream);
451 #else
452 c = getc (stream);
453 #endif
454 if (c == EOF)
455 return EOF;
456 }
457
458 (*address)++;
459 buf[i] = c;
460 }
461
462 switch (encoding)
463 {
464 case 'S':
465 case 's':
466 r = buf[0];
467 break;
468 case 'b':
469 r = (buf[0] << 8) | buf[1];
470 break;
471 case 'l':
472 r = buf[0] | (buf[1] << 8);
473 break;
474 case 'B':
475 r = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
476 ((long) buf[2] << 8) | buf[3];
477 break;
478 case 'L':
479 r = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
480 ((long) buf[3] << 24);
481 break;
482 }
483
484 if (r == EOF)
485 return 0;
486
487 return r;
488 }
489 \f
490 /* Find the strings in file FILENAME, read from STREAM.
491 Assume that STREAM is positioned so that the next byte read
492 is at address ADDRESS in the file.
493 Stop reading at address STOP_POINT in the file, if nonzero.
494
495 If STREAM is NULL, do not read from it.
496 The caller can supply a buffer of characters
497 to be processed before the data in STREAM.
498 MAGIC is the address of the buffer and
499 MAGICCOUNT is how many characters are in it.
500 Those characters come at address ADDRESS and the data in STREAM follow. */
501
502 static void
503 print_strings (const char *filename, FILE *stream, file_off address,
504 int stop_point, int magiccount, char *magic)
505 {
506 char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
507
508 while (1)
509 {
510 file_off start;
511 int i;
512 long c;
513
514 /* See if the next `string_min' chars are all graphic chars. */
515 tryline:
516 if (stop_point && address >= stop_point)
517 break;
518 start = address;
519 for (i = 0; i < string_min; i++)
520 {
521 c = get_char (stream, &address, &magiccount, &magic);
522 if (c == EOF)
523 return;
524 if (! STRING_ISGRAPHIC (c))
525 /* Found a non-graphic. Try again starting with next char. */
526 goto tryline;
527 buf[i] = c;
528 }
529
530 /* We found a run of `string_min' graphic characters. Print up
531 to the next non-graphic character. */
532
533 if (print_filenames)
534 printf ("%s: ", filename);
535 if (print_addresses)
536 switch (address_radix)
537 {
538 case 8:
539 #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
540 if (sizeof (start) > sizeof (long))
541 printf ("%7Lo ", (unsigned long long) start);
542 else
543 #else
544 # if !BFD_HOST_64BIT_LONG
545 if (start != (unsigned long) start)
546 printf ("++%7lo ", (unsigned long) start);
547 else
548 # endif
549 #endif
550 printf ("%7lo ", (unsigned long) start);
551 break;
552
553 case 10:
554 #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
555 if (sizeof (start) > sizeof (long))
556 printf ("%7Ld ", (unsigned long long) start);
557 else
558 #else
559 # if !BFD_HOST_64BIT_LONG
560 if (start != (unsigned long) start)
561 printf ("++%7ld ", (unsigned long) start);
562 else
563 # endif
564 #endif
565 printf ("%7ld ", (long) start);
566 break;
567
568 case 16:
569 #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
570 if (sizeof (start) > sizeof (long))
571 printf ("%7Lx ", (unsigned long long) start);
572 else
573 #else
574 # if !BFD_HOST_64BIT_LONG
575 if (start != (unsigned long) start)
576 printf ("%lx%8.8lx ", (unsigned long) (start >> 32),
577 (unsigned long) (start & 0xffffffff));
578 else
579 # endif
580 #endif
581 printf ("%7lx ", (unsigned long) start);
582 break;
583 }
584
585 buf[i] = '\0';
586 fputs (buf, stdout);
587
588 while (1)
589 {
590 c = get_char (stream, &address, &magiccount, &magic);
591 if (c == EOF)
592 break;
593 if (! STRING_ISGRAPHIC (c))
594 break;
595 putchar (c);
596 }
597
598 putchar ('\n');
599 }
600 }
601 \f
602 /* Parse string S as an integer, using decimal radix by default,
603 but allowing octal and hex numbers as in C. */
604
605 static int
606 integer_arg (char *s)
607 {
608 int value;
609 int radix = 10;
610 char *p = s;
611 int c;
612
613 if (*p != '0')
614 radix = 10;
615 else if (*++p == 'x')
616 {
617 radix = 16;
618 p++;
619 }
620 else
621 radix = 8;
622
623 value = 0;
624 while (((c = *p++) >= '0' && c <= '9')
625 || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
626 {
627 value *= radix;
628 if (c >= '0' && c <= '9')
629 value += c - '0';
630 else
631 value += (c & ~40) - 'A';
632 }
633
634 if (c == 'b')
635 value *= 512;
636 else if (c == 'B')
637 value *= 1024;
638 else
639 p--;
640
641 if (*p)
642 fatal (_("invalid integer argument %s"), s);
643
644 return value;
645 }
646
647 static void
648 usage (FILE *stream, int status)
649 {
650 fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
651 fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n"));
652 fprintf (stream, _(" The options are:\n\
653 -a - --all Scan the entire file, not just the data section\n\
654 -f --print-file-name Print the name of the file before each string\n\
655 -n --bytes=[number] Locate & print any NUL-terminated sequence of at\n\
656 -<number> least [number] characters (default 4).\n\
657 -t --radix={o,x,d} Print the location of the string in base 8, 10 or 16\n\
658 -o An alias for --radix=o\n\
659 -T --target=<BFDNAME> Specify the binary file format\n\
660 -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\
661 s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
662 -h --help Display this information\n\
663 -v --version Print the program's version number\n"));
664 list_supported_targets (program_name, stream);
665 if (status == 0)
666 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
667 exit (status);
668 }