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