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

Archive Download this file

Revision: 2156