Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 850