1/* 2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#include <CoreFoundation/CoreFoundation.h> 24 25#include <IOKit/kext/OSKext.h> 26#include <IOKit/kext/OSKextPrivate.h> 27 28#include "kextlibs_main.h" 29#include "kext_tools_util.h" 30 31 32/******************************************************************************* 33* Local function prototypes and misc grotty bits. 34*******************************************************************************/ 35const char * progname = "(unknown)"; 36 37/******************************************************************************* 38*******************************************************************************/ 39int main(int argc, char * const * argv) 40{ 41 ExitStatus result = EX_OSERR; 42 ExitStatus printResult = EX_OSERR; 43 44 KextlibsArgs toolArgs; 45 CFArrayRef kexts = NULL; // must release 46 47 const NXArchInfo ** arches = NULL; // must free 48 KextlibsInfo * libInfo = NULL; // must release contents & free 49 Boolean libsAreArchSpecific = FALSE; 50 51 CFIndex count, i; 52 CFIndex numArches; 53 54 /***** 55 * Find out what the program was invoked as. 56 */ 57 progname = rindex(argv[0], '/'); 58 if (progname) { 59 progname++; // go past the '/' 60 } else { 61 progname = (char *)argv[0]; 62 } 63 64 /* Set the OSKext log callback right away. 65 */ 66 OSKextSetLogOutputFunction(&tool_log); 67 68 result = readArgs(argc, argv, &toolArgs); 69 if (result != EX_OK) { 70 if (result == kKextlibsExitHelp) { 71 result = EX_OK; 72 } 73 goto finish; 74 } 75 76 result = EX_OSERR; 77 78 /***** 79 * If necessary or requested, add the extensions folders to the 80 * BEGINNING of the list of folders. 81 */ 82 count = CFArrayGetCount(toolArgs.repositoryURLs); 83 if (!count || toolArgs.flagSysKexts) { 84 CFArrayRef osExtFolders = OSKextGetSystemExtensionsFolderURLs(); // do not release 85 86 if (!osExtFolders) { 87 OSKextLog(/* kext */ NULL, 88 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 89 "Library error - can't get system extensions folders."); 90 goto finish; 91 } 92 93 count = CFArrayGetCount(osExtFolders); 94 for (i = 0; i < count; i++) { 95 CFTypeRef osExtFolder = CFArrayGetValueAtIndex(osExtFolders, i); 96 CFIndex folderIndex = CFArrayGetFirstIndexOfValue( 97 toolArgs.repositoryURLs, RANGE_ALL(toolArgs.repositoryURLs), 98 osExtFolder); 99 if (folderIndex == kCFNotFound) { 100 CFArrayInsertValueAtIndex(toolArgs.repositoryURLs, i, 101 osExtFolder); 102 } 103 } 104 } 105 106 kexts = OSKextCreateKextsFromURLs(kCFAllocatorDefault, 107 toolArgs.repositoryURLs); 108 if (!kexts) { 109 OSKextLog(/* kext */ NULL, 110 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 111 "Can't read kexts from folders."); 112 goto finish; 113 } 114 115 toolArgs.kextURL = CFURLCreateFromFileSystemRepresentation( 116 kCFAllocatorDefault, (u_char *)toolArgs.kextName, 117 strlen(toolArgs.kextName), /* isDirectory */ true); 118 if (!toolArgs.kextURL) { 119 OSKextLogStringError(/* kext */ NULL); 120 goto finish; 121 } 122 toolArgs.theKext = OSKextCreate(kCFAllocatorDefault,toolArgs. kextURL); 123 if (!toolArgs.theKext) { 124 OSKextLog(/* kext */ NULL, 125 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 126 "Can't open %s.", toolArgs.kextName); 127 goto finish; 128 } 129 130 /* A codeless kext is either a library redirect, 131 * so we can't advise, or it doesn't need any libraries! 132 */ 133 if (!OSKextDeclaresExecutable(toolArgs.theKext)) { 134 if (OSKextIsLibrary(toolArgs.theKext)) { 135 OSKextLog(/* kext */ NULL, 136 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 137 "%s is a library without an executable; " 138 "defining its OSBundleLibraries (if any) is up to you.", 139 toolArgs.kextName); 140 } else { 141 CFDictionaryRef libs = OSKextGetValueForInfoDictionaryKey(toolArgs.theKext, 142 CFSTR(kOSBundleLibrariesKey)); 143 144 if (libs && 145 CFDictionaryGetTypeID() == CFGetTypeID(libs) && 146 CFDictionaryGetCount(libs)) { 147 148 OSKextLog(/* kext */ NULL, 149 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 150 "%s has no executable and should not declare OSBundleLibraries.", 151 toolArgs.kextName); 152 } else { 153 154 /* In this one case, the exit status will be EX_OK. 155 */ 156 OSKextLog(/* kext */ NULL, 157 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 158 "%s has no executable and does not need to declare OSBundleLibraries.", 159 toolArgs.kextName); 160 result = EX_OK; 161 } 162 } 163 164 goto finish; 165 } 166 167 arches = OSKextCopyArchitectures(toolArgs.theKext); 168 if (!arches || !arches[0]) { 169 OSKextLog(/* kext */ NULL, 170 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 171 "Can't determine architectures of %s.", 172 toolArgs.kextName); 173 goto finish; 174 } 175 176 result = EX_OK; 177 178 for (numArches = 0; arches[numArches]; numArches++) { 179 /* just counting */ 180 } 181 182 libInfo = (KextlibsInfo *)malloc(numArches * sizeof(KextlibsInfo)); 183 if (!libInfo) { 184 OSKextLogMemError(); 185 goto finish; 186 } 187 188 /* Find libraries for the kext for each architecture in the kext. 189 */ 190 for (i = 0; i < numArches; i++) { 191 OSKextSetArchitecture(arches[i]); 192 193 libInfo[i].libKexts = OSKextFindLinkDependencies(toolArgs.theKext, 194 toolArgs.flagNonKPI, toolArgs.flagAllowUnsupported, 195 &libInfo[i].undefSymbols, &libInfo[i].onedefSymbols, 196 &libInfo[i].multdefSymbols, &libInfo[i].multdefLibs); 197 198 if (!libInfo[i].libKexts) { 199 OSKextLogMemError(); 200 result = EX_OSERR; 201 goto finish; 202 } 203 } 204 205 /* If there's more than 1 arch, see if we have to print arch-specific 206 * results. 207 */ 208 if (numArches >= 2) { 209 for (i = 0; i < numArches - 1; i++) { 210 if (!CFEqual(libInfo[i].libKexts, libInfo[i+1].libKexts)) { 211 libsAreArchSpecific = TRUE; 212 break; 213 } 214 } 215 } 216 217 /* If all the libs are the same for all arches, then just print them 218 * once at the top of the output. Otherwise, only when doing XML, 219 * print the arch-specific XML declarations before the diagnostics. 220 */ 221 if (!libsAreArchSpecific) { 222 printResult = printLibs(&toolArgs, NULL, libInfo[0].libKexts, 223 /* extraNewline? */ TRUE); 224 225 /* Higher exit statuses always win. 226 */ 227 if (printResult > result) { 228 result = printResult; 229 } 230 } else if (toolArgs.flagXML) { 231 232 for (i = 0; i < numArches; i++) { 233 printResult = printLibs(&toolArgs, arches[i], 234 libInfo[i].libKexts, 235 /* extraNewline? */ i + 1 == numArches); 236 if (printResult > result) { 237 result = printResult; 238 } 239 } 240 } 241 242 /* Down here, for each arch, print arch-specific non-XML library declarations, 243 * followed by any problems found for that arch. 244 */ 245 for (i = 0; i < numArches; i++) { 246 247 if (libsAreArchSpecific && !toolArgs.flagXML) { 248 printResult = printLibs(&toolArgs, arches[i], libInfo[i].libKexts, 249 /* extraNewline? */ i + 1 == numArches); 250 if (printResult > result) { 251 result = printResult; 252 } 253 } 254 255 printResult = printProblems(&toolArgs, arches[i], 256 libInfo[i].undefSymbols, libInfo[i].onedefSymbols, 257 libInfo[i].multdefSymbols, libInfo[i].multdefLibs, 258 /* printArchFlag */ !libsAreArchSpecific || toolArgs.flagXML, 259 /* extraNewline? */ i + i < numArches); 260 261 if (printResult != EX_OK) { 262 /* Higher exit statuses always win. 263 */ 264 if (printResult > result) { 265 result = printResult; 266 } 267 } 268 } 269 270 271finish: 272 273 /* Theoretically, we could exit w/o cleaning up. However, 12569152 274 points out that while clang should know exit() cleans up, its 275 analyzer *should* treat CF objects differently: releasing them might 276 have (important, expected) side effects. So we just clean up 277 everything and return from main, letting the runtime exit(result). 278 */ 279 280 281 SAFE_FREE(arches); 282 283 SAFE_RELEASE(toolArgs.repositoryURLs); 284 SAFE_RELEASE(toolArgs.kextURL); 285 SAFE_RELEASE(toolArgs.theKext); 286 SAFE_RELEASE(kexts); // this is the one clang unexpectedly noticed 287 288 if (libInfo) { 289 for (i = 0; i < numArches; i++) { 290 SAFE_RELEASE_NULL(libInfo[i].libKexts); 291 SAFE_RELEASE_NULL(libInfo[i].undefSymbols); 292 SAFE_RELEASE_NULL(libInfo[i].onedefSymbols); 293 SAFE_RELEASE_NULL(libInfo[i].multdefSymbols); 294 SAFE_RELEASE_NULL(libInfo[i].multdefLibs); 295 } 296 free(libInfo); 297 } 298 return result; 299} 300 301/******************************************************************************* 302*******************************************************************************/ 303ExitStatus readArgs( 304 int argc, 305 char * const * argv, 306 KextlibsArgs * toolArgs) 307{ 308 ExitStatus result = EX_USAGE; 309 ExitStatus scratchResult = EX_USAGE; 310 int optChar = 0; 311 312 bzero(toolArgs, sizeof(*toolArgs)); 313 314 /***** 315 * Allocate collection objects needed for command line argument processing. 316 */ 317 toolArgs->repositoryURLs = CFArrayCreateMutable(kCFAllocatorDefault, 0, 318 &kCFTypeArrayCallBacks); 319 if (!toolArgs->repositoryURLs) { 320 OSKextLogMemError(); 321 result = EX_OSERR; 322 goto finish; 323 } 324 325 /***** 326 * Process command-line arguments. 327 */ 328 result = EX_USAGE; 329 330 while ((optChar = getopt_long_only(argc, argv, kOptChars, 331 sOptInfo, NULL)) != -1) { 332 333 switch (optChar) { 334 335 case kOptHelp: 336 usage(kUsageLevelFull); 337 result = kKextlibsExitHelp; 338 goto finish; 339 break; 340 341 case kOptRepository: 342 scratchResult = addRepository(toolArgs, optarg); 343 if (scratchResult != EX_OK) { 344 result = scratchResult; 345 goto finish; 346 } 347 break; 348 349 case kOptCompatible: 350 toolArgs->flagCompatible = true; 351 break; 352 353 case kOptSystemExtensions: 354 toolArgs->flagSysKexts = true; 355 break; 356 357 case kOptQuiet: 358 beQuiet(); 359 break; 360 361 case kOptVerbose: 362 scratchResult = setLogFilterForOpt(argc, argv, /* forceOnFlags */ 0); 363 if (scratchResult != EX_OK) { 364 result = scratchResult; 365 goto finish; 366 } 367 break; 368 369 case 0: 370 switch (longopt) { 371 case kLongOptXML: 372 toolArgs->flagXML = true; 373 break; 374 375 case kLongOptAllSymbols: 376 toolArgs->flagPrintUndefSymbols = true; 377 toolArgs->flagPrintOnedefSymbols = true; 378 toolArgs->flagPrintMultdefSymbols = true; 379 break; 380 381 case kLongOptUndefSymbols: 382 toolArgs->flagPrintUndefSymbols = true; 383 break; 384 385 case kLongOptOnedefSymbols: 386 toolArgs->flagPrintOnedefSymbols = true; 387 break; 388 389 case kLongOptMultdefSymbols: 390 toolArgs->flagPrintMultdefSymbols = true; 391 break; 392 393 case kLongOptNonKPI: 394 toolArgs->flagNonKPI = true; 395 break; 396 397 case kLongOptUnsupported: 398 toolArgs->flagAllowUnsupported = true; 399 break; 400 401 } 402 break; 403 404 default: 405 usage(kUsageLevelBrief); 406 goto finish; 407 break; 408 } 409 } 410 411 argc -= optind; 412 argv += optind; 413 414 if (!argv[0]) { 415 fprintf(stderr, "No kext specified."); 416 usage(kUsageLevelBrief); 417 goto finish; 418 } 419 420 scratchResult = checkPath(argv[0], kOSKextBundleExtension, 421 /* directoryRequired */ TRUE, /* writableRequired */ FALSE); 422 if (scratchResult != EX_OK) { 423 result = scratchResult; 424 goto finish; 425 } 426 toolArgs->kextName = argv[0]; 427 428 argc--; 429 argv++; 430 431 if (argc) { 432 OSKextLog(/* kext */ NULL, 433 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 434 "Too many arguments starting at '%s'.", argv[0]); 435 usage(kUsageLevelBrief); 436 goto finish; 437 } 438 439 result = EX_OK; 440finish: 441 return result; 442} 443 444/******************************************************************************* 445*******************************************************************************/ 446ExitStatus addRepository( 447 KextlibsArgs * toolArgs, 448 const char * path) 449{ 450 ExitStatus result = EX_OSERR; 451 CFURLRef url = NULL; // must release 452 453 result = checkPath(path, /* suffix */ NULL, 454 /* dirRequired? */ TRUE, /* writableRequired? */ FALSE); 455 if (result != EX_OK) { 456 goto finish; 457 } 458 459 url = CFURLCreateFromFileSystemRepresentation( 460 kCFAllocatorDefault, (const UInt8 *)path, strlen(path), true); 461 if (!url) { 462 OSKextLog(/* kext */ NULL, 463 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 464 "Can't create CFURL for '%s'.", path); 465 goto finish; 466 } 467 addToArrayIfAbsent(toolArgs->repositoryURLs, url); 468 469 result = EX_OK; 470finish: 471 SAFE_RELEASE(url); 472 return result; 473} 474 475/******************************************************************************* 476* This function prints to stdout, as it represents the only real output of 477* the program and we want to be able to pipe it into pbcopy. 478*******************************************************************************/ 479ExitStatus printLibs( 480 KextlibsArgs * toolArgs, 481 const NXArchInfo * arch, 482 CFArrayRef libKexts, 483 Boolean trailingNewlineFlag) 484{ 485 ExitStatus result = EX_OSERR; 486 const NXArchInfo * genericArch = NULL; // do not free 487 char * libIdentifier = NULL; // must free 488 CFIndex count, i; 489 490 /* Get the generic architecture name for the arch, except for PPC, 491 * which we no longer support. 492 */ 493 if (arch && arch->cputype != CPU_TYPE_POWERPC) { 494 genericArch = NXGetArchInfoFromCpuType(arch->cputype, 495 CPU_SUBTYPE_MULTIPLE); 496 if (!genericArch) { 497 OSKextLog(/* kext */ NULL, 498 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 499 "Can't find generic NXArchInfo for %s.", 500 arch->name); 501 goto finish; 502 } 503 } 504 505 count = CFArrayGetCount(libKexts); 506 507 /* For XML output, don't print anything if we found no libraries; 508 * an empty OSBundleLibraries might look like good output to somebody. 509 */ 510 if (toolArgs->flagXML) { 511 if (count) { 512 fprintf(stdout, "\t<key>OSBundleLibraries%s%s</key>\n", 513 genericArch ? "_" : "", 514 genericArch ? genericArch->name : ""); 515 fprintf(stdout, "\t<dict>\n"); 516 } 517 } else { 518 if (arch) { 519 fprintf(stderr, "For %s:\n", arch->name); 520 } else { 521 fprintf(stderr, "For all architectures:\n"); 522 } 523 if (!count) { 524 fprintf(stdout, " No libraries found.\n"); 525 } 526 } 527 for (i = 0; i < count; i++) { 528 OSKextRef libKext = (OSKextRef)CFArrayGetValueAtIndex(libKexts, i); 529 OSKextVersion version; 530 char versCString[kOSKextVersionMaxLength]; 531 532 SAFE_FREE_NULL(libIdentifier); 533 534 libIdentifier = createUTF8CStringForCFString(OSKextGetIdentifier(libKext)); 535 536 if (toolArgs->flagCompatible) { 537 version = OSKextGetCompatibleVersion(libKext); 538 } else { 539 version = OSKextGetVersion(libKext); 540 } 541 542 if (libIdentifier && version > kOSKextVersionUndefined) { 543 OSKextVersionGetString(version, versCString, sizeof(versCString)); 544 545 if (toolArgs->flagXML) { 546 fprintf(stdout, "\t\t<key>%s</key>\n", libIdentifier); 547 fprintf(stdout, "\t\t<string>%s</string>\n", versCString); 548 } else { 549 fprintf(stdout, " %s = %s\n", libIdentifier, versCString); 550 } 551 } else { 552 OSKextLog(/* kext */ NULL, 553 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 554 "Internal error generating library list."); 555 goto finish; 556 } 557 } 558 if (count && toolArgs->flagXML) { 559 fprintf(stdout, "\t</dict>\n"); 560 } 561 562 if (trailingNewlineFlag) { 563 fprintf(stderr, "\n"); 564 } 565 566 result = kKextlibsExitOK; 567finish: 568 SAFE_FREE(libIdentifier); 569 return result; 570} 571 572/******************************************************************************* 573*******************************************************************************/ 574ExitStatus printProblems( 575 KextlibsArgs * toolArgs, 576 const NXArchInfo * arch, 577 CFDictionaryRef undefSymbols, 578 CFDictionaryRef onedefSymbols, 579 CFDictionaryRef multdefSymbols, 580 CFArrayRef multdefLibs, 581 Boolean printArchFlag, 582 Boolean trailingNewlineFlag) 583{ 584 ExitStatus result = EX_OSERR; 585 CFIndex undefCount, onedefCount, multdefCount; 586 CFIndex count, i; 587 588 onedefCount = CFDictionaryGetCount(onedefSymbols); 589 undefCount = CFDictionaryGetCount(undefSymbols); 590 multdefCount = CFDictionaryGetCount(multdefSymbols); 591 592 if (!toolArgs->flagPrintOnedefSymbols && !undefCount && !multdefCount) { 593 result = kKextlibsExitOK; 594 goto finish; 595 } 596 597 if (printArchFlag) { 598 fprintf(stderr, "For %s:\n", arch->name); 599 } 600 601 if (toolArgs->flagPrintOnedefSymbols) { 602 fprintf(stderr, " %ld symbol%s found in one library kext each%s\n", 603 onedefCount, 604 onedefCount > 1 ? "s" : "", 605 onedefCount && toolArgs->flagPrintOnedefSymbols ? ":" : "."); 606 CFDictionaryApplyFunction(onedefSymbols, printOnedefSymbol, 607 &(toolArgs->flagCompatible)); 608 } 609 610 if (undefCount) { 611 fprintf(stderr, " %ld symbol%s not found in any library kext%s\n", 612 undefCount, 613 undefCount > 1 ? "s" : "", 614 toolArgs->flagPrintUndefSymbols ? ":" : "."); 615 if (toolArgs->flagPrintUndefSymbols) { 616 CFDictionaryApplyFunction(undefSymbols, printUndefSymbol, NULL); 617 } 618 result = kKextlibsExitUndefineds; 619 } 620 if (multdefCount) { 621 if (toolArgs->flagPrintMultdefSymbols) { 622 fprintf(stderr, " %ld symbol%s found in more than one library kext:\n", 623 multdefCount, 624 multdefCount > 1 ? "s" : ""); 625 CFDictionaryApplyFunction(multdefSymbols, printMultdefSymbol, 626 &(toolArgs->flagCompatible)); 627 } else { 628 count = CFArrayGetCount(multdefLibs); 629 fprintf(stderr, " Multiple symbols found among %ld libraries:\n", 630 count); 631 for (i = 0; i < count; i++) { 632 OSKextRef lib = (OSKextRef)CFArrayGetValueAtIndex(multdefLibs, i); 633 char * name = NULL; // must free 634 name = createUTF8CStringForCFString(OSKextGetIdentifier(lib)); 635 if (name) { 636 fprintf(stderr, "\t%s\n", name); 637 } 638 SAFE_FREE(name); 639 } 640 } 641 result = kKextlibsExitMultiples; 642 } 643 644 if (trailingNewlineFlag) { 645 fprintf(stderr, "\n"); 646 } 647 648 if (undefCount || multdefCount) { 649 goto finish; 650 } 651 652 result = kKextlibsExitOK; 653 654finish: 655 return result; 656} 657 658/******************************************************************************* 659* 660*******************************************************************************/ 661void printUndefSymbol(const void * key, 662 const void * value __unused, void * context __unused) 663{ 664 char * cSymbol = NULL; // must free 665 666 cSymbol = createUTF8CStringForCFString((CFStringRef)key); 667 if (cSymbol) { 668 fprintf(stderr, "\t%s\n", cSymbol); 669 } 670 SAFE_FREE(cSymbol); 671 return; 672} 673 674/******************************************************************************* 675* 676*******************************************************************************/ 677void printOnedefSymbol(const void * key, const void * value, void * context) 678{ 679 Boolean flagCompatible = *(Boolean *)context; 680 OSKextRef libKext = (OSKextRef)value; 681 char * cSymbol = NULL; // must free 682 char * libVers = NULL; // must free 683 CFURLRef libKextURL; 684 char libKextName[PATH_MAX]; 685 CFStringRef libVersString = NULL; // do not release 686 687 cSymbol = createUTF8CStringForCFString((CFStringRef)key); 688 if (!cSymbol) { 689 OSKextLogStringError(/* kext */ NULL); 690 goto finish; 691 } 692 693 libKextURL = OSKextGetURL(libKext); 694 if (!CFURLGetFileSystemRepresentation(libKextURL, 695 /* resolveToBase */ false, 696 (u_char *)libKextName, PATH_MAX)) { 697 698 OSKextLogStringError(/* kext */ NULL); 699 goto finish; 700 } 701 if (flagCompatible) { 702 libVersString = OSKextGetValueForInfoDictionaryKey(libKext, 703 CFSTR("OSBundleCompatibleVersion")); 704 } else { 705 libVersString = OSKextGetValueForInfoDictionaryKey(libKext, 706 kCFBundleVersionKey); 707 } 708 709 libVers = createUTF8CStringForCFString(libVersString); 710 if (!libVers) { 711 OSKextLogStringError(/* kext */ NULL); 712 goto finish; 713 } 714 715 fprintf(stderr, " %s in %s (%s%s)\n", cSymbol, libKextName, 716 flagCompatible ? "compatible version " : "", libVers); 717 718finish: 719 SAFE_FREE(cSymbol); 720 SAFE_FREE(libVers); 721 722 return; 723} 724 725/******************************************************************************* 726* 727*******************************************************************************/ 728void printMultdefSymbol(const void * key, const void * value, void * context) 729{ 730 char * cSymbol = NULL; // must free 731 char * libVers = NULL; // must free 732 CFArrayRef libs = (CFArrayRef)value; 733 Boolean flagCompatible = *(Boolean *)context; 734 CFIndex count, i; 735 736 cSymbol = createUTF8CStringForCFString((CFStringRef)key); 737 if (cSymbol) { 738 fprintf(stderr, " %s: in\n", cSymbol); 739 } 740 741 count = CFArrayGetCount(libs); 742 for (i = 0; i < count; i++) { 743 OSKextRef libKext = (OSKextRef)CFArrayGetValueAtIndex(libs, i); 744 CFURLRef libKextURL; 745 char libKextName[PATH_MAX]; 746 CFStringRef libVersString = NULL; // do not release 747 748 SAFE_FREE_NULL(libVers); 749 750 libKextURL = OSKextGetURL(libKext); 751 if (!CFURLGetFileSystemRepresentation(libKextURL, 752 /* resolveToBase */ true, 753 (u_char *)libKextName, PATH_MAX)) { 754 755 fprintf(stderr, "string/url conversion error\n"); 756 goto finish; 757 } 758 if (flagCompatible) { 759 libVersString = OSKextGetValueForInfoDictionaryKey(libKext, 760 CFSTR("OSBundleCompatibleVersion")); 761 } else { 762 libVersString = OSKextGetValueForInfoDictionaryKey(libKext, 763 kCFBundleVersionKey); 764 } 765 766 libVers = createUTF8CStringForCFString(libVersString); 767 if (!libVers) { 768 fprintf(stderr, "string/url conversion error\n"); 769 goto finish; 770 } 771 fprintf(stderr, " %s (%s%s)\n", libKextName, 772 flagCompatible ? "compatible version " : "", libVers); 773 } 774 775finish: 776 SAFE_FREE(cSymbol); 777 SAFE_FREE(libVers); 778 779 return; 780} 781 782/******************************************************************************* 783* usage() 784*******************************************************************************/ 785static void usage(UsageLevel usageLevel) 786{ 787 fprintf(stderr, "usage: %s [options] kext\n", progname); 788 789 if (usageLevel == kUsageLevelBrief) { 790 fprintf(stderr, "\nuse %s -%s for a list of options\n", 791 progname, kOptNameHelp); 792 return; 793 } 794 795 fprintf(stderr, "\n"); 796 797 // extra newline for spacing 798 fprintf(stderr, "<kext>: the kext to find libraries for\n"); 799 800 fprintf(stderr, "-%s <arch>:\n", kOptNameArch); 801 fprintf(stderr, " resolve for architecture <arch> instead of running kernel's\n"); 802 fprintf(stderr, "-%s: print XML fragment suitable for pasting\n", kOptNameXML); 803 804 // fake out compiler for blank line 805 fprintf(stderr, "\n"); 806 807 fprintf(stderr, "-%s (-%c):\n", 808 kOptNameSystemExtensions, kOptSystemExtensions); 809 fprintf(stderr, " look in the system exensions folder (assumed if no other folders\n" 810 " specified with %s)\n",kOptNameRepository); 811 fprintf(stderr, "-%s <directory> (-%c):\n", kOptNameRepository, kOptRepository); 812 fprintf(stderr, " look in <directory> for library kexts\n"); 813 814 fprintf(stderr, "%s", "\n"); 815 816 fprintf(stderr, "-%s:\n", kOptNameAllSymbols); 817 fprintf(stderr, " list all symbols, found, not found, or found more than once\n"); 818 fprintf(stderr, "-%s:\n", kOptNameOnedefSymbols); 819 fprintf(stderr, " list all symbols found with the library kext they were found in\n"); 820 fprintf(stderr, "-%s:\n", kOptNameUndefSymbols); 821 fprintf(stderr, " list all symbols not found in any library\n"); 822 fprintf(stderr, "-%s:\n", kOptNameMultdefSymbols); 823 fprintf(stderr, " list all symbols found more than once with their library kexts\n"); 824 825 fprintf(stderr, "%s", "\n"); 826 827 fprintf(stderr, "-%s (-%c):\n", kOptNameCompatible, kOptCompatible); 828 fprintf(stderr, " use library kext compatble versions rather than current versions\n"); 829 fprintf(stderr, "-%s:\n", kOptNameUnsupported); 830 fprintf(stderr, " look in unsupported kexts for symbols\n"); 831 return; 832} 833