|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.0 (the 'License'). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License." ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: #include <stdio.h> ! 25: #include <stdlib.h> ! 26: #include <sys/file.h> ! 27: #include <sys/types.h> ! 28: #include <sys/stat.h> ! 29: #include <mach-o/loader.h> ! 30: #include <objc/objc-runtime.h> ! 31: #include <objc/NXString.h> ! 32: #include <sys/types.h> ! 33: #include "Protocol.h" ! 34: ! 35: /* These are in libc in later updates */ ! 36: void ! 37: swap_mach_header( ! 38: struct mach_header *mh, ! 39: enum NXByteOrder target_byte_order) ! 40: { ! 41: mh->magic = NXSwapLong(mh->magic); ! 42: mh->cputype = NXSwapLong(mh->cputype); ! 43: mh->cpusubtype = NXSwapLong(mh->cpusubtype); ! 44: mh->filetype = NXSwapLong(mh->filetype); ! 45: mh->ncmds = NXSwapLong(mh->ncmds); ! 46: mh->sizeofcmds = NXSwapLong(mh->sizeofcmds); ! 47: mh->flags = NXSwapLong(mh->flags); ! 48: } ! 49: ! 50: void ! 51: swap_load_command( ! 52: struct load_command *lc, ! 53: enum NXByteOrder target_byte_order) ! 54: { ! 55: lc->cmd = NXSwapLong(lc->cmd); ! 56: lc->cmdsize = NXSwapLong(lc->cmdsize); ! 57: } ! 58: ! 59: void ! 60: swap_segment_command( ! 61: struct segment_command *sg, ! 62: enum NXByteOrder target_byte_order) ! 63: { ! 64: /* segname[16] */ ! 65: sg->cmd = NXSwapLong(sg->cmd); ! 66: sg->cmdsize = NXSwapLong(sg->cmdsize); ! 67: sg->vmaddr = NXSwapLong(sg->vmaddr); ! 68: sg->vmsize = NXSwapLong(sg->vmsize); ! 69: sg->fileoff = NXSwapLong(sg->fileoff); ! 70: sg->filesize = NXSwapLong(sg->filesize); ! 71: sg->maxprot = NXSwapLong(sg->maxprot); ! 72: sg->initprot = NXSwapLong(sg->initprot); ! 73: sg->nsects = NXSwapLong(sg->nsects); ! 74: sg->flags = NXSwapLong(sg->flags); ! 75: } ! 76: ! 77: void ! 78: swap_section( ! 79: struct section *s, ! 80: unsigned long nsects, ! 81: enum NXByteOrder target_byte_order) ! 82: { ! 83: unsigned long i; ! 84: ! 85: for(i = 0; i < nsects; i++){ ! 86: /* sectname[16] */ ! 87: /* segname[16] */ ! 88: s[i].addr = NXSwapLong(s[i].addr); ! 89: s[i].size = NXSwapLong(s[i].size); ! 90: s[i].offset = NXSwapLong(s[i].offset); ! 91: s[i].align = NXSwapLong(s[i].align); ! 92: s[i].reloff = NXSwapLong(s[i].reloff); ! 93: s[i].nreloc = NXSwapLong(s[i].nreloc); ! 94: s[i].flags = NXSwapLong(s[i].flags); ! 95: s[i].reserved1 = NXSwapLong(s[i].reserved1); ! 96: s[i].reserved2 = NXSwapLong(s[i].reserved2); ! 97: } ! 98: } ! 99: ! 100: void ! 101: swap_symtab_command( ! 102: struct symtab_command *st, ! 103: enum NXByteOrder target_byte_order) ! 104: { ! 105: st->cmd = NXSwapLong(st->cmd); ! 106: st->cmdsize = NXSwapLong(st->cmdsize); ! 107: st->symoff = NXSwapLong(st->symoff); ! 108: st->nsyms = NXSwapLong(st->nsyms); ! 109: st->stroff = NXSwapLong(st->stroff); ! 110: st->strsize = NXSwapLong(st->strsize); ! 111: } ! 112: ! 113: void ! 114: swap_symseg_command( ! 115: struct symseg_command *ss, ! 116: enum NXByteOrder target_byte_order) ! 117: { ! 118: ss->cmd = NXSwapLong(ss->cmd); ! 119: ss->cmdsize = NXSwapLong(ss->cmdsize); ! 120: ss->offset = NXSwapLong(ss->offset); ! 121: ss->size = NXSwapLong(ss->size); ! 122: } ! 123: ! 124: /* ! 125: * For system call errors the error messages allways contains ! 126: * sys_errlist[errno] as part of the message. ! 127: */ ! 128: extern char *sys_errlist[]; ! 129: extern int errno; ! 130: ! 131: /* Name of this program for error messages (argv[0]) */ ! 132: char *progname; ! 133: ! 134: extern void _sel_writeHashTable( ! 135: int start_addr, ! 136: char *myselectorstraddr, ! 137: char *shlibselectorstraddr, ! 138: void **stuff, ! 139: int *stuffsize ! 140: ); ! 141: ! 142: /* ! 143: * Declarations for the static routines in this file. ! 144: */ ! 145: static void usage(); ! 146: ! 147: static Module get_objc( ! 148: long fd, ! 149: char *filename, ! 150: struct section *objcsects, ! 151: int nsects ! 152: ); ! 153: static void print_method_list( ! 154: struct objc_method_list *mlist_before_reloc, ! 155: struct section *firstobjcsect, ! 156: int nsects ! 157: ); ! 158: static void print_method_list2( ! 159: struct objc_method_description_list *mlist_before_reloc, ! 160: struct section *firstobjcsect, ! 161: int nsects ! 162: ); ! 163: static void getObjcSections( ! 164: struct mach_header *mh, ! 165: struct load_command *lc, ! 166: struct section **objcsects, ! 167: int *nsects ! 168: ); ! 169: static void readObjcData( ! 170: long fd, ! 171: char *filename, ! 172: struct section *objcsects, ! 173: int nsects ! 174: ); ! 175: static void swapObjcData( ! 176: struct section *objcsects, ! 177: int nsects ! 178: ); ! 179: static void swap_objc_modules( ! 180: struct objc_module *modules, ! 181: unsigned long size ! 182: ); ! 183: static void swap_objc_symtabs( ! 184: struct objc_symtab *symtabs, ! 185: unsigned long size ! 186: ); ! 187: static void swap_objc_classes( ! 188: struct objc_class *classes, ! 189: unsigned long size ! 190: ); ! 191: static void swap_objc_categories( ! 192: struct objc_category *categories, ! 193: unsigned long size ! 194: ); ! 195: static void swap_objc_method_lists( ! 196: struct objc_method_list *method_lists, ! 197: unsigned long size ! 198: ); ! 199: static void swap_objc_protocols( ! 200: Protocol *protocols, ! 201: unsigned long size ! 202: ); ! 203: static void swap_objc_ivar_lists( ! 204: struct objc_ivar_list *ivar_lists, ! 205: unsigned long size ! 206: ); ! 207: static void swap_objc_protocol_lists( ! 208: struct objc_protocol_list *protocol_lists, ! 209: unsigned long size ! 210: ); ! 211: static void swap_objc_refs( ! 212: unsigned long *refs, ! 213: unsigned long size ! 214: ); ! 215: static void swap_string_objects( ! 216: NXConstantString *s, ! 217: unsigned long size ! 218: ); ! 219: static void swap_objc_method_description_lists( ! 220: struct objc_method_description_list *mdls, ! 221: unsigned long size ! 222: ); ! 223: struct _hashEntry { ! 224: struct _hashEntry *next; ! 225: char *sel; ! 226: }; ! 227: static void swap_hashEntries( ! 228: struct _hashEntry *_hashEntries, ! 229: unsigned long size ! 230: ); ! 231: static void *getObjcData( ! 232: struct section *objcsects, ! 233: int nsects, ! 234: const void *addr ! 235: ); ! 236: static struct section *getObjcSection( ! 237: struct section *objcsects, ! 238: int nsects, ! 239: char *name ! 240: ); ! 241: ! 242: int swapped = 0; ! 243: ! 244: void ! 245: main(argc, argv) ! 246: int argc; ! 247: char *argv[]; ! 248: { ! 249: long fd; ! 250: char *filename; ! 251: struct mach_header mh; ! 252: struct load_command *lcp; ! 253: ! 254: progname = argv[0]; ! 255: ! 256: if(argc == 1) { ! 257: fprintf(stderr, "%s: At least one file must be specified\n", ! 258: progname); ! 259: usage(); ! 260: exit(1); ! 261: } ! 262: else if (argc == 2) ! 263: filename = argv[1]; ! 264: else ! 265: { ! 266: usage(); ! 267: exit(1); ! 268: } ! 269: ! 270: fd = open(filename, O_RDONLY); ! 271: if(fd < 0){ ! 272: fprintf(stderr, "%s : Can't open %s (%s)\n", progname, ! 273: filename, sys_errlist[errno]); ! 274: } ! 275: lseek(fd, 0, 0); ! 276: if(read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)){ ! 277: fprintf(stderr, "%s : Can't read mach header of %s (%s)\n", ! 278: progname, filename, sys_errlist[errno]); ! 279: return; ! 280: } ! 281: if(mh.magic == MH_MAGIC){ ! 282: if((lcp = (struct load_command *)malloc(mh.sizeofcmds)) ! 283: == (struct load_command *)0){ ! 284: fprintf(stderr, "%s : Ran out of memory (%s)\n", ! 285: progname, sys_errlist[errno]); ! 286: exit(1); ! 287: } ! 288: if(read(fd, (char *)lcp, mh.sizeofcmds) != mh.sizeofcmds){ ! 289: fprintf(stderr,"%s : Can't read load commands of %s (%s)\n", ! 290: progname, filename, sys_errlist[errno]); ! 291: lcp = (struct load_command *)0; ! 292: } ! 293: } ! 294: else if(mh.magic == NXSwapLong(MH_MAGIC)){ ! 295: if((lcp = (struct load_command *) ! 296: malloc(NXSwapLong(mh.sizeofcmds))) ! 297: == (struct load_command *)0){ ! 298: fprintf(stderr, "%s : Ran out of memory (%s)\n", ! 299: progname, sys_errlist[errno]); ! 300: exit(1); ! 301: } ! 302: if(read(fd, (char *)lcp, NXSwapLong(mh.sizeofcmds)) != ! 303: NXSwapLong(mh.sizeofcmds)){ ! 304: fprintf(stderr,"%s : Can't read load commands of %s (%s)\n", ! 305: progname, filename, sys_errlist[errno]); ! 306: lcp = (struct load_command *)0; ! 307: } ! 308: } ! 309: ! 310: { ! 311: struct section *firstobjcsect; ! 312: int nsects, size; ! 313: long vm_hashaddr; ! 314: void *table; ! 315: struct section *sel, *tmp; ! 316: char *selectors, tempfilename[] = "objcoptXXXXXX"; ! 317: ! 318: getObjcSections(&mh, lcp, &firstobjcsect, &nsects); ! 319: get_objc(fd, filename, firstobjcsect, nsects); ! 320: ! 321: if (strcmp(firstobjcsect[nsects-1].sectname, "__runtime_setup") == 0) ! 322: // we are doing a `replace' ! 323: vm_hashaddr = firstobjcsect[nsects-1].addr; ! 324: else ! 325: vm_hashaddr = round(firstobjcsect[nsects-1].addr + ! 326: firstobjcsect[nsects-1].size, sizeof(long)); ! 327: ! 328: sel = getObjcSection(firstobjcsect, nsects, "__meth_var_names"); ! 329: ! 330: tmp = getObjcSection(firstobjcsect, nsects, "__selector_strs"); ! 331: ! 332: if (sel && tmp) ! 333: { ! 334: fprintf (stderr, ! 335: "Cannot objcopt mixture of new and old strings\n"); ! 336: exit (1); ! 337: } ! 338: ! 339: if (!sel) ! 340: sel = tmp; // Use old-style strings ! 341: ! 342: selectors = (char *)sel->reserved1; ! 343: ! 344: _sel_writeHashTable(vm_hashaddr, (char *)selectors, (char *)sel->addr, ! 345: &table, &size); ! 346: if(swapped) ! 347: swap_hashEntries((struct _hashEntry *)table, size); ! 348: ! 349: mktemp(tempfilename); ! 350: add_objc_runtime_setup(filename,tempfilename,table, size); ! 351: ! 352: close(fd); ! 353: unlink(filename); ! 354: if (rename(tempfilename, filename) == -1) { ! 355: fprintf(stderr, "%s : Cannot rename temporary file from: " ! 356: "%s to %s\n", progname, tempfilename, filename); ! 357: exit(1); ! 358: } ! 359: } ! 360: ! 361: exit(0); ! 362: } ! 363: ! 364: static void getObjcSections( ! 365: struct mach_header *mh, ! 366: struct load_command *lc, ! 367: struct section **objcsects, ! 368: int *nsects ! 369: ) ! 370: { ! 371: int i,j; ! 372: struct segment_command *sg; ! 373: struct section *s; ! 374: struct load_command l, *initlc; ! 375: ! 376: swapped = mh->magic == NXSwapLong(MH_MAGIC); ! 377: if(swapped) ! 378: swap_mach_header(mh, NXHostByteOrder()); ! 379: initlc = lc; ! 380: ! 381: for(i = 0 ; i < mh->ncmds; i++){ ! 382: l = *lc; ! 383: if(swapped) ! 384: swap_load_command(&l, NXHostByteOrder()); ! 385: if(l.cmdsize % sizeof(long) != 0) ! 386: printf("load command %d size not a multiple of sizeof(long)\n", ! 387: i); ! 388: if((char *)lc + l.cmdsize > (char *)initlc + mh->sizeofcmds) ! 389: printf("load command %d extends past end of load commands\n",i); ! 390: if(l.cmd == LC_SEGMENT){ ! 391: sg = (struct segment_command *)lc; ! 392: if(swapped) ! 393: swap_segment_command(sg, NXHostByteOrder()); ! 394: if(mh->filetype == MH_OBJECT || ! 395: strcmp(sg->segname, SEG_OBJC) == 0){ ! 396: ! 397: s = (struct section *) ! 398: ((char *)sg + sizeof(struct segment_command)); ! 399: ! 400: *objcsects = s; ! 401: *nsects = sg->nsects; ! 402: ! 403: for(j = 0 ; j < sg->nsects ; j++){ ! 404: if(swapped) ! 405: swap_section(s, 1, NXHostByteOrder()); ! 406: if((char *)s + sizeof(struct section) > ! 407: (char *)initlc + mh->sizeofcmds){ ! 408: printf("section structure command extends past end " ! 409: "of load commands\n"); ! 410: } ! 411: if((char *)s + sizeof(struct section) > ! 412: (char *)initlc + mh->sizeofcmds) ! 413: break; ! 414: s++; ! 415: } ! 416: } ! 417: } ! 418: if(l.cmdsize <= 0){ ! 419: printf("load command %d size negative or zero (can't " ! 420: "advance to other load commands)\n", i); ! 421: break; ! 422: } ! 423: lc = (struct load_command *)((char *)lc + l.cmdsize); ! 424: if((char *)lc > (char *)initlc + mh->sizeofcmds) ! 425: break; ! 426: } ! 427: if((char *)initlc + mh->sizeofcmds != (char *)lc) ! 428: printf("Inconsistant mh_sizeofcmds\n"); ! 429: } ! 430: ! 431: static void readObjcData( ! 432: long fd, ! 433: char *filename, ! 434: struct section *objcsects, ! 435: int nsects ! 436: ) ! 437: { ! 438: int i; ! 439: ! 440: for (i = 0; i < nsects; i++) { ! 441: ! 442: struct section *s; ! 443: ! 444: s = objcsects + i; ! 445: ! 446: if (s->size > 0) { ! 447: if((s->reserved1 = (long)malloc(s->size)) == 0) { ! 448: fprintf(stderr, "%s : Ran out of memory (%s)\n", ! 449: progname, sys_errlist[errno]); ! 450: exit(1); ! 451: } ! 452: lseek(fd, s->offset, 0); ! 453: if((read(fd, s->reserved1, s->size)) != s->size){ ! 454: fprintf(stderr, "%s : Can't read modules of %s (%s)\n", ! 455: progname, filename, sys_errlist[errno]); ! 456: free((void *)s->reserved1); ! 457: return; ! 458: } ! 459: } ! 460: } ! 461: } ! 462: ! 463: struct objc_protocol ! 464: { ! 465: @defs(Protocol) ! 466: }; ! 467: ! 468: struct objc_string_object ! 469: { ! 470: @defs(NXConstantString) ! 471: }; ! 472: ! 473: static void swapObjcData( ! 474: struct section *objcsects, ! 475: int nsects ! 476: ) ! 477: { ! 478: int i, categories_size = 0, protocols_size = 0; ! 479: struct objc_category *categories = NULL; ! 480: struct objc_protocol *protocols = NULL; ! 481: struct section *s, *cat_inst = NULL, *cat_cls = NULL; ! 482: struct objc_method_list *method_list; ! 483: struct objc_protocol_list *protocol_list; ! 484: struct objc_method_description_list *mdl; ! 485: ! 486: for (i = 0; i < nsects; i++) { ! 487: ! 488: s = objcsects + i; ! 489: if(strncmp(s->sectname, "__class", 16) == 0 || ! 490: strncmp(s->sectname, "__meta_class", 16) == 0){ ! 491: swap_objc_classes((struct objc_class *)s->reserved1, ! 492: s->size); ! 493: } ! 494: else if(strncmp(s->sectname, "__string_object", 16) == 0){ ! 495: swap_string_objects((NXConstantString *)s->reserved1, ! 496: s->size); ! 497: } ! 498: else if(strncmp(s->sectname, "__protocol", 16) == 0){ ! 499: protocols = (struct objc_protocol *)s->reserved1; ! 500: protocols_size = s->size; ! 501: swap_objc_protocols((Protocol *)s->reserved1, ! 502: s->size); ! 503: } ! 504: else if(strncmp(s->sectname, "__cat_cls_meth", 16) == 0){ ! 505: /* handled special below */ ! 506: cat_cls = s; ! 507: } ! 508: else if(strncmp(s->sectname, "__cat_inst_meth", 16) == 0){ ! 509: /* handled special below */ ! 510: cat_inst = s; ! 511: } ! 512: else if(strncmp(s->sectname, "__cls_meth", 16) == 0 || ! 513: strncmp(s->sectname, "__inst_meth", 16) == 0){ ! 514: swap_objc_method_lists((struct objc_method_list *) ! 515: s->reserved1, s->size); ! 516: } ! 517: else if(strncmp(s->sectname, "__message_refs", 16) == 0 || ! 518: strncmp(s->sectname, "__selector_refs", 16) == 0 || ! 519: strncmp(s->sectname, "__cls_refs", 16) == 0){ ! 520: swap_objc_refs((unsigned long *)s->reserved1, s->size); ! 521: } ! 522: else if(strncmp(s->sectname, "__class_names", 16) == 0 || ! 523: strncmp(s->sectname, "__meth_var_names", 16) == 0 || ! 524: strncmp(s->sectname, "__meth_var_types", 16) == 0 || ! 525: strncmp(s->sectname, "__selector_strs", 16) == 0){ ! 526: ; /* character strings, no swapping */ ! 527: } ! 528: else if(strncmp(s->sectname, "__module_info", 16) == 0){ ! 529: swap_objc_modules((struct objc_module *)s->reserved1, ! 530: s->size); ! 531: } ! 532: else if(strncmp(s->sectname, "__symbols", 16) == 0){ ! 533: swap_objc_symtabs((struct objc_symtab *)s->reserved1, ! 534: s->size); ! 535: } ! 536: else if(strncmp(s->sectname, "__category", 16) == 0){ ! 537: categories = (struct objc_category *)s->reserved1; ! 538: categories_size = s->size; ! 539: swap_objc_categories((struct objc_category *)s->reserved1, ! 540: s->size); ! 541: } ! 542: else if(strncmp(s->sectname, "__class_vars", 16) == 0 || ! 543: strncmp(s->sectname, "__instance_vars", 16) == 0){ ! 544: swap_objc_ivar_lists((struct objc_ivar_list *)s->reserved1, ! 545: s->size); ! 546: } ! 547: else if(strncmp(s->sectname, "__runtime_setup", 16) == 0){ ! 548: ; /* do nothing it will be tossed */ ! 549: } ! 550: else if(strncmp(s->sectname, "__cstring_object", 16)) { ! 551: ; /* do nothing */ ! 552: } ! 553: else if(strncmp(s->sectname, "__sel_fixup", 16)) { ! 554: ; /* do nothing */ ! 555: } ! 556: else{ ! 557: fprintf(stderr, "%s : unknown __OBJC section: %s\n", ! 558: progname, s->sectname); ! 559: exit(1); ! 560: } ! 561: } ! 562: ! 563: for (i = 0; i < categories_size; i += sizeof(struct objc_category)){ ! 564: if(categories->instance_methods != 0){ ! 565: method_list = (struct objc_method_list *) ! 566: (cat_inst->reserved1 + ! 567: ((unsigned long)categories->instance_methods - ! 568: (unsigned long)cat_inst->addr)); ! 569: swap_objc_method_lists(method_list, ! 570: sizeof(struct objc_method_list) - ! 571: sizeof(struct objc_method)); ! 572: } ! 573: ! 574: if(categories->class_methods != 0){ ! 575: method_list = (struct objc_method_list *) ! 576: (cat_cls->reserved1 + ! 577: ((unsigned long)categories->class_methods - ! 578: (unsigned long)cat_cls->addr)); ! 579: swap_objc_method_lists(method_list, ! 580: sizeof(struct objc_method_list) - ! 581: sizeof(struct objc_method)); ! 582: } ! 583: ! 584: if(categories->protocols != 0){ ! 585: protocol_list = (struct objc_protocol_list *) ! 586: (cat_cls->reserved1 + ! 587: ((unsigned long)categories->protocols - ! 588: (unsigned long)cat_cls->addr)); ! 589: swap_objc_protocol_lists(protocol_list, ! 590: sizeof(struct objc_protocol_list) - ! 591: sizeof(struct objc_protocol *)); ! 592: } ! 593: categories++; ! 594: } ! 595: for (i = 0; i < protocols_size; i += sizeof(struct objc_protocol)){ ! 596: if(protocols->instance_methods != 0){ ! 597: mdl = (struct objc_method_description_list *) ! 598: (cat_inst->reserved1 + ! 599: ((unsigned long)protocols->instance_methods - ! 600: (unsigned long)cat_inst->addr)); ! 601: swap_objc_method_description_lists(mdl, ! 602: sizeof(struct objc_method_description_list) - ! 603: sizeof(struct objc_method_description)); ! 604: } ! 605: ! 606: if(protocols->class_methods != 0){ ! 607: mdl = (struct objc_method_description_list *) ! 608: (cat_cls->reserved1 + ! 609: ((unsigned long)protocols->class_methods - ! 610: (unsigned long)cat_cls->addr)); ! 611: swap_objc_method_description_lists(mdl, ! 612: sizeof(struct objc_method_description_list) - ! 613: sizeof(struct objc_method_description)); ! 614: } ! 615: protocols++; ! 616: } ! 617: } ! 618: ! 619: static ! 620: void ! 621: swap_objc_module( ! 622: struct objc_module *module, ! 623: enum NXByteOrder target_byte_order) ! 624: { ! 625: module->version = NXSwapLong(module->version); ! 626: module->size = NXSwapLong(module->size); ! 627: module->name = (char *) NXSwapLong((long)module->name); ! 628: module->symtab = (Symtab) NXSwapLong((long)module->symtab); ! 629: } ! 630: ! 631: static ! 632: void ! 633: swap_objc_symtab( ! 634: struct objc_symtab *symtab, ! 635: enum NXByteOrder target_byte_order) ! 636: { ! 637: symtab->sel_ref_cnt = NXSwapLong(symtab->sel_ref_cnt); ! 638: symtab->refs = (SEL *) NXSwapLong((long)symtab->refs); ! 639: symtab->cls_def_cnt = NXSwapShort(symtab->cls_def_cnt); ! 640: symtab->cat_def_cnt = NXSwapShort(symtab->cat_def_cnt); ! 641: } ! 642: ! 643: static ! 644: void ! 645: swap_objc_class( ! 646: struct objc_class *objc_class, ! 647: enum NXByteOrder target_byte_order) ! 648: { ! 649: objc_class->isa = (struct objc_class *) ! 650: NXSwapLong((long)objc_class->isa); ! 651: objc_class->super_class = (struct objc_class *) ! 652: NXSwapLong((long)objc_class->super_class); ! 653: objc_class->name = (const char *) ! 654: NXSwapLong((long)objc_class->name); ! 655: objc_class->version = ! 656: NXSwapLong(objc_class->version); ! 657: objc_class->info = ! 658: NXSwapLong(objc_class->info); ! 659: objc_class->instance_size = ! 660: NXSwapLong(objc_class->instance_size); ! 661: objc_class->ivars = (struct objc_ivar_list *) ! 662: NXSwapLong((long)objc_class->ivars); ! 663: objc_class->methods = (struct objc_method_list *) ! 664: NXSwapLong((long)objc_class->methods); ! 665: objc_class->cache = (struct objc_cache *) ! 666: NXSwapLong((long)objc_class->cache); ! 667: objc_class->protocols = (struct objc_protocol_list *) ! 668: NXSwapLong((long)objc_class->protocols); ! 669: } ! 670: ! 671: static ! 672: void ! 673: swap_objc_category( ! 674: struct objc_category *objc_category, ! 675: enum NXByteOrder target_byte_order) ! 676: { ! 677: objc_category->category_name = (char *) ! 678: NXSwapLong((long)objc_category->category_name); ! 679: objc_category->class_name = (char *) ! 680: NXSwapLong((long)objc_category->class_name); ! 681: objc_category->instance_methods = (struct objc_method_list *) ! 682: NXSwapLong((long)objc_category->instance_methods); ! 683: objc_category->class_methods = (struct objc_method_list *) ! 684: NXSwapLong((long)objc_category->class_methods); ! 685: objc_category->protocols = (struct objc_protocol_list *) ! 686: NXSwapLong((long)objc_category->protocols); ! 687: } ! 688: ! 689: static ! 690: void ! 691: swap_objc_ivar_list( ! 692: struct objc_ivar_list *objc_ivar_list, ! 693: enum NXByteOrder target_byte_order) ! 694: { ! 695: objc_ivar_list->ivar_count = NXSwapLong(objc_ivar_list->ivar_count); ! 696: } ! 697: ! 698: static ! 699: void ! 700: swap_objc_ivar( ! 701: struct objc_ivar *objc_ivar, ! 702: enum NXByteOrder target_byte_order) ! 703: { ! 704: objc_ivar->ivar_name = (char *) ! 705: NXSwapLong((long)objc_ivar->ivar_name); ! 706: objc_ivar->ivar_type = (char *) ! 707: NXSwapLong((long)objc_ivar->ivar_type); ! 708: objc_ivar->ivar_offset = ! 709: NXSwapLong(objc_ivar->ivar_offset); ! 710: } ! 711: ! 712: static ! 713: void ! 714: swap_objc_method_list( ! 715: struct objc_method_list *method_list, ! 716: enum NXByteOrder target_byte_order) ! 717: { ! 718: method_list->method_next = (struct objc_method_list *) ! 719: NXSwapLong((long)method_list->method_next); ! 720: method_list->method_count = ! 721: NXSwapLong(method_list->method_count); ! 722: } ! 723: ! 724: static ! 725: void ! 726: swap_objc_method( ! 727: struct objc_method *method, ! 728: enum NXByteOrder target_byte_order) ! 729: { ! 730: method->method_name = (SEL) ! 731: NXSwapLong((long)method->method_name); ! 732: method->method_types = (char *) ! 733: NXSwapLong((long)method->method_types); ! 734: method->method_imp = (IMP) ! 735: NXSwapLong((long)method->method_imp); ! 736: } ! 737: ! 738: static ! 739: void ! 740: swap_objc_protocol_list( ! 741: struct objc_protocol_list *protocol_list, ! 742: enum NXByteOrder target_byte_order) ! 743: { ! 744: protocol_list->next = (struct objc_protocol_list *) ! 745: NXSwapLong((long)protocol_list->next); ! 746: protocol_list->count = ! 747: NXSwapLong(protocol_list->count); ! 748: } ! 749: ! 750: static ! 751: void ! 752: swap_objc_protocol( ! 753: Protocol *p, ! 754: enum NXByteOrder target_byte_order) ! 755: { ! 756: struct objc_protocol *protocol; ! 757: ! 758: protocol = (struct objc_protocol *)p; ! 759: ! 760: protocol->isa = (struct objc_class *) ! 761: NXSwapLong((long)protocol->isa); ! 762: protocol->protocol_name = (char *) ! 763: NXSwapLong((long)protocol->protocol_name); ! 764: protocol->protocol_list = (struct objc_protocol_list *) ! 765: NXSwapLong((long)protocol->protocol_list); ! 766: protocol->instance_methods = (struct objc_method_description_list *) ! 767: NXSwapLong((long)protocol->instance_methods); ! 768: protocol->class_methods = (struct objc_method_description_list *) ! 769: NXSwapLong((long)protocol->class_methods); ! 770: ! 771: } ! 772: ! 773: static ! 774: void ! 775: swap_objc_method_description_list( ! 776: struct objc_method_description_list *mdl, ! 777: enum NXByteOrder target_byte_order) ! 778: { ! 779: mdl->count = NXSwapLong(mdl->count); ! 780: } ! 781: ! 782: static ! 783: void ! 784: swap_objc_method_description( ! 785: struct objc_method_description *md, ! 786: enum NXByteOrder target_byte_order) ! 787: { ! 788: md->name = (SEL)NXSwapLong((long)md->name); ! 789: md->types = (char *)NXSwapLong((long)md->types); ! 790: } ! 791: ! 792: void ! 793: swap_string_object( ! 794: NXConstantString *p, ! 795: enum NXByteOrder target_byte_order) ! 796: { ! 797: struct objc_string_object *string_object; ! 798: ! 799: string_object = (struct objc_string_object *)p; ! 800: ! 801: string_object->isa = (struct objc_class *) ! 802: NXSwapLong((long)string_object->isa); ! 803: string_object->characters = (char *) ! 804: NXSwapLong((long)string_object->characters); ! 805: string_object->_length = ! 806: NXSwapLong(string_object->_length); ! 807: } ! 808: ! 809: static ! 810: void ! 811: swap_hashEntry( ! 812: struct _hashEntry *_hashEntry, ! 813: enum NXByteOrder target_byte_order) ! 814: { ! 815: _hashEntry->next = (struct _hashEntry *) ! 816: NXSwapLong((long)_hashEntry->next); ! 817: _hashEntry->sel = (char *) ! 818: NXSwapLong((long)_hashEntry->sel); ! 819: } ! 820: ! 821: static void swap_objc_modules( ! 822: struct objc_module *modules, ! 823: unsigned long size ! 824: ) ! 825: { ! 826: int i, j; ! 827: ! 828: for (i = 0, j = 0; i < size; i += sizeof(struct objc_module), j++) ! 829: swap_objc_module(modules + j, NXHostByteOrder()); ! 830: } ! 831: ! 832: static void swap_objc_symtabs( ! 833: struct objc_symtab *symtabs, ! 834: unsigned long size ! 835: ) ! 836: { ! 837: int i, j; ! 838: struct objc_symtab *symtab; ! 839: ! 840: symtab = symtabs; ! 841: while ((unsigned long)symtab - (unsigned long)symtabs < size){ ! 842: swap_objc_symtab(symtab, NXHostByteOrder()); ! 843: for(j = 0; j < symtab->cls_def_cnt; j++){ ! 844: symtab->defs[j] = (struct objc_class *) ! 845: NXSwapLong((long)symtab->defs[j]); ! 846: } ! 847: for(j = 0; j < symtab->cat_def_cnt; j++){ ! 848: symtab->defs[j + symtab->cls_def_cnt] = ! 849: (struct objc_class *) ! 850: NXSwapLong((long)symtab->defs[j + symtab->cls_def_cnt]); ! 851: } ! 852: symtab = (struct objc_symtab *) ! 853: (&(symtab->defs[symtab->cls_def_cnt + ! 854: symtab->cat_def_cnt])); ! 855: } ! 856: } ! 857: ! 858: static void swap_objc_classes( ! 859: struct objc_class *classes, ! 860: unsigned long size ! 861: ) ! 862: { ! 863: int i, j; ! 864: ! 865: for (i = 0, j = 0; i < size; i += sizeof(struct objc_class), j++) ! 866: swap_objc_class(classes + j, NXHostByteOrder()); ! 867: } ! 868: ! 869: static void swap_objc_categories( ! 870: struct objc_category *categories, ! 871: unsigned long size ! 872: ) ! 873: { ! 874: int i, j; ! 875: ! 876: for (i = 0, j = 0; i < size; i += sizeof(struct objc_category), j++) ! 877: swap_objc_category(categories + j, NXHostByteOrder()); ! 878: } ! 879: ! 880: static void swap_objc_method_lists( ! 881: struct objc_method_list *method_lists, ! 882: unsigned long size ! 883: ) ! 884: { ! 885: int i, j; ! 886: struct objc_method_list *method_list; ! 887: ! 888: method_list = method_lists; ! 889: while ((unsigned long)method_list - (unsigned long)method_lists < size){ ! 890: swap_objc_method_list(method_list, NXHostByteOrder()); ! 891: for (j = 0; j < method_list->method_count; j++){ ! 892: swap_objc_method(&(method_list->method_list[j]), ! 893: NXHostByteOrder()); ! 894: } ! 895: method_list = (struct objc_method_list *) ! 896: (&(method_list->method_list[method_list->method_count])); ! 897: } ! 898: } ! 899: ! 900: static void swap_objc_protocols( ! 901: Protocol *protocols, ! 902: unsigned long size ! 903: ) ! 904: { ! 905: int i, j; ! 906: ! 907: for (i = 0, j = 0; i < size; i += sizeof(struct objc_protocol), j++) ! 908: swap_objc_protocol(protocols + j, NXHostByteOrder()); ! 909: } ! 910: ! 911: static void swap_objc_ivar_lists( ! 912: struct objc_ivar_list *ivar_lists, ! 913: unsigned long size ! 914: ) ! 915: { ! 916: int i, j; ! 917: struct objc_ivar_list *ivar_list; ! 918: ! 919: ivar_list = ivar_lists; ! 920: while ((unsigned long)ivar_list - (unsigned long)ivar_lists < size){ ! 921: swap_objc_ivar_list(ivar_list, NXHostByteOrder()); ! 922: for (j = 0; j < ivar_list->ivar_count; j++){ ! 923: swap_objc_ivar(&(ivar_list->ivar_list[j]), ! 924: NXHostByteOrder()); ! 925: } ! 926: ivar_list = (struct objc_ivar_list *) ! 927: (&(ivar_list->ivar_list[ivar_list->ivar_count])); ! 928: } ! 929: } ! 930: ! 931: static void swap_objc_protocol_lists( ! 932: struct objc_protocol_list *protocol_lists, ! 933: unsigned long size ! 934: ) ! 935: { ! 936: int i, j; ! 937: struct objc_protocol_list *protocol_list; ! 938: ! 939: protocol_list = protocol_lists; ! 940: while ((unsigned long)protocol_list - ! 941: (unsigned long)protocol_lists < size){ ! 942: swap_objc_protocol_list(protocol_list, NXHostByteOrder()); ! 943: for (j = 0; j < protocol_list->count; j++){ ! 944: protocol_list->list[j] = (Protocol *) ! 945: NXSwapLong((long)(protocol_list->list[j])); ! 946: } ! 947: protocol_list = (struct objc_protocol_list *) ! 948: (&(protocol_list->list[protocol_list->count])); ! 949: } ! 950: } ! 951: ! 952: static void swap_objc_method_description_lists( ! 953: struct objc_method_description_list *mdls, ! 954: unsigned long size ! 955: ) ! 956: { ! 957: int i, j; ! 958: struct objc_method_description_list *mdl; ! 959: ! 960: mdl = mdls; ! 961: while ((unsigned long)mdl - (unsigned long)mdls < size){ ! 962: swap_objc_method_description_list(mdl, NXHostByteOrder()); ! 963: for (j = 0; j < mdl->count; j++){ ! 964: swap_objc_method_description( &(mdl->list[j]), ! 965: NXHostByteOrder()); ! 966: } ! 967: mdl = (struct objc_method_description_list *) ! 968: (&(mdl->list[mdl->count])); ! 969: } ! 970: } ! 971: ! 972: static void *getObjcData( ! 973: struct section *objcsects, ! 974: int nsects, ! 975: const void *addr ! 976: ) ! 977: { ! 978: int i; ! 979: ! 980: if (addr == 0) ! 981: return 0; ! 982: ! 983: for (i = 0; i < nsects; i++) { ! 984: struct section *s; ! 985: ! 986: s = objcsects + i; ! 987: if (((long)addr >= s->addr) && ! 988: ((long)addr < (s->addr + s->size))) ! 989: return (void *)(s->reserved1 + ((long)addr - s->addr)); ! 990: } ! 991: fprintf(stderr, "%s : Could not `getObjcData'\n", progname); ! 992: exit(1); ! 993: } ! 994: ! 995: static void swap_objc_refs( ! 996: unsigned long *refs, ! 997: unsigned long size ! 998: ) ! 999: { ! 1000: int i,j; ! 1001: ! 1002: for (i = 0, j = 0; i < size; i += sizeof(unsigned long), j++) ! 1003: refs[j] = NXSwapLong(refs[j]); ! 1004: } ! 1005: ! 1006: static struct section *getObjcSection( ! 1007: struct section *objcsects, ! 1008: int nsects, ! 1009: char *name ! 1010: ) ! 1011: { ! 1012: int i; ! 1013: ! 1014: for (i = 0; i < nsects; i++) { ! 1015: struct section *s; ! 1016: ! 1017: s = objcsects + i; ! 1018: if (strncmp(s->sectname,name,16) == 0) ! 1019: return s; ! 1020: } ! 1021: return 0; ! 1022: } ! 1023: ! 1024: static void swap_string_objects( ! 1025: NXConstantString *s, ! 1026: unsigned long size ! 1027: ) ! 1028: { ! 1029: int i, j; ! 1030: ! 1031: for (i = 0, j = 0; i < size; i += sizeof(struct objc_string_object), j++) ! 1032: swap_string_object(s + j, NXHostByteOrder()); ! 1033: } ! 1034: ! 1035: static void swap_hashEntries( ! 1036: struct _hashEntry *_hashEntries, ! 1037: unsigned long size ! 1038: ) ! 1039: { ! 1040: int i, j; ! 1041: enum NXByteOrder target_byte_order; ! 1042: ! 1043: target_byte_order = NXHostByteOrder() == NX_BigEndian ? ! 1044: NX_LittleEndian : NX_BigEndian; ! 1045: ! 1046: for (i = 0, j = 0; i < size; i += sizeof(struct _hashEntry), j++) ! 1047: swap_hashEntry(_hashEntries + j, target_byte_order); ! 1048: } ! 1049: ! 1050: /* ! 1051: * Print the objc segment. ! 1052: */ ! 1053: static ! 1054: struct objc_module * ! 1055: get_objc(fd, filename, firstobjcsect, nsects) ! 1056: long fd; ! 1057: char *filename; ! 1058: struct section *firstobjcsect; ! 1059: int nsects; ! 1060: { ! 1061: long i, j; ! 1062: struct section *modsect, *msgsect, *selsect, *protosect; ! 1063: struct objc_module *modules, *m; ! 1064: struct objc_symtab *t; ! 1065: ! 1066: readObjcData(fd, filename, firstobjcsect, nsects); ! 1067: if(swapped) ! 1068: swapObjcData(firstobjcsect, nsects); ! 1069: ! 1070: modsect = getObjcSection(firstobjcsect, nsects, "__module_info"); ! 1071: msgsect = getObjcSection(firstobjcsect, nsects, "__message_refs"); ! 1072: if (msgsect) { ! 1073: int i, cnt = msgsect->size/sizeof(SEL); ! 1074: SEL *sels = (SEL *)msgsect->reserved1; ! 1075: ! 1076: /* overwrite the string with a unique identifier */ ! 1077: for (i = 0; i < cnt; i++) ! 1078: sels[i] = (SEL)sel_registerName( ! 1079: getObjcData(firstobjcsect, nsects, ! 1080: sels[i])); ! 1081: } ! 1082: selsect = getObjcSection(firstobjcsect, nsects, "__selector_refs"); ! 1083: if (selsect) { ! 1084: int i, cnt = selsect->size/sizeof(SEL); ! 1085: SEL *sels = (SEL *)selsect->reserved1; ! 1086: ! 1087: /* overwrite the string with a unique identifier */ ! 1088: for (i = 0; i < cnt; i++) ! 1089: sels[i] = (SEL)sel_registerName( ! 1090: getObjcData(firstobjcsect, nsects, ! 1091: sels[i])); ! 1092: } ! 1093: modules = (Module)modsect->reserved1; ! 1094: ! 1095: for(m = modules ; ! 1096: (char *)m < (char *)modules + modsect->size; ! 1097: m = (struct objc_module *)((char *)m + m->size) ){ ! 1098: ! 1099: /* relocate fields in module structure */ ! 1100: ! 1101: m->name = (char *)getObjcData(firstobjcsect, nsects, ! 1102: m->name); ! 1103: m->symtab = t = (Symtab)getObjcData(firstobjcsect, nsects, ! 1104: m->symtab); ! 1105: ! 1106: if (t) { ! 1107: ! 1108: /* Simulate map! */ ! 1109: if (m->version == 1) { ! 1110: int i, cnt = m->symtab->sel_ref_cnt; ! 1111: SEL *sels = (SEL *)getObjcData(firstobjcsect, nsects, ! 1112: m->symtab->refs); ! 1113: ! 1114: /* overwrite the string with a unique identifier */ ! 1115: for (i = 0; i < cnt; i++) ! 1116: sels[i] = (SEL)sel_registerName( ! 1117: getObjcData(firstobjcsect, nsects, ! 1118: sels[i])); ! 1119: } ! 1120: ! 1121: for(i = 0; i < t->cls_def_cnt; i++){ ! 1122: ! 1123: struct objc_class *objc_class; ! 1124: ! 1125: t->defs[i] = objc_class = ! 1126: (Class)getObjcData(firstobjcsect, nsects, ! 1127: t->defs[i]); ! 1128: print_objc_class: ! 1129: /* relocate class structure */ ! 1130: ! 1131: if(CLS_GETINFO(objc_class, CLS_META)){ ! 1132: objc_class->isa = (Class)getObjcData( ! 1133: firstobjcsect, nsects, objc_class->isa); ! 1134: } ! 1135: ! 1136: objc_class->super_class = (Class)getObjcData( ! 1137: firstobjcsect, nsects, ! 1138: objc_class->super_class); ! 1139: ! 1140: objc_class->name = (char *)getObjcData( ! 1141: firstobjcsect, nsects, ! 1142: objc_class->name); ! 1143: ! 1144: if (objc_class->ivars) { ! 1145: struct objc_ivar_list *ilist; ! 1146: struct objc_ivar *ivar; ! 1147: ! 1148: objc_class->ivars = ilist = ! 1149: (struct objc_ivar_list *)getObjcData( ! 1150: firstobjcsect, nsects, ! 1151: objc_class->ivars); ! 1152: ! 1153: ivar = ilist->ivar_list; ! 1154: for(j = 0; j < ilist->ivar_count; j++, ivar++){ ! 1155: ivar->ivar_name= (char *)getObjcData( ! 1156: firstobjcsect, nsects, ! 1157: ivar->ivar_name); ! 1158: ! 1159: ivar->ivar_type= (char *)getObjcData( ! 1160: firstobjcsect, nsects, ! 1161: ivar->ivar_type); ! 1162: } ! 1163: } ! 1164: ! 1165: if (objc_class->methods) { ! 1166: print_method_list(objc_class->methods, ! 1167: firstobjcsect, nsects); ! 1168: } ! 1169: ! 1170: if(CLS_GETINFO(objc_class, CLS_CLASS)){ ! 1171: objc_class->isa = objc_class = ! 1172: (Class)getObjcData( ! 1173: firstobjcsect, nsects, ! 1174: objc_class->isa); ! 1175: goto print_objc_class; ! 1176: } ! 1177: } ! 1178: ! 1179: for(i = 0; i < t->cat_def_cnt; i++){ ! 1180: ! 1181: struct objc_category *objc_category; ! 1182: ! 1183: t->defs[i + t->cls_def_cnt] = objc_category = ! 1184: (Category)getObjcData(firstobjcsect, nsects, ! 1185: t->defs[i+t->cls_def_cnt]); ! 1186: ! 1187: objc_category->category_name = (char *)getObjcData( ! 1188: firstobjcsect, nsects, ! 1189: objc_category->category_name); ! 1190: ! 1191: objc_category->class_name = (char *)getObjcData( ! 1192: firstobjcsect, nsects, ! 1193: objc_category->class_name); ! 1194: ! 1195: if (objc_category->instance_methods) { ! 1196: print_method_list(objc_category->instance_methods, ! 1197: firstobjcsect, nsects); ! 1198: } ! 1199: ! 1200: if (objc_category->class_methods) { ! 1201: print_method_list(objc_category->class_methods, ! 1202: firstobjcsect, nsects); ! 1203: } ! 1204: } ! 1205: } ! 1206: } ! 1207: protosect = getObjcSection(firstobjcsect, nsects, "__protocol"); ! 1208: if (protosect) { ! 1209: int i, cnt = protosect->size/sizeof(Protocol); ! 1210: struct proto_template { @defs(Protocol) } *protos; ! 1211: ! 1212: protos = (struct proto_template *) protosect->reserved1; ! 1213: ! 1214: for (i = 0; i < cnt; i++) ! 1215: { ! 1216: if (protos[i].instance_methods) { ! 1217: print_method_list2(protos[i].instance_methods, ! 1218: firstobjcsect, nsects); ! 1219: } ! 1220: ! 1221: if (protos[i].class_methods) { ! 1222: print_method_list2(protos[i].class_methods, ! 1223: firstobjcsect, nsects); ! 1224: } ! 1225: } ! 1226: } ! 1227: return modules; ! 1228: } ! 1229: ! 1230: static ! 1231: void ! 1232: print_method_list(struct objc_method_list *mlist_before_reloc, ! 1233: struct section *firstobjcsect, ! 1234: int nsects) ! 1235: { ! 1236: long i; ! 1237: struct objc_method *method; ! 1238: struct objc_method_list *mlist; ! 1239: ! 1240: mlist = (struct objc_method_list *)getObjcData(firstobjcsect, nsects, ! 1241: mlist_before_reloc); ! 1242: method = mlist->method_list; ! 1243: for(i = 0; i < mlist->method_count; i++, method++){ ! 1244: ! 1245: method->method_name = (SEL)getObjcData(firstobjcsect, nsects, ! 1246: method->method_name); ! 1247: ! 1248: method->method_types = (char *)getObjcData(firstobjcsect, nsects, ! 1249: method->method_types); ! 1250: ! 1251: method->method_name = ! 1252: (SEL)sel_registerName((STR)method->method_name); ! 1253: ! 1254: } ! 1255: } ! 1256: ! 1257: static ! 1258: void ! 1259: print_method_list2(struct objc_method_description_list *mlist_before_reloc, ! 1260: struct section *firstobjcsect, ! 1261: int nsects) ! 1262: { ! 1263: long i; ! 1264: struct objc_method_description *method; ! 1265: struct objc_method_description_list *mlist; ! 1266: ! 1267: mlist = (struct objc_method_description_list *)getObjcData(firstobjcsect, nsects, ! 1268: mlist_before_reloc); ! 1269: method = mlist->list; ! 1270: for(i = 0; i < mlist->count; i++, method++){ ! 1271: ! 1272: method->name = (SEL)getObjcData(firstobjcsect, nsects, ! 1273: method->name); ! 1274: method->name = ! 1275: (SEL)sel_registerName((STR)method->name); ! 1276: ! 1277: } ! 1278: } ! 1279: ! 1280: /* ! 1281: * Print the current usage message. ! 1282: */ ! 1283: static ! 1284: void ! 1285: usage() ! 1286: { ! 1287: fprintf(stderr, ! 1288: "Usage: %s <shlib file>\n", ! 1289: progname); ! 1290: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.