Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 1468