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