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

Archive Download this file

Revision: 2118