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

Archive Download this file

Revision: 708