git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@332 0109f412-320b-0410-ab79-c3e0c5ffbbe6
385 lines
8.7 KiB
C++
385 lines
8.7 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Module loading
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 2004-2006 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of version 2 of the GNU General Public
|
|
// License as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com
|
|
//
|
|
// $Id: ftkmod.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaim.h"
|
|
|
|
#ifndef FLM_OSX
|
|
|
|
// OS X 10.2 and earlier don't have dlopen, dlsym, etc... They have a totally
|
|
// different mechanism and since these functions are only used for our unit
|
|
// tests, it's probably not worth the time to sort it all out. In 10.3,
|
|
// the dl functions were implemented in terms of the native functions and
|
|
// this should all work. Pity there's no easy way to determine which version
|
|
// we're on...
|
|
|
|
|
|
#include "flaimsys.h"
|
|
|
|
#ifdef FLM_UNIX
|
|
#include <dlfcn.h>
|
|
#endif
|
|
|
|
|
|
#ifdef FLM_WIN
|
|
|
|
FSTATIC RCODE flmSymLoadWin(
|
|
const FLMBYTE * pszName,
|
|
FlmModHandle hMod,
|
|
void ** ppvSym);
|
|
|
|
#elif defined (FLM_NLM)
|
|
|
|
FSTATIC RCODE flmSymLoadNW(
|
|
const FLMBYTE * pszName,
|
|
void ** ppvSym);
|
|
|
|
#elif defined( FLM_UNIX)
|
|
|
|
FSTATIC RCODE flmSymLoadUnix(
|
|
const FLMBYTE * pszName,
|
|
FlmModHandle hMod,
|
|
void ** ppvSym);
|
|
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: This routine loads a shared library (cross-platform)
|
|
****************************************************************************/
|
|
RCODE FlmModLoad(
|
|
const char * pszName,
|
|
FlmModHandle * phMod)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
#ifdef FLM_WIN
|
|
HMODULE hMod;
|
|
|
|
if ((hMod = LoadLibrary( pszName)) == NULL)
|
|
{
|
|
rc = MapWinErrorToFlaim( GetLastError(), FERR_LOAD_LIBRARY);
|
|
goto Exit;
|
|
}
|
|
|
|
if ( phMod)
|
|
{
|
|
*phMod = (FlmModHandle)hMod;
|
|
}
|
|
|
|
#elif defined (FLM_UNIX)
|
|
FlmModHandle hMod;
|
|
|
|
if (!(hMod = dlopen( (const char *)pszName, RTLD_LAZY)))
|
|
{
|
|
// Note, I can't seem to get any real diagnostic info back
|
|
// from the operating system. It does not set errno on failure.
|
|
rc = RC_SET( FERR_LOAD_LIBRARY);
|
|
goto Exit;
|
|
}
|
|
|
|
if ( phMod)
|
|
{
|
|
*phMod = hMod;
|
|
}
|
|
|
|
#elif defined (FLM_NLM)
|
|
|
|
char szLoadName[ 128];
|
|
LONG lErr;
|
|
|
|
// The module handle will be passed back in the first 4 bytes of the name
|
|
f_strcpy( &szLoadName[4], pszName);
|
|
|
|
if ( ( lErr = LoadModule(
|
|
GetSystemConsoleScreen(),
|
|
(unsigned char *)&szLoadName[4],
|
|
LO_RETURN_HANDLE)) != 0)
|
|
{
|
|
rc = RC_SET( FERR_LOAD_LIBRARY);
|
|
goto Exit;
|
|
}
|
|
|
|
*phMod = (FlmModHandle)&szLoadName[0];
|
|
|
|
#else
|
|
#error Unsupported OS
|
|
#endif
|
|
|
|
Exit:
|
|
return( rc);
|
|
}
|
|
|
|
#ifndef FLM_NLM
|
|
/****************************************************************************
|
|
Desc: This routine unloads a shared library (cross-platform)
|
|
****************************************************************************/
|
|
RCODE FlmModUnload( FlmModHandle * phMod)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
|
|
flmAssert( phMod);
|
|
#ifdef FLM_WIN
|
|
|
|
if (!FreeLibrary((HMODULE)*phMod))
|
|
{
|
|
rc = MapWinErrorToFlaim( GetLastError(), FERR_UNLOAD_LIBRARY);
|
|
goto Exit;
|
|
}
|
|
*phMod = NULL;
|
|
|
|
#elif defined (FLM_UNIX)
|
|
if (dlclose(phMod) != 0)
|
|
{
|
|
rc = RC_SET( FERR_UNLOAD_LIBRARY);
|
|
goto Exit;
|
|
}
|
|
*phMod = NULL;
|
|
#else
|
|
#error Unsupported OS
|
|
#endif
|
|
Exit:
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
#ifdef FLM_NLM
|
|
|
|
/****************************************************************************
|
|
Desc: This routine creates a FLAIM file. For whatever reason, NetWare unloads
|
|
a module using its path and not its handle. While routines exist that look up
|
|
the path given the module handle, I can't use them because they are all LibC
|
|
calls
|
|
****************************************************************************/
|
|
RCODE FlmModUnload( FLMBYTE * pszModPath)
|
|
{
|
|
int iErr;
|
|
RCODE rc = FERR_OK;
|
|
|
|
if ( (iErr = UnloadModule(
|
|
NULL,
|
|
(const char *)pszModPath)) != 0)
|
|
{
|
|
rc = MapNWtoFlaimError( iErr, FERR_UNLOAD_LIBRARY);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
#ifdef FLM_WIN
|
|
|
|
/****************************************************************************
|
|
Desc: This routine loads a symbol from a .dll file
|
|
****************************************************************************/
|
|
FSTATIC RCODE flmSymLoadWin(
|
|
const FLMBYTE * pszName,
|
|
FlmModHandle hMod,
|
|
void ** ppvSym)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
void * pvSym;
|
|
|
|
if ( ( pvSym = GetProcAddress( (HMODULE)hMod, (LPCSTR)pszName)) == NULL)
|
|
{
|
|
rc = MapWinErrorToFlaim( GetLastError(), FERR_IMPORT_SYMBOL);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
if ( ppvSym && RC_OK( rc))
|
|
{
|
|
*ppvSym = pvSym;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
#elif defined (FLM_NLM)
|
|
|
|
/****************************************************************************
|
|
Desc: This routine loads a symbol from a .nlm file
|
|
****************************************************************************/
|
|
FSTATIC RCODE flmSymLoadNW(
|
|
const FLMBYTE * pszName,
|
|
void ** ppvSym)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
void * pvSym;
|
|
FLMUINT uiNameLen;
|
|
FLMBYTE * pszLengthPlusName = NULL;
|
|
|
|
// NetWare is a little different (of course). You use your own handle
|
|
// to query for and retrieve symbols. All loaded modules are queried.
|
|
|
|
uiNameLen = f_strlen( (const char *)pszName);
|
|
|
|
if ( uiNameLen > 255)
|
|
{
|
|
|
|
// If the name's length can't be represented in a single byte,
|
|
// it's too large.
|
|
|
|
rc = RC_SET( FERR_VALUE_TOO_LARGE);
|
|
goto Exit;
|
|
}
|
|
|
|
if ( RC_BAD( rc = f_alloc( uiNameLen + 2, &pszLengthPlusName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// The first byte of the name should be the length of the name
|
|
|
|
pszLengthPlusName[0] = (FLMBYTE)uiNameLen;
|
|
f_strcpy( (char *)&pszLengthPlusName[1], (const char *)pszName);
|
|
|
|
if (( pvSym = (void *)ImportPublicSymbol(
|
|
f_getNLMHandle(),
|
|
(BYTE*)pszLengthPlusName)) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_IMPORT_SYMBOL);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
if ( pszLengthPlusName)
|
|
{
|
|
f_free( &pszLengthPlusName);
|
|
}
|
|
|
|
if ( ppvSym && RC_OK( rc))
|
|
{
|
|
*ppvSym = pvSym;
|
|
}
|
|
return( rc);
|
|
}
|
|
|
|
#elif defined( FLM_UNIX)
|
|
|
|
/****************************************************************************
|
|
Desc: This routine loads a symbol from a .so file.
|
|
****************************************************************************/
|
|
FSTATIC RCODE flmSymLoadUnix(
|
|
const FLMBYTE * pszName,
|
|
FlmModHandle hMod,
|
|
void ** ppvSym)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
void * pvSym;
|
|
|
|
if ( ( pvSym = dlsym( hMod, (const char*)pszName)) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_IMPORT_SYMBOL);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
if ( ppvSym && RC_OK( rc))
|
|
{
|
|
*ppvSym = pvSym;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: This routine loads a symbol from a shared library (cross-platform)
|
|
****************************************************************************/
|
|
RCODE FlmSymLoad( const FLMBYTE * pszName, FlmModHandle hMod, void ** ppvSym)
|
|
{
|
|
#ifdef FLM_WIN
|
|
return flmSymLoadWin( pszName, hMod, ppvSym);
|
|
#elif defined (FLM_NLM)
|
|
F_UNREFERENCED_PARM( hMod);
|
|
return flmSymLoadNW( pszName, ppvSym);
|
|
#elif defined (FLM_UNIX)
|
|
return flmSymLoadUnix( pszName, hMod, ppvSym);
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This routine unloads a shared library symbol (cross-platform, but only
|
|
really useful on NetWare since it seems to be the only platform that keeps a
|
|
reference count on loaded symbols)
|
|
****************************************************************************/
|
|
RCODE FlmSymUnload(
|
|
const FLMBYTE * pszName)
|
|
{
|
|
#ifdef FLM_NLM
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiSymLen;
|
|
FLMBYTE * pszLenAndSymbol = NULL;
|
|
|
|
uiSymLen = f_strlen( (const char *)pszName);
|
|
|
|
if ( uiSymLen > 255)
|
|
{
|
|
rc = RC_SET( FERR_VALUE_TOO_LARGE);
|
|
goto Exit;
|
|
}
|
|
|
|
if ( RC_BAD( rc = f_alloc( uiSymLen + 2, &pszLenAndSymbol)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pszLenAndSymbol[0] = (FLMBYTE)uiSymLen;
|
|
f_strcpy( (char *)&pszLenAndSymbol[1], (const char *)pszName);
|
|
|
|
if ((UnImportPublicSymbol (
|
|
f_getNLMHandle(), pszLenAndSymbol)) != 0)
|
|
{
|
|
rc = RC_SET( FERR_UNIMPORT_SYMBOL);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
if( pszLenAndSymbol)
|
|
{
|
|
f_free( &pszLenAndSymbol);
|
|
}
|
|
|
|
return( rc);
|
|
#else
|
|
|
|
// This is only really necessary on NetWare
|
|
|
|
F_UNREFERENCED_PARM( pszName);
|
|
return FERR_OK;
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_OSX)
|
|
void gv_ftkmod()
|
|
{
|
|
}
|
|
#endif
|