* Doc fixes.
[external/binutils.git] / binutils / strings.c
1 /* strings -- print the strings of printable characters in files
2    Copyright (C) 1993 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 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17 \f
18 /* Usage: strings [options] file...
19
20    Options:
21    --all
22    -a
23    -            Do not scan only the initialized data section of object files.
24
25    --print-file-name
26    -f           Print the name of the file before each string.
27
28    --bytes=min-len
29    -n min-len
30    -min-len     Print graphic char sequences, MIN-LEN or more bytes long,
31                 that are followed by a NUL or a newline.  Default is 4.
32
33    --radix={o,x,d}
34    -t {o,x,d}   Print the offset within the file before each string,
35                 in octal/hex/decimal.
36
37    -o           Like -to.  (Some other implementations have -o like -to,
38                 others like -td.  We chose one arbitrarily.)
39
40    --help
41    -h           Print the usage message on the standard output.
42
43    --version
44    -v           Print the program version number.
45
46    Written by Richard Stallman <rms@gnu.ai.mit.edu>
47    and David MacKenzie <djm@gnu.ai.mit.edu>.  */
48
49 #include <stdio.h>
50 #include <getopt.h>
51 #include <ctype.h>
52 #include <errno.h>
53 #include "bfd.h"
54 #include "bucomm.h"
55
56 #ifdef isascii
57 #define isgraphic(c) (isascii (c) && isprint (c))
58 #else
59 #define isgraphic(c) (isprint (c))
60 #endif
61
62 #ifndef errno
63 extern int errno;
64 #endif
65
66 /* The BFD section flags that identify an initialized data section.  */
67 #define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS)
68
69 /* Radix for printing addresses (must be 8, 10 or 16).  */
70 static int address_radix;
71
72 /* Minimum length of sequence of graphic chars to trigger output.  */
73 static int string_min;
74
75 /* true means print address within file for each string.  */
76 static boolean print_addresses;
77
78 /* true means print filename for each string.  */
79 static boolean print_filenames;
80
81 /* true means for object files scan only the data section.  */
82 static boolean datasection_only;
83
84 /* true if we found an initialized data section in the current file.  */
85 static boolean got_a_section;
86
87 /* Opened to /dev/null for reading from a BFD.
88    This is a kludge to avoid rewriting print_strings;
89    the way we call print_strings now, it actually only needs
90    to read from either a memory buffer or a stream, never both
91    for a given file.  */
92 static FILE *devnull;
93
94 extern char *program_version;
95
96 static struct option long_options[] =
97 {
98   {"all", no_argument, NULL, 'a'},
99   {"print-file-name", no_argument, NULL, 'f'},
100   {"bytes", required_argument, NULL, 'n'},
101   {"radix", required_argument, NULL, 't'},
102   {"help", no_argument, NULL, 'h'},
103   {"version", no_argument, NULL, 'v'},
104   {NULL, 0, NULL, 0}
105 };
106
107 static boolean strings_file PARAMS ((char *file));
108 static int integer_arg PARAMS ((char *s));
109 static void print_strings PARAMS ((char *filename, FILE *stream,
110                                   file_ptr address, int stop_point,
111                                   int magiccount, char *magic));
112 static void usage PARAMS ((FILE *stream, int status));
113 \f
114 void
115 main (argc, argv)
116      int argc;
117      char **argv;
118 {
119   int optc;
120   int exit_status = 0;
121   boolean files_given = false;
122
123   program_name = argv[0];
124   string_min = -1;
125   print_addresses = false;
126   print_filenames = false;
127   datasection_only = true;
128
129   while ((optc = getopt_long (argc, argv, "afn:ot:v0123456789",
130                               long_options, (int *) 0)) != EOF)
131     {
132       switch (optc)
133         {
134         case 'a':
135           datasection_only = false;
136           break;
137
138         case 'f':
139           print_filenames = true;
140           break;
141
142         case 'h':
143           usage (stdout, 0);
144
145         case 'n':
146           string_min = integer_arg (optarg);
147           if (string_min < 1)
148             {
149               fprintf (stderr, "%s: invalid number %s\n",
150                        program_name, optarg);
151               exit (1);
152             }
153           break;
154
155         case 'o':
156           print_addresses = true;
157           address_radix = 8;
158           break;
159
160         case 't':
161           print_addresses = true;
162           if (optarg[1] != '\0')
163             usage (stderr, 1);
164           switch (optarg[0])
165             {
166             case 'o':
167               address_radix = 8;
168               break;
169
170             case 'd':
171               address_radix = 10;
172               break;
173
174             case 'x':
175               address_radix = 16;
176               break;
177
178             default:
179               usage (stderr, 1);
180             }
181           break;
182
183         case 'v':
184           printf ("GNU %s version %s\n", program_name, program_version);
185           exit (0);
186
187         case '?':
188           usage (stderr, 1);
189
190         default:
191           if (string_min < 0)
192             string_min = optc;
193           else
194             string_min = string_min * 10 + optc - '0';
195           break;
196         }
197     }
198
199   if (string_min < 0)
200     string_min = 4;
201
202   bfd_init ();
203   devnull = fopen ("/dev/null", "r");
204   if (devnull == NULL)
205     {
206       fprintf (stderr, "%s: ", program_name);
207       perror ("/dev/null");
208       exit (1);
209     }
210
211   for (; optind < argc; ++optind)
212     {
213       if (!strcmp (argv[optind], "-"))
214         datasection_only = false;
215       else
216         {
217           files_given = true;
218           exit_status |= (strings_file (argv[optind]) == false);
219         }
220     }
221
222   if (files_given == false)
223     usage (stderr, 1);
224
225   exit (exit_status);
226 }
227 \f
228 /* Scan section SECT of the file ABFD, whose printable name is FILE.
229    If it contains initialized data,
230    set `got_a_section' and print the strings in it.  */
231
232 static void
233 strings_a_section (abfd, sect, file)
234      bfd *abfd;
235      asection *sect;
236      PTR file;
237 {
238   if ((sect->flags & DATA_FLAGS) == DATA_FLAGS)
239     {
240       bfd_size_type sz = bfd_get_section_size_before_reloc (sect);
241       PTR mem = xmalloc (sz);
242       if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sz))
243         {
244           got_a_section = true;
245           print_strings (file, devnull, sect->filepos, 0, sz, mem);
246         }
247       free (mem);
248     }
249 }
250
251 /* Scan all of the sections in FILE, and print the strings
252    in the initialized data section(s).
253    Return true if successful,
254    false if not (such as if FILE is not an object file).  */
255
256 static boolean
257 strings_object_file (file)
258      char *file;
259 {
260   bfd *abfd = bfd_openr (file, NULL);
261
262   if (abfd == NULL)
263     {
264       if (bfd_error != system_call_error)
265         {
266           /* Out of memory, or an invalid target is specified by the
267              GNUTARGET environment variable.  */
268           fprintf (stderr, "%s: ", program_name);
269           bfd_perror (file);
270         }
271       return false;
272     }
273
274   /* For some reason, without this call, the BFD has no sections.
275      This call is only for the side effect of reading in the sections.  */
276   bfd_check_format (abfd, bfd_object);
277
278   got_a_section = false;
279   bfd_map_over_sections (abfd, strings_a_section, file);
280
281   if (!bfd_close (abfd))
282     {
283       fprintf (stderr, "%s: ", program_name);
284       bfd_perror (file);
285       return false;
286     }
287
288   return got_a_section;
289 }
290
291 /* Print the strings in FILE.  Return true if ok, false if an error occurs.  */
292
293 static boolean
294 strings_file (file)
295      char *file;
296 {
297   /* If we weren't told to scan the whole file,
298      try to open it as an object file and only look at
299      initialized data sections.  If that fails, fall back to the
300      whole file.  */
301   if (!datasection_only || !strings_object_file (file))
302     {
303       FILE *stream;
304
305       stream = fopen (file, "r");
306       if (stream == NULL)
307         {
308           fprintf (stderr, "%s: ", program_name);
309           perror (file);
310           return false;
311         }
312
313       print_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
314
315       if (fclose (stream) == EOF)
316         {
317           fprintf (stderr, "%s: ", program_name);
318           perror (file);
319           return false;
320         }
321     }
322
323   return true;
324 }
325 \f
326 /* Find the strings in file FILENAME, read from STREAM.
327    Assume that STREAM is positioned so that the next byte read
328    is at address ADDRESS in the file.
329    Stop reading at address STOP_POINT in the file, if nonzero.
330
331    Optionally the caller can supply a buffer of characters
332    to be processed before the data in STREAM.
333    MAGIC is the address of the buffer and
334    MAGICCOUNT is how many characters are in it.
335    Those characters come at address ADDRESS and the data in STREAM follow.  */
336
337 static void
338 print_strings (filename, stream, address, stop_point, magiccount, magic)
339      char *filename;
340      FILE *stream;
341      file_ptr address;
342      int stop_point;
343      int magiccount;
344      char *magic;
345 {
346   int bufsize = 100;
347   char *buf = (char *) xmalloc (bufsize);
348
349   while (1)
350     {
351       int i;
352       int c;
353
354       /* See if the next `string_min' chars are all graphic chars.  */
355     tryline:
356       if (stop_point && address >= stop_point)
357         break;
358       for (i = 0; i < string_min; i++)
359         {
360           if (magiccount)
361             {
362               magiccount--;
363               c = *magic++;
364             }
365           else
366             {
367               c = getc (stream);
368               if (c < 0)
369                 return;
370             }
371           address++;
372           if (!isgraphic (c))
373             /* Found a non-graphic.  Try again starting with next char.  */
374             goto tryline;
375           buf[i] = c;
376         }
377
378       /* We found a run of `string_min' graphic characters.
379          Now see if it is terminated with a NUL byte or a newline.   */
380       while (1)
381         {
382           if (i == bufsize)
383             {
384               bufsize *= 2;
385               buf = (char *) xrealloc (buf, bufsize);
386             }
387           if (magiccount)
388             {
389               magiccount--;
390               c = *magic++;
391             }
392           else
393             {
394               c = getc (stream);
395               if (c < 0)
396                 return;
397             }
398           address++;
399           if (c == '\0' || c == '\n')
400             break;              /* It is; print this string.  */
401           if (!isgraphic (c))
402             goto tryline;       /* It isn't; give up on this string.  */
403           buf[i++] = c;         /* The string continues; store it all.  */
404         }
405
406       /* If we get here, the string is all graphics and properly terminated,
407          so print it.  It is all in `buf' and `i' is its length.  */
408       buf[i] = '\0';
409       if (print_filenames)
410         printf ("%s: ", filename);
411       if (print_addresses)
412         switch (address_radix)
413           {
414           case 8:
415             printf ("%7lo ", address - i - 1);
416             break;
417
418           case 10:
419             printf ("%7ld ", address - i - 1);
420             break;
421
422           case 16:
423             printf ("%7lx ", address - i - 1);
424             break;
425           }
426
427       for (i = 0; (c = buf[i]) != '\0'; i++)
428         switch (c)
429           {
430           case '\n':
431             printf ("\\n");
432             break;
433           case '\t':
434             printf ("\\t");
435             break;
436           case '\f':
437             printf ("\\f");
438             break;
439           case '\b':
440             printf ("\\b");
441             break;
442           case '\r':
443             printf ("\\r");
444             break;
445           default:
446             putchar (c);
447           }
448       putchar ('\n');
449     }
450 }
451 \f
452 /* Parse string S as an integer, using decimal radix by default,
453    but allowing octal and hex numbers as in C.  */
454
455 static int
456 integer_arg (s)
457      char *s;
458 {
459   int value;
460   int radix = 10;
461   char *p = s;
462   int c;
463
464   if (*p != '0')
465     radix = 10;
466   else if (*++p == 'x')
467     {
468       radix = 16;
469       p++;
470     }
471   else
472     radix = 8;
473
474   value = 0;
475   while (((c = *p++) >= '0' && c <= '9')
476          || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
477     {
478       value *= radix;
479       if (c >= '0' && c <= '9')
480         value += c - '0';
481       else
482         value += (c & ~40) - 'A';
483     }
484
485   if (c == 'b')
486     value *= 512;
487   else if (c == 'B')
488     value *= 1024;
489   else
490     p--;
491
492   if (*p)
493     {
494       fprintf (stderr, "%s: invalid integer argument %s\n", program_name, s);
495       exit (1);
496     }
497   return value;
498 }
499
500 static void
501 usage (stream, status)
502      FILE *stream;
503      int status;
504 {
505   fprintf (stream, "\
506 Usage: %s [-afov] [-n min-len] [-min-len] [-t {o,x,d}] [-]\n\
507        [--all] [--print-file-name] [--bytes=min-len] [--radix={o,x,d}]\n\
508        [--help] [--version] file...\n",
509            program_name);
510   exit (status);
511 }