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