Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/libsaio/modules.c

1/*
2 * Copyright 2010 Evan Lojewski. All rights reserved.
3 *
4 */
5
6/*
7 * Copyright 2012 Cadet-petit Armel <armelcadetpetit@gmail.com>. All rights reserved.
8 *
9 * Cleaned, Added (runtime) bundles module support, based on a dylib environement.
10 *
11 */
12#include "libsaio.h"
13#include "bootstruct.h"
14#include "modules.h"
15
16#include "sl.h"
17#include "xml.h"
18
19#ifndef DEBUG_MODULES
20#define DEBUG_MODULES 0
21#endif
22
23#if DEBUG_MODULES
24#define DBG(x...)printf(x)
25#else
26#define DBG(x...)
27#endif
28
29struct Bundle {
30struct Bundle *nextBundle;
31long willLoad;
32TagPtr dict;
33 TagPtr personalities;
34#if 0
35config_file_t *LanguageConfig; // we will use an xml file instead of pure txt file ... it's easier to parse
36#endif
37//pool_t workspace;
38char *plistAddr;
39long plistLength;
40char *executablePath;
41char *bundlePath;
42long bundlePathLength;
43};
44typedef struct Bundle Bundle, *BundlePtr;
45
46// NOTE: Global so that modules can link with this
47unsigned long long textAddress = 0;
48unsigned long long textSection = 0;
49
50moduleHook_t* moduleCallbacks = NULL;
51symbolList_t* moduleSymbols = NULL;
52unsigned int (*lookup_symbol)(const char*, int(*strcmp_callback)(const char*, const char*)) = NULL;
53moduleHook_t* get_callback(const char* name);
54static unsigned int load_module(char * name, char* module, BundlePtr bundle);
55static EFI_STATUS _bind_macho(char* module, void* base, char* bind_stream, UInt32 size, BundlePtr bundle);
56
57#if macho_64
58static unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long, char), BundlePtr bundle);
59#else
60static unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long), BundlePtr bundle);
61#endif
62
63#if macho_64
64unsigned int handle_symtable(char *module, UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, char*, long long, char), char is64);
65#else
66unsigned int handle_symtable(char *module, UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, char*, long long));
67#endif
68
69#if DEBUG_MODULES
70VOID print_symbol_list(VOID);
71VOID print_hook_list(VOID);
72
73VOID print_hook_list(VOID)
74{
75moduleHook_t* hooks = moduleCallbacks;
76printf("Hook list: \n");
77while(hooks)
78{
79printf("* %s\n", hooks->name);
80hooks = hooks->next;
81}
82printf("\n");
83}
84
85VOID print_symbol_list(VOID)
86{
87symbolList_t* symbol = moduleSymbols;
88printf("Symbol list: \n");
89while(symbol)
90{
91printf("* %s : %s\n", symbol->module, symbol->symbol);
92symbol = symbol->next;
93}
94printf("\n");
95}
96#endif
97
98#if DYLIB_SUPPORT
99
100typedef struct dylbList_t
101{
102char* dylib_name;
103struct dylbList_t* next;
104} dylbList_t;
105
106dylbList_t* loadedDylib = NULL;
107
108
109static EFI_STATUS is_system_loaded(void)
110{
111msglog("* Attempting to load system module\n");
112
113
114 if((UInt32)lookup_symbol != 0xFFFFFFFF)
115 {
116#ifDEBUG_MODULES == 2
117 printf("System successfully Loaded.\n");
118 getc();
119#endif
120 return EFI_SUCCESS;
121 }
122
123
124#ifDEBUG_MODULES == 2
125 printf("Failed to load system module\n");
126 getc();
127#endif
128return EFI_LOAD_ERROR;
129}
130
131/*
132 * print out the information about the loaded module
133 */
134static VOID add_dylib(const char* name)
135{
136dylbList_t* new_entry = malloc(sizeof(dylbList_t));
137if (new_entry)
138{
139bzero(new_entry,sizeof(dylbList_t));
140
141new_entry->next = loadedDylib;
142
143loadedDylib = new_entry;
144
145new_entry->dylib_name = (char*)name;
146}
147}
148
149static EFI_STATUS is_dylib_loaded(const char* name)
150{
151dylbList_t* entry = loadedDylib;
152while(entry)
153{
154DBG("Comparing %s with %s\n", name, entry->dylib_name);
155char *fullname = newStringWithFormat("%s.dylib",name);
156if(fullname && ((strcmp(entry->dylib_name, name) == 0) || (strcmp(entry->dylib_name, fullname) == 0)))
157{
158free(fullname);
159DBG("Located module %s\n", name);
160return EFI_SUCCESS;
161}
162else
163{
164entry = entry->next;
165}
166
167}
168DBG("Module %s not found\n", name);
169
170return EFI_NOT_FOUND;
171}
172
173/*
174 * Load a dylib
175 *
176 * ex: load_dylib("/Extra/modules/", "AcpiCodec.dylib");
177 */
178VOID load_dylib(const char * dylib_path, const char * name)
179{
180 void (*module_start)(void);
181
182 char *tmp = newStringWithFormat("%s%s",dylib_path, name);
183 if (!tmp) {
184 return;
185 }
186 char *dylib_name = newString(name);
187 if (!dylib_name) {
188 free(tmp);
189 return;
190 }
191 msglog("* Attempting to load module: %s\n", tmp);
192 module_start = (void*)load_module(dylib_name,tmp, NULL);
193
194 if(module_start && ( module_start != (void*)0xFFFFFFFF))
195 {
196 add_dylib(name);
197 module_start();
198 }
199 else
200 {
201 // failed to load or already loaded
202 free(tmp);
203 free(dylib_name);
204
205 }
206}
207
208/*
209 * Load all dylib in the /Extra/modules/ directory
210 */
211
212VOID load_all_dylib(void)
213{
214char* name;
215long flags;
216long time;
217
218 if (is_system_loaded() != EFI_SUCCESS) return;
219
220 long ret, length, flags, time, bundleType;
221 long long index;
222 long result = -1;
223 const char * name;
224 void (*module_start)(void);
225
226DBG("FileLoadBundles in %s\n",dirSpec);
227
228 index = 0;
229 while (1) {
230 ret = GetDirEntry("/Extra/modules/", &index, &name, &flags, &time);
231 if (ret == -1) break;
232
233 // Make sure this is not a directory.
234 if ((flags & kFileTypeMask) == kFileTypeDirectory) continue;
235
236 if ((strncmp("Symbols.dylib",name, sizeof("Symbols.dylib"))) == 0) continue; // if we found Symbols.dylib, just skip it
237
238 if (is_dylib_loaded(name) == EFI_SUCCESS) continue;
239
240
241 // Make sure this is a kext.
242 length = strlen(name);
243 if (strncmp(name + length - 6, ".dylib", 6)) continue;
244
245 char *tmp = newStringWithFormat( "/Extra/modules/%s",name);
246 if (!tmp) {
247 continue;
248 }
249 char *dylib_name = newString(name);
250 if (!dylib_name) {
251 free(tmp);
252 continue;
253 }
254 msglog("* Attempting to load module: %s\n", tmp);
255 module_start = (void*)load_module(dylib_name,tmp, NULL);
256
257 if(module_start && ( module_start != (void*)0xFFFFFFFF))
258 {
259 add_dylib(name);
260 module_start();
261 }
262 else
263 {
264 // failed to load or already loaded
265 free(tmp);
266 free(dylib_name);
267
268 }
269 }
270
271#if DEBUG_MODULES
272print_symbol_list();
273#endif
274}
275
276#endif
277
278/*
279 * Load a module file
280 */
281static unsigned int load_module(char * name, char* module, BundlePtr bundle)
282{
283unsigned int module_start = 0xFFFFFFFF;
284
285
286int fh = -1;
287
288fh = open(module,0);
289if(fh < 0)
290{
291#if DEBUG_MODULES
292DBG("Unable to locate module %s\n", module);
293getc();
294#else
295msglog("Unable to locate module %s\n", module);
296#endif
297return 0xFFFFFFFF;
298}
299
300{
301int moduleSize = file_size(fh);
302
303char* module_base = NULL;
304
305if (moduleSize > 0)
306{
307module_base = (char*) malloc(moduleSize);
308}
309
310if (!module_base)
311{
312goto out;
313}
314bzero(module_base,moduleSize);
315
316if (read(fh, module_base, moduleSize) == moduleSize)
317{
318
319DBG("Module %s read in.\n", module);
320
321// Module loaded into memory, parse it
322module_start = parse_mach(name, module_base, &add_symbol, bundle);
323
324
325}
326else
327{
328printf("Unable to read in module %s\n.", module);
329#if DEBUG_MODULES
330getc();
331#endif
332free(module_base);
333}
334}
335out:
336close(fh);
337return module_start;
338}
339
340moduleHook_t* get_callback(const char* name)
341{
342moduleHook_t* hooks = moduleCallbacks;
343
344// look for a hook. If it exists, return the moduleHook_t*,
345// If not, return NULL.
346while(hooks)
347{
348if(strcmp(name, hooks->name) == 0)
349{
350//DBG("Located hook %s\n", name);
351return hooks;
352}
353hooks = hooks->next;
354}
355return NULL;
356
357}
358
359/*
360 *execute_hook( const char* name )
361 *name - Name of the module hook
362 *If any callbacks have been registered for this hook
363 *they will be executed now in the same order that the
364 *hooks were added.
365 */
366EFI_STATUS execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6)
367{
368DBG("Attempting to execute hook '%s'\n", name);
369moduleHook_t* hook = get_callback(name);
370
371if(hook)
372{
373// Loop through all callbacks for this module
374callbackList_t* callbacks = hook->callbacks;
375
376while(callbacks)
377{
378// Execute callback
379callbacks->callback(arg1, arg2, arg3, arg4, arg5, arg6);
380callbacks = callbacks->next;
381}
382DBG("Hook '%s' executed.\n", name);
383return EFI_SUCCESS;
384}
385
386// Callback for this hook doesn't exist;
387DBG("No callbacks for '%s' hook.\n", name);
388return EFI_NOT_FOUND;
389
390}
391
392/*
393 *register_hook_callback( const char* name, void(*callback)())
394 *name - Name of the module hook to attach to.
395 *callbacks - The funciton pointer that will be called when the
396 *hook is executed. When registering a new callback name, the callback is added sorted.
397 *NOTE: the hooks take four void* arguments.
398 */
399static VOID __register_hook_callback(moduleHook_t* hook, const char* name, void(*callback)(void*, void*, void*, void*, void*, void*))
400{
401if(hook)
402{
403// append
404callbackList_t* newCallback = malloc(sizeof(callbackList_t));
405if (!newCallback) {
406DBG("Unable to allocate memory for callback \n");
407return;
408}
409bzero(newCallback,sizeof(callbackList_t));
410
411newCallback->next = hook->callbacks;
412hook->callbacks = newCallback;
413newCallback->callback = callback;
414}
415else
416{
417// create new hook
418moduleHook_t* newHook = malloc(sizeof(moduleHook_t));
419if (!newHook) {
420DBG("Unable to allocate memory for hook '%s'.\n", name);
421return;
422}
423bzero(newHook,sizeof(moduleHook_t));
424
425newHook->name = name;
426newHook->callbacks = malloc(sizeof(callbackList_t));
427if (!newHook->callbacks) {
428DBG("Unable to allocate memory for callback \n");
429free(newHook);
430return;
431}
432bzero(newHook->callbacks,sizeof(callbackList_t));
433
434newHook->callbacks->callback = callback;
435newHook->callbacks->next = NULL;
436
437newHook->next = moduleCallbacks;
438moduleCallbacks = newHook;
439
440}
441
442#if DEBUG_MODULES
443print_hook_list();
444getc();
445#endif
446}
447
448VOID register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*, void*, void*))
449{
450DBG("Adding callback for hook '%s'.\n", name);
451
452moduleHook_t* hook = get_callback(name);
453
454__register_hook_callback(hook, name, callback);
455}
456
457VOID register_one_callback(const char* name, void(*callback)(void*, void*, void*, void*, void*, void*))
458{
459DBG("Adding one callback for hook '%s'.\n", name);
460
461moduleHook_t* hook = get_callback(name);
462
463if (hook)
464{
465return;
466}
467__register_hook_callback(hook, name, callback);
468}
469
470#if DEBUG_MODULES
471unsigned long vmaddr;
472long vmsize;
473#endif
474
475/*
476 * Parse through a macho module. The module will be rebased and binded
477 * as specified in the macho header. If the module is successfully loaded
478 * the module iinit address will be returned.
479 * NOTE; all dependecies will be loaded before this module is started
480 * NOTE: If the module is unable to load ot completeion, the modules
481 * symbols will still be available (TODO: fix this). This should not
482 * happen as all dependencies are verified before the sybols are read in.
483 */
484#if macho_64
485static unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long, char), BundlePtr bundle)// TODO: add param to specify valid archs
486#else
487static unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long), BundlePtr bundle)// TODO: add param to specify valid archs
488#endif
489{
490#if macho_64
491char is64 = false;
492#endif
493unsigned int module_start = 0xFFFFFFFF;
494EFI_STATUS bind_status = EFI_SUCCESS;
495
496// TODO convert all of the structs to a union
497struct dyld_info_command* dyldInfoCommand = NULL;
498struct symtab_command* symtabCommand = NULL;
499
500{
501struct segment_command *segCommand = NULL;
502#if macho_64
503struct segment_command_64 *segCommand64 = NULL;
504#endif
505struct load_command *loadCommand = NULL;
506UInt32 binaryIndex = 0;
507UInt16 cmd = 0;
508
509// Parse through the load commands
510if(((struct mach_header*)binary)->magic == MH_MAGIC)
511{
512#if macho_64
513is64 = false;
514#endif
515binaryIndex += sizeof(struct mach_header);
516}
517#if macho_64
518else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
519{
520// NOTE: modules cannot be 64bit...
521is64 = true;
522binaryIndex += sizeof(struct mach_header_64);
523}
524#endif
525else
526{
527printf("Modules: Invalid mach magic\n");
528getc();
529return 0xFFFFFFFF;
530}
531
532
533
534/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
535 {
536 printf("Module is not a dylib. Unable to load.\n");
537 getc();
538 return NULL; // Module is in the incorrect format
539 }*/
540
541while(cmd < ((struct mach_header*)binary)->ncmds)
542{
543cmd++;
544
545loadCommand = binary + binaryIndex;
546UInt32 cmdSize = loadCommand->cmdsize;
547
548
549switch ((loadCommand->cmd & 0x7FFFFFFF))
550{
551case LC_SYMTAB:
552symtabCommand = binary + binaryIndex;
553break;
554
555case LC_SEGMENT: // 32bit macho
556{
557segCommand = binary + binaryIndex;
558
559//printf("Segment name is %s\n", segCommand->segname);
560
561if(strncmp("__TEXT", segCommand->segname, sizeof("__TEXT")) == 0)
562{
563UInt32 sectionIndex;
564
565#if DEBUG_MODULES
566unsigned long fileaddr;
567long filesize;
568vmaddr = (segCommand->vmaddr & 0x3fffffff);
569vmsize = segCommand->vmsize;
570fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand->fileoff);
571filesize = segCommand->filesize;
572
573printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
574 segCommand->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
575 (unsigned) segCommand->nsects, (unsigned)segCommand->flags);
576#if DEBUG_MODULES==2
577
578getc();
579#endif
580#endif
581
582sectionIndex = sizeof(struct segment_command);
583
584struct section *sect;
585
586while(sectionIndex < segCommand->cmdsize)
587{
588sect = binary + binaryIndex + sectionIndex;
589
590sectionIndex += sizeof(struct section);
591
592
593if(strncmp("__text", sect->sectname,sizeof("__text")) == 0)
594{
595// __TEXT,__text found, save the offset and address for when looking for the calls.
596textSection = sect->offset;
597textAddress = sect->addr;
598break;
599}
600}
601}
602break;
603}
604#if macho_64
605case LC_SEGMENT_64:// 64bit macho's
606{
607segCommand64 = binary + binaryIndex;
608
609//printf("Segment name is %s\n", segCommand->segname);
610
611if(strncmp("__TEXT", segCommand64->segname, sizeof("__TEXT")) == 0)
612{
613UInt32 sectionIndex;
614
615#if DEBUG_MODULES
616unsigned long fileaddr;
617long filesize;
618vmaddr = (segCommand64->vmaddr & 0x3fffffff);
619vmsize = segCommand64->vmsize;
620fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand64->fileoff);
621filesize = segCommand64->filesize;
622
623printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
624 segCommand64->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
625 (unsigned) segCommand64->nsects, (unsigned)segCommand64->flags);
626#if DEBUG_MODULES==2
627
628getc();
629#endif
630#endif
631
632sectionIndex = sizeof(struct segment_command_64);
633
634struct section_64 *sect;
635
636while(sectionIndex < segCommand64->cmdsize)
637{
638sect = binary + binaryIndex + sectionIndex;
639
640sectionIndex += sizeof(struct section_64);
641
642
643if(strncmp("__text", sect->sectname, sizeof("__text")) == 0)
644{
645// __TEXT,__text found, save the offset and address for when looking for the calls.
646textSection = sect->offset;
647textAddress = sect->addr;
648
649break;
650}
651}
652}
653
654break;
655}
656#endif
657case LC_DYSYMTAB:
658break;
659
660case LC_LOAD_DYLIB:
661case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
662 break;
663
664case LC_ID_DYLIB:
665 break;
666
667
668case LC_DYLD_INFO:
669// Bind and rebase info is stored here
670dyldInfoCommand = binary + binaryIndex;
671break;
672
673case LC_UUID:
674break;
675
676case LC_UNIXTHREAD:
677break;
678
679default:
680DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
681break;
682
683}
684
685binaryIndex += cmdSize;
686}
687//if(!moduleName) return NULL;
688}
689
690// bind_macho uses the symbols.
691#if macho_64
692module_start = handle_symtable(module, (UInt32)binary, symtabCommand, symbol_handler, is64);
693#else
694module_start = handle_symtable(module, (UInt32)binary, symtabCommand, symbol_handler);
695#endif
696// Rebase the module before binding it.
697if(dyldInfoCommand && dyldInfoCommand->rebase_off)
698{
699rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
700}
701
702if(dyldInfoCommand && dyldInfoCommand->bind_off)
703{
704bind_status = _bind_macho(module, binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size, bundle);
705}
706
707if(dyldInfoCommand && dyldInfoCommand->weak_bind_off && (bind_status == EFI_SUCCESS))
708{
709// NOTE: this currently should never happen.
710bind_status = _bind_macho(module, binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size, bundle);
711}
712
713if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off && (bind_status == EFI_SUCCESS))
714{
715// NOTE: we are binding the lazy pointers as a module is laoded,
716// This should be changed to bind when a symbol is referened at runtime instead.
717bind_status = _bind_macho(module, binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size, bundle);
718}
719
720 if (bind_status != EFI_SUCCESS) {
721 module_start = 0xFFFFFFFF;
722 }
723
724return module_start;
725
726}
727
728// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
729void rebase_macho(void* base, char* rebase_stream, UInt32 size)
730{
731rebase_stream += (UInt32)base;
732
733UInt8 immediate = 0;
734UInt8 opcode = 0;
735UInt8 type = 0;
736
737UInt32 segmentAddress = 0;
738
739
740
741UInt32 tmp = 0;
742UInt32 tmp2 = 0;
743UInt8 bits = 0;
744UInt32 index = 0;
745
746//int done = 0;
747unsigned int i = 0;
748
749while(/*!done &&*/ i < size)
750{
751immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
752opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
753
754
755switch(opcode)
756{
757case REBASE_OPCODE_DONE:
758// Rebase complete.
759//done = 1;
760break;
761
762
763case REBASE_OPCODE_SET_TYPE_IMM:
764// Set rebase type (pointer, absolute32, pcrel32)
765//DBG("Rebase type = 0x%X\n", immediate);
766type = immediate;
767break;
768
769
770case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
771{
772// Locate address to begin rebasing
773//segmentAddress = 0;
774
775struct segment_command* segCommand = NULL; // NOTE: 32bit only
776
777{
778unsigned int binIndex = 0;
779index = 0;
780do
781{
782segCommand = base + sizeof(struct mach_header) + binIndex;
783
784
785binIndex += segCommand->cmdsize;
786index++;
787}
788while(index <= immediate);
789}
790
791segmentAddress = segCommand->fileoff;
792
793tmp = 0;
794bits = 0;
795do
796{
797tmp |= (rebase_stream[++i] & 0x7f) << bits;
798bits += 7;
799}
800while(rebase_stream[i] & 0x80);
801
802segmentAddress += tmp;
803break;
804}
805case REBASE_OPCODE_ADD_ADDR_ULEB:
806// Add value to rebase address
807tmp = 0;
808bits = 0;
809do
810{
811tmp <<= bits;
812tmp |= rebase_stream[++i] & 0x7f;
813bits += 7;
814}
815while(rebase_stream[i] & 0x80);
816
817segmentAddress +=tmp;
818break;
819
820case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
821segmentAddress += immediate * sizeof(void*);
822break;
823
824
825case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
826for (index = 0; index < immediate; ++index)
827{
828rebase_location(base + segmentAddress, (char*)base, type);
829segmentAddress += sizeof(void*);
830}
831break;
832
833case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
834tmp = 0;
835bits = 0;
836do
837{
838tmp |= (rebase_stream[++i] & 0x7f) << bits;
839bits += 7;
840}
841while(rebase_stream[i] & 0x80);
842
843for (index = 0; index < tmp; ++index)
844{
845//DBG("\tRebasing 0x%X\n", segmentAddress);
846rebase_location(base + segmentAddress, (char*)base, type);
847segmentAddress += sizeof(void*);
848}
849break;
850
851case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
852tmp = 0;
853bits = 0;
854do
855{
856tmp |= (rebase_stream[++i] & 0x7f) << bits;
857bits += 7;
858}
859while(rebase_stream[i] & 0x80);
860
861rebase_location(base + segmentAddress, (char*)base, type);
862
863segmentAddress += tmp + sizeof(void*);
864break;
865
866case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
867tmp = 0;
868bits = 0;
869do
870{
871tmp |= (rebase_stream[++i] & 0x7f) << bits;
872bits += 7;
873}
874while(rebase_stream[i] & 0x80);
875
876
877tmp2 = 0;
878bits = 0;
879do
880{
881tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
882bits += 7;
883}
884while(rebase_stream[i] & 0x80);
885
886for (index = 0; index < tmp; ++index)
887{
888
889rebase_location(base + segmentAddress, (char*)base, type);
890
891segmentAddress += tmp2 + sizeof(void*);
892}
893break;
894default:
895break;
896}
897i++;
898}
899}
900
901// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
902// NOTE: this uses 32bit values, and not 64bit values.
903// There is apossibility that this could cause issues,
904// however the macho file is 32 bit, so it shouldn't matter too much
905EFI_STATUS bind_macho(char* module, void* base, char* bind_stream, UInt32 size)
906{
907return _bind_macho( module, base, bind_stream, size, NULL);
908}
909
910static EFI_STATUS _bind_macho(char* module, void* base, char* bind_stream, UInt32 size, BundlePtr bundle)
911{
912bind_stream += (UInt32)base;
913
914UInt8 immediate = 0;
915UInt8 opcode = 0;
916
917UInt32 segmentAddress = 0;
918
919UInt32 address = 0;
920
921SInt32 addend = 0;// TODO: handle this
922
923const char* symbolName = NULL;
924UInt32 symbolAddr = 0xFFFFFFFF;
925
926// Temperary variables
927UInt8 bits = 0;
928UInt32 tmp = 0;
929UInt32 tmp2 = 0;
930
931UInt32 index = 0;
932unsigned int i = 0;
933
934while(i < size)
935{
936immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
937opcode = bind_stream[i] & BIND_OPCODE_MASK;
938
939
940switch(opcode)
941{
942case BIND_OPCODE_DONE:
943break;
944
945case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
946 {
947#if DEBUG_MODULES==2
948SInt32 libraryOrdinal = immediate;
949DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
950#endif
951break;
952 }
953case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
954 {
955#if DEBUG_MODULES==2
956SInt32 libraryOrdinal = 0;
957UInt8 bits = 0;
958do
959{
960libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
961bits += 7;
962}
963while(bind_stream[i] & 0x80);
964
965DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
966#else
967 do
968{
969i++;
970}
971while(bind_stream[i] & 0x80);
972#endif
973break;
974}
975case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
976 {
977#if DEBUG_MODULES==2
978 // NOTE: this is wrong, fortunately we don't use it
979SInt32 libraryOrdinal = -immediate;
980DBG("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
981#endif
982break;
983}
984case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
985 {
986symbolName = (char*)&bind_stream[++i];
987i += strlen((char*)&bind_stream[i]);
988#if DEBUG_MODULES==2
989UInt8 symbolFlags = immediate;
990 DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symbolFlags);
991#endif
992symbolAddr = 0xFFFFFFFF;
993TagPtr prop;
994
995if (bundle != NULL)
996{
997prop = XMLGetProperty(bundle->dict, kPropOSBundleLibraries);
998if (prop != 0)
999{
1000prop = prop->tag;
1001while (prop != 0)
1002{
1003/* the order in OSBundleLibraries is important */
1004
1005if (prop->string)
1006{
1007symbolAddr = lookup_all_symbols(prop->string ,symbolName);
1008
1009if (symbolAddr != 0xFFFFFFFF) break; // the symbol is found , we can exit the loop
1010}
1011
1012prop = prop->tagNext;
1013
1014}
1015}
1016
1017}
1018
1019 if (symbolAddr == 0xFFFFFFFF) symbolAddr = lookup_all_symbols(NULL ,symbolName); // at this point if the symbol is still undefined, we search everywhere by starting to the internal symbols
1020
1021 if((symbolAddr == 0xFFFFFFFF) && (strncmp(symbolName, SYMBOL_DYLD_STUB_BINDER,sizeof(SYMBOL_DYLD_STUB_BINDER)) != 0))
1022{
1023printf("Unable to bind symbol %s needed by %s\n", symbolName, module);
1024 getc();
1025 goto error;
1026
1027}
1028
1029break;
1030 }
1031case BIND_OPCODE_SET_TYPE_IMM:
1032 {
1033// Set bind type (pointer, absolute32, pcrel32)
1034#if DEBUG_MODULES==2
1035 UInt8 type = immediate;
1036DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
1037#endif
1038break;
1039 }
1040case BIND_OPCODE_SET_ADDEND_SLEB:
1041addend = 0;
1042bits = 0;
1043do
1044{
1045addend |= (bind_stream[++i] & 0x7f) << bits;
1046bits += 7;
1047}
1048while(bind_stream[i] & 0x80);
1049
1050if(!(bind_stream[i-1] & 0x40)) addend *= -1;
1051#if DEBUG_MODULES==2
1052DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
1053#endif
1054
1055break;
1056
1057case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1058{
1059// Locate address
1060struct segment_command* segCommand = NULL;// NOTE: 32bit only
1061
1062{
1063unsigned int binIndex = 0;
1064index = 0;
1065do
1066{
1067segCommand = base + sizeof(struct mach_header) + binIndex;
1068binIndex += segCommand->cmdsize;
1069index++;
1070}while(index <= immediate);
1071}
1072
1073
1074segmentAddress = segCommand->fileoff;
1075
1076// Read in offset
1077tmp = 0;
1078bits = 0;
1079do
1080{
1081tmp |= (bind_stream[++i] & 0x7f) << bits;
1082bits += 7;
1083}while(bind_stream[i] & 0x80);
1084
1085segmentAddress += tmp;
1086#if DEBUG_MODULES==2
1087DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);
1088#endif
1089break;
1090}
1091case BIND_OPCODE_ADD_ADDR_ULEB:
1092// Read in offset
1093tmp = 0;
1094bits = 0;
1095do
1096{
1097tmp |= (bind_stream[++i] & 0x7f) << bits;
1098bits += 7;
1099}
1100while(bind_stream[i] & 0x80);
1101
1102segmentAddress += tmp;
1103#if DEBUG_MODULES==2
1104DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);
1105#endif
1106
1107break;
1108
1109case BIND_OPCODE_DO_BIND:
1110#if DEBUG_MODULES==2
1111DBG("BIND_OPCODE_DO_BIND\n");
1112#endif
1113
1114 if(symbolAddr != 0xFFFFFFFF)
1115{
1116address = segmentAddress + (UInt32)base;
1117
1118bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
1119}
1120else if(symbolName && (strncmp(symbolName, SYMBOL_DYLD_STUB_BINDER,sizeof(SYMBOL_DYLD_STUB_BINDER)) != 0))
1121{
1122printf("Unable to bind symbol %s needed by %s\n", symbolName, module);
1123 getc();
1124 goto error;
1125
1126}
1127
1128segmentAddress += sizeof(void*);
1129break;
1130
1131case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1132#if DEBUG_MODULES==2
1133DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
1134#endif
1135
1136// Read in offset
1137tmp = 0;
1138bits = 0;
1139do
1140{
1141tmp |= (bind_stream[++i] & 0x7f) << bits;
1142bits += 7;
1143}
1144while(bind_stream[i] & 0x80);
1145
1146
1147 if(symbolAddr != 0xFFFFFFFF)
1148{
1149address = segmentAddress + (UInt32)base;
1150
1151bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
1152}
1153else if(symbolName && (strncmp(symbolName, SYMBOL_DYLD_STUB_BINDER,sizeof(SYMBOL_DYLD_STUB_BINDER)) != 0))
1154{
1155printf("Unable to bind symbol %s needed by %s\n", symbolName, module);
1156 getc();
1157 goto error;
1158
1159}
1160
1161segmentAddress += tmp + sizeof(void*);
1162
1163
1164break;
1165
1166case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1167#if DEBUG_MODULES==2
1168DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
1169#endif
1170
1171 if(symbolAddr != 0xFFFFFFFF)
1172{
1173address = segmentAddress + (UInt32)base;
1174
1175bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
1176}
1177else if(symbolName && (strncmp(symbolName, SYMBOL_DYLD_STUB_BINDER,sizeof(SYMBOL_DYLD_STUB_BINDER)) != 0))
1178{
1179printf("Unable to bind symbol %s needed by %s\n", symbolName, module);
1180 getc();
1181 goto error;
1182
1183}
1184segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
1185
1186break;
1187
1188case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1189
1190tmp = 0;
1191bits = 0;
1192do
1193{
1194tmp |= (bind_stream[++i] & 0x7f) << bits;
1195bits += 7;
1196}
1197while(bind_stream[i] & 0x80);
1198
1199
1200tmp2 = 0;
1201bits = 0;
1202do
1203{
1204tmp2 |= (bind_stream[++i] & 0x7f) << bits;
1205bits += 7;
1206}
1207while(bind_stream[i] & 0x80);
1208
1209#if DEBUG_MODULES==2
1210DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);
1211#endif
1212
1213 if(symbolAddr != 0xFFFFFFFF)
1214{
1215for(index = 0; index < tmp; index++)
1216{
1217
1218address = segmentAddress + (UInt32)base;
1219
1220bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
1221
1222segmentAddress += tmp2 + sizeof(void*);
1223}
1224}
1225else if(symbolName && (strncmp(symbolName, SYMBOL_DYLD_STUB_BINDER,sizeof(SYMBOL_DYLD_STUB_BINDER)) != 0))
1226{
1227printf("Unable to bind symbol %s needed by %s\n", symbolName, module);
1228 getc();
1229 goto error;
1230
1231}
1232
1233break;
1234default:
1235break;
1236
1237}
1238i++;
1239}
1240 return EFI_SUCCESS;
1241error:
1242 return EFI_NOT_FOUND;
1243}
1244
1245void rebase_location(UInt32* location, char* base, int type)
1246{
1247switch(type)
1248{
1249case REBASE_TYPE_POINTER:
1250case REBASE_TYPE_TEXT_ABSOLUTE32:
1251*location += (UInt32)base;
1252break;
1253
1254default:
1255break;
1256}
1257}
1258
1259void bind_location(UInt32* location, char* value, UInt32 addend, int type)
1260{
1261// do actual update
1262char* newValue = value + addend;
1263
1264switch (type) {
1265case BIND_TYPE_POINTER:
1266case BIND_TYPE_TEXT_ABSOLUTE32:
1267break;
1268
1269case BIND_TYPE_TEXT_PCREL32:
1270newValue -= ((UInt32)location + 4);
1271
1272break;
1273default:
1274return;
1275}
1276*location = (UInt32)newValue;
1277
1278
1279}
1280
1281/*
1282 * add_symbol
1283 * This function adds a symbol from a module to the list of known symbols
1284 * possibly change to a pointer and add this to the Symbol module so that it can
1285 * adjust it's internal symbol list (sort) to optimize locating new symbols
1286 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
1287 */
1288#if macho_64
1289long long add_symbol(char* module,char* symbol, long long addr, char is64)
1290#else
1291long long add_symbol(char* module,char* symbol, long long addr)
1292#endif
1293{
1294#if macho_64
1295if(is64) return 0xFFFFFFFF; // Fixme
1296#endif
1297// This only can handle 32bit symbols
1298symbolList_t* new_entry= malloc(sizeof(symbolList_t));
1299DBG("Adding symbol %s at 0x%X\n", symbol, addr);
1300if (new_entry)
1301{
1302bzero(new_entry,sizeof(symbolList_t));
1303
1304new_entry->next = moduleSymbols;
1305
1306moduleSymbols = new_entry;
1307
1308new_entry->addr = (UInt32)addr;
1309 new_entry->module = module;
1310new_entry->symbol = symbol;
1311return addr;
1312}
1313
1314return 0xFFFFFFFF;
1315
1316}
1317
1318// Look for symbols using the Smbols moduel function.
1319// If non are found, look through the list of module symbols
1320unsigned int lookup_all_symbols(const char* module, const char* name)
1321{
1322
1323 unsigned int addr = 0xFFFFFFFF;
1324
1325 do {
1326
1327 if ((module != NULL) && (strncmp(module,SYMBOLS_BUNDLE,sizeof(SYMBOLS_BUNDLE)) != 0))
1328 break;
1329
1330 if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
1331 {
1332 addr = lookup_symbol(name, &strcmp);
1333 if(addr != 0xFFFFFFFF)
1334 {
1335 DBG("Internal symbol %s located at 0x%X\n", name, addr);
1336 goto out;
1337 }
1338 }
1339
1340 } while (0);
1341
1342
1343{
1344symbolList_t* entry = moduleSymbols;
1345while(entry)
1346{
1347 if ((module != NULL) && (strcmp(entry->module,module) != 0))
1348 {
1349 entry = entry->next;
1350 continue;
1351 }
1352
1353 if(strcmp(entry->symbol, name) == 0)
1354 {
1355 DBG("External symbol %s located at 0x%X\n", name, entry->addr);
1356 addr = entry->addr;
1357 goto out;
1358 }
1359 else
1360 {
1361 entry = entry->next;
1362 }
1363
1364}
1365}
1366
1367#if DEBUG_MODULES
1368if(strncmp(name, SYMBOL_DYLD_STUB_BINDER, sizeof(SYMBOL_DYLD_STUB_BINDER)) != 0)
1369{
1370verbose("Unable to locate symbol %s\n", name);
1371getc();
1372}
1373#endif
1374out:
1375 return addr;
1376
1377}
1378
1379
1380/*
1381 * parse the symbol table
1382 * Lookup any undefined symbols
1383 */
1384#if macho_64
1385unsigned int handle_symtable(char *module, UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, char*, long long, char), char is64)
1386#else
1387unsigned int handle_symtable(char *module, UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, char*, long long))
1388#endif
1389{
1390unsigned int module_start = 0xFFFFFFFF;
1391
1392UInt32 symbolIndex = 0;
1393 if (!symtabCommand) {
1394 return 0xFFFFFFFF;
1395 }
1396char* symbolString = base + (char*)symtabCommand->stroff;
1397#if macho_64
1398if(!is64)
1399#endif
1400{
1401struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
1402while(symbolIndex < symtabCommand->nsyms)
1403{
1404if(symbolEntry->n_value)
1405{
1406if(strstr(symbolString + symbolEntry->n_un.n_strx, "module_start") || (strncmp(symbolString + symbolEntry->n_un.n_strx, "start", sizeof("start")) == 0))
1407{
1408module_start = base + symbolEntry->n_value;
1409DBG("n_value %x module_start %x\n", (unsigned)symbolEntry->n_value, (unsigned)module_start);
1410}
1411else
1412{
1413#if macho_64
1414symbol_handler(module, symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
1415#else
1416symbol_handler(module, symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value);
1417#endif
1418
1419}
1420#if DEBUG_MODULES
1421bool isTexT = (((unsigned)symbolEntry->n_value > (unsigned)vmaddr) && ((unsigned)(vmaddr + vmsize) > (unsigned)symbolEntry->n_value ));
1422printf("%s %s\n", isTexT ? "__TEXT :" : "__DATA(OR ANY) :", symbolString + symbolEntry->n_un.n_strx);
1423#if DEBUG_MODULES==2
1424
1425if(strcmp(symbolString + symbolEntry->n_un.n_strx, "_BootHelp_txt") == 0)
1426{
1427long long addr = (long long)base + symbolEntry->n_value;
1428unsigned char *BootHelp = NULL;
1429BootHelp = (unsigned char*)(UInt32)addr;
1430printf("method 1: __DATA : BootHelp_txt[0] %x\n", BootHelp[0]);
1431
1432long long addr2 = symbolEntry->n_value;
1433unsigned char *BootHelp2 = NULL;
1434BootHelp2 = (unsigned char*)(UInt32)addr2;
1435printf("method 2: __DATA : BootHelp_txt[0] %x\n", BootHelp2[0]);
1436}
1437#endif
1438#endif
1439
1440}
1441
1442symbolEntry++;
1443symbolIndex++;// TODO remove
1444}
1445}
1446#if macho_64
1447else
1448{
1449struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
1450// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
1451while(symbolIndex < symtabCommand->nsyms)
1452{
1453
1454if(strstr(symbolString + symbolEntry->n_un.n_strx, "module_start") || (strncmp(symbolString + symbolEntry->n_un.n_strx, "start",sizeof("start")) == 0))
1455{
1456module_start = (unsigned int)(base + symbolEntry->n_value);
1457}
1458else
1459{
1460symbol_handler(module, symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
1461}
1462
1463symbolEntry++;
1464symbolIndex++;// TODO remove
1465}
1466}
1467#endif
1468
1469return module_start;
1470
1471}
1472
1473
1474/*
1475 * Locate the symbol for an already loaded function and modify the beginning of
1476 * the function to jump directly to the new one
1477 * example: replace_system_function("_getc", &replacement);
1478 * replace_function(module_name,"_getc", &replacement);
1479 * replace_function_any("_getc", &replacement);
1480 */
1481EFI_STATUS replace_function(const char* module, const char* symbol, void* newAddress)
1482{
1483// TODO: look into using the next four bytes of the function instead
1484// Most functions should support this, as they probably will be at
1485// least 10 bytes long, but you never know, this is sligtly safer as
1486// function can be as small as 6 bytes.
1487UInt32 addr = lookup_all_symbols(module, symbol);
1488
1489char* binary = (char*)addr;
1490if(addr != 0xFFFFFFFF)
1491{
1492UInt32* jumpPointer = malloc(sizeof(UInt32));
1493if (!jumpPointer) {
1494return EFI_OUT_OF_RESOURCES;
1495}
1496bzero(jumpPointer,sizeof(UInt32));
1497
1498*binary++ = 0xFF;// Jump
1499*binary++ = 0x25;// Long Jump
1500*((UInt32*)binary) = (UInt32)jumpPointer;
1501
1502*jumpPointer = (UInt32)newAddress;
1503
1504return EFI_SUCCESS;
1505}
1506
1507return EFI_NOT_FOUND;
1508
1509}
1510
1511EFI_STATUS replace_system_function(const char* symbol, void* newAddress)
1512{
1513
1514return replace_function(SYMBOLS_BUNDLE,symbol,newAddress);
1515
1516}
1517
1518EFI_STATUS replace_function_any(const char* symbol, void* newAddress)
1519{
1520
1521return replace_function(NULL,symbol,newAddress);
1522
1523}
1524/*
1525 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
1526 *
1527 * @APPLE_LICENSE_HEADER_START@
1528 *
1529 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
1530 * Reserved. This file contains Original Code and/or Modifications of
1531 * Original Code as defined in and that are subject to the Apple Public
1532 * Source License Version 2.0 (the 'License'). You may not use this file
1533 * except in compliance with the License. Please obtain a copy of the
1534 * License at http://www.apple.com/publicsource and read it before using
1535 * this file.
1536 *
1537 * The Original Code and all software distributed under the License are
1538 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1539 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
1540 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
1541 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
1542 * License for the specific language governing rights and limitations
1543 * under the License.
1544 *
1545 * @APPLE_LICENSE_HEADER_END@
1546 */
1547/*
1548 * drivers.c - Driver Loading Functions.
1549 *
1550 * Copyright (c) 2000 Apple Computer, Inc.
1551 *
1552 * DRI: Josh de Cesare
1553 */
1554
1555/*
1556 * Copyright 2012 Cadet-petit Armel <armelcadetpetit@gmail.com>. All rights reserved.
1557 *
1558 * Cleaned, Added (runtime) bundles support.
1559 *
1560 */
1561#include <mach-o/fat.h>
1562#include <libkern/OSByteOrder.h>
1563#include <mach/machine.h>
1564
1565
1566
1567
1568enum {
1569kCFBundleType2,
1570kCFBundleType3
1571};
1572
1573enum {
1574BundlePriorityNull = 0,
1575BundlePriorityInit = 1,
1576BundlePrioritySystem = 2,
1577BundlePrioritySystemLib = 3,
1578 BundlePriorityNormalPriority = 4,
1579 BundlePriorityLowestPriority = 99,
1580BundlePriorityEnd = 100 // can not be assigned
1581
1582};
1583
1584static BundlePtr gBundleHead;
1585static char * gBundlesSpec;
1586static char * gDriverSpec;
1587static char * gFileSpec;
1588static char * gTempSpec;
1589static char * gFileName;
1590static int gLowestLoadPriority;
1591
1592static long ParseXML(char *buffer, BundlePtr *module);
1593static BundlePtr FindBundle( char * bundle_id );
1594
1595static void
1596FreeBundleSupport( void )
1597{
1598
1599 if ( gBundlesSpec ) free(gBundlesSpec);
1600 if ( gDriverSpec) free(gDriverSpec);
1601 if ( gFileSpec ) free(gFileSpec);
1602 if ( gTempSpec ) free(gTempSpec);
1603 if ( gFileName ) free(gFileName);
1604}
1605
1606//==========================================================================
1607// InitBundleSupport
1608
1609long
1610InitBundleSupport( void )
1611{
1612DBG("InitBundleSupport\n");
1613
1614 static bool BundleSet = false;
1615
1616 if (BundleSet == true) return 0;
1617
1618 gBundlesSpec = calloc( DEFAULT_BUNDLE_SPEC_SIZE, sizeof(char) );
1619 gDriverSpec = calloc( DEFAULT_BUNDLE_SPEC_SIZE, sizeof(char) );
1620 gFileSpec = calloc( DEFAULT_BUNDLE_SPEC_SIZE, sizeof(char) );
1621 gTempSpec = calloc( DEFAULT_BUNDLE_SPEC_SIZE, sizeof(char) );
1622 gFileName = calloc( DEFAULT_BUNDLE_SPEC_SIZE, sizeof(char) );
1623
1624 if ( !gBundlesSpec || !gDriverSpec || !gFileSpec || !gTempSpec || !gFileName )
1625 goto error;
1626
1627 BundleSet = true;
1628
1629 return 0;
1630error:
1631 FreeBundleSupport();
1632 return 1;
1633}
1634
1635//==========================================================================
1636// LoadBundles
1637
1638long LoadBundles( char * dirSpec )
1639{
1640DBG("LoadBundles\n");
1641
1642 if ( InitBundleSupport() != 0 )
1643 return 1;
1644
1645
1646strlcpy(gBundlesSpec, dirSpec, DEFAULT_BUNDLE_SPEC_SIZE);
1647 strlcat(gBundlesSpec, "Modules", DEFAULT_BUNDLE_SPEC_SIZE);
1648 FileLoadBundles(gBundlesSpec, 0);
1649
1650
1651 MatchBundlesLibraries();
1652
1653 LoadMatchedBundles();
1654
1655DBG("LoadBundles Finished\n");
1656
1657 return 0;
1658}
1659
1660//==========================================================================
1661// FileLoadBundles
1662long
1663FileLoadBundles( char * dirSpec, long plugin )
1664{
1665 long ret, length, flags, time, bundleType;
1666 long long index;
1667 long result = -1;
1668 const char * name;
1669
1670DBG("FileLoadBundles in %s\n",dirSpec);
1671
1672 index = 0;
1673 while (1) {
1674 ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
1675 if (ret == -1) break;
1676
1677 // Make sure this is a directory.
1678 if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
1679
1680 // Make sure this is a kext.
1681 length = strlen(name);
1682 if (strncmp(name + length - 7, ".bundle",7)) continue;
1683
1684 // Save the file name.
1685 strlcpy(gFileName, name, DEFAULT_BUNDLE_SPEC_SIZE);
1686DBG("Load Bundles %s\n",gFileName);
1687
1688 // Determine the bundle type.
1689 snprintf(gTempSpec,DEFAULT_BUNDLE_SPEC_SIZE,"%s/%s", dirSpec, gFileName);
1690 ret = GetFileInfo(gTempSpec, "Contents", &flags, &time);
1691 if (ret == 0) bundleType = kCFBundleType2;
1692 else bundleType = kCFBundleType3;
1693
1694DBG("Bundles type = %d\n",bundleType);
1695
1696 if (!plugin)
1697 snprintf(gDriverSpec, DEFAULT_BUNDLE_SPEC_SIZE,"%s/%s/%sPlugIns", dirSpec, gFileName,
1698 (bundleType == kCFBundleType2) ? "Contents/" : "");
1699
1700 ret = LoadBundlePList( dirSpec, gFileName, bundleType);
1701
1702 if (result != 0)
1703result = ret;
1704
1705 if (!plugin)
1706FileLoadBundles(gDriverSpec, 1);
1707 }
1708
1709 return result;
1710}
1711
1712
1713static void add_bundle(BundlePtr module,char* name)
1714{
1715BundlePtr new_entry= malloc(sizeof(Bundle));
1716DBG("Adding bundle %s \n", name );
1717if (new_entry)
1718{
1719bzero(new_entry,sizeof(Bundle));
1720
1721new_entry->nextBundle = gBundleHead;
1722
1723gBundleHead = new_entry;
1724
1725new_entry->executablePath = module->executablePath;
1726 new_entry->bundlePath = module->bundlePath;
1727 new_entry->bundlePathLength = module->bundlePathLength;
1728 new_entry->plistAddr = module->plistAddr;
1729 new_entry->willLoad = module->willLoad;
1730 new_entry->dict = module->dict;
1731 new_entry->plistLength = module->plistLength;
1732 new_entry->personalities = module->personalities;
1733
1734}
1735
1736}
1737
1738//==========================================================================
1739// LoadBundlePList
1740
1741long
1742LoadBundlePList( char * dirSpec, char * name, long bundleType )
1743{
1744 long length, executablePathLength, bundlePathLength;
1745 BundlePtr module = 0;
1746 char * buffer = 0;
1747 char * tmpExecutablePath = 0;
1748 char * tmpBundlePath = 0;
1749 long ret = -1;
1750DBG("LoadBundlePList\n");
1751
1752 do {
1753 // Save the driver path.
1754
1755 snprintf(gFileSpec,DEFAULT_BUNDLE_SPEC_SIZE,"%s/%s/%s", dirSpec, name,
1756 (bundleType == kCFBundleType2) ? "Contents/MacOS/" : "");
1757 executablePathLength = strlen(gFileSpec) + 1;
1758
1759 tmpExecutablePath = calloc(executablePathLength,sizeof(char));
1760 if (tmpExecutablePath == 0) break;
1761
1762 strlcpy(tmpExecutablePath, gFileSpec, executablePathLength);
1763
1764 snprintf(gFileSpec, DEFAULT_BUNDLE_SPEC_SIZE,"%s/%s", dirSpec, name);
1765 bundlePathLength = strlen(gFileSpec) + 1;
1766
1767 tmpBundlePath = calloc(bundlePathLength,sizeof(char));
1768 if (tmpBundlePath == 0) break;
1769
1770 strlcpy(tmpBundlePath, gFileSpec, bundlePathLength);
1771
1772
1773 // Construct the file spec to the plist, then load it.
1774
1775 snprintf(gFileSpec, DEFAULT_BUNDLE_SPEC_SIZE,"%s/%s/%sInfo.plist", dirSpec, name,
1776 (bundleType == kCFBundleType2) ? "Contents/" : "");
1777
1778DBG("Loading Bundle PList %s\n",gFileSpec);
1779
1780 length = LoadFile(gFileSpec);
1781 if (length == -1) break;
1782
1783 length = length + 1;
1784 buffer = malloc(length);
1785 if (buffer == 0) break;
1786
1787bzero(buffer, length);
1788
1789 strlcpy(buffer, (char *)kLoadAddr, length);
1790
1791 // Parse the plist.
1792
1793 ret = ParseXML(buffer, &module);
1794 if (ret != 0 ) { printf("Unable to read plist of %s",name); break; }
1795
1796if (!module) {ret = -1;break;} // Should never happen but it will make the compiler happy
1797
1798 // Allocate memory for the driver path and the plist.
1799
1800 module->executablePath = tmpExecutablePath;
1801 module->bundlePath = tmpBundlePath;
1802 module->bundlePathLength = bundlePathLength;
1803 module->plistAddr = malloc(length);
1804
1805 if ((module->executablePath == 0) || (module->bundlePath == 0) || (module->plistAddr == 0))
1806 {
1807 if ( module->plistAddr ) free(module->plistAddr);
1808ret = -1;
1809 break;
1810 }
1811bzero(module->plistAddr, length);
1812
1813 // Add the plist to the module.
1814
1815 strlcpy(module->plistAddr, (char *)kLoadAddr, length);
1816 module->plistLength = length;
1817
1818 // Add the module to the module list.
1819
1820 add_bundle(module, name);
1821
1822
1823 ret = 0;
1824 }
1825 while (0);
1826
1827 if ( buffer ) free( buffer );
1828 if ( module ) free( module );
1829
1830 if (ret != 0) {
1831 if ( tmpExecutablePath ) free( tmpExecutablePath );
1832 if ( tmpBundlePath ) free( tmpBundlePath );
1833 }
1834 return ret;
1835}
1836
1837#define WillLoadBundles \
1838module = gBundleHead; \
1839while (module != NULL) \
1840{ \
1841if (module->willLoad == willLoad) \
1842{ \
1843prop = XMLGetProperty(module->dict, kPropCFBundleExecutable); \
1844\
1845if (prop != 0) \
1846{ \
1847fileName = prop->string; \
1848snprintf(gFileSpec, DEFAULT_BUNDLE_SPEC_SIZE,"%s%s", module->executablePath, fileName); \
1849\
1850module_start = (void*)load_module((char*)fileName,gFileSpec,module); \
1851if(!module_start || (*module_start == (void*)0xFFFFFFFF)) \
1852{ \
1853if (module->willLoad > BundlePrioritySystemLib) \
1854{ \
1855module->willLoad = BundlePriorityNull ; \
1856printf("Unable to start %s\n", gFileSpec); \
1857} \
1858} else module_start(); \
1859if (module->willLoad == BundlePrioritySystem) \
1860{ \
1861lookup_symbol = (void*)lookup_all_symbols(SYMBOLS_BUNDLE,SYMBOL_LOOKUP_SYMBOL); \
1862if((UInt32)lookup_symbol != 0xFFFFFFFF) \
1863{ \
1864msglog("%s successfully Loaded.\n", gFileSpec); \
1865} else return -1; \
1866} \
1867} \
1868} \
1869module = module->nextBundle; \
1870}
1871
1872//==========================================================================
1873// LoadMatchedBundles
1874
1875long LoadMatchedBundles( void )
1876{
1877 TagPtr prop;
1878 BundlePtr module;
1879 char *fileName;
1880 void (*module_start)(void);
1881 long willLoad;
1882
1883DBG("LoadMatchedBundles\n");
1884
1885int priority_end = MIN(gLowestLoadPriority+1, BundlePriorityEnd);
1886
1887 for (willLoad = BundlePrioritySystem; willLoad < priority_end ; willLoad++)
1888 {
1889
1890 WillLoadBundles ;
1891
1892 }
1893
1894 return 0;
1895}
1896
1897//==========================================================================
1898// MatchBundlesLibraries
1899
1900long MatchBundlesLibraries( void )
1901{
1902
1903 TagPtr prop, prop2;
1904 BundlePtr module, module2,dummy_module;
1905
1906 // Check for active modules with the same Bundle IDs or same principal class, only one must remain (except for type 3 aka system libs)
1907 {
1908 module = gBundleHead;
1909
1910 while (module != 0)
1911 {
1912 if (!(module->willLoad > BundlePriorityInit)) // if the module load priority is not higher than initialized, continue
1913 {
1914 module = module->nextBundle;
1915 continue;
1916 }
1917
1918 prop = XMLGetProperty(module->dict, kPropNSPrincipalClass);
1919 prop2 = XMLGetProperty(module->dict, kPropCFBundleIdentifier);
1920
1921 if (prop != 0 && prop2 != 0)
1922 {
1923 module2 = gBundleHead;
1924
1925 TagPtr prop3,prop4;
1926
1927 while (module2 != 0)
1928 {
1929 prop3 = XMLGetProperty(module2->dict, kPropNSPrincipalClass);
1930 prop4 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
1931
1932 if ((prop3 != 0) && (prop4 != 0) && (module != module2))
1933 {
1934
1935 if ((module2->willLoad == BundlePrioritySystemLib) && ((strcmp(prop2->string, prop4->string)!= 0) /*&& (!strcmp(prop->string, prop3->string))*/)) {
1936 continue;
1937 }
1938
1939 if ((!strcmp(prop2->string, prop4->string)) || (!strcmp(prop->string, prop3->string))) {
1940 if (module2->willLoad > BundlePriorityNull) module2->willLoad = BundlePriorityNull;
1941 }
1942
1943 }
1944 module2 = module2->nextBundle;
1945 }
1946
1947 }
1948
1949 module = module->nextBundle;
1950 }
1951 }
1952
1953 // Check for dependencies (it works in most cases, still a little buggy but should be sufficient for what we have to do,
1954// clearly the Achilles' heel of this implementation, please use dependencies with caution !!!)
1955 dummy_module = gBundleHead;
1956 while (dummy_module != 0)
1957 {
1958 module = gBundleHead;
1959
1960 while (module != 0)
1961 {
1962 if (module->willLoad > BundlePrioritySystemLib)
1963 {
1964 prop = XMLGetProperty(module->dict, kPropOSBundleLibraries);
1965 if (prop != 0)
1966 {
1967 prop = prop->tag;
1968 while (prop != 0)
1969 {
1970 module2 = gBundleHead;
1971 while (module2 != 0)
1972 {
1973 prop2 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
1974 if ((prop2 != 0) && (!strncmp(prop->string, prop2->string, strlen( prop->string))))
1975 {
1976 // found a parent
1977
1978 if (module2->willLoad > BundlePriorityInit)
1979 {
1980 // parent is active
1981 if (module->willLoad == BundlePriorityNull) {
1982 module->willLoad = BundlePriorityNormalPriority;
1983 }
1984
1985 // Check if the version of the parent >= version of the child
1986 if (strtol(XMLCastString ( XMLGetProperty(module2->dict,"CFBundleShortVersionString") ), NULL, 10) >= strtol(XMLCastString( prop->tag ), NULL, 10)) {
1987
1988 if ((module2->willLoad >= module->willLoad) && (module->willLoad > BundlePrioritySystemLib))
1989module->willLoad = MIN(MAX(module->willLoad, module2->willLoad+1), BundlePriorityLowestPriority); // child must be loaded after the parent, this allow the to find symbols of the parent while we bind the child.
1990
1991 } else {
1992 module->willLoad = BundlePriorityNull;
1993 goto nextmodule;
1994 }
1995 break;
1996 }
1997
1998 }
1999if (module->willLoad != BundlePriorityNull) module->willLoad = BundlePriorityNull;
2000 module2 = module2->nextBundle;
2001 }
2002 if (module->willLoad == BundlePriorityNull) goto nextmodule;
2003 prop = prop->tagNext;
2004 }
2005 }
2006 }
2007 nextmodule:
2008 module = module->nextBundle;
2009 }
2010
2011dummy_module = dummy_module->nextBundle;
2012 }
2013
2014 // Get the lowest load priority
2015 {
2016 gLowestLoadPriority = BundlePriorityNormalPriority;
2017 module = gBundleHead;
2018
2019 while (module != 0)
2020 {
2021 if (module->willLoad > BundlePriorityInit)
2022 {
2023 gLowestLoadPriority = MIN(MAX(module->willLoad,gLowestLoadPriority), BundlePriorityLowestPriority);
2024 }
2025 module = module->nextBundle;
2026 }
2027 }
2028
2029 return 0;
2030}
2031
2032
2033//==========================================================================
2034// FindBundle
2035
2036static BundlePtr
2037FindBundle( char * bundle_id )
2038{
2039 BundlePtr module;
2040 TagPtr prop;
2041DBG("FindBundle %s\n",bundle_id);
2042
2043 module = gBundleHead;
2044
2045 while (module != 0)
2046 {
2047 prop = XMLGetProperty(module->dict, kPropCFBundleIdentifier);
2048 if ((prop != 0) && !strcmp(bundle_id, prop->string)) break;
2049 module = module->nextBundle;
2050 }
2051
2052 return module;
2053}
2054
2055//==========================================================================
2056// GetBundleDict
2057
2058void *
2059GetBundleDict( char * bundle_id )
2060{
2061 BundlePtr module;
2062DBG("GetBundleDict %s\n",bundle_id);
2063
2064 module = FindBundle( bundle_id );
2065
2066 if (module != 0)
2067 {
2068 return (void *)module->dict;
2069 }
2070
2071 return 0;
2072}
2073
2074//==========================================================================
2075// GetBundlePersonality
2076
2077void *
2078GetBundlePersonality( char * bundle_id )
2079{
2080 BundlePtr module;
2081DBG("GetBundlePersonalities %s\n",bundle_id);
2082
2083 module = FindBundle( bundle_id );
2084
2085 if (module != 0)
2086 {
2087 return (void *)module->personalities;
2088 }
2089
2090 return 0;
2091}
2092
2093//==========================================================================
2094// GetBundlePath
2095
2096char *
2097GetBundlePath( char * bundle_id )
2098{
2099 BundlePtr module;
2100DBG("GetBundlePath %s\n",bundle_id);
2101
2102 module = FindBundle( bundle_id );
2103
2104 if (module != 0)
2105 {
2106 return module->bundlePath;
2107 }
2108
2109 return 0;
2110}
2111
2112//==========================================================================
2113// ParseXML
2114
2115static long
2116ParseXML( char * buffer, BundlePtr * module )
2117{
2118long length, pos;
2119TagPtr moduleDict, prop;
2120BundlePtr tmpBundle;
2121
2122 pos = 0;
2123DBG("ParseXML\n");
2124
2125if (!module) {
2126 return -1;
2127 }
2128
2129 while (1)
2130 {
2131 length = XMLParseNextTag(buffer + pos, &moduleDict);
2132 if (length == -1) break;
2133
2134 pos += length;
2135
2136 if (moduleDict == 0) continue;
2137 if (moduleDict->type == kTagTypeDict) break;
2138
2139 XMLFreeTag(moduleDict);
2140 }
2141
2142 if (length == -1)
2143 {
2144 return -1;
2145 }
2146
2147
2148 tmpBundle = malloc(sizeof(Bundle));
2149 if (tmpBundle == 0)
2150 {
2151 XMLFreeTag(moduleDict);
2152 return -1;
2153 }
2154bzero(tmpBundle, sizeof(Bundle));
2155
2156 tmpBundle->dict = moduleDict;
2157
2158 do {
2159 prop = XMLGetProperty(moduleDict, kPropOSBundleEnabled);
2160 if ((prop != 0) && prop->string)
2161 {
2162 if ( (strlen(prop->string) >= 1) && (prop->string[0] == 'N' || prop->string[0] == 'n') )
2163 {
2164 tmpBundle->willLoad = 0;
2165 break;
2166 }
2167 }
2168 prop = XMLGetProperty(moduleDict, kPropNSPrincipalClass);
2169 if ((prop != 0) && prop->string)
2170 {
2171 if (!strncmp(prop->string,SYSLIB_CLASS, sizeof(SYSLIB_CLASS)))
2172 {
2173 tmpBundle->willLoad = BundlePrioritySystemLib;
2174 break;
2175 }
2176 if (!strncmp(prop->string,SYS_CLASS, sizeof(SYS_CLASS)))
2177 {
2178 tmpBundle->willLoad = BundlePrioritySystem;
2179 break;
2180 }
2181 }
2182
2183 prop = XMLGetProperty(moduleDict, kPropOSBundlePriority);
2184 if ((prop != 0) && prop->string)
2185 {
2186 int tmpwillLoad;
2187 if ((tmpwillLoad = strtoul(prop->string, NULL, 10)) > BundlePrioritySystemLib )
2188 {
2189 tmpBundle->willLoad = MIN(tmpwillLoad, BundlePriorityLowestPriority);
2190 break;
2191
2192 }
2193
2194 }
2195
2196 tmpBundle->willLoad = BundlePriorityNormalPriority;
2197
2198#if 0
2199prop = XMLGetProperty(moduleDict, kPropCFBundleLocalizations);
2200 if ((prop != 0) && prop->string)
2201 {
2202char * path = newStringWithFormat("%s%s",module->bundlePath,prop->string);
2203if (path == NULL) {
2204break;
2205}
2206
2207 if (loadConfigFile(path, module->LanguageConfig) != 0)
2208{
2209free(path);
2210path = NULL;
2211
2212const char * default_local;
2213if ((default_local = getStringForKey(kPropCFBundleLocalizations, DEFAULT_BOOT_CONFIG)))
2214{
2215path = newStringWithFormat("%s%s",module->bundlePath,default_local);
2216if (path == NULL) {
2217break;
2218}
2219loadConfigFile(path, module->LanguageConfig);
2220}
2221
2222}
2223
2224if (path) {
2225free(path);
2226}
2227 }
2228#endif
2229
2230 } while (0);
2231
2232 // Get the personalities.
2233 tmpBundle->personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);
2234
2235 *module = tmpBundle;
2236
2237
2238
2239 return 0;
2240}
2241

Archive Download this file

Revision: HEAD