VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/components/xcDll.cpp@ 101837

Last change on this file since 101837 was 101803, checked in by vboxsync, 16 months ago

libs/xpcom: Get rid of code used only if MOZ_TIMELINE is defined which we never do, bugref:10545

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38/* nsDll
39 *
40 * Abstraction of a Dll. Stores modifiedTime and size for easy detection of
41 * change in dll.
42 *
43 * dp Suresh <[email protected]>
44 */
45
46#include "xcDll.h"
47#include "nsDebug.h"
48#include "nsIComponentManager.h"
49#include "nsIComponentLoaderManager.h"
50#include "nsIModule.h"
51#include "nsILocalFile.h"
52#include "nsDirectoryServiceDefs.h"
53#include "nsDirectoryServiceUtils.h"
54#include "nsCOMPtr.h"
55#include "nsCRT.h"
56#include "nsString.h"
57#include "nsModule.h"
58#ifdef DEBUG
59#if defined(VMS)
60#include <lib$routines.h>
61#include <ssdef.h>
62#elif defined(XP_MACOSX)
63#include <signal.h>
64#endif
65#endif /* defined(DEBUG) */
66
67#include "nsTraceRefcntImpl.h"
68
69#define UNLOAD_DEPENDENT_LIBS
70#ifdef HPUX
71#undef UNLOAD_DEPENDENT_LIBS
72#endif
73
74#include "nsNativeComponentLoader.h"
75#ifdef VBOX_USE_IPRT_IN_XPCOM
76# include "nsMemory.h"
77#endif
78
79nsDll::nsDll(nsIFile *dllSpec, nsNativeComponentLoader *loader)
80 : m_dllSpec(do_QueryInterface(dllSpec)),
81 m_instance(NULL),
82 m_moduleObject(NULL),
83 m_loader(loader),
84 m_markForUnload(PR_FALSE)
85{
86 NS_ASSERTION(loader, "Null loader when creating a nsDLL");
87}
88
89nsDll::~nsDll(void)
90{
91 //#if DEBUG_dougt
92 // The dll gets deleted when the dllStore is destroyed. This happens on
93 // app shutdown. At that point, unloading dlls can cause crashes if we have
94 // - dll dependencies
95 // - callbacks
96 // - static dtors
97 // Hence turn it back on after all the above have been removed.
98 //Unload();
99 //#endif
100}
101
102void
103nsDll::GetDisplayPath(nsACString& aLeafName)
104{
105 m_dllSpec->GetNativeLeafName(aLeafName);
106
107 if (aLeafName.IsEmpty())
108 aLeafName.AssignLiteral("unknown!");
109}
110
111PRBool
112nsDll::HasChanged()
113{
114 nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(m_loader->mCompMgr);
115 if (!manager)
116 return PR_TRUE;
117
118 // If mod date has changed, then dll has changed
119 PRInt64 currentDate;
120 nsresult rv = m_dllSpec->GetLastModifiedTime(&currentDate);
121 if (NS_FAILED(rv))
122 return PR_TRUE;
123 PRBool changed = PR_TRUE;
124 manager->HasFileChanged(m_dllSpec, nsnull, currentDate, &changed);
125 return changed;
126}
127
128PRBool nsDll::Load(void)
129{
130 if (m_instance != NULL)
131 {
132 // Already loaded
133 return (PR_TRUE);
134 }
135
136 if (m_dllSpec)
137 {
138#ifdef NS_BUILD_REFCNT_LOGGING
139 nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE);
140#endif
141
142 // Load any library dependencies
143 // The Component Loader Manager may hold onto some extra data
144 // set by either the native component loader or the native
145 // component. We assume that this data is a space delimited
146 // listing of dependent libraries which are required to be
147 // loaded prior to us loading the given component. Once, the
148 // component is loaded into memory, we can release our hold
149 // on the dependent libraries with the assumption that the
150 // component library holds a reference via the OS so loader.
151
152#if defined(XP_UNIX)
153 nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(m_loader->mCompMgr);
154 if (!manager)
155 return PR_TRUE;
156
157 nsXPIDLCString extraData;
158 manager->GetOptionalData(m_dllSpec, nsnull, getter_Copies(extraData));
159
160#ifdef UNLOAD_DEPENDENT_LIBS
161 nsVoidArray dependentLibArray;
162#endif
163
164 // if there was any extra data, treat it as a listing of dependent libs
165 if (extraData != nsnull)
166 {
167 // all dependent libraries are suppose to be in the "gre" directory.
168 // note that the gre directory is the same as the "bin" directory,
169 // when there isn't a real "gre" found.
170
171 nsXPIDLCString path;
172 nsCOMPtr<nsIFile> file;
173 NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
174
175 if (!file)
176 return NS_ERROR_FAILURE;
177
178 // we are talking about a file in the GRE dir. Lets append something
179 // stupid right now, so that later we can just set the leaf name.
180 file->AppendNative(NS_LITERAL_CSTRING("dummy"));
181
182# ifdef VBOX_USE_IPRT_IN_XPCOM
183 char *buffer = (char *)nsMemory::Clone(extraData, strlen(extraData) + 1);
184# else
185 char *buffer = strdup(extraData);
186# endif
187 if (!buffer)
188 return NS_ERROR_OUT_OF_MEMORY;
189
190 char* newStr;
191 char *token = nsCRT::strtok(buffer, " ", &newStr);
192 while (token!=nsnull)
193 {
194 nsCStringKey key(token);
195 if (m_loader->mLoadedDependentLibs.Get(&key)) {
196 token = nsCRT::strtok(newStr, " ", &newStr);
197 continue;
198 }
199
200 m_loader->mLoadedDependentLibs.Put(&key, (void*)1);
201
202 nsXPIDLCString libpath;
203 file->SetNativeLeafName(nsDependentCString(token));
204 file->GetNativePath(path);
205 if (!path)
206 return NS_ERROR_FAILURE;
207
208 // Load this dependent library with the global flag and stash
209 // the result for later so that we can unload it.
210 PRLibSpec libSpec;
211 libSpec.type = PR_LibSpec_Pathname;
212
213 // if the depend library path starts with a / we are
214 // going to assume that it is a full path and should
215 // be loaded without prepending the gre diretory
216 // location. We could have short circuited the
217 // SetNativeLeafName above, but this is clearer and
218 // the common case is a relative path.
219
220 if (token[0] == '/')
221 libSpec.value.pathname = token;
222 else
223 libSpec.value.pathname = path;
224
225 PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_LAZY|PR_LD_GLOBAL);
226 // if we couldn't load the dependent library. We did the best we
227 // can. Now just let us fail later if this really was a required
228 // dependency.
229#ifdef UNLOAD_DEPENDENT_LIBS
230 if (lib)
231 dependentLibArray.AppendElement((void*)lib);
232#endif
233
234 token = nsCRT::strtok(newStr, " ", &newStr);
235 }
236# ifdef VBOX_USE_IPRT_IN_XPCOM
237 nsMemory::Free(buffer);
238# else
239 free(buffer);
240# endif
241 }
242#endif
243
244 // load the component
245 nsCOMPtr<nsILocalFile> lf(do_QueryInterface(m_dllSpec));
246 NS_ASSERTION(lf, "nsIFile here must implement a nsILocalFile");
247 lf->Load(&m_instance);
248
249#if defined(XP_UNIX)
250 // Unload any of library dependencies we loaded earlier. The assumption
251 // here is that the component will have a "internal" reference count to
252 // the dependency library we just loaded.
253 // XXX should we unload later - or even at all?
254
255#ifdef UNLOAD_DEPENDENT_LIBS
256 if (extraData != nsnull)
257 {
258 PRInt32 arrayCount = dependentLibArray.Count();
259 for (PRInt32 index = 0; index < arrayCount; index++)
260 PR_UnloadLibrary((PRLibrary*)dependentLibArray.ElementAt(index));
261 }
262#endif
263#endif
264
265#ifdef NS_BUILD_REFCNT_LOGGING
266 nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE);
267 if (m_instance) {
268 // Inform refcnt tracer of new library so that calls through the
269 // new library can be traced.
270 nsXPIDLCString displayPath;
271 GetDisplayPath(displayPath);
272 nsTraceRefcntImpl::LoadLibrarySymbols(displayPath.get(), m_instance);
273 }
274#endif
275 }
276
277#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD
278 // Debugging help for components. Component dlls need to have their
279 // symbols loaded before we can put a breakpoint in the debugger.
280 // This will help figureing out the point when the dll was loaded.
281 nsXPIDLCString displayPath;
282 GetDisplayPath(displayPath);
283 BreakAfterLoad(displayPath.get());
284#endif
285
286 return ((m_instance == NULL) ? PR_FALSE : PR_TRUE);
287}
288
289PRBool nsDll::Unload(void)
290{
291 if (m_instance == NULL)
292 return (PR_FALSE);
293
294 // Shutdown the dll
295 Shutdown();
296
297#ifdef NS_BUILD_REFCNT_LOGGING
298 nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE);
299#endif
300 PRStatus ret = PR_UnloadLibrary(m_instance);
301#ifdef NS_BUILD_REFCNT_LOGGING
302 nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE);
303#endif
304
305 if (ret == PR_SUCCESS)
306 {
307 m_instance = NULL;
308 return (PR_TRUE);
309 }
310 else
311 return (PR_FALSE);
312}
313
314void * nsDll::FindSymbol(const char *symbol)
315{
316 if (symbol == NULL)
317 return (NULL);
318
319 // If not already loaded, load it now.
320 if (Load() != PR_TRUE)
321 return (NULL);
322
323 return(PR_FindSymbol(m_instance, symbol));
324}
325
326
327// Component dll specific functions
328nsresult nsDll::GetDllSpec(nsIFile **fsobj)
329{
330 NS_ASSERTION(m_dllSpec, "m_dllSpec NULL");
331 NS_ASSERTION(fsobj, "xcDll::GetModule : Null argument" );
332
333 *fsobj = m_dllSpec;
334 NS_ADDREF(*fsobj);
335 return NS_OK;
336}
337
338nsresult nsDll::GetModule(nsISupports *servMgr, nsIModule **cobj)
339{
340 // using the backpointer of the loader.
341 nsIComponentManager* compMgr = m_loader->mCompMgr;
342 NS_ASSERTION(compMgr, "Global Component Manager is null" );
343 if (!compMgr) return NS_ERROR_UNEXPECTED;
344
345 NS_ASSERTION(cobj, "xcDll::GetModule : Null argument" );
346
347 if (m_moduleObject)
348 {
349 NS_ADDREF(m_moduleObject);
350 *cobj = m_moduleObject;
351 return NS_OK;
352 }
353
354 // If not already loaded, load it now.
355 if (Load() != PR_TRUE) return NS_ERROR_FAILURE;
356
357 // We need a nsIFile for location
358 if (!m_dllSpec)
359 {
360 return NS_ERROR_FAILURE;
361 }
362
363 nsGetModuleProc proc =
364 (nsGetModuleProc) FindSymbol(NS_GET_MODULE_SYMBOL);
365
366 if (proc == NULL)
367 return NS_ERROR_FACTORY_NOT_LOADED;
368
369 nsresult rv = (*proc) (compMgr, m_dllSpec, &m_moduleObject);
370 if (NS_SUCCEEDED(rv))
371 {
372 NS_ADDREF(m_moduleObject);
373 *cobj = m_moduleObject;
374 }
375 return rv;
376}
377
378
379// These are used by BreakAfterLoad, below.
380#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD
381static nsCString *sBreakList[16];
382static int sBreakListCount = 0;
383#endif
384
385nsresult nsDll::Shutdown(void)
386{
387 // Release the module object if we got one
388 nsrefcnt refcnt;
389 if (m_moduleObject)
390 {
391 NS_RELEASE2(m_moduleObject, refcnt);
392 NS_ASSERTION(refcnt == 0, "Dll moduleObject refcount non zero");
393 }
394#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD
395 for (int i = 0; i < sBreakListCount; i++)
396 {
397 delete sBreakList[i];
398 sBreakList[i] = nsnull;
399 }
400 sBreakListCount = 0;
401#endif
402 return NS_OK;
403
404}
405#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD
406void nsDll::BreakAfterLoad(const char *nsprPath)
407{
408 static PRBool firstTime = PR_TRUE;
409
410 // return if invalid input
411 if (!nsprPath || !*nsprPath) return;
412
413 // return if nothing to break on
414 if (!firstTime && sBreakListCount == 0) return;
415
416 if (firstTime)
417 {
418 firstTime = PR_FALSE;
419 // Form the list of dlls to break on load
420 nsCAutoString envList(getenv("XPCOM_BREAK_ON_LOAD"));
421 if (envList.IsEmpty()) return;
422 PRInt32 ofset = 0;
423 PRInt32 start = 0;
424 do
425 {
426 ofset = envList.FindChar(':', start);
427 sBreakList[sBreakListCount] = new nsCString();
428 envList.Mid(*(sBreakList[sBreakListCount]), start, ofset);
429 sBreakListCount++;
430 start = ofset + 1;
431 }
432 while (ofset != -1 && 16 > sBreakListCount); // avoiding vc6.0 compiler issue. count < thinks it is starting a template
433 }
434
435 // Find the dllname part of the string
436 nsCString currentPath(nsprPath);
437 PRInt32 lastSep = currentPath.RFindCharInSet(":\\/");
438
439 for (int i=0; i<sBreakListCount; i++)
440 if (currentPath.Find(*(sBreakList[i]), PR_TRUE, lastSep) > 0)
441 {
442 // Loading a dll that we want to break on
443 // Put your breakpoint here
444 fprintf(stderr, "...Loading module %s\n", nsprPath);
445 // Break in the debugger here.
446#if defined(__i386) && defined(__GNUC__)
447 asm("int $3");
448#elif defined(VMS)
449 lib$signal(SS$_DEBUG);
450#elif defined(XP_MACOSX)
451 raise(SIGTRAP);
452#endif
453 }
454 return;
455}
456#endif /* SHOULD_IMPLEMENT_BREAKAFTERLOAD */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette