Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 633