diff --git a/examples/mpi/send-recv.c b/examples/mpi/send-recv.c index 7ac673972..ee43a0718 100644 --- a/examples/mpi/send-recv.c +++ b/examples/mpi/send-recv.c @@ -27,7 +27,7 @@ main(int argc, char** argv) // We are assuming 2 processes for this task if(world_size != 2) { - fprintf(stderr, "World size must be two for %s\n", argv[0]); + fprintf(stderr, "World size must be two for %s, not %i\n", argv[0], world_size); MPI_Abort(MPI_COMM_WORLD, 1); } diff --git a/source/bin/omnitrace/CMakeLists.txt b/source/bin/omnitrace/CMakeLists.txt index 38b7e6321..fb9be4ce0 100644 --- a/source/bin/omnitrace/CMakeLists.txt +++ b/source/bin/omnitrace/CMakeLists.txt @@ -10,17 +10,19 @@ add_executable(omnitrace-exe) target_sources( omnitrace-exe - PRIVATE ${CMAKE_CURRENT_LIST_DIR}/omnitrace.cpp - ${CMAKE_CURRENT_LIST_DIR}/details.cpp + PRIVATE ${CMAKE_CURRENT_LIST_DIR}/details.cpp ${CMAKE_CURRENT_LIST_DIR}/function_signature.cpp - ${CMAKE_CURRENT_LIST_DIR}/log.cpp - ${CMAKE_CURRENT_LIST_DIR}/module_function.cpp - ${CMAKE_CURRENT_LIST_DIR}/omnitrace.hpp - ${CMAKE_CURRENT_LIST_DIR}/fwd.hpp ${CMAKE_CURRENT_LIST_DIR}/function_signature.hpp + ${CMAKE_CURRENT_LIST_DIR}/fwd.hpp ${CMAKE_CURRENT_LIST_DIR}/info.hpp + ${CMAKE_CURRENT_LIST_DIR}/internal_libs.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal_libs.hpp + ${CMAKE_CURRENT_LIST_DIR}/log.cpp ${CMAKE_CURRENT_LIST_DIR}/log.hpp - ${CMAKE_CURRENT_LIST_DIR}/module_function.hpp) + ${CMAKE_CURRENT_LIST_DIR}/module_function.cpp + ${CMAKE_CURRENT_LIST_DIR}/module_function.hpp + ${CMAKE_CURRENT_LIST_DIR}/omnitrace.cpp + ${CMAKE_CURRENT_LIST_DIR}/omnitrace.hpp) target_link_libraries( omnitrace-exe diff --git a/source/bin/omnitrace/details.cpp b/source/bin/omnitrace/details.cpp index 3e6664c3f..34c62390a 100644 --- a/source/bin/omnitrace/details.cpp +++ b/source/bin/omnitrace/details.cpp @@ -25,6 +25,9 @@ #include "log.hpp" #include "omnitrace.hpp" +#include +#include + #include #include @@ -39,17 +42,24 @@ get_whole_function_names() "sem_init", "sem_destroy", "sem_open", "sem_close", "sem_post", "sem_wait", "sem_getvalue", "sem_clockwait", "sem_timedwait", "sem_trywait", "sem_unlink", "fork", "do_futex_wait", "dl_iterate_phdr", "dlinfo", "dlopen", "dlmopen", - "dlvsym", "dlsym", "getenv", "setenv", "unsetenv", "printf", "fprintf", "fflush", - "malloc", "malloc_stats", "malloc_trim", "mallopt", "calloc", "free", "pvalloc", - "valloc", "mmap", "munmap", "fopen", "fclose", "fmemopen", "fmemclose", - "backtrace", "backtrace_symbols", "backtrace_symbols_fd", "sigaddset", - "sigandset", "sigdelset", "sigemptyset", "sigfillset", "sighold", "sigisemptyset", - "sigismember", "sigorset", "sigrelse", "sigvec", "strtok", "strstr", "sbrk", - "strxfrm", "atexit", "ompt_start_tool", "nanosleep", "cfree", "tolower", - "toupper", "fileno", "fileno_unlocked", "exit", "quick_exit", "abort", "mbind", - "migrate_pages", "move_pages", "numa_migrate_pages", "numa_move_pages", - "numa_alloc", "numa_alloc_local", "numa_alloc_interleaved", "numa_alloc_onnode", - "numa_realloc", "numa_free", + "dlvsym", "dlsym", "dlerror", "dladdr", "_dl_sym", "_dl_vsym", "_dl_addr", + "getenv", "setenv", "unsetenv", "printf", "fprintf", "vprintf", + "buffered_vfprintf", "vfprintf", "printf_positional", "puts", "fputs", "vfputs", + "fflush", "fwrite", "malloc", "malloc_stats", "malloc_trim", "mallopt", "calloc", + "free", "pvalloc", "valloc", "sysmalloc", "posix_memalign", "freehook", + "mallochook", "memalignhook", "mprobe", "reallochook", "mmap", "munmap", "fopen", + "fclose", "fmemopen", "fmemclose", "backtrace", "backtrace_symbols", + "backtrace_symbols_fd", "sigaddset", "sigandset", "sigdelset", "sigemptyset", + "sigfillset", "sighold", "sigisemptyset", "sigismember", "sigorset", "sigrelse", + "sigvec", "strtok", "strstr", "sbrk", "strxfrm", "atexit", "ompt_start_tool", + "nanosleep", "cfree", "tolower", "toupper", "fileno", "fileno_unlocked", "exit", + "quick_exit", "abort", "mbind", "migrate_pages", "move_pages", + "numa_migrate_pages", "numa_move_pages", "numa_alloc", "numa_alloc_local", + "numa_alloc_interleaved", "numa_alloc_onnode", "numa_realloc", "numa_free", + "round_and_return", "_init", "_fini", "_start", "__do_global_dtors_aux", + "__libc_csu_init", "__libc_csu_fini", "__hip_module_ctor", "__hip_module_dtor", + "__hipRegisterManagedVar", "__hipRegisterFunction", "__hipPushCallConfiguration", + "__hipPopCallConfiguration", "hipApiName", "enlarge_userbuf", // below are functions which never terminate "rocr::core::Signal::WaitAny", "rocr::core::Runtime::AsyncEventsLoop", "rocr::core::BusyWaitSignal::WaitAcquire", @@ -108,6 +118,59 @@ get_name(module_t* _module) return _v.at(_module); } +symtab_func_t* +get_symtab_function(procedure_t* _func) +{ + static auto _v = std::unordered_map{}; + + auto itr = _v.find(_func); + if(itr == _v.end()) + { + auto _name = _func->getName(); + { + auto nitr = symtab_data.mangled_symbol_names.find(_name); + if(nitr != symtab_data.mangled_symbol_names.end()) + { + _v.emplace(_func, nitr->second->getFunction()); + return _v.at(_func); + } + } + + for(auto& fitr : symtab_data.symbols) + { + if(_name == fitr.first->getName()) + { + _v.emplace(_func, fitr.first); + return _v.at(_func); + } + } + + auto _dname = _func->getDemangledName(); + + { + auto nitr = symtab_data.typed_func_names.find(_dname); + if(nitr != symtab_data.typed_func_names.end()) + { + _v.emplace(_func, nitr->second); + return _v.at(_func); + } + } + + { + auto nitr = symtab_data.typed_symbol_names.find(_dname); + if(nitr != symtab_data.typed_symbol_names.end()) + { + _v.emplace(_func, nitr->second->getFunction()); + return _v.at(_func); + } + } + + if(_v.find(_func) == _v.end()) _v.emplace(_func, nullptr); + } + + return _v.at(_func); +} + namespace { std::string @@ -390,7 +453,7 @@ find_function(image_t* app_image, const std::string& _name, const strset_t& _ext auto _find = [app_image](const std::string& _f) -> procedure_t* { // Extract the vector of functions - bpvector_t _found; + std::vector _found; auto* ret = app_image->findFunction(_f.c_str(), _found, false, true, true); if(ret == nullptr || _found.empty()) return nullptr; return _found.at(0); @@ -488,6 +551,83 @@ error_func_fake(error_level_t level, int num, const char* const* params) .force(level < BPatchInfo); } +#include "internal_libs.hpp" + +#include +#include + +using ::timemory::join::join; + +//======================================================================================// +// +// Read the symtab data from Dyninst +// +void +process_modules(const std::vector& _app_modules) +{ + parse_internal_libs_data(); + + auto _wc = tim::component::wall_clock{}; + auto _pr = tim::component::peak_rss{}; + _wc.start(); + _pr.start(); + + for(auto* itr : _app_modules) + { + auto* _module = SymTab::convert(itr); + if(_module) symtab_data.modules.emplace_back(_module); + } + + verbprintf(0, "Processing %zu modules...\n", symtab_data.modules.size()); + + const auto& _data = get_internal_libs_data(); + auto _names = std::set{}; + for(const auto& itr : _data) + { + _names.emplace(itr.first); + for(const auto& ditr : itr.second) + _names.emplace(ditr.first); + } + + for(auto* itr : symtab_data.modules) + { + const auto* _base_name = tim::filepath::basename(itr->fullName()); + auto _real_name = tim::filepath::realpath(itr->fullName(), nullptr, false); + + if(_names.count(_base_name) == 0 && _names.count(_real_name) == 0) + { + verbprintf(2, "Processing symbol table for module '%s'...\n", + itr->fullName().c_str()); + } + + symtab_data.functions.emplace(itr, std::vector{}); + itr->getAllFunctions(symtab_data.functions.at(itr)); + for(auto* fitr : symtab_data.functions.at(itr)) + { + symtab_data.typed_func_names[tim::demangle(fitr->getName())] = fitr; + + symtab_data.symbols.emplace(fitr, std::vector{}); + fitr->getSymbols(symtab_data.symbols.at(fitr)); + for(auto* sitr : symtab_data.symbols.at(fitr)) + { + symtab_data.mangled_symbol_names[sitr->getMangledName()] = sitr; + symtab_data.typed_symbol_names[sitr->getTypedName()] = sitr; + } + } + } + + _pr.stop(); + _wc.stop(); + verbprintf(0, "Processing %zu modules... Done (%.3f %s, %.3f %s)\n", + _app_modules.size(), _wc.get(), _wc.display_unit().c_str(), _pr.get(), + _pr.display_unit().c_str()); +} + +//======================================================================================// +// +// I/O assistance +// + namespace std { std::string @@ -538,4 +678,87 @@ to_string(error_level_t _level) return JOIN("", tim::log::color::warning(), "UnknownErrorLevel", static_cast(_level)); } + +namespace +{ +std::string&& +to_lower(std::string&& _v) +{ + for(auto& itr : std::move(_v)) + itr = tolower(itr); + return std::move(_v); +} +} // namespace + +std::string +to_string(symbol_visibility_t _v) +{ + return to_lower(SymTab::Symbol::symbolVisibility2Str(_v) + 3); +} + +std::string +to_string(symbol_linkage_t _v) +{ + return to_lower(SymTab::Symbol::symbolLinkage2Str(_v) + 3); +} } // namespace std + +template +Tp +from_string(std::string_view _v) +{ + if constexpr(std::is_same::value) + { + for(const auto& itr : + { SV_UNKNOWN, SV_DEFAULT, SV_INTERNAL, SV_HIDDEN, SV_PROTECTED }) + if(_v == std::to_string(itr)) return itr; + return SV_UNKNOWN; + } + else if constexpr(std::is_same::value) + { + for(const auto& itr : { SL_UNKNOWN, SL_GLOBAL, SL_LOCAL, SL_WEAK, SL_UNIQUE }) + if(_v == std::to_string(itr)) return itr; + return SL_UNKNOWN; + } + else + { + static_assert(std::is_empty::value, "Error! not defined"); + return Tp{}; + } +} + +template symbol_visibility_t +from_string(std::string_view _v); + +template symbol_linkage_t +from_string(std::string_view _v); + +std::ostream& +operator<<(std::ostream& _os, symbol_linkage_t _v) +{ + return (_os << std::to_string(_v)); +} + +std::ostream& +operator<<(std::ostream& _os, symbol_visibility_t _v) +{ + return (_os << std::to_string(_v)); +} + +std::istream& +operator>>(std::istream& _is, symbol_linkage_t& _v) +{ + auto _v_s = std::string{}; + _is >> _v_s; + _v = from_string(_v_s); + return _is; +} + +std::istream& +operator>>(std::istream& _is, symbol_visibility_t& _v) +{ + auto _v_s = std::string{}; + _is >> _v_s; + _v = from_string(_v_s); + return _is; +} diff --git a/source/bin/omnitrace/fwd.hpp b/source/bin/omnitrace/fwd.hpp index 85f110efe..acff922b0 100644 --- a/source/bin/omnitrace/fwd.hpp +++ b/source/bin/omnitrace/fwd.hpp @@ -49,8 +49,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -61,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -88,9 +91,6 @@ struct function_signature; struct basic_block_signature; struct module_function; -template -using bpvector_t = BPatch_Vector; - using string_t = std::string; using string_view_t = std::string_view; using stringstream_t = std::stringstream; @@ -127,14 +127,40 @@ using snippet_handle_t = BPatchSnippetHandle; using patch_pointer_t = std::shared_ptr; using snippet_pointer_t = std::shared_ptr; using call_expr_pointer_t = std::shared_ptr; -using snippet_vec_t = bpvector_t; -using procedure_vec_t = bpvector_t; +using snippet_vec_t = std::vector; +using procedure_vec_t = std::vector; using basic_block_set_t = std::set; -using basic_loop_vec_t = bpvector_t; +using basic_loop_vec_t = std::vector; using snippet_pointer_vec_t = std::vector; using instruction_t = Dyninst::InstructionAPI::Instruction; using instruction_category_t = Dyninst::InstructionAPI::InsnCategory; +namespace SymTab = ::Dyninst::SymtabAPI; +using symtab_t = SymTab::Symtab; +using symtab_module_t = SymTab::Module; +using symtab_symbol_t = SymTab::Symbol; +using symtab_func_t = SymTab::Function; +using symbol_linkage_t = SymTab::Symbol::SymbolLinkage; +using symbol_visibility_t = SymTab::Symbol::SymbolVisibility; + +constexpr auto SL_UNKNOWN = symtab_symbol_t::SL_UNKNOWN; +constexpr auto SL_GLOBAL = symtab_symbol_t::SL_GLOBAL; +constexpr auto SL_LOCAL = symtab_symbol_t::SL_LOCAL; +constexpr auto SL_WEAK = symtab_symbol_t::SL_WEAK; +constexpr auto SL_UNIQUE = symtab_symbol_t::SL_UNIQUE; + +constexpr auto SV_UNKNOWN = symtab_symbol_t::SV_UNKNOWN; +constexpr auto SV_DEFAULT = symtab_symbol_t::SV_DEFAULT; +constexpr auto SV_INTERNAL = symtab_symbol_t::SV_INTERNAL; +constexpr auto SV_HIDDEN = symtab_symbol_t::SV_HIDDEN; +constexpr auto SV_PROTECTED = symtab_symbol_t::SV_PROTECTED; + +constexpr auto SL_END_V = + std::max({ SL_UNKNOWN, SL_GLOBAL, SL_LOCAL, SL_WEAK, SL_UNIQUE }) + 1; + +constexpr auto SV_END_V = + std::max({ SV_UNKNOWN, SV_DEFAULT, SV_INTERNAL, SV_HIDDEN, SV_PROTECTED }) + 1; + void omnitrace_prefork_callback(thread_t* parent, thread_t* child); @@ -165,6 +191,7 @@ extern bool loop_level_instr; extern bool instr_dynamic_callsites; extern bool instr_traps; extern bool instr_loop_traps; +extern bool parse_all_modules; extern size_t min_address_range; extern size_t min_loop_address_range; extern size_t min_instructions; @@ -182,6 +209,7 @@ extern int num_log_entries; // extern bool simulate; extern bool include_uninstr; +extern bool include_internal_linked_libs; // // string settings // @@ -209,7 +237,26 @@ extern regexvec_t file_exclude; extern regexvec_t file_restrict; extern regexvec_t func_restrict; extern regexvec_t caller_include; +extern regexvec_t func_internal_include; +extern regexvec_t file_internal_include; +extern regexvec_t instruction_exclude; extern CodeCoverageMode coverage_mode; +// +// symtab variables +// +struct symtab_data_s +{ + std::vector modules = {}; + std::map> functions = {}; + std::map> symbols = {}; + std::unordered_map mangled_symbol_names = {}; + std::unordered_map typed_func_names = {}; + std::unordered_map typed_symbol_names = {}; +}; + +extern symtab_data_s symtab_data; +extern std::set enabled_linkage; +extern std::set enabled_visibility; // logging extern std::unique_ptr log_ofs; @@ -267,6 +314,9 @@ consume_parameters(T&&...) //======================================================================================// +void +process_modules(const std::vector&); + strset_t get_whole_function_names(); @@ -293,7 +343,7 @@ query_instr(procedure_t* funcToInstr, procedure_loc_t traceLoc, flow_graph_t* cf template bool -insert_instr(address_space_t* mutatee, const bpvector_t& _points, Tp traceFunc, +insert_instr(address_space_t* mutatee, const std::vector& _points, Tp traceFunc, procedure_loc_t traceLoc, bool allow_traps = instr_traps); template @@ -317,13 +367,33 @@ void error_func_fake(error_level_t level, int num, const char* const* params); std::string_view -get_name(procedure_t* _module); +get_name(procedure_t*); std::string_view -get_name(module_t* _module); +get_name(module_t*); + +symtab_func_t* +get_symtab_function(procedure_t*); namespace std { std::string to_string(instruction_category_t); std::string to_string(error_level_t); +std::string to_string(symbol_visibility_t); +std::string to_string(symbol_linkage_t); } // namespace std + +template +Tp from_string(std::string_view); + +std::ostream& +operator<<(std::ostream&, symbol_linkage_t); + +std::ostream& +operator<<(std::ostream&, symbol_visibility_t); + +std::istream& +operator>>(std::istream&, symbol_linkage_t&); + +std::istream& +operator>>(std::istream&, symbol_visibility_t&); diff --git a/source/bin/omnitrace/internal_libs.cpp b/source/bin/omnitrace/internal_libs.cpp new file mode 100644 index 000000000..35504f23d --- /dev/null +++ b/source/bin/omnitrace/internal_libs.cpp @@ -0,0 +1,592 @@ +// MIT License +// +// Copyright (c) 2022 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 "internal_libs.hpp" +#include "binary/analysis.hpp" +#include "binary/binary_info.hpp" +#include "binary/link_map.hpp" +#include "binary/scope_filter.hpp" +#include "binary/symbol.hpp" +#include "common/defines.h" +#include "core/utility.hpp" +#include "fwd.hpp" +#include "log.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ +namespace filepath = ::tim::filepath; +using ::tim::delimit; +using ::tim::get_env; +using ::timemory::join::join; +using strview_init_t = std::initializer_list; +using strview_set_t = std::set; +using open_modes_vec_t = std::vector; + +auto +get_exe_realpath() +{ + return filepath::realpath("/proc/self/exe", nullptr, false); +} + +auto& +get_symtab_file_cache() +{ + static auto _cache = std::unordered_map>{}; + return _cache; +} + +symtab_t* +get_symtab_file(const std::string& _name) +{ + auto& _cache = get_symtab_file_cache(); + auto itr = _cache.find(_name); + if(itr == _cache.end()) + { + symtab_t* _v = SymTab::Symtab::findOpenSymtab(_name); + bool _closable = (_v == nullptr); + if(!_v) SymTab::Symtab::openFile(_v, _name); + + TIMEMORY_PREFER(_v != nullptr) + << "Warning! Dyninst could not open a Symtab instance for file '" << _name + << "'\n"; + _cache.emplace(_name, std::make_pair(_v, _closable)); + } + + return _cache.at(_name).first; +} + +bool +close_symtab_file(const std::string& _name) +{ + auto& _cache = get_symtab_file_cache(); + auto itr = _cache.find(_name); + if(itr != _cache.end()) + { + symtab_t* _symtab = itr->second.first; + bool _closable = itr->second.second; + if(_symtab && _closable) SymTab::Symtab::closeSymtab(_symtab); + _cache.erase(itr); + return true; + } + return false; +} + +template