Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 1887