Use dl_iterate_phdr() in wxDynamicLibrary::ListLoaded()
This has the advantage of returning libraries in their load order, which is more useful than the unspecified order that was used before. It also means that this function now has a chance of working under other systems such as FreeBSD, which also provides dl_iterate_phdr().
This commit is contained in:
parent
d22275ce0a
commit
aec49d9c9d
6 changed files with 75 additions and 76 deletions
|
|
@ -565,6 +565,7 @@ check_symbol_exists(dlopen dlfcn.h HAVE_DLOPEN)
|
|||
cmake_pop_check_state()
|
||||
if(HAVE_DLOPEN)
|
||||
check_symbol_exists(dladdr dlfcn.h HAVE_DLADDR)
|
||||
check_symbol_exists(dl_iterate_phdr link.h HAVE_DL_ITERATE_PHDR)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
|
|
|
|||
12
configure
vendored
12
configure
vendored
|
|
@ -35456,6 +35456,18 @@ fi
|
|||
|
||||
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
for ac_func in dl_iterate_phdr
|
||||
do :
|
||||
ac_fn_c_check_func "$LINENO" "dl_iterate_phdr" "ac_cv_func_dl_iterate_phdr"
|
||||
if test "x$ac_cv_func_dl_iterate_phdr" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_DL_ITERATE_PHDR 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
|
|||
|
|
@ -4839,7 +4839,7 @@ else
|
|||
])
|
||||
])
|
||||
|
||||
dnl check also for dlerror()
|
||||
dnl check also for some optional functions which we may use
|
||||
if test "$HAVE_DL_FUNCS" = 1; then
|
||||
AC_CHECK_FUNCS(dladdr,
|
||||
AC_DEFINE(HAVE_DLADDR),
|
||||
|
|
@ -4851,6 +4851,8 @@ else
|
|||
])
|
||||
]
|
||||
)
|
||||
|
||||
AC_CHECK_FUNCS(dl_iterate_phdr)
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ public:
|
|||
/**
|
||||
Retrieves the load address and the size of this module.
|
||||
|
||||
Note that under ELF systems (such as Linux) the region defined by the
|
||||
parameters of this function can be discontinuous and contain multiple
|
||||
segments belonging to the module with holes between them.
|
||||
|
||||
@param addr
|
||||
The pointer to the location to return load address in, may be
|
||||
@NULL.
|
||||
|
|
@ -38,6 +42,8 @@ public:
|
|||
/**
|
||||
Returns the base name of this module, e.g.\ @c "kernel32.dll" or
|
||||
@c "libc-2.3.2.so".
|
||||
|
||||
This name is empty for the main program itself.
|
||||
*/
|
||||
wxString GetName() const;
|
||||
|
||||
|
|
@ -217,13 +223,20 @@ public:
|
|||
bool IsLoaded() const;
|
||||
|
||||
/**
|
||||
This static method returns a wxArray containing the details of all
|
||||
modules loaded into the address space of the current project. The array
|
||||
elements are objects of the type: wxDynamicLibraryDetails. The array
|
||||
will be empty if an error occurred.
|
||||
This static method returns a vector-like object containing the details
|
||||
of all modules loaded into the address space of the current project.
|
||||
|
||||
This method is currently implemented only under Win32 and Linux and is
|
||||
useful mostly for diagnostics purposes.
|
||||
The array elements are objects of the type wxDynamicLibraryDetails.
|
||||
Under Unix systems they appear in the order in which they libraries
|
||||
have been loaded, with the module corresponding to the main program
|
||||
itself coming first.
|
||||
|
||||
The returned array will be empty if an error occurred or if the
|
||||
function is not implemented for the current platform.
|
||||
|
||||
This method is currently implemented only under Win32 and Unix systems
|
||||
providing `dl_iterate_phdr()` function (such as Linux) and is useful
|
||||
mostly for diagnostics purposes.
|
||||
*/
|
||||
static wxDynamicLibraryDetailsArray ListLoaded();
|
||||
|
||||
|
|
|
|||
|
|
@ -935,6 +935,9 @@
|
|||
/* Define if you have the dladdr function. */
|
||||
#undef HAVE_DLADDR
|
||||
|
||||
/* Define if you have the dl_iterate_phdr function. */
|
||||
#undef HAVE_DL_ITERATE_PHDR
|
||||
|
||||
/* Define if you have Posix fnctl() function. */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@
|
|||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DL_ITERATE_PHDR
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
// if some flags are not supported, just ignore them
|
||||
#ifndef RTLD_LAZY
|
||||
#define RTLD_LAZY 0
|
||||
|
|
@ -125,20 +129,38 @@ void wxDynamicLibrary::ReportError(const wxString& message,
|
|||
// listing loaded modules
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifdef HAVE_DL_ITERATE_PHDR
|
||||
|
||||
// wxDynamicLibraryDetails declares this class as its friend, so put the code
|
||||
// initializing new details objects here
|
||||
class wxDynamicLibraryDetailsCreator
|
||||
{
|
||||
public:
|
||||
// create a new wxDynamicLibraryDetails from the given data
|
||||
static wxDynamicLibraryDetails
|
||||
New(void *start, void *end, const wxString& path)
|
||||
static int Callback(dl_phdr_info* info, size_t /* size */, void* data)
|
||||
{
|
||||
const wxString path = wxString::FromUTF8(info->dlpi_name);
|
||||
|
||||
wxDynamicLibraryDetails details;
|
||||
details.m_path = path;
|
||||
details.m_name = path.AfterLast(wxT('/'));
|
||||
details.m_address = start;
|
||||
details.m_length = (char *)end - (char *)start;
|
||||
|
||||
// Find the first and last address belonging to this module.
|
||||
decltype(info->dlpi_addr) start = 0, end = 0;
|
||||
for ( decltype(info->dlpi_phnum) n = 0; n < info->dlpi_phnum; n++ )
|
||||
{
|
||||
const auto& segment = info->dlpi_phdr[n];
|
||||
if ( !segment.p_vaddr || !segment.p_memsz )
|
||||
continue;
|
||||
|
||||
if ( !start || segment.p_vaddr < start )
|
||||
start = segment.p_vaddr;
|
||||
|
||||
if ( !end || segment.p_vaddr + segment.p_memsz > end )
|
||||
end = segment.p_vaddr + segment.p_memsz;
|
||||
}
|
||||
|
||||
details.m_address = wxUIntToPtr(info->dlpi_addr + start);
|
||||
details.m_length = end - start;
|
||||
|
||||
// try to extract the library version from its name
|
||||
const size_t posExt = path.rfind(wxT(".so"));
|
||||
|
|
@ -161,78 +183,24 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
return details;
|
||||
auto dlls = static_cast<wxDynamicLibraryDetailsArray*>(data);
|
||||
dlls->push_back(std::move(details));
|
||||
|
||||
// Return 0 to keep iterating.
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // HAVE_DL_ITERATE_PHDR
|
||||
|
||||
/* static */
|
||||
wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded()
|
||||
{
|
||||
wxDynamicLibraryDetailsArray dlls;
|
||||
|
||||
#ifdef __LINUX__
|
||||
// examine /proc/self/maps to find out what is loaded in our address space
|
||||
wxFFile file(wxT("/proc/self/maps"));
|
||||
if ( file.IsOpened() )
|
||||
{
|
||||
// details of the module currently being parsed
|
||||
wxString pathCur;
|
||||
void *startCur = nullptr,
|
||||
*endCur = nullptr;
|
||||
|
||||
char path[1024];
|
||||
char buf[1024];
|
||||
while ( fgets(buf, WXSIZEOF(buf), file.fp()) )
|
||||
{
|
||||
// format is: "start-end perm offset maj:min inode path", see proc(5)
|
||||
void *start,
|
||||
*end;
|
||||
switch ( sscanf(buf, "%p-%p %*4s %*p %*02x:%*02x %*d %1023s\n",
|
||||
&start, &end, path) )
|
||||
{
|
||||
case 2:
|
||||
// there may be no path column
|
||||
path[0] = '\0';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// nothing to do, read everything we wanted
|
||||
break;
|
||||
|
||||
default:
|
||||
// chop '\n'
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
wxLogDebug(wxT("Failed to parse line \"%s\" in /proc/self/maps."),
|
||||
buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
wxASSERT_MSG( start >= endCur,
|
||||
wxT("overlapping regions in /proc/self/maps?") );
|
||||
|
||||
wxString pathNew = wxString::FromAscii(path);
|
||||
if ( pathCur.empty() )
|
||||
{
|
||||
// new module start
|
||||
pathCur = pathNew;
|
||||
startCur = start;
|
||||
endCur = end;
|
||||
}
|
||||
else if ( pathCur == pathNew && endCur == end )
|
||||
{
|
||||
// continuation of the same module in the address space
|
||||
endCur = end;
|
||||
}
|
||||
else // end of the current module
|
||||
{
|
||||
dlls.Add(wxDynamicLibraryDetailsCreator::New(startCur,
|
||||
endCur,
|
||||
pathCur));
|
||||
pathCur.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // __LINUX__
|
||||
#ifdef HAVE_DL_ITERATE_PHDR
|
||||
dl_iterate_phdr(wxDynamicLibraryDetailsCreator::Callback, &dlls);
|
||||
#endif // HAVE_DL_ITERATE_PHDR
|
||||
|
||||
return dlls;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue