Support printable characters outside of the ASCII range
[external/binutils.git] / binutils / strings.c
1 /* strings -- print the strings of printable characters in files
2    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3    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    --target=BFDNAME
43                 Specify a non-default object file format.
44
45    --help
46    -h           Print the usage message on the standard output.
47
48    --version
49    -v           Print the program version number.
50
51    Written by Richard Stallman <rms@gnu.ai.mit.edu>
52    and David MacKenzie <djm@gnu.ai.mit.edu>.  */
53
54 #include "bfd.h"
55 #include <stdio.h>
56 #include <getopt.h>
57 #include <ctype.h>
58 #include <errno.h>
59 #include "bucomm.h"
60 #include "libiberty.h"
61
62 /* Some platforms need to put stdin into binary mode, to read
63     binary files.  */
64 #ifdef HAVE_SETMODE
65 #ifndef O_BINARY
66 #ifdef _O_BINARY
67 #define O_BINARY _O_BINARY
68 #define setmode _setmode
69 #else
70 #define O_BINARY 0
71 #endif
72 #endif
73 #if O_BINARY
74 #include <io.h>
75 #define SET_BINARY(f) do { if (!isatty(f)) setmode(f,O_BINARY); } while (0)
76 #endif
77 #endif
78
79 /* Not all printable characters have ASCII codes (depending upon the
80    LOCALE set) but on some older systems it is not safe to test isprint
81    without first testing isascii...  */
82 #if defined isascii && !defined HAVE_LOCALE_H
83 #define isgraphic(c) (isascii (c) && (isprint (c) || (c) == '\t'))
84 #else
85 #define isgraphic(c) (isprint (c) || (c) == '\t')
86 #endif
87
88 #ifndef errno
89 extern int errno;
90 #endif
91
92 /* The BFD section flags that identify an initialized data section.  */
93 #define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
94
95 /* Radix for printing addresses (must be 8, 10 or 16).  */
96 static int address_radix;
97
98 /* Minimum length of sequence of graphic chars to trigger output.  */
99 static int string_min;
100
101 /* true means print address within file for each string.  */
102 static boolean print_addresses;
103
104 /* true means print filename for each string.  */
105 static boolean print_filenames;
106
107 /* true means for object files scan only the data section.  */
108 static boolean datasection_only;
109
110 /* true if we found an initialized data section in the current file.  */
111 static boolean got_a_section;
112
113 /* The BFD object file format.  */
114 static char *target;
115
116 static struct option long_options[] =
117 {
118   {"all", no_argument, NULL, 'a'},
119   {"print-file-name", no_argument, NULL, 'f'},
120   {"bytes", required_argument, NULL, 'n'},
121   {"radix", required_argument, NULL, 't'},
122   {"target", required_argument, NULL, 'T'},
123   {"help", no_argument, NULL, 'h'},
124   {"version", no_argument, NULL, 'v'},
125   {NULL, 0, NULL, 0}
126 };
127
128 static void strings_a_section PARAMS ((bfd *, asection *, PTR));
129 static boolean strings_object_file PARAMS ((const char *));
130 static boolean strings_file PARAMS ((char *file));
131 static int integer_arg PARAMS ((char *s));
132 static void print_strings PARAMS ((const char *filename, FILE *stream,
133                                   file_ptr address, int stop_point,
134                                   int magiccount, char *magic));
135 static void usage PARAMS ((FILE *stream, int status));
136 \f
137 int
138 main (argc, argv)
139      int argc;
140      char **argv;
141 {
142   int optc;
143   int exit_status = 0;
144   boolean files_given = false;
145
146 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
147   setlocale (LC_ALL, "");
148 #endif
149   bindtextdomain (PACKAGE, LOCALEDIR);
150   textdomain (PACKAGE);
151
152   program_name = argv[0];
153   xmalloc_set_program_name (program_name);
154   string_min = -1;
155   print_addresses = false;
156   print_filenames = false;
157   datasection_only = true;
158   target = NULL;
159
160   while ((optc = getopt_long (argc, argv, "afn:ot:v0123456789",
161                               long_options, (int *) 0)) != EOF)
162     {
163       switch (optc)
164         {
165         case 'a':
166           datasection_only = false;
167           break;
168
169         case 'f':
170           print_filenames = true;
171           break;
172
173         case 'h':
174           usage (stdout, 0);
175
176         case 'n':
177           string_min = integer_arg (optarg);
178           if (string_min < 1)
179             {
180               fatal (_("invalid number %s"), optarg);
181             }
182           break;
183
184         case 'o':
185           print_addresses = true;
186           address_radix = 8;
187           break;
188
189         case 't':
190           print_addresses = true;
191           if (optarg[1] != '\0')
192             usage (stderr, 1);
193           switch (optarg[0])
194             {
195             case 'o':
196               address_radix = 8;
197               break;
198
199             case 'd':
200               address_radix = 10;
201               break;
202
203             case 'x':
204               address_radix = 16;
205               break;
206
207             default:
208               usage (stderr, 1);
209             }
210           break;
211
212         case 'T':
213           target = optarg;
214           break;
215
216         case 'v':
217           print_version ("strings");
218           break;
219
220         case '?':
221           usage (stderr, 1);
222
223         default:
224           if (string_min < 0)
225             string_min = optc - '0';
226           else
227             string_min = string_min * 10 + optc - '0';
228           break;
229         }
230     }
231
232   if (string_min < 0)
233     string_min = 4;
234
235   bfd_init ();
236   set_default_bfd_target ();
237
238   if (optind >= argc)
239     {
240       datasection_only = false;
241 #ifdef SET_BINARY
242       SET_BINARY (fileno (stdin));
243 #endif
244       print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
245       files_given = true;
246     }
247   else
248     {
249       for (; optind < argc; ++optind)
250         {
251           if (strcmp (argv[optind], "-") == 0)
252             datasection_only = false;
253           else
254             {
255               files_given = true;
256               exit_status |= (strings_file (argv[optind]) == false);
257             }
258         }
259     }
260
261   if (files_given == false)
262     usage (stderr, 1);
263
264   return (exit_status);
265 }
266 \f
267 /* Scan section SECT of the file ABFD, whose printable name is FILE.
268    If it contains initialized data,
269    set `got_a_section' and print the strings in it.  */
270
271 static void
272 strings_a_section (abfd, sect, filearg)
273      bfd *abfd;
274      asection *sect;
275      PTR filearg;
276 {
277   const char *file = (const char *) filearg;
278
279   if ((sect->flags & DATA_FLAGS) == DATA_FLAGS)
280     {
281       bfd_size_type sz = bfd_get_section_size_before_reloc (sect);
282       PTR mem = xmalloc (sz);
283       if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sz))
284         {
285           got_a_section = true;
286           print_strings (file, (FILE *) NULL, sect->filepos, 0, sz, mem);
287         }
288       free (mem);
289     }
290 }
291
292 /* Scan all of the sections in FILE, and print the strings
293    in the initialized data section(s).
294
295    Return true if successful,
296    false if not (such as if FILE is not an object file).  */
297
298 static boolean
299 strings_object_file (file)
300      const char *file;
301 {
302   bfd *abfd = bfd_openr (file, target);
303
304   if (abfd == NULL)
305     {
306       /* Treat the file as a non-object file.  */
307       return false;
308     }
309
310   /* This call is mainly for its side effect of reading in the sections.
311      We follow the traditional behavior of `strings' in that we don't
312      complain if we don't recognize a file to be an object file.  */
313   if (bfd_check_format (abfd, bfd_object) == false)
314     {
315       bfd_close (abfd);
316       return false;
317     }
318
319   got_a_section = false;
320   bfd_map_over_sections (abfd, strings_a_section, (PTR) file);
321
322   if (!bfd_close (abfd))
323     {
324       bfd_nonfatal (file);
325       return false;
326     }
327
328   return got_a_section;
329 }
330
331 /* Print the strings in FILE.  Return true if ok, false if an error occurs.  */
332
333 static boolean
334 strings_file (file)
335      char *file;
336 {
337   /* If we weren't told to scan the whole file,
338      try to open it as an object file and only look at
339      initialized data sections.  If that fails, fall back to the
340      whole file.  */
341   if (!datasection_only || !strings_object_file (file))
342     {
343       FILE *stream;
344
345       stream = fopen (file, "rb");
346       /* Not all systems permit "rb", so try "r" if it failed.  */
347       if (stream == NULL)
348         stream = fopen (file, "r");
349       if (stream == NULL)
350         {
351           fprintf (stderr, "%s: ", program_name);
352           perror (file);
353           return false;
354         }
355
356       print_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
357
358       if (fclose (stream) == EOF)
359         {
360           fprintf (stderr, "%s: ", program_name);
361           perror (file);
362           return false;
363         }
364     }
365
366   return true;
367 }
368 \f
369 /* Find the strings in file FILENAME, read from STREAM.
370    Assume that STREAM is positioned so that the next byte read
371    is at address ADDRESS in the file.
372    Stop reading at address STOP_POINT in the file, if nonzero.
373
374    If STREAM is NULL, do not read from it.
375    The caller can supply a buffer of characters
376    to be processed before the data in STREAM.
377    MAGIC is the address of the buffer and
378    MAGICCOUNT is how many characters are in it.
379    Those characters come at address ADDRESS and the data in STREAM follow.  */
380
381 static void
382 print_strings (filename, stream, address, stop_point, magiccount, magic)
383      const char *filename;
384      FILE *stream;
385      file_ptr address;
386      int stop_point;
387      int magiccount;
388      char *magic;
389 {
390   char *buf = (char *) xmalloc (string_min + 1);
391
392   while (1)
393     {
394       file_ptr start;
395       int i;
396       int c;
397
398       /* See if the next `string_min' chars are all graphic chars.  */
399     tryline:
400       if (stop_point && address >= stop_point)
401         break;
402       start = address;
403       for (i = 0; i < string_min; i++)
404         {
405           if (magiccount)
406             {
407               magiccount--;
408               c = *magic++;
409             }
410           else
411             {
412               if (stream == NULL)
413                 return;
414               c = getc (stream);
415               if (c == EOF)
416                 return;
417             }
418           address++;
419           if (!isgraphic (c))
420             /* Found a non-graphic.  Try again starting with next char.  */
421             goto tryline;
422           buf[i] = c;
423         }
424
425       /* We found a run of `string_min' graphic characters.  Print up
426          to the next non-graphic character.  */
427
428       if (print_filenames)
429         printf ("%s: ", filename);
430       if (print_addresses)
431         switch (address_radix)
432           {
433           case 8:
434             printf ("%7lo ", (unsigned long) start);
435             break;
436
437           case 10:
438             printf ("%7ld ", (long) start);
439             break;
440
441           case 16:
442             printf ("%7lx ", (unsigned long) start);
443             break;
444           }
445
446       buf[i] = '\0';
447       fputs (buf, stdout);
448
449       while (1)
450         {
451           if (magiccount)
452             {
453               magiccount--;
454               c = *magic++;
455             }
456           else
457             {
458               if (stream == NULL)
459                 break;
460               c = getc (stream);
461               if (c == EOF)
462                 break;
463             }
464           address++;
465           if (! isgraphic (c))
466             break;
467           putchar (c);
468         }
469
470       putchar ('\n');
471     }
472 }
473 \f
474 /* Parse string S as an integer, using decimal radix by default,
475    but allowing octal and hex numbers as in C.  */
476
477 static int
478 integer_arg (s)
479      char *s;
480 {
481   int value;
482   int radix = 10;
483   char *p = s;
484   int c;
485
486   if (*p != '0')
487     radix = 10;
488   else if (*++p == 'x')
489     {
490       radix = 16;
491       p++;
492     }
493   else
494     radix = 8;
495
496   value = 0;
497   while (((c = *p++) >= '0' && c <= '9')
498          || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
499     {
500       value *= radix;
501       if (c >= '0' && c <= '9')
502         value += c - '0';
503       else
504         value += (c & ~40) - 'A';
505     }
506
507   if (c == 'b')
508     value *= 512;
509   else if (c == 'B')
510     value *= 1024;
511   else
512     p--;
513
514   if (*p)
515     {
516       fatal (_("invalid integer argument %s"), s);
517     }
518   return value;
519 }
520
521 static void
522 usage (stream, status)
523      FILE *stream;
524      int status;
525 {
526   fprintf (stream, _("\
527 Usage: %s [-afov] [-n min-len] [-min-len] [-t {o,x,d}] [-]\n\
528        [--all] [--print-file-name] [--bytes=min-len] [--radix={o,x,d}]\n\
529        [--target=bfdname] [--help] [--version] file...\n"),
530            program_name);
531   list_supported_targets (program_name, stream);
532   if (status == 0)
533     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
534   exit (status);
535 }