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