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

Archive Download this file

Revision: 714