xref: /freebsd-src/contrib/elftoolchain/strings/strings.c (revision 839529caa9c35f92b638dbe074655598e7a6bb6f)
1a85fe12eSEd Maste /*-
2a85fe12eSEd Maste  * Copyright (c) 2007 S.Sam Arun Raj
3a85fe12eSEd Maste  * All rights reserved.
4a85fe12eSEd Maste  *
5a85fe12eSEd Maste  * Redistribution and use in source and binary forms, with or without
6a85fe12eSEd Maste  * modification, are permitted provided that the following conditions
7a85fe12eSEd Maste  * are met:
8a85fe12eSEd Maste  * 1. Redistributions of source code must retain the above copyright
9a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer.
10a85fe12eSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
11a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer in the
12a85fe12eSEd Maste  *    documentation and/or other materials provided with the distribution.
13a85fe12eSEd Maste  *
14a85fe12eSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a85fe12eSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a85fe12eSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a85fe12eSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a85fe12eSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a85fe12eSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a85fe12eSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a85fe12eSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a85fe12eSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a85fe12eSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a85fe12eSEd Maste  * SUCH DAMAGE.
25a85fe12eSEd Maste  */
26a85fe12eSEd Maste 
27a85fe12eSEd Maste #include <sys/stat.h>
28a85fe12eSEd Maste #include <sys/types.h>
29a85fe12eSEd Maste 
30a85fe12eSEd Maste #include <ctype.h>
31a85fe12eSEd Maste #include <err.h>
32a85fe12eSEd Maste #include <errno.h>
33a85fe12eSEd Maste #include <fcntl.h>
34a85fe12eSEd Maste #include <getopt.h>
35a85fe12eSEd Maste #include <inttypes.h>
36a85fe12eSEd Maste #include <stdint.h>
37a85fe12eSEd Maste #include <stdio.h>
38a85fe12eSEd Maste #include <stdlib.h>
39a85fe12eSEd Maste #include <string.h>
40*839529caSEd Maste #include <sysexits.h>
41a85fe12eSEd Maste #include <unistd.h>
42a85fe12eSEd Maste 
43a85fe12eSEd Maste #include <libelf.h>
44a85fe12eSEd Maste #include <libelftc.h>
45a85fe12eSEd Maste #include <gelf.h>
46a85fe12eSEd Maste 
47a85fe12eSEd Maste #include "_elftc.h"
48a85fe12eSEd Maste 
49*839529caSEd Maste ELFTC_VCSID("$Id: strings.c 3360 2016-01-24 18:34:06Z jkoshy $");
50a85fe12eSEd Maste 
51a85fe12eSEd Maste enum return_code {
52a85fe12eSEd Maste 	RETURN_OK,
53a85fe12eSEd Maste 	RETURN_NOINPUT,
54a85fe12eSEd Maste 	RETURN_SOFTWARE
55a85fe12eSEd Maste };
56a85fe12eSEd Maste 
57a85fe12eSEd Maste enum radix_style {
58a85fe12eSEd Maste 	RADIX_DECIMAL,
59a85fe12eSEd Maste 	RADIX_HEX,
60a85fe12eSEd Maste 	RADIX_OCTAL
61a85fe12eSEd Maste };
62a85fe12eSEd Maste 
63a85fe12eSEd Maste enum encoding_style {
64a85fe12eSEd Maste 	ENCODING_7BIT,
65a85fe12eSEd Maste 	ENCODING_8BIT,
66a85fe12eSEd Maste 	ENCODING_16BIT_BIG,
67a85fe12eSEd Maste 	ENCODING_16BIT_LITTLE,
68a85fe12eSEd Maste 	ENCODING_32BIT_BIG,
69a85fe12eSEd Maste 	ENCODING_32BIT_LITTLE
70a85fe12eSEd Maste };
71a85fe12eSEd Maste 
72a85fe12eSEd Maste #define PRINTABLE(c)						\
73a85fe12eSEd Maste       ((c) >= 0 && (c) <= 255 && 				\
74a85fe12eSEd Maste 	  ((c) == '\t' || isprint((c)) ||			\
75a85fe12eSEd Maste 	      (encoding == ENCODING_8BIT && (c) > 127)))
76a85fe12eSEd Maste 
77*839529caSEd Maste static int encoding_size, entire_file, show_filename, show_loc;
7850f69bfbSEd Maste static enum encoding_style encoding;
7950f69bfbSEd Maste static enum radix_style radix;
80*839529caSEd Maste static intmax_t min_len;
81a85fe12eSEd Maste 
82a85fe12eSEd Maste static struct option strings_longopts[] = {
83a85fe12eSEd Maste 	{ "all",		no_argument,		NULL,	'a'},
84a85fe12eSEd Maste 	{ "bytes",		required_argument,	NULL,	'n'},
85a85fe12eSEd Maste 	{ "encoding",		required_argument,	NULL,	'e'},
86a85fe12eSEd Maste 	{ "help",		no_argument,		NULL,	'h'},
87a85fe12eSEd Maste 	{ "print-file-name",	no_argument,		NULL,	'f'},
88a85fe12eSEd Maste 	{ "radix",		required_argument,	NULL,	't'},
89a85fe12eSEd Maste 	{ "version",		no_argument,		NULL,	'v'},
90a85fe12eSEd Maste 	{ NULL, 0, NULL, 0 }
91a85fe12eSEd Maste };
92a85fe12eSEd Maste 
93a85fe12eSEd Maste long	getcharacter(void);
94a85fe12eSEd Maste int	handle_file(const char *);
95a85fe12eSEd Maste int	handle_elf(const char *, int);
96a85fe12eSEd Maste int	handle_binary(const char *, int);
97a85fe12eSEd Maste int	find_strings(const char *, off_t, off_t);
98a85fe12eSEd Maste void	show_version(void);
99a85fe12eSEd Maste void	usage(void);
100a85fe12eSEd Maste 
101a85fe12eSEd Maste /*
102a85fe12eSEd Maste  * strings(1) extracts text(contiguous printable characters)
103a85fe12eSEd Maste  * from elf and binary files.
104a85fe12eSEd Maste  */
105a85fe12eSEd Maste int
106a85fe12eSEd Maste main(int argc, char **argv)
107a85fe12eSEd Maste {
108a85fe12eSEd Maste 	int ch, rc;
109a85fe12eSEd Maste 
110a85fe12eSEd Maste 	rc = RETURN_OK;
111a85fe12eSEd Maste 	min_len = 0;
112a85fe12eSEd Maste 	encoding_size = 1;
113a85fe12eSEd Maste 	if (elf_version(EV_CURRENT) == EV_NONE)
114a85fe12eSEd Maste 		errx(EXIT_FAILURE, "ELF library initialization failed: %s",
115a85fe12eSEd Maste 		    elf_errmsg(-1));
116a85fe12eSEd Maste 
117a85fe12eSEd Maste 	while ((ch = getopt_long(argc, argv, "1234567890ae:fhn:ot:Vv",
118a85fe12eSEd Maste 	    strings_longopts, NULL)) != -1)
119a85fe12eSEd Maste 		switch((char)ch) {
120a85fe12eSEd Maste 		case 'a':
121a85fe12eSEd Maste 			entire_file = 1;
122a85fe12eSEd Maste 			break;
123a85fe12eSEd Maste 		case 'e':
124a85fe12eSEd Maste 			if (*optarg == 's') {
125a85fe12eSEd Maste 				encoding = ENCODING_7BIT;
126a85fe12eSEd Maste 			} else if (*optarg == 'S') {
127a85fe12eSEd Maste 				encoding = ENCODING_8BIT;
128a85fe12eSEd Maste 			} else if (*optarg == 'b') {
129a85fe12eSEd Maste 				encoding = ENCODING_16BIT_BIG;
130a85fe12eSEd Maste 				encoding_size = 2;
131a85fe12eSEd Maste 			} else if (*optarg == 'B') {
132a85fe12eSEd Maste 				encoding = ENCODING_32BIT_BIG;
133a85fe12eSEd Maste 				encoding_size = 4;
134a85fe12eSEd Maste 			} else if (*optarg == 'l') {
135a85fe12eSEd Maste 				encoding = ENCODING_16BIT_LITTLE;
136a85fe12eSEd Maste 				encoding_size = 2;
137a85fe12eSEd Maste 			} else if (*optarg == 'L') {
138a85fe12eSEd Maste 				encoding = ENCODING_32BIT_LITTLE;
139a85fe12eSEd Maste 				encoding_size = 4;
140a85fe12eSEd Maste 			} else
141a85fe12eSEd Maste 				usage();
142a85fe12eSEd Maste 			        /* NOTREACHED */
143a85fe12eSEd Maste 			break;
144a85fe12eSEd Maste 		case 'f':
145a85fe12eSEd Maste 			show_filename = 1;
146a85fe12eSEd Maste 			break;
147a85fe12eSEd Maste 		case 'n':
148*839529caSEd Maste 			min_len = strtoimax(optarg, (char**)NULL, 10);
149*839529caSEd Maste 			if (min_len <= 0)
150*839529caSEd Maste 				errx(EX_USAGE, "option -n should specify a "
151*839529caSEd Maste 				    "positive decimal integer.");
152a85fe12eSEd Maste 			break;
153a85fe12eSEd Maste 		case 'o':
154a85fe12eSEd Maste 			show_loc = 1;
155a85fe12eSEd Maste 			radix = RADIX_OCTAL;
156a85fe12eSEd Maste 			break;
157a85fe12eSEd Maste 		case 't':
158a85fe12eSEd Maste 			show_loc = 1;
159a85fe12eSEd Maste 			if (*optarg == 'd')
160a85fe12eSEd Maste 				radix = RADIX_DECIMAL;
161a85fe12eSEd Maste 			else if (*optarg == 'o')
162a85fe12eSEd Maste 				radix = RADIX_OCTAL;
163a85fe12eSEd Maste 			else if (*optarg == 'x')
164a85fe12eSEd Maste 				radix = RADIX_HEX;
165a85fe12eSEd Maste 			else
166a85fe12eSEd Maste 				usage();
167a85fe12eSEd Maste 			        /* NOTREACHED */
168a85fe12eSEd Maste 			break;
169a85fe12eSEd Maste 		case 'v':
170a85fe12eSEd Maste 		case 'V':
171a85fe12eSEd Maste 			show_version();
172a85fe12eSEd Maste 			/* NOTREACHED */
173a85fe12eSEd Maste 		case '0':
174a85fe12eSEd Maste 	        case '1':
175a85fe12eSEd Maste 		case '2':
176a85fe12eSEd Maste 		case '3':
177a85fe12eSEd Maste 		case '4':
178a85fe12eSEd Maste 		case '5':
179a85fe12eSEd Maste 		case '6':
180a85fe12eSEd Maste 		case '7':
181a85fe12eSEd Maste 		case '8':
182a85fe12eSEd Maste 		case '9':
183a85fe12eSEd Maste 			min_len *= 10;
184a85fe12eSEd Maste 			min_len += ch - '0';
185a85fe12eSEd Maste 			break;
186a85fe12eSEd Maste 		case 'h':
187a85fe12eSEd Maste 		case '?':
188a85fe12eSEd Maste 		default:
189a85fe12eSEd Maste 			usage();
190a85fe12eSEd Maste 			/* NOTREACHED */
191a85fe12eSEd Maste 		}
192a85fe12eSEd Maste 	argc -= optind;
193a85fe12eSEd Maste 	argv += optind;
194a85fe12eSEd Maste 
195a85fe12eSEd Maste 	if (!min_len)
196a85fe12eSEd Maste 		min_len = 4;
197a85fe12eSEd Maste 	if (!*argv)
198a85fe12eSEd Maste 		rc = handle_file("{standard input}");
199a85fe12eSEd Maste 	else while (*argv) {
200a85fe12eSEd Maste 		rc = handle_file(*argv);
201a85fe12eSEd Maste 		argv++;
202a85fe12eSEd Maste 	}
203a85fe12eSEd Maste 	return (rc);
204a85fe12eSEd Maste }
205a85fe12eSEd Maste 
206a85fe12eSEd Maste int
207a85fe12eSEd Maste handle_file(const char *name)
208a85fe12eSEd Maste {
209a85fe12eSEd Maste 	int fd, rt;
210a85fe12eSEd Maste 
211a85fe12eSEd Maste 	if (name == NULL)
212a85fe12eSEd Maste 		return (RETURN_NOINPUT);
213a85fe12eSEd Maste 	if (strcmp("{standard input}", name) != 0) {
214a85fe12eSEd Maste 		if (freopen(name, "rb", stdin) == NULL) {
215a85fe12eSEd Maste 			warnx("'%s': %s", name, strerror(errno));
216a85fe12eSEd Maste 			return (RETURN_NOINPUT);
217a85fe12eSEd Maste 		}
218a85fe12eSEd Maste 	} else {
219a85fe12eSEd Maste 		return (find_strings(name, (off_t)0, (off_t)0));
220a85fe12eSEd Maste 	}
221a85fe12eSEd Maste 
222a85fe12eSEd Maste 	fd = fileno(stdin);
223a85fe12eSEd Maste 	if (fd < 0)
224a85fe12eSEd Maste 		return (RETURN_NOINPUT);
225a85fe12eSEd Maste 	rt = handle_elf(name, fd);
226a85fe12eSEd Maste 	return (rt);
227a85fe12eSEd Maste }
228a85fe12eSEd Maste 
229a85fe12eSEd Maste /*
230a85fe12eSEd Maste  * Files not understood by handle_elf, will be passed off here and will
231a85fe12eSEd Maste  * treated as a binary file. This would include text file, core dumps ...
232a85fe12eSEd Maste  */
233a85fe12eSEd Maste int
234a85fe12eSEd Maste handle_binary(const char *name, int fd)
235a85fe12eSEd Maste {
236a85fe12eSEd Maste 	struct stat buf;
237a85fe12eSEd Maste 
238a85fe12eSEd Maste 	memset(&buf, 0, sizeof(struct stat));
239a85fe12eSEd Maste 	(void) lseek(fd, (off_t)0, SEEK_SET);
240a85fe12eSEd Maste 	if (!fstat(fd, &buf))
241a85fe12eSEd Maste 		return (find_strings(name, (off_t)0, buf.st_size));
242a85fe12eSEd Maste 	return (RETURN_SOFTWARE);
243a85fe12eSEd Maste }
244a85fe12eSEd Maste 
245a85fe12eSEd Maste /*
246a85fe12eSEd Maste  * Will analyse a file to see if it ELF, other files including ar(1),
247a85fe12eSEd Maste  * core dumps are passed off and treated as flat binary files. Unlike
248a85fe12eSEd Maste  * GNU size in FreeBSD this routine will not treat ELF object from
249a85fe12eSEd Maste  * different archs as flat binary files(has to overridden using -a).
250a85fe12eSEd Maste  */
251a85fe12eSEd Maste int
252a85fe12eSEd Maste handle_elf(const char *name, int fd)
253a85fe12eSEd Maste {
254a85fe12eSEd Maste 	GElf_Ehdr elfhdr;
255a85fe12eSEd Maste 	GElf_Shdr shdr;
256a85fe12eSEd Maste 	Elf *elf;
257a85fe12eSEd Maste 	Elf_Scn *scn;
258a85fe12eSEd Maste 	int rc;
259a85fe12eSEd Maste 
260a85fe12eSEd Maste 	rc = RETURN_OK;
261a85fe12eSEd Maste 	/* If entire file is choosen, treat it as a binary file */
262a85fe12eSEd Maste 	if (entire_file)
263a85fe12eSEd Maste 		return (handle_binary(name, fd));
264a85fe12eSEd Maste 
265a85fe12eSEd Maste 	(void) lseek(fd, (off_t)0, SEEK_SET);
266a85fe12eSEd Maste 	elf = elf_begin(fd, ELF_C_READ, NULL);
267a85fe12eSEd Maste 	if (elf_kind(elf) != ELF_K_ELF) {
268a85fe12eSEd Maste 		(void) elf_end(elf);
269a85fe12eSEd Maste 		return (handle_binary(name, fd));
270a85fe12eSEd Maste 	}
271a85fe12eSEd Maste 
272a85fe12eSEd Maste 	if (gelf_getehdr(elf, &elfhdr) == NULL) {
273a85fe12eSEd Maste 		(void) elf_end(elf);
274a85fe12eSEd Maste 		warnx("%s: ELF file could not be processed", name);
275a85fe12eSEd Maste 		return (RETURN_SOFTWARE);
276a85fe12eSEd Maste 	}
277a85fe12eSEd Maste 
278a85fe12eSEd Maste 	if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) {
279a85fe12eSEd Maste 		(void) elf_end(elf);
280a85fe12eSEd Maste 		return (handle_binary(name, fd));
281a85fe12eSEd Maste 	} else {
282a85fe12eSEd Maste 		scn = NULL;
283a85fe12eSEd Maste 		while ((scn = elf_nextscn(elf, scn)) != NULL) {
284a85fe12eSEd Maste 			if (gelf_getshdr(scn, &shdr) == NULL)
285a85fe12eSEd Maste 				continue;
286a85fe12eSEd Maste 			if (shdr.sh_type != SHT_NOBITS &&
287a85fe12eSEd Maste 			    (shdr.sh_flags & SHF_ALLOC) != 0) {
288a85fe12eSEd Maste 				rc = find_strings(name, shdr.sh_offset,
289a85fe12eSEd Maste 				    shdr.sh_size);
290a85fe12eSEd Maste 			}
291a85fe12eSEd Maste 		}
292a85fe12eSEd Maste 	}
293a85fe12eSEd Maste 	(void) elf_end(elf);
294a85fe12eSEd Maste 	return (rc);
295a85fe12eSEd Maste }
296a85fe12eSEd Maste 
297a85fe12eSEd Maste /*
298a85fe12eSEd Maste  * Retrieves a character from input stream based on the encoding
299a85fe12eSEd Maste  * type requested.
300a85fe12eSEd Maste  */
301a85fe12eSEd Maste long
302a85fe12eSEd Maste getcharacter(void)
303a85fe12eSEd Maste {
304a85fe12eSEd Maste 	long rt;
305a85fe12eSEd Maste 	int i;
306a85fe12eSEd Maste 	char buf[4], c;
307a85fe12eSEd Maste 
308a85fe12eSEd Maste 	rt = EOF;
309a85fe12eSEd Maste 	for(i = 0; i < encoding_size; i++) {
310a85fe12eSEd Maste 		c = getc(stdin);
311a85fe12eSEd Maste 		if (feof(stdin))
312a85fe12eSEd Maste 			return (EOF);
313a85fe12eSEd Maste 		buf[i] = c;
314a85fe12eSEd Maste 	}
315a85fe12eSEd Maste 
316a85fe12eSEd Maste 	switch(encoding) {
317a85fe12eSEd Maste 	case ENCODING_7BIT:
318a85fe12eSEd Maste 	case ENCODING_8BIT:
319a85fe12eSEd Maste 		rt = buf[0];
320a85fe12eSEd Maste 		break;
321a85fe12eSEd Maste 	case ENCODING_16BIT_BIG:
322a85fe12eSEd Maste 		rt = (buf[0] << 8) | buf[1];
323a85fe12eSEd Maste 		break;
324a85fe12eSEd Maste 	case ENCODING_16BIT_LITTLE:
325a85fe12eSEd Maste 		 rt = buf[0] | (buf[1] << 8);
326a85fe12eSEd Maste 		 break;
327a85fe12eSEd Maste 	case ENCODING_32BIT_BIG:
328a85fe12eSEd Maste 		rt = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
329a85fe12eSEd Maste            	    ((long) buf[2] << 8) | buf[3];
330a85fe12eSEd Maste            	break;
331a85fe12eSEd Maste 	case ENCODING_32BIT_LITTLE:
332a85fe12eSEd Maste 		rt = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
333a85fe12eSEd Maste         	    ((long) buf[3] << 24);
334a85fe12eSEd Maste            	break;
335a85fe12eSEd Maste 	}
336a85fe12eSEd Maste 	return (rt);
337a85fe12eSEd Maste }
338a85fe12eSEd Maste 
339a85fe12eSEd Maste /*
340a85fe12eSEd Maste  * Input stream stdin is read until the end of file is reached or until
341a85fe12eSEd Maste  * the section size is reached in case of ELF files. Contiguous
342a85fe12eSEd Maste  * characters of >= min_size(default 4) will be displayed.
343a85fe12eSEd Maste  */
344a85fe12eSEd Maste int
345a85fe12eSEd Maste find_strings(const char *name, off_t offset, off_t size)
346a85fe12eSEd Maste {
347a85fe12eSEd Maste 	off_t cur_off, start_off;
348a85fe12eSEd Maste 	char *obuf;
349a85fe12eSEd Maste 	long c;
350a85fe12eSEd Maste 	int i;
351a85fe12eSEd Maste 
352a85fe12eSEd Maste 	if ((obuf = (char*)calloc(1, min_len + 1)) == NULL) {
353a85fe12eSEd Maste 		(void) fprintf(stderr, "Unable to allocate memory: %s\n",
354a85fe12eSEd Maste 		     strerror(errno));
355a85fe12eSEd Maste 		return (RETURN_SOFTWARE);
356a85fe12eSEd Maste 	}
357a85fe12eSEd Maste 
358a85fe12eSEd Maste 	(void) fseeko(stdin, offset, SEEK_SET);
359a85fe12eSEd Maste 	cur_off = offset;
360a85fe12eSEd Maste 	start_off = 0;
361a85fe12eSEd Maste 	while(1) {
362a85fe12eSEd Maste 		if ((offset + size) && (cur_off >= offset + size))
363a85fe12eSEd Maste 			break;
364a85fe12eSEd Maste 		start_off = cur_off;
365a85fe12eSEd Maste 		memset(obuf, 0, min_len+1);
366a85fe12eSEd Maste 		for(i = 0; i < min_len; i++) {
367a85fe12eSEd Maste 			c = getcharacter();
368a85fe12eSEd Maste 			if (c == EOF && feof(stdin))
369a85fe12eSEd Maste 				goto _exit1;
370a85fe12eSEd Maste 		 	if (PRINTABLE(c)) {
371a85fe12eSEd Maste 		 		obuf[i] = c;
372a85fe12eSEd Maste 		 		obuf[i+1] = 0;
373a85fe12eSEd Maste 		 		cur_off += encoding_size;
374a85fe12eSEd Maste 		 	} else {
375a85fe12eSEd Maste 				if (encoding == ENCODING_8BIT &&
376a85fe12eSEd Maste 				    (uint8_t)c > 127) {
377a85fe12eSEd Maste 			 		obuf[i] = c;
378a85fe12eSEd Maste 			 		obuf[i+1] = 0;
379a85fe12eSEd Maste 			 		cur_off += encoding_size;
380a85fe12eSEd Maste 			 		continue;
381a85fe12eSEd Maste 			 	}
382a85fe12eSEd Maste 	 			cur_off += encoding_size;
383a85fe12eSEd Maste 	 			break;
384a85fe12eSEd Maste 		 	}
385a85fe12eSEd Maste 		}
386a85fe12eSEd Maste 
387a85fe12eSEd Maste 		if (i >= min_len && ((cur_off <= offset + size) ||
388a85fe12eSEd Maste 		    !(offset + size))) {
389a85fe12eSEd Maste 			if (show_filename)
390a85fe12eSEd Maste 				printf ("%s: ", name);
391a85fe12eSEd Maste 			if (show_loc) {
392a85fe12eSEd Maste 				switch(radix) {
393a85fe12eSEd Maste 				case RADIX_DECIMAL:
394a85fe12eSEd Maste 					(void) printf("%7ju ",
395a85fe12eSEd Maste 					    (uintmax_t)start_off);
396a85fe12eSEd Maste 					break;
397a85fe12eSEd Maste 				case RADIX_HEX:
398a85fe12eSEd Maste 					(void) printf("%7jx ",
399a85fe12eSEd Maste 					    (uintmax_t)start_off);
400a85fe12eSEd Maste 					break;
401a85fe12eSEd Maste 				case RADIX_OCTAL:
402a85fe12eSEd Maste 					(void) printf("%7jo ",
403a85fe12eSEd Maste 					    (uintmax_t)start_off);
404a85fe12eSEd Maste 					break;
405a85fe12eSEd Maste 				}
406a85fe12eSEd Maste 			}
407a85fe12eSEd Maste 			printf("%s", obuf);
408a85fe12eSEd Maste 
409a85fe12eSEd Maste 			while(1) {
410a85fe12eSEd Maste 				if ((offset + size) &&
411a85fe12eSEd Maste 				    (cur_off >= offset + size))
412a85fe12eSEd Maste 					break;
413a85fe12eSEd Maste 				c = getcharacter();
414a85fe12eSEd Maste 				cur_off += encoding_size;
415a85fe12eSEd Maste 				if (encoding == ENCODING_8BIT &&
416a85fe12eSEd Maste 				    (uint8_t)c > 127) {
417a85fe12eSEd Maste 			 		putchar(c);
418a85fe12eSEd Maste 			 		continue;
419a85fe12eSEd Maste 			 	}
420a85fe12eSEd Maste 				if (!PRINTABLE(c) || c == EOF)
421a85fe12eSEd Maste 					break;
422a85fe12eSEd Maste 				putchar(c);
423a85fe12eSEd Maste 			}
424a85fe12eSEd Maste 			putchar('\n');
425a85fe12eSEd Maste 		}
426a85fe12eSEd Maste 	}
427a85fe12eSEd Maste _exit1:
428a85fe12eSEd Maste 	free(obuf);
429a85fe12eSEd Maste 	return (RETURN_OK);
430a85fe12eSEd Maste }
431a85fe12eSEd Maste 
432a85fe12eSEd Maste #define	USAGE_MESSAGE	"\
433a85fe12eSEd Maste Usage: %s [options] [file...]\n\
434a85fe12eSEd Maste   Print contiguous sequences of printable characters.\n\n\
435a85fe12eSEd Maste   Options:\n\
436a85fe12eSEd Maste   -a     | --all               Scan the entire file for strings.\n\
437a85fe12eSEd Maste   -e ENC | --encoding=ENC      Select the character encoding to use.\n\
438a85fe12eSEd Maste   -f     | --print-file-name   Print the file name before each string.\n\
439a85fe12eSEd Maste   -h     | --help              Print a help message and exit.\n\
440a85fe12eSEd Maste   -n N   | --bytes=N | -N      Print sequences with 'N' or more characters.\n\
441a85fe12eSEd Maste   -o                           Print offsets in octal.\n\
442a85fe12eSEd Maste   -t R   | --radix=R           Print offsets using the radix named by 'R'.\n\
443a85fe12eSEd Maste   -v     | --version           Print a version identifier and exit.\n"
444a85fe12eSEd Maste 
445a85fe12eSEd Maste void
446a85fe12eSEd Maste usage(void)
447a85fe12eSEd Maste {
448a85fe12eSEd Maste 	(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
449a85fe12eSEd Maste 	exit(EXIT_FAILURE);
450a85fe12eSEd Maste }
451a85fe12eSEd Maste 
452a85fe12eSEd Maste void
453a85fe12eSEd Maste show_version(void)
454a85fe12eSEd Maste {
455a85fe12eSEd Maste         (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
456a85fe12eSEd Maste         exit(EXIT_SUCCESS);
457a85fe12eSEd Maste }
458