|
|
1.1 ! root 1: /* ! 2: * trace1.c ! 3: * ! 4: * The information contained herein is a trade secret of Mark Williams ! 5: * Company, and is confidential information. It is provided under a ! 6: * license agreement, and may be copied or disclosed only under the ! 7: * terms of that agreement. Any reproduction or disclosure of this ! 8: * material without the express written authorization of Mark Williams ! 9: * Company or persuant to the license agreement is unlawful. ! 10: * ! 11: * COHERENT Version 2.3.35 ! 12: * Copyright (c) 1982, 1983, 1984. ! 13: * An unpublished work by Mark Williams Company, Chicago. ! 14: * All rights reserved. ! 15: * ! 16: * Initialization, command line parsing. ! 17: */ ! 18: #include <stdio.h> ! 19: #include <ctype.h> ! 20: #include <canon.h> ! 21: #include <l.out.h> ! 22: #include <sys/timeout.h> ! 23: #include <sys/proc.h> ! 24: #include <sys/ptrace.h> ! 25: #include <signal.h> ! 26: #include <sys/uproc.h> ! 27: #include "trace.h" ! 28: ! 29: static char *symName(); ! 30: ! 31: main(argc, argv) ! 32: char **argv; ! 33: { ! 34: initialise(); ! 35: setup(argc, argv); ! 36: signal(SIGINT, &armsint); ! 37: signal(SIGQUIT, SIG_IGN); ! 38: process(); ! 39: } ! 40: ! 41: /* ! 42: * Leave. ! 43: */ ! 44: leave() ! 45: { ! 46: nfree(ssymp); ! 47: nfree(gblsymMap); ! 48: killc(); ! 49: exit(0); ! 50: } ! 51: ! 52: /* ! 53: * Initialize segment formats and clear the breakpoint table. ! 54: */ ! 55: initialise() ! 56: { ! 57: strcpy(segform[DSEG], "w"); ! 58: strcpy(segform[ISEG], "i"); ! 59: strcpy(segform[USEG], "w"); ! 60: bptinit(); ! 61: } ! 62: ! 63: /* ! 64: * Setup arguments. ! 65: */ ! 66: setup(argc, argv) ! 67: char **argv; ! 68: { ! 69: register char *cp; ! 70: register int c; ! 71: register int t; ! 72: register int u; ! 73: register int tflag; ! 74: ! 75: t = '\0'; ! 76: tflag = 0; ! 77: ! 78: /* process command line switches -[cdefkorst] */ ! 79: for (; argc>1; argc--, argv++) { ! 80: cp = argv[1]; ! 81: if (*cp++ != '-') ! 82: break; ! 83: while ((c=*cp++) != '\0') { ! 84: switch (c) { ! 85: case 'c': ! 86: case 'd': ! 87: case 'e': ! 88: case 'f': ! 89: case 'k': ! 90: case 'o': ! 91: /* only one of [cdefko] is allowed */ ! 92: if (t != '\0') ! 93: usage(); ! 94: t = c; ! 95: continue; ! 96: case 'r': ! 97: rflag = 1; ! 98: continue; ! 99: case 's': ! 100: sflag = 1; ! 101: continue; ! 102: case 't': ! 103: tflag = 1; ! 104: continue; ! 105: default: ! 106: usage(); ! 107: } ! 108: } ! 109: } ! 110: switch (t) { ! 111: case '\0': ! 112: switch (argc) { ! 113: case 1: ! 114: setfh(DEFLT_OBJ, 3); ! 115: setcore(DEFLT_AUX); ! 116: break; ! 117: case 2: ! 118: setfh(argv[1], 3); ! 119: break; ! 120: case 3: ! 121: setfh(argv[1], 3); ! 122: setcore(argv[2]); ! 123: break; ! 124: default: ! 125: usage(); ! 126: } ! 127: break; ! 128: case 'c': ! 129: switch (argc) { ! 130: case 1: ! 131: setfh(DEFLT_OBJ, 3); ! 132: setcore(DEFLT_AUX); ! 133: break; ! 134: case 2: ! 135: setcore(argv[1]); ! 136: break; ! 137: case 3: ! 138: setfh(argv[1], 3); ! 139: setcore(argv[2]); ! 140: break; ! 141: default: ! 142: usage(); ! 143: } ! 144: break; ! 145: case 'd': ! 146: switch (argc) { ! 147: case 1: ! 148: setfh("/coherent", 3); ! 149: setdump("/dev/dump"); ! 150: break; ! 151: case 3: ! 152: setfh(argv[1], 3); ! 153: setdump(argv[2]); ! 154: break; ! 155: default: ! 156: usage(); ! 157: } ! 158: break; ! 159: case 'e': ! 160: if (argc < 2) ! 161: usage(); ! 162: setfh(argv[1], 3); ! 163: if (startup(&argv[1], NULL, NULL, 0)==0 || shiftup()==0) ! 164: leave(); ! 165: break; ! 166: case 'f': ! 167: switch (argc) { ! 168: case 2: ! 169: setfile(argv[1]); ! 170: break; ! 171: case 3: ! 172: setfh(argv[1], 1); ! 173: setfile(argv[2]); ! 174: break; ! 175: default: ! 176: usage(); ! 177: } ! 178: break; ! 179: case 'k': ! 180: switch (argc) { ! 181: case 1: ! 182: setfh("/coherent", 1); ! 183: setkmem("/dev/mem"); ! 184: break; ! 185: case 2: ! 186: setkmem(argv[1]); ! 187: break; ! 188: case 3: ! 189: setfh(argv[1], 1); ! 190: setkmem(argv[2]); ! 191: break; ! 192: default: ! 193: usage(); ! 194: } ! 195: break; ! 196: case 'o': ! 197: switch (argc) { ! 198: case 1: ! 199: setfh(DEFLT_OBJ, 3); ! 200: break; ! 201: case 2: ! 202: setfh(argv[1], 3); ! 203: break; ! 204: case 3: ! 205: setfh(argv[1], 1); ! 206: setfh(argv[2], 2); ! 207: break; ! 208: default: ! 209: usage(); ! 210: } ! 211: } ! 212: if (tflag) { ! 213: if ((u=open("/dev/tty", 2)) < 0) ! 214: panic("Cannot open /dev/tty"); ! 215: dup2(u, 0); ! 216: dup2(u, 1); ! 217: dup2(u, 2); ! 218: } ! 219: } ! 220: ! 221: /* ! 222: * Generate a usage message. ! 223: */ ! 224: usage() ! 225: { ! 226: panic("Usage: db [-cdefort] [object file] [auxiliary file]"); ! 227: } ! 228: ! 229: /* ! 230: * Catch and flag interrupts. ! 231: */ ! 232: armsint() ! 233: { ! 234: signal(SIGINT, &armsint); ! 235: intflag++; ! 236: } ! 237: ! 238: /* ! 239: * Check for interrupts and clear flag. ! 240: */ ! 241: testint() ! 242: { ! 243: register int n; ! 244: ! 245: if ((n=intflag) != 0) ! 246: printe("Interrupt"); ! 247: intflag = 0; ! 248: return (n); ! 249: } ! 250: ! 251: /* ! 252: * Assume the file, `np', is the name of an l.out. If the bottom bit ! 253: * of the flag is set, set up the symbol table. If the next bit is set, ! 254: * set up segmentation for the l.out. ! 255: */ ! 256: setlout(np, f) ! 257: char *np; ! 258: { ! 259: struct ldheader ldh; ! 260: ! 261: fseek(lfp, 0L, 0L); ! 262: if (fread(&ldh, sizeof(ldh), 1, lfp) != 1) ! 263: panic("Cannot read object file"); ! 264: canlout(&ldh); ! 265: if (ldh.l_magic != L_MAGIC) ! 266: panic("Bad object file"); ! 267: hdrinfo.magic = ldh.l_magic; ! 268: hdrinfo.defsegatt = DSA16; ! 269: objflag = 1; ! 270: if ((f&1) != 0) { ! 271: sbase = sizeof(ldh); ! 272: sbase += ldh.l_ssize[L_SHRI] + ldh.l_ssize[L_PRVI]; ! 273: sbase += ldh.l_ssize[L_SHRD] + ldh.l_ssize[L_PRVD]; ! 274: snsym = ldh.l_ssize[L_SYM] / sizeof(struct ldsym); ! 275: if (snsym != 0) { ! 276: sfp = lfp; ! 277: if (sflag == 0) ! 278: readsym(sfp); ! 279: } ! 280: } ! 281: if ((f&2) != 0) { ! 282: lfn = np; ! 283: setaseg(&ldh); ! 284: } ! 285: } ! 286: ! 287: /* ! 288: * Canonicalize an l.out header. ! 289: */ ! 290: canlout(ldp) ! 291: struct ldheader *ldp; ! 292: { ! 293: register int i; ! 294: ! 295: canint(ldp->l_magic); ! 296: canint(ldp->l_flag); ! 297: canint(ldp->l_machine); ! 298: canvaddr(ldp->l_entry); ! 299: for (i=0; i<NLSEG; i++) ! 300: cansize(ldp->l_ssize[i]); ! 301: } ! 302: ! 303: /* ! 304: * Read all global symbols into memory. ! 305: */ ! 306: readsym(fp) ! 307: FILE *fp; ! 308: { ! 309: register int n, i; ! 310: register SYM *sp; ! 311: struct ldsym lds; ! 312: struct LDSYM LDS; ! 313: ! 314: if ((ssymp=nalloc((int)snsym * sizeof(SYM))) == NULL) ! 315: return; ! 316: fseek(fp, (long)sbase, 0); ! 317: for (n=snsym, sp=ssymp; n--; sp++) { ! 318: if (fread(&lds, sizeof(struct ldsym), 1, fp) != 1) { ! 319: nfree(ssymp); ! 320: ssymp = NULL; ! 321: return; ! 322: } ! 323: canint(lds.ls_type); ! 324: canvaddr(lds.ls_addr); ! 325: for (i=0; i<NCPLN; i++) ! 326: LDS.ls_id[i] = lds.ls_id[i]; ! 327: LDS.ls_type = lds.ls_type; ! 328: LDS.ls_addr = (long)lds.ls_addr; ! 329: ! 330: sp->s_hash = hash(&LDS); ! 331: sp->s_type = LDS.ls_type; ! 332: sp->s_sval = LDS.ls_addr; ! 333: } ! 334: } ! 335: ! 336: /* ! 337: * Hash a symbol name. ! 338: */ ! 339: hash(ldp) ! 340: struct LDSYM *ldp; ! 341: { ! 342: register int h, n; ! 343: register char *cp; ! 344: ! 345: h = 0; ! 346: n = CCSSIZE; ! 347: cp = ldp->ls_id; ! 348: do { ! 349: if (*cp != '_') ! 350: h += *cp; ! 351: if (*cp++ == '\0') ! 352: break; ! 353: } while (--n); ! 354: return (h&0377); ! 355: } ! 356: ! 357: /* ! 358: * Set up segmentation for a core dump. The registers are also read. ! 359: */ ! 360: setcore(np) ! 361: char *np; ! 362: { ! 363: register unsigned i; ! 364: register MAP *mp; ! 365: register char *cp; ! 366: register char *lcp; ! 367: register fsize_t size; ! 368: register fsize_t offt; ! 369: char ucomm[10]; ! 370: SR usegs[NUSEG]; ! 371: ! 372: cfp = openfil(np, rflag); ! 373: fseek(cfp, (long)offset(uproc, u_comm[0]), 0); ! 374: if ((cp=lfn)!=NULL && fread(ucomm, sizeof(ucomm), 1, cfp)==1) { ! 375: lcp = cp; ! 376: while (*cp) { ! 377: if (*cp++ == '/') ! 378: lcp = cp; ! 379: } ! 380: if (strncmp(lcp, ucomm, sizeof(ucomm)) != 0) ! 381: printr("Core different from object"); ! 382: } ! 383: fseek(cfp, (long)offset(uproc, u_segl[0]), 0); ! 384: if (fread(usegs, sizeof(usegs), 1, cfp) != 1) ! 385: panic("Bad core file"); ! 386: USPACE = setsmap(NULL, (fsize_t)0, (fsize_t)UPASIZE, (fsize_t)0, ! 387: getf, putf, 1); ! 388: mp = clrsmap(DSPACE, endpure); ! 389: offt = usegs[0].sr_size; ! 390: #ifdef _I386 ! 391: usegs[SISTACK].sr_base -= usegs[SISTACK].sr_size; ! 392: #endif ! 393: for (i=1; i<NUSEG; i++) { ! 394: if (usegs[i].sr_segp == NULL) ! 395: continue; ! 396: if ((~usegs[i].sr_flag) & (SRFDUMP|SRFPMAP)) ! 397: continue; ! 398: size = usegs[i].sr_size; ! 399: mp = setsmap(mp, (fsize_t)usegs[i].sr_base, size, offt, ! 400: getf, putf, 1); ! 401: offt += size; ! 402: } ! 403: if (ISPACE == DSPACE) ! 404: ISPACE = mp; ! 405: DSPACE = mp; ! 406: settrap(); ! 407: setregs(); ! 408: } ! 409: ! 410: /* ! 411: * Find out signal sent to traced process. ! 412: */ ! 413: settrap() ! 414: { ! 415: int f; ! 416: ! 417: trapstr = "???"; ! 418: add = PTRACE_SIG; ! 419: if (getb(USEG, (char *)&f, sizeof(f)) == 0) { ! 420: printr("Cannot read signal in traced process"); ! 421: return 0; ! 422: } ! 423: if (f<=0 || f>NSIG) { ! 424: printr("Bad signal in traced process"); ! 425: return 0; ! 426: } ! 427: trapstr = signame[f-1]; ! 428: return f; ! 429: } ! 430: ! 431: /* ! 432: * Set up segmentation for an ordinary file. ! 433: * This is really easy. ! 434: */ ! 435: setfile(np) ! 436: char *np; ! 437: { ! 438: lfp = openfil(np, rflag); ! 439: DSPACE = setsmap(NULL, (fsize_t)0, (fsize_t)LI, (fsize_t)0, ! 440: getf, putf, 0); ! 441: ISPACE = DSPACE; ! 442: } ! 443: ! 444: /* ! 445: * Open the given file. If `rflag' is set, the file is opened for ! 446: * read only. ! 447: */ ! 448: FILE * ! 449: openfil(np, rflag) ! 450: char *np; ! 451: { ! 452: register FILE *fp; ! 453: ! 454: if (rflag) { ! 455: if ((fp=fopen(np, "r")) != NULL) ! 456: return (fp); ! 457: } else { ! 458: if ((fp=fopen(np, "r+w")) != NULL) ! 459: return (fp); ! 460: if ((fp=fopen(np, "r")) != NULL) { ! 461: printr("%s: opened read only", np); ! 462: return (fp); ! 463: } ! 464: } ! 465: panic("Cannot open %s", np); ! 466: } ! 467: ! 468: /* ! 469: * Initialise an element of a segment map. ! 470: */ ! 471: MAP * setsmap(next, base, size, offt, getf, putf, segi) ! 472: MAP *next; ! 473: fsize_t base; ! 474: fsize_t size; ! 475: fsize_t offt; ! 476: int (*getf)(); ! 477: int (*putf)(); ! 478: { ! 479: register MAP *mp; ! 480: ! 481: mp = (MAP *)nalloc(sizeof(MAP)); ! 482: mp->m_next = next; ! 483: mp->m_base = base; ! 484: mp->m_bend = base+size; ! 485: mp->m_offt = offt; ! 486: mp->m_getf = getf; ! 487: mp->m_putf = putf; ! 488: mp->m_segi = segi; ! 489: return (mp); ! 490: } ! 491: ! 492: /* ! 493: * Clear a section of a segment map. ! 494: */ ! 495: MAP * clrsmap(mp, np) ! 496: register MAP *mp; ! 497: register MAP *np; ! 498: { ! 499: while (mp != np) { ! 500: nfree(mp); ! 501: mp = mp->m_next; ! 502: } ! 503: return (mp); ! 504: } ! 505: ! 506: /* ! 507: * Clear all maps. ! 508: */ ! 509: clramap() ! 510: { ! 511: register int n; ! 512: ! 513: n = 0; ! 514: if (segmapl[0] == segmapl[1]) ! 515: segmapl[n++] = NULL; ! 516: while (n < NSEGM) { ! 517: segmapl[n] = clrsmap(segmapl[n], NULL); ! 518: n++; ! 519: } ! 520: } ! 521: ! 522: ! 523: /****************************************************************************** ! 524: * ! 525: * Note some #defines in these include files interferes with ! 526: * items in preceeding include files. Hence the strange ! 527: * program order. ! 528: * ! 529: ******************************************************************************/ ! 530: ! 531: #include <coff.h> ! 532: ! 533: char *read_str_tab(); ! 534: SCNHDR *read_scns(); ! 535: ! 536: /* ! 537: * Setup object file. ! 538: * ! 539: * Arguments: ! 540: * np = file name ! 541: * f is bit mapped ! 542: * set 1's bit if reading symbol table info from file "np" ! 543: * set 2's bit if reading segment info from file "np" ! 544: */ ! 545: setfh (np,f) ! 546: char *np; ! 547: { ! 548: FILEHDR coffh; ! 549: ! 550: lfp = openfil(np, (f&2) ? rflag : 1); ! 551: if (fread(&coffh, sizeof(coffh), 1, lfp) != 1) ! 552: panic("Cannot read object file"); ! 553: if (coffh.f_magic == C_386_MAGIC) ! 554: setcoff(lfp, &coffh, np, f); ! 555: else setlout(np, f); ! 556: } ! 557: ! 558: setcoff(fp, coffhp, np, f) ! 559: FILE *fp; ! 560: FILEHDR *coffhp; ! 561: char *np; ! 562: int f; ! 563: { ! 564: hdrinfo.magic = coffhp->f_magic; ! 565: hdrinfo.defsegatt = DSA32; ! 566: objflag = 1; ! 567: if (f&1) { ! 568: if (coffhp->f_nsyms) { ! 569: sbase = (fsize_t)coffhp->f_symptr; ! 570: snsym = (fsize_t)coffhp->f_nsyms; ! 571: if (snsym != 0L) { ! 572: sfp = fp; ! 573: if (sflag == 0) { ! 574: readCoffSym(fp, coffhp); ! 575: } ! 576: } ! 577: } ! 578: } ! 579: if (f&2) { ! 580: lfn = np; ! 581: setcoffseg(fp, coffhp); ! 582: } ! 583: } ! 584: ! 585: readCoffSym(fp, coffhp) ! 586: FILE *fp; ! 587: FILEHDR *coffhp; ! 588: { ! 589: SYMENT coffsym; ! 590: struct LDSYM lds; ! 591: SYM *sp; ! 592: long n; ! 593: char *str_tabp; ! 594: SCNHDR *scnhp; ! 595: ! 596: ! 597: str_tabp = read_str_tab(fp, coffhp->f_nsyms, coffhp->f_symptr); ! 598: ! 599: scnhp = read_scns(fp, coffhp->f_nscns ! 600: , sizeof(FILEHDR)+coffhp->f_opthdr); ! 601: ! 602: /* could get entry point here FIX 386 */ ! 603: ! 604: if (scnhp == NULL) ! 605: return; ! 606: ! 607: if ((gblsymMap=nalloc((int)coffhp->f_nsyms * sizeof(off_t))) == NULL) { ! 608: printf("Not enough memory for the global symbol map.\n"); ! 609: return; ! 610: } ! 611: if ((ssymp=nalloc((int)coffhp->f_nsyms * sizeof(SYM))) == NULL) { ! 612: printf("Not enough memory for the coff symbol header section.\n"); ! 613: return; ! 614: } ! 615: ! 616: fseek(fp, coffhp->f_symptr, 0); ! 617: ! 618: for (n=coffhp->f_nsyms, sp=ssymp; n--; ) { ! 619: if (fread(&coffsym, sizeof(SYMENT), 1, fp) != 1) { ! 620: printf("Cannot read coff.h symbols\n"); ! 621: nfree(ssymp); ! 622: ssymp = NULL; ! 623: return; ! 624: } ! 625: ! 626: switch (coffsym.n_sclass) { ! 627: case C_EXT: ! 628: case C_EXTDEF: ! 629: break; ! 630: default: ! 631: continue; ! 632: } ! 633: ! 634: coff_to_lout(&coffsym, &lds, str_tabp, scnhp); ! 635: ! 636: sp->s_hash = hash(&lds); ! 637: sp->s_type = lds.ls_type; ! 638: sp->s_sval = lds.ls_addr; ! 639: ! 640: gblsymMap[sp-ssymp] = snsym - n - 1; ! 641: sp++; ! 642: } ! 643: gblsymMap=(off_t *)realloc( gblsymMap, (sp-ssymp)*sizeof(off_t) ); ! 644: ssymp=(SYM *)realloc( ssymp, (sp-ssymp)*sizeof(SYM) ); ! 645: sngblsym = sp - ssymp; ! 646: if (str_tabp) nfree(str_tabp); ! 647: nfree(scnhp); ! 648: } ! 649: ! 650: char * ! 651: read_str_tab(fp, nsyms, symptr) ! 652: FILE *fp; ! 653: long nsyms; ! 654: long symptr; ! 655: { ! 656: long strtab_len, symtab_len; ! 657: unsigned len; ! 658: char * strTabp; ! 659: ! 660: strtab_len = 0; ! 661: strTabp = NULL; ! 662: len = symtab_len = sizeof(SYMENT) * nsyms; ! 663: if (!len) ! 664: return(NULL); ! 665: ! 666: if (symtab_len != len) { ! 667: panic("Cannot process small model"); ! 668: } ! 669: fseek(fp, symptr+len, 0); ! 670: if (1 != fread(&strtab_len, sizeof(strtab_len), 1, fp)) { ! 671: strtab_len = 0; ! 672: } ! 673: if (!strtab_len) ! 674: return(NULL); ! 675: ! 676: len = strtab_len -= 4; ! 677: if (len != strtab_len) ! 678: panic("Cannot process small model"); ! 679: if ( (strTabp = nalloc((int)len)) == NULL ) { ! 680: printf("Not enough memory for the symbol string table.\n"); ! 681: return(NULL); ! 682: } ! 683: if ( fread(strTabp, len, 1, fp) != 1) { ! 684: printf("Unable to read symbol string table.\n"); ! 685: return(NULL); ! 686: } ! 687: ! 688: return(strTabp); ! 689: } ! 690: ! 691: SCNHDR * ! 692: read_scns(fp, nscns, scnh_off) ! 693: FILE *fp; ! 694: unsigned short nscns, scnh_off; ! 695: { ! 696: int len; ! 697: SCNHDR *scnhp; ! 698: ! 699: len = (int)(nscns*sizeof(SCNHDR)); ! 700: if ( (scnhp = nalloc(len)) == NULL ) { ! 701: printf("Not enough memory for the symbol string table.\n"); ! 702: return(NULL); ! 703: } ! 704: fseek(fp, scnh_off, 0); ! 705: if ( fread(scnhp, len, 1, fp) != 1) { ! 706: printf("Unable to read section headers.\n"); ! 707: return(NULL); ! 708: } ! 709: return(scnhp); ! 710: } ! 711: ! 712: coff_to_lout(coffsymp, ldsp, str_tabp, scnhp) ! 713: SYMENT *coffsymp; ! 714: struct LDSYM *ldsp; ! 715: char *str_tabp; ! 716: SCNHDR *scnhp; ! 717: { ! 718: char *cp; ! 719: char w1[SYMNMLEN+1]; ! 720: ! 721: cp = symName(coffsymp, w1, str_tabp); ! 722: memcpy(ldsp->ls_id, cp, NCPLN-1); ! 723: ldsp->ls_id[NCPLN-1] = '\0'; ! 724: ! 725: switch((int)scnhp[coffsymp->n_scnum-1].s_flags) { ! 726: case STYP_TEXT: ! 727: ldsp->ls_type = L_GLOBAL + L_SHRI; ! 728: break; ! 729: case STYP_DATA: ! 730: ldsp->ls_type = L_GLOBAL + L_PRVD; ! 731: break; ! 732: case STYP_BSS: ! 733: ldsp->ls_type = L_GLOBAL + L_BSSD; ! 734: break; ! 735: default: ! 736: ldsp->ls_type = -1; ! 737: panic("Unallowed section flag in coff header"); ! 738: } ! 739: ! 740: ldsp->ls_addr = (long)coffsymp->n_value; ! 741: } ! 742: ! 743: /* ! 744: * Symbol name. ! 745: */ ! 746: static char * ! 747: symName(sym, work, str_tabp) ! 748: SYMENT *sym; ! 749: char *work; ! 750: char *str_tabp; ! 751: { ! 752: if (!sym->n_zeroes) { ! 753: return (str_tabp + sym->n_offset - 4); ! 754: } ! 755: ! 756: /* make sure it's zero terminated */ ! 757: memcpy(work, sym->n_name, SYMNMLEN); ! 758: work[SYMNMLEN] = '\0'; ! 759: return (work); ! 760: } ! 761: ! 762: /* end of trace1.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.