xref: /dflybsd-src/contrib/binutils-2.34/binutils/strings.c (revision b52ef7118d1621abed722c5bbbd542210290ecef)
1*fae548d3Szrj /* strings -- print the strings of printable characters in files
2*fae548d3Szrj    Copyright (C) 1993-2020 Free Software Foundation, Inc.
3*fae548d3Szrj 
4*fae548d3Szrj    This program is free software; you can redistribute it and/or modify
5*fae548d3Szrj    it under the terms of the GNU General Public License as published by
6*fae548d3Szrj    the Free Software Foundation; either version 3, or (at your option)
7*fae548d3Szrj    any later version.
8*fae548d3Szrj 
9*fae548d3Szrj    This program is distributed in the hope that it will be useful,
10*fae548d3Szrj    but WITHOUT ANY WARRANTY; without even the implied warranty of
11*fae548d3Szrj    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*fae548d3Szrj    GNU General Public License for more details.
13*fae548d3Szrj 
14*fae548d3Szrj    You should have received a copy of the GNU General Public License
15*fae548d3Szrj    along with this program; if not, write to the Free Software
16*fae548d3Szrj    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17*fae548d3Szrj    02110-1301, USA.  */
18*fae548d3Szrj 
19*fae548d3Szrj /* Usage: strings [options] file...
20*fae548d3Szrj 
21*fae548d3Szrj    Options:
22*fae548d3Szrj    --all
23*fae548d3Szrj    -a
24*fae548d3Szrj    -		Scan each file in its entirety.
25*fae548d3Szrj 
26*fae548d3Szrj    --data
27*fae548d3Szrj    -d		Scan only the initialized data section(s) of object files.
28*fae548d3Szrj 
29*fae548d3Szrj    --print-file-name
30*fae548d3Szrj    -f		Print the name of the file before each string.
31*fae548d3Szrj 
32*fae548d3Szrj    --bytes=min-len
33*fae548d3Szrj    -n min-len
34*fae548d3Szrj    -min-len	Print graphic char sequences, MIN-LEN or more bytes long,
35*fae548d3Szrj 		that are followed by a NUL or a newline.  Default is 4.
36*fae548d3Szrj 
37*fae548d3Szrj    --radix={o,x,d}
38*fae548d3Szrj    -t {o,x,d}	Print the offset within the file before each string,
39*fae548d3Szrj 		in octal/hex/decimal.
40*fae548d3Szrj 
41*fae548d3Szrj   --include-all-whitespace
42*fae548d3Szrj   -w		By default tab and space are the only whitepace included in graphic
43*fae548d3Szrj 		char sequences.  This option considers all of isspace() valid.
44*fae548d3Szrj 
45*fae548d3Szrj    -o		Like -to.  (Some other implementations have -o like -to,
46*fae548d3Szrj 		others like -td.  We chose one arbitrarily.)
47*fae548d3Szrj 
48*fae548d3Szrj    --encoding={s,S,b,l,B,L}
49*fae548d3Szrj    -e {s,S,b,l,B,L}
50*fae548d3Szrj 		Select character encoding: 7-bit-character, 8-bit-character,
51*fae548d3Szrj 		bigendian 16-bit, littleendian 16-bit, bigendian 32-bit,
52*fae548d3Szrj 		littleendian 32-bit.
53*fae548d3Szrj 
54*fae548d3Szrj    --target=BFDNAME
55*fae548d3Szrj    -T {bfdname}
56*fae548d3Szrj 		Specify a non-default object file format.
57*fae548d3Szrj 
58*fae548d3Szrj   --output-separator=sep_string
59*fae548d3Szrj   -s sep_string	String used to separate parsed strings in output.
60*fae548d3Szrj 		Default is newline.
61*fae548d3Szrj 
62*fae548d3Szrj    --help
63*fae548d3Szrj    -h		Print the usage message on the standard output.
64*fae548d3Szrj 
65*fae548d3Szrj    --version
66*fae548d3Szrj    -V
67*fae548d3Szrj    -v		Print the program version number.
68*fae548d3Szrj 
69*fae548d3Szrj    Written by Richard Stallman <rms@gnu.ai.mit.edu>
70*fae548d3Szrj    and David MacKenzie <djm@gnu.ai.mit.edu>.  */
71*fae548d3Szrj 
72*fae548d3Szrj #include "sysdep.h"
73*fae548d3Szrj #include "bfd.h"
74*fae548d3Szrj #include "getopt.h"
75*fae548d3Szrj #include "libiberty.h"
76*fae548d3Szrj #include "safe-ctype.h"
77*fae548d3Szrj #include "bucomm.h"
78*fae548d3Szrj 
79*fae548d3Szrj #define STRING_ISGRAPHIC(c) \
80*fae548d3Szrj       (   (c) >= 0 \
81*fae548d3Szrj        && (c) <= 255 \
82*fae548d3Szrj        && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127) \
83*fae548d3Szrj 	   || (include_all_whitespace && ISSPACE (c))) \
84*fae548d3Szrj       )
85*fae548d3Szrj 
86*fae548d3Szrj #ifndef errno
87*fae548d3Szrj extern int errno;
88*fae548d3Szrj #endif
89*fae548d3Szrj 
90*fae548d3Szrj /* The BFD section flags that identify an initialized data section.  */
91*fae548d3Szrj #define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
92*fae548d3Szrj 
93*fae548d3Szrj /* Radix for printing addresses (must be 8, 10 or 16).  */
94*fae548d3Szrj static int address_radix;
95*fae548d3Szrj 
96*fae548d3Szrj /* Minimum length of sequence of graphic chars to trigger output.  */
97*fae548d3Szrj static int string_min;
98*fae548d3Szrj 
99*fae548d3Szrj /* Whether or not we include all whitespace as a graphic char.   */
100*fae548d3Szrj static bfd_boolean include_all_whitespace;
101*fae548d3Szrj 
102*fae548d3Szrj /* TRUE means print address within file for each string.  */
103*fae548d3Szrj static bfd_boolean print_addresses;
104*fae548d3Szrj 
105*fae548d3Szrj /* TRUE means print filename for each string.  */
106*fae548d3Szrj static bfd_boolean print_filenames;
107*fae548d3Szrj 
108*fae548d3Szrj /* TRUE means for object files scan only the data section.  */
109*fae548d3Szrj static bfd_boolean datasection_only;
110*fae548d3Szrj 
111*fae548d3Szrj /* The BFD object file format.  */
112*fae548d3Szrj static char *target;
113*fae548d3Szrj 
114*fae548d3Szrj /* The character encoding format.  */
115*fae548d3Szrj static char encoding;
116*fae548d3Szrj static int encoding_bytes;
117*fae548d3Szrj 
118*fae548d3Szrj /* Output string used to separate parsed strings  */
119*fae548d3Szrj static char *output_separator;
120*fae548d3Szrj 
121*fae548d3Szrj static struct option long_options[] =
122*fae548d3Szrj {
123*fae548d3Szrj   {"all", no_argument, NULL, 'a'},
124*fae548d3Szrj   {"data", no_argument, NULL, 'd'},
125*fae548d3Szrj   {"print-file-name", no_argument, NULL, 'f'},
126*fae548d3Szrj   {"bytes", required_argument, NULL, 'n'},
127*fae548d3Szrj   {"radix", required_argument, NULL, 't'},
128*fae548d3Szrj   {"include-all-whitespace", no_argument, NULL, 'w'},
129*fae548d3Szrj   {"encoding", required_argument, NULL, 'e'},
130*fae548d3Szrj   {"target", required_argument, NULL, 'T'},
131*fae548d3Szrj   {"output-separator", required_argument, NULL, 's'},
132*fae548d3Szrj   {"help", no_argument, NULL, 'h'},
133*fae548d3Szrj   {"version", no_argument, NULL, 'v'},
134*fae548d3Szrj   {NULL, 0, NULL, 0}
135*fae548d3Szrj };
136*fae548d3Szrj 
137*fae548d3Szrj static bfd_boolean strings_file (char *);
138*fae548d3Szrj static void print_strings (const char *, FILE *, file_ptr, int, int, char *);
139*fae548d3Szrj static void usage (FILE *, int) ATTRIBUTE_NORETURN;
140*fae548d3Szrj 
141*fae548d3Szrj int main (int, char **);
142*fae548d3Szrj 
143*fae548d3Szrj int
main(int argc,char ** argv)144*fae548d3Szrj main (int argc, char **argv)
145*fae548d3Szrj {
146*fae548d3Szrj   int optc;
147*fae548d3Szrj   int exit_status = 0;
148*fae548d3Szrj   bfd_boolean files_given = FALSE;
149*fae548d3Szrj   char *s;
150*fae548d3Szrj   int numeric_opt = 0;
151*fae548d3Szrj 
152*fae548d3Szrj #if defined (HAVE_SETLOCALE)
153*fae548d3Szrj   setlocale (LC_ALL, "");
154*fae548d3Szrj #endif
155*fae548d3Szrj   bindtextdomain (PACKAGE, LOCALEDIR);
156*fae548d3Szrj   textdomain (PACKAGE);
157*fae548d3Szrj 
158*fae548d3Szrj   program_name = argv[0];
159*fae548d3Szrj   xmalloc_set_program_name (program_name);
160*fae548d3Szrj   bfd_set_error_program_name (program_name);
161*fae548d3Szrj 
162*fae548d3Szrj   expandargv (&argc, &argv);
163*fae548d3Szrj 
164*fae548d3Szrj   string_min = 4;
165*fae548d3Szrj   include_all_whitespace = FALSE;
166*fae548d3Szrj   print_addresses = FALSE;
167*fae548d3Szrj   print_filenames = FALSE;
168*fae548d3Szrj   if (DEFAULT_STRINGS_ALL)
169*fae548d3Szrj     datasection_only = FALSE;
170*fae548d3Szrj   else
171*fae548d3Szrj     datasection_only = TRUE;
172*fae548d3Szrj   target = NULL;
173*fae548d3Szrj   encoding = 's';
174*fae548d3Szrj   output_separator = NULL;
175*fae548d3Szrj 
176*fae548d3Szrj   while ((optc = getopt_long (argc, argv, "adfhHn:wot:e:T:s:Vv0123456789",
177*fae548d3Szrj 			      long_options, (int *) 0)) != EOF)
178*fae548d3Szrj     {
179*fae548d3Szrj       switch (optc)
180*fae548d3Szrj 	{
181*fae548d3Szrj 	case 'a':
182*fae548d3Szrj 	  datasection_only = FALSE;
183*fae548d3Szrj 	  break;
184*fae548d3Szrj 
185*fae548d3Szrj 	case 'd':
186*fae548d3Szrj 	  datasection_only = TRUE;
187*fae548d3Szrj 	  break;
188*fae548d3Szrj 
189*fae548d3Szrj 	case 'f':
190*fae548d3Szrj 	  print_filenames = TRUE;
191*fae548d3Szrj 	  break;
192*fae548d3Szrj 
193*fae548d3Szrj 	case 'H':
194*fae548d3Szrj 	case 'h':
195*fae548d3Szrj 	  usage (stdout, 0);
196*fae548d3Szrj 
197*fae548d3Szrj 	case 'n':
198*fae548d3Szrj 	  string_min = (int) strtoul (optarg, &s, 0);
199*fae548d3Szrj 	  if (s != NULL && *s != 0)
200*fae548d3Szrj 	    fatal (_("invalid integer argument %s"), optarg);
201*fae548d3Szrj 	  break;
202*fae548d3Szrj 
203*fae548d3Szrj 	case 'w':
204*fae548d3Szrj 	  include_all_whitespace = TRUE;
205*fae548d3Szrj 	  break;
206*fae548d3Szrj 
207*fae548d3Szrj 	case 'o':
208*fae548d3Szrj 	  print_addresses = TRUE;
209*fae548d3Szrj 	  address_radix = 8;
210*fae548d3Szrj 	  break;
211*fae548d3Szrj 
212*fae548d3Szrj 	case 't':
213*fae548d3Szrj 	  print_addresses = TRUE;
214*fae548d3Szrj 	  if (optarg[1] != '\0')
215*fae548d3Szrj 	    usage (stderr, 1);
216*fae548d3Szrj 	  switch (optarg[0])
217*fae548d3Szrj 	    {
218*fae548d3Szrj 	    case 'o':
219*fae548d3Szrj 	      address_radix = 8;
220*fae548d3Szrj 	      break;
221*fae548d3Szrj 
222*fae548d3Szrj 	    case 'd':
223*fae548d3Szrj 	      address_radix = 10;
224*fae548d3Szrj 	      break;
225*fae548d3Szrj 
226*fae548d3Szrj 	    case 'x':
227*fae548d3Szrj 	      address_radix = 16;
228*fae548d3Szrj 	      break;
229*fae548d3Szrj 
230*fae548d3Szrj 	    default:
231*fae548d3Szrj 	      usage (stderr, 1);
232*fae548d3Szrj 	    }
233*fae548d3Szrj 	  break;
234*fae548d3Szrj 
235*fae548d3Szrj 	case 'T':
236*fae548d3Szrj 	  target = optarg;
237*fae548d3Szrj 	  break;
238*fae548d3Szrj 
239*fae548d3Szrj 	case 'e':
240*fae548d3Szrj 	  if (optarg[1] != '\0')
241*fae548d3Szrj 	    usage (stderr, 1);
242*fae548d3Szrj 	  encoding = optarg[0];
243*fae548d3Szrj 	  break;
244*fae548d3Szrj 
245*fae548d3Szrj 	case 's':
246*fae548d3Szrj 	  output_separator = optarg;
247*fae548d3Szrj           break;
248*fae548d3Szrj 
249*fae548d3Szrj 	case 'V':
250*fae548d3Szrj 	case 'v':
251*fae548d3Szrj 	  print_version ("strings");
252*fae548d3Szrj 	  break;
253*fae548d3Szrj 
254*fae548d3Szrj 	case '?':
255*fae548d3Szrj 	  usage (stderr, 1);
256*fae548d3Szrj 
257*fae548d3Szrj 	default:
258*fae548d3Szrj 	  numeric_opt = optind;
259*fae548d3Szrj 	  break;
260*fae548d3Szrj 	}
261*fae548d3Szrj     }
262*fae548d3Szrj 
263*fae548d3Szrj   if (numeric_opt != 0)
264*fae548d3Szrj     {
265*fae548d3Szrj       string_min = (int) strtoul (argv[numeric_opt - 1] + 1, &s, 0);
266*fae548d3Szrj       if (s != NULL && *s != 0)
267*fae548d3Szrj 	fatal (_("invalid integer argument %s"), argv[numeric_opt - 1] + 1);
268*fae548d3Szrj     }
269*fae548d3Szrj   if (string_min < 1)
270*fae548d3Szrj     fatal (_("invalid minimum string length %d"), string_min);
271*fae548d3Szrj 
272*fae548d3Szrj   switch (encoding)
273*fae548d3Szrj     {
274*fae548d3Szrj     case 'S':
275*fae548d3Szrj     case 's':
276*fae548d3Szrj       encoding_bytes = 1;
277*fae548d3Szrj       break;
278*fae548d3Szrj     case 'b':
279*fae548d3Szrj     case 'l':
280*fae548d3Szrj       encoding_bytes = 2;
281*fae548d3Szrj       break;
282*fae548d3Szrj     case 'B':
283*fae548d3Szrj     case 'L':
284*fae548d3Szrj       encoding_bytes = 4;
285*fae548d3Szrj       break;
286*fae548d3Szrj     default:
287*fae548d3Szrj       usage (stderr, 1);
288*fae548d3Szrj     }
289*fae548d3Szrj 
290*fae548d3Szrj   if (bfd_init () != BFD_INIT_MAGIC)
291*fae548d3Szrj     fatal (_("fatal error: libbfd ABI mismatch"));
292*fae548d3Szrj   set_default_bfd_target ();
293*fae548d3Szrj 
294*fae548d3Szrj   if (optind >= argc)
295*fae548d3Szrj     {
296*fae548d3Szrj       datasection_only = FALSE;
297*fae548d3Szrj       SET_BINARY (fileno (stdin));
298*fae548d3Szrj       print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
299*fae548d3Szrj       files_given = TRUE;
300*fae548d3Szrj     }
301*fae548d3Szrj   else
302*fae548d3Szrj     {
303*fae548d3Szrj       for (; optind < argc; ++optind)
304*fae548d3Szrj 	{
305*fae548d3Szrj 	  if (strcmp (argv[optind], "-") == 0)
306*fae548d3Szrj 	    datasection_only = FALSE;
307*fae548d3Szrj 	  else
308*fae548d3Szrj 	    {
309*fae548d3Szrj 	      files_given = TRUE;
310*fae548d3Szrj 	      exit_status |= !strings_file (argv[optind]);
311*fae548d3Szrj 	    }
312*fae548d3Szrj 	}
313*fae548d3Szrj     }
314*fae548d3Szrj 
315*fae548d3Szrj   if (!files_given)
316*fae548d3Szrj     usage (stderr, 1);
317*fae548d3Szrj 
318*fae548d3Szrj   return (exit_status);
319*fae548d3Szrj }
320*fae548d3Szrj 
321*fae548d3Szrj /* Scan section SECT of the file ABFD, whose printable name is
322*fae548d3Szrj    FILENAME.  If it contains initialized data set GOT_A_SECTION and
323*fae548d3Szrj    print the strings in it.  */
324*fae548d3Szrj 
325*fae548d3Szrj static void
strings_a_section(bfd * abfd,asection * sect,const char * filename,bfd_boolean * got_a_section)326*fae548d3Szrj strings_a_section (bfd *abfd, asection *sect, const char *filename,
327*fae548d3Szrj 		   bfd_boolean *got_a_section)
328*fae548d3Szrj {
329*fae548d3Szrj   bfd_size_type sectsize;
330*fae548d3Szrj   bfd_byte *mem;
331*fae548d3Szrj 
332*fae548d3Szrj   if ((sect->flags & DATA_FLAGS) != DATA_FLAGS)
333*fae548d3Szrj     return;
334*fae548d3Szrj 
335*fae548d3Szrj   sectsize = bfd_section_size (sect);
336*fae548d3Szrj   if (sectsize == 0)
337*fae548d3Szrj     return;
338*fae548d3Szrj 
339*fae548d3Szrj   if (!bfd_malloc_and_get_section (abfd, sect, &mem))
340*fae548d3Szrj     {
341*fae548d3Szrj       non_fatal (_("%s: Reading section %s failed: %s"),
342*fae548d3Szrj 		 filename, sect->name, bfd_errmsg (bfd_get_error ()));
343*fae548d3Szrj       return;
344*fae548d3Szrj     }
345*fae548d3Szrj 
346*fae548d3Szrj   *got_a_section = TRUE;
347*fae548d3Szrj   print_strings (filename, NULL, sect->filepos, 0, sectsize, (char *) mem);
348*fae548d3Szrj   free (mem);
349*fae548d3Szrj }
350*fae548d3Szrj 
351*fae548d3Szrj /* Scan all of the sections in FILE, and print the strings
352*fae548d3Szrj    in the initialized data section(s).
353*fae548d3Szrj 
354*fae548d3Szrj    Return TRUE if successful,
355*fae548d3Szrj    FALSE if not (such as if FILE is not an object file).  */
356*fae548d3Szrj 
357*fae548d3Szrj static bfd_boolean
strings_object_file(const char * file)358*fae548d3Szrj strings_object_file (const char *file)
359*fae548d3Szrj {
360*fae548d3Szrj   bfd *abfd;
361*fae548d3Szrj   asection *s;
362*fae548d3Szrj   bfd_boolean got_a_section;
363*fae548d3Szrj 
364*fae548d3Szrj   abfd = bfd_openr (file, target);
365*fae548d3Szrj 
366*fae548d3Szrj   if (abfd == NULL)
367*fae548d3Szrj     /* Treat the file as a non-object file.  */
368*fae548d3Szrj     return FALSE;
369*fae548d3Szrj 
370*fae548d3Szrj   /* This call is mainly for its side effect of reading in the sections.
371*fae548d3Szrj      We follow the traditional behavior of `strings' in that we don't
372*fae548d3Szrj      complain if we don't recognize a file to be an object file.  */
373*fae548d3Szrj   if (!bfd_check_format (abfd, bfd_object))
374*fae548d3Szrj     {
375*fae548d3Szrj       bfd_close (abfd);
376*fae548d3Szrj       return FALSE;
377*fae548d3Szrj     }
378*fae548d3Szrj 
379*fae548d3Szrj   got_a_section = FALSE;
380*fae548d3Szrj   for (s = abfd->sections; s != NULL; s = s->next)
381*fae548d3Szrj     strings_a_section (abfd, s, file, &got_a_section);
382*fae548d3Szrj 
383*fae548d3Szrj   if (!bfd_close (abfd))
384*fae548d3Szrj     {
385*fae548d3Szrj       bfd_nonfatal (file);
386*fae548d3Szrj       return FALSE;
387*fae548d3Szrj     }
388*fae548d3Szrj 
389*fae548d3Szrj   return got_a_section;
390*fae548d3Szrj }
391*fae548d3Szrj 
392*fae548d3Szrj /* Print the strings in FILE.  Return TRUE if ok, FALSE if an error occurs.  */
393*fae548d3Szrj 
394*fae548d3Szrj static bfd_boolean
strings_file(char * file)395*fae548d3Szrj strings_file (char *file)
396*fae548d3Szrj {
397*fae548d3Szrj   struct stat st;
398*fae548d3Szrj 
399*fae548d3Szrj   /* get_file_size does not support non-S_ISREG files.  */
400*fae548d3Szrj 
401*fae548d3Szrj   if (stat (file, &st) < 0)
402*fae548d3Szrj     {
403*fae548d3Szrj       if (errno == ENOENT)
404*fae548d3Szrj 	non_fatal (_("'%s': No such file"), file);
405*fae548d3Szrj       else
406*fae548d3Szrj 	non_fatal (_("Warning: could not locate '%s'.  reason: %s"),
407*fae548d3Szrj 		   file, strerror (errno));
408*fae548d3Szrj       return FALSE;
409*fae548d3Szrj     }
410*fae548d3Szrj   else if (S_ISDIR (st.st_mode))
411*fae548d3Szrj     {
412*fae548d3Szrj       non_fatal (_("Warning: '%s' is a directory"), file);
413*fae548d3Szrj       return FALSE;
414*fae548d3Szrj     }
415*fae548d3Szrj 
416*fae548d3Szrj   /* If we weren't told to scan the whole file,
417*fae548d3Szrj      try to open it as an object file and only look at
418*fae548d3Szrj      initialized data sections.  If that fails, fall back to the
419*fae548d3Szrj      whole file.  */
420*fae548d3Szrj   if (!datasection_only || !strings_object_file (file))
421*fae548d3Szrj     {
422*fae548d3Szrj       FILE *stream;
423*fae548d3Szrj 
424*fae548d3Szrj       stream = fopen (file, FOPEN_RB);
425*fae548d3Szrj       if (stream == NULL)
426*fae548d3Szrj 	{
427*fae548d3Szrj 	  fprintf (stderr, "%s: ", program_name);
428*fae548d3Szrj 	  perror (file);
429*fae548d3Szrj 	  return FALSE;
430*fae548d3Szrj 	}
431*fae548d3Szrj 
432*fae548d3Szrj       print_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
433*fae548d3Szrj 
434*fae548d3Szrj       if (fclose (stream) == EOF)
435*fae548d3Szrj 	{
436*fae548d3Szrj 	  fprintf (stderr, "%s: ", program_name);
437*fae548d3Szrj 	  perror (file);
438*fae548d3Szrj 	  return FALSE;
439*fae548d3Szrj 	}
440*fae548d3Szrj     }
441*fae548d3Szrj 
442*fae548d3Szrj   return TRUE;
443*fae548d3Szrj }
444*fae548d3Szrj 
445*fae548d3Szrj /* Read the next character, return EOF if none available.
446*fae548d3Szrj    Assume that STREAM is positioned so that the next byte read
447*fae548d3Szrj    is at address ADDRESS in the file.
448*fae548d3Szrj 
449*fae548d3Szrj    If STREAM is NULL, do not read from it.
450*fae548d3Szrj    The caller can supply a buffer of characters
451*fae548d3Szrj    to be processed before the data in STREAM.
452*fae548d3Szrj    MAGIC is the address of the buffer and
453*fae548d3Szrj    MAGICCOUNT is how many characters are in it.  */
454*fae548d3Szrj 
455*fae548d3Szrj static long
get_char(FILE * stream,file_ptr * address,int * magiccount,char ** magic)456*fae548d3Szrj get_char (FILE *stream, file_ptr *address, int *magiccount, char **magic)
457*fae548d3Szrj {
458*fae548d3Szrj   int c, i;
459*fae548d3Szrj   long r = 0;
460*fae548d3Szrj 
461*fae548d3Szrj   for (i = 0; i < encoding_bytes; i++)
462*fae548d3Szrj     {
463*fae548d3Szrj       if (*magiccount)
464*fae548d3Szrj 	{
465*fae548d3Szrj 	  (*magiccount)--;
466*fae548d3Szrj 	  c = *(*magic)++;
467*fae548d3Szrj 	}
468*fae548d3Szrj       else
469*fae548d3Szrj 	{
470*fae548d3Szrj 	  if (stream == NULL)
471*fae548d3Szrj 	    return EOF;
472*fae548d3Szrj 
473*fae548d3Szrj 	  /* Only use getc_unlocked if we found a declaration for it.
474*fae548d3Szrj 	     Otherwise, libc is not thread safe by default, and we
475*fae548d3Szrj 	     should not use it.  */
476*fae548d3Szrj 
477*fae548d3Szrj #if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_GETC_UNLOCKED
478*fae548d3Szrj 	  c = getc_unlocked (stream);
479*fae548d3Szrj #else
480*fae548d3Szrj 	  c = getc (stream);
481*fae548d3Szrj #endif
482*fae548d3Szrj 	  if (c == EOF)
483*fae548d3Szrj 	    return EOF;
484*fae548d3Szrj 	}
485*fae548d3Szrj 
486*fae548d3Szrj       (*address)++;
487*fae548d3Szrj       r = (r << 8) | (c & 0xff);
488*fae548d3Szrj     }
489*fae548d3Szrj 
490*fae548d3Szrj   switch (encoding)
491*fae548d3Szrj     {
492*fae548d3Szrj     default:
493*fae548d3Szrj       break;
494*fae548d3Szrj     case 'l':
495*fae548d3Szrj       r = ((r & 0xff) << 8) | ((r & 0xff00) >> 8);
496*fae548d3Szrj       break;
497*fae548d3Szrj     case 'L':
498*fae548d3Szrj       r = (((r & 0xff) << 24) | ((r & 0xff00) << 8)
499*fae548d3Szrj 	   | ((r & 0xff0000) >> 8) | ((r & 0xff000000) >> 24));
500*fae548d3Szrj       break;
501*fae548d3Szrj     }
502*fae548d3Szrj 
503*fae548d3Szrj   return r;
504*fae548d3Szrj }
505*fae548d3Szrj 
506*fae548d3Szrj /* Throw away one byte of a (possibly) multi-byte char C, updating
507*fae548d3Szrj    address and buffer to suit.  */
508*fae548d3Szrj 
509*fae548d3Szrj static void
unget_part_char(long c,file_ptr * address,int * magiccount,char ** magic)510*fae548d3Szrj unget_part_char (long c, file_ptr *address, int *magiccount, char **magic)
511*fae548d3Szrj {
512*fae548d3Szrj   static char tmp[4];
513*fae548d3Szrj 
514*fae548d3Szrj   if (encoding_bytes > 1)
515*fae548d3Szrj     {
516*fae548d3Szrj       *address -= encoding_bytes - 1;
517*fae548d3Szrj 
518*fae548d3Szrj       if (*magiccount == 0)
519*fae548d3Szrj 	{
520*fae548d3Szrj 	  /* If no magic buffer exists, use temp buffer.  */
521*fae548d3Szrj 	  switch (encoding)
522*fae548d3Szrj 	    {
523*fae548d3Szrj 	    default:
524*fae548d3Szrj 	      break;
525*fae548d3Szrj 	    case 'b':
526*fae548d3Szrj 	      tmp[0] = c & 0xff;
527*fae548d3Szrj 	      *magiccount = 1;
528*fae548d3Szrj 	      break;
529*fae548d3Szrj 	    case 'l':
530*fae548d3Szrj 	      tmp[0] = (c >> 8) & 0xff;
531*fae548d3Szrj 	      *magiccount = 1;
532*fae548d3Szrj 	      break;
533*fae548d3Szrj 	    case 'B':
534*fae548d3Szrj 	      tmp[0] = (c >> 16) & 0xff;
535*fae548d3Szrj 	      tmp[1] = (c >> 8) & 0xff;
536*fae548d3Szrj 	      tmp[2] = c & 0xff;
537*fae548d3Szrj 	      *magiccount = 3;
538*fae548d3Szrj 	      break;
539*fae548d3Szrj 	    case 'L':
540*fae548d3Szrj 	      tmp[0] = (c >> 8) & 0xff;
541*fae548d3Szrj 	      tmp[1] = (c >> 16) & 0xff;
542*fae548d3Szrj 	      tmp[2] = (c >> 24) & 0xff;
543*fae548d3Szrj 	      *magiccount = 3;
544*fae548d3Szrj 	      break;
545*fae548d3Szrj 	    }
546*fae548d3Szrj 	  *magic = tmp;
547*fae548d3Szrj 	}
548*fae548d3Szrj       else
549*fae548d3Szrj 	{
550*fae548d3Szrj 	  /* If magic buffer exists, rewind.  */
551*fae548d3Szrj 	  *magic -= encoding_bytes - 1;
552*fae548d3Szrj 	  *magiccount += encoding_bytes - 1;
553*fae548d3Szrj 	}
554*fae548d3Szrj     }
555*fae548d3Szrj }
556*fae548d3Szrj 
557*fae548d3Szrj /* Find the strings in file FILENAME, read from STREAM.
558*fae548d3Szrj    Assume that STREAM is positioned so that the next byte read
559*fae548d3Szrj    is at address ADDRESS in the file.
560*fae548d3Szrj    Stop reading at address STOP_POINT in the file, if nonzero.
561*fae548d3Szrj 
562*fae548d3Szrj    If STREAM is NULL, do not read from it.
563*fae548d3Szrj    The caller can supply a buffer of characters
564*fae548d3Szrj    to be processed before the data in STREAM.
565*fae548d3Szrj    MAGIC is the address of the buffer and
566*fae548d3Szrj    MAGICCOUNT is how many characters are in it.
567*fae548d3Szrj    Those characters come at address ADDRESS and the data in STREAM follow.  */
568*fae548d3Szrj 
569*fae548d3Szrj static void
print_strings(const char * filename,FILE * stream,file_ptr address,int stop_point,int magiccount,char * magic)570*fae548d3Szrj print_strings (const char *filename, FILE *stream, file_ptr address,
571*fae548d3Szrj 	       int stop_point, int magiccount, char *magic)
572*fae548d3Szrj {
573*fae548d3Szrj   char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
574*fae548d3Szrj 
575*fae548d3Szrj   while (1)
576*fae548d3Szrj     {
577*fae548d3Szrj       file_ptr start;
578*fae548d3Szrj       int i;
579*fae548d3Szrj       long c;
580*fae548d3Szrj 
581*fae548d3Szrj       /* See if the next `string_min' chars are all graphic chars.  */
582*fae548d3Szrj     tryline:
583*fae548d3Szrj       if (stop_point && address >= stop_point)
584*fae548d3Szrj 	break;
585*fae548d3Szrj       start = address;
586*fae548d3Szrj       for (i = 0; i < string_min; i++)
587*fae548d3Szrj 	{
588*fae548d3Szrj 	  c = get_char (stream, &address, &magiccount, &magic);
589*fae548d3Szrj 	  if (c == EOF)
590*fae548d3Szrj 	    {
591*fae548d3Szrj 	      free (buf);
592*fae548d3Szrj 	      return;
593*fae548d3Szrj 	    }
594*fae548d3Szrj 
595*fae548d3Szrj 	  if (! STRING_ISGRAPHIC (c))
596*fae548d3Szrj 	    {
597*fae548d3Szrj 	      /* Found a non-graphic.  Try again starting with next byte.  */
598*fae548d3Szrj 	      unget_part_char (c, &address, &magiccount, &magic);
599*fae548d3Szrj 	      goto tryline;
600*fae548d3Szrj 	    }
601*fae548d3Szrj 	  buf[i] = c;
602*fae548d3Szrj 	}
603*fae548d3Szrj 
604*fae548d3Szrj       /* We found a run of `string_min' graphic characters.  Print up
605*fae548d3Szrj 	 to the next non-graphic character.  */
606*fae548d3Szrj 
607*fae548d3Szrj       if (print_filenames)
608*fae548d3Szrj 	printf ("%s: ", filename);
609*fae548d3Szrj       if (print_addresses)
610*fae548d3Szrj 	switch (address_radix)
611*fae548d3Szrj 	  {
612*fae548d3Szrj 	  case 8:
613*fae548d3Szrj #ifdef HAVE_LONG_LONG
614*fae548d3Szrj 	    if (sizeof (start) > sizeof (long))
615*fae548d3Szrj 	      {
616*fae548d3Szrj # ifndef __MSVCRT__
617*fae548d3Szrj 		printf ("%7llo ", (unsigned long long) start);
618*fae548d3Szrj # else
619*fae548d3Szrj 		printf ("%7I64o ", (unsigned long long) start);
620*fae548d3Szrj # endif
621*fae548d3Szrj 	      }
622*fae548d3Szrj 	    else
623*fae548d3Szrj #elif !BFD_HOST_64BIT_LONG
624*fae548d3Szrj 	      if (start != (unsigned long) start)
625*fae548d3Szrj 		printf ("++%7lo ", (unsigned long) start);
626*fae548d3Szrj 	      else
627*fae548d3Szrj #endif
628*fae548d3Szrj 		printf ("%7lo ", (unsigned long) start);
629*fae548d3Szrj 	    break;
630*fae548d3Szrj 
631*fae548d3Szrj 	  case 10:
632*fae548d3Szrj #ifdef HAVE_LONG_LONG
633*fae548d3Szrj 	    if (sizeof (start) > sizeof (long))
634*fae548d3Szrj 	      {
635*fae548d3Szrj # ifndef __MSVCRT__
636*fae548d3Szrj 		printf ("%7llu ", (unsigned long long) start);
637*fae548d3Szrj # else
638*fae548d3Szrj 		printf ("%7I64d ", (unsigned long long) start);
639*fae548d3Szrj # endif
640*fae548d3Szrj 	      }
641*fae548d3Szrj 	    else
642*fae548d3Szrj #elif !BFD_HOST_64BIT_LONG
643*fae548d3Szrj 	      if (start != (unsigned long) start)
644*fae548d3Szrj 		printf ("++%7lu ", (unsigned long) start);
645*fae548d3Szrj 	      else
646*fae548d3Szrj #endif
647*fae548d3Szrj 		printf ("%7ld ", (long) start);
648*fae548d3Szrj 	    break;
649*fae548d3Szrj 
650*fae548d3Szrj 	  case 16:
651*fae548d3Szrj #ifdef HAVE_LONG_LONG
652*fae548d3Szrj 	    if (sizeof (start) > sizeof (long))
653*fae548d3Szrj 	      {
654*fae548d3Szrj # ifndef __MSVCRT__
655*fae548d3Szrj 		printf ("%7llx ", (unsigned long long) start);
656*fae548d3Szrj # else
657*fae548d3Szrj 		printf ("%7I64x ", (unsigned long long) start);
658*fae548d3Szrj # endif
659*fae548d3Szrj 	      }
660*fae548d3Szrj 	    else
661*fae548d3Szrj #elif !BFD_HOST_64BIT_LONG
662*fae548d3Szrj 	      if (start != (unsigned long) start)
663*fae548d3Szrj 		printf ("%lx%8.8lx ", (unsigned long) (start >> 32),
664*fae548d3Szrj 			(unsigned long) (start & 0xffffffff));
665*fae548d3Szrj 	      else
666*fae548d3Szrj #endif
667*fae548d3Szrj 		printf ("%7lx ", (unsigned long) start);
668*fae548d3Szrj 	    break;
669*fae548d3Szrj 	  }
670*fae548d3Szrj 
671*fae548d3Szrj       buf[i] = '\0';
672*fae548d3Szrj       fputs (buf, stdout);
673*fae548d3Szrj 
674*fae548d3Szrj       while (1)
675*fae548d3Szrj 	{
676*fae548d3Szrj 	  c = get_char (stream, &address, &magiccount, &magic);
677*fae548d3Szrj 	  if (c == EOF)
678*fae548d3Szrj 	    break;
679*fae548d3Szrj 	  if (! STRING_ISGRAPHIC (c))
680*fae548d3Szrj 	    {
681*fae548d3Szrj 	      unget_part_char (c, &address, &magiccount, &magic);
682*fae548d3Szrj 	      break;
683*fae548d3Szrj 	    }
684*fae548d3Szrj 	  putchar (c);
685*fae548d3Szrj 	}
686*fae548d3Szrj 
687*fae548d3Szrj       if (output_separator)
688*fae548d3Szrj 	fputs (output_separator, stdout);
689*fae548d3Szrj       else
690*fae548d3Szrj 	putchar ('\n');
691*fae548d3Szrj     }
692*fae548d3Szrj   free (buf);
693*fae548d3Szrj }
694*fae548d3Szrj 
695*fae548d3Szrj static void
usage(FILE * stream,int status)696*fae548d3Szrj usage (FILE *stream, int status)
697*fae548d3Szrj {
698*fae548d3Szrj   fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
699*fae548d3Szrj   fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n"));
700*fae548d3Szrj   fprintf (stream, _(" The options are:\n"));
701*fae548d3Szrj 
702*fae548d3Szrj   if (DEFAULT_STRINGS_ALL)
703*fae548d3Szrj     fprintf (stream, _("\
704*fae548d3Szrj   -a - --all                Scan the entire file, not just the data section [default]\n\
705*fae548d3Szrj   -d --data                 Only scan the data sections in the file\n"));
706*fae548d3Szrj   else
707*fae548d3Szrj     fprintf (stream, _("\
708*fae548d3Szrj   -a - --all                Scan the entire file, not just the data section\n\
709*fae548d3Szrj   -d --data                 Only scan the data sections in the file [default]\n"));
710*fae548d3Szrj 
711*fae548d3Szrj   fprintf (stream, _("\
712*fae548d3Szrj   -f --print-file-name      Print the name of the file before each string\n\
713*fae548d3Szrj   -n --bytes=[number]       Locate & print any NUL-terminated sequence of at\n\
714*fae548d3Szrj   -<number>                   least [number] characters (default 4).\n\
715*fae548d3Szrj   -t --radix={o,d,x}        Print the location of the string in base 8, 10 or 16\n\
716*fae548d3Szrj   -w --include-all-whitespace Include all whitespace as valid string characters\n\
717*fae548d3Szrj   -o                        An alias for --radix=o\n\
718*fae548d3Szrj   -T --target=<BFDNAME>     Specify the binary file format\n\
719*fae548d3Szrj   -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\
720*fae548d3Szrj                             s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
721*fae548d3Szrj   -s --output-separator=<string> String used to separate strings in output.\n\
722*fae548d3Szrj   @<file>                   Read options from <file>\n\
723*fae548d3Szrj   -h --help                 Display this information\n\
724*fae548d3Szrj   -v -V --version           Print the program's version number\n"));
725*fae548d3Szrj   list_supported_targets (program_name, stream);
726*fae548d3Szrj   if (REPORT_BUGS_TO[0] && status == 0)
727*fae548d3Szrj     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
728*fae548d3Szrj   exit (status);
729*fae548d3Szrj }
730