From 4f670d6df7e0e29bb41a5918b06dfd127cecbf34 Mon Sep 17 00:00:00 2001 From: Shweta Khatri Date: Thu, 19 Jan 2023 17:58:41 -0500 Subject: [PATCH] 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 [ROCm/ROCR-Runtime commit: 8aac885318fa89dedd0a8991a47143bfca83fdaa] --- .../hsa-runtime/core/runtime/runtime.cpp | 2 +- .../hsa-runtime/core/util/lnx/os_linux.cpp | 84 ++++++++++++++++++- .../runtime/hsa-runtime/core/util/os.h | 5 +- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp index 39e2ba8e97..f26b862a9e 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp @@ -1542,7 +1542,7 @@ void Runtime::LoadTools() { } // Discover loaded tools. - std::vector loaded = os::GetLoadedLibs(); + std::vector loaded = os::GetLoadedToolsLib(); for(auto& handle : loaded) { const uint32_t* order = (const uint32_t*)os::GetExportAddress(handle, "HSA_AMD_TOOL_PRIORITY"); if(order) { diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/util/lnx/os_linux.cpp b/projects/rocr-runtime/runtime/hsa-runtime/core/util/lnx/os_linux.cpp index c80cad67e2..6324c26c58 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/util/lnx/os_linux.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/util/lnx/os_linux.cpp @@ -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* loadedToolsLib = (std::vector*)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* loadedlib = (std::vector*)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 GetLoadedLibs() { - +std::vector GetLoadedToolsLib() { std::vector ret; std::vector names; + /* Iterate through all of the loaded shared libraries in the process */ dl_iterate_phdr(callback, &names); if (!names.empty()) { diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/util/os.h b/projects/rocr-runtime/runtime/hsa-runtime/core/util/os.h index aa0c8d565f..4f87ceac09 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/util/os.h +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/util/os.h @@ -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 GetLoadedLibs(); +std::vector GetLoadedToolsLib(); /// @brief: Returns the library's path name. /// @param: lib(Input), libray handle