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