Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/boot2/drivers.c

Source at commit 569 created 13 years 6 months ago.
By meklort, NBI postboot installer + recovery mode module (as usual, untested)
1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 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 2.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/*
25 * drivers.c - Driver Loading Functions.
26 *
27 * Copyright (c) 2000 Apple Computer, Inc.
28 *
29 * DRI: Josh de Cesare
30 */
31
32#include <mach-o/fat.h>
33#include <libkern/OSByteOrder.h>
34#include <mach/machine.h>
35
36#include "sl.h"
37#include "boot.h"
38#include "bootstruct.h"
39#include "xml.h"
40#include "ramdisk.h"
41#include "drivers.h"
42#include "modules.h"
43
44extern char gMacOSVersion;
45
46#ifndef OPTION_ROM
47long (*LoadExtraDrivers_p)(FileLoadDrivers_t FileLoadDrivers_p);
48#endif
49
50static unsigned long Alder32( unsigned char * buffer, long length );
51
52long FileLoadDrivers(char *dirSpec, long plugin);
53#ifndef OPTION_ROM
54long NetLoadDrivers(char *dirSpec);
55#endif
56long LoadDriverMKext(char *fileSpec);
57long LoadDriverPList(char *dirSpec, char *name, long bundleType);
58long LoadMatchedModules(void);
59long MatchPersonalities(void);
60long MatchLibraries(void);
61#ifdef NOTDEF
62static ModulePtr FindModule(char *name);
63static void ThinFatFile(void **loadAddrP, unsigned long *lengthP);
64#endif
65static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities);
66long InitDriverSupport(void);
67
68static ModulePtr gModuleHead, gModuleTail;
69static TagPtr gPersonalityHead, gPersonalityTail;
70char * gExtensionsSpec;
71char * gDriverSpec;
72char * gFileSpec;
73char * gTempSpec;
74char * gFileName;
75
76static unsigned long
77Alder32( unsigned char * buffer, long length )
78{
79 long cnt;
80 unsigned long result, lowHalf, highHalf;
81
82 lowHalf = 1;
83 highHalf = 0;
84
85for ( cnt = 0; cnt < length; cnt++ )
86 {
87 if ((cnt % 5000) == 0)
88 {
89 lowHalf %= 65521L;
90 highHalf %= 65521L;
91 }
92
93 lowHalf += buffer[cnt];
94 highHalf += lowHalf;
95 }
96
97lowHalf %= 65521L;
98highHalf %= 65521L;
99
100result = (highHalf << 16) | lowHalf;
101
102return result;
103}
104
105
106//==========================================================================
107// InitDriverSupport
108
109long
110InitDriverSupport( void )
111{
112 gExtensionsSpec = malloc( 4096 );
113 gDriverSpec = malloc( 4096 );
114 gFileSpec = malloc( 4096 );
115 gTempSpec = malloc( 4096 );
116 gFileName = malloc( 4096 );
117
118 if ( !gExtensionsSpec || !gDriverSpec || !gFileSpec || !gTempSpec || !gFileName )
119 stop("InitDriverSupport error");
120
121 return 0;
122}
123
124//==========================================================================
125// LoadDrivers
126
127long LoadDrivers( char * dirSpec )
128{
129 char dirSpecExtra[1024];
130
131 if ( InitDriverSupport() != 0 )
132 return 0;
133
134#ifndef OPTION_ROM
135 // Load extra drivers if a hook has been installed.
136 if (LoadExtraDrivers_p != NULL)
137 {
138 (*LoadExtraDrivers_p)(&FileLoadDrivers);
139 }
140
141 if ( gBootFileType == kNetworkDeviceType )
142 {
143 if (NetLoadDrivers(dirSpec) != 0) {
144 error("Could not load drivers from the network\n");
145 return -1;
146 }
147 }
148 else
149#endif
150if ( gBootFileType == kBlockDeviceType )
151{
152// First try to load Extra extensions from the ramdisk if isn't aliased as bt(0,0).
153#ifndef OPTION_ROM
154if (gRAMDiskVolume && !gRAMDiskBTAliased)
155{
156strcpy(dirSpecExtra, "rd(0,0)/Extra/");
157FileLoadDrivers(dirSpecExtra, 0);
158}
159#endif
160// Next try to load Extra extensions from the selected root partition.
161strcpy(dirSpecExtra, "/Extra/");
162if (FileLoadDrivers(dirSpecExtra, 0) != 0)
163{
164// If failed, then try to load Extra extensions from the boot partition
165// in case we have a separate booter partition or a bt(0,0) aliased ramdisk.
166if ( !(gBIOSBootVolume->biosdev == gBootVolume->biosdev && gBIOSBootVolume->part_no == gBootVolume->part_no)
167#ifndef OPTION_ROM
168|| (gRAMDiskVolume && gRAMDiskBTAliased) )
169#else
170)
171#endif
172{
173// First try a specfic OS version folder ie 10.5
174sprintf(dirSpecExtra, "bt(0,0)/Extra/%s/", &gMacOSVersion);
175if (FileLoadDrivers(dirSpecExtra, 0) != 0)
176{
177// Next we'll try the base
178strcpy(dirSpecExtra, "bt(0,0)/Extra/");
179FileLoadDrivers(dirSpecExtra, 0);
180}
181}
182}
183
184// TODO: fix this, the order does matter, and it's not correct now.
185// Also try to load Extensions from boot helper partitions.
186if (gBootVolume->flags & kBVFlagBooter)
187{
188strcpy(dirSpecExtra, "/com.apple.boot.P/System/Library/");
189if (FileLoadDrivers(dirSpecExtra, 0) != 0)
190{
191strcpy(dirSpecExtra, "/com.apple.boot.R/System/Library/");
192if (FileLoadDrivers(dirSpecExtra, 0) != 0)
193{
194strcpy(dirSpecExtra, "/com.apple.boot.S/System/Library/");
195FileLoadDrivers(dirSpecExtra, 0);
196}
197}
198}
199
200if (gMKextName[0] != '\0')
201{
202verbose("LoadDrivers: Loading from [%s]\n", gMKextName);
203if ( LoadDriverMKext(gMKextName) != 0 )
204{
205error("Could not load %s\n", gMKextName);
206return -1;
207}
208}
209else
210{
211strcpy(gExtensionsSpec, dirSpec);
212strcat(gExtensionsSpec, "System/Library/");
213FileLoadDrivers(gExtensionsSpec, 0);
214}
215}
216else
217{
218return 0;
219}
220
221 MatchPersonalities();
222
223 MatchLibraries();
224
225 LoadMatchedModules();
226
227 return 0;
228}
229
230//==========================================================================
231// FileLoadMKext
232
233static long
234FileLoadMKext( const char * dirSpec, const char * extDirSpec )
235{
236long ret, flags, time, time2;
237char altDirSpec[512];
238
239sprintf (altDirSpec, "%s%s", dirSpec, extDirSpec);
240ret = GetFileInfo(altDirSpec, "Extensions.mkext", &flags, &time);
241if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
242{
243ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2);
244if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeDirectory) ||
245(((gBootMode & kBootModeSafe) == 0) && (time == (time2 + 1))))
246{
247sprintf(gDriverSpec, "%sExtensions.mkext", altDirSpec);
248verbose("LoadDrivers: Loading from [%s]\n", gDriverSpec);
249if (LoadDriverMKext(gDriverSpec) == 0) return 0;
250}
251}
252return -1;
253}
254
255//==========================================================================
256// FileLoadDrivers
257
258long
259FileLoadDrivers( char * dirSpec, long plugin )
260{
261 long ret, length, flags, time, bundleType;
262 long long index;
263 long result = -1;
264 const char * name;
265
266 if ( !plugin )
267 {
268 // First try 10.6's path for loading Extensions.mkext.
269 if (FileLoadMKext(dirSpec, "Caches/com.apple.kext.caches/Startup/") == 0)
270return 0;
271
272 // Next try the legacy path.
273 else if (FileLoadMKext(dirSpec, "") == 0)
274return 0;
275
276 strcat(dirSpec, "Extensions");
277 }
278
279 index = 0;
280 while (1) {
281 ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
282 if (ret == -1) break;
283
284 // Make sure this is a directory.
285 if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
286
287 // Make sure this is a kext.
288 length = strlen(name);
289 if (strcmp(name + length - 5, ".kext")) continue;
290
291 // Save the file name.
292 strcpy(gFileName, name);
293
294 // Determine the bundle type.
295 sprintf(gTempSpec, "%s/%s", dirSpec, gFileName);
296 ret = GetFileInfo(gTempSpec, "Contents", &flags, &time);
297 if (ret == 0) bundleType = kCFBundleType2;
298 else bundleType = kCFBundleType3;
299
300 if (!plugin)
301 sprintf(gDriverSpec, "%s/%s/%sPlugIns", dirSpec, gFileName,
302 (bundleType == kCFBundleType2) ? "Contents/" : "");
303
304 ret = LoadDriverPList(dirSpec, gFileName, bundleType);
305
306 if (result != 0)
307result = ret;
308
309 if (!plugin)
310FileLoadDrivers(gDriverSpec, 1);
311 }
312
313 return result;
314}
315
316//==========================================================================
317//
318#ifndef OPTION_ROM
319long
320NetLoadDrivers( char * dirSpec )
321{
322 long tries;
323
324#if NODEF
325 long cnt;
326
327 // Get the name of the kernel
328 cnt = strlen(gBootFile);
329 while (cnt--) {
330 if ((gBootFile[cnt] == '\\') || (gBootFile[cnt] == ',')) {
331cnt++;
332break;
333 }
334 }
335#endif
336
337 // INTEL modification
338 sprintf(gDriverSpec, "%s%s.mkext", dirSpec, bootInfo->bootFile);
339
340 verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec);
341
342 tries = 3;
343 while (tries--)
344 {
345 if (LoadDriverMKext(gDriverSpec) == 0) break;
346 }
347 if (tries == -1) return -1;
348
349 return 0;
350}
351#endif
352//==========================================================================
353// loadDriverMKext
354
355long
356LoadDriverMKext( char * fileSpec )
357{
358 unsigned long driversAddr, driversLength;
359 long length;
360 char segName[32];
361 DriversPackage * package;
362
363#define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
364
365 // Load the MKext.
366 length = LoadThinFatFile(fileSpec, (void **)&package);
367 if (length < sizeof (DriversPackage)) return -1;
368
369// call hook to notify modules that the mkext has been loaded
370execute_hook("LoadDriverMKext", (void*)fileSpec, (void*)package, (void*) length, NULL);
371
372
373 // Verify the MKext.
374 if (( GetPackageElement(signature1) != kDriverPackageSignature1) ||
375 ( GetPackageElement(signature2) != kDriverPackageSignature2) ||
376 ( GetPackageElement(length) > kLoadSize ) ||
377 ( GetPackageElement(alder32) !=
378 Alder32((unsigned char *)&package->version, GetPackageElement(length) - 0x10) ) )
379 {
380 return -1;
381 }
382
383
384 // Make space for the MKext.
385 driversLength = GetPackageElement(length);
386 driversAddr = AllocateKernelMemory(driversLength);
387
388 // Copy the MKext.
389 memcpy((void *)driversAddr, (void *)package, driversLength);
390
391 // Add the MKext to the memory map.
392 sprintf(segName, "DriversPackage-%lx", driversAddr);
393 AllocateMemoryRange(segName, driversAddr, driversLength,
394 kBootDriverTypeMKEXT);
395
396 return 0;
397}
398
399//==========================================================================
400// LoadDriverPList
401
402long
403LoadDriverPList( char * dirSpec, char * name, long bundleType )
404{
405 long length, executablePathLength, bundlePathLength;
406 ModulePtr module;
407 TagPtr personalities;
408 char * buffer = 0;
409 char * tmpExecutablePath = 0;
410 char * tmpBundlePath = 0;
411 long ret = -1;
412
413 do {
414 // Save the driver path.
415
416 sprintf(gFileSpec, "%s/%s/%s", dirSpec, name,
417 (bundleType == kCFBundleType2) ? "Contents/MacOS/" : "");
418 executablePathLength = strlen(gFileSpec) + 1;
419
420 tmpExecutablePath = malloc(executablePathLength);
421 if (tmpExecutablePath == 0) break;
422
423 strcpy(tmpExecutablePath, gFileSpec);
424
425 sprintf(gFileSpec, "%s/%s", dirSpec, name);
426 bundlePathLength = strlen(gFileSpec) + 1;
427
428 tmpBundlePath = malloc(bundlePathLength);
429 if (tmpBundlePath == 0) break;
430
431 strcpy(tmpBundlePath, gFileSpec);
432
433 // Construct the file spec to the plist, then load it.
434
435 sprintf(gFileSpec, "%s/%s/%sInfo.plist", dirSpec, name,
436 (bundleType == kCFBundleType2) ? "Contents/" : "");
437
438 length = LoadFile(gFileSpec);
439 if (length == -1) break;
440
441 length = length + 1;
442 buffer = malloc(length);
443 if (buffer == 0) break;
444
445 strlcpy(buffer, (char *)kLoadAddr, length);
446
447 // Parse the plist.
448
449 ret = ParseXML(buffer, &module, &personalities);
450 if (ret != 0) { break; }
451
452 // Allocate memory for the driver path and the plist.
453
454 module->executablePath = tmpExecutablePath;
455 module->bundlePath = tmpBundlePath;
456 module->bundlePathLength = bundlePathLength;
457 module->plistAddr = malloc(length);
458
459 if ((module->executablePath == 0) || (module->bundlePath == 0) || (module->plistAddr == 0))
460 break;
461
462 // Save the driver path in the module.
463 //strcpy(module->driverPath, tmpDriverPath);
464 tmpExecutablePath = 0;
465 tmpBundlePath = 0;
466
467 // Add the plist to the module.
468
469 strlcpy(module->plistAddr, (char *)kLoadAddr, length);
470 module->plistLength = length;
471
472 // Add the module to the end of the module list.
473
474 if (gModuleHead == 0)
475 gModuleHead = module;
476 else
477 gModuleTail->nextModule = module;
478 gModuleTail = module;
479
480 // Add the persionalities to the personality list.
481
482 if (personalities) personalities = personalities->tag;
483 while (personalities != 0)
484 {
485 if (gPersonalityHead == 0)
486 gPersonalityHead = personalities->tag;
487 else
488 gPersonalityTail->tagNext = personalities->tag;
489
490 gPersonalityTail = personalities->tag;
491 personalities = personalities->tagNext;
492 }
493
494 ret = 0;
495 }
496 while (0);
497
498 if ( buffer ) free( buffer );
499 if ( tmpExecutablePath ) free( tmpExecutablePath );
500 if ( tmpBundlePath ) free( tmpBundlePath );
501
502 return ret;
503}
504
505
506//==========================================================================
507// LoadMatchedModules
508
509long LoadMatchedModules( void )
510{
511 TagPtr prop;
512 ModulePtr module;
513 char *fileName, segName[32];
514 DriverInfoPtr driver;
515 long length, driverAddr, driverLength;
516 void *executableAddr = 0;
517
518
519 module = gModuleHead;
520
521 while (module != 0)
522 {
523 if (module->willLoad)
524 {
525 prop = XMLGetProperty(module->dict, kPropCFBundleExecutable);
526
527 if (prop != 0)
528 {
529 fileName = prop->string;
530 sprintf(gFileSpec, "%s%s", module->executablePath, fileName);
531 length = LoadThinFatFile(gFileSpec, &executableAddr);
532if (length == 0)
533{
534length = LoadFile(gFileSpec);
535executableAddr = (void *)kLoadAddr;
536}
537 //printf("%s length = %d addr = 0x%x\n", gFileSpec, length, driverModuleAddr); getc();
538 }
539 else
540 length = 0;
541
542 if (length != -1)
543 {
544//driverModuleAddr = (void *)kLoadAddr;
545 //if (length != 0)
546 //{
547// ThinFatFile(&driverModuleAddr, &length);
548//}
549
550 // Make make in the image area.
551
552execute_hook("LoadMatchedModules", module, &length, executableAddr, NULL);
553
554 driverLength = sizeof(DriverInfo) + module->plistLength + length + module->bundlePathLength;
555 driverAddr = AllocateKernelMemory(driverLength);
556
557 // Set up the DriverInfo.
558 driver = (DriverInfoPtr)driverAddr;
559 driver->plistAddr = (char *)(driverAddr + sizeof(DriverInfo));
560 driver->plistLength = module->plistLength;
561 if (length != 0)
562 {
563 driver->executableAddr = (void *)(driverAddr + sizeof(DriverInfo) +
564 module->plistLength);
565 driver->executableLength = length;
566 }
567 else
568 {
569 driver->executableAddr = 0;
570 driver->executableLength = 0;
571 }
572 driver->bundlePathAddr = (void *)(driverAddr + sizeof(DriverInfo) +
573 module->plistLength + driver->executableLength);
574 driver->bundlePathLength = module->bundlePathLength;
575
576 // Save the plist, module and bundle.
577 strcpy(driver->plistAddr, module->plistAddr);
578 if (length != 0)
579 {
580 memcpy(driver->executableAddr, executableAddr, length);
581 }
582 strcpy(driver->bundlePathAddr, module->bundlePath);
583
584 // Add an entry to the memory map.
585 sprintf(segName, "Driver-%lx", (unsigned long)driver);
586 AllocateMemoryRange(segName, driverAddr, driverLength,
587 kBootDriverTypeKEXT);
588 }
589 }
590 module = module->nextModule;
591 }
592
593 return 0;
594}
595
596//==========================================================================
597// MatchPersonalities
598
599long MatchPersonalities( void )
600{
601 /* IONameMatch support not implemented */
602 return 0;
603}
604
605//==========================================================================
606// MatchLibraries
607
608long MatchLibraries( void )
609{
610 TagPtr prop, prop2;
611 ModulePtr module, module2;
612 long done;
613
614 do {
615 done = 1;
616 module = gModuleHead;
617
618 while (module != 0)
619 {
620 if (module->willLoad == 1)
621 {
622 prop = XMLGetProperty(module->dict, kPropOSBundleLibraries);
623 if (prop != 0)
624 {
625 prop = prop->tag;
626 while (prop != 0)
627 {
628 module2 = gModuleHead;
629 while (module2 != 0)
630 {
631 prop2 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
632 if ((prop2 != 0) && (!strcmp(prop->string, prop2->string)))
633 {
634 if (module2->willLoad == 0) module2->willLoad = 1;
635 break;
636 }
637 module2 = module2->nextModule;
638 }
639 prop = prop->tagNext;
640 }
641 }
642 module->willLoad = 2;
643 done = 0;
644 }
645 module = module->nextModule;
646 }
647 }
648 while (!done);
649
650 return 0;
651}
652
653
654//==========================================================================
655// FindModule
656
657#if NOTDEF
658static ModulePtr
659FindModule( char * name )
660{
661 ModulePtr module;
662 TagPtr prop;
663
664 module = gModuleHead;
665
666 while (module != 0)
667 {
668 prop = GetProperty(module->dict, kPropCFBundleIdentifier);
669 if ((prop != 0) && !strcmp(name, prop->string)) break;
670 module = module->nextModule;
671 }
672
673 return module;
674}
675#endif /* NOTDEF */
676
677//==========================================================================
678// ParseXML
679
680static long
681ParseXML( char * buffer, ModulePtr * module, TagPtr * personalities )
682{
683long length, pos;
684TagPtr moduleDict, required;
685ModulePtr tmpModule;
686
687 pos = 0;
688
689 while (1)
690 {
691 length = XMLParseNextTag(buffer + pos, &moduleDict);
692 if (length == -1) break;
693
694 pos += length;
695
696 if (moduleDict == 0) continue;
697 if (moduleDict->type == kTagTypeDict) break;
698
699 XMLFreeTag(moduleDict);
700 }
701
702 if (length == -1) return -1;
703
704 required = XMLGetProperty(moduleDict, kPropOSBundleRequired);
705 if ( (required == 0) ||
706(required->type != kTagTypeString) ||
707!strcmp(required->string, "Safe Boot"))
708 {
709 XMLFreeTag(moduleDict);
710 return -2;
711 }
712
713 tmpModule = malloc(sizeof(Module));
714 if (tmpModule == 0)
715 {
716 XMLFreeTag(moduleDict);
717 return -1;
718 }
719 tmpModule->dict = moduleDict;
720
721 // For now, load any module that has OSBundleRequired != "Safe Boot".
722
723 tmpModule->willLoad = 1;
724
725 *module = tmpModule;
726
727 // Get the personalities.
728
729 *personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);
730
731 return 0;
732}
733
734#if NOTDEF
735static char gPlatformName[64];
736#endif
737
738long
739DecodeKernel(void *binary, entry_t *rentry, char **raddr, int *rsize)
740{
741 long ret;
742 compressed_kernel_header * kernel_header = (compressed_kernel_header *) binary;
743 u_int32_t uncompressed_size, size;
744 void *buffer;
745unsigned long len;
746
747#if 0
748 printf("kernel header:\n");
749 printf("signature: 0x%x\n", kernel_header->signature);
750 printf("compress_type: 0x%x\n", kernel_header->compress_type);
751 printf("adler32: 0x%x\n", kernel_header->adler32);
752 printf("uncompressed_size: 0x%x\n", kernel_header->uncompressed_size);
753 printf("compressed_size: 0x%x\n", kernel_header->compressed_size);
754 getc();
755#endif
756
757 if (kernel_header->signature == OSSwapBigToHostConstInt32('comp')) {
758 if (kernel_header->compress_type != OSSwapBigToHostConstInt32('lzss')) {
759 error("kernel compression is bad\n");
760 return -1;
761 }
762#if NOTDEF
763 if (kernel_header->platform_name[0] && strcmp(gPlatformName, kernel_header->platform_name))
764 return -1;
765 if (kernel_header->root_path[0] && strcmp(gBootFile, kernel_header->root_path))
766 return -1;
767#endif
768
769 uncompressed_size = OSSwapBigToHostInt32(kernel_header->uncompressed_size);
770 binary = buffer = malloc(uncompressed_size);
771
772 size = decompress_lzss((u_int8_t *) binary, &kernel_header->data[0],
773 OSSwapBigToHostInt32(kernel_header->compressed_size));
774 if (uncompressed_size != size) {
775 error("size mismatch from lzss: %x\n", size);
776 return -1;
777 }
778 if (OSSwapBigToHostInt32(kernel_header->adler32) !=
779 Alder32(binary, uncompressed_size)) {
780 printf("adler mismatch\n");
781 return -1;
782 }
783 }
784
785ret = ThinFatFile(&binary, &len);
786if (ret == 0 && len == 0 && archCpuType==CPU_TYPE_X86_64)
787{
788archCpuType=CPU_TYPE_I386;
789ret = ThinFatFile(&binary, &len);
790}
791
792//patch_kernel(binary);
793
794ret = DecodeMachO(binary, rentry, raddr, rsize);
795
796if (ret<0 && archCpuType==CPU_TYPE_X86_64)
797{
798archCpuType=CPU_TYPE_I386;
799ret = DecodeMachO(binary, rentry, raddr, rsize);
800}
801
802
803return ret;
804}
805

Archive Download this file

Revision: 569