strings.c revision 4fce32e15d9c284a06aea2e40852f6674f03b63e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
* All Rights Reserved
*/
/*
* Copyright (c) 1987, 1988 Microsoft Corporation
* All Rights Reserved
*/
/*
* Copyright (c) 1979 Regents of the University of California
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include "a.out.h"
#include <ctype.h>
#include <wchar.h>
#include <wctype.h>
#include <libelf.h>
#include <sys/elf.h>
#include <locale.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <widec.h>
#include <gelf.h>
#include <errno.h>
#define NOTOUT 0
#define AOUT 1
#define ELF 4
struct aexec ahdr;
/*
* function prototypes
*/
static void Usage();
static void find(long);
static int ismagic(int, struct aexec *, FILE *);
static int tryelf(FILE *);
static int dirt(int, int);
/*
* Strings - extract strings from an object file for whatever
*
* The algorithm is to look for sequences of "non-junk" characters
* The variable "minlen" is the minimum length string printed.
* This helps get rid of garbage.
* Default minimum string length is 4 characters.
*
*/
#define DEF_MIN_STRING 4
static int tflg;
static char t_format;
static int aflg;
static int minlength = 0;
static int isClocale = 0;
static char *buf = NULL;
static char *tbuf = NULL;
static size_t buf_size = 0;
static int rc = 0; /* exit code */
int
main(argc, argv)
int argc;
char *argv[];
{
int hsize;
int htype;
int fd;
Elf *elf;
GElf_Ehdr ehdr;
Elf_Scn *scn;
GElf_Shdr shdr;
char *scn_name;
char *locale;
int opt;
int i;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
#endif
(void) textdomain(TEXT_DOMAIN);
locale = setlocale(LC_CTYPE, NULL);
if ((strcmp(locale, "C") == 0) ||
(strcmp(locale, "POSIX") == 0)) {
isClocale = 1;
}
/* check for non-standard "-" option */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-") == 0) {
aflg++;
while (i < argc) {
argv[i] = argv[i+1];
i++;
}
argc--;
}
}
/* get options */
while ((opt = getopt(argc, argv, "1234567890an:ot:")) != -1) {
switch (opt) {
case 'a':
aflg++;
break;
case 'n':
minlength = (int)strtol(optarg, (char **)NULL,
10);
break;
case 'o':
tflg++;
t_format = 'd';
break;
case 't':
tflg++;
t_format = *optarg;
if (t_format != 'd' && t_format != 'o' &&
t_format != 'x')
{
(void) fprintf(stderr,
gettext("Invalid format\n"));
Usage();
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
minlength *= 10;
minlength += opt - '0';
break;
default:
Usage();
}
}
/* if min string not specified, use default */
if (!minlength)
minlength = DEF_MIN_STRING;
/* dynamic allocation of char buffer array */
buf = (char *)malloc(BUFSIZ);
if (buf == NULL) {
(void) fprintf(stderr, gettext("Cannot allocate memory: %s\n"),
strerror(errno));
exit(1);
}
buf_size = BUFSIZ;
tbuf = buf;
/* for each file operand */
do {
if (argv[optind] != NULL) {
if (freopen(argv[optind], "r", stdin) == NULL) {
perror(argv[optind]);
rc = 1;
optind++;
continue;
}
optind++;
} else
aflg++;
if (aflg)
htype = NOTOUT;
else {
hsize = fread((char *)&ahdr, sizeof (char),
sizeof (ahdr), stdin);
htype = ismagic(hsize, &ahdr, stdin);
}
switch (htype) {
case AOUT:
(void) fseek(stdin, (long)ADATAPOS(&ahdr), 0);
find((long)ahdr.xa_data);
continue;
case ELF:
/*
* Will take care of COFF M32 and i386 also
* As well as ELF M32, i386 and Sparc (32- and 64-bit)
*/
fd = fileno(stdin);
(void) lseek(fd, 0L, 0);
elf = elf_begin(fd, ELF_C_READ, NULL);
if (gelf_getehdr(elf, &ehdr) ==
(GElf_Ehdr *)NULL) {
(void) fprintf(stderr, "%s: %s\n",
argv[optind-1], elf_errmsg(-1));
(void) elf_end(elf);
rc = 1;
continue;
}
scn = 0;
while ((scn = elf_nextscn(elf, scn)) != 0)
{
if (gelf_getshdr(scn, &shdr) ==
(GElf_Shdr *)0) {
(void) fprintf(stderr,
"%s: %s\n", argv[optind-1],
elf_errmsg(-1));
rc = 1;
continue;
}
if ((scn_name = elf_strptr(elf,
ehdr.e_shstrndx,
(size_t)shdr.sh_name))
== (char *)NULL) {
(void) fprintf(stderr,
"%s: %s\n", argv[optind-1],
elf_errmsg(-1));
rc = 1;
continue;
}
/*
* There is more than one .data section
*/
if ((strcmp(scn_name, ".rodata")
== 0) ||
(strcmp(scn_name, ".rodata1")
== 0) ||
(strcmp(scn_name, ".data")
== 0) ||
(strcmp(scn_name, ".data1")
== 0))
{
(void) fseek(stdin,
(long)shdr.sh_offset, 0);
find((long)shdr.sh_size);
}
}
continue;
case NOTOUT:
default:
if (!aflg)
(void) fseek(stdin, (long)0, 0);
find(LONG_MAX);
continue;
}
} while (argv[optind] != NULL);
return (rc);
}
static void
find(cnt)
long cnt;
{
int c;
int cc;
int cr;
cc = 0;
for (c = ~EOF; (cnt > 0) && (c != EOF); cnt--) {
c = getc(stdin);
if (!(cr = dirt(c, cc))) {
if (cc >= minlength) {
if (tflg) {
switch (t_format) {
case 'd':
(void) printf("%7ld ",
ftell(stdin) - cc - 1);
break;
case 'o':
(void) printf("%7lo ",
ftell(stdin) - cc - 1);
break;
case 'x':
(void) printf("%7lx ",
ftell(stdin) - cc - 1);
break;
}
}
if (cc >= buf_size)
buf[buf_size-1] = '\0';
else
buf[cc] = '\0';
(void) puts(buf);
}
cc = 0;
}
cc += cr;
}
}
static int
dirt(c, cc)
int c;
int cc;
{
char mbuf[MB_LEN_MAX + 1];
int len, len1, i;
wchar_t wc;
int r_val;
if (isascii(c)) {
if (isprint(c)) {
/*
* If character count is greater than dynamic
* char buffer size, then increase char buffer size.
*/
if (cc >= (buf_size-2)) {
if (tbuf != NULL) {
buf_size += BUFSIZ;
tbuf = (char *)realloc(buf, buf_size);
if (tbuf == NULL) {
(void) fprintf(stderr,
gettext("Cannot allocate memory: %s\n"),
strerror(errno));
buf_size -= BUFSIZ;
rc = 1;
return (0);
} else {
buf = tbuf;
}
} else {
return (0);
}
}
buf[cc] = c;
return (1);
}
return (0);
}
if (isClocale)
return (0);
r_val = 0;
mbuf[0] = c;
for (len = 1; len < (unsigned int)MB_CUR_MAX; len++) {
if ((signed char)
(mbuf[len] = getc(stdin)) == -1)
break;
}
mbuf[len] = 0;
if ((len1 = mbtowc(&wc, mbuf, len)) <= 0) {
len1 = 1;
goto _unget;
}
if (iswprint(wc)) {
if ((cc + len1) >= (buf_size-2)) {
if (tbuf != NULL) {
buf_size += BUFSIZ;
tbuf = (char *)realloc(buf, buf_size);
if (tbuf == NULL) {
(void) fprintf(stderr,
gettext("Cannot allocate memory: %s\n"),
strerror(errno));
buf_size -= BUFSIZ;
rc = 1;
return (0);
}
buf = tbuf;
} else {
return (0);
}
}
for (i = 0; i < len1; i++, cc++)
buf[cc] = mbuf[i];
r_val = len1;
}
_unget:
for (len--; len >= len1; len--)
(void) ungetc(mbuf[len], stdin);
return (r_val);
}
static int
ismagic(hsize, hdr, fp)
int hsize;
struct aexec *hdr;
FILE *fp;
{
switch (hdr->xa_magic) {
case A_MAGIC1:
case A_MAGIC2:
case A_MAGIC3:
case A_MAGIC4:
if (hsize < sizeof (struct aexec))
return (NOTOUT);
else
return (AOUT);
default:
break;
}
return (tryelf(fp));
}
static int
tryelf(fp)
FILE *fp;
{
int fd;
Elf *elf;
GElf_Ehdr ehdr;
fd = fileno(fp);
if ((elf_version(EV_CURRENT)) == EV_NONE) {
(void) fprintf(stderr, "%s\n", elf_errmsg(-1));
return (NOTOUT);
}
(void) lseek(fd, 0L, 0);
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
(void) fprintf(stderr, "%s\n", elf_errmsg(-1));
return (NOTOUT);
}
switch (elf_kind(elf)) {
case ELF_K_AR:
/*
* This should try to run strings on each element
* of the archive. For now, just search entire
* file (-a), as strings has always done
* for archives.
*/
case ELF_K_NONE:
(void) elf_end(elf);
return (NOTOUT);
}
if (gelf_getehdr(elf, &ehdr) == (GElf_Ehdr *)NULL) {
(void) fprintf(stderr, "%s\n", elf_errmsg(-1));
(void) elf_end(elf);
return (NOTOUT);
}
if ((ehdr.e_type == ET_CORE) || (ehdr.e_type == ET_NONE)) {
(void) elf_end(elf);
return (NOTOUT);
}
(void) elf_end(elf);
return (ELF);
}
static void
Usage()
{
(void) fprintf(stderr, gettext(
"Usage: strings [-|-a] [-t format] [-n #] [file ...]\n"
" strings [-|-a] [-o] [-#] [file ...]\n"));
exit(1);
}