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);
 }

Reply via email to