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

Archive Download this file

Revision: 789