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