Back to index

lightning-sunbird  0.9+nobinonly
xcDll.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /* nsDll
00039  *
00040  * Abstraction of a Dll. Stores modifiedTime and size for easy detection of
00041  * change in dll.
00042  *
00043  * dp Suresh <dp@netscape.com>
00044  */
00045 
00046 #include "xcDll.h"
00047 #include "nsDebug.h"
00048 #include "nsIComponentManager.h"
00049 #include "nsIComponentLoaderManager.h"
00050 #include "nsIModule.h"
00051 #include "nsILocalFile.h"
00052 #include "nsDirectoryServiceDefs.h"
00053 #include "nsDirectoryServiceUtils.h"
00054 #include "nsCOMPtr.h"
00055 #include "nsCRT.h"
00056 #include "nsString.h"
00057 #include "nsITimelineService.h"
00058 #include "nsModule.h"
00059 #ifdef DEBUG
00060 #if defined(VMS)
00061 #include <lib$routines.h>
00062 #include <ssdef.h>
00063 #elif defined(XP_MACOSX)
00064 #include <signal.h>
00065 #endif
00066 #endif /* defined(DEBUG) */
00067 
00068 #include "nsTraceRefcntImpl.h"
00069 
00070 #define UNLOAD_DEPENDENT_LIBS
00071 #ifdef HPUX
00072 #undef UNLOAD_DEPENDENT_LIBS
00073 #endif
00074 
00075 #include "nsNativeComponentLoader.h"
00076 
00077 nsDll::nsDll(nsIFile *dllSpec, nsNativeComponentLoader *loader)
00078     : m_dllSpec(do_QueryInterface(dllSpec)),
00079       m_instance(NULL), 
00080       m_moduleObject(NULL),
00081       m_loader(loader),
00082       m_markForUnload(PR_FALSE)
00083 {
00084     NS_ASSERTION(loader, "Null loader when creating a nsDLL");
00085 }
00086 
00087 nsDll::~nsDll(void)
00088 {
00089     //#if DEBUG_dougt
00090     // The dll gets deleted when the dllStore is destroyed. This happens on
00091     // app shutdown. At that point, unloading dlls can cause crashes if we have
00092     // - dll dependencies
00093     // - callbacks
00094     // - static dtors
00095     // Hence turn it back on after all the above have been removed.
00096     //Unload();
00097     //#endif
00098 }
00099 
00100 void
00101 nsDll::GetDisplayPath(nsACString& aLeafName)
00102 {
00103     m_dllSpec->GetNativeLeafName(aLeafName);
00104     
00105     if (aLeafName.IsEmpty())
00106         aLeafName.AssignLiteral("unknown!");
00107 }
00108 
00109 PRBool
00110 nsDll::HasChanged()
00111 {
00112     nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(m_loader->mCompMgr);
00113     if (!manager)
00114         return PR_TRUE;
00115 
00116     // If mod date has changed, then dll has changed
00117     PRInt64 currentDate;
00118     nsresult rv = m_dllSpec->GetLastModifiedTime(&currentDate);
00119     if (NS_FAILED(rv))
00120         return PR_TRUE;
00121     PRBool changed = PR_TRUE;
00122     manager->HasFileChanged(m_dllSpec, nsnull, currentDate, &changed); 
00123     return changed;
00124 }
00125 
00126 PRBool nsDll::Load(void)
00127 {
00128        if (m_instance != NULL)
00129        {
00130               // Already loaded
00131               return (PR_TRUE);
00132        }
00133 
00134     if (m_dllSpec)
00135     {
00136 #ifdef NS_BUILD_REFCNT_LOGGING
00137         nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE);
00138 #endif
00139         
00140     // load the component
00141     nsCOMPtr<nsILocalFile> lf(do_QueryInterface(m_dllSpec));
00142     NS_ASSERTION(lf, "nsIFile here must implement a nsILocalFile"); 
00143     lf->Load(&m_instance);
00144 
00145 #ifdef NS_BUILD_REFCNT_LOGGING
00146         nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE);
00147         if (m_instance) {
00148             // Inform refcnt tracer of new library so that calls through the
00149             // new library can be traced.
00150             nsXPIDLCString displayPath;
00151             GetDisplayPath(displayPath);
00152             nsTraceRefcntImpl::LoadLibrarySymbols(displayPath.get(), m_instance);
00153         }
00154 #endif
00155     }
00156 
00157 #ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD
00158     // Debugging help for components. Component dlls need to have their
00159     // symbols loaded before we can put a breakpoint in the debugger.
00160     // This will help figureing out the point when the dll was loaded.
00161     nsXPIDLCString displayPath;
00162     GetDisplayPath(displayPath);
00163     BreakAfterLoad(displayPath.get());
00164 #endif
00165 
00166     return ((m_instance == NULL) ? PR_FALSE : PR_TRUE);
00167 }
00168 
00169 PRBool nsDll::Unload(void)
00170 {
00171        if (m_instance == NULL)
00172               return (PR_FALSE);
00173 
00174     // Shutdown the dll
00175     Shutdown();
00176 
00177 #ifdef NS_BUILD_REFCNT_LOGGING
00178     nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE);
00179 #endif
00180        PRStatus ret = PR_UnloadLibrary(m_instance);
00181 #ifdef NS_BUILD_REFCNT_LOGGING
00182     nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE);
00183 #endif
00184 
00185        if (ret == PR_SUCCESS)
00186        {
00187               m_instance = NULL;
00188               return (PR_TRUE);
00189        }
00190        else
00191               return (PR_FALSE);
00192 }
00193 
00194 void * nsDll::FindSymbol(const char *symbol)
00195 {
00196        if (symbol == NULL)
00197               return (NULL);
00198        
00199        // If not already loaded, load it now.
00200        if (Load() != PR_TRUE)
00201               return (NULL);
00202 
00203     return(PR_FindSymbol(m_instance, symbol));
00204 }
00205 
00206 
00207 // Component dll specific functions
00208 nsresult nsDll::GetDllSpec(nsIFile **fsobj)
00209 {
00210     NS_ASSERTION(m_dllSpec, "m_dllSpec NULL");
00211     NS_ASSERTION(fsobj, "xcDll::GetModule : Null argument" );
00212 
00213     *fsobj = m_dllSpec;
00214     NS_ADDREF(*fsobj);
00215     return NS_OK;
00216 }
00217 
00218 nsresult nsDll::GetModule(nsISupports *servMgr, nsIModule **cobj)
00219 {
00220     // using the backpointer of the loader.
00221     nsIComponentManager* compMgr = m_loader->mCompMgr;
00222     NS_ASSERTION(compMgr, "Global Component Manager is null" );
00223     if (!compMgr) return NS_ERROR_UNEXPECTED;
00224 
00225     NS_ASSERTION(cobj, "xcDll::GetModule : Null argument" );
00226 
00227     if (m_moduleObject)
00228     {
00229         NS_ADDREF(m_moduleObject);
00230         *cobj = m_moduleObject;
00231         return NS_OK;
00232     }
00233 
00234        // If not already loaded, load it now.
00235        if (Load() != PR_TRUE) return NS_ERROR_FAILURE;
00236 
00237     // We need a nsIFile for location
00238     if (!m_dllSpec)
00239     {
00240         return NS_ERROR_FAILURE;
00241     }
00242 
00243     nsGetModuleProc proc =
00244       (nsGetModuleProc) FindSymbol(NS_GET_MODULE_SYMBOL);
00245 
00246     if (proc == NULL)
00247         return NS_ERROR_FACTORY_NOT_LOADED;
00248 
00249     nsresult rv = (*proc) (compMgr, m_dllSpec, &m_moduleObject);
00250     if (NS_SUCCEEDED(rv))
00251     {
00252         NS_ADDREF(m_moduleObject);
00253         *cobj = m_moduleObject;
00254     }
00255     return rv;
00256 }
00257 
00258 
00259 // These are used by BreakAfterLoad, below.
00260 #ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD
00261 static nsCString *sBreakList[16];
00262 static int sBreakListCount = 0;
00263 #endif
00264 
00265 nsresult nsDll::Shutdown(void)
00266 {
00267     // Release the module object if we got one
00268     nsrefcnt refcnt;
00269     if (m_moduleObject)
00270     {
00271         NS_RELEASE2(m_moduleObject, refcnt);
00272         NS_ASSERTION(refcnt == 0, "Dll moduleObject refcount non zero");
00273     }
00274 #ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD
00275     for (int i = 0; i < sBreakListCount; i++)
00276     {
00277         delete sBreakList[i];
00278         sBreakList[i] = nsnull;
00279     }
00280     sBreakListCount = 0;
00281 #endif
00282     return NS_OK;
00283 
00284 }
00285 #ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD
00286 void nsDll::BreakAfterLoad(const char *nsprPath)
00287 {
00288     static PRBool firstTime = PR_TRUE;
00289 
00290     // return if invalid input
00291     if (!nsprPath || !*nsprPath) return;
00292 
00293     // return if nothing to break on
00294     if (!firstTime && sBreakListCount == 0) return;
00295 
00296     if (firstTime)
00297     {
00298         firstTime = PR_FALSE;
00299         // Form the list of dlls to break on load
00300         nsCAutoString envList(getenv("XPCOM_BREAK_ON_LOAD"));
00301         if (envList.IsEmpty()) return;
00302         PRInt32 ofset = 0;
00303         PRInt32 start = 0;
00304         do
00305         {
00306             ofset = envList.FindChar(':', start);
00307             sBreakList[sBreakListCount] = new nsCString();
00308             envList.Mid(*(sBreakList[sBreakListCount]), start, ofset);
00309             sBreakListCount++;
00310             start = ofset + 1;
00311         }
00312         while (ofset != -1 && 16 > sBreakListCount); // avoiding vc6.0 compiler issue. count < thinks it is starting a template
00313     }
00314 
00315     // Find the dllname part of the string
00316     nsCString currentPath(nsprPath);
00317     PRInt32 lastSep = currentPath.RFindCharInSet(":\\/");
00318 
00319     for (int i=0; i<sBreakListCount; i++)
00320         if (currentPath.Find(*(sBreakList[i]), PR_TRUE, lastSep) > 0)
00321         {
00322             // Loading a dll that we want to break on
00323             // Put your breakpoint here
00324             fprintf(stderr, "...Loading module %s\n", nsprPath);
00325             // Break in the debugger here.
00326 #if defined(__i386) && defined(__GNUC__)
00327             asm("int $3");
00328 #elif defined(VMS)
00329             lib$signal(SS$_DEBUG);
00330 #elif defined(XP_MACOSX)
00331             raise(SIGTRAP);
00332 #endif
00333         }
00334     return;
00335 }
00336 #endif /* SHOULD_IMPLEMENT_BREAKAFTERLOAD */