Skip to content

Commit

Permalink
Add wxDynamicLibrary::GetModuleFromAddress().
Browse files Browse the repository at this point in the history
Use dladdr() under Unix, if available, to provide the same functionality as we
get from GetModuleHandleEx() under MSW and export it in a new public function.

Closes #15248.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76114 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
  • Loading branch information
vadz committed Mar 11, 2014
1 parent acd8a61 commit f51dc81
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 18 deletions.
57 changes: 57 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -33348,6 +33348,63 @@ fi



fi
done

for ac_func in dladdr
do :
ac_fn_c_check_func "$LINENO" "dladdr" "ac_cv_func_dladdr"
if test "x$ac_cv_func_dladdr" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_DLADDR 1
_ACEOF
$as_echo "#define HAVE_DLADDR 1" >>confdefs.h

else

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dladdr in -ldl" >&5
$as_echo_n "checking for dladdr in -ldl... " >&6; }
if ${ac_cv_lib_dl_dladdr+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-ldl $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */

/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char dladdr ();
int
main ()
{
return dladdr ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_dl_dladdr=yes
else
ac_cv_lib_dl_dladdr=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dladdr" >&5
$as_echo "$ac_cv_lib_dl_dladdr" >&6; }
if test "x$ac_cv_lib_dl_dladdr" = xyes; then :
$as_echo "#define HAVE_DLADDR 1" >>confdefs.h

fi



fi
done

Expand Down
6 changes: 6 additions & 0 deletions configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -5442,6 +5442,12 @@ if test "$TOOLKIT" != "MSW" -a "$USE_OS2" != 1; then
AC_CHECK_LIB(dl, dlerror, AC_DEFINE(HAVE_DLERROR))
]
)
AC_CHECK_FUNCS(dladdr,
AC_DEFINE(HAVE_DLADDR),
[
AC_CHECK_LIB(dl, dladdr, AC_DEFINE(HAVE_DLADDR))
]
)
fi
fi

Expand Down
1 change: 1 addition & 0 deletions docs/changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ All:

- Allow iterating over wxCmdLineParser arguments in order (Armel Asselin).
- Add wxScopedArray ctor taking the number of elements to allocate.
- Add wxDynamicLibrary::GetModuleFromAddress() (Luca Bacci).

All (GUI):

Expand Down
6 changes: 6 additions & 0 deletions include/wx/dynlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,12 @@ class WXDLLIMPEXP_BASE wxDynamicLibrary
// string on others:
static wxString GetPluginsDirectory();

// Return the load address of the module containing the given address or
// NULL if not found.
//
// If path output parameter is non-NULL, fill it with the full path to this
// module disk file on success.
static void* GetModuleFromAddress(const void* addr, wxString* path = NULL);

#ifdef __WINDOWS__
// return the handle (HMODULE/HINSTANCE) of the DLL with the given name
Expand Down
15 changes: 15 additions & 0 deletions interface/wx/dynlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,21 @@ class wxDynamicLibrary
*/
static wxDynamicLibraryDetailsArray ListLoaded();

/**
Returns the load address of the module containing the specified address
or @NULL if not found.
If the second argument @a path is not @NULL, it is filled with the full
path to the file the module was loaded from upon a successful return.
This method is implemented under MSW and Unix platforms providing
`dladdr()` call (which include Linux and various BSD systems) and
always returns @NULL elsewhere.
@since 3.1.0
*/
static void* GetModuleFromAddress(const void* addr, wxString* path = NULL);

/**
Loads DLL with the given @a name into memory. The @a flags argument can
be a combination of the styles outlined in the class description.
Expand Down
3 changes: 3 additions & 0 deletions setup.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,9 @@
/* Define if you have the dlerror function. */
#undef HAVE_DLERROR

/* Define if you have the dladdr function. */
#undef HAVE_DLADDR

/* Define if you have Posix fnctl() function. */
#undef HAVE_FCNTL

Expand Down
3 changes: 3 additions & 0 deletions setup.h_vms
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,9 @@ typedef pid_t GPid;
/* Define if you have the dlerror function. */
#define HAVE_DLERROR 1

/* Define if you have the dladdr function. */
#undef HAVE_DLADDR

/* Define if you have Posix fnctl() function. */
#define HAVE_FCNTL 1

Expand Down
85 changes: 67 additions & 18 deletions src/msw/dlmsw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,40 +297,89 @@ wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded()
return dlls;
}

/* static */
WXHMODULE wxDynamicLibrary::MSWGetModuleHandle(const wxString& name, void *addr)
// ----------------------------------------------------------------------------
// Getting the module from an address inside it
// ----------------------------------------------------------------------------

namespace
{
// we want to use GetModuleHandleEx() instead of usual GetModuleHandle()
// because the former works correctly for comctl32.dll while the latter
// returns NULL when comctl32.dll version 6 is used under XP (note that
// GetModuleHandleEx() is only available under XP and later, coincidence?)

// check if we can use GetModuleHandleEx
// Tries to dynamically load GetModuleHandleEx() from kernel32.dll and call it
// to get the module handle from the given address. Returns NULL if it fails to
// either resolve the function (which can only happen on pre-Vista systems
// normally) or if the function itself failed.
HMODULE CallGetModuleHandleEx(const void* addr)
{
typedef BOOL (WINAPI *GetModuleHandleEx_t)(DWORD, LPCTSTR, HMODULE *);

static const GetModuleHandleEx_t INVALID_FUNC_PTR = (GetModuleHandleEx_t)-1;

static GetModuleHandleEx_t s_pfnGetModuleHandleEx = INVALID_FUNC_PTR;
if ( s_pfnGetModuleHandleEx == INVALID_FUNC_PTR )
{
wxDynamicLibrary dll(wxT("kernel32.dll"), wxDL_VERBATIM);
s_pfnGetModuleHandleEx =
(GetModuleHandleEx_t)dll.GetSymbolAorW(wxT("GetModuleHandleEx"));

wxDL_INIT_FUNC_AW(s_pfn, GetModuleHandleEx, dll);

// dll object can be destroyed, kernel32.dll won't be unloaded anyhow
}

// get module handle from its address
if ( s_pfnGetModuleHandleEx )
if ( !s_pfnGetModuleHandleEx )
return NULL;

// flags are GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
// GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
HMODULE hmod;
if ( !s_pfnGetModuleHandleEx(6, (LPCTSTR)addr, &hmod) )
return NULL;

return hmod;
}

} // anonymous namespace

/* static */
void* wxDynamicLibrary::GetModuleFromAddress(const void* addr, wxString* path)
{
HMODULE hmod = CallGetModuleHandleEx(addr);
if ( !hmod )
{
wxLogLastError(wxT("GetModuleHandleEx"));
return NULL;
}

if ( path )
{
// flags are GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
// GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
HMODULE hmod;
if ( s_pfnGetModuleHandleEx(6, (LPCTSTR)addr, &hmod) && hmod )
return hmod;
TCHAR libname[MAX_PATH];
if ( !::GetModuleFileName(hmod, libname, MAX_PATH) )
{
// GetModuleFileName could also return extended-length paths (paths
// prepended with "//?/", maximum length is 32767 charachters) so,
// in principle, MAX_PATH could be unsufficient and we should try
// increasing the buffer size here.
wxLogLastError(wxT("GetModuleFromAddress"));
return NULL;
}

libname[MAX_PATH-1] = wxT('\0');

*path = libname;
}

return ::GetModuleHandle(name.t_str());
// In Windows HMODULE is actually the base address of the module so we
// can just cast it to the address.
return reinterpret_cast<void *>(hmod);
}

/* static */
WXHMODULE wxDynamicLibrary::MSWGetModuleHandle(const wxString& name, void *addr)
{
// we want to use GetModuleHandleEx() instead of usual GetModuleHandle()
// because the former works correctly for comctl32.dll while the latter
// returns NULL when comctl32.dll version 6 is used under XP (note that
// GetModuleHandleEx() is only available under XP and later, coincidence?)
HMODULE hmod = CallGetModuleHandleEx(addr);

return hmod ? hmod : ::GetModuleHandle(name.t_str());
}

#endif // wxUSE_DYNLIB_CLASS
Expand Down
20 changes: 20 additions & 0 deletions src/unix/dlunix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,5 +280,25 @@ wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded()
return dlls;
}


/* static */
void* wxDynamicLibrary::GetModuleFromAddress(const void* addr, wxString* path)
{
#ifdef HAVE_DLADDR
Dl_info di = { 0 };

if ( dladdr(addr, &di) == 0 )
return NULL;

if ( path )
*path = di.dli_fname;

return di.dli_fbase;
#endif // HAVE_DLADDR

return NULL;
}


#endif // wxUSE_DYNLIB_CLASS

0 comments on commit f51dc81

Please sign in to comment.