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