1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T 29 * All Rights Reserved 30 */ 31 32 /* 33 * Copyright (c) 1987, 1988 Microsoft Corporation 34 * All Rights Reserved 35 */ 36 37 /* 38 * Copyright (c) 1979 Regents of the University of California 39 */ 40 41 #pragma ident "%Z%%M% %I% %E% SMI" 42 43 #include <stdio.h> 44 #include "a.out.h" 45 #include <ctype.h> 46 #include <wchar.h> 47 #include <wctype.h> 48 #include <libelf.h> 49 #include <sys/elf.h> 50 #include <locale.h> 51 #include <string.h> 52 #include <stdlib.h> 53 #include <sys/types.h> 54 #include <unistd.h> 55 #include <limits.h> 56 #include <widec.h> 57 #include <gelf.h> 58 #include <errno.h> 59 60 61 #define NOTOUT 0 62 #define AOUT 1 63 #define ELF 4 64 65 struct aexec ahdr; 66 67 /* 68 * function prototypes 69 */ 70 static void Usage(); 71 static void find(long); 72 static int ismagic(int, struct aexec *, FILE *); 73 static int tryelf(FILE *); 74 static int dirt(int, int); 75 76 77 /* 78 * Strings - extract strings from an object file for whatever 79 * 80 * The algorithm is to look for sequences of "non-junk" characters 81 * The variable "minlen" is the minimum length string printed. 82 * This helps get rid of garbage. 83 * Default minimum string length is 4 characters. 84 * 85 */ 86 87 #define DEF_MIN_STRING 4 88 89 static int tflg; 90 static char t_format; 91 static int aflg; 92 static int minlength = 0; 93 static int isClocale = 0; 94 static char *buf = NULL; 95 static char *tbuf = NULL; 96 static size_t buf_size = 0; 97 static int rc = 0; /* exit code */ 98 99 int 100 main(argc, argv) 101 int argc; 102 char *argv[]; 103 { 104 int hsize; 105 int htype; 106 int fd; 107 Elf *elf; 108 GElf_Ehdr ehdr; 109 Elf_Scn *scn; 110 GElf_Shdr shdr; 111 char *scn_name; 112 char *locale; 113 int opt; 114 int i; 115 116 (void) setlocale(LC_ALL, ""); 117 118 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 119 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 120 #endif 121 (void) textdomain(TEXT_DOMAIN); 122 123 locale = setlocale(LC_CTYPE, NULL); 124 if ((strcmp(locale, "C") == 0) || 125 (strcmp(locale, "POSIX") == 0)) { 126 isClocale = 1; 127 } 128 129 /* check for non-standard "-" option */ 130 for (i = 1; i < argc; i++) { 131 if (strcmp(argv[i], "-") == 0) { 132 aflg++; 133 while (i < argc) { 134 argv[i] = argv[i+1]; 135 i++; 136 } 137 argc--; 138 } 139 } 140 141 /* get options */ 142 while ((opt = getopt(argc, argv, "1234567890an:ot:")) != -1) { 143 switch (opt) { 144 case 'a': 145 aflg++; 146 break; 147 148 case 'n': 149 minlength = (int)strtol(optarg, (char **)NULL, 150 10); 151 break; 152 153 case 'o': 154 tflg++; 155 t_format = 'd'; 156 break; 157 158 case 't': 159 tflg++; 160 t_format = *optarg; 161 if (t_format != 'd' && t_format != 'o' && 162 t_format != 'x') 163 { 164 (void) fprintf(stderr, 165 gettext("Invalid format\n")); 166 Usage(); 167 } 168 break; 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 minlength *= 10; 180 minlength += opt - '0'; 181 break; 182 183 default: 184 Usage(); 185 } 186 } 187 188 /* if min string not specified, use default */ 189 if (!minlength) 190 minlength = DEF_MIN_STRING; 191 192 193 /* dynamic allocation of char buffer array */ 194 buf = (char *)malloc(BUFSIZ); 195 if (buf == NULL) { 196 (void) fprintf(stderr, gettext("Cannot allocate memory: %s\n"), 197 strerror(errno)); 198 exit(1); 199 } 200 buf_size = BUFSIZ; 201 tbuf = buf; 202 203 204 /* for each file operand */ 205 do { 206 if (argv[optind] != NULL) { 207 if (freopen(argv[optind], "r", stdin) == NULL) { 208 perror(argv[optind]); 209 rc = 1; 210 optind++; 211 continue; 212 } 213 optind++; 214 } else 215 aflg++; 216 217 if (aflg) 218 htype = NOTOUT; 219 else { 220 hsize = fread((char *)&ahdr, sizeof (char), 221 sizeof (ahdr), stdin); 222 htype = ismagic(hsize, &ahdr, stdin); 223 } 224 switch (htype) { 225 case AOUT: 226 (void) fseek(stdin, (long)ADATAPOS(&ahdr), 0); 227 find((long)ahdr.xa_data); 228 continue; 229 230 case ELF: 231 /* 232 * Will take care of COFF M32 and i386 also 233 * As well as ELF M32, i386 and Sparc (32- and 64-bit) 234 */ 235 236 fd = fileno(stdin); 237 (void) lseek(fd, 0L, 0); 238 elf = elf_begin(fd, ELF_C_READ, NULL); 239 if (gelf_getehdr(elf, &ehdr) == 240 (GElf_Ehdr *)NULL) { 241 (void) fprintf(stderr, "%s: %s\n", 242 argv[optind-1], elf_errmsg(-1)); 243 (void) elf_end(elf); 244 rc = 1; 245 continue; 246 } 247 scn = 0; 248 while ((scn = elf_nextscn(elf, scn)) != 0) 249 { 250 if (gelf_getshdr(scn, &shdr) == 251 (GElf_Shdr *)0) { 252 (void) fprintf(stderr, 253 "%s: %s\n", argv[optind-1], 254 elf_errmsg(-1)); 255 rc = 1; 256 continue; 257 } 258 if ((scn_name = elf_strptr(elf, 259 ehdr.e_shstrndx, 260 (size_t)shdr.sh_name)) 261 == (char *)NULL) { 262 (void) fprintf(stderr, 263 "%s: %s\n", argv[optind-1], 264 elf_errmsg(-1)); 265 rc = 1; 266 continue; 267 } 268 /* 269 * There is more than one .data section 270 */ 271 272 if ((strcmp(scn_name, ".rodata") 273 == 0) || 274 (strcmp(scn_name, ".rodata1") 275 == 0) || 276 (strcmp(scn_name, ".data") 277 == 0) || 278 (strcmp(scn_name, ".data1") 279 == 0)) 280 { 281 (void) fseek(stdin, 282 (long)shdr.sh_offset, 0); 283 find((long)shdr.sh_size); 284 } 285 } 286 continue; 287 288 case NOTOUT: 289 default: 290 if (!aflg) 291 (void) fseek(stdin, (long)0, 0); 292 find(LONG_MAX); 293 continue; 294 } 295 } while (argv[optind] != NULL); 296 297 return (rc); 298 } 299 300 301 static void 302 find(cnt) 303 long cnt; 304 { 305 int c; 306 int cc; 307 int cr; 308 309 cc = 0; 310 for (c = ~EOF; (cnt > 0) && (c != EOF); cnt--) { 311 c = getc(stdin); 312 if (!(cr = dirt(c, cc))) { 313 if (cc >= minlength) { 314 if (tflg) { 315 switch (t_format) { 316 case 'd': 317 (void) printf("%7ld ", 318 ftell(stdin) - cc - 1); 319 break; 320 321 case 'o': 322 (void) printf("%7lo ", 323 ftell(stdin) - cc - 1); 324 break; 325 326 case 'x': 327 (void) printf("%7lx ", 328 ftell(stdin) - cc - 1); 329 break; 330 } 331 } 332 333 if (cc >= buf_size) 334 buf[buf_size-1] = '\0'; 335 else 336 buf[cc] = '\0'; 337 (void) puts(buf); 338 } 339 cc = 0; 340 } 341 cc += cr; 342 } 343 } 344 345 static int 346 dirt(c, cc) 347 int c; 348 int cc; 349 { 350 char mbuf[MB_LEN_MAX + 1]; 351 int len, len1, i; 352 wchar_t wc; 353 int r_val; 354 355 if (isascii(c)) { 356 if (isprint(c)) { 357 /* 358 * If character count is greater than dynamic 359 * char buffer size, then increase char buffer size. 360 */ 361 if (cc >= (buf_size-2)) { 362 if (tbuf != NULL) { 363 buf_size += BUFSIZ; 364 tbuf = (char *)realloc(buf, buf_size); 365 if (tbuf == NULL) { 366 (void) fprintf(stderr, 367 gettext("Cannot allocate memory: %s\n"), 368 strerror(errno)); 369 buf_size -= BUFSIZ; 370 rc = 1; 371 return (0); 372 } else { 373 buf = tbuf; 374 } 375 } else { 376 return (0); 377 } 378 } 379 buf[cc] = c; 380 return (1); 381 } 382 return (0); 383 } 384 385 if (isClocale) 386 return (0); 387 388 r_val = 0; 389 mbuf[0] = c; 390 for (len = 1; len < (unsigned int)MB_CUR_MAX; len++) { 391 if ((signed char) 392 (mbuf[len] = getc(stdin)) == -1) 393 break; 394 } 395 mbuf[len] = 0; 396 397 if ((len1 = mbtowc(&wc, mbuf, len)) <= 0) { 398 len1 = 1; 399 goto _unget; 400 } 401 402 if (iswprint(wc)) { 403 if ((cc + len1) >= (buf_size-2)) { 404 if (tbuf != NULL) { 405 buf_size += BUFSIZ; 406 tbuf = (char *)realloc(buf, buf_size); 407 if (tbuf == NULL) { 408 (void) fprintf(stderr, 409 gettext("Cannot allocate memory: %s\n"), 410 strerror(errno)); 411 buf_size -= BUFSIZ; 412 rc = 1; 413 return (0); 414 } 415 buf = tbuf; 416 } else { 417 return (0); 418 } 419 } 420 for (i = 0; i < len1; i++, cc++) 421 buf[cc] = mbuf[i]; 422 r_val = len1; 423 } 424 425 _unget: 426 for (len--; len >= len1; len--) 427 (void) ungetc(mbuf[len], stdin); 428 return (r_val); 429 } 430 431 432 static int 433 ismagic(hsize, hdr, fp) 434 int hsize; 435 struct aexec *hdr; 436 FILE *fp; 437 { 438 switch (hdr->xa_magic) { 439 case A_MAGIC1: 440 case A_MAGIC2: 441 case A_MAGIC3: 442 case A_MAGIC4: 443 if (hsize < sizeof (struct aexec)) 444 return (NOTOUT); 445 else 446 return (AOUT); 447 default: 448 break; 449 } 450 return (tryelf(fp)); 451 } 452 453 454 static int 455 tryelf(fp) 456 FILE *fp; 457 { 458 int fd; 459 Elf *elf; 460 GElf_Ehdr ehdr; 461 462 fd = fileno(fp); 463 464 if ((elf_version(EV_CURRENT)) == EV_NONE) { 465 (void) fprintf(stderr, "%s\n", elf_errmsg(-1)); 466 return (NOTOUT); 467 } 468 469 (void) lseek(fd, 0L, 0); 470 471 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 472 (void) fprintf(stderr, "%s\n", elf_errmsg(-1)); 473 return (NOTOUT); 474 } 475 476 switch (elf_kind(elf)) { 477 case ELF_K_AR: 478 /* 479 * This should try to run strings on each element 480 * of the archive. For now, just search entire 481 * file (-a), as strings has always done 482 * for archives. 483 */ 484 case ELF_K_NONE: 485 (void) elf_end(elf); 486 return (NOTOUT); 487 } 488 489 if (gelf_getehdr(elf, &ehdr) == (GElf_Ehdr *)NULL) { 490 (void) fprintf(stderr, "%s\n", elf_errmsg(-1)); 491 (void) elf_end(elf); 492 return (NOTOUT); 493 } 494 495 if ((ehdr.e_type == ET_CORE) || (ehdr.e_type == ET_NONE)) { 496 (void) elf_end(elf); 497 return (NOTOUT); 498 } 499 500 (void) elf_end(elf); 501 502 return (ELF); 503 504 } 505 506 507 static void 508 Usage() 509 { 510 (void) fprintf(stderr, gettext( 511 "Usage: strings [-|-a] [-t format] [-n #] [file ...]\n" 512 " strings [-|-a] [-o] [-#] [file ...]\n")); 513 exit(1); 514 } 515