Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 681