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