Fixes hang due to change in order of initialization of libraries

Fixes hang due to change in order of initialization of libraries
that have cyclical dependencies and they call hsa_init() during their
initialization phase.
This implementation looks for a symbol called "HSA_AMD_TOOL_PRIORITY"
across all loaded shared libraries using dynamic section entries of the
loaded lib instead of using dlopen and dlsym for the same purpose.

Change-Id: I4865f2fd18dd186ec311a432ec38fbb5583805d2
Αυτή η υποβολή περιλαμβάνεται σε:
Shweta Khatri
2023-01-19 17:58:41 -05:00
γονέας e30be76f37
υποβολή 8aac885318
3 αρχεία άλλαξαν με 84 προσθήκες και 7 διαγραφές
@@ -1542,7 +1542,7 @@ void Runtime::LoadTools() {
}
// Discover loaded tools.
std::vector<os::LibHandle> loaded = os::GetLoadedLibs();
std::vector<os::LibHandle> loaded = os::GetLoadedToolsLib();
for(auto& handle : loaded) {
const uint32_t* order = (const uint32_t*)os::GetExportAddress(handle, "HSA_AMD_TOOL_PRIORITY");
if(order) {
@@ -204,19 +204,95 @@ void* GetExportAddress(LibHandle lib, std::string export_name) {
void CloseLib(LibHandle lib) { dlclose(*(void**)&lib); }
/*
* @brief Look for a symbol called "HSA_AMD_TOOL_PRIORITY" across all loaded
* shared libraries, and if found, store the name of the library
*
* @param[in]: info A dl_phdr_info struct pointer, which contains information
* about library's load address, header, and name.
*
* @param[in]: size integer size of dl_phdr_info struct
*
* @param[out]: data copy of the data argument to dl_phdr_iterate call
*
* @retval:: Return 0 on Success. If callback returns a non-zero value,
* dl_iterate_phdr() will stop processing, even if there are unprocessed
* shared objects.
*/
static int callback(struct dl_phdr_info* info, size_t size, void* data) {
std::vector<std::string>* loadedToolsLib = (std::vector<std::string>*)data;
assert(loadedToolsLib != nullptr);
/*
* Check if lib name is not empty and its not a "vdso.so" lib,
* The vDSO is a special shared object file that is built into the Linux kernel.
* It is not a regular shared library and thus does not have all the properties
* of regular shared libraries. The way the vDSO is loaded and organized in memory
* is different from regular shared libraries and it's not guaranteed that it
* will have a specific segment or section. Hence its skipped.
*/
if ((info) && (info->dlpi_name[0] != '\0')) {
std::vector<std::string>* loadedlib = (std::vector<std::string>*)data;
loadedlib->push_back(info->dlpi_name);
if (std::string(info->dlpi_name).find("vdso.so") != std::string::npos) return 0;
/*
* Iterate through the program headers of the loaded lib and check for PT_DYNAMIC program
* header. If the PT_DYNAMIC program header is found, use dlpi_addr and dlpi_phdr members
* of dl_phdr_info struct to get the address of the dynamic section of the loaded
* library in memory
*/
for (int i = 0; i < info->dlpi_phnum; i++) {
if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
Elf64_Dyn* dyn_section = (Elf64_Dyn*)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
char* strings = nullptr;
Elf64_Xword limit = 0;
/*
* The dynamic section is searched for DT_STRTAB (address of string table),
* and DT_STRSZ (size of string table)
* DT_NULL - Marks the end of the _DYNAMIC array
*/
for (int j = 0;; j++) {
if (dyn_section[j].d_tag == DT_NULL) break;
if (dyn_section[j].d_tag == DT_STRTAB) strings = (char*)(dyn_section[j].d_un.d_ptr);
if (dyn_section[j].d_tag == DT_STRSZ) limit = dyn_section[j].d_un.d_val;
}
if (strings == nullptr) debug_print("String table not found");
/*
* Hacky lookup, if string and symbol tables are found,
* iterate through the strings in string table and check if
* any string matches "HSA_AMD_TOOL_PRIORITY".
* If yes, then add the name of the library to the vector of
* lib names
*/
if (strings != nullptr) {
char* end = strings + limit;
while (strings < end) {
if (strcmp(strings, "HSA_AMD_TOOL_PRIORITY") == 0) {
loadedToolsLib->push_back(info->dlpi_name);
return 0;
}
strings += (strlen(strings) + 1);
}
}
}
}
}
return 0;
}
std::vector<LibHandle> GetLoadedLibs() {
std::vector<LibHandle> GetLoadedToolsLib() {
std::vector<LibHandle> ret;
std::vector<std::string> names;
/* Iterate through all of the loaded shared libraries in the process */
dl_iterate_phdr(callback, &names);
if (!names.empty()) {
@@ -86,9 +86,10 @@ void* GetExportAddress(LibHandle lib, std::string export_name);
/// @param: lib(Input), library handle which will be unloaded.
void CloseLib(LibHandle lib);
/// @brief: Lists libraries in the process
/// @brief: Lists loaded tool libraries that contain
/// symbol HSA_AMD_TOOL_PRIORITY
/// @return: List of library handles
std::vector<LibHandle> GetLoadedLibs();
std::vector<LibHandle> GetLoadedToolsLib();
/// @brief: Returns the library's path name.
/// @param: lib(Input), libray handle