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