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 load_command *loadCommand = NULL;
368UInt32 binaryIndex = 0;
369UInt16 cmd = 0;
370
371// Parse through the load commands
372if(((struct mach_header*)binary)->magic == MH_MAGIC)
373{
374is64 = false;
375binaryIndex += sizeof(struct mach_header);
376}
377else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
378{
379// NOTE: modules cannot be 64bit...
380is64 = true;
381binaryIndex += sizeof(struct mach_header_64);
382}
383else
384{
385printf("Modules: Invalid mach magic\n");
386getc();
387return NULL;
388}
389
390
391
392/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
393 {
394 printf("Module is not a dylib. Unable to load.\n");
395 getc();
396 return NULL; // Module is in the incorrect format
397 }*/
398
399while(cmd < ((struct mach_header*)binary)->ncmds)
400{
401cmd++;
402
403loadCommand = binary + binaryIndex;
404UInt32 cmdSize = loadCommand->cmdsize;
405
406
407switch ((loadCommand->cmd & 0x7FFFFFFF))
408{
409case LC_SYMTAB:
410symtabCommand = binary + binaryIndex;
411break;
412
413case LC_SEGMENT: // 32bit macho
414{
415segCommand = binary + binaryIndex;
416
417//printf("Segment name is %s\n", segCommand->segname);
418
419if(strcmp("__TEXT", segCommand->segname) == 0)
420{
421UInt32 sectionIndex;
422
423#if DEBUG_MODULES
424unsigned long fileaddr;
425long filesize;
426vmaddr = (segCommand->vmaddr & 0x3fffffff);
427vmsize = segCommand->vmsize;
428fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand->fileoff);
429filesize = segCommand->filesize;
430
431printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
432 segCommand->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
433 (unsigned) segCommand->nsects, (unsigned)segCommand->flags);
434#if DEBUG_MODULES==2
435
436getc();
437#endif
438#endif
439
440sectionIndex = sizeof(struct segment_command);
441
442struct section *sect;
443
444while(sectionIndex < segCommand->cmdsize)
445{
446sect = binary + binaryIndex + sectionIndex;
447
448sectionIndex += sizeof(struct section);
449
450
451if(strcmp("__text", sect->sectname) == 0)
452{
453// __TEXT,__text found, save the offset and address for when looking for the calls.
454textSection = sect->offset;
455textAddress = sect->addr;
456break;
457}
458}
459}
460break;
461}
462case LC_SEGMENT_64:// 64bit macho's
463{
464segCommand64 = binary + binaryIndex;
465
466//printf("Segment name is %s\n", segCommand->segname);
467
468if(strcmp("__TEXT", segCommand64->segname) == 0)
469{
470UInt32 sectionIndex;
471
472#if DEBUG_MODULES
473unsigned long fileaddr;
474long filesize;
475vmaddr = (segCommand64->vmaddr & 0x3fffffff);
476vmsize = segCommand64->vmsize;
477fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand64->fileoff);
478filesize = segCommand64->filesize;
479
480printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
481 segCommand64->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
482 (unsigned) segCommand64->nsects, (unsigned)segCommand64->flags);
483#if DEBUG_MODULES==2
484
485getc();
486#endif
487#endif
488
489sectionIndex = sizeof(struct segment_command_64);
490
491struct section_64 *sect;
492
493while(sectionIndex < segCommand64->cmdsize)
494{
495sect = binary + binaryIndex + sectionIndex;
496
497sectionIndex += sizeof(struct section_64);
498
499
500if(strcmp("__text", sect->sectname) == 0)
501{
502// __TEXT,__text found, save the offset and address for when looking for the calls.
503textSection = sect->offset;
504textAddress = sect->addr;
505
506break;
507}
508}
509}
510
511break;
512}
513case LC_DYSYMTAB:
514break;
515
516case LC_LOAD_DYLIB:
517case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
518{
519struct dylib_command* dylibCommand = binary + binaryIndex;
520char* weak_module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
521
522char *name=NULL;
523name = newStringWithFormat( "%s.dylib", weak_module);
524if (!name) {
525printf("Unable to allocate module name : %s\n", weak_module);
526return NULL;
527}
528if(dylib_loader)
529{
530EFI_STATUS statue = dylib_loader(weak_module);
531
532if( statue != EFI_SUCCESS)
533{
534if (statue != EFI_ALREADY_STARTED)
535{
536// Unable to load dependancy
537//free(weak_module);
538return NULL;
539}
540
541}
542
543}
544//free(weak_module);
545
546break;
547}
548case LC_ID_DYLIB:
549 {
550 /*struct dylib_command* dylibCommand = binary + binaryIndex;
551 moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
552 moduleVersion =dylibCommand->dylib.current_version;
553 moduleCompat =dylibCommand->dylib.compatibility_version;
554 */
555 }
556break;
557
558case LC_DYLD_INFO:
559// Bind and rebase info is stored here
560dyldInfoCommand = binary + binaryIndex;
561break;
562
563case LC_UUID:
564break;
565
566case LC_UNIXTHREAD:
567break;
568
569default:
570DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
571break;
572
573}
574
575binaryIndex += cmdSize;
576}
577//if(!moduleName) return NULL;
578}
579
580// bind_macho uses the symbols.
581module_start = (void*)handle_symtable(module, (UInt32)binary, symtabCommand, symbol_handler, is64);
582
583// Rebase the module before binding it.
584if(dyldInfoCommand && dyldInfoCommand->rebase_off)
585{
586rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
587}
588
589if(dyldInfoCommand && dyldInfoCommand->bind_off)
590{
591bind_status = bind_macho(module, binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
592}
593
594if(dyldInfoCommand && dyldInfoCommand->weak_bind_off && (bind_status == EFI_SUCCESS))
595{
596// NOTE: this currently should never happen.
597bind_status = bind_macho(module, binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
598}
599
600if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off && (bind_status == EFI_SUCCESS))
601{
602// NOTE: we are binding the lazy pointers as a module is laoded,
603// This should be changed to bind when a symbol is referened at runtime instead.
604bind_status = bind_macho(module, binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
605}
606
607 if (bind_status != EFI_SUCCESS) {
608 module_start = (void*)0xFFFFFFFF;
609 }
610
611return module_start;
612
613}
614
615// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
616void rebase_macho(void* base, char* rebase_stream, UInt32 size)
617{
618rebase_stream += (UInt32)base;
619
620UInt8 immediate = 0;
621UInt8 opcode = 0;
622UInt8 type = 0;
623
624UInt32 segmentAddress = 0;
625
626
627
628UInt32 tmp = 0;
629UInt32 tmp2 = 0;
630UInt8 bits = 0;
631UInt32 index = 0;
632
633//int done = 0;
634unsigned int i = 0;
635
636while(/*!done &&*/ i < size)
637{
638immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
639opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
640
641
642switch(opcode)
643{
644case REBASE_OPCODE_DONE:
645// Rebase complete.
646//done = 1;
647break;
648
649
650case REBASE_OPCODE_SET_TYPE_IMM:
651// Set rebase type (pointer, absolute32, pcrel32)
652//DBG("Rebase type = 0x%X\n", immediate);
653type = immediate;
654break;
655
656
657case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
658{
659// Locate address to begin rebasing
660//segmentAddress = 0;
661
662struct segment_command* segCommand = NULL; // NOTE: 32bit only
663
664{
665unsigned int binIndex = 0;
666index = 0;
667do
668{
669segCommand = base + sizeof(struct mach_header) + binIndex;
670
671
672binIndex += segCommand->cmdsize;
673index++;
674}
675while(index <= immediate);
676}
677
678segmentAddress = segCommand->fileoff;
679
680tmp = 0;
681bits = 0;
682do
683{
684tmp |= (rebase_stream[++i] & 0x7f) << bits;
685bits += 7;
686}
687while(rebase_stream[i] & 0x80);
688
689segmentAddress += tmp;
690break;
691}
692case REBASE_OPCODE_ADD_ADDR_ULEB:
693// Add value to rebase address
694tmp = 0;
695bits = 0;
696do
697{
698tmp <<= bits;
699tmp |= rebase_stream[++i] & 0x7f;
700bits += 7;
701}
702while(rebase_stream[i] & 0x80);
703
704segmentAddress +=tmp;
705break;
706
707case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
708segmentAddress += immediate * sizeof(void*);
709break;
710
711
712case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
713for (index = 0; index < immediate; ++index)
714{
715rebase_location(base + segmentAddress, (char*)base, type);
716segmentAddress += sizeof(void*);
717}
718break;
719
720case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
721tmp = 0;
722bits = 0;
723do
724{
725tmp |= (rebase_stream[++i] & 0x7f) << bits;
726bits += 7;
727}
728while(rebase_stream[i] & 0x80);
729
730for (index = 0; index < tmp; ++index)
731{
732//DBG("\tRebasing 0x%X\n", segmentAddress);
733rebase_location(base + segmentAddress, (char*)base, type);
734segmentAddress += sizeof(void*);
735}
736break;
737
738case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
739tmp = 0;
740bits = 0;
741do
742{
743tmp |= (rebase_stream[++i] & 0x7f) << bits;
744bits += 7;
745}
746while(rebase_stream[i] & 0x80);
747
748rebase_location(base + segmentAddress, (char*)base, type);
749
750segmentAddress += tmp + sizeof(void*);
751break;
752
753case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
754tmp = 0;
755bits = 0;
756do
757{
758tmp |= (rebase_stream[++i] & 0x7f) << bits;
759bits += 7;
760}
761while(rebase_stream[i] & 0x80);
762
763
764tmp2 = 0;
765bits = 0;
766do
767{
768tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
769bits += 7;
770}
771while(rebase_stream[i] & 0x80);
772
773for (index = 0; index < tmp; ++index)
774{
775
776rebase_location(base + segmentAddress, (char*)base, type);
777
778segmentAddress += tmp2 + sizeof(void*);
779}
780break;
781default:
782break;
783}
784i++;
785}
786}
787
788// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
789// NOTE: this uses 32bit values, and not 64bit values.
790// There is apossibility that this could cause issues,
791// however the macho file is 32 bit, so it shouldn't matter too much
792EFI_STATUS bind_macho(char* module, void* base, char* bind_stream, UInt32 size)
793{
794bind_stream += (UInt32)base;
795
796UInt8 immediate = 0;
797UInt8 opcode = 0;
798
799UInt32 segmentAddress = 0;
800
801UInt32 address = 0;
802
803SInt32 addend = 0;// TODO: handle this
804
805const char* symbolName = NULL;
806UInt32 symbolAddr = 0xFFFFFFFF;
807
808// Temperary variables
809UInt8 bits = 0;
810UInt32 tmp = 0;
811UInt32 tmp2 = 0;
812
813UInt32 index = 0;
814unsigned int i = 0;
815
816while(i < size)
817{
818immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
819opcode = bind_stream[i] & BIND_OPCODE_MASK;
820
821
822switch(opcode)
823{
824case BIND_OPCODE_DONE:
825break;
826
827case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
828 {
829#if DEBUG_MODULES==2
830SInt32 libraryOrdinal = immediate;
831DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
832#endif
833break;
834 }
835case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
836 {
837#if DEBUG_MODULES==2
838SInt32 libraryOrdinal = 0;
839UInt8 bits = 0;
840do
841{
842libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
843bits += 7;
844}
845while(bind_stream[i] & 0x80);
846
847DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
848#else
849 do
850{
851i++;
852}
853while(bind_stream[i] & 0x80);
854#endif
855break;
856}
857case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
858 {
859#if DEBUG_MODULES==2
860 // NOTE: this is wrong, fortunately we don't use it
861SInt32 libraryOrdinal = -immediate;
862DBG("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
863#endif
864break;
865}
866case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
867 {
868symbolName = (char*)&bind_stream[++i];
869i += strlen((char*)&bind_stream[i]);
870#if DEBUG_MODULES==2
871UInt8 symbolFlags = immediate;
872 DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symbolFlags);
873#endif
874symbolAddr = lookup_all_symbols(NULL ,symbolName);
875
876break;
877 }
878case BIND_OPCODE_SET_TYPE_IMM:
879 {
880// Set bind type (pointer, absolute32, pcrel32)
881#if DEBUG_MODULES==2
882 UInt8 type = immediate;
883DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
884#endif
885break;
886 }
887case BIND_OPCODE_SET_ADDEND_SLEB:
888addend = 0;
889bits = 0;
890do
891{
892addend |= (bind_stream[++i] & 0x7f) << bits;
893bits += 7;
894}
895while(bind_stream[i] & 0x80);
896
897if(!(bind_stream[i-1] & 0x40)) addend *= -1;
898#if DEBUG_MODULES==2
899DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
900#endif
901
902break;
903
904case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
905{
906// Locate address
907struct segment_command* segCommand = NULL;// NOTE: 32bit only
908
909{
910unsigned int binIndex = 0;
911index = 0;
912do
913{
914segCommand = base + sizeof(struct mach_header) + binIndex;
915binIndex += segCommand->cmdsize;
916index++;
917}while(index <= immediate);
918}
919
920
921segmentAddress = segCommand->fileoff;
922
923// Read in offset
924tmp = 0;
925bits = 0;
926do
927{
928tmp |= (bind_stream[++i] & 0x7f) << bits;
929bits += 7;
930}while(bind_stream[i] & 0x80);
931
932segmentAddress += tmp;
933#if DEBUG_MODULES==2
934DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);
935#endif
936break;
937}
938case BIND_OPCODE_ADD_ADDR_ULEB:
939// Read in offset
940tmp = 0;
941bits = 0;
942do
943{
944tmp |= (bind_stream[++i] & 0x7f) << bits;
945bits += 7;
946}
947while(bind_stream[i] & 0x80);
948
949segmentAddress += tmp;
950#if DEBUG_MODULES==2
951DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);
952#endif
953
954break;
955
956case BIND_OPCODE_DO_BIND:
957#if DEBUG_MODULES==2
958DBG("BIND_OPCODE_DO_BIND\n");
959#endif
960
961 if(symbolAddr != 0xFFFFFFFF)
962{
963address = segmentAddress + (UInt32)base;
964
965bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
966}
967else if(symbolName && (strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0))
968{
969printf("Unable to bind symbol %s needed by %s\n", symbolName, module);
970 getc();
971 goto error;
972
973}
974
975segmentAddress += sizeof(void*);
976break;
977
978case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
979#if DEBUG_MODULES==2
980DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
981#endif
982
983// Read in offset
984tmp = 0;
985bits = 0;
986do
987{
988tmp |= (bind_stream[++i] & 0x7f) << bits;
989bits += 7;
990}
991while(bind_stream[i] & 0x80);
992
993
994 if(symbolAddr != 0xFFFFFFFF)
995{
996address = segmentAddress + (UInt32)base;
997
998bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
999}
1000else if(symbolName && (strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0))
1001{
1002printf("Unable to bind symbol %s needed by %s\n", symbolName, module);
1003 getc();
1004 goto error;
1005
1006}
1007
1008segmentAddress += tmp + sizeof(void*);
1009
1010
1011break;
1012
1013case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1014#if DEBUG_MODULES==2
1015DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
1016#endif
1017
1018 if(symbolAddr != 0xFFFFFFFF)
1019{
1020address = segmentAddress + (UInt32)base;
1021
1022bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
1023}
1024else if(symbolName && (strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0))
1025{
1026printf("Unable to bind symbol %s needed by %s\n", symbolName, module);
1027 getc();
1028 goto error;
1029
1030}
1031segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
1032
1033break;
1034
1035case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1036
1037tmp = 0;
1038bits = 0;
1039do
1040{
1041tmp |= (bind_stream[++i] & 0x7f) << bits;
1042bits += 7;
1043}
1044while(bind_stream[i] & 0x80);
1045
1046
1047tmp2 = 0;
1048bits = 0;
1049do
1050{
1051tmp2 |= (bind_stream[++i] & 0x7f) << bits;
1052bits += 7;
1053}
1054while(bind_stream[i] & 0x80);
1055
1056#if DEBUG_MODULES==2
1057DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);
1058#endif
1059
1060 if(symbolAddr != 0xFFFFFFFF)
1061{
1062for(index = 0; index < tmp; index++)
1063{
1064
1065address = segmentAddress + (UInt32)base;
1066
1067bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
1068
1069segmentAddress += tmp2 + sizeof(void*);
1070}
1071}
1072else if(symbolName && (strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0))
1073{
1074printf("Unable to bind symbol %s needed by %s\n", symbolName, module);
1075 getc();
1076 goto error;
1077
1078}
1079
1080break;
1081default:
1082break;
1083
1084}
1085i++;
1086}
1087 return EFI_SUCCESS;
1088error:
1089 return EFI_NOT_FOUND;
1090}
1091
1092void rebase_location(UInt32* location, char* base, int type)
1093{
1094switch(type)
1095{
1096case REBASE_TYPE_POINTER:
1097case REBASE_TYPE_TEXT_ABSOLUTE32:
1098*location += (UInt32)base;
1099break;
1100
1101default:
1102break;
1103}
1104}
1105
1106void bind_location(UInt32* location, char* value, UInt32 addend, int type)
1107{
1108// do actual update
1109char* newValue = value + addend;
1110
1111switch (type) {
1112case BIND_TYPE_POINTER:
1113case BIND_TYPE_TEXT_ABSOLUTE32:
1114break;
1115
1116case BIND_TYPE_TEXT_PCREL32:
1117newValue -= ((UInt32)location + 4);
1118
1119break;
1120default:
1121return;
1122}
1123*location = (UInt32)newValue;
1124
1125
1126}
1127
1128/*
1129 * add_symbol
1130 * This function adds a symbol from a module to the list of known symbols
1131 * possibly change to a pointer and add this to the Symbol module so that it can
1132 * adjust it's internal symbol list (sort) to optimize locating new symbols
1133 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
1134 */
1135long long add_symbol(char* module,char* symbol, long long addr, char is64)
1136{
1137if(is64) return 0xFFFFFFFF; // Fixme
1138
1139// This only can handle 32bit symbols
1140symbolList_t* new_entry= malloc(sizeof(symbolList_t));
1141DBG("Adding symbol %s at 0x%X\n", symbol, addr);
1142if (new_entry)
1143{
1144new_entry->next = moduleSymbols;
1145
1146moduleSymbols = new_entry;
1147
1148new_entry->addr = (UInt32)addr;
1149 new_entry->module = module;
1150new_entry->symbol = symbol;
1151return addr;
1152}
1153
1154return 0xFFFFFFFF;
1155
1156}
1157
1158/*
1159 * print out the information about the loaded module
1160 */
1161VOID module_loaded(const char* name)
1162{
1163moduleList_t* new_entry = malloc(sizeof(moduleList_t));
1164if (new_entry)
1165{
1166new_entry->next = loadedModules;
1167
1168loadedModules = new_entry;
1169
1170new_entry->module = (char*)name;
1171}
1172}
1173
1174EFI_STATUS is_module_loaded(const char* name)
1175{
1176moduleList_t* entry = loadedModules;
1177while(entry)
1178{
1179DBG("Comparing %s with %s\n", name, entry->module);
1180char *fullname = newStringWithFormat("%s.dylib",name);
1181if(fullname && ((strcmp(entry->module, name) == 0) || (strcmp(entry->module, fullname) == 0)))
1182{
1183free(fullname);
1184DBG("Located module %s\n", name);
1185return EFI_SUCCESS;
1186}
1187else
1188{
1189entry = entry->next;
1190}
1191
1192}
1193DBG("Module %s not found\n", name);
1194
1195return EFI_NOT_FOUND;
1196}
1197
1198// Look for symbols using the Smbols moduel function.
1199// If non are found, look through the list of module symbols
1200unsigned int lookup_all_symbols(const char* module, const char* name)
1201{
1202
1203 unsigned int addr = 0xFFFFFFFF;
1204
1205 do {
1206
1207 if ((module != NULL) && (strcmp(module,SYMBOLS_MODULE) != 0))
1208 break;
1209
1210 if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
1211 {
1212 addr = lookup_symbol(name, &strcmp);
1213 if(addr != 0xFFFFFFFF)
1214 {
1215 DBG("Internal symbol %s located at 0x%X\n", name, addr);
1216 goto out;
1217 }
1218 }
1219
1220 } while (0);
1221
1222
1223{
1224symbolList_t* entry = moduleSymbols;
1225while(entry)
1226{
1227 if ((module != NULL) && (strcmp(entry->module,module) != 0))
1228 {
1229 entry = entry->next;
1230 continue;
1231 }
1232
1233 if(strcmp(entry->symbol, name) == 0)
1234 {
1235 DBG("External symbol %s located at 0x%X\n", name, entry->addr);
1236 addr = entry->addr;
1237 goto out;
1238 }
1239 else
1240 {
1241 entry = entry->next;
1242 }
1243
1244}
1245}
1246
1247#if DEBUG_MODULES
1248if(strcmp(name, SYMBOL_DYLD_STUB_BINDER) != 0)
1249{
1250verbose("Unable to locate symbol %s\n", name);
1251getc();
1252}
1253#endif
1254out:
1255 return addr;
1256
1257}
1258
1259
1260/*
1261 * parse the symbol table
1262 * Lookup any undefined symbols
1263 */
1264
1265unsigned int handle_symtable(char *module, UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, char*, long long, char), char is64)
1266{
1267unsigned int module_start = 0xFFFFFFFF;
1268
1269UInt32 symbolIndex = 0;
1270 if (!symtabCommand) {
1271 return 0xFFFFFFFF;
1272 }
1273char* symbolString = base + (char*)symtabCommand->stroff;
1274//char* symbolTable = base + symtabCommand->symoff;
1275if(!is64)
1276{
1277struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
1278while(symbolIndex < symtabCommand->nsyms)
1279{
1280if(symbolEntry->n_value)
1281{
1282if(strstr(symbolString + symbolEntry->n_un.n_strx, "module_start") || (strcmp(symbolString + symbolEntry->n_un.n_strx, "start") == 0))
1283{
1284module_start = base + symbolEntry->n_value;
1285DBG("n_value %x module_start %x\n", (unsigned)symbolEntry->n_value, (unsigned)module_start);
1286}
1287else
1288{
1289symbol_handler(module, symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
1290}
1291#if DEBUG_MODULES
1292bool isTexT = (((unsigned)symbolEntry->n_value > (unsigned)vmaddr) && ((unsigned)(vmaddr + vmsize) > (unsigned)symbolEntry->n_value ));
1293printf("%s %s\n", isTexT ? "__TEXT :" : "__DATA(OR ANY) :", symbolString + symbolEntry->n_un.n_strx);
1294#if DEBUG_MODULES==2
1295
1296if(strcmp(symbolString + symbolEntry->n_un.n_strx, "_BootHelp_txt") == 0)
1297{
1298long long addr = (long long)base + symbolEntry->n_value;
1299unsigned char *BootHelp = NULL;
1300BootHelp = (unsigned char*)(UInt32)addr;
1301printf("method 1: __DATA : BootHelp_txt[0] %x\n", BootHelp[0]);
1302
1303long long addr2 = symbolEntry->n_value;
1304unsigned char *BootHelp2 = NULL;
1305BootHelp2 = (unsigned char*)(UInt32)addr2;
1306printf("method 2: __DATA : BootHelp_txt[0] %x\n", BootHelp2[0]);
1307}
1308#endif
1309#endif
1310
1311}
1312
1313symbolEntry++;
1314symbolIndex++;// TODO remove
1315}
1316}
1317else
1318{
1319struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
1320// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
1321while(symbolIndex < symtabCommand->nsyms)
1322{
1323
1324if(strstr(symbolString + symbolEntry->n_un.n_strx, "module_start") || (strcmp(symbolString + symbolEntry->n_un.n_strx, "start") == 0))
1325{
1326module_start = (unsigned int)(base + symbolEntry->n_value);
1327}
1328else
1329{
1330symbol_handler(module, symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
1331}
1332
1333symbolEntry++;
1334symbolIndex++;// TODO remove
1335}
1336}
1337
1338return module_start;
1339
1340}
1341
1342
1343/*
1344 * Locate the symbol for an already loaded function and modify the beginning of
1345 * the function to jump directly to the new one
1346 * example: replace_system_function("_getc", &replacement);
1347 * replace_function(module_name,"_getc", &replacement);
1348 * replace_function_any("_getc", &replacement);
1349 */
1350EFI_STATUS replace_function(const char* module, const char* symbol, void* newAddress)
1351{
1352// TODO: look into using the next four bytes of the function instead
1353// Most functions should support this, as they probably will be at
1354// least 10 bytes long, but you never know, this is sligtly safer as
1355// function can be as small as 6 bytes.
1356UInt32 addr = lookup_all_symbols(module, symbol);
1357
1358char* binary = (char*)addr;
1359if(addr != 0xFFFFFFFF)
1360{
1361UInt32* jumpPointer = malloc(sizeof(UInt32*));
1362if (!jumpPointer) {
1363return EFI_OUT_OF_RESOURCES;
1364}
1365
1366*binary++ = 0xFF;// Jump
1367*binary++ = 0x25;// Long Jump
1368*((UInt32*)binary) = (UInt32)jumpPointer;
1369
1370*jumpPointer = (UInt32)newAddress;
1371
1372return EFI_SUCCESS;
1373}
1374
1375return EFI_NOT_FOUND;
1376
1377}
1378
1379EFI_STATUS replace_system_function(const char* symbol, void* newAddress)
1380{
1381
1382return replace_function(SYMBOLS_MODULE,symbol,newAddress);
1383
1384}
1385
1386EFI_STATUS replace_function_any(const char* symbol, void* newAddress)
1387{
1388
1389return replace_function(NULL,symbol,newAddress);
1390
1391}
1392

Archive Download this file

Revision: 1913