Chameleon

Chameleon Svn Source Tree

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

1/*
2 * Copyright 2010 Evan Lojewski. All rights reserved.
3 *
4 */
5
6#include "boot.h"
7#include "bootstruct.h"
8#include "multiboot.h"
9#include "modules.h"
10
11#ifndef DEBUG_MODULES
12#define DEBUG_MODULES 0
13#endif
14
15#if DEBUG_MODULES
16#define DBG(x...)printf(x)
17#else
18#define DBG(x...)
19#endif
20
21// NOTE: Global so that modules can link with this
22unsigned long long textAddress = 0;
23unsigned long long textSection = 0;
24
25moduleHook_t* moduleCallbacks = NULL;
26moduleList_t* loadedModules = NULL;
27symbolList_t* moduleSymbols = NULL;
28unsigned int (*lookup_symbol)(const char*) = NULL;
29
30#if DEBUG_MODULES
31VOID print_hook_list()
32{
33moduleHook_t* hooks = moduleCallbacks;
34printf("Hook list: \n");
35while(hooks)
36{
37printf("* %s\n", hooks->name);
38hooks = hooks->next;
39}
40printf("\n");
41}
42
43VOID print_symbol_list()
44{
45symbolList_t* symbol = moduleSymbols;
46printf("Symbol list: \n");
47while(symbol)
48{
49printf("* %s\n", symbol->symbol);
50symbol = symbol->next;
51}
52printf("\n");
53}
54#endif
55
56
57/*
58 * Initialize the module system by loading the Symbols.dylib module.
59 * Once loaded, locate the _lookup_symbol function so that internal
60 * symbols can be resolved.
61 */
62EFI_STATUS init_module_system()
63{
64msglog("* Attempting to load system module\n");
65
66// Intialize module system
67 EFI_STATUS status = load_module(SYMBOLS_MODULE);
68if((status == EFI_SUCCESS) || (status == EFI_ALREADY_STARTED)/*should never happen*/ )
69{
70lookup_symbol = (void*)lookup_all_symbols(SYMBOL_LOOKUP_SYMBOL);
71
72if((UInt32)lookup_symbol != 0xFFFFFFFF)
73{
74return status;
75}
76
77}
78
79return EFI_LOAD_ERROR;
80}
81
82
83/*
84 * Load all modules in the /Extra/modules/ directory
85 * Module depencdies will be loaded first
86 * MOdules will only be loaded once. When loaded a module must
87 * setup apropriete function calls and hooks as required.
88 * NOTE: To ensure a module loads after another you may
89 * link one module with the other. For dyld to allow this, you must
90 * reference at least one symbol within the module.
91 */
92
93VOID load_all_modules()
94{
95char* name;
96long flags;
97long time;
98struct dirstuff* moduleDir = opendir("/Extra/modules/");
99while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)
100{
101if ((strcmp(SYMBOLS_MODULE,name)) == 0) continue; // if we found Symbols.dylib, just skip it
102
103int len = strlen(name);
104int ext_size = sizeof("dylib");
105
106if (len >= ext_size)
107{
108if(strcmp(&name[len - ext_size], ".dylib") == 0)
109{
110char* tmp = malloc(len /*+ 1*/);
111strlcpy(tmp, name, len + 1);
112msglog("* Attempting to load module: %s\n", tmp);
113if(load_module(tmp) != EFI_SUCCESS)
114{
115// failed to load or already loaded
116free(tmp);
117}
118}
119#if DEBUG_MODULES
120else
121{
122DBG("Ignoring %s\n", name);
123}
124#endif
125}
126#if DEBUG_MODULES
127else
128{
129DBG("Ignoring %s\n", name);
130}
131#endif
132
133}
134#if DEBUG_MODULES
135print_symbol_list();
136#endif
137}
138
139/*
140 * Load a module file in /Extra/modules
141 * TODO: verify version number of module
142 */
143EFI_STATUS load_module(char* module)
144{
145void (*module_start)(void) = NULL;
146
147
148// Check to see if the module has already been loaded
149if(is_module_loaded(module) == EFI_SUCCESS)
150{
151msglog("Module %s already registred\n", module);
152return EFI_ALREADY_STARTED;
153}
154
155char modString[128];
156int fh = -1;
157sprintf(modString, "/Extra/modules/%s", module);
158fh = open(modString);
159if(fh < 0)
160{
161#if DEBUG_MODULES
162DBG("Unable to locate module %s\n", modString);
163getc();
164#else
165msglog("Unable to locate module %s\n", modString);
166#endif
167return EFI_OUT_OF_RESOURCES;
168}
169EFI_STATUS ret = EFI_SUCCESS;
170
171{
172int moduleSize = file_size(fh);
173char* module_base = (char*) malloc(moduleSize);
174if (moduleSize && read(fh, module_base, moduleSize) == moduleSize)
175{
176
177DBG("Module %s read in.\n", modString);
178
179// Module loaded into memory, parse it
180module_start = parse_mach(module_base, &load_module, &add_symbol);
181
182if(module_start && module_start != (void*)0xFFFFFFFF)
183{
184module_loaded(module/*moduleName, moduleVersion, moduleCompat*/);
185// Notify the system that it was laoded
186(*module_start)();// Start the module
187msglog("%s successfully Loaded.\n", module);
188}
189else
190{
191// The module does not have a valid start function
192printf("Unable to start %s\n", module);
193ret = EFI_NOT_STARTED;
194#if DEBUG_MODULES
195getc();
196#endif
197}
198}
199else
200{
201printf("Unable to read in module %s\n.", module);
202#if DEBUG_MODULES
203getc();
204#endif
205ret = EFI_LOAD_ERROR;
206}
207}
208close(fh);
209return ret;
210}
211
212moduleHook_t* get_callback(const char* name)
213{
214moduleHook_t* hooks = moduleCallbacks;
215
216// look for a hook. If it exists, return the moduleHook_t*,
217// If not, return NULL.
218while(hooks)
219{
220if(strcmp(name, hooks->name) == 0)
221{
222//DBG("Located hook %s\n", name);
223return hooks;
224}
225hooks = hooks->next;
226}
227return NULL;
228
229}
230
231/*
232 *execute_hook( const char* name )
233 *name - Name of the module hook
234 *If any callbacks have been registered for this hook
235 *they will be executed now in the same order that the
236 *hooks were added.
237 */
238EFI_STATUS execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6)
239{
240DBG("Attempting to execute hook '%s'\n", name);
241moduleHook_t* hook = get_callback(name);
242
243if(hook)
244{
245// Loop through all callbacks for this module
246callbackList_t* callbacks = hook->callbacks;
247
248while(callbacks)
249{
250// Execute callback
251callbacks->callback(arg1, arg2, arg3, arg4, arg5, arg6);
252callbacks = callbacks->next;
253}
254DBG("Hook '%s' executed.\n", name);
255return EFI_SUCCESS;
256}
257
258// Callback for this hook doesn't exist;
259DBG("No callbacks for '%s' hook.\n", name);
260return EFI_NOT_FOUND;
261
262}
263
264/*
265 *register_hook_callback( const char* name, void(*callback)())
266 *name - Name of the module hook to attach to.
267 *callbacks - The funciton pointer that will be called when the
268 *hook is executed. When registering a new callback name, the callback is added sorted.
269 *NOTE: the hooks take four void* arguments.
270 */
271VOID register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*, void*, void*))
272{
273DBG("Adding callback for '%s' hook.\n", name);
274
275moduleHook_t* hook = get_callback(name);
276
277if(hook)
278{
279// append
280callbackList_t* newCallback = malloc(sizeof(callbackList_t));
281newCallback->next = hook->callbacks;
282hook->callbacks = newCallback;
283newCallback->callback = callback;
284}
285else
286{
287// create new hook
288moduleHook_t* newHook = malloc(sizeof(moduleHook_t));
289newHook->name = name;
290newHook->callbacks = malloc(sizeof(callbackList_t));
291newHook->callbacks->callback = callback;
292newHook->callbacks->next = NULL;
293
294newHook->next = moduleCallbacks;
295moduleCallbacks = newHook;
296
297}
298
299#if DEBUG_MODULES
300print_hook_list();
301getc();
302#endif
303
304}
305
306#if DEBUG_MODULES
307unsigned long vmaddr;
308long vmsize;
309#endif
310
311/*
312 * Parse through a macho module. The module will be rebased and binded
313 * as specified in the macho header. If the module is successfully loaded
314 * the module iinit address will be returned.
315 * NOTE; all dependecies will be loaded before this module is started
316 * NOTE: If the module is unable to load ot completeion, the modules
317 * symbols will still be available (TODO: fix this). This should not
318 * happen as all dependencies are verified before the sybols are read in.
319 */
320void* parse_mach(void* binary, EFI_STATUS(*dylib_loader)(char*), long long(*symbol_handler)(char*, long long, char))// TODO: add param to specify valid archs
321{
322char is64 = false;
323void (*module_start)(void) = NULL;
324
325// Module info
326/*char* moduleName = NULL;
327UInt32 moduleVersion = 0;
328UInt32 moduleCompat = 0;
329*/
330
331// TODO convert all of the structs to a union
332struct dyld_info_command* dyldInfoCommand = NULL;
333struct symtab_command* symtabCommand = NULL;
334
335{
336struct segment_command *segCommand = NULL;
337struct segment_command_64 *segCommand64 = NULL;
338struct dylib_command* dylibCommand = NULL;
339struct load_command *loadCommand = NULL;
340UInt32 binaryIndex = 0;
341UInt16 cmd = 0;
342
343// Parse through the load commands
344if(((struct mach_header*)binary)->magic == MH_MAGIC)
345{
346is64 = false;
347binaryIndex += sizeof(struct mach_header);
348}
349else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
350{
351// NOTE: modules cannot be 64bit...
352is64 = true;
353binaryIndex += sizeof(struct mach_header_64);
354}
355else
356{
357printf("Modules: Invalid mach magic\n");
358getc();
359return NULL;
360}
361
362
363
364/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
365 {
366 printf("Module is not a dylib. Unable to load.\n");
367 getc();
368 return NULL; // Module is in the incorrect format
369 }*/
370
371while(cmd < ((struct mach_header*)binary)->ncmds)
372{
373cmd++;
374
375loadCommand = binary + binaryIndex;
376UInt32 cmdSize = loadCommand->cmdsize;
377
378
379switch ((loadCommand->cmd & 0x7FFFFFFF))
380{
381case LC_SYMTAB:
382symtabCommand = binary + binaryIndex;
383break;
384
385case LC_SEGMENT: // 32bit macho
386{
387segCommand = binary + binaryIndex;
388
389//printf("Segment name is %s\n", segCommand->segname);
390
391if(strcmp("__TEXT", segCommand->segname) == 0)
392{
393UInt32 sectionIndex;
394
395#if HARD_DEBUG_MODULES
396unsigned long fileaddr;
397long filesize;
398vmaddr = (segCommand->vmaddr & 0x3fffffff);
399vmsize = segCommand->vmsize;
400fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand->fileoff);
401filesize = segCommand->filesize;
402
403printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
404 segCommand->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
405 (unsigned) segCommand->nsects, (unsigned)segCommand->flags);
406getc();
407#endif
408sectionIndex = sizeof(struct segment_command);
409
410struct section *sect;
411
412while(sectionIndex < segCommand->cmdsize)
413{
414sect = binary + binaryIndex + sectionIndex;
415
416sectionIndex += sizeof(struct section);
417
418
419if(strcmp("__text", sect->sectname) == 0)
420{
421// __TEXT,__text found, save the offset and address for when looking for the calls.
422textSection = sect->offset;
423textAddress = sect->addr;
424break;
425}
426}
427}
428break;
429}
430case LC_SEGMENT_64:// 64bit macho's
431{
432segCommand64 = binary + binaryIndex;
433
434//printf("Segment name is %s\n", segCommand->segname);
435
436if(strcmp("__TEXT", segCommand64->segname) == 0)
437{
438UInt32 sectionIndex;
439
440#if HARD_DEBUG_MODULES
441
442unsigned long fileaddr;
443long filesize;
444vmaddr = (segCommand64->vmaddr & 0x3fffffff);
445vmsize = segCommand64->vmsize;
446fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand64->fileoff);
447filesize = segCommand64->filesize;
448
449printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
450 segCommand64->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
451 (unsigned) segCommand64->nsects, (unsigned)segCommand64->flags);
452getc();
453#endif
454
455sectionIndex = sizeof(struct segment_command_64);
456
457struct section_64 *sect;
458
459while(sectionIndex < segCommand64->cmdsize)
460{
461sect = binary + binaryIndex + sectionIndex;
462
463sectionIndex += sizeof(struct section_64);
464
465
466if(strcmp("__text", sect->sectname) == 0)
467{
468// __TEXT,__text found, save the offset and address for when looking for the calls.
469textSection = sect->offset;
470textAddress = sect->addr;
471
472break;
473}
474}
475}
476
477break;
478}
479case LC_DYSYMTAB:
480break;
481
482case LC_LOAD_DYLIB:
483case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
484{
485dylibCommand = binary + binaryIndex;
486char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
487// TODO: verify version
488// =dylibCommand->dylib.current_version;
489// =dylibCommand->dylib.compatibility_version;
490char* name = malloc(strlen(module) + strlen(".dylib") + 1);
491sprintf(name, "%s.dylib", module);
492if(dylib_loader == EFI_SUCCESS)
493{
494EFI_STATUS statue = dylib_loader(name);
495
496if( statue != EFI_SUCCESS)
497{
498free(name);
499if (statue != EFI_ALREADY_STARTED)
500{
501// Unable to load dependancy
502return NULL;
503}
504
505}
506
507}
508break;
509}
510case LC_ID_DYLIB:
511dylibCommand = binary + binaryIndex;
512/*moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
513 moduleVersion =dylibCommand->dylib.current_version;
514 moduleCompat =dylibCommand->dylib.compatibility_version;
515 */
516break;
517
518case LC_DYLD_INFO:
519// Bind and rebase info is stored here
520dyldInfoCommand = binary + binaryIndex;
521break;
522
523case LC_UUID:
524break;
525
526case LC_UNIXTHREAD:
527break;
528
529default:
530DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
531break;
532
533}
534
535binaryIndex += cmdSize;
536}
537//if(!moduleName) return NULL;
538}
539
540// bind_macho uses the symbols.
541module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);
542
543// Rebase the module before binding it.
544if(dyldInfoCommand && dyldInfoCommand->rebase_off)
545{
546rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
547}
548
549if(dyldInfoCommand && dyldInfoCommand->bind_off)
550{
551bind_macho(binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
552}
553
554if(dyldInfoCommand && dyldInfoCommand->weak_bind_off)
555{
556// NOTE: this currently should never happen.
557bind_macho(binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
558}
559
560if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off)
561{
562// NOTE: we are binding the lazy pointers as a module is laoded,
563// This should be changed to bind when a symbol is referened at runtime instead.
564bind_macho(binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
565}
566
567return module_start;
568
569}
570
571// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
572void rebase_macho(void* base, char* rebase_stream, UInt32 size)
573{
574rebase_stream += (UInt32)base;
575
576UInt8 immediate = 0;
577UInt8 opcode = 0;
578UInt8 type = 0;
579
580UInt32 segmentAddress = 0;
581
582
583
584UInt32 tmp = 0;
585UInt32 tmp2 = 0;
586UInt8 bits = 0;
587UInt32 index = 0;
588
589int done = 0;
590unsigned int i = 0;
591
592while(/*!done &&*/ i < size)
593{
594immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
595opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
596
597
598switch(opcode)
599{
600case REBASE_OPCODE_DONE:
601// Rebase complete.
602done = 1;
603break;
604
605
606case REBASE_OPCODE_SET_TYPE_IMM:
607// Set rebase type (pointer, absolute32, pcrel32)
608//DBG("Rebase type = 0x%X\n", immediate);
609type = immediate;
610break;
611
612
613case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
614{
615// Locate address to begin rebasing
616segmentAddress = 0;
617
618struct segment_command* segCommand = NULL; // NOTE: 32bit only
619
620{
621unsigned int binIndex = 0;
622index = 0;
623do
624{
625segCommand = base + sizeof(struct mach_header) + binIndex;
626
627
628binIndex += segCommand->cmdsize;
629index++;
630}
631while(index <= immediate);
632}
633
634segmentAddress = segCommand->fileoff;
635
636tmp = 0;
637bits = 0;
638do
639{
640tmp |= (rebase_stream[++i] & 0x7f) << bits;
641bits += 7;
642}
643while(rebase_stream[i] & 0x80);
644
645segmentAddress += tmp;
646break;
647}
648case REBASE_OPCODE_ADD_ADDR_ULEB:
649// Add value to rebase address
650tmp = 0;
651bits = 0;
652do
653{
654tmp <<= bits;
655tmp |= rebase_stream[++i] & 0x7f;
656bits += 7;
657}
658while(rebase_stream[i] & 0x80);
659
660segmentAddress +=tmp;
661break;
662
663case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
664segmentAddress += immediate * sizeof(void*);
665break;
666
667
668case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
669index = 0;
670for (index = 0; index < immediate; ++index)
671{
672rebase_location(base + segmentAddress, (char*)base, type);
673segmentAddress += sizeof(void*);
674}
675break;
676
677
678case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
679tmp = 0;
680bits = 0;
681do
682{
683tmp |= (rebase_stream[++i] & 0x7f) << bits;
684bits += 7;
685}
686while(rebase_stream[i] & 0x80);
687
688index = 0;
689for (index = 0; index < tmp; ++index)
690{
691//DBG("\tRebasing 0x%X\n", segmentAddress);
692rebase_location(base + segmentAddress, (char*)base, type);
693segmentAddress += sizeof(void*);
694}
695break;
696
697case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
698tmp = 0;
699bits = 0;
700do
701{
702tmp |= (rebase_stream[++i] & 0x7f) << bits;
703bits += 7;
704}
705while(rebase_stream[i] & 0x80);
706
707rebase_location(base + segmentAddress, (char*)base, type);
708
709segmentAddress += tmp + sizeof(void*);
710break;
711
712case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
713tmp = 0;
714bits = 0;
715do
716{
717tmp |= (rebase_stream[++i] & 0x7f) << bits;
718bits += 7;
719}
720while(rebase_stream[i] & 0x80);
721
722
723tmp2 = 0;
724bits = 0;
725do
726{
727tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
728bits += 7;
729}
730while(rebase_stream[i] & 0x80);
731
732index = 0;
733for (index = 0; index < tmp; ++index)
734{
735
736rebase_location(base + segmentAddress, (char*)base, type);
737
738segmentAddress += tmp2 + sizeof(void*);
739}
740break;
741default:
742break;
743}
744i++;
745}
746}
747
748// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
749// NOTE: this uses 32bit values, and not 64bit values.
750// There is apossibility that this could cause issues,
751// however the macho file is 32 bit, so it shouldn't matter too much
752void bind_macho(void* base, char* bind_stream, UInt32 size)
753{
754bind_stream += (UInt32)base;
755
756UInt8 immediate = 0;
757UInt8 opcode = 0;
758UInt8 type = 0;
759
760UInt32 segmentAddress = 0;
761
762UInt32 address = 0;
763
764SInt32 addend = 0;// TODO: handle this
765SInt32 libraryOrdinal = 0;
766
767const char* symbolName = NULL;
768UInt8 symboFlags = 0;
769UInt32 symbolAddr = 0xFFFFFFFF;
770
771// Temperary variables
772UInt8 bits = 0;
773UInt32 tmp = 0;
774UInt32 tmp2 = 0;
775
776UInt32 index = 0;
777int done = 0;
778unsigned int i = 0;
779
780while(/*!done &&*/ i < size)
781{
782immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
783opcode = bind_stream[i] & BIND_OPCODE_MASK;
784
785
786switch(opcode)
787{
788case BIND_OPCODE_DONE:
789done = 1;
790break;
791
792case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
793libraryOrdinal = immediate;
794//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
795break;
796
797case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
798libraryOrdinal = 0;
799bits = 0;
800do
801{
802libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
803bits += 7;
804}
805while(bind_stream[i] & 0x80);
806
807//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
808
809break;
810
811case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
812// NOTE: this is wrong, fortunately we don't use it
813libraryOrdinal = -immediate;
814//DBG("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
815
816break;
817
818case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
819symboFlags = immediate;
820symbolName = (char*)&bind_stream[++i];
821i += strlen((char*)&bind_stream[i]);
822//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);
823
824symbolAddr = lookup_all_symbols(symbolName);
825
826break;
827
828case BIND_OPCODE_SET_TYPE_IMM:
829// Set bind type (pointer, absolute32, pcrel32)
830type = immediate;
831//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
832
833break;
834
835case BIND_OPCODE_SET_ADDEND_SLEB:
836addend = 0;
837bits = 0;
838do
839{
840addend |= (bind_stream[++i] & 0x7f) << bits;
841bits += 7;
842}
843while(bind_stream[i] & 0x80);
844
845if(!(bind_stream[i-1] & 0x40)) addend *= -1;
846
847//DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
848break;
849
850case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
851{
852segmentAddress = 0;
853
854// Locate address
855struct segment_command* segCommand = NULL;// NOTE: 32bit only
856
857{
858unsigned int binIndex = 0;
859index = 0;
860do
861{
862segCommand = base + sizeof(struct mach_header) + binIndex;
863binIndex += segCommand->cmdsize;
864index++;
865}while(index <= immediate);
866}
867
868
869segmentAddress = segCommand->fileoff;
870
871// Read in offset
872tmp = 0;
873bits = 0;
874do
875{
876tmp |= (bind_stream[++i] & 0x7f) << bits;
877bits += 7;
878}while(bind_stream[i] & 0x80);
879
880segmentAddress += tmp;
881
882//DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);
883break;
884}
885case BIND_OPCODE_ADD_ADDR_ULEB:
886// Read in offset
887tmp = 0;
888bits = 0;
889do
890{
891tmp |= (bind_stream[++i] & 0x7f) << bits;
892bits += 7;
893}
894while(bind_stream[i] & 0x80);
895
896segmentAddress += tmp;
897//DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);
898break;
899
900case BIND_OPCODE_DO_BIND:
901//DBG("BIND_OPCODE_DO_BIND\n");
902if(symbolAddr != 0xFFFFFFFF)
903{
904address = segmentAddress + (UInt32)base;
905
906bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
907}
908else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
909{
910printf("Unable to bind symbol %s\n", symbolName);
911}
912
913segmentAddress += sizeof(void*);
914break;
915
916case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
917//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
918
919
920// Read in offset
921tmp = 0;
922bits = 0;
923do
924{
925tmp |= (bind_stream[++i] & 0x7f) << bits;
926bits += 7;
927}
928while(bind_stream[i] & 0x80);
929
930
931
932if(symbolAddr != 0xFFFFFFFF)
933{
934address = segmentAddress + (UInt32)base;
935
936bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
937}
938else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
939{
940printf("Unable to bind symbol %s\n", symbolName);
941}
942segmentAddress += tmp + sizeof(void*);
943
944
945break;
946
947case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
948//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
949
950if(symbolAddr != 0xFFFFFFFF)
951{
952address = segmentAddress + (UInt32)base;
953
954bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
955}
956else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
957{
958printf("Unable to bind symbol %s\n", symbolName);
959}
960segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
961
962
963break;
964
965case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
966
967tmp = 0;
968bits = 0;
969do
970{
971tmp |= (bind_stream[++i] & 0x7f) << bits;
972bits += 7;
973}
974while(bind_stream[i] & 0x80);
975
976
977tmp2 = 0;
978bits = 0;
979do
980{
981tmp2 |= (bind_stream[++i] & 0x7f) << bits;
982bits += 7;
983}
984while(bind_stream[i] & 0x80);
985
986
987//DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);
988
989
990if(symbolAddr != 0xFFFFFFFF)
991{
992for(index = 0; index < tmp; index++)
993{
994
995address = segmentAddress + (UInt32)base;
996
997bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
998
999segmentAddress += tmp2 + sizeof(void*);
1000}
1001}
1002else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
1003{
1004printf("Unable to bind symbol %s\n", symbolName);
1005}
1006
1007
1008break;
1009default:
1010break;
1011
1012}
1013i++;
1014}
1015}
1016
1017inline void rebase_location(UInt32* location, char* base, int type)
1018{
1019switch(type)
1020{
1021case REBASE_TYPE_POINTER:
1022case REBASE_TYPE_TEXT_ABSOLUTE32:
1023*location += (UInt32)base;
1024break;
1025
1026default:
1027break;
1028}
1029}
1030
1031inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)
1032{
1033// do actual update
1034char* newValue = value + addend;
1035
1036switch (type) {
1037case BIND_TYPE_POINTER:
1038case BIND_TYPE_TEXT_ABSOLUTE32:
1039break;
1040
1041case BIND_TYPE_TEXT_PCREL32:
1042newValue -= ((UInt32)location + 4);
1043
1044break;
1045default:
1046return;
1047}
1048*location = (UInt32)newValue;
1049
1050
1051}
1052
1053/*
1054 * add_symbol
1055 * This function adds a symbol from a module to the list of known symbols
1056 * possibly change to a pointer and add this to the Symbol module so that it can
1057 * adjust it's internal symbol list (sort) to optimize locating new symbols
1058 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
1059 */
1060long long add_symbol(char* symbol, long long addr, char is64)
1061{
1062if(is64) return 0xFFFFFFFF; // Fixme
1063
1064// This only can handle 32bit symbols
1065symbolList_t* new_entry= malloc(sizeof(symbolList_t));
1066DBG("Adding symbol %s at 0x%X\n", symbol, addr);
1067if (new_entry)
1068{
1069new_entry->next = moduleSymbols;
1070
1071moduleSymbols = new_entry;
1072
1073new_entry->addr = (UInt32)addr;
1074new_entry->symbol = symbol;
1075return addr;
1076}
1077
1078return 0xFFFFFFFF;
1079
1080}
1081
1082/*
1083 * print out the information about the loaded module
1084 */
1085VOID module_loaded(const char* name/*, UInt32 version, UInt32 compat*/)
1086{
1087moduleList_t* new_entry = malloc(sizeof(moduleList_t));
1088if (new_entry)
1089{
1090new_entry->next = loadedModules;
1091
1092loadedModules = new_entry;
1093
1094new_entry->module = (char*)name;
1095//new_entry->version = version;
1096//new_entry->compat = compat;
1097}
1098}
1099
1100EFI_STATUS is_module_loaded(const char* name)
1101{
1102moduleList_t* entry = loadedModules;
1103while(entry)
1104{
1105DBG("Comparing %s with %s\n", name, entry->module);
1106char fullname[128];
1107sprintf(fullname, "%s.dylib",name);
1108if((strcmp(entry->module, name) == 0) || (strcmp(entry->module, fullname) == 0))
1109{
1110DBG("Located module %s\n", name);
1111return EFI_SUCCESS;
1112}
1113else
1114{
1115entry = entry->next;
1116}
1117
1118}
1119DBG("Module %s not found\n", name);
1120
1121return EFI_NOT_FOUND;
1122}
1123
1124// Look for symbols using the Smbols moduel function.
1125// If non are found, look through the list of module symbols
1126unsigned int lookup_all_symbols(const char* name)
1127{
1128{
1129unsigned int addr = 0xFFFFFFFF;
1130if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
1131{
1132addr = lookup_symbol(name);
1133if(addr != 0xFFFFFFFF)
1134{
1135DBG("Internal symbol %s located at 0x%X\n", name, addr);
1136return addr;
1137}
1138}
1139}
1140
1141{
1142symbolList_t* entry = moduleSymbols;
1143while(entry)
1144{
1145if(strcmp(entry->symbol, name) == 0)
1146{
1147DBG("External symbol %s located at 0x%X\n", name, entry->addr);
1148return entry->addr;
1149}
1150else
1151{
1152entry = entry->next;
1153}
1154
1155}
1156}
1157
1158#if DEBUG_MODULES
1159if(strcmp(name, SYMBOL_DYLD_STUB_BINDER) != 0)
1160{
1161verbose("Unable to locate symbol %s\n", name);
1162getc();
1163}
1164#endif
1165return 0xFFFFFFFF;
1166}
1167
1168
1169/*
1170 * parse the symbol table
1171 * Lookup any undefined symbols
1172 */
1173
1174unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
1175{
1176unsigned int module_start = 0xFFFFFFFF;
1177
1178UInt32 symbolIndex = 0;
1179char* symbolString = base + (char*)symtabCommand->stroff;
1180//char* symbolTable = base + symtabCommand->symoff;
1181if(!is64)
1182{
1183struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
1184while(symbolIndex < symtabCommand->nsyms)
1185{
1186if(symbolEntry->n_value)
1187{
1188if(strcmp(symbolString + symbolEntry->n_un.n_strx, "start") == 0)
1189{
1190// Module start located. 'start' is an alias so don't register it
1191module_start = base + symbolEntry->n_value;
1192DBG("n_value %x module_start %x\n", (unsigned)symbolEntry->n_value, (unsigned)module_start);
1193}
1194else
1195{
1196symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
1197}
1198
1199#if HARD_DEBUG_MODULES
1200bool isTexT = (((unsigned)symbolEntry->n_value > (unsigned)vmaddr) && ((unsigned)(vmaddr + vmsize) > (unsigned)symbolEntry->n_value ));
1201printf("%s %s\n", isTexT ? "__TEXT :" : "__DATA(OR ANY) :", symbolString + symbolEntry->n_un.n_strx);
1202
1203if(strcmp(symbolString + symbolEntry->n_un.n_strx, "_BootHelp_txt") == 0)
1204{
1205long long addr = (long long)base + symbolEntry->n_value;
1206unsigned char *BootHelp = NULL;
1207BootHelp = (unsigned char*)(UInt32)addr;
1208printf("method 1: __DATA : BootHelp_txt[0] %x\n", BootHelp[0]);
1209
1210long long addr2 = symbolEntry->n_value;
1211unsigned char *BootHelp2 = NULL;
1212BootHelp2 = (unsigned char*)(UInt32)addr2;
1213printf("method 2: __DATA : BootHelp_txt[0] %x\n", BootHelp2[0]);
1214}
1215#endif
1216}
1217
1218symbolEntry++;
1219symbolIndex++;// TODO remove
1220}
1221}
1222else
1223{
1224struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
1225// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
1226while(symbolIndex < symtabCommand->nsyms)
1227{
1228
1229if(strcmp(symbolString + symbolEntry->n_un.n_strx, "start") == 0)
1230{
1231// Module start located. 'start' is an alias so don't register it
1232module_start = base + symbolEntry->n_value;
1233}
1234else
1235{
1236symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
1237}
1238
1239symbolEntry++;
1240symbolIndex++;// TODO remove
1241}
1242}
1243
1244return module_start;
1245
1246}
1247
1248
1249/*
1250 * Locate the symbol for an already loaded function and modify the beginning of
1251 * the function to jump directly to the new one
1252 * example: replace_function("_HelloWorld_start", &replacement_start);
1253 */
1254EFI_STATUS replace_function(const char* symbol, void* newAddress)
1255{
1256// TODO: look into using the next four bytes of the function instead
1257// Most functions should support this, as they probably will be at
1258// least 10 bytes long, but you never know, this is sligtly safer as
1259// function can be as small as 6 bytes.
1260UInt32 addr = lookup_all_symbols(symbol);
1261
1262char* binary = (char*)addr;
1263if(addr != 0xFFFFFFFF)
1264{
1265UInt32* jumpPointer = malloc(sizeof(UInt32*));
1266
1267*binary++ = 0xFF;// Jump
1268*binary++ = 0x25;// Long Jump
1269*((UInt32*)binary) = (UInt32)jumpPointer;
1270
1271*jumpPointer = (UInt32)newAddress;
1272
1273return EFI_SUCCESS;
1274}
1275
1276return EFI_NOT_FOUND;
1277
1278}
1279
1280
1281/* Nedded to divide 64bit numbers correctly. TODO: look into why modules need this
1282 * And why it isn't needed when compiled into boot2
1283 *
1284 * In the next versions, this will be surely replaced by the Apple's libcc_kext or the meklort's klibc
1285 */
1286
1287uint64_t __udivdi3(uint64_t numerator, uint64_t denominator)
1288{
1289uint64_t quotient = 0, qbit = 1;
1290
1291if (denominator)
1292{
1293while ((int64_t) denominator >= 0)
1294{
1295denominator <<= 1;
1296qbit <<= 1;
1297}
1298
1299while (denominator)
1300{
1301if (denominator <= numerator)
1302{
1303numerator -= denominator;
1304quotient += qbit;
1305}
1306denominator >>= 1;
1307qbit >>= 1;
1308}
1309
1310return quotient;
1311}
1312
1313stop("Divide by 0");
1314return 0;
1315}
1316

Archive Download this file

Revision: 1525