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