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

Archive Download this file

Revision: 2154