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//pool_t workspace;
1429char *plistAddr;
1430long plistLength;
1431char *executablePath;
1432char *bundlePath;
1433long bundlePathLength;
1434};
1435typedef struct Module Module, *ModulePtr;
1436
1437
1438enum {
1439kCFBundleType2,
1440kCFBundleType3
1441};
1442
1443enum {
1444BundlePriorityNull = 0,
1445BundlePriorityInit = 1,
1446BundlePrioritySystem = 2,
1447BundlePrioritySystemLib = 3,
1448 BundlePriorityNormalPriority = 4,
1449 BundlePriorityLowestPriority = 99,
1450BundlePriorityEnd = 100 // can not be assigned
1451
1452};
1453
1454static ModulePtr gModuleHead;
1455static char * gModulesSpec;
1456static char * gDriverSpec;
1457static char * gFileSpec;
1458static char * gTempSpec;
1459static char * gFileName;
1460static int gLowestLoadPriority;
1461
1462static long ParseXML(char *buffer, ModulePtr *module);
1463static ModulePtr FindBundle( char * bundle_id );
1464
1465static void
1466FreeBundleSupport( void )
1467{
1468
1469 if ( gModulesSpec ) free(gModulesSpec);
1470 if ( gDriverSpec) free(gDriverSpec);
1471 if ( gFileSpec ) free(gFileSpec);
1472 if ( gTempSpec ) free(gTempSpec);
1473 if ( gFileName ) free(gFileName);
1474}
1475
1476//==========================================================================
1477// InitBundleSupport
1478
1479long
1480InitBundleSupport( void )
1481{
1482DBG("InitBundleSupport\n");
1483
1484 static bool BundleSet = false;
1485
1486 if (BundleSet == true) return 0;
1487
1488 gModulesSpec = malloc( 4096 );
1489 gDriverSpec = malloc( 4096 );
1490 gFileSpec = malloc( 4096 );
1491 gTempSpec = malloc( 4096 );
1492 gFileName = malloc( 4096 );
1493
1494 if ( !gModulesSpec || !gDriverSpec || !gFileSpec || !gTempSpec || !gFileName )
1495 goto error;
1496
1497 BundleSet = true;
1498
1499 return 0;
1500error:
1501 FreeBundleSupport();
1502 return 1;
1503}
1504
1505//==========================================================================
1506// LoadBundles
1507
1508long LoadBundles( char * dirSpec )
1509{
1510DBG("LoadBundles\n");
1511
1512 if ( InitBundleSupport() != 0 )
1513 return 1;
1514
1515
1516strlcpy(gModulesSpec, dirSpec, 4096);
1517 strlcat(gModulesSpec, "Modules", 4096 - 1);
1518 FileLoadBundles(gModulesSpec, 0);
1519
1520
1521 MatchBundlesLibraries();
1522
1523 LoadMatchedBundles();
1524
1525DBG("LoadBundles Finished\n");
1526
1527 return 0;
1528}
1529
1530//==========================================================================
1531// FileLoadBundles
1532long
1533FileLoadBundles( char * dirSpec, long plugin )
1534{
1535 long ret, length, flags, time, bundleType;
1536 long long index;
1537 long result = -1;
1538 const char * name;
1539
1540DBG("FileLoadBundles in %s\n",dirSpec);
1541
1542 index = 0;
1543 while (1) {
1544 ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
1545 if (ret == -1) break;
1546
1547 // Make sure this is a directory.
1548 if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
1549
1550 // Make sure this is a kext.
1551 length = strlen(name);
1552 if (strcmp(name + length - 7, ".bundle")) continue;
1553
1554 // Save the file name.
1555 strlcpy(gFileName, name, 4096);
1556DBG("Load Bundles %s\n",gFileName);
1557
1558 // Determine the bundle type.
1559 sprintf(gTempSpec, "%s/%s", dirSpec, gFileName);
1560 ret = GetFileInfo(gTempSpec, "Contents", &flags, &time);
1561 if (ret == 0) bundleType = kCFBundleType2;
1562 else bundleType = kCFBundleType3;
1563
1564DBG("Bundles type = %d\n",bundleType);
1565
1566 if (!plugin)
1567 sprintf(gDriverSpec, "%s/%s/%sPlugIns", dirSpec, gFileName,
1568 (bundleType == kCFBundleType2) ? "Contents/" : "");
1569
1570 ret = LoadBundlePList( dirSpec, gFileName, bundleType);
1571
1572 if (result != 0)
1573result = ret;
1574
1575 if (!plugin)
1576FileLoadBundles(gDriverSpec, 1);
1577 }
1578
1579 return result;
1580}
1581
1582
1583static void add_bundle(ModulePtr module,char* name)
1584{
1585ModulePtr new_entry= malloc(sizeof(Module));
1586DBG("Adding bundle %s \n", name );
1587if (new_entry)
1588{
1589new_entry->nextModule = gModuleHead;
1590
1591gModuleHead = new_entry;
1592
1593new_entry->executablePath = module->executablePath;
1594 new_entry->bundlePath = module->bundlePath;
1595 new_entry->bundlePathLength = module->bundlePathLength;
1596 new_entry->plistAddr = module->plistAddr;
1597 new_entry->willLoad = module->willLoad;
1598 new_entry->dict = module->dict;
1599 new_entry->plistLength = module->plistLength;
1600 new_entry->personalities = module->personalities;
1601
1602}
1603
1604}
1605
1606//==========================================================================
1607// LoadBundlePList
1608
1609long
1610LoadBundlePList( char * dirSpec, char * name, long bundleType )
1611{
1612 long length, executablePathLength, bundlePathLength;
1613 ModulePtr module = 0;
1614 char * buffer = 0;
1615 char * tmpExecutablePath = 0;
1616 char * tmpBundlePath = 0;
1617 long ret = -1;
1618DBG("LoadBundlePList\n");
1619
1620 do {
1621 // Save the driver path.
1622
1623 sprintf(gFileSpec, "%s/%s/%s", dirSpec, name,
1624 (bundleType == kCFBundleType2) ? "Contents/MacOS/" : "");
1625 executablePathLength = strlen(gFileSpec) + 1;
1626
1627 tmpExecutablePath = malloc(executablePathLength);
1628 if (tmpExecutablePath == 0) break;
1629
1630 strlcpy(tmpExecutablePath, gFileSpec, executablePathLength);
1631
1632 sprintf(gFileSpec, "%s/%s", dirSpec, name);
1633 bundlePathLength = strlen(gFileSpec) + 1;
1634
1635 tmpBundlePath = malloc(bundlePathLength);
1636 if (tmpBundlePath == 0) break;
1637
1638 strlcpy(tmpBundlePath, gFileSpec, bundlePathLength);
1639
1640
1641 // Construct the file spec to the plist, then load it.
1642
1643 sprintf(gFileSpec, "%s/%s/%sInfo.plist", dirSpec, name,
1644 (bundleType == kCFBundleType2) ? "Contents/" : "");
1645
1646DBG("Loading Bundle PList %s\n",gFileSpec);
1647
1648 length = LoadFile(gFileSpec);
1649 if (length == -1) break;
1650
1651 length = length + 1;
1652 buffer = malloc(length);
1653 if (buffer == 0) break;
1654
1655 strlcpy(buffer, (char *)kLoadAddr, length);
1656
1657 // Parse the plist.
1658
1659 ret = ParseXML(buffer, &module);
1660 if (ret != 0 ) { printf("Unable to read plist of %s",name); break; }
1661
1662if (!module) {ret = -1;break;} // Should never happen but it will make the compiler happy
1663
1664 // Allocate memory for the driver path and the plist.
1665
1666 module->executablePath = tmpExecutablePath;
1667 module->bundlePath = tmpBundlePath;
1668 module->bundlePathLength = bundlePathLength;
1669 module->plistAddr = malloc(length);
1670
1671 if ((module->executablePath == 0) || (module->bundlePath == 0) || (module->plistAddr == 0))
1672 {
1673 if ( module->plistAddr ) free(module->plistAddr);
1674ret = -1;
1675 break;
1676 }
1677
1678 // Add the plist to the module.
1679
1680 strlcpy(module->plistAddr, (char *)kLoadAddr, length);
1681 module->plistLength = length;
1682
1683 // Add the module to the module list.
1684
1685 add_bundle(module, name);
1686
1687
1688 ret = 0;
1689 }
1690 while (0);
1691
1692 if ( buffer ) free( buffer );
1693 if ( module ) free( module );
1694
1695 if (ret != 0) {
1696 if ( tmpExecutablePath ) free( tmpExecutablePath );
1697 if ( tmpBundlePath ) free( tmpBundlePath );
1698 }
1699 return ret;
1700}
1701
1702#define WillLoadBundles \
1703module = gModuleHead; \
1704while (module != NULL) \
1705{ \
1706if (module->willLoad == willLoad) \
1707{ \
1708prop = XMLGetProperty(module->dict, kPropCFBundleExecutable); \
1709\
1710if (prop != 0) \
1711{ \
1712fileName = prop->string; \
1713sprintf(gFileSpec, "%s%s", module->executablePath, fileName); \
1714\
1715module_start = (void*)load_module((char*)fileName,gFileSpec); \
1716if(!module_start || (*module_start == (void*)0xFFFFFFFF)) \
1717{ \
1718if (module->willLoad > BundlePrioritySystemLib) \
1719{ \
1720module->willLoad = BundlePriorityNull ; \
1721printf("Unable to start %s\n", gFileSpec); \
1722} \
1723} else module_start(); \
1724if (module->willLoad == BundlePrioritySystem) \
1725{ \
1726lookup_symbol = (void*)lookup_all_symbols(SYMBOLS_BUNDLE,SYMBOL_LOOKUP_SYMBOL); \
1727if((UInt32)lookup_symbol != 0xFFFFFFFF) \
1728{ \
1729msglog("%s successfully Loaded.\n", gFileSpec); \
1730} else return -1; \
1731} \
1732} \
1733} \
1734module = module->nextModule; \
1735}
1736
1737//==========================================================================
1738// LoadMatchedBundles
1739
1740long LoadMatchedBundles( void )
1741{
1742 TagPtr prop;
1743 ModulePtr module;
1744 char *fileName;
1745 void (*module_start)(void);
1746 long willLoad;
1747
1748DBG("LoadMatchedBundles\n");
1749
1750int priority_end = MIN(gLowestLoadPriority+1, BundlePriorityEnd);
1751
1752 for (willLoad = BundlePrioritySystem; willLoad < priority_end ; willLoad++)
1753 {
1754
1755 WillLoadBundles ;
1756
1757 }
1758
1759 return 0;
1760}
1761
1762//==========================================================================
1763// MatchBundlesLibraries
1764
1765long MatchBundlesLibraries( void )
1766{
1767
1768 TagPtr prop, prop2;
1769 ModulePtr module, module2,dummy_module;
1770
1771 // Check for active modules with the same Bundle IDs or same principal class, only one must remain (except for type 3 aka system libs)
1772 {
1773 module = gModuleHead;
1774
1775 while (module != 0)
1776 {
1777 if (!(module->willLoad > BundlePriorityInit)) // if the module load priority is not higher than initialized, continue
1778 {
1779 module = module->nextModule;
1780 continue;
1781 }
1782
1783 prop = XMLGetProperty(module->dict, kPropNSPrincipalClass);
1784 prop2 = XMLGetProperty(module->dict, kPropCFBundleIdentifier);
1785
1786 if (prop != 0 && prop2 != 0)
1787 {
1788 module2 = gModuleHead;
1789
1790 TagPtr prop3,prop4;
1791
1792 while (module2 != 0)
1793 {
1794 prop3 = XMLGetProperty(module2->dict, kPropNSPrincipalClass);
1795 prop4 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
1796
1797 if ((prop3 != 0) && (prop4 != 0) && (module != module2))
1798 {
1799
1800 if ((module2->willLoad == BundlePrioritySystemLib) && ((strcmp(prop2->string, prop4->string)!= 0) /*&& (!strcmp(prop->string, prop3->string))*/)) {
1801 continue;
1802 }
1803
1804 if ((!strcmp(prop2->string, prop4->string)) || (!strcmp(prop->string, prop3->string))) {
1805 if (module2->willLoad > BundlePriorityNull) module2->willLoad = BundlePriorityNull;
1806 }
1807
1808 }
1809 module2 = module2->nextModule;
1810 }
1811
1812 }
1813
1814 module = module->nextModule;
1815 }
1816 }
1817
1818 // Check for dependencies (it works in most cases, still a little buggy but should be sufficient for what we have to do,
1819// clearly the Achilles' heel of this implementation, please use dependencies with caution !!!)
1820 dummy_module = gModuleHead;
1821 while (dummy_module != 0)
1822 {
1823 module = gModuleHead;
1824
1825 while (module != 0)
1826 {
1827 if (module->willLoad > BundlePrioritySystemLib)
1828 {
1829 prop = XMLGetProperty(module->dict, kPropOSBundleLibraries);
1830 if (prop != 0)
1831 {
1832 prop = prop->tag;
1833 while (prop != 0)
1834 {
1835 module2 = gModuleHead;
1836 while (module2 != 0)
1837 {
1838 prop2 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
1839 if ((prop2 != 0) && (!strncmp(prop->string, prop2->string, strlen( prop->string))))
1840 {
1841 // found a parent
1842
1843 if (module2->willLoad > BundlePriorityInit)
1844 {
1845 // parent is active
1846 if (module->willLoad == BundlePriorityNull) {
1847 module->willLoad = BundlePriorityNormalPriority;
1848 }
1849
1850 // Check if the version of the parent >= version of the child
1851 if (strtol(XMLCastString ( XMLGetProperty(module2->dict,"CFBundleShortVersionString") ), NULL, 10) >= strtol(XMLCastString( prop->tag ), NULL, 10)) {
1852
1853 if ((module2->willLoad >= module->willLoad) && (module->willLoad > BundlePrioritySystemLib))
1854module->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.
1855
1856 } else {
1857 module->willLoad = BundlePriorityNull;
1858 goto nextmodule;
1859 }
1860 break;
1861 }
1862
1863 }
1864if (module->willLoad != BundlePriorityNull) module->willLoad = BundlePriorityNull;
1865 module2 = module2->nextModule;
1866 }
1867 if (module->willLoad == BundlePriorityNull) goto nextmodule;
1868 prop = prop->tagNext;
1869 }
1870 }
1871 }
1872 nextmodule:
1873 module = module->nextModule;
1874 }
1875
1876dummy_module = dummy_module->nextModule;
1877 }
1878
1879 // Get the lowest load priority
1880 {
1881 gLowestLoadPriority = BundlePriorityNormalPriority;
1882 module = gModuleHead;
1883
1884 while (module != 0)
1885 {
1886 if (module->willLoad > BundlePriorityInit)
1887 {
1888 gLowestLoadPriority = MIN(module->willLoad, BundlePriorityLowestPriority);
1889 }
1890 module = module->nextModule;
1891 }
1892 }
1893
1894 return 0;
1895}
1896
1897
1898//==========================================================================
1899// FindBundle
1900
1901static ModulePtr
1902FindBundle( char * bundle_id )
1903{
1904 ModulePtr module;
1905 TagPtr prop;
1906DBG("FindBundle %s\n",bundle_id);
1907
1908 module = gModuleHead;
1909
1910 while (module != 0)
1911 {
1912 prop = XMLGetProperty(module->dict, kPropCFBundleIdentifier);
1913 if ((prop != 0) && !strcmp(bundle_id, prop->string)) break;
1914 module = module->nextModule;
1915 }
1916
1917 return module;
1918}
1919
1920//==========================================================================
1921// GetBundleDict
1922
1923void *
1924GetBundleDict( char * bundle_id )
1925{
1926 ModulePtr module;
1927DBG("GetBundleDict %s\n",bundle_id);
1928
1929 module = FindBundle( bundle_id );
1930
1931 if (module != 0)
1932 {
1933 return (void *)module->dict;
1934 }
1935
1936 return 0;
1937}
1938
1939//==========================================================================
1940// GetBundlePersonality
1941
1942void *
1943GetBundlePersonality( char * bundle_id )
1944{
1945 ModulePtr module;
1946DBG("GetBundlePersonalities %s\n",bundle_id);
1947
1948 module = FindBundle( bundle_id );
1949
1950 if (module != 0)
1951 {
1952 return (void *)module->personalities;
1953 }
1954
1955 return 0;
1956}
1957
1958//==========================================================================
1959// GetBundlePath
1960
1961char *
1962GetBundlePath( char * bundle_id )
1963{
1964 ModulePtr module;
1965DBG("GetBundlePath %s\n",bundle_id);
1966
1967 module = FindBundle( bundle_id );
1968
1969 if (module != 0)
1970 {
1971 return module->bundlePath;
1972 }
1973
1974 return 0;
1975}
1976
1977//==========================================================================
1978// ParseXML
1979
1980static long
1981ParseXML( char * buffer, ModulePtr * module )
1982{
1983long length, pos;
1984TagPtr moduleDict, prop;
1985ModulePtr tmpModule;
1986
1987 pos = 0;
1988DBG("ParseXML\n");
1989
1990if (!module) {
1991 return -1;
1992 }
1993
1994 while (1)
1995 {
1996 length = XMLParseNextTag(buffer + pos, &moduleDict);
1997 if (length == -1) break;
1998
1999 pos += length;
2000
2001 if (moduleDict == 0) continue;
2002 if (moduleDict->type == kTagTypeDict) break;
2003
2004 XMLFreeTag(moduleDict);
2005 }
2006
2007 if (length == -1)
2008 {
2009 return -1;
2010 }
2011
2012
2013 tmpModule = malloc(sizeof(Module));
2014 if (tmpModule == 0)
2015 {
2016 XMLFreeTag(moduleDict);
2017 return -1;
2018 }
2019 tmpModule->dict = moduleDict;
2020
2021 do {
2022 prop = XMLGetProperty(moduleDict, kPropOSBundleEnabled);
2023 if ((prop != 0) && prop->string)
2024 {
2025 if ( (strlen(prop->string) >= 1) && (prop->string[0] == 'N' || prop->string[0] == 'n') )
2026 {
2027 tmpModule->willLoad = 0;
2028 break;
2029 }
2030 }
2031 prop = XMLGetProperty(moduleDict, kPropNSPrincipalClass);
2032 if ((prop != 0) && prop->string)
2033 {
2034 if (!strcmp(prop->string,SYSLIB_CLASS))
2035 {
2036 tmpModule->willLoad = BundlePrioritySystemLib;
2037 break;
2038 }
2039 if (!strcmp(prop->string,SYS_CLASS))
2040 {
2041 tmpModule->willLoad = BundlePrioritySystem;
2042 break;
2043 }
2044 }
2045
2046 prop = XMLGetProperty(moduleDict, kPropOSBundlePriority);
2047 if ((prop != 0) && prop->string)
2048 {
2049 int tmpwillLoad;
2050 if ((tmpwillLoad = strtoul(prop->string, NULL, 10)) > BundlePrioritySystemLib )
2051 {
2052 tmpModule->willLoad = MIN(tmpwillLoad, BundlePriorityLowestPriority);
2053 break;
2054
2055 }
2056
2057 }
2058
2059 tmpModule->willLoad = BundlePriorityNormalPriority;
2060
2061 } while (0);
2062
2063 // Get the personalities.
2064 tmpModule->personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);
2065
2066 *module = tmpModule;
2067
2068
2069
2070 return 0;
2071}
2072

Archive Download this file

Revision: 1972