Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2112