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

Archive Download this file

Revision: 2044