VirtualBox

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

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

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

© 2023 Oracle
ContactPrivacy policyTerms of Use