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

Archive Download this file

Revision: 1931