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