On 09/04/11(Sat) 09:19, Matthew Dempsky wrote: > On Fri, Apr 8, 2011 at 11:04 PM, Martin Pieuchot <mpieuc...@nolizard.org> > wrote: > > Diff below add elf support to (bsd) strings(1) and make it usable for > > architectures with ELF_TOOLCHAIN=Yes. > > Wait, why? I don't get it. This seems out of scope for strings(1).
Without the "-a" option strings(1) doesn't scan the file entirely [0]. In this case, for elf files it only looks for strings in non empty sections flagged with SHF_ALLOC [1]. Maybe the manpage should be updated. > > > +elf32.c: ${.CURDIR}/elf.c > > + echo '#define ELFSIZE 32' | cat - $> > ${.TARGET} > > + > > +elf64.c: ${.CURDIR}/elf.c > > + echo '#define ELFSIZE 64' | cat - $> > ${.TARGET} > > Why not just create elf32.c with: > > #define ELFSIZE 32 > #include "elf.c" > > and similar for elf64.c? > I would say to not create empty files, I just used the same method as for nm. The question here is more about *how* to reuse nm(1)'s elf.c in a smart way (for nm, ranlib, strings...). I could have used the same file (diff below) but that makes the binary twice bigger in size (but still less than 5% of the size of the actual strings on amd64). Martin [0] http://pubs.opengroup.org/onlinepubs/9699919799/utilities/strings.html [1] http://www.sco.com/developers/gabi/latest/ch4.sheader.html#special_sections Index: Makefile =================================================================== RCS file: /cvs/src/usr.bin/strings/Makefile,v retrieving revision 1.3 diff -u -p -r1.3 Makefile --- Makefile 21 Sep 1997 11:51:00 -0000 1.3 +++ Makefile 10 Apr 2011 10:54:50 -0000 @@ -1,5 +1,16 @@ # $OpenBSD: Makefile,v 1.3 1997/09/21 11:51:00 deraadt Exp $ PROG= strings +SRCS= strings.c elf32.c elf64.c + +CLEANFILES+= elf32.c elf64.c + +CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../nm + +elf32.c: ${.CURDIR}/../nm/elf.c + echo '#define ELFSIZE 32' | cat - $> > ${.TARGET} + +elf64.c: ${.CURDIR}/../nm/elf.c + echo '#define ELFSIZE 64' | cat - $> > ${.TARGET} .include <bsd.prog.mk> =================================================================== RCS file: /cvs/src/usr.bin/strings/strings.c,v retrieving revision 1.15 diff -u -p -r1.15 strings.c --- strings.c 27 Oct 2009 23:59:43 -0000 1.15 +++ strings.c 10 Apr 2011 10:57:01 -0000 @@ -34,46 +34,56 @@ #include <a.out.h> #include <ctype.h> +#include <elf_abi.h> +#include <err.h> #include <errno.h> #include <fcntl.h> +#include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <locale.h> #include <unistd.h> -#include <err.h> -#define FORMAT_DEC "%07ld " -#define FORMAT_OCT "%07lo " -#define FORMAT_HEX "%07lx " +#include "elfuncs.h" + +#define FORMAT_DEC "%7lld " +#define FORMAT_OCT "%7llo " +#define FORMAT_HEX "%7llx " #define DEF_LEN 4 /* default minimum string length */ #define ISSTR(ch) (isascii(ch) && (isprint(ch) || ch == '\t')) -typedef struct exec EXEC; /* struct exec cast */ - -static long foff; /* offset in the file */ -static int hcnt, /* head count */ - head_len, /* length of header */ - read_len; /* length to read */ -static u_char hbfr[sizeof(EXEC)]; /* buffer for struct exec */ - -static void usage(void); -int getch(void); +union hdr { + struct exec aout; + Elf32_Ehdr elf32; + Elf64_Ehdr elf64; +}; + +char *stab; /* Unsused, keep elf.c happy */ +int usemmap; /* Unsused, keep elf.c happy */ + +static int hcnt, /* head count */ + head_len; /* length of header */ +static u_char hbuf[sizeof(union hdr)]; /* buffer for header */ + +short scan_entirely; +short print_name; +char *offset_format; +int minlen, maxlen, buflen; + +static void usage(void); +int getch(void); +int process_file(const char *, u_char *); +void find_strings(const char *, u_char *, off_t, off_t); int main(int argc, char *argv[]) { - extern char *optarg; - extern int optind; - int ch, cnt; - u_char *C; - EXEC *head; - int exitcode, minlen, maxlen, bfrlen; - short asdata, fflg; - u_char *bfr; - char *file, *p; - char *offset_format; + extern char *optarg; + extern int optind; + int ch, rval = 0; + u_char *buf; + char *file, *p; setlocale(LC_ALL, ""); @@ -81,7 +91,7 @@ main(int argc, char *argv[]) * for backward compatibility, allow '-' to specify 'a' flag; no * longer documented in the man page or usage string. */ - asdata = exitcode = fflg = 0; + scan_entirely = print_name = 0; offset_format = NULL; minlen = -1; maxlen = -1; @@ -103,10 +113,10 @@ main(int argc, char *argv[]) break; case '-': case 'a': - asdata = 1; + scan_entirely = 1; break; case 'f': - fflg = 1; + print_name = 1; break; case 'n': minlen = atoi(optarg); @@ -136,6 +146,7 @@ main(int argc, char *argv[]) case '?': default: usage(); + /* NOTREACHED */ } argc -= optind; argv += optind; @@ -146,85 +157,163 @@ main(int argc, char *argv[]) errx(1, "length less than 1"); if (maxlen != -1 && maxlen < minlen) errx(1, "max length less than min"); - bfrlen = maxlen == -1 ? minlen : maxlen; - bfr = malloc(bfrlen + 1); - if (!bfr) + + buflen = (maxlen == -1) ? minlen : maxlen; + if ((buf = malloc(buflen + 1)) == NULL) err(1, "malloc"); - bfr[bfrlen] = '\0'; + buf[buflen] = '\0'; + file = "stdin"; do { if (*argv) { file = *argv++; if (!freopen(file, "r", stdin)) { warn("%s", file); - exitcode = 1; - goto nextfile; + rval = 1; + continue; } } - foff = 0; -#define DO_EVERYTHING() {read_len = -1; head_len = 0; goto start;} - read_len = -1; - if (asdata) - DO_EVERYTHING() - else { - head = (EXEC *)hbfr; - if ((head_len = - read(fileno(stdin), head, sizeof(EXEC))) == -1) - DO_EVERYTHING() - if (head_len == sizeof(EXEC) && !N_BADMAG(*head)) { - foff = N_TXTOFF(*head); - if (fseek(stdin, foff, SEEK_SET) == -1) - DO_EVERYTHING() - read_len = head->a_text + head->a_data; - head_len = 0; + rval |= process_file(file, buf); + } while (*argv); + + exit(rval); +} + +int +process_file(const char *file, u_char *buf) +{ + union hdr *head; + size_t bytes; + off_t foff = 0, offset = 0; + int i, rval = 0; + + head_len = 0; + + if (scan_entirely) { + find_strings(file, buf, 0, 0); + return (0); + } + + head = (union hdr*)hbuf; + bzero(head, sizeof(*head)); + + bytes = fread((char *)head, 1, sizeof(*head), stdin); + if (bytes == -1) { + find_strings(file, buf, 0, 0); + return (1); + } + + if (bytes >= sizeof(head->aout) && !N_BADMAG(head->aout)) { + foff = N_TXTOFF(head->aout); + if (fseeko(stdin, foff, SEEK_SET)) { + warn("%s: fseeko", file); + rval = errno; + find_strings(file, buf, 0, 0); + return (rval); + } + offset = head->aout.a_text + head->aout.a_data; + } else if (IS_ELF(head->elf32) && + head->elf32.e_ident[EI_CLASS] == ELFCLASS32 && + head->elf32.e_ident[EI_VERSION] == ELF_TARG_VER) { + Elf32_Shdr *shdrs; + Elf32_Ehdr *h = &head->elf32; + + if ((shdrs = elf32_load_shdrs(file, stdin, 0, h)) == NULL) + return (1); + + for (i = 1; i < h->e_shnum; i++) { + if (shdrs[i].sh_type != SHT_NOBITS && + (shdrs[i].sh_flags & SHF_ALLOC)) { + foff = shdrs[i].sh_offset; + offset = foff + shdrs[i].sh_size; + if (fseeko(stdin, foff, SEEK_SET)) { + warn("%s: fseeko", file); + rval = errno; + break; + } + find_strings(file, buf, foff, offset); } - else - hcnt = 0; } -start: - for (cnt = 0, C = bfr; (ch = getch()) != EOF;) { - if (ISSTR(ch)) { - *C++ = ch; - if (++cnt < minlen) - continue; - if (maxlen != -1) { - while ((ch = getch()) != EOF && - ISSTR(ch) && cnt++ < maxlen) - *C++ = ch; - if (ch == EOF || - (ch != 0 && ch != '\n')) { - /* get all of too big string */ - while ((ch = getch()) != EOF && - ISSTR(ch)) - ; - ungetc(ch, stdin); - goto out; - } - *C = 0; + + free(shdrs); + return (rval); + } else if (IS_ELF(head->elf64) && + head->elf64.e_ident[EI_CLASS] == ELFCLASS64 && + head->elf64.e_ident[EI_VERSION] == ELF_TARG_VER) { + Elf64_Shdr *shdrs; + Elf64_Ehdr *h = &head->elf64; + + if ((shdrs = elf64_load_shdrs(file, stdin, 0, h)) == NULL) + return (1); + + for (i = 1; i < h->e_shnum; i++) { + if (shdrs[i].sh_type != SHT_NOBITS && + (shdrs[i].sh_flags & SHF_ALLOC)) { + foff = shdrs[i].sh_offset; + offset = foff + shdrs[i].sh_size; + if (fseeko(stdin, foff, SEEK_SET)) { + warn("%s: fseeko", file); + rval = errno; + break; } + find_strings(file, buf, foff, offset); + } + } + + free(shdrs); + return (rval); + } else { + head_len = bytes; + hcnt = 0; + } - if (fflg) - printf("%s:", file); + find_strings(file, buf, foff, offset); - if (offset_format) - printf(offset_format, foff - minlen); + return (0); +} - printf("%s", bfr); - - if (maxlen == -1) - while ((ch = getch()) != EOF && - ISSTR(ch)) - putchar((char)ch); - putchar('\n'); - out: - ; - } - cnt = 0; - C = bfr; +void +find_strings(const char *filename, u_char *buf, off_t foff, off_t offset) +{ + int i, c = 0; + + while (c != EOF && (foff < offset || !offset)) { + for (i = 0; i < buflen; i++) { + c = getch(); + foff++; + if (!ISSTR(c) || foff == offset) + break; + buf[i] = c; + buf[i + 1] = '\0'; } -nextfile: ; - } while (*argv); - exit(exitcode); + + if (i >= minlen) { + if (print_name) + printf("%s: ", filename); + + if (offset_format) + printf(offset_format, (foff - i)); + + printf("%s", buf); + + if (maxlen == -1) + while (c != EOF && (foff < offset || !offset)) { + c = getch(); + foff++; + if (!ISSTR(c) || foff == offset) + break; + putchar(c); + } + putchar('\n'); + + /* Eat all the string if it's too big */ + if (i == maxlen && (c != '\n' || c != '\0')) + while ((foff < offset || !offset) && ISSTR(c)) { + c = getch(); + foff++; + } + } + } } /* @@ -234,21 +323,23 @@ nextfile: ; int getch(void) { - ++foff; if (head_len) { if (hcnt < head_len) - return((int)hbfr[hcnt++]); + return ((int)hbuf[hcnt++]); head_len = 0; } - if (read_len == -1 || read_len-- > 0) - return(getchar()); - return(EOF); + + return (getchar()); } static void usage(void) { + extern char *__progname; + (void)fprintf(stderr, - "usage: strings [-afo] [-m number] [-n number] [-t radix] [file ...]\n"); + "usage: %s [-afo] [-m number] [-n number] [-t radix] [file ...]\n", + __progname); + exit(1); }