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