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