Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 742