Parse ELF format for rocprofiler_configure symbol (#970)
* Parse ELF format to search for rocprofiler_configure * Use ELF parsing in registration
Tento commit je obsažen v:
@@ -22,3 +22,6 @@
|
||||
[submodule "external/perfetto"]
|
||||
path = external/perfetto
|
||||
url = https://android.googlesource.com/platform/external/perfetto
|
||||
[submodule "external/elfio"]
|
||||
path = external/elfio
|
||||
url = https://github.com/serge1/ELFIO.git
|
||||
|
||||
@@ -266,3 +266,13 @@ find_library(
|
||||
target_include_directories(rocprofiler-drm SYSTEM INTERFACE ${drm_INCLUDE_DIR}
|
||||
${xf86drm_INCLUDE_DIR})
|
||||
target_link_libraries(rocprofiler-drm INTERFACE ${drm_LIBRARY} ${drm_amdgpu_LIBRARY})
|
||||
|
||||
# ----------------------------------------------------------------------------------------#
|
||||
#
|
||||
# ELFIO library
|
||||
#
|
||||
# ----------------------------------------------------------------------------------------#
|
||||
|
||||
# get_target_property(ELFIO_INCLUDE_DIR elfio::elfio INTERFACE_INCLUDE_DIRECTORIES)
|
||||
# target_include_directories(rocprofiler-elfio SYSTEM INTERFACE ${ELFIO_INCLUDE_DIR})
|
||||
target_link_libraries(rocprofiler-elfio INTERFACE elfio::elfio)
|
||||
|
||||
@@ -52,6 +52,8 @@ rocprofiler_add_interface_library(rocprofiler-cxx-filesystem "C++ filesystem lib
|
||||
rocprofiler_add_interface_library(rocprofiler-ptl "Parallel Tasking Library" INTERNAL)
|
||||
rocprofiler_add_interface_library(rocprofiler-elf "ElfUtils elf library" INTERNAL)
|
||||
rocprofiler_add_interface_library(rocprofiler-dw "ElfUtils dw library" INTERNAL)
|
||||
rocprofiler_add_interface_library(rocprofiler-elfio "ELFIO header-only C++ library"
|
||||
INTERNAL)
|
||||
|
||||
#
|
||||
# interface for libraries (ROCm-specific)
|
||||
|
||||
vendorováno
+17
@@ -151,6 +151,7 @@ if(ROCPROFILER_BUILD_DOCS)
|
||||
REPO_BRANCH "main")
|
||||
endif()
|
||||
|
||||
# perfetto
|
||||
rocprofiler_checkout_git_submodule(
|
||||
RECURSIVE
|
||||
RELATIVE_PATH external/perfetto
|
||||
@@ -172,3 +173,19 @@ set_target_properties(
|
||||
OUTPUT_NAME rocprofiler-sdk-perfetto)
|
||||
target_link_libraries(rocprofiler-perfetto
|
||||
INTERFACE $<BUILD_INTERFACE:rocprofiler-perfetto-static-library>)
|
||||
|
||||
# ELFIO
|
||||
rocprofiler_checkout_git_submodule(
|
||||
RECURSIVE
|
||||
RELATIVE_PATH external/elfio
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
REPO_URL https://github.com/serge1/ELFIO.git
|
||||
REPO_BRANCH "Release_3.12")
|
||||
|
||||
set(ELFIO_BUILD_EXAMPLES OFF)
|
||||
set(ELFIO_BUILD_TESTS OFF)
|
||||
add_subdirectory(elfio EXCLUDE_FROM_ALL)
|
||||
if(TARGET rocprofiler-elfio)
|
||||
get_target_property(ELFIO_INCLUDE_DIR elfio::elfio INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(rocprofiler-elfio SYSTEM INTERFACE ${ELFIO_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
+1
Submodul external/elfio přidán v 8ae6cec5d6
@@ -3,19 +3,22 @@
|
||||
#
|
||||
rocprofiler_activate_clang_tidy()
|
||||
|
||||
set(common_sources environment.cpp demangle.cpp logging.cpp static_object.cpp utility.cpp
|
||||
xml.cpp)
|
||||
set(common_sources demangle.cpp elf_utils.cpp environment.cpp logging.cpp
|
||||
static_object.cpp utility.cpp xml.cpp)
|
||||
set(common_headers
|
||||
abi.hpp
|
||||
defines.hpp
|
||||
environment.hpp
|
||||
demangle.hpp
|
||||
elf_utils.hpp
|
||||
environment.hpp
|
||||
filesystem.hpp
|
||||
logging.hpp
|
||||
mpl.hpp
|
||||
scope_destructor.hpp
|
||||
static_object.hpp
|
||||
stringize_arg.hpp
|
||||
synchronized.hpp
|
||||
units.hpp
|
||||
utility.hpp
|
||||
xml.hpp)
|
||||
|
||||
@@ -41,7 +44,8 @@ target_link_libraries(
|
||||
$<BUILD_INTERFACE:rocprofiler-sdk::rocprofiler-dl>
|
||||
$<BUILD_INTERFACE:rocprofiler-sdk::rocprofiler-ptl>
|
||||
$<BUILD_INTERFACE:rocprofiler-sdk::rocprofiler-atomic>
|
||||
$<BUILD_INTERFACE:rocprofiler-sdk::rocprofiler-hsakmt-nolink>)
|
||||
$<BUILD_INTERFACE:rocprofiler-sdk::rocprofiler-hsakmt-nolink>
|
||||
$<BUILD_INTERFACE:rocprofiler-sdk::rocprofiler-elfio>)
|
||||
|
||||
set_target_properties(rocprofiler-common-library PROPERTIES OUTPUT_NAME
|
||||
rocprofiler-common)
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "lib/common/elf_utils.hpp"
|
||||
|
||||
#include <elfio/elfio.hpp>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "lib/common/logging.hpp"
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace elf_utils
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const ELFIO::Elf_Xword PAGE_SIZE = sysconf(_SC_PAGESIZE);
|
||||
|
||||
template <typename Tp>
|
||||
std::string
|
||||
as_hex_string(Tp&& _v, size_t _w = 16)
|
||||
{
|
||||
auto _ss = std::stringstream{};
|
||||
_ss.fill('0');
|
||||
_ss << "0x" << std::hex << std::setw(_w) << std::forward<Tp>(_v);
|
||||
return _ss.str();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SymbolEntry::SymbolEntry(unsigned int _idx, const accessor_type& _accessor)
|
||||
: index{_idx}
|
||||
{
|
||||
if(!_accessor.get_symbol(index, name, value, size, bind, type, section_index, other))
|
||||
throw std::runtime_error("Error in ELFIO::symbol_section_accessor::get_symbol");
|
||||
}
|
||||
|
||||
DynamicEntry::DynamicEntry(unsigned int _idx, const accessor_type& _accessor)
|
||||
: index{_idx}
|
||||
{
|
||||
if(!_accessor.get_entry(_idx, tag, value, name)) return;
|
||||
}
|
||||
|
||||
RelocationEntry::RelocationEntry(unsigned int _idx, const accessor_type& _accessor)
|
||||
: index{_idx}
|
||||
{
|
||||
if(!_accessor.get_entry(_idx, offset, symbol, type, addend))
|
||||
throw std::runtime_error("Error in ELFIO::relocation_section_accessor::get_entry");
|
||||
}
|
||||
|
||||
ElfInfo::ElfInfo(std::string _fname)
|
||||
: filename{std::move(_fname)}
|
||||
{}
|
||||
|
||||
bool
|
||||
ElfInfo::has_symbol(std::regex&& _re) const
|
||||
{
|
||||
for(const auto& itr : symbol_entries)
|
||||
{
|
||||
if(!itr.name.empty() && std::regex_search(itr.name, _re)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ElfInfo
|
||||
read(const std::string& _inp)
|
||||
{
|
||||
auto _info = ElfInfo{_inp};
|
||||
auto& reader = _info.reader;
|
||||
auto& sections = _info.sections;
|
||||
auto& symbol_entries = _info.symbol_entries;
|
||||
auto& dynamic_entries = _info.dynamic_entries;
|
||||
auto& reloc_entries = _info.reloc_entries;
|
||||
|
||||
ROCP_TRACE << "\nReading " << _inp;
|
||||
|
||||
if(!reader.load(_inp)) throw std::runtime_error("Could not load elf file " + _inp);
|
||||
|
||||
if(reader.get_class() == ELFIO::ELFCLASS32)
|
||||
ROCP_TRACE << "ELF 32-bit";
|
||||
else
|
||||
ROCP_TRACE << "ELF 64-bit";
|
||||
|
||||
ROCP_TRACE << "ELF file encoding: "
|
||||
<< ((reader.get_encoding() == ELFIO::ELFDATA2LSB) ? std::string_view{"Little endian"}
|
||||
: std::string_view{"Big endian"});
|
||||
|
||||
ROCP_TRACE << "ELF version: " << reader.get_elf_version();
|
||||
ROCP_TRACE << "ELF header size: " << reader.get_header_size();
|
||||
ROCP_TRACE << "ELF OS ABI: " << reader.get_os_abi();
|
||||
|
||||
// Print ELF file sections info
|
||||
ELFIO::Elf_Half sec_num = reader.sections.size();
|
||||
ROCP_TRACE << "Number of sections: " << sec_num;
|
||||
|
||||
for(ELFIO::Elf_Half j = 0; j < sec_num; ++j)
|
||||
{
|
||||
ELFIO::section* psec = reader.sections[j];
|
||||
sections.emplace_back(psec);
|
||||
}
|
||||
|
||||
std::sort(sections.begin(), sections.end(), [](const Section* lhs, const Section* rhs) {
|
||||
return std::string_view{lhs->get_name()} < std::string_view{rhs->get_name()};
|
||||
});
|
||||
|
||||
for(ELFIO::Elf_Half j = 0; j < sec_num; ++j)
|
||||
{
|
||||
Section* psec = sections.at(j);
|
||||
ROCP_TRACE << " [" << j << "] \t" << std::setw(20) << psec->get_name() << "\t : \t"
|
||||
<< "size / entry-size = " << std::setw(6) << psec->get_size() << " / "
|
||||
<< std::setw(3) << psec->get_entry_size()
|
||||
<< " | addr: " << as_hex_string(psec->get_address())
|
||||
<< " | offset: " << as_hex_string(psec->get_offset());
|
||||
|
||||
if(psec->get_size() == 0) continue;
|
||||
|
||||
if(psec->get_type() == ELFIO::SHT_SYMTAB)
|
||||
{
|
||||
const ELFIO::symbol_section_accessor _symbols(reader, psec);
|
||||
ROCP_TRACE << " Number of symbol_entries: " << _symbols.get_symbols_num();
|
||||
for(ELFIO::Elf_Xword k = 0; k < _symbols.get_symbols_num(); ++k)
|
||||
symbol_entries.emplace_back(k, _symbols);
|
||||
}
|
||||
else if(psec->get_type() == ELFIO::SHT_DYNAMIC)
|
||||
{
|
||||
const ELFIO::dynamic_section_accessor dynamic{reader, psec};
|
||||
ROCP_TRACE << " Number of dynamic entries: " << dynamic.get_entries_num();
|
||||
for(ELFIO::Elf_Xword k = 0; k < dynamic.get_entries_num(); ++k)
|
||||
dynamic_entries.emplace_back(k, dynamic);
|
||||
}
|
||||
else if(psec->get_type() == ELFIO::SHT_REL || psec->get_type() == ELFIO::SHT_RELA)
|
||||
{
|
||||
const ELFIO::relocation_section_accessor reloc{reader, psec};
|
||||
ROCP_TRACE << " Number of relocation entries: " << reloc.get_entries_num();
|
||||
for(ELFIO::Elf_Xword k = 0; k < reloc.get_entries_num(); ++k)
|
||||
reloc_entries.emplace_back(k, reloc);
|
||||
}
|
||||
}
|
||||
|
||||
ROCP_TRACE << "Symbols:";
|
||||
for(size_t k = 0; k < symbol_entries.size(); ++k)
|
||||
{
|
||||
if(!symbol_entries.at(k).name.empty())
|
||||
ROCP_TRACE << " [" << k << "] " << symbol_entries.at(k).name;
|
||||
}
|
||||
|
||||
ROCP_TRACE << "Dynamic entries:";
|
||||
for(size_t k = 0; k < dynamic_entries.size(); ++k)
|
||||
{
|
||||
if(!dynamic_entries.at(k).name.empty())
|
||||
ROCP_TRACE << " [" << k << "] " << dynamic_entries.at(k).name;
|
||||
}
|
||||
|
||||
ROCP_TRACE << "Relocation entries:";
|
||||
for(size_t k = 0; k < reloc_entries.size(); ++k)
|
||||
{
|
||||
auto _sym_idx = reloc_entries.at(k).symbol;
|
||||
auto _name = std::string{};
|
||||
if(_sym_idx < symbol_entries.size()) _name = symbol_entries.at(_sym_idx).name;
|
||||
if(!_name.empty()) ROCP_TRACE << " [" << k << "] " << _name;
|
||||
}
|
||||
|
||||
// Print ELF file segments info
|
||||
ELFIO::Elf_Half seg_num = reader.segments.size();
|
||||
ROCP_TRACE << "Number of segments: " << seg_num;
|
||||
for(ELFIO::Elf_Half j = 0; j < seg_num; ++j)
|
||||
{
|
||||
const ELFIO::segment* pseg = reader.segments[j];
|
||||
ROCP_TRACE << " [" << std::setw(2) << j << "] flags: " << as_hex_string(pseg->get_flags())
|
||||
<< " offset: " << as_hex_string(pseg->get_offset())
|
||||
<< " align: " << as_hex_string(pseg->get_align())
|
||||
<< " virt: " << as_hex_string(pseg->get_virtual_address())
|
||||
<< " phys: " << as_hex_string(pseg->get_physical_address())
|
||||
<< " fsize: " << std::setw(8) << pseg->get_file_size()
|
||||
<< " msize: " << std::setw(8) << pseg->get_memory_size();
|
||||
}
|
||||
|
||||
return _info;
|
||||
}
|
||||
} // namespace elf_utils
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,121 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <elfio/elfio.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace elf_utils
|
||||
{
|
||||
using Section = ELFIO::section;
|
||||
using Segment = ELFIO::segment;
|
||||
|
||||
struct SymbolEntry
|
||||
{
|
||||
using accessor_type = ELFIO::symbol_section_accessor;
|
||||
|
||||
SymbolEntry(unsigned int _idx, const accessor_type& _accessor);
|
||||
|
||||
unsigned int index = 0;
|
||||
std::string name = {};
|
||||
ELFIO::Elf64_Addr value = {};
|
||||
ELFIO::Elf_Xword size = {};
|
||||
unsigned char bind = {};
|
||||
unsigned char type = {};
|
||||
ELFIO::Elf_Half section_index = {};
|
||||
unsigned char other = {};
|
||||
};
|
||||
|
||||
struct DynamicEntry
|
||||
{
|
||||
using accessor_type = ELFIO::dynamic_section_accessor;
|
||||
|
||||
DynamicEntry(unsigned int _idx, const accessor_type& _accessor);
|
||||
|
||||
unsigned int index = 0;
|
||||
std::string name = {};
|
||||
ELFIO::Elf_Xword tag = {};
|
||||
ELFIO::Elf_Xword value = {};
|
||||
};
|
||||
|
||||
struct RelocationEntry
|
||||
{
|
||||
using accessor_type = ELFIO::relocation_section_accessor;
|
||||
|
||||
RelocationEntry(unsigned int _idx, const accessor_type& _accessor);
|
||||
|
||||
unsigned int index = 0;
|
||||
ELFIO::Elf64_Addr offset = {};
|
||||
ELFIO::Elf_Word symbol = {};
|
||||
ELFIO::Elf_Word type = {};
|
||||
ELFIO::Elf_Sxword addend = {};
|
||||
};
|
||||
|
||||
struct ElfInfo
|
||||
{
|
||||
explicit ElfInfo(std::string);
|
||||
|
||||
std::string filename = {};
|
||||
ELFIO::elfio reader = {};
|
||||
std::vector<Section*> sections = {};
|
||||
std::vector<SymbolEntry> symbol_entries = {};
|
||||
std::vector<DynamicEntry> dynamic_entries = {};
|
||||
std::vector<RelocationEntry> reloc_entries = {};
|
||||
|
||||
bool has_symbol(std::regex&&) const;
|
||||
|
||||
friend bool operator==(const ElfInfo& lhs, const ElfInfo& rhs)
|
||||
{
|
||||
return (lhs.filename == rhs.filename);
|
||||
}
|
||||
|
||||
friend bool operator<(const ElfInfo& lhs, const ElfInfo& rhs)
|
||||
{
|
||||
return (lhs.filename < rhs.filename);
|
||||
}
|
||||
|
||||
friend bool operator>(const ElfInfo& lhs, const ElfInfo& rhs)
|
||||
{
|
||||
return !(lhs == rhs || lhs < rhs);
|
||||
}
|
||||
|
||||
friend bool operator<=(const ElfInfo& lhs, const ElfInfo& rhs) { return !(lhs > rhs); }
|
||||
friend bool operator>=(const ElfInfo& lhs, const ElfInfo& rhs) { return !(lhs < rhs); }
|
||||
};
|
||||
|
||||
ElfInfo
|
||||
read(const std::string& _inp);
|
||||
} // namespace elf_utils
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
@@ -23,7 +23,9 @@
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include "lib/rocprofiler-sdk/registration.hpp"
|
||||
#include "lib/common/elf_utils.hpp"
|
||||
#include "lib/common/environment.hpp"
|
||||
#include "lib/common/filesystem.hpp"
|
||||
#include "lib/common/logging.hpp"
|
||||
#include "lib/common/static_object.hpp"
|
||||
#include "lib/rocprofiler-sdk/agent.hpp"
|
||||
@@ -88,6 +90,8 @@ namespace registration
|
||||
{
|
||||
namespace
|
||||
{
|
||||
namespace fs = ::rocprofiler::common::filesystem;
|
||||
|
||||
// invoke all rocprofiler_configure symbols
|
||||
bool
|
||||
invoke_client_configures();
|
||||
@@ -129,8 +133,7 @@ std::vector<std::string>
|
||||
get_link_map()
|
||||
{
|
||||
auto chain = std::vector<std::string>{};
|
||||
void* handle = nullptr;
|
||||
handle = dlopen(nullptr, RTLD_LAZY | RTLD_NOLOAD);
|
||||
void* handle = dlopen(nullptr, RTLD_LAZY | RTLD_NOLOAD);
|
||||
|
||||
if(handle)
|
||||
{
|
||||
@@ -245,6 +248,16 @@ find_clients()
|
||||
{
|
||||
ROCP_INFO << "[env] searching " << itr << " for rocprofiler_configure";
|
||||
|
||||
if(fs::exists(itr))
|
||||
{
|
||||
auto elfinfo = common::elf_utils::read(itr);
|
||||
if(!elfinfo.has_symbol(std::regex{"^rocprofiler_configure$"}))
|
||||
{
|
||||
ROCP_FATAL << "rocprofiler tool library " << itr
|
||||
<< " did not contain rocprofiler_configure symbol";
|
||||
}
|
||||
}
|
||||
|
||||
void* handle = dlopen(itr.c_str(), RTLD_NOLOAD | RTLD_LAZY);
|
||||
|
||||
if(!handle)
|
||||
@@ -294,12 +307,24 @@ find_clients()
|
||||
|
||||
// if there are two "rocprofiler_configures", we need to trigger a search of all the shared
|
||||
// libraries
|
||||
if(_next_configure)
|
||||
if(_default_configure)
|
||||
{
|
||||
for(const auto& itr : get_link_map())
|
||||
{
|
||||
ROCP_INFO << "searching " << itr << " for rocprofiler_configure";
|
||||
|
||||
if(fs::exists(itr))
|
||||
{
|
||||
auto elfinfo = common::elf_utils::read(itr);
|
||||
if(!elfinfo.has_symbol(std::regex{"^rocprofiler_configure$"})) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ROCP_INFO << "dlopening " << itr << " for rocprofiler_configure";
|
||||
|
||||
void* handle = dlopen(itr.c_str(), RTLD_LAZY | RTLD_NOLOAD);
|
||||
ROCP_ERROR_IF(handle == nullptr) << "error dlopening " << itr;
|
||||
|
||||
|
||||
Odkázat v novém úkolu
Zablokovat Uživatele