* Fix a couple of typos.
[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;
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",
148 program_name, optarg);
149 exit (1);
150 }
151 break;
152
153 case 'o':
154 print_addresses = true;
155 address_radix = 8;
156 break;
157
158 case 't':
159 print_addresses = true;
160 if (optarg[1] != '\0')
161 usage ();
162 switch (optarg[0])
163 {
164 case 'o':
165 address_radix = 8;
166 break;
167
168 case 'd':
169 address_radix = 10;
170 break;
171
172 case 'x':
173 address_radix = 16;
174 break;
175
176 default:
177 usage ();
178 }
179 break;
180
181 case 'v':
182 printf ("%s version %s\n", program_name, program_version);
183 exit (0);
184
185 case '?':
186 usage (stderr);
187
188 default:
189 if (string_min < 0)
190 string_min = optc;
191 else
192 string_min = string_min * 10 + optc - '0';
193 break;
194 }
195 }
196
197 if (string_min < 0)
198 string_min = 4;
199
200 bfd_init ();
201 devnull = fopen ("/dev/null", "r");
202 if (devnull == NULL)
203 {
204 fprintf (stderr, "%s: ", program_name);
205 perror ("/dev/null");
206 exit (1);
207 }
208
209 for (; optind < argc; ++optind)
210 {
211 if (!strcmp (argv[optind], "-"))
212 datasection_only = false;
213 else
214 {
215 files_given = true;
216 exit_status |= (strings_file (argv[optind]) == false);
217 }
218 }
219
220 if (files_given == false)
221 usage (stderr);
222
223 exit (exit_status);
224 }
225 \f
226 /* Scan the sections of the file ABFD, whose printable name is FILE.
227 If any of them contain initialized data,
228 set `got_a_section' and print the strings in them. */
229
230 static void
231 strings_a_section (abfd, sect, file)
232 bfd *abfd;
233 asection *sect;
234 PTR file;
235 {
236 if ((sect->flags & DATA_FLAGS) == DATA_FLAGS)
237 {
238 bfd_size_type sz = bfd_get_section_size_before_reloc (sect);
239 PTR mem = xmalloc (sz);
240 if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sz))
241 {
242 got_a_section = true;
243 dump_strings (file, devnull, sect->filepos, 0, sz, mem);
244 }
245 free (mem);
246 }
247 }
248
249 /* Print the strings in the initialized data section of FILE.
250 Return true if successful,
251 false if not (such as if FILE is not an object file). */
252
253 static boolean
254 strings_object_file (file)
255 char *file;
256 {
257 bfd *abfd = bfd_openr (file, NULL);
258
259 if (abfd == NULL)
260 {
261 if (bfd_error != system_call_error)
262 {
263 /* Out of memory, or an invalid target is specified by the
264 GNUTARGET environment variable. */
265 fprintf (stderr, "%s: ", program_name);
266 bfd_perror (file);
267 }
268 return false;
269 }
270
271 /* For some reason, without this call, the BFD has no sections.
272 This call is only for the side effect of reading in the sections. */
273 bfd_check_format (abfd, bfd_object);
274
275 got_a_section = false;
276 bfd_map_over_sections (abfd, strings_a_section, file);
277
278 if (!bfd_close (abfd))
279 {
280 fprintf (stderr, "%s: ", program_name);
281 bfd_perror (file);
282 return false;
283 }
284
285 return got_a_section;
286 }
287
288 /* Print the strings in FILE. Return true if ok, false if an error occurs. */
289
290 static boolean
291 strings_file (file)
292 char *file;
293 {
294 /* If we weren't told to scan the whole file,
295 try to open it as an object file and only look at
296 initialized data sections. If that fails, fall back to the
297 whole file. */
298 if (!datasection_only || !strings_object_file (file))
299 {
300 FILE *stream;
301
302 stream = fopen (file, "r");
303 if (stream == NULL)
304 {
305 fprintf (stderr, "%s: ", program_name);
306 perror (file);
307 return false;
308 }
309
310 dump_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
311
312 if (fclose (stream) == EOF)
313 {
314 fprintf (stderr, "%s: ", program_name);
315 perror (file);
316 return false;
317 }
318 }
319
320 return true;
321 }
322 \f
323 /* Find the strings in file FILENAME, read from STREAM.
324 Assume that STREAM is positioned so that the next byte read
325 is at address ADDRESS in the file.
326 Stop reading at address STOP_POINT in the file, if nonzero.
327
328 Optionally the caller can supply a buffer of characters
329 to be processed before the data in STREAM.
330 MAGIC is the address of the buffer and
331 MAGICCOUNT is how many characters are in it.
332 Those characters come at address ADDRESS and the data in STREAM follow. */
333
334 static void
335 dump_strings (filename, stream, address, stop_point, magiccount, magic)
336 char *filename;
337 FILE *stream;
338 file_ptr address;
339 int stop_point;
340 int magiccount;
341 char *magic;
342 {
343 int bufsize = 100;
344 char *buf = (char *) xmalloc (bufsize);
345
346 while (1)
347 {
348 int i;
349 int c;
350
351 /* See if the next `string_min' chars are all graphic chars. */
352 tryline:
353 if (stop_point && address >= stop_point)
354 break;
355 for (i = 0; i < string_min; i++)
356 {
357 if (magiccount)
358 {
359 magiccount--;
360 c = *magic++;
361 }
362 else
363 {
364 c = getc (stream);
365 if (c < 0)
366 return;
367 }
368 address++;
369 if (!isgraphic (c))
370 /* Found a non-graphic. Try again starting with next char. */
371 goto tryline;
372 buf[i] = c;
373 }
374
375 /* We found a run of `string_min' graphic characters.
376 Now see if it is terminated with a NUL byte or a newline. */
377 while (1)
378 {
379 if (i == bufsize)
380 {
381 bufsize *= 2;
382 buf = (char *) xrealloc (buf, bufsize);
383 }
384 if (magiccount)
385 {
386 magiccount--;
387 c = *magic++;
388 }
389 else
390 {
391 c = getc (stream);
392 if (c < 0)
393 return;
394 }
395 address++;
396 if (c == '\0' || c == '\n')
397 break; /* It is; print this string. */
398 if (!isgraphic (c))
399 goto tryline; /* It isn't; give up on this string. */
400 buf[i++] = c; /* The string continues; store it all. */
401 }
402
403 /* If we get here, the string is all graphics and properly terminated,
404 so print it. It is all in `buf' and `i' is its length. */
405 buf[i] = '\0';
406 if (print_filenames)
407 printf ("%s: ", filename);
408 if (print_addresses)
409 switch (address_radix)
410 {
411 case 8:
412 printf ("%7lo ", address - i - 1);
413 break;
414
415 case 10:
416 printf ("%7ld ", address - i - 1);
417 break;
418
419 case 16:
420 printf ("%7lx ", address - i - 1);
421 break;
422 }
423
424 for (i = 0; (c = buf[i]) != '\0'; i++)
425 switch (c)
426 {
427 case '\n':
428 printf ("\\n");
429 break;
430 case '\t':
431 printf ("\\t");
432 break;
433 case '\f':
434 printf ("\\f");
435 break;
436 case '\b':
437 printf ("\\b");
438 break;
439 case '\r':
440 printf ("\\r");
441 break;
442 default:
443 putchar (c);
444 }
445 putchar ('\n');
446 }
447 }
448 \f
449 /* Parse string S as an integer, using decimal radix by default,
450 but allowing octal and hex numbers as in C. */
451
452 static int
453 integer_arg (s)
454 char *s;
455 {
456 int value;
457 int radix = 10;
458 char *p = s;
459 int c;
460
461 if (*p != '0')
462 radix = 10;
463 else if (*++p == 'x')
464 {
465 radix = 16;
466 p++;
467 }
468 else
469 radix = 8;
470
471 value = 0;
472 while (((c = *p++) >= '0' && c <= '9')
473 || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
474 {
475 value *= radix;
476 if (c >= '0' && c <= '9')
477 value += c - '0';
478 else
479 value += (c & ~40) - 'A';
480 }
481
482 if (c == 'b')
483 value *= 512;
484 else if (c == 'B')
485 value *= 1024;
486 else
487 p--;
488
489 if (*p)
490 {
491 fprintf (stderr, "%s: invalid integer argument %s\n", program_name, s);
492 exit (1);
493 }
494 return value;
495 }
496
497 static void
498 usage (stream)
499 FILE *stream;
500 {
501 fprintf (stream, "\
502 Usage: %s [-afhov] [-n min-len] [-min-len] [-t {o,x,d}] [-]\n\
503 [--all] [--print-file-name] [--bytes=min-len] [--radix={o,x,d}]\n\
504 [--help] [--version] file...\n",
505 program_name);
506 exit (1);
507 }
This page took 0.041 seconds and 5 git commands to generate.