133965Sjdp/* strings -- print the strings of printable characters in files 289865Sobrien Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 3218822Sdim 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 433965Sjdp 533965Sjdp This program is free software; you can redistribute it and/or modify 633965Sjdp it under the terms of the GNU General Public License as published by 733965Sjdp the Free Software Foundation; either version 2, or (at your option) 833965Sjdp any later version. 933965Sjdp 1033965Sjdp This program is distributed in the hope that it will be useful, 1133965Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1233965Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1333965Sjdp GNU General Public License for more details. 1433965Sjdp 1533965Sjdp You should have received a copy of the GNU General Public License 1633965Sjdp along with this program; if not, write to the Free Software 17218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 18218822Sdim 02110-1301, USA. */ 1933965Sjdp 2033965Sjdp/* Usage: strings [options] file... 2133965Sjdp 2233965Sjdp Options: 2333965Sjdp --all 2433965Sjdp -a 2533965Sjdp - Do not scan only the initialized data section of object files. 2633965Sjdp 2733965Sjdp --print-file-name 2833965Sjdp -f Print the name of the file before each string. 2933965Sjdp 3033965Sjdp --bytes=min-len 3133965Sjdp -n min-len 3233965Sjdp -min-len Print graphic char sequences, MIN-LEN or more bytes long, 3333965Sjdp that are followed by a NUL or a newline. Default is 4. 3433965Sjdp 3533965Sjdp --radix={o,x,d} 3633965Sjdp -t {o,x,d} Print the offset within the file before each string, 3733965Sjdp in octal/hex/decimal. 3833965Sjdp 3933965Sjdp -o Like -to. (Some other implementations have -o like -to, 4033965Sjdp others like -td. We chose one arbitrarily.) 4133965Sjdp 42130570Sobrien --encoding={s,S,b,l,B,L} 43130570Sobrien -e {s,S,b,l,B,L} 44130570Sobrien Select character encoding: 7-bit-character, 8-bit-character, 45130570Sobrien bigendian 16-bit, littleendian 16-bit, bigendian 32-bit, 46130570Sobrien littleendian 32-bit. 4789865Sobrien 4833965Sjdp --target=BFDNAME 49218822Sdim -T {bfdname} 5033965Sjdp Specify a non-default object file format. 5133965Sjdp 5233965Sjdp --help 5333965Sjdp -h Print the usage message on the standard output. 5433965Sjdp 5533965Sjdp --version 5633965Sjdp -v Print the program version number. 5733965Sjdp 5833965Sjdp Written by Richard Stallman <rms@gnu.ai.mit.edu> 5933965Sjdp and David MacKenzie <djm@gnu.ai.mit.edu>. */ 6033965Sjdp 61218822Sdim#include "sysdep.h" 6233965Sjdp#include "bfd.h" 63104837Sobrien#include "getopt.h" 6433965Sjdp#include "libiberty.h" 6589865Sobrien#include "safe-ctype.h" 66218822Sdim#include <sys/stat.h> 67218822Sdim#include "bucomm.h" 6833965Sjdp 6961846Sobrien/* Some platforms need to put stdin into binary mode, to read 7061846Sobrien binary files. */ 7161846Sobrien#ifdef HAVE_SETMODE 7261846Sobrien#ifndef O_BINARY 7361846Sobrien#ifdef _O_BINARY 7461846Sobrien#define O_BINARY _O_BINARY 7561846Sobrien#define setmode _setmode 7661846Sobrien#else 7761846Sobrien#define O_BINARY 0 7861846Sobrien#endif 7961846Sobrien#endif 8061846Sobrien#if O_BINARY 8161846Sobrien#include <io.h> 82130570Sobrien#define SET_BINARY(f) do { if (!isatty (f)) setmode (f,O_BINARY); } while (0) 8361846Sobrien#endif 8461846Sobrien#endif 8561846Sobrien 86130570Sobrien#define STRING_ISGRAPHIC(c) \ 87130570Sobrien ( (c) >= 0 \ 88130570Sobrien && (c) <= 255 \ 89130570Sobrien && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127))) 9033965Sjdp 9133965Sjdp#ifndef errno 9233965Sjdpextern int errno; 9333965Sjdp#endif 9433965Sjdp 9533965Sjdp/* The BFD section flags that identify an initialized data section. */ 9633965Sjdp#define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS) 9733965Sjdp 9889865Sobrien#ifdef HAVE_FOPEN64 9989865Sobrientypedef off64_t file_off; 100130570Sobrien#define file_open(s,m) fopen64(s, m) 10189865Sobrien#else 10289865Sobrientypedef off_t file_off; 103130570Sobrien#define file_open(s,m) fopen(s, m) 10489865Sobrien#endif 105218822Sdim#ifdef HAVE_STAT64 106218822Sdimtypedef struct stat64 statbuf; 107218822Sdim#define file_stat(f,s) stat64(f, s) 108218822Sdim#else 109218822Sdimtypedef struct stat statbuf; 110218822Sdim#define file_stat(f,s) stat(f, s) 111218822Sdim#endif 11289865Sobrien 11333965Sjdp/* Radix for printing addresses (must be 8, 10 or 16). */ 11433965Sjdpstatic int address_radix; 11533965Sjdp 11633965Sjdp/* Minimum length of sequence of graphic chars to trigger output. */ 11733965Sjdpstatic int string_min; 11833965Sjdp 119130570Sobrien/* TRUE means print address within file for each string. */ 120130570Sobrienstatic bfd_boolean print_addresses; 12133965Sjdp 122130570Sobrien/* TRUE means print filename for each string. */ 123130570Sobrienstatic bfd_boolean print_filenames; 12433965Sjdp 125130570Sobrien/* TRUE means for object files scan only the data section. */ 126130570Sobrienstatic bfd_boolean datasection_only; 12733965Sjdp 128130570Sobrien/* TRUE if we found an initialized data section in the current file. */ 129130570Sobrienstatic bfd_boolean got_a_section; 13033965Sjdp 13133965Sjdp/* The BFD object file format. */ 13233965Sjdpstatic char *target; 13333965Sjdp 13489865Sobrien/* The character encoding format. */ 13589865Sobrienstatic char encoding; 13689865Sobrienstatic int encoding_bytes; 13789865Sobrien 13833965Sjdpstatic struct option long_options[] = 13933965Sjdp{ 14033965Sjdp {"all", no_argument, NULL, 'a'}, 14133965Sjdp {"print-file-name", no_argument, NULL, 'f'}, 14233965Sjdp {"bytes", required_argument, NULL, 'n'}, 14333965Sjdp {"radix", required_argument, NULL, 't'}, 14489865Sobrien {"encoding", required_argument, NULL, 'e'}, 14533965Sjdp {"target", required_argument, NULL, 'T'}, 14633965Sjdp {"help", no_argument, NULL, 'h'}, 14733965Sjdp {"version", no_argument, NULL, 'v'}, 14833965Sjdp {NULL, 0, NULL, 0} 14933965Sjdp}; 15033965Sjdp 151218822Sdim/* Records the size of a named file so that we 152218822Sdim do not repeatedly run bfd_stat() on it. */ 153218822Sdim 154218822Sdimtypedef struct 155218822Sdim{ 156218822Sdim const char * filename; 157218822Sdim bfd_size_type filesize; 158218822Sdim} filename_and_size_t; 159218822Sdim 160130570Sobrienstatic void strings_a_section (bfd *, asection *, void *); 161130570Sobrienstatic bfd_boolean strings_object_file (const char *); 162130570Sobrienstatic bfd_boolean strings_file (char *file); 163130570Sobrienstatic int integer_arg (char *s); 164130570Sobrienstatic void print_strings (const char *, FILE *, file_off, int, int, char *); 165130570Sobrienstatic void usage (FILE *, int); 166130570Sobrienstatic long get_char (FILE *, file_off *, int *, char **); 16733965Sjdp 168130570Sobrienint main (int, char **); 16989865Sobrien 17033965Sjdpint 171130570Sobrienmain (int argc, char **argv) 17233965Sjdp{ 17333965Sjdp int optc; 17433965Sjdp int exit_status = 0; 175130570Sobrien bfd_boolean files_given = FALSE; 17633965Sjdp 17789865Sobrien#if defined (HAVE_SETLOCALE) 17878837Sobrien setlocale (LC_ALL, ""); 17960513Sobrien#endif 18060513Sobrien bindtextdomain (PACKAGE, LOCALEDIR); 18160513Sobrien textdomain (PACKAGE); 18260513Sobrien 18333965Sjdp program_name = argv[0]; 18433965Sjdp xmalloc_set_program_name (program_name); 185218822Sdim 186218822Sdim expandargv (&argc, &argv); 187218822Sdim 18833965Sjdp string_min = -1; 189130570Sobrien print_addresses = FALSE; 190130570Sobrien print_filenames = FALSE; 191130570Sobrien datasection_only = TRUE; 19233965Sjdp target = NULL; 19389865Sobrien encoding = 's'; 19433965Sjdp 195218822Sdim while ((optc = getopt_long (argc, argv, "afhHn:ot:e:T:Vv0123456789", 19633965Sjdp long_options, (int *) 0)) != EOF) 19733965Sjdp { 19833965Sjdp switch (optc) 19933965Sjdp { 20033965Sjdp case 'a': 201130570Sobrien datasection_only = FALSE; 20233965Sjdp break; 20333965Sjdp 20433965Sjdp case 'f': 205130570Sobrien print_filenames = TRUE; 20633965Sjdp break; 20733965Sjdp 20889865Sobrien case 'H': 20933965Sjdp case 'h': 21033965Sjdp usage (stdout, 0); 21133965Sjdp 21233965Sjdp case 'n': 21333965Sjdp string_min = integer_arg (optarg); 21433965Sjdp if (string_min < 1) 215130570Sobrien fatal (_("invalid number %s"), optarg); 21633965Sjdp break; 21733965Sjdp 21833965Sjdp case 'o': 219130570Sobrien print_addresses = TRUE; 22033965Sjdp address_radix = 8; 22133965Sjdp break; 22233965Sjdp 22333965Sjdp case 't': 224130570Sobrien print_addresses = TRUE; 22533965Sjdp if (optarg[1] != '\0') 22633965Sjdp usage (stderr, 1); 22733965Sjdp switch (optarg[0]) 22833965Sjdp { 22933965Sjdp case 'o': 23033965Sjdp address_radix = 8; 23133965Sjdp break; 23233965Sjdp 23333965Sjdp case 'd': 23433965Sjdp address_radix = 10; 23533965Sjdp break; 23633965Sjdp 23733965Sjdp case 'x': 23833965Sjdp address_radix = 16; 23933965Sjdp break; 24033965Sjdp 24133965Sjdp default: 24233965Sjdp usage (stderr, 1); 24333965Sjdp } 24433965Sjdp break; 24533965Sjdp 24633965Sjdp case 'T': 24733965Sjdp target = optarg; 24833965Sjdp break; 24933965Sjdp 25089865Sobrien case 'e': 25189865Sobrien if (optarg[1] != '\0') 25289865Sobrien usage (stderr, 1); 25389865Sobrien encoding = optarg[0]; 25489865Sobrien break; 25589865Sobrien 25689865Sobrien case 'V': 25733965Sjdp case 'v': 25833965Sjdp print_version ("strings"); 25933965Sjdp break; 26033965Sjdp 26133965Sjdp case '?': 26233965Sjdp usage (stderr, 1); 26333965Sjdp 26433965Sjdp default: 26533965Sjdp if (string_min < 0) 26660513Sobrien string_min = optc - '0'; 26733965Sjdp else 26833965Sjdp string_min = string_min * 10 + optc - '0'; 26933965Sjdp break; 27033965Sjdp } 27133965Sjdp } 27233965Sjdp 27333965Sjdp if (string_min < 0) 27433965Sjdp string_min = 4; 27533965Sjdp 27689865Sobrien switch (encoding) 27789865Sobrien { 278130570Sobrien case 'S': 27989865Sobrien case 's': 28089865Sobrien encoding_bytes = 1; 28189865Sobrien break; 28289865Sobrien case 'b': 28389865Sobrien case 'l': 28489865Sobrien encoding_bytes = 2; 28589865Sobrien break; 28689865Sobrien case 'B': 28789865Sobrien case 'L': 28889865Sobrien encoding_bytes = 4; 28989865Sobrien break; 29089865Sobrien default: 29189865Sobrien usage (stderr, 1); 29289865Sobrien } 29389865Sobrien 29433965Sjdp bfd_init (); 29533965Sjdp set_default_bfd_target (); 29633965Sjdp 29733965Sjdp if (optind >= argc) 29833965Sjdp { 299130570Sobrien datasection_only = FALSE; 30061846Sobrien#ifdef SET_BINARY 30161846Sobrien SET_BINARY (fileno (stdin)); 30261846Sobrien#endif 30333965Sjdp print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL); 304130570Sobrien files_given = TRUE; 30533965Sjdp } 30633965Sjdp else 30733965Sjdp { 30833965Sjdp for (; optind < argc; ++optind) 30933965Sjdp { 31033965Sjdp if (strcmp (argv[optind], "-") == 0) 311130570Sobrien datasection_only = FALSE; 31233965Sjdp else 31333965Sjdp { 314130570Sobrien files_given = TRUE; 315130570Sobrien exit_status |= strings_file (argv[optind]) == FALSE; 31633965Sjdp } 31733965Sjdp } 31833965Sjdp } 31933965Sjdp 320130570Sobrien if (!files_given) 32133965Sjdp usage (stderr, 1); 32233965Sjdp 32333965Sjdp return (exit_status); 32433965Sjdp} 32533965Sjdp 326218822Sdim/* Scan section SECT of the file ABFD, whose printable name is in 327218822Sdim ARG->filename and whose size might be in ARG->filesize. If it 328218822Sdim contains initialized data set `got_a_section' and print the 329218822Sdim strings in it. 33033965Sjdp 331218822Sdim FIXME: We ought to be able to return error codes/messages for 332218822Sdim certain conditions. */ 333218822Sdim 33433965Sjdpstatic void 335218822Sdimstrings_a_section (bfd *abfd, asection *sect, void *arg) 33633965Sjdp{ 337218822Sdim filename_and_size_t * filename_and_sizep; 338218822Sdim bfd_size_type *filesizep; 339218822Sdim bfd_size_type sectsize; 340218822Sdim void *mem; 341218822Sdim 342218822Sdim if ((sect->flags & DATA_FLAGS) != DATA_FLAGS) 343218822Sdim return; 34433965Sjdp 345218822Sdim sectsize = bfd_get_section_size (sect); 346218822Sdim 347218822Sdim if (sectsize <= 0) 348218822Sdim return; 349218822Sdim 350218822Sdim /* Get the size of the file. This might have been cached for us. */ 351218822Sdim filename_and_sizep = (filename_and_size_t *) arg; 352218822Sdim filesizep = & filename_and_sizep->filesize; 353218822Sdim 354218822Sdim if (*filesizep == 0) 35533965Sjdp { 356218822Sdim struct stat st; 357218822Sdim 358218822Sdim if (bfd_stat (abfd, &st)) 359218822Sdim return; 360130570Sobrien 361218822Sdim /* Cache the result so that we do not repeatedly stat this file. */ 362218822Sdim *filesizep = st.st_size; 36333965Sjdp } 364218822Sdim 365218822Sdim /* Compare the size of the section against the size of the file. 366218822Sdim If the section is bigger then the file must be corrupt and 367218822Sdim we should not try dumping it. */ 368218822Sdim if (sectsize >= *filesizep) 369218822Sdim return; 370218822Sdim 371218822Sdim mem = xmalloc (sectsize); 372218822Sdim 373218822Sdim if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sectsize)) 374218822Sdim { 375218822Sdim got_a_section = TRUE; 376218822Sdim 377218822Sdim print_strings (filename_and_sizep->filename, NULL, sect->filepos, 378218822Sdim 0, sectsize, mem); 379218822Sdim } 380218822Sdim 381218822Sdim free (mem); 38233965Sjdp} 38333965Sjdp 38433965Sjdp/* Scan all of the sections in FILE, and print the strings 38533965Sjdp in the initialized data section(s). 38633965Sjdp 387130570Sobrien Return TRUE if successful, 388130570Sobrien FALSE if not (such as if FILE is not an object file). */ 38933965Sjdp 390130570Sobrienstatic bfd_boolean 391130570Sobrienstrings_object_file (const char *file) 39233965Sjdp{ 393218822Sdim filename_and_size_t filename_and_size; 394218822Sdim bfd *abfd; 39533965Sjdp 396218822Sdim abfd = bfd_openr (file, target); 397218822Sdim 39833965Sjdp if (abfd == NULL) 399130570Sobrien /* Treat the file as a non-object file. */ 400130570Sobrien return FALSE; 40133965Sjdp 40233965Sjdp /* This call is mainly for its side effect of reading in the sections. 40333965Sjdp We follow the traditional behavior of `strings' in that we don't 40433965Sjdp complain if we don't recognize a file to be an object file. */ 405130570Sobrien if (!bfd_check_format (abfd, bfd_object)) 40633965Sjdp { 40733965Sjdp bfd_close (abfd); 408130570Sobrien return FALSE; 40933965Sjdp } 41033965Sjdp 411130570Sobrien got_a_section = FALSE; 412218822Sdim filename_and_size.filename = file; 413218822Sdim filename_and_size.filesize = 0; 414218822Sdim bfd_map_over_sections (abfd, strings_a_section, & filename_and_size); 41533965Sjdp 41633965Sjdp if (!bfd_close (abfd)) 41733965Sjdp { 41833965Sjdp bfd_nonfatal (file); 419130570Sobrien return FALSE; 42033965Sjdp } 42133965Sjdp 42233965Sjdp return got_a_section; 42333965Sjdp} 42433965Sjdp 425130570Sobrien/* Print the strings in FILE. Return TRUE if ok, FALSE if an error occurs. */ 42633965Sjdp 427130570Sobrienstatic bfd_boolean 428130570Sobrienstrings_file (char *file) 42933965Sjdp{ 430218822Sdim statbuf st; 431130570Sobrien 432218822Sdim if (file_stat (file, &st) < 0) 433218822Sdim { 434218822Sdim if (errno == ENOENT) 435218822Sdim non_fatal (_("'%s': No such file"), file); 436218822Sdim else 437218822Sdim non_fatal (_("Warning: could not locate '%s'. reason: %s"), 438218822Sdim file, strerror (errno)); 439218822Sdim return FALSE; 440218822Sdim } 441218822Sdim 44233965Sjdp /* If we weren't told to scan the whole file, 44333965Sjdp try to open it as an object file and only look at 44433965Sjdp initialized data sections. If that fails, fall back to the 44533965Sjdp whole file. */ 44633965Sjdp if (!datasection_only || !strings_object_file (file)) 44733965Sjdp { 44833965Sjdp FILE *stream; 44933965Sjdp 45089865Sobrien stream = file_open (file, FOPEN_RB); 45133965Sjdp if (stream == NULL) 45233965Sjdp { 45333965Sjdp fprintf (stderr, "%s: ", program_name); 45433965Sjdp perror (file); 455130570Sobrien return FALSE; 45633965Sjdp } 45733965Sjdp 45889865Sobrien print_strings (file, stream, (file_off) 0, 0, 0, (char *) 0); 45933965Sjdp 46033965Sjdp if (fclose (stream) == EOF) 46133965Sjdp { 46233965Sjdp fprintf (stderr, "%s: ", program_name); 46333965Sjdp perror (file); 464130570Sobrien return FALSE; 46533965Sjdp } 46633965Sjdp } 46733965Sjdp 468130570Sobrien return TRUE; 46933965Sjdp} 47033965Sjdp 47189865Sobrien/* Read the next character, return EOF if none available. 47289865Sobrien Assume that STREAM is positioned so that the next byte read 47389865Sobrien is at address ADDRESS in the file. 47489865Sobrien 47589865Sobrien If STREAM is NULL, do not read from it. 47689865Sobrien The caller can supply a buffer of characters 47789865Sobrien to be processed before the data in STREAM. 47889865Sobrien MAGIC is the address of the buffer and 47989865Sobrien MAGICCOUNT is how many characters are in it. */ 48089865Sobrien 48189865Sobrienstatic long 482130570Sobrienget_char (FILE *stream, file_off *address, int *magiccount, char **magic) 48389865Sobrien{ 48489865Sobrien int c, i; 48589865Sobrien long r = EOF; 48689865Sobrien unsigned char buf[4]; 48789865Sobrien 48889865Sobrien for (i = 0; i < encoding_bytes; i++) 48989865Sobrien { 49089865Sobrien if (*magiccount) 49189865Sobrien { 49289865Sobrien (*magiccount)--; 49389865Sobrien c = *(*magic)++; 49489865Sobrien } 49589865Sobrien else 49689865Sobrien { 49789865Sobrien if (stream == NULL) 49889865Sobrien return EOF; 499218822Sdim 500218822Sdim /* Only use getc_unlocked if we found a declaration for it. 501218822Sdim Otherwise, libc is not thread safe by default, and we 502218822Sdim should not use it. */ 503218822Sdim 504218822Sdim#if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_GETC_UNLOCKED 50589865Sobrien c = getc_unlocked (stream); 50689865Sobrien#else 50789865Sobrien c = getc (stream); 50889865Sobrien#endif 50989865Sobrien if (c == EOF) 51089865Sobrien return EOF; 51189865Sobrien } 51289865Sobrien 51389865Sobrien (*address)++; 51489865Sobrien buf[i] = c; 51589865Sobrien } 51689865Sobrien 51789865Sobrien switch (encoding) 51889865Sobrien { 519130570Sobrien case 'S': 52089865Sobrien case 's': 52189865Sobrien r = buf[0]; 52289865Sobrien break; 52389865Sobrien case 'b': 52489865Sobrien r = (buf[0] << 8) | buf[1]; 52589865Sobrien break; 52689865Sobrien case 'l': 52789865Sobrien r = buf[0] | (buf[1] << 8); 52889865Sobrien break; 52989865Sobrien case 'B': 53089865Sobrien r = ((long) buf[0] << 24) | ((long) buf[1] << 16) | 53189865Sobrien ((long) buf[2] << 8) | buf[3]; 53289865Sobrien break; 53389865Sobrien case 'L': 53489865Sobrien r = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) | 53589865Sobrien ((long) buf[3] << 24); 53689865Sobrien break; 53789865Sobrien } 53889865Sobrien 53989865Sobrien if (r == EOF) 54089865Sobrien return 0; 54189865Sobrien 54289865Sobrien return r; 54389865Sobrien} 54489865Sobrien 54533965Sjdp/* Find the strings in file FILENAME, read from STREAM. 54633965Sjdp Assume that STREAM is positioned so that the next byte read 54733965Sjdp is at address ADDRESS in the file. 54833965Sjdp Stop reading at address STOP_POINT in the file, if nonzero. 54933965Sjdp 55033965Sjdp If STREAM is NULL, do not read from it. 55133965Sjdp The caller can supply a buffer of characters 55233965Sjdp to be processed before the data in STREAM. 55333965Sjdp MAGIC is the address of the buffer and 55433965Sjdp MAGICCOUNT is how many characters are in it. 55533965Sjdp Those characters come at address ADDRESS and the data in STREAM follow. */ 55633965Sjdp 55733965Sjdpstatic void 558130570Sobrienprint_strings (const char *filename, FILE *stream, file_off address, 559130570Sobrien int stop_point, int magiccount, char *magic) 56033965Sjdp{ 56189865Sobrien char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1)); 56233965Sjdp 56333965Sjdp while (1) 56433965Sjdp { 56589865Sobrien file_off start; 56633965Sjdp int i; 56789865Sobrien long c; 56833965Sjdp 56933965Sjdp /* See if the next `string_min' chars are all graphic chars. */ 57033965Sjdp tryline: 57133965Sjdp if (stop_point && address >= stop_point) 57233965Sjdp break; 57333965Sjdp start = address; 57433965Sjdp for (i = 0; i < string_min; i++) 57533965Sjdp { 57689865Sobrien c = get_char (stream, &address, &magiccount, &magic); 57789865Sobrien if (c == EOF) 57889865Sobrien return; 579130570Sobrien if (! STRING_ISGRAPHIC (c)) 58033965Sjdp /* Found a non-graphic. Try again starting with next char. */ 58133965Sjdp goto tryline; 58233965Sjdp buf[i] = c; 58333965Sjdp } 58433965Sjdp 58533965Sjdp /* We found a run of `string_min' graphic characters. Print up 586218822Sdim to the next non-graphic character. */ 58733965Sjdp 58833965Sjdp if (print_filenames) 58933965Sjdp printf ("%s: ", filename); 59033965Sjdp if (print_addresses) 59133965Sjdp switch (address_radix) 59233965Sjdp { 59333965Sjdp case 8: 59489865Sobrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) 59589865Sobrien if (sizeof (start) > sizeof (long)) 596222204Sbenl printf ("%7llo ", (unsigned long long) start); 59789865Sobrien else 59889865Sobrien#else 59989865Sobrien# if !BFD_HOST_64BIT_LONG 60089865Sobrien if (start != (unsigned long) start) 60189865Sobrien printf ("++%7lo ", (unsigned long) start); 60289865Sobrien else 60389865Sobrien# endif 60489865Sobrien#endif 60589865Sobrien printf ("%7lo ", (unsigned long) start); 60633965Sjdp break; 60733965Sjdp 60833965Sjdp case 10: 60989865Sobrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) 61089865Sobrien if (sizeof (start) > sizeof (long)) 611222204Sbenl printf ("%7lld ", (unsigned long long) start); 61289865Sobrien else 61389865Sobrien#else 61489865Sobrien# if !BFD_HOST_64BIT_LONG 61589865Sobrien if (start != (unsigned long) start) 61689865Sobrien printf ("++%7ld ", (unsigned long) start); 61789865Sobrien else 61889865Sobrien# endif 61989865Sobrien#endif 62089865Sobrien printf ("%7ld ", (long) start); 62133965Sjdp break; 62233965Sjdp 62333965Sjdp case 16: 62489865Sobrien#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) 62589865Sobrien if (sizeof (start) > sizeof (long)) 626222204Sbenl printf ("%7llx ", (unsigned long long) start); 62789865Sobrien else 62889865Sobrien#else 62989865Sobrien# if !BFD_HOST_64BIT_LONG 63089865Sobrien if (start != (unsigned long) start) 631218822Sdim printf ("%lx%8.8lx ", (unsigned long) (start >> 32), 632218822Sdim (unsigned long) (start & 0xffffffff)); 63389865Sobrien else 63489865Sobrien# endif 63589865Sobrien#endif 63689865Sobrien printf ("%7lx ", (unsigned long) start); 63733965Sjdp break; 63833965Sjdp } 63933965Sjdp 64033965Sjdp buf[i] = '\0'; 64133965Sjdp fputs (buf, stdout); 64233965Sjdp 64333965Sjdp while (1) 64433965Sjdp { 64589865Sobrien c = get_char (stream, &address, &magiccount, &magic); 64689865Sobrien if (c == EOF) 64733965Sjdp break; 648130570Sobrien if (! STRING_ISGRAPHIC (c)) 64989865Sobrien break; 65033965Sjdp putchar (c); 65133965Sjdp } 65233965Sjdp 65333965Sjdp putchar ('\n'); 65433965Sjdp } 65533965Sjdp} 65633965Sjdp 65733965Sjdp/* Parse string S as an integer, using decimal radix by default, 65833965Sjdp but allowing octal and hex numbers as in C. */ 65933965Sjdp 66033965Sjdpstatic int 661130570Sobrieninteger_arg (char *s) 66233965Sjdp{ 66333965Sjdp int value; 66433965Sjdp int radix = 10; 66533965Sjdp char *p = s; 66633965Sjdp int c; 66733965Sjdp 66833965Sjdp if (*p != '0') 66933965Sjdp radix = 10; 67033965Sjdp else if (*++p == 'x') 67133965Sjdp { 67233965Sjdp radix = 16; 67333965Sjdp p++; 67433965Sjdp } 67533965Sjdp else 67633965Sjdp radix = 8; 67733965Sjdp 67833965Sjdp value = 0; 67933965Sjdp while (((c = *p++) >= '0' && c <= '9') 68033965Sjdp || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z')) 68133965Sjdp { 68233965Sjdp value *= radix; 68333965Sjdp if (c >= '0' && c <= '9') 68433965Sjdp value += c - '0'; 68533965Sjdp else 68633965Sjdp value += (c & ~40) - 'A'; 68733965Sjdp } 68833965Sjdp 68933965Sjdp if (c == 'b') 69033965Sjdp value *= 512; 69133965Sjdp else if (c == 'B') 69233965Sjdp value *= 1024; 69333965Sjdp else 69433965Sjdp p--; 69533965Sjdp 69633965Sjdp if (*p) 697130570Sobrien fatal (_("invalid integer argument %s"), s); 698130570Sobrien 69933965Sjdp return value; 70033965Sjdp} 70133965Sjdp 70233965Sjdpstatic void 703130570Sobrienusage (FILE *stream, int status) 70433965Sjdp{ 70589865Sobrien fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name); 70689865Sobrien fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n")); 70789865Sobrien fprintf (stream, _(" The options are:\n\ 70889865Sobrien -a - --all Scan the entire file, not just the data section\n\ 70989865Sobrien -f --print-file-name Print the name of the file before each string\n\ 71089865Sobrien -n --bytes=[number] Locate & print any NUL-terminated sequence of at\n\ 71189865Sobrien -<number> least [number] characters (default 4).\n\ 712218822Sdim -t --radix={o,d,x} Print the location of the string in base 8, 10 or 16\n\ 71389865Sobrien -o An alias for --radix=o\n\ 71489865Sobrien -T --target=<BFDNAME> Specify the binary file format\n\ 715130570Sobrien -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\ 716130570Sobrien s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\ 717218822Sdim @<file> Read options from <file>\n\ 71889865Sobrien -h --help Display this information\n\ 71989865Sobrien -v --version Print the program's version number\n")); 72033965Sjdp list_supported_targets (program_name, stream); 721218822Sdim if (REPORT_BUGS_TO[0] && status == 0) 72260513Sobrien fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); 72333965Sjdp exit (status); 72433965Sjdp} 725