michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: * This Original Code has been modified by IBM Corporation. michael@0: * Modifications made by IBM described herein are michael@0: * Copyright (c) International Business Machines michael@0: * Corporation, 2000 michael@0: * michael@0: * Modifications to Mozilla code or documentation michael@0: * identified per MPL Section 3.3 michael@0: * michael@0: * Date Modified by Description of modification michael@0: * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 michael@0: */ michael@0: michael@0: /* Allow logging in the release build */ michael@0: #ifdef MOZ_LOGGING michael@0: #define FORCE_PR_LOG michael@0: #endif michael@0: michael@0: #include "nsNativeComponentLoader.h" michael@0: michael@0: #include "prlog.h" michael@0: #include "prinit.h" michael@0: #include "prerror.h" michael@0: michael@0: #include "nsComponentManager.h" michael@0: #include "ManifestParser.h" // for LogMessage michael@0: #include "nsCRTGlue.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsTraceRefcnt.h" michael@0: michael@0: #include "nsIFile.h" michael@0: #include "mozilla/WindowsDllBlocklist.h" michael@0: michael@0: #ifdef XP_WIN michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef VMS michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef DEBUG michael@0: #define IMPLEMENT_BREAK_AFTER_LOAD michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: michael@0: static PRLogModuleInfo * michael@0: GetNativeModuleLoaderLog() michael@0: { michael@0: static PRLogModuleInfo *sLog; michael@0: if (!sLog) michael@0: sLog = PR_NewLogModule("nsNativeModuleLoader"); michael@0: return sLog; michael@0: } michael@0: michael@0: #define LOG(level, args) PR_LOG(GetNativeModuleLoaderLog(), level, args) michael@0: michael@0: NS_IMPL_QUERY_INTERFACE(nsNativeModuleLoader, michael@0: mozilla::ModuleLoader) michael@0: michael@0: NS_IMPL_ADDREF_USING_AGGREGATOR(nsNativeModuleLoader, michael@0: nsComponentManagerImpl::gComponentManager) michael@0: NS_IMPL_RELEASE_USING_AGGREGATOR(nsNativeModuleLoader, michael@0: nsComponentManagerImpl::gComponentManager) michael@0: michael@0: nsresult michael@0: nsNativeModuleLoader::Init() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Startup not on main thread?"); michael@0: LOG(PR_LOG_DEBUG, ("nsNativeModuleLoader::Init()")); michael@0: return NS_OK; michael@0: } michael@0: michael@0: class LoadModuleMainThreadRunnable : public nsRunnable michael@0: { michael@0: public: michael@0: LoadModuleMainThreadRunnable(nsNativeModuleLoader* loader, michael@0: FileLocation &file) michael@0: : mLoader(loader) michael@0: , mFile(file) michael@0: , mResult(nullptr) michael@0: { } michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: mResult = mLoader->LoadModule(mFile); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsRefPtr mLoader; michael@0: FileLocation mFile; michael@0: const mozilla::Module* mResult; michael@0: }; michael@0: michael@0: const mozilla::Module* michael@0: nsNativeModuleLoader::LoadModule(FileLocation &aFile) michael@0: { michael@0: if (aFile.IsZip()) { michael@0: NS_ERROR("Binary components cannot be loaded from JARs"); michael@0: return nullptr; michael@0: } michael@0: nsCOMPtr file = aFile.GetBaseFile(); michael@0: nsresult rv; michael@0: michael@0: if (!NS_IsMainThread()) { michael@0: // If this call is off the main thread, synchronously proxy it michael@0: // to the main thread. michael@0: nsRefPtr r = new LoadModuleMainThreadRunnable(this, aFile); michael@0: NS_DispatchToMainThread(r, NS_DISPATCH_SYNC); michael@0: return r->mResult; michael@0: } michael@0: michael@0: nsCOMPtr hashedFile(do_QueryInterface(file)); michael@0: if (!hashedFile) { michael@0: NS_ERROR("nsIFile is not nsIHashable"); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsAutoCString filePath; michael@0: file->GetNativePath(filePath); michael@0: michael@0: NativeLoadData data; michael@0: michael@0: if (mLibraries.Get(hashedFile, &data)) { michael@0: NS_ASSERTION(data.module, "Corrupt mLibraries hash"); michael@0: LOG(PR_LOG_DEBUG, michael@0: ("nsNativeModuleLoader::LoadModule(\"%s\") - found in cache", michael@0: filePath.get())); michael@0: return data.module; michael@0: } michael@0: michael@0: // We haven't loaded this module before michael@0: { michael@0: #ifdef HAS_DLL_BLOCKLIST michael@0: AutoSetXPCOMLoadOnMainThread guard; michael@0: #endif michael@0: rv = file->Load(&data.library); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: char errorMsg[1024] = ""; michael@0: michael@0: if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) michael@0: PR_GetErrorText(errorMsg); michael@0: michael@0: LogMessage("Failed to load native module at path '%s': (%lx) %s", michael@0: filePath.get(), rv, errorMsg); michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: #ifdef IMPLEMENT_BREAK_AFTER_LOAD michael@0: nsAutoCString leafName; michael@0: file->GetNativeLeafName(leafName); michael@0: michael@0: char *env = getenv("XPCOM_BREAK_ON_LOAD"); michael@0: char *blist; michael@0: if (env && *env && (blist = strdup(env))) { michael@0: char *nextTok = blist; michael@0: while (char *token = NS_strtok(":", &nextTok)) { michael@0: if (leafName.Find(token, true) != kNotFound) { michael@0: NS_BREAK(); michael@0: } michael@0: } michael@0: michael@0: free(blist); michael@0: } michael@0: #endif michael@0: michael@0: void *module = PR_FindSymbol(data.library, "NSModule"); michael@0: if (!module) { michael@0: LogMessage("Native module at path '%s' doesn't export symbol `NSModule`.", michael@0: filePath.get()); michael@0: PR_UnloadLibrary(data.library); michael@0: return nullptr; michael@0: } michael@0: michael@0: data.module = *(mozilla::Module const *const *) module; michael@0: if (mozilla::Module::kVersion != data.module->mVersion) { michael@0: LogMessage("Native module at path '%s' is incompatible with this version of Firefox, has version %i, expected %i.", michael@0: filePath.get(), data.module->mVersion, michael@0: mozilla::Module::kVersion); michael@0: PR_UnloadLibrary(data.library); michael@0: return nullptr; michael@0: } michael@0: michael@0: mLibraries.Put(hashedFile, data); // infallible michael@0: return data.module; michael@0: } michael@0: michael@0: PLDHashOperator michael@0: nsNativeModuleLoader::ReleaserFunc(nsIHashable* aHashedFile, michael@0: NativeLoadData& aLoadData, void*) michael@0: { michael@0: aLoadData.module = nullptr; michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: PLDHashOperator michael@0: nsNativeModuleLoader::UnloaderFunc(nsIHashable* aHashedFile, michael@0: NativeLoadData& aLoadData, void*) michael@0: { michael@0: if (PR_LOG_TEST(GetNativeModuleLoaderLog(), PR_LOG_DEBUG)) { michael@0: nsCOMPtr file(do_QueryInterface(aHashedFile)); michael@0: michael@0: nsAutoCString filePath; michael@0: file->GetNativePath(filePath); michael@0: michael@0: LOG(PR_LOG_DEBUG, michael@0: ("nsNativeModuleLoader::UnloaderFunc(\"%s\")", filePath.get())); michael@0: } michael@0: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: nsTraceRefcnt::SetActivityIsLegal(false); michael@0: #endif michael@0: michael@0: #if 0 michael@0: // XXXbsmedberg: do this as soon as the static-destructor crash(es) michael@0: // are fixed michael@0: PRStatus ret = PR_UnloadLibrary(aLoadData.library); michael@0: NS_ASSERTION(ret == PR_SUCCESS, "Failed to unload library"); michael@0: #endif michael@0: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: nsTraceRefcnt::SetActivityIsLegal(true); michael@0: #endif michael@0: michael@0: return PL_DHASH_REMOVE; michael@0: } michael@0: michael@0: void michael@0: nsNativeModuleLoader::UnloadLibraries() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Shutdown not on main thread?"); michael@0: mLibraries.Enumerate(ReleaserFunc, nullptr); michael@0: mLibraries.Enumerate(UnloaderFunc, nullptr); michael@0: }