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