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

Archive Download this file

Revision: 1804