2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 Written by: Jeffrey Robbin
25 Copyright: © 1994, 1996 by Apple Computer, Inc., all rights reserved.
27 File: GetSymbolFromPEF.c
28 Written by: Jeffrey Robbin
29 Copyright: © 1994, 1996 by Apple Computer, Inc., all rights reserved.
32 #include <IOKit/IOKitLib.h>
33 #include <IOKit/kext/KEXTManager.h>
40 #include <sys/param.h>
42 #include <sys/errno.h>
45 #include <mach/mach.h>
46 #include <mach/mach_error.h>
47 #include <mach/mach_host.h>
49 #include "GetSymbolFromPEF.h"
52 PEFGetNextByte (unsigned char** rawBuffer
, long* rawBufferRemaining
)
54 *rawBufferRemaining
= *rawBufferRemaining
- 1;
55 return *(*rawBuffer
)++;
60 PEFGetCount(unsigned char** rawBuffer
, long* rawBufferRemaining
)
62 register unsigned char b
;
63 register unsigned long value
= 0UL;
65 /* Scan the count value. All required bytes MUST be present... */
67 b
= PEFGetNextByte(rawBuffer
, rawBufferRemaining
);
68 if (!IS_LAST_PICNT_BYTE(b
)) { /* if 1st byte is not that last... */
69 value
= CONCAT_PICNT(value
, b
); /* ...init value using 1st byte */
71 b
= PEFGetNextByte(rawBuffer
, rawBufferRemaining
);
72 if (!IS_LAST_PICNT_BYTE(b
)) { /* if 2nd byte is not the last... */
73 value
= CONCAT_PICNT(value
, b
); /* ...add in 2nd byte */
75 b
= PEFGetNextByte(rawBuffer
, rawBufferRemaining
);
76 if (!IS_LAST_PICNT_BYTE(b
)) { /* if 3rd byte is not the last... */
77 value
= CONCAT_PICNT(value
, b
); /* ...add in 3rd byte */
79 b
= PEFGetNextByte(rawBuffer
, rawBufferRemaining
);
80 if (!IS_LAST_PICNT_BYTE(b
)) { /* if 4th byte is not the last... */
81 value
= CONCAT_PICNT(value
, b
); /* ...add in 4th byte */
83 /* 5th byte is definitly last! */
84 b
= PEFGetNextByte(rawBuffer
, rawBufferRemaining
);
90 value
= CONCAT_PICNT(value
, b
); /* add in "last" byte (whichever one) */
97 // UnpackPiData expands a compressed section into memory.
100 UnpackPiData (LogicalAddress thePEFPtr
,
101 SectionHeaderPtr sectionHeaderPtr
,
102 LogicalAddress
* theData
)
104 long cntX
, cnt
, rpt
, dcnt
, delta
;
106 unsigned char* unpackBuffer
;
107 unsigned char* originalUnpackBuffer
;
108 unsigned char* endUnpackBuffer
;
109 unsigned char* oldRawBuffer
;
110 long oldRawBufferRemaining
;
111 unsigned char* rawBuffer
;
112 long rawBufferRemaining
;
114 // Verify incoming section is packed.
115 if (sectionHeaderPtr
->regionKind
!= kPIDataSection
)
119 // Allocate memory to unpack into
120 originalUnpackBuffer
= (unsigned char*)NewPtrSys(sectionHeaderPtr
->initSize
);
121 if (originalUnpackBuffer
== nil
)
124 unpackBuffer
= originalUnpackBuffer
;
125 endUnpackBuffer
= unpackBuffer
+ sectionHeaderPtr
->initSize
;
126 rawBuffer
= (unsigned char*)((unsigned long)thePEFPtr
+ sectionHeaderPtr
->containerOffset
);
127 rawBufferRemaining
= sectionHeaderPtr
->rawSize
;
130 /* Expand the pidata instructions. EOF will terminate processing through the setjmp */
131 /* on pidData_jmpbuf above... */
133 while (rawBufferRemaining
> 0) {
135 /* The first byte of each instruction contains the opcode and a count. If the count */
136 /* is 0, the count starts in the next byte... */
138 /* Pick up the opcode and first count operand... */
140 b
= PEFGetNextByte(&rawBuffer
, &rawBufferRemaining
);
146 cnt
= PEFGetCount(&rawBuffer
, &rawBufferRemaining
);
148 /* Unpack the data as a function of the opcode... */
151 case kZero
: /* zero out cnt bytes...*/
152 if (unpackBuffer
+ cnt
> endUnpackBuffer
)
154 memset(unpackBuffer
, 0, cnt
);
158 case kBlock
: /* copy cnt bytes...*/
159 if (unpackBuffer
+ cnt
> endUnpackBuffer
)
162 *unpackBuffer
++ = PEFGetNextByte(&rawBuffer
, &rawBufferRemaining
);
165 case kRepeat
: /* copy cnt bytes rpt times...*/
166 rpt
= PEFGetCount(&rawBuffer
, &rawBufferRemaining
) + 1;
170 if (unpackBuffer
+ rpt
> endUnpackBuffer
)
172 b
= PEFGetNextByte(&rawBuffer
, &rawBufferRemaining
);
173 memset(unpackBuffer
, b
, rpt
);
178 oldRawBufferRemaining
= rawBufferRemaining
;
179 oldRawBuffer
= rawBuffer
;
181 if (unpackBuffer
+ cnt
> endUnpackBuffer
)
183 rawBufferRemaining
= oldRawBufferRemaining
;
184 rawBuffer
= oldRawBuffer
;
187 *unpackBuffer
++ = PEFGetNextByte(&rawBuffer
, &rawBufferRemaining
);
192 case kRepeatZero
: /* copy cnt 0's and dcnt bytes rpt times*/
193 dcnt
= PEFGetCount(&rawBuffer
, &rawBufferRemaining
); /* ...then copy cnt more 0's */
194 rpt
= PEFGetCount(&rawBuffer
, &rawBufferRemaining
);
196 goto rptPart1
; /* jump into loop to copy 0's first... */
199 if (unpackBuffer
+ dcnt
> endUnpackBuffer
)
201 cntX
= dcnt
; /* cnt repeating parts follow each other*/
203 *unpackBuffer
++ = PEFGetNextByte(&rawBuffer
, &rawBufferRemaining
);
204 rptPart1
: /* non-repeating part is always 0's... */
205 if (unpackBuffer
+ cnt
> endUnpackBuffer
)
207 memset(unpackBuffer
, 0, cnt
);
213 case kRepeatBlock
: /* copy cnt repeating bytes and dcnt */
214 dcnt
= PEFGetCount(&rawBuffer
, &rawBufferRemaining
); /* non-repating bytes rcnt times... */
215 rpt
= PEFGetCount(&rawBuffer
, &rawBufferRemaining
); /* ...then copy cnt repeating bytes */
217 oldRawBufferRemaining
= rawBufferRemaining
;
218 oldRawBuffer
= rawBuffer
;
219 delta
= 0; /* the repeating part and each non-rep */
221 goto rptPart2
; /* jump into loop to copy rptng part 1st*/
224 if (unpackBuffer
+ dcnt
> endUnpackBuffer
)
227 rawBuffer
= oldRawBuffer
+ cnt
+ delta
;
228 rawBufferRemaining
= oldRawBufferRemaining
- (cnt
+ delta
);
231 *unpackBuffer
++ = PEFGetNextByte(&rawBuffer
, &rawBufferRemaining
);
234 if (unpackBuffer
+ cnt
> endUnpackBuffer
)
236 rawBuffer
= oldRawBuffer
;
237 rawBufferRemaining
= oldRawBufferRemaining
;
240 *unpackBuffer
++ = PEFGetNextByte(&rawBuffer
, &rawBufferRemaining
);
243 rawBuffer
= oldRawBuffer
+ cnt
+ delta
;
244 rawBufferRemaining
= oldRawBufferRemaining
- (cnt
+ delta
);
252 *theData
= originalUnpackBuffer
;
258 DisposePtr((Ptr
)originalUnpackBuffer
);
265 // GetSymbolFromPEF will extract from a PEF container the data associated
266 // with a given symbol name. It requires that the PEF file have been previously
267 // loaded into memory.
270 GetSymbolFromPEF( StringPtr theSymbolName
,
271 const LogicalAddress thePEFPtr
,
272 LogicalAddress theSymbolPtr
,
273 ByteCount theSymbolSize
)
275 ContainerHeaderPtr containerHeaderPtr
; // Pointer to the Container Header
276 SectionHeaderPtr loaderSectionPtr
; // Pointer to the Loader Section Header
277 SectionHeaderPtr exportSectionPtr
; // Pointer to the Section Header with the symbol
278 short currentSection
;
279 Boolean foundSection
;
281 long numExportSymbols
;
282 LoaderHeaderPtr loaderHeaderPtr
;
283 ExportSymbolEntryPtr exportSymbolEntryPtr
;
284 LoaderExportChainEntryPtr exportChainEntryPtr
;
285 StringPtr exportSymbolName
;
286 LogicalAddress expandedDataPtr
;
287 unsigned char* sourceDataPtr
;
288 unsigned char* destDataPtr
;
291 containerHeaderPtr
= (ContainerHeaderPtr
)thePEFPtr
;
293 // Does the magic cookie match?
294 if (containerHeaderPtr
->magicCookie
!= 'Joy!')
295 return cfragFragmentFormatErr
;
297 // Is this a known PEF container format?
298 if (containerHeaderPtr
->containerID
!= 'peff')
299 return cfragFragmentFormatErr
;
301 // Validate parameters
302 if (theSymbolPtr
== nil
)
306 // Find the loader section.
307 foundSection
= false;
308 for (currentSection
= 0; currentSection
< containerHeaderPtr
->nbrOfSections
; currentSection
++)
310 loaderSectionPtr
= (SectionHeaderPtr
)( (unsigned long)containerHeaderPtr
+
311 sizeof(ContainerHeader
) +
312 (sizeof(SectionHeader
) * currentSection
));
313 if (loaderSectionPtr
->regionKind
== kLoaderSection
)
320 if (foundSection
== false)
321 return cfragNoSectionErr
;
323 // Get the number of export symbols.
324 loaderHeaderPtr
= (LoaderHeaderPtr
)((unsigned long)thePEFPtr
+ loaderSectionPtr
->containerOffset
);
325 numExportSymbols
= loaderHeaderPtr
->nbrExportSyms
;
327 // Start at the first exported symbol.
328 exportSymbolEntryPtr
= (ExportSymbolEntryPtr
)( (unsigned long)loaderHeaderPtr
+
329 loaderHeaderPtr
->slotTblOffset
+
330 (sizeof(LoaderHashSlotEntry
) * (1<<loaderHeaderPtr
->hashSlotTblSz
)) +
331 (sizeof(LoaderExportChainEntry
) * numExportSymbols
));
333 exportChainEntryPtr
= (LoaderExportChainEntryPtr
)( (unsigned long)loaderHeaderPtr
+
334 loaderHeaderPtr
->slotTblOffset
+
335 (sizeof(LoaderHashSlotEntry
) * (1<<loaderHeaderPtr
->hashSlotTblSz
)));
338 while (numExportSymbols
-- > 0)
340 exportSymbolName
= (StringPtr
)( (unsigned long)loaderHeaderPtr
+
341 loaderHeaderPtr
->strTblOffset
+
342 (exportSymbolEntryPtr
->class_and_name
& 0x00FFFFFF));
343 if (SymbolCompare(theSymbolName
, exportSymbolName
, exportChainEntryPtr
->_h
._h_h
._nameLength
))
348 exportSymbolEntryPtr
= (ExportSymbolEntryPtr
)(((int)exportSymbolEntryPtr
) + 10);
349 exportChainEntryPtr
++;
352 if (foundSymbol
== false)
353 return cfragNoSymbolErr
;
356 // Found the symbol, so... let's go get the data!
358 exportSectionPtr
= (SectionHeaderPtr
)( (unsigned long)containerHeaderPtr
+
359 sizeof(ContainerHeader
) +
360 (sizeof(SectionHeader
) * exportSymbolEntryPtr
->sectionNumber
));
362 expandedDataPtr
= nil
;
364 switch (exportSectionPtr
-> regionKind
)
368 // Expand the data! (Not yet... :)
370 if (UnpackPiData (thePEFPtr
, exportSectionPtr
, &expandedDataPtr
) != noErr
)
371 return cfragFragmentCorruptErr
;
373 sourceDataPtr
= (unsigned char*)((unsigned long)expandedDataPtr
+
374 exportSymbolEntryPtr
->address
);
378 sourceDataPtr
= (unsigned char*)((unsigned long)thePEFPtr
+
379 exportSectionPtr
->containerOffset
+
380 exportSymbolEntryPtr
->address
);
387 destDataPtr
= (unsigned char*)theSymbolPtr
;
390 while (theSymbolSize
-- > 0)
391 *destDataPtr
++ = *sourceDataPtr
++;
394 // Cleanup any expanded data
396 if (expandedDataPtr
!= nil
)
397 DisposePtr((Ptr
)expandedDataPtr
);
403 static IOByteCount
GetPEFLen ( LogicalAddress thePEFPtr
)
405 ContainerHeaderPtr containerHeaderPtr
; // Pointer to the Container Header
406 SectionHeaderPtr sections
;
407 short currentSection
;
411 containerHeaderPtr
= (ContainerHeaderPtr
)thePEFPtr
;
413 // Does the magic cookie match?
414 if (containerHeaderPtr
->magicCookie
!= 'Joy!')
417 // Is this a known PEF container format?
418 if (containerHeaderPtr
->containerID
!= 'peff')
421 // Find the loader section.
422 sections
= (SectionHeaderPtr
) (containerHeaderPtr
+ 1);
423 for (currentSection
= 0; currentSection
< containerHeaderPtr
->nbrOfSections
; currentSection
++)
425 if( sections
[currentSection
].containerOffset
> lastOffset
) {
426 lastOffset
= sections
[currentSection
].containerOffset
;
427 len
= sections
[currentSection
].rawSize
;
431 return( lastOffset
+ len
);
437 // theExportSymbol is NOT null-terminated, so use theExportSymbolLength.
439 static Boolean
SymbolCompare ( StringPtr theLookedForSymbol
,
440 StringPtr theExportSymbol
,
441 unsigned long theExportSymbolLength
)
443 unsigned char* p1
= (unsigned char*)theLookedForSymbol
;
444 unsigned char* p2
= (unsigned char*)theExportSymbol
;
447 // (skip over p string len byte)
448 if ( theExportSymbolLength
!= *p1
++ )
451 while ( theExportSymbolLength
-- != 0 )
453 if ( *p1
++ != *p2
++ )
461 readFile(char *path
, char **objAddr
, long *objSize
)
465 struct stat stat_buf
;
470 if((fd
= open(path
, O_RDONLY
)) == -1)
474 if(fstat(fd
, &stat_buf
) == -1) {
478 *objSize
= stat_buf
.st_size
;
480 if( KERN_SUCCESS
!= map_fd(fd
, 0, (vm_offset_t
*) objAddr
, TRUE
, *objSize
)) {
497 // The Driver Description
499 kInitialDriverDescriptor
= 0,
500 kVersionOneDriverDescriptor
= 1,
501 kTheDescriptionSignature
= 'mtej',
505 unsigned char nameInfoStr
[32]; // Driver Name/Info String
506 unsigned long version
; // Driver Version Number - really NumVersion
508 typedef struct DriverType DriverType
;
510 struct DriverDescription
{
511 unsigned long driverDescSignature
; // Signature field of this structure
512 unsigned long driverDescVersion
; // Version of this data structure
513 DriverType driverType
; // Type of Driver
514 char otherStuff
[512];
516 typedef struct DriverDescription DriverDescription
;
519 ExaminePEF( mach_port_t masterPort
, char *pef
, IOByteCount pefLen
, CFArrayRef okList
)
521 char descripName
[] = "\pTheDriverDescription";
523 DriverDescription descrip
;
524 DriverDescription curDesc
;
527 unsigned long newVersion
;
528 unsigned long curVersion
;
531 io_service_t service
;
534 CFStringRef ndrvPropName
= CFSTR("driver,AAPL,MacOS,PowerPC");
536 CFMutableDictionaryRef dict
;
541 err
= GetSymbolFromPEF(descripName
, pef
, &descrip
, sizeof(descrip
));
543 printf("\nGetSymbolFromPEF returns %ld\n",err
);
546 if((descrip
.driverDescSignature
!= kTheDescriptionSignature
) ||
547 (descrip
.driverDescVersion
!= kInitialDriverDescriptor
))
550 strncpy(matchName
, descrip
.driverType
.nameInfoStr
+ 1,
551 descrip
.driverType
.nameInfoStr
[0]);
552 matchName
[ descrip
.driverType
.nameInfoStr
[0] ] = 0;
555 for( index
= 0; (!ok
) && (index
< CFArrayGetCount(okList
)); index
++) {
556 okStr
= CFArrayGetValueAtIndex( okList
, index
);
557 if( CFStringGetTypeID() != CFGetTypeID(okStr
))
559 ok
= CFStringGetCString( okStr
, okName
, sizeof(okName
),
560 kCFStringEncodingMacRoman
)
561 && (0 == strcmp( okName
, matchName
));
564 newVersion
= descrip
.driverType
.version
;
565 if((newVersion
& 0xffff) == 0x8000) // final stage, release rev
568 IOMasterPort(mach_task_self(), &masterPort
);
570 kr
= IOServiceGetMatchingServices(masterPort
,
571 IOServiceNameMatching(matchName
),
573 if( kIOReturnSuccess
!= kr
)
578 (service
= IOIteratorNext(iter
));
579 IOObjectRelease(service
)) {
581 kr
= IORegistryEntryGetPath( service
, kIOServicePlane
, path
);
582 if( kIOReturnSuccess
== kr
)
583 printf("Name %s matches %s, ", matchName
, path
);
585 printf("(skipping)\n");
589 ndrv
= (CFDataRef
) IORegistryEntryCreateCFProperty( service
, ndrvPropName
,
590 kCFAllocatorDefault
, kNilOptions
);
593 err
= GetSymbolFromPEF( descripName
, CFDataGetBytePtr(ndrv
),
594 &curDesc
, sizeof(curDesc
));
596 printf("GetSymbolFromPEF returns %ld\n",err
);
598 if((curDesc
.driverDescSignature
== kTheDescriptionSignature
) &&
599 (curDesc
.driverDescVersion
== kInitialDriverDescriptor
)) {
601 curVersion
= curDesc
.driverType
.version
;
602 printf("new version %08lx, current version %08lx\n", newVersion
, curVersion
);
603 if((curVersion
& 0xffff) == 0x8000) // final stage, release rev
606 if( newVersion
<= curVersion
)
616 ndrv
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
617 pef
, pefLen
, kCFAllocatorNull
);
620 printf("Installing ndrv (");
621 dict
= CFDictionaryCreateMutable( kCFAllocatorDefault
, 0,
622 &kCFTypeDictionaryKeyCallBacks
,
623 &kCFTypeDictionaryValueCallBacks
);
626 CFDictionarySetValue(dict
, ndrvPropName
, ndrv
);
627 kr
= IORegistryEntryGetChildEntry( service
, kIOServicePlane
, &child
);
628 if( kr
== kIOReturnSuccess
) {
629 kr
= IORegistryEntrySetCFProperties( child
, dict
);
630 IOObjectRelease( child
);
634 kr
= kIOReturnNoMemory
;
637 printf("%08x)\n", kr
);
639 IOObjectRelease( iter
);
645 PEFExamineFile( mach_port_t masterPort
, CFURLRef file
)
650 long pefFileLen
, plistLen
;
651 IOByteCount pefLen
, pos
= 0;
653 CFDictionaryRef props
= 0;
655 CFArrayRef okList
= 0;
656 enum { kIOCFMaxPathSize
= 1026 };
657 char cFile
[kIOCFMaxPathSize
];
659 if (CFURLGetFileSystemRepresentation(file
, TRUE
, cFile
, kIOCFMaxPathSize
))
660 err
= readFile(cFile
, &pefBytes
, &pefFileLen
);
662 err
= kIOReturnIOError
;
667 strcat( cFile
, ".plist");
668 err
= readFile(cFile
, &plistBytes
, &plistLen
);
672 data
= CFDataCreateWithBytesNoCopy( kCFAllocatorDefault
,
673 plistBytes
, plistLen
, kCFAllocatorNull
);
676 props
= (CFDictionaryRef
) CFPropertyListCreateFromXMLData(
677 kCFAllocatorDefault
, data
, kCFPropertyListImmutable
, 0 );
680 if( CFDictionaryGetTypeID() != CFGetTypeID(props
))
683 okList
= CFDictionaryGetValue( props
, CFSTR("IONDRVList") );
684 if( CFArrayGetTypeID() != CFGetTypeID(okList
))
690 while( (pos
< pefFileLen
) && (pefLen
= GetPEFLen( pef
))) {
691 ExaminePEF( masterPort
, pef
, pefLen
, okList
);
692 pefLen
= (pefLen
+ 15) & ~15;
703 vm_deallocate( mach_task_self(), (vm_address_t
) plistBytes
, plistLen
);
705 vm_deallocate( mach_task_self(), (vm_address_t
) pefBytes
, pefFileLen
);