]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/strings.c
import gdb-1999-07-07 pre reformat
[thirdparty/binutils-gdb.git] / binutils / strings.c
CommitLineData
252b5132
RH
1/* strings -- print the strings of printable characters in files
2 Copyright (C) 1993, 94, 95, 96, 97, 98, 1999 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., 59 Temple Place - Suite 330, Boston, MA
17 02111-1307, USA. */
18\f
19/* Usage: strings [options] file...
20
21 Options:
22 --all
23 -a
24 - Do not scan only the initialized data section of object files.
25
26 --print-file-name
27 -f Print the name of the file before each string.
28
29 --bytes=min-len
30 -n min-len
31 -min-len Print graphic char sequences, MIN-LEN or more bytes long,
32 that are followed by a NUL or a newline. Default is 4.
33
34 --radix={o,x,d}
35 -t {o,x,d} Print the offset within the file before each string,
36 in octal/hex/decimal.
37
38 -o Like -to. (Some other implementations have -o like -to,
39 others like -td. We chose one arbitrarily.)
40
41 --target=BFDNAME
42 Specify a non-default object file format.
43
44 --help
45 -h Print the usage message on the standard output.
46
47 --version
48 -v Print the program version number.
49
50 Written by Richard Stallman <rms@gnu.ai.mit.edu>
51 and David MacKenzie <djm@gnu.ai.mit.edu>. */
52
53#include "bfd.h"
54#include <stdio.h>
55#include <getopt.h>
56#include <ctype.h>
57#include <errno.h>
58#include "bucomm.h"
59#include "libiberty.h"
60
61#ifdef isascii
62#define isgraphic(c) (isascii (c) && isprint (c))
63#else
64#define isgraphic(c) (isprint (c))
65#endif
66
67#ifndef errno
68extern int errno;
69#endif
70
71/* The BFD section flags that identify an initialized data section. */
72#define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS)
73
74/* Radix for printing addresses (must be 8, 10 or 16). */
75static int address_radix;
76
77/* Minimum length of sequence of graphic chars to trigger output. */
78static int string_min;
79
80/* true means print address within file for each string. */
81static boolean print_addresses;
82
83/* true means print filename for each string. */
84static boolean print_filenames;
85
86/* true means for object files scan only the data section. */
87static boolean datasection_only;
88
89/* true if we found an initialized data section in the current file. */
90static boolean got_a_section;
91
92/* The BFD object file format. */
93static char *target;
94
95static struct option long_options[] =
96{
97 {"all", no_argument, NULL, 'a'},
98 {"print-file-name", no_argument, NULL, 'f'},
99 {"bytes", required_argument, NULL, 'n'},
100 {"radix", required_argument, NULL, 't'},
101 {"target", required_argument, NULL, 'T'},
102 {"help", no_argument, NULL, 'h'},
103 {"version", no_argument, NULL, 'v'},
104 {NULL, 0, NULL, 0}
105};
106
107static void strings_a_section PARAMS ((bfd *, asection *, PTR));
108static boolean strings_object_file PARAMS ((const char *));
109static boolean strings_file PARAMS ((char *file));
110static int integer_arg PARAMS ((char *s));
111static void print_strings PARAMS ((const char *filename, FILE *stream,
112 file_ptr address, int stop_point,
113 int magiccount, char *magic));
114static void usage PARAMS ((FILE *stream, int status));
115\f
116int
117main (argc, argv)
118 int argc;
119 char **argv;
120{
121 int optc;
122 int exit_status = 0;
123 boolean files_given = false;
124
125#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
126 setlocale (LC_MESSAGES, "");
127#endif
128 bindtextdomain (PACKAGE, LOCALEDIR);
129 textdomain (PACKAGE);
130
131 program_name = argv[0];
132 xmalloc_set_program_name (program_name);
133 string_min = -1;
134 print_addresses = false;
135 print_filenames = false;
136 datasection_only = true;
137 target = NULL;
138
139 while ((optc = getopt_long (argc, argv, "afn:ot:v0123456789",
140 long_options, (int *) 0)) != EOF)
141 {
142 switch (optc)
143 {
144 case 'a':
145 datasection_only = false;
146 break;
147
148 case 'f':
149 print_filenames = true;
150 break;
151
152 case 'h':
153 usage (stdout, 0);
154
155 case 'n':
156 string_min = integer_arg (optarg);
157 if (string_min < 1)
158 {
159 fprintf (stderr, _("%s: invalid number %s\n"),
160 program_name, optarg);
161 exit (1);
162 }
163 break;
164
165 case 'o':
166 print_addresses = true;
167 address_radix = 8;
168 break;
169
170 case 't':
171 print_addresses = true;
172 if (optarg[1] != '\0')
173 usage (stderr, 1);
174 switch (optarg[0])
175 {
176 case 'o':
177 address_radix = 8;
178 break;
179
180 case 'd':
181 address_radix = 10;
182 break;
183
184 case 'x':
185 address_radix = 16;
186 break;
187
188 default:
189 usage (stderr, 1);
190 }
191 break;
192
193 case 'T':
194 target = optarg;
195 break;
196
197 case 'v':
198 print_version ("strings");
199 break;
200
201 case '?':
202 usage (stderr, 1);
203
204 default:
205 if (string_min < 0)
206 string_min = optc;
207 else
208 string_min = string_min * 10 + optc - '0';
209 break;
210 }
211 }
212
213 if (string_min < 0)
214 string_min = 4;
215
216 bfd_init ();
217 set_default_bfd_target ();
218
219 if (optind >= argc)
220 {
221 datasection_only = false;
222 print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
223 files_given = true;
224 }
225 else
226 {
227 for (; optind < argc; ++optind)
228 {
229 if (strcmp (argv[optind], "-") == 0)
230 datasection_only = false;
231 else
232 {
233 files_given = true;
234 exit_status |= (strings_file (argv[optind]) == false);
235 }
236 }
237 }
238
239 if (files_given == false)
240 usage (stderr, 1);
241
242 return (exit_status);
243}
244\f
245/* Scan section SECT of the file ABFD, whose printable name is FILE.
246 If it contains initialized data,
247 set `got_a_section' and print the strings in it. */
248
249static void
250strings_a_section (abfd, sect, filearg)
251 bfd *abfd;
252 asection *sect;
253 PTR filearg;
254{
255 const char *file = (const char *) filearg;
256
257 if ((sect->flags & DATA_FLAGS) == DATA_FLAGS)
258 {
259 bfd_size_type sz = bfd_get_section_size_before_reloc (sect);
260 PTR mem = xmalloc (sz);
261 if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sz))
262 {
263 got_a_section = true;
264 print_strings (file, (FILE *) NULL, sect->filepos, 0, sz, mem);
265 }
266 free (mem);
267 }
268}
269
270/* Scan all of the sections in FILE, and print the strings
271 in the initialized data section(s).
272
273 Return true if successful,
274 false if not (such as if FILE is not an object file). */
275
276static boolean
277strings_object_file (file)
278 const char *file;
279{
280 bfd *abfd = bfd_openr (file, target);
281
282 if (abfd == NULL)
283 {
284 /* Treat the file as a non-object file. */
285 return false;
286 }
287
288 /* This call is mainly for its side effect of reading in the sections.
289 We follow the traditional behavior of `strings' in that we don't
290 complain if we don't recognize a file to be an object file. */
291 if (bfd_check_format (abfd, bfd_object) == false)
292 {
293 bfd_close (abfd);
294 return false;
295 }
296
297 got_a_section = false;
298 bfd_map_over_sections (abfd, strings_a_section, (PTR) file);
299
300 if (!bfd_close (abfd))
301 {
302 bfd_nonfatal (file);
303 return false;
304 }
305
306 return got_a_section;
307}
308
309/* Print the strings in FILE. Return true if ok, false if an error occurs. */
310
311static boolean
312strings_file (file)
313 char *file;
314{
315 /* If we weren't told to scan the whole file,
316 try to open it as an object file and only look at
317 initialized data sections. If that fails, fall back to the
318 whole file. */
319 if (!datasection_only || !strings_object_file (file))
320 {
321 FILE *stream;
322
323 stream = fopen (file, "rb");
324 /* Not all systems permit "rb", so try "r" if it failed. */
325 if (stream == NULL)
326 stream = fopen (file, "r");
327 if (stream == NULL)
328 {
329 fprintf (stderr, "%s: ", program_name);
330 perror (file);
331 return false;
332 }
333
334 print_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
335
336 if (fclose (stream) == EOF)
337 {
338 fprintf (stderr, "%s: ", program_name);
339 perror (file);
340 return false;
341 }
342 }
343
344 return true;
345}
346\f
347/* Find the strings in file FILENAME, read from STREAM.
348 Assume that STREAM is positioned so that the next byte read
349 is at address ADDRESS in the file.
350 Stop reading at address STOP_POINT in the file, if nonzero.
351
352 If STREAM is NULL, do not read from it.
353 The caller can supply a buffer of characters
354 to be processed before the data in STREAM.
355 MAGIC is the address of the buffer and
356 MAGICCOUNT is how many characters are in it.
357 Those characters come at address ADDRESS and the data in STREAM follow. */
358
359static void
360print_strings (filename, stream, address, stop_point, magiccount, magic)
361 const char *filename;
362 FILE *stream;
363 file_ptr address;
364 int stop_point;
365 int magiccount;
366 char *magic;
367{
368 char *buf = (char *) xmalloc (string_min + 1);
369
370 while (1)
371 {
372 file_ptr start;
373 int i;
374 int c;
375
376 /* See if the next `string_min' chars are all graphic chars. */
377 tryline:
378 if (stop_point && address >= stop_point)
379 break;
380 start = address;
381 for (i = 0; i < string_min; i++)
382 {
383 if (magiccount)
384 {
385 magiccount--;
386 c = *magic++;
387 }
388 else
389 {
390 if (stream == NULL)
391 return;
392 c = getc (stream);
393 if (c == EOF)
394 return;
395 }
396 address++;
397 if (!isgraphic (c))
398 /* Found a non-graphic. Try again starting with next char. */
399 goto tryline;
400 buf[i] = c;
401 }
402
403 /* We found a run of `string_min' graphic characters. Print up
404 to the next non-graphic character. */
405
406 if (print_filenames)
407 printf ("%s: ", filename);
408 if (print_addresses)
409 switch (address_radix)
410 {
411 case 8:
412 printf ("%7lo ", (unsigned long) start);
413 break;
414
415 case 10:
416 printf ("%7ld ", (long) start);
417 break;
418
419 case 16:
420 printf ("%7lx ", (unsigned long) start);
421 break;
422 }
423
424 buf[i] = '\0';
425 fputs (buf, stdout);
426
427 while (1)
428 {
429 if (magiccount)
430 {
431 magiccount--;
432 c = *magic++;
433 }
434 else
435 {
436 if (stream == NULL)
437 break;
438 c = getc (stream);
439 if (c == EOF)
440 break;
441 }
442 address++;
443 if (! isgraphic (c))
444 break;
445 putchar (c);
446 }
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
501usage (stream, status)
502 FILE *stream;
503 int status;
504{
505 fprintf (stream, _("\
506Usage: %s [-afov] [-n min-len] [-min-len] [-t {o,x,d}] [-]\n\
507 [--all] [--print-file-name] [--bytes=min-len] [--radix={o,x,d}]\n\
508 [--target=bfdname] [--help] [--version] file...\n"),
509 program_name);
510 list_supported_targets (program_name, stream);
511 if (status == 0)
512 fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n"));
513 exit (status);
514}