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