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