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