#include "bootstruct.h"␊ |
#include "modules.h"␊ |
␊ |
#include "sl.h"␊ |
#include "xml.h"␊ |
␊ |
#ifndef DEBUG_MODULES␊ |
#define DEBUG_MODULES 0␊ |
#endif␊ |
|
#define DBG(x...)␊ |
#endif␊ |
␊ |
struct Bundle { ␊ |
␉struct Bundle *nextBundle;␊ |
␉long willLoad;␊ |
␉TagPtr dict;␊ |
TagPtr personalities;␊ |
#if 0␊ |
␉config_file_t *LanguageConfig; // we will use an xml file instead of pure txt file ... it's easier to parse␊ |
#endif␊ |
␉//pool_t workspace;␊ |
␉char *plistAddr;␊ |
␉long plistLength;␊ |
␉char *executablePath;␊ |
␉char *bundlePath;␊ |
␉long bundlePathLength;␊ |
};␊ |
typedef struct Bundle Bundle, *BundlePtr;␊ |
␊ |
// NOTE: Global so that modules can link with this␊ |
unsigned long long textAddress = 0;␊ |
unsigned long long textSection = 0;␊ |
|
symbolList_t* moduleSymbols = NULL;␊ |
unsigned int (*lookup_symbol)(const char*, int(*strcmp_callback)(const char*, const char*)) = NULL;␊ |
moduleHook_t* get_callback(const char* name);␊ |
static unsigned int load_module(char * name, char* module);␊ |
static unsigned int load_module(char * name, char* module, BundlePtr bundle);␊ |
static EFI_STATUS _bind_macho(char* module, void* base, char* bind_stream, UInt32 size, BundlePtr bundle);␊ |
␊ |
#if macho_64␊ |
static unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long, char), BundlePtr bundle);␊ |
#else␊ |
static unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long), BundlePtr bundle);␊ |
#endif␊ |
␊ |
#if DEBUG_MODULES␊ |
VOID print_symbol_list(VOID);␊ |
VOID print_hook_list(VOID);␊ |
|
return;␊ |
}␊ |
msglog("* Attempting to load module: %s\n", tmp);␊ |
module_start = (void*)load_module(dylib_name,tmp);␊ |
module_start = (void*)load_module(dylib_name,tmp, NULL);␊ |
␊ |
if(module_start && ( module_start != (void*)0xFFFFFFFF))␊ |
{␊ |
|
continue;␊ |
}␊ |
msglog("* Attempting to load module: %s\n", tmp);␊ |
module_start = (void*)load_module(dylib_name,tmp);␊ |
module_start = (void*)load_module(dylib_name,tmp, NULL);␊ |
␊ |
if(module_start && ( module_start != (void*)0xFFFFFFFF))␊ |
{␊ |
|
/*␊ |
* Load a module file ␊ |
*/␊ |
static unsigned int load_module(char * name, char* module)␊ |
static unsigned int load_module(char * name, char* module, BundlePtr bundle)␊ |
{␊ |
␉unsigned int module_start = 0xFFFFFFFF;␊ |
␊ |
|
␉␉␉DBG("Module %s read in.\n", module);␊ |
␉␉␉␊ |
␉␉␉// Module loaded into memory, parse it␊ |
␉␉␉module_start = parse_mach(name, module_base, &add_symbol); ␊ |
␉␉␉module_start = parse_mach(name, module_base, &add_symbol, bundle); ␊ |
␉␉␉␊ |
␉␉␉␊ |
␉␉}␊ |
|
* happen as all dependencies are verified before the sybols are read in.␊ |
*/␊ |
#if macho_64␊ |
unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long, char))␉// TODO: add param to specify valid archs␊ |
static unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long, char), BundlePtr bundle)␉// TODO: add param to specify valid archs␊ |
#else␊ |
unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long))␉// TODO: add param to specify valid archs␊ |
static unsigned int parse_mach(char *module, void* binary, long long(*symbol_handler)(char*, char*, long long), BundlePtr bundle)␉// TODO: add param to specify valid archs␊ |
#endif␊ |
{␉␊ |
#if macho_64␊ |
|
␉␊ |
␉if(dyldInfoCommand && dyldInfoCommand->bind_off)␊ |
␉{␊ |
␉␉bind_status = bind_macho(module, binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);␊ |
␉␉bind_status = _bind_macho(module, binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size, bundle);␊ |
␉}␊ |
␉␊ |
␉if(dyldInfoCommand && dyldInfoCommand->weak_bind_off && (bind_status == EFI_SUCCESS))␊ |
␉{␊ |
␉␉// NOTE: this currently should never happen.␊ |
␉␉bind_status = bind_macho(module, binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);␊ |
␉␉bind_status = _bind_macho(module, binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size, bundle);␊ |
␉}␊ |
␉␊ |
␉if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off && (bind_status == EFI_SUCCESS))␊ |
␉{␊ |
␉␉// NOTE: we are binding the lazy pointers as a module is laoded,␊ |
␉␉// This should be changed to bind when a symbol is referened at runtime instead.␊ |
␉␉bind_status = bind_macho(module, binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);␊ |
␉␉bind_status = _bind_macho(module, binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size, bundle);␊ |
␉}␊ |
␉␊ |
if (bind_status != EFI_SUCCESS) {␊ |
|
// There is apossibility that this could cause issues,␊ |
// however the macho file is 32 bit, so it shouldn't matter too much␊ |
EFI_STATUS bind_macho(char* module, void* base, char* bind_stream, UInt32 size)␊ |
{␊ |
␉return _bind_macho( module, base, bind_stream, size, NULL);␊ |
}␊ |
␊ |
static EFI_STATUS _bind_macho(char* module, void* base, char* bind_stream, UInt32 size, BundlePtr bundle)␊ |
{␉␊ |
␉bind_stream += (UInt32)base;␊ |
␉␊ |
|
␉␉␉␉UInt8 symbolFlags = immediate;␊ |
DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symbolFlags);␊ |
#endif␉␉␉␉␊ |
␉␉␉␉symbolAddr = 0xFFFFFFFF;␊ |
␉␉␉␉TagPtr prop;␊ |
␉␉␉␉␊ |
␉␉␉␉symbolAddr = lookup_all_symbols("EXTERNAL" ,symbolName); /* Dirty hack, this will be replaced soon by a better mechanism */␊ |
␉␉␉␉if (bundle != NULL)␊ |
␉␉␉␉{␊ |
␉␉␉␉␉prop = XMLGetProperty(bundle->dict, kPropOSBundleLibraries);␊ |
␉␉␉␉␉if (prop != 0)␊ |
␉␉␉␉␉{␊ |
␉␉␉␉␉␉prop = prop->tag;␊ |
␉␉␉␉␉␉while (prop != 0)␊ |
␉␉␉␉␉␉{␊ |
␉␉␉␉␉␉␉/* the order in OSBundleLibraries is important */␊ |
␊ |
␉␉␉␉␉␉␉if (prop->string)␊ |
␉␉␉␉␉␉␉{␊ |
␉␉␉␉␉␉␉␉symbolAddr = lookup_all_symbols(prop->string ,symbolName); ␊ |
␉␉␉␉␉␉␉␉␊ |
␉␉␉␉␉␉␉␉if (symbolAddr != 0xFFFFFFFF) break; // the symbol is found , we can exit the loop␊ |
␉␉␉␉␉␉␉}␉␉␉␉␉␉␉␊ |
␉␉␉␉␉␉␉␊ |
␉␉␉␉␉␉␉prop = prop->tagNext;␊ |
␊ |
␉␉␉␉␉␉}␊ |
␉␉␉␉␉}␊ |
␉␉␉␉␉␊ |
␉␉␉␉}␉␉␉␉␊ |
␉␉␉␉␊ |
if (symbolAddr == 0xFFFFFFFF) symbolAddr = lookup_all_symbols(NULL ,symbolName);␊ |
if (symbolAddr == 0xFFFFFFFF) symbolAddr = lookup_all_symbols(NULL ,symbolName); // at this point if the symbol is still undefined, we search everywhere by starting to the internal symbols␊ |
␉␉␉␉␊ |
if((symbolAddr == 0xFFFFFFFF) && (strncmp(symbolName, SYMBOL_DYLD_STUB_BINDER,sizeof(SYMBOL_DYLD_STUB_BINDER)) != 0))␊ |
␉␉␉␉{␉␉␉␉␉␊ |
|
#include <libkern/OSByteOrder.h>␊ |
#include <mach/machine.h>␊ |
␊ |
#include "sl.h"␊ |
#include "xml.h"␊ |
␊ |
struct Module { ␊ |
␉struct Module *nextModule;␊ |
␉long willLoad;␊ |
␉TagPtr dict;␊ |
TagPtr personalities;␊ |
#if 0␊ |
␉config_file_t *LanguageConfig; // we will use an xml file instead of pure txt file ... it's easier to parse␊ |
#endif␊ |
␉//pool_t workspace;␊ |
␉char *plistAddr;␊ |
␉long plistLength;␊ |
␉char *executablePath;␊ |
␉char *bundlePath;␊ |
␉long bundlePathLength;␊ |
};␊ |
typedef struct Module Module, *ModulePtr;␊ |
␊ |
␊ |
enum {␊ |
|
␊ |
};␊ |
␊ |
static ModulePtr gModuleHead;␊ |
static char * gModulesSpec;␊ |
static BundlePtr gBundleHead;␊ |
static char * gBundlesSpec;␊ |
static char * gDriverSpec;␊ |
static char * gFileSpec;␊ |
static char * gTempSpec;␊ |
static char * gFileName;␊ |
static int gLowestLoadPriority;␊ |
␊ |
static long ParseXML(char *buffer, ModulePtr *module);␊ |
static ModulePtr FindBundle( char * bundle_id );␊ |
static long ParseXML(char *buffer, BundlePtr *module);␊ |
static BundlePtr FindBundle( char * bundle_id );␊ |
␊ |
static void␊ |
FreeBundleSupport( void )␊ |
{␊ |
␊ |
if ( gModulesSpec ) free(gModulesSpec);␊ |
if ( gBundlesSpec ) free(gBundlesSpec);␊ |
if ( gDriverSpec) free(gDriverSpec);␊ |
if ( gFileSpec ) free(gFileSpec);␊ |
if ( gTempSpec ) free(gTempSpec);␊ |
|
␊ |
if (BundleSet == true) return 0; ␊ |
␊ |
gModulesSpec = malloc( DEFAULT_BUNDLE_SPEC_SIZE );␊ |
gBundlesSpec = malloc( DEFAULT_BUNDLE_SPEC_SIZE );␊ |
gDriverSpec = malloc( DEFAULT_BUNDLE_SPEC_SIZE );␊ |
gFileSpec = malloc( DEFAULT_BUNDLE_SPEC_SIZE );␊ |
gTempSpec = malloc( DEFAULT_BUNDLE_SPEC_SIZE );␊ |
gFileName = malloc( DEFAULT_BUNDLE_SPEC_SIZE );␊ |
␊ |
if ( !gModulesSpec || !gDriverSpec || !gFileSpec || !gTempSpec || !gFileName )␊ |
if ( !gBundlesSpec || !gDriverSpec || !gFileSpec || !gTempSpec || !gFileName )␊ |
goto error;␊ |
␊ |
BundleSet = true;␊ |
|
return 1;␊ |
␉␊ |
␉␊ |
␉strlcpy(gModulesSpec, dirSpec, DEFAULT_BUNDLE_SPEC_SIZE);␊ |
strlcat(gModulesSpec, "Modules", DEFAULT_BUNDLE_SPEC_SIZE);␊ |
FileLoadBundles(gModulesSpec, 0);␉␉␊ |
␉strlcpy(gBundlesSpec, dirSpec, DEFAULT_BUNDLE_SPEC_SIZE);␊ |
strlcat(gBundlesSpec, "Modules", DEFAULT_BUNDLE_SPEC_SIZE);␊ |
FileLoadBundles(gBundlesSpec, 0);␉␉␊ |
␊ |
␉␊ |
MatchBundlesLibraries();␊ |
|
}␊ |
␊ |
␊ |
static void add_bundle(ModulePtr module,char* name)␊ |
static void add_bundle(BundlePtr module,char* name)␊ |
{␊ |
␉ModulePtr new_entry= malloc(sizeof(Module));␊ |
␉BundlePtr new_entry= malloc(sizeof(Bundle));␊ |
␉DBG("Adding bundle %s \n", name );␊ |
␉if (new_entry)␊ |
␉{␉␊ |
␉␉new_entry->nextModule = gModuleHead;␊ |
␉␉new_entry->nextBundle = gBundleHead;␊ |
␉␉␊ |
␉␉gModuleHead = new_entry;␊ |
␉␉gBundleHead = new_entry;␊ |
␉␉␊ |
␉␉new_entry->executablePath = module->executablePath;␊ |
new_entry->bundlePath = module->bundlePath;␊ |
|
LoadBundlePList( char * dirSpec, char * name, long bundleType )␊ |
{␊ |
long length, executablePathLength, bundlePathLength;␊ |
ModulePtr module = 0;␊ |
BundlePtr module = 0;␊ |
char * buffer = 0;␊ |
char * tmpExecutablePath = 0;␊ |
char * tmpBundlePath = 0;␊ |
|
}␊ |
␊ |
#define WillLoadBundles \␊ |
module = gModuleHead; \␊ |
module = gBundleHead; \␊ |
while (module != NULL) \␊ |
{ \␊ |
if (module->willLoad == willLoad) \␊ |
|
fileName = prop->string; \␊ |
snprintf(gFileSpec, DEFAULT_BUNDLE_SPEC_SIZE,"%s%s", module->executablePath, fileName); \␊ |
\␊ |
module_start = (void*)load_module((char*)fileName,gFileSpec); \␊ |
module_start = (void*)load_module((char*)fileName,gFileSpec,module); \␊ |
if(!module_start || (*module_start == (void*)0xFFFFFFFF)) \␊ |
{ \␊ |
if (module->willLoad > BundlePrioritySystemLib) \␊ |
|
} \␊ |
} \␊ |
} \␊ |
module = module->nextModule; \␊ |
module = module->nextBundle; \␊ |
} ␊ |
␊ |
//==========================================================================␊ |
|
long LoadMatchedBundles( void )␊ |
{␊ |
TagPtr prop;␊ |
ModulePtr module;␊ |
BundlePtr module;␊ |
char *fileName;␊ |
void (*module_start)(void);␊ |
long willLoad;␊ |
|
{␊ |
␊ |
TagPtr prop, prop2;␊ |
ModulePtr module, module2,dummy_module;␊ |
BundlePtr module, module2,dummy_module;␊ |
␉␊ |
// Check for active modules with the same Bundle IDs or same principal class, only one must remain (except for type 3 aka system libs)␊ |
{␊ |
module = gModuleHead;␊ |
module = gBundleHead;␊ |
␊ |
while (module != 0)␊ |
{␊ |
if (!(module->willLoad > BundlePriorityInit)) // if the module load priority is not higher than initialized, continue␊ |
{␊ |
module = module->nextModule;␊ |
module = module->nextBundle;␊ |
continue;␊ |
}␊ |
␊ |
|
␊ |
if (prop != 0 && prop2 != 0)␊ |
{ ␊ |
module2 = gModuleHead;␊ |
module2 = gBundleHead;␊ |
␊ |
TagPtr prop3,prop4;␊ |
␊ |
|
}␊ |
␊ |
}␊ |
module2 = module2->nextModule;␊ |
module2 = module2->nextBundle;␊ |
} ␊ |
␊ |
}␊ |
␊ |
module = module->nextModule;␊ |
module = module->nextBundle;␊ |
}␊ |
}␊ |
␊ |
// Check for dependencies (it works in most cases, still a little buggy but should be sufficient for what we have to do, ␊ |
␉// clearly the Achilles' heel of this implementation, please use dependencies with caution !!!)␊ |
dummy_module = gModuleHead;␊ |
dummy_module = gBundleHead;␊ |
while (dummy_module != 0)␊ |
{␊ |
module = gModuleHead;␊ |
module = gBundleHead;␊ |
␊ |
while (module != 0)␊ |
{␊ |
|
prop = prop->tag;␊ |
while (prop != 0)␊ |
{␊ |
module2 = gModuleHead;␊ |
module2 = gBundleHead;␊ |
while (module2 != 0)␊ |
{␊ |
prop2 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);␊ |
|
␊ |
}␊ |
␉␉␉␉␉␉␉if (module->willLoad != BundlePriorityNull) module->willLoad = BundlePriorityNull;␊ |
module2 = module2->nextModule;␊ |
module2 = module2->nextBundle;␊ |
}␊ |
if (module->willLoad == BundlePriorityNull) goto nextmodule;␊ |
prop = prop->tagNext;␊ |
|
}␊ |
}␊ |
nextmodule:␊ |
module = module->nextModule;␊ |
module = module->nextBundle;␊ |
}␊ |
␊ |
␉␉dummy_module = dummy_module->nextModule;␊ |
␉␉dummy_module = dummy_module->nextBundle;␊ |
}␉␊ |
␉␊ |
// Get the lowest load priority␊ |
{␊ |
gLowestLoadPriority = BundlePriorityNormalPriority;␊ |
module = gModuleHead;␊ |
module = gBundleHead;␊ |
␊ |
while (module != 0)␊ |
{␊ |
|
{ ␊ |
gLowestLoadPriority = MIN(MAX(module->willLoad,gLowestLoadPriority), BundlePriorityLowestPriority); ␊ |
}␊ |
module = module->nextModule;␊ |
module = module->nextBundle;␊ |
}␊ |
}␊ |
␊ |
|
//==========================================================================␊ |
// FindBundle␊ |
␊ |
static ModulePtr␊ |
static BundlePtr␊ |
FindBundle( char * bundle_id )␊ |
{␊ |
ModulePtr module;␊ |
BundlePtr module;␊ |
TagPtr prop;␊ |
␉DBG("FindBundle %s\n",bundle_id);␊ |
␊ |
module = gModuleHead;␊ |
module = gBundleHead;␊ |
␊ |
while (module != 0)␊ |
{␊ |
prop = XMLGetProperty(module->dict, kPropCFBundleIdentifier);␊ |
if ((prop != 0) && !strcmp(bundle_id, prop->string)) break;␊ |
module = module->nextModule;␊ |
module = module->nextBundle;␊ |
}␊ |
␊ |
return module;␊ |
|
void *␊ |
GetBundleDict( char * bundle_id )␊ |
{␊ |
ModulePtr module;␊ |
BundlePtr module;␊ |
␉DBG("GetBundleDict %s\n",bundle_id);␊ |
␊ |
module = FindBundle( bundle_id );␊ |
|
void *␊ |
GetBundlePersonality( char * bundle_id )␊ |
{␊ |
ModulePtr module;␊ |
BundlePtr module;␊ |
␉DBG("GetBundlePersonalities %s\n",bundle_id);␊ |
␊ |
module = FindBundle( bundle_id );␊ |
|
char *␊ |
GetBundlePath( char * bundle_id )␊ |
{␊ |
ModulePtr module;␊ |
BundlePtr module;␊ |
␉DBG("GetBundlePath %s\n",bundle_id);␊ |
␊ |
module = FindBundle( bundle_id );␊ |
|
// ParseXML␊ |
␊ |
static long␊ |
ParseXML( char * buffer, ModulePtr * module )␊ |
ParseXML( char * buffer, BundlePtr * module )␊ |
{␊ |
␉long length, pos;␊ |
␉TagPtr moduleDict, prop;␊ |
␉ModulePtr tmpModule;␊ |
␉BundlePtr tmpBundle;␊ |
␉␊ |
pos = 0;␊ |
␉DBG("ParseXML\n");␊ |
|
}␊ |
␉␊ |
␊ |
tmpModule = malloc(sizeof(Module));␊ |
if (tmpModule == 0)␊ |
tmpBundle = malloc(sizeof(Bundle));␊ |
if (tmpBundle == 0)␊ |
{␊ |
XMLFreeTag(moduleDict);␊ |
return -1;␊ |
}␊ |
tmpModule->dict = moduleDict;␊ |
tmpBundle->dict = moduleDict;␊ |
␊ |
do {␊ |
prop = XMLGetProperty(moduleDict, kPropOSBundleEnabled);␊ |
|
{␊ |
if ( (strlen(prop->string) >= 1) && (prop->string[0] == 'N' || prop->string[0] == 'n') )␊ |
{␊ |
tmpModule->willLoad = 0;␊ |
tmpBundle->willLoad = 0;␊ |
break;␊ |
}␊ |
}␊ |
|
{␊ |
if (!strncmp(prop->string,SYSLIB_CLASS, sizeof(SYSLIB_CLASS))) ␊ |
{␊ |
tmpModule->willLoad = BundlePrioritySystemLib;␊ |
tmpBundle->willLoad = BundlePrioritySystemLib;␊ |
break;␊ |
}␊ |
if (!strncmp(prop->string,SYS_CLASS, sizeof(SYS_CLASS))) ␊ |
{␊ |
tmpModule->willLoad = BundlePrioritySystem;␊ |
tmpBundle->willLoad = BundlePrioritySystem;␊ |
break;␊ |
}␊ |
} ␊ |
|
int tmpwillLoad;␊ |
if ((tmpwillLoad = strtoul(prop->string, NULL, 10)) > BundlePrioritySystemLib )␊ |
{ ␊ |
tmpModule->willLoad = MIN(tmpwillLoad, BundlePriorityLowestPriority);␊ |
tmpBundle->willLoad = MIN(tmpwillLoad, BundlePriorityLowestPriority);␊ |
break;␊ |
␊ |
}␊ |
␊ |
}␊ |
␉␉␊ |
tmpModule->willLoad = BundlePriorityNormalPriority;␊ |
tmpBundle->willLoad = BundlePriorityNormalPriority;␊ |
␉␉␊ |
#if 0␊ |
␉␉prop = XMLGetProperty(moduleDict, kPropCFBundleLocalizations);␊ |
|
} while (0);␊ |
␊ |
// Get the personalities.␊ |
tmpModule->personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);␊ |
tmpBundle->personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);␊ |
␊ |
*module = tmpModule;␊ |
*module = tmpBundle;␊ |
␉␊ |
␉␊ |
␉␊ |