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