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