restructure libomnitrace + tasking and omnitrace-causal updates (#237)

* restructured libomnitrace

- this is necessary to incorporate some of the binary analysis capabilities into omnitrace exe
- created libomnitrace-core (static)
- created libomnitrace-binary (static)
- created libomnitrace (static)
- omnitrace-avail links to libomnitrace.a
- omnitrace-critical-trace links to libomnitrace.a
- tweaked the testing
  - reduced verbosity on some of MPI tests
  - excluded trace-time-window from tests on Ubuntu 18.04
  - reduced causal e2e iterations
- minor tweak to tasking
  - manually create `PTL::UserTaskQueue` instance instead of relying on `PTL::ThreadPool` to create it

* Update formatting workflow

- source formatting uses ubuntu-22.04
- check-includes doesn't generate false positive for 'include "timemory.hpp"'

* omnitrace-causal --generate-configs

- fix config generation in omnitrace causal
- add test for omnitrace-causal + generating configs

* Fix omnitrace-object-library build

- accidentally included rocm sources in non-rocm builds

* Fix rocm compilation w/o rocprofiler

* update timemory submodule with mpi_get warning messages

* sampling offload file updates

- more verbose messages
- disable offload before stopping

* testing updates

- increase causal e2e iterations to 12
- increase lock_environment verbose to 2 (for sampling offload messages)
- fix return for omnitrace_add_validation_test
Este commit está contenido en:
Jonathan R. Madsen
2023-02-04 10:59:50 -06:00
cometido por GitHub
padre 8feb6bf8b6
commit e7d3125459
Se han modificado 164 ficheros con 721 adiciones y 574 borrados
+28
Ver fichero
@@ -0,0 +1,28 @@
#
set(binary_sources
${CMAKE_CURRENT_LIST_DIR}/address_multirange.cpp
${CMAKE_CURRENT_LIST_DIR}/analysis.cpp
${CMAKE_CURRENT_LIST_DIR}/dwarf_entry.cpp
${CMAKE_CURRENT_LIST_DIR}/link_map.cpp
${CMAKE_CURRENT_LIST_DIR}/scope_filter.cpp
${CMAKE_CURRENT_LIST_DIR}/symbol.cpp)
set(binary_headers
${CMAKE_CURRENT_LIST_DIR}/address_multirange.hpp
${CMAKE_CURRENT_LIST_DIR}/analysis.hpp
${CMAKE_CURRENT_LIST_DIR}/dwarf_entry.hpp
${CMAKE_CURRENT_LIST_DIR}/binary_info.hpp
${CMAKE_CURRENT_LIST_DIR}/link_map.hpp
${CMAKE_CURRENT_LIST_DIR}/scope_filter.hpp
${CMAKE_CURRENT_LIST_DIR}/symbol.hpp)
add_library(omnitrace-binary-library STATIC)
add_library(omnitrace::omnitrace-binary ALIAS omnitrace-binary-library)
target_sources(omnitrace-binary-library PRIVATE ${binary_sources} ${binary_headers})
target_link_libraries(
omnitrace-binary-library PRIVATE omnitrace::omnitrace-interface-library
omnitrace::omnitrace-core)
set_target_properties(omnitrace-binary-library PROPERTIES OUTPUT_NAME omnitrace-binary)
+75
Ver fichero
@@ -0,0 +1,75 @@
// 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 "address_multirange.hpp"
#include <algorithm>
#include <cstdint>
#include <string>
#include <utility>
namespace omnitrace
{
namespace binary
{
address_multirange&
address_multirange::operator+=(std::pair<coarse, uintptr_t>&& _v)
{
coarse_range = address_range{ std::min(coarse_range.low, _v.second),
std::max(coarse_range.high, _v.second) };
return *this;
}
address_multirange&
address_multirange::operator+=(std::pair<coarse, address_range>&& _v)
{
coarse_range = address_range{ std::min(coarse_range.low, _v.second.low),
std::max(coarse_range.high, _v.second.high) };
return *this;
}
address_multirange&
address_multirange::operator+=(uintptr_t _v)
{
*this += std::make_pair(coarse{}, _v);
for(auto&& itr : m_fine_ranges)
if(itr.contains(_v)) return *this;
m_fine_ranges.emplace(address_range{ _v });
return *this;
}
address_multirange&
address_multirange::operator+=(address_range _v)
{
*this += std::make_pair(coarse{}, _v);
for(auto&& itr : m_fine_ranges)
if(itr.contains(_v)) return *this;
m_fine_ranges.emplace(_v);
return *this;
}
} // namespace binary
} // namespace omnitrace
+76
Ver fichero
@@ -0,0 +1,76 @@
// 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.
#pragma once
#include "core/binary/address_range.hpp"
#include "core/binary/fwd.hpp"
#include <timemory/utility/macros.hpp>
#include <cstdint>
#include <utility>
namespace omnitrace
{
namespace binary
{
struct address_multirange
{
struct coarse
{};
OMNITRACE_DEFAULT_OBJECT(address_multirange)
address_multirange& operator+=(std::pair<coarse, uintptr_t>&&);
address_multirange& operator+=(std::pair<coarse, address_range>&& _v);
address_multirange& operator+=(uintptr_t _v);
address_multirange& operator+=(address_range _v);
template <typename Tp>
bool contains(Tp&& _v) const;
address_range coarse_range = {};
auto size() const { return m_fine_ranges.size(); }
auto empty() const { return m_fine_ranges.empty(); }
auto range_size() const { return coarse_range.size(); }
private:
std::set<address_range> m_fine_ranges = {};
};
template <typename Tp>
OMNITRACE_INLINE bool
address_multirange::contains(Tp&& _v) const
{
using type = concepts::unqualified_type_t<Tp>;
static_assert(std::is_integral<type>::value ||
std::is_same<type, address_range>::value,
"Error! operator+= supports only integrals or address_ranges");
if(!coarse_range.contains(_v)) return false;
return std::any_of(m_fine_ranges.begin(), m_fine_ranges.end(),
[_v](auto&& itr) { return itr.contains(_v); });
}
} // namespace binary
} // namespace omnitrace
+201
Ver fichero
@@ -0,0 +1,201 @@
// 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 "core/config.hpp"
#if !defined(TIMEMORY_USE_BFD)
# error "BFD support not enabled"
#endif
#define PACKAGE "omnitrace"
#include <bfd.h>
#include "analysis.hpp"
#include "binary_info.hpp"
#include "core/binary/address_range.hpp"
#include "core/binary/fwd.hpp"
#include "core/common.hpp"
#include "core/config.hpp"
#include "core/debug.hpp"
#include "core/state.hpp"
#include "core/utility.hpp"
#include "dwarf_entry.hpp"
#include "scope_filter.hpp"
#include "symbol.hpp"
#include <timemory/log/macros.hpp>
#include <timemory/unwind/bfd.hpp>
#include <timemory/unwind/dlinfo.hpp>
#include <timemory/utility/filepath.hpp>
#include <timemory/utility/join.hpp>
#include <timemory/utility/procfs/maps.hpp>
#include <cstdint>
#include <cstdlib>
#include <dlfcn.h>
#include <regex>
#include <set>
#include <stdexcept>
namespace omnitrace
{
namespace binary
{
namespace
{
binary_info
parse_line_info(const std::string& _name, bool _process_dwarf)
{
auto _info = binary_info{};
auto& _bfd = _info.bfd;
_bfd = std::make_shared<bfd_file>(_name);
OMNITRACE_VERBOSE(0, "[binary] Reading line info for '%s'...\n", _name.c_str());
if(_bfd && _bfd->is_good())
{
auto& _section_map = _info.sections;
auto _section_set = std::set<asection*>{};
auto _processed = std::set<uintptr_t>{};
for(auto&& itr : _bfd->get_symbols())
{
if(itr.symsize == 0) continue;
auto& _sym = _info.symbols.emplace_back(symbol{ itr });
// if(itr.symsize == 0) continue;
auto* _section = static_cast<asection*>(itr.section);
_section_set.emplace(_section);
_processed.emplace(itr.address);
_info.ranges.emplace_back(
address_range{ itr.address, itr.address + itr.symsize });
_sym.read_bfd(*_bfd);
}
for(auto* itr : _section_set)
{
auto* _section = const_cast<asection*>(itr);
bfd_vma _section_vma = bfd_section_vma(_section);
bfd_size_type _section_len = bfd_section_size(_section);
auto _section_range =
address_range{ _section_vma, _section_vma + _section_len };
_section_map[_section_range] = _section;
}
TIMEMORY_REQUIRE(_section_set.size() == _section_map.size())
<< "section set size (" << _section_set.size() << ") != section map size ("
<< _section_map.size() << ")\n";
if(_process_dwarf)
{
std::tie(_info.debug_info, _info.ranges, _info.breakpoints) =
dwarf_entry::process_dwarf(_bfd->fd);
}
for(auto& itr : _info.symbols)
{
itr.read_dwarf_entries(_info.debug_info);
itr.read_dwarf_breakpoints(_info.breakpoints);
}
_info.sort();
}
OMNITRACE_VERBOSE(1, "[binary] Reading line info for '%s'... %zu entries\n",
_bfd->name.c_str(), _info.symbols.size());
return _info;
}
} // namespace
std::vector<binary_info>
get_binary_info(const std::vector<std::string>& _files,
const std::vector<scope_filter>& _filters, bool _process_dwarf)
{
auto _satisfies_filter = [&_filters](auto _scope, const std::string& _value) {
for(const auto& itr : _filters) // NOLINT
{
// if the filter is for the specified scope and itr does not satisfy the
// include/exclude mode, return false
if((itr.scope & _scope) == _scope && !itr(_value)) return false;
}
return true;
};
auto _satisfies_binary_filter = [&_satisfies_filter](const std::string& _value) {
return _satisfies_filter(scope_filter::BINARY_FILTER, _value);
};
// filter function used by procfs::get_contiguous_maps
// ensures that we do not process omnitrace/gotcha/libunwind libraries
// and do not process the libraries outside of the binary scope
auto _filter = [&_satisfies_binary_filter](const procfs::maps& _v) {
if(_v.pathname.empty()) return false;
auto _path = filepath::realpath(_v.pathname, nullptr, false);
return (filepath::exists(_path) && _satisfies_binary_filter(_path));
};
auto _data = std::vector<binary_info>{};
_data.reserve(_files.size());
{
auto _exists = std::set<std::string>{};
for(const auto& itr : _files)
{
auto _filename = filepath::realpath(itr, nullptr, false);
if(filepath::exists(_filename) && _satisfies_binary_filter(_filename) &&
_exists.find(_filename) == _exists.end())
{
_data.emplace_back(parse_line_info(_filename, _process_dwarf));
_exists.emplace(_filename);
}
}
}
// get the memory maps
auto _maps = procfs::get_contiguous_maps(process::get_id(), _filter, true);
for(auto& itr : _data)
{
for(const auto& mitr : _maps)
if(itr.bfd->name == mitr.pathname) itr.mappings.emplace_back(mitr);
}
for(auto& itr : _data)
{
for(const auto& mitr : itr.mappings)
{
auto mrange = address_range{ mitr.load_address, mitr.last_address };
for(auto& sitr : itr.symbols)
{
auto _addr = sitr.address + mitr.load_address;
if(mrange.contains(_addr)) sitr.load_address = mitr.load_address;
}
}
}
for(auto& itr : _data)
itr.sort();
return _data;
}
} // namespace binary
} // namespace omnitrace
+60
Ver fichero
@@ -0,0 +1,60 @@
// 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.
#pragma once
#include "common/defines.h"
#include "core/binary/fwd.hpp"
#include "core/common.hpp"
#include "core/defines.hpp"
#include "core/exception.hpp"
#include <timemory/hash/types.hpp>
#include <timemory/mpl/concepts.hpp>
#include <timemory/tpls/cereal/cereal/cereal.hpp>
#include <timemory/unwind/bfd.hpp>
#include <timemory/unwind/types.hpp>
#include <timemory/utility/procfs/maps.hpp>
#include <cstdint>
#include <deque>
#include <map>
#include <memory>
#include <regex>
#include <string>
#include <tuple>
#include <variant>
namespace omnitrace
{
namespace binary
{
namespace procfs = ::tim::procfs; // NOLINT
using bfd_file = ::tim::unwind::bfd_file;
using hash_value_t = ::tim::hash_value_t;
std::vector<binary_info>
get_binary_info(const std::vector<std::string>&, const std::vector<scope_filter>&,
bool _process_dwarf = true);
} // namespace binary
} // namespace omnitrace
+87
Ver fichero
@@ -0,0 +1,87 @@
// 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.
#pragma once
#include "core/binary/address_range.hpp"
#include "core/binary/fwd.hpp"
#include "core/utility.hpp"
#include "dwarf_entry.hpp"
#include "symbol.hpp"
#include <timemory/utility/procfs/maps.hpp>
#include <cstdint>
#include <deque>
#include <memory>
#include <string>
#include <vector>
namespace omnitrace
{
namespace binary
{
struct binary_info
{
std::shared_ptr<bfd_file> bfd = {};
std::vector<procfs::maps> mappings = {};
std::deque<symbol> symbols = {};
std::deque<dwarf_entry> debug_info = {};
std::vector<address_range> ranges = {};
std::vector<uintptr_t> breakpoints = {};
std::unordered_map<address_range, void*> sections = {};
void sort();
std::string filename() const;
template <typename RetT = void>
RetT* find_section(uintptr_t) const;
};
inline void
binary_info::sort()
{
utility::filter_sort_unique(mappings);
utility::filter_sort_unique(symbols);
utility::filter_sort_unique(ranges);
utility::filter_sort_unique(debug_info);
utility::filter_sort_unique(breakpoints);
}
template <typename RetT>
inline RetT*
binary_info::find_section(uintptr_t _addr) const
{
for(const auto& sitr : sections)
{
if(sitr.first.contains(_addr)) return static_cast<RetT*>(sitr.second);
}
return nullptr;
}
inline std::string
binary_info::filename() const
{
return (bfd) ? std::string{ bfd->name } : std::string{};
}
} // namespace binary
} // namespace omnitrace
+237
Ver fichero
@@ -0,0 +1,237 @@
// 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 "dwarf_entry.hpp"
#include "core/binary/fwd.hpp"
#include "core/timemory.hpp"
#include "core/utility.hpp"
#include <dwarf.h>
#include <elfutils/libdw.h>
namespace omnitrace
{
namespace binary
{
namespace
{
using utility::combine;
auto
get_dwarf_address_ranges(Dwarf_Die* _die)
{
auto _ranges = std::vector<address_range>{};
if(dwarf_tag(_die) != DW_TAG_compile_unit && dwarf_tag(_die) != DW_TAG_subprogram)
return _ranges;
Dwarf_Addr _low_pc;
Dwarf_Addr _high_pc;
dwarf_lowpc(_die, &_low_pc);
dwarf_highpc(_die, &_high_pc);
if(_low_pc > _high_pc)
{
Dwarf_Addr _entry_pc;
dwarf_entrypc(_die, &_entry_pc);
if(_entry_pc < _low_pc) _low_pc = _entry_pc;
}
if(_low_pc < _high_pc) _ranges.emplace_back(_low_pc, _high_pc);
Dwarf_Addr _base_addr;
ptrdiff_t _offset = 0;
do
{
uintptr_t _low = 0;
uintptr_t _high = 0;
_offset = dwarf_ranges(_die, _offset, &_base_addr, &_low, &_high);
if(_low < _high) _ranges.emplace_back(_low, _high);
} while(_offset > 0);
return _ranges;
}
auto
get_dwarf_breakpoints(Dwarf_Die* _die)
{
auto _bkpts = std::vector<uintptr_t>{};
if(dwarf_tag(_die) != DW_TAG_subprogram) return _bkpts;
Dwarf_Addr* _pts = nullptr;
auto _npts = dwarf_entry_breakpoints(_die, &_pts);
if(_npts > 0 && _pts) _bkpts.assign(_pts, _pts + _npts);
return _bkpts;
}
auto
get_dwarf_entry(Dwarf_Die* _die)
{
auto _line_info = std::deque<dwarf_entry>{};
if(dwarf_tag(_die) != DW_TAG_compile_unit) return _line_info;
Dwarf_Lines* _lines = nullptr;
size_t _num_lines = 0;
if(dwarf_getsrclines(_die, &_lines, &_num_lines) == 0)
{
_line_info.resize(_num_lines);
for(size_t j = 0; j < _num_lines; ++j)
{
auto& itr = _line_info.at(j);
auto* _line = dwarf_onesrcline(_lines, j);
if(_line)
{
int _lineno = 0;
uintptr_t _address = 0;
dwarf_lineno(_line, &_lineno);
dwarf_linecol(_line, &itr.col);
dwarf_linebeginstatement(_line, &itr.begin_statement);
dwarf_lineendsequence(_line, &itr.end_sequence);
dwarf_lineblock(_line, &itr.line_block);
dwarf_lineepiloguebegin(_line, &itr.epilogue_begin);
dwarf_lineprologueend(_line, &itr.prologue_end);
dwarf_lineisa(_line, &itr.isa);
dwarf_linediscriminator(_line, &itr.discriminator);
dwarf_lineaddr(_line, &_address);
itr.address = address_range{ _address };
if(_lineno > 0) itr.line = _lineno;
const auto* _file = dwarf_linesrc(_line, nullptr, nullptr);
if(!_file) _file = dwarf_diename(_die);
itr.file = filepath::realpath(_file, nullptr, false);
}
}
}
return _line_info;
}
} // namespace
bool
dwarf_entry::operator<(const dwarf_entry& _rhs) const
{
return std::tie(address, line, col, discriminator) <
std::tie(_rhs.address, _rhs.line, _rhs.col, _rhs.discriminator);
}
bool
dwarf_entry::operator==(const dwarf_entry& _rhs) const
{
return std::tie(address, line, col, discriminator, vliw_op_index, isa, file) ==
std::tie(_rhs.address, _rhs.line, _rhs.col, _rhs.discriminator,
_rhs.vliw_op_index, _rhs.isa, _rhs.file);
}
bool
dwarf_entry::operator!=(const dwarf_entry& _rhs) const
{
return !(*this == _rhs);
}
bool
dwarf_entry::is_valid() const
{
return (*this != dwarf_entry{} && !file.empty());
}
dwarf_entry::dwarf_tuple_t
dwarf_entry::process_dwarf(int _fd)
{
auto* _dwarf_v = dwarf_begin(_fd, DWARF_C_READ);
auto _data_v = dwarf_tuple_t{};
if(_dwarf_v)
{
auto& _entries = std::get<0>(_data_v);
auto& _ranges = std::get<1>(_data_v);
auto& _bkpts = std::get<2>(_data_v);
size_t cu_header_size = 0;
Dwarf_Off cu_off = 0;
Dwarf_Off next_cu_off = 0;
for(; dwarf_nextcu(_dwarf_v, cu_off, &next_cu_off, &cu_header_size, nullptr,
nullptr, nullptr) == 0;
cu_off = next_cu_off)
{
auto cu_die_off = cu_off + cu_header_size;
auto cu_die = Dwarf_Die{};
if(dwarf_offdie(_dwarf_v, cu_die_off, &cu_die) != nullptr)
{
Dwarf_Die* _die = &cu_die;
if(dwarf_tag(_die) == DW_TAG_compile_unit)
{
combine(_entries, get_dwarf_entry(_die));
combine(_ranges, get_dwarf_address_ranges(_die));
}
else if(dwarf_tag(_die) == DW_TAG_subprogram)
{
combine(_bkpts, get_dwarf_breakpoints(_die));
combine(_ranges, get_dwarf_address_ranges(_die));
}
}
}
dwarf_end(_dwarf_v);
utility::filter_sort_unique(_entries);
utility::filter_sort_unique(_ranges);
utility::filter_sort_unique(_bkpts);
}
return _data_v;
}
template <typename ArchiveT>
void
dwarf_entry::serialize(ArchiveT& ar, const unsigned int)
{
#define OMNITRACE_SERIALIZE_MEMBER(MEMBER) ar(::tim::cereal::make_nvp(#MEMBER, MEMBER));
OMNITRACE_SERIALIZE_MEMBER(file)
OMNITRACE_SERIALIZE_MEMBER(line)
OMNITRACE_SERIALIZE_MEMBER(col)
OMNITRACE_SERIALIZE_MEMBER(address)
OMNITRACE_SERIALIZE_MEMBER(discriminator)
// OMNITRACE_SERIALIZE_MEMBER(begin_statement)
// OMNITRACE_SERIALIZE_MEMBER(end_sequence)
// OMNITRACE_SERIALIZE_MEMBER(line_block)
// OMNITRACE_SERIALIZE_MEMBER(prologue_end)
// OMNITRACE_SERIALIZE_MEMBER(epilogue_begin)
// OMNITRACE_SERIALIZE_MEMBER(vliw_op_index)
// OMNITRACE_SERIALIZE_MEMBER(isa)
}
template void
dwarf_entry::serialize<cereal::JSONInputArchive>(cereal::JSONInputArchive&,
const unsigned int);
template void
dwarf_entry::serialize<cereal::MinimalJSONOutputArchive>(
cereal::MinimalJSONOutputArchive&, const unsigned int);
template void
dwarf_entry::serialize<cereal::PrettyJSONOutputArchive>(cereal::PrettyJSONOutputArchive&,
const unsigned int);
} // namespace binary
} // namespace omnitrace
+66
Ver fichero
@@ -0,0 +1,66 @@
// 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.
#pragma once
#include "core/binary/address_range.hpp"
#include "core/binary/fwd.hpp"
namespace omnitrace
{
namespace binary
{
struct dwarf_entry
{
// tuple of dwarf line info, address ranges, and breakpoints
using dwarf_tuple_t = std::tuple<std::deque<dwarf_entry>, std::vector<address_range>,
std::vector<uintptr_t>>;
OMNITRACE_DEFAULT_OBJECT(dwarf_entry)
bool begin_statement = false;
bool end_sequence = false;
bool line_block = false;
bool prologue_end = false;
bool epilogue_begin = false;
unsigned int line = 0;
int col = 0;
unsigned int vliw_op_index = 0;
unsigned int isa = 0;
unsigned int discriminator = 0;
address_range address = { 0, 0 };
std::string file = {};
bool is_valid() const;
bool operator<(const dwarf_entry&) const;
bool operator==(const dwarf_entry&) const;
bool operator!=(const dwarf_entry&) const;
explicit operator bool() const { return is_valid(); }
static dwarf_tuple_t process_dwarf(int _fd);
template <typename ArchiveT>
void serialize(ArchiveT&, const unsigned int);
};
} // namespace binary
} // namespace omnitrace
+182
Ver fichero
@@ -0,0 +1,182 @@
// 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 "link_map.hpp"
#include "core/common.hpp"
#include "core/config.hpp"
#include "core/debug.hpp"
#include "core/timemory.hpp"
#include <timemory/utility/filepath.hpp>
#include <cstdint>
#include <dlfcn.h>
#include <link.h>
#include <set>
#include <string>
#include <string_view>
namespace omnitrace
{
namespace binary
{
namespace
{
const open_modes_vec_t default_link_open_modes = { (RTLD_LAZY | RTLD_NOLOAD),
(RTLD_LAZY | RTLD_LOCAL) };
}
std::string
get_linked_path(const char* _name, open_modes_vec_t&& _open_modes)
{
if(_name == nullptr) return config::get_exe_realpath();
if(_open_modes.empty()) _open_modes = default_link_open_modes;
auto _lib = std::string{ _name };
void* _handle = nullptr;
bool _noload = false;
for(auto _mode : _open_modes)
{
_handle = dlopen(_name, _mode);
_noload = (_mode & RTLD_NOLOAD) == RTLD_NOLOAD;
if(_handle) break;
}
if(_handle)
{
struct link_map* _link_map = nullptr;
dlinfo(_handle, RTLD_DI_LINKMAP, &_link_map);
if(_link_map != nullptr && !std::string_view{ _link_map->l_name }.empty())
{
_lib = filepath::realpath(_link_map->l_name, nullptr, false);
}
if(_noload == false) dlclose(_handle);
}
return _lib;
}
std::set<link_file>
get_link_map(const char* _lib, const std::string& _exclude_linked_by,
const std::string& _exclude_re, open_modes_vec_t&& _open_modes)
{
if(_open_modes.empty()) _open_modes = default_link_open_modes;
auto _get_chain = [&_open_modes](const char* _name) {
void* _handle = nullptr;
bool _noload = false;
for(auto _mode : _open_modes)
{
_handle = dlopen(_name, _mode);
_noload = (_mode & RTLD_NOLOAD) == RTLD_NOLOAD;
if(_handle) break;
}
auto _chain = std::set<std::string>{};
if(_handle)
{
struct link_map* _link_map = nullptr;
dlinfo(_handle, RTLD_DI_LINKMAP, &_link_map);
struct link_map* _next = _link_map;
while(_next)
{
if(_name == nullptr && _next == _link_map &&
std::string_view{ _next->l_name }.empty())
{
// only insert exe name if dlopened the exe and
// empty name is first entry
_chain.emplace(config::get_exe_realpath());
}
else if(!std::string_view{ _next->l_name }.empty())
{
_chain.emplace(_next->l_name);
}
_next = _next->l_next;
}
if(_noload == false) dlclose(_handle);
}
return _chain;
};
auto _full_chain = _get_chain(_lib);
auto _excl_chain = (_exclude_linked_by.empty())
? std::set<std::string>{}
: _get_chain(_exclude_linked_by.c_str());
auto _fini_chain = std::set<link_file>{};
for(const auto& itr : _full_chain)
{
std::cout << itr << std::endl;
if(_excl_chain.find(itr) == _excl_chain.end())
{
if(_exclude_re.empty() || !std::regex_search(itr, std::regex{ _exclude_re }))
_fini_chain.emplace(itr);
else
_excl_chain.emplace(itr);
}
}
auto _name = (!_lib) ? config::get_exe_realpath() : std::string{ _lib };
for(const auto& itr : _fini_chain)
{
OMNITRACE_VERBOSE(2, "[linkmap][%s]: %s\n", filepath::basename(_name),
itr.real().c_str());
}
for(const auto& itr : _excl_chain)
{
OMNITRACE_VERBOSE(3, "[linkmap][%s]: %s\n", _exclude_linked_by.c_str(),
link_file{ itr }.real().c_str());
}
return _fini_chain;
}
bool
link_file::operator<(const link_file& _rhs) const
{
if(name == _rhs.name) return false;
auto _lhs_base = base();
auto _lhs_real = real();
auto _rhs_base = _rhs.base();
auto _rhs_real = _rhs.real();
if(_lhs_base == _rhs_base || _lhs_real == _rhs_real) return false;
return (_lhs_real < _rhs_real);
}
std::string_view
link_file::base() const
{
return std::string_view{ filepath::basename(name) };
}
std::string
link_file::real() const
{
return filepath::realpath(name, nullptr, false);
}
} // namespace binary
} // namespace omnitrace
+63
Ver fichero
@@ -0,0 +1,63 @@
// 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.
#pragma once
#include <cstdint>
#include <dlfcn.h>
#include <set>
#include <string>
#include <string_view>
#include <vector>
namespace omnitrace
{
namespace binary
{
using open_modes_vec_t = std::vector<int>;
struct link_file
{
link_file(std::string_view&& _v)
: name{ _v }
{}
std::string_view base() const;
std::string real() const;
bool operator<(const link_file&) const;
std::string name = {};
};
// helper function for translating generic lib name to resolved path
std::string
get_linked_path(const char*, open_modes_vec_t&& = {});
// default parameters: get the linked binaries for the exe but exclude the linked binaries
// from libomnitrace
std::set<link_file>
get_link_map(const char* _lib = nullptr,
const std::string& _exclude_linked_by = "libomnitrace.so",
const std::string& _exclude_re = "libomnitrace-([a-zA-Z]+)\\.so",
open_modes_vec_t&& _open_modes = {});
} // namespace binary
} // namespace omnitrace
+46
Ver fichero
@@ -0,0 +1,46 @@
// 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 "scope_filter.hpp"
#include "core/exception.hpp"
#include <regex>
namespace omnitrace
{
namespace binary
{
bool
scope_filter::operator()(std::string_view _value) const
{
if(mode == FILTER_INCLUDE)
return (expression.empty())
? true
: std::regex_search(_value.data(), std::regex{ expression });
else if(mode == FILTER_EXCLUDE)
return (expression.empty())
? false
: !std::regex_search(_value.data(), std::regex{ expression });
throw exception<std::runtime_error>{ "invalid scope filter mode" };
}
} // namespace binary
} // namespace omnitrace
+75
Ver fichero
@@ -0,0 +1,75 @@
// 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.
#pragma once
#include "core/defines.hpp"
#include <cstdint>
#include <string>
namespace omnitrace
{
namespace binary
{
struct scope_filter
{
enum filter_mode : uint8_t
{
FILTER_INCLUDE = 0,
FILTER_EXCLUDE
};
enum filter_scope : uint8_t
{
UNIVERSAL_FILTER = (1 << 0),
BINARY_FILTER = (1 << 1),
SOURCE_FILTER = (1 << 2),
FUNCTION_FILTER = (1 << 3)
};
filter_mode mode = FILTER_INCLUDE;
filter_scope scope = UNIVERSAL_FILTER;
std::string expression = {};
bool operator()(std::string_view _value) const;
template <typename ContainerT>
static bool satisfies_filter(const ContainerT&, filter_scope,
std::string_view) OMNITRACE_PURE;
};
template <typename ContainerT>
inline bool
scope_filter::satisfies_filter(const ContainerT& _filters, filter_scope _scope,
std::string_view _value)
{
for(const auto& itr : _filters) // NOLINT
{
// if the filter is for the specified scope and itr does not satisfy the
// include/exclude mode, return false
if((itr.scope & _scope) > 0 && !itr(_value)) return false;
}
return true;
}
} // namespace binary
} // namespace omnitrace
+370
Ver fichero
@@ -0,0 +1,370 @@
// 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 "core/config.hpp"
#include "core/debug.hpp"
#if !defined(TIMEMORY_USE_BFD)
# error "BFD support not enabled"
#endif
#define PACKAGE "omnitrace"
#define L_LNNO_SIZE 4
#include <bfd.h>
#include <coff/external.h>
#include <coff/internal.h>
#include <cstddef>
#include <cstdio>
#include <dwarf.h>
#include <elf-bfd.h>
#include <elfutils/libdw.h>
#include <libcoff.h>
#include "core/binary/fwd.hpp"
#include "core/timemory.hpp"
#include "core/utility.hpp"
#include "dwarf_entry.hpp"
#include "scope_filter.hpp"
#include "symbol.hpp"
#include <timemory/mpl/concepts.hpp>
namespace omnitrace
{
namespace binary
{
namespace
{
std::vector<inlined_symbol>
read_inliner_info(bfd* _inp)
{
auto _data = std::vector<inlined_symbol>{};
while(true)
{
const char* _file = nullptr;
const char* _func = nullptr;
unsigned int _line = 0;
if(bfd_find_inliner_info(_inp, &_file, &_func, &_line) != 0)
{
if(_file && _func && _line > 0)
_data.emplace_back(inlined_symbol{
_line, filepath::realpath(_file, nullptr, false), _func });
}
else
{
break;
}
}
return _data;
}
} // namespace
symbol::symbol(const base_type& _v)
: base_type{ _v }
, address{ _v.address, _v.address + _v.symsize }
{}
bool
symbol::operator==(const symbol& _rhs) const
{
return std::tie(address, base_type::name) ==
std::tie(_rhs.address, _rhs.base_type::name);
}
bool
symbol::operator<(const symbol& _rhs) const
{
return std::tie(address, base_type::binding, base_type::visibility, base_type::name) <
std::tie(_rhs.address, _rhs.base_type::binding, base_type::visibility,
base_type::name);
}
bool
symbol::operator()(const std::vector<scope_filter>& _filters) const
{
using sf = scope_filter;
// apply filters to the main symbol
return (sf::satisfies_filter(_filters, sf::FUNCTION_FILTER, demangle(func)) &&
(sf::satisfies_filter(_filters, sf::SOURCE_FILTER, file) ||
sf::satisfies_filter(_filters, sf::SOURCE_FILTER, join(':', file, line))));
}
symbol&
symbol::operator+=(const symbol& _rhs)
{
if(address.contiguous_with(_rhs.address) &&
std::tie(line, load_address, func, file) ==
std::tie(_rhs.line, _rhs.load_address, _rhs.func, _rhs.file))
{
address += _rhs.address;
utility::combine(inlines, _rhs.inlines);
utility::combine(dwarf_info, _rhs.dwarf_info);
}
else
{
throw exception<std::runtime_error>("incompatible symbol+=");
}
return *this;
}
symbol::operator bool() const
{
return address.is_valid() && (file.length() + func.length() + line) > 0;
}
size_t
symbol::read_dwarf_entries(const std::deque<dwarf_entry>& _info)
{
for(const auto& itr : _info)
{
if(address.contains(itr.address)) dwarf_info.emplace_back(itr);
}
// make sure the dwarf info is sorted by address (low to high)
std::sort(dwarf_info.begin(), dwarf_info.end(),
[](const dwarf_entry& _lhs, const dwarf_entry& _rhs) {
return _lhs.address < _rhs.address;
});
// helper for getting the end address
auto _get_next_address = [&](auto nitr, uintptr_t _low) {
while(++nitr != dwarf_info.end())
{
if(nitr->address.low > _low)
{
return nitr->address.low;
}
}
// return the end address of the symbol
return address.high;
};
// convert the single addresses into ranges
for(auto itr = dwarf_info.begin(); itr != dwarf_info.end(); ++itr)
{
// if address is already a range, do not update it
if(!itr->address.is_range())
itr->address = address_range{ itr->address.low,
_get_next_address(itr, itr->address.low) };
}
return dwarf_info.size();
}
size_t
symbol::read_dwarf_breakpoints(const std::vector<uintptr_t>& _bkpts)
{
for(const auto& itr : _bkpts)
{
if(address.contains(itr)) breakpoints.emplace_back(itr);
}
// make sure the breakpoints are sorted low to high
std::sort(breakpoints.begin(), breakpoints.end());
return breakpoints.size();
}
bool
symbol::read_bfd(bfd_file& _bfd)
{
auto* _section = static_cast<asection*>(section);
bfd_vma _vma = bfd_section_vma(_section);
bfd_size_type _size = bfd_section_size(_section);
auto& _pc = address.low;
auto& _pc_end = address.high;
if(_pc < _vma || _pc >= _vma + _size) return false;
// add one to vma + size because address range is exclusive of last address
if(_pc_end > _vma + _size) _pc_end = (_vma + _size);
auto* _inp = static_cast<bfd*>(_bfd.data);
auto* _syms = reinterpret_cast<asymbol**>(_bfd.syms);
{
const char* _file = nullptr;
const char* _func = nullptr;
unsigned int _line = 0;
unsigned int _discriminator = 0;
// if(bfd_find_nearest_line(_inp, _section, _syms, _pc - _vma, &_file,
// &_func, &_line) != 0)
if(bfd_find_nearest_line_discriminator(_inp, _section, _syms, _pc - _vma, &_file,
&_func, &_line, &_discriminator) != 0)
{
if(_file) file = _file;
if(_func) func = _func;
if(_file && strnlen(_file, 1) > 0)
file = _file;
else if(!_file || strnlen(_file, 1) == 0)
file = bfd_get_filename(_inp);
if(!func.empty())
{
file = filepath::realpath(file, nullptr, false);
line = _line;
inlines = read_inliner_info(_inp);
return true;
}
}
}
return false;
}
symbol
symbol::clone() const
{
auto _sym = symbol{ static_cast<base_type>(*this) };
_sym.line = line;
_sym.load_address = load_address;
_sym.address = address;
_sym.func = func;
_sym.file = file;
return _sym;
}
template <typename Tp>
Tp
symbol::get_inline_symbols(const std::vector<scope_filter>& _filters) const
{
using sf = scope_filter;
using value_type = typename Tp::value_type;
auto _data = Tp{};
for(const auto& itr : inlines)
{
if(sf::satisfies_filter(_filters, sf::FUNCTION_FILTER, demangle(itr.func)) &&
(sf::satisfies_filter(_filters, sf::SOURCE_FILTER, itr.file) ||
sf::satisfies_filter(_filters, sf::SOURCE_FILTER,
join(':', itr.file, itr.line))))
{
if constexpr(concepts::is_unqualified_same<value_type, symbol>::value)
{
auto _sym = clone();
_sym.func = itr.func;
_sym.line = itr.line;
_sym.file = itr.file;
_data.emplace_back(_sym);
}
else if constexpr(concepts::is_unqualified_same<value_type,
inlined_symbol>::value)
{
_data.emplace_back(itr);
}
}
}
return _data;
}
template <typename Tp>
Tp
symbol::get_debug_line_info(const std::vector<scope_filter>& _filters) const
{
using sf = scope_filter;
using value_type = typename Tp::value_type;
auto _data = Tp{};
if(sf::satisfies_filter(_filters, sf::FUNCTION_FILTER, demangle(func)))
{
for(const auto& itr : dwarf_info)
{
if(sf::satisfies_filter(_filters, sf::SOURCE_FILTER, itr.file) ||
sf::satisfies_filter(_filters, sf::SOURCE_FILTER,
join(':', itr.file, itr.line)))
{
if constexpr(concepts::is_unqualified_same<value_type, symbol>::value)
{
auto _sym = clone();
_sym.address = itr.address;
_sym.file = itr.file;
_sym.line = itr.line;
_data.emplace_back(_sym);
}
else if constexpr(concepts::is_unqualified_same<value_type,
dwarf_entry>::value)
{
_data.emplace_back(itr);
}
}
}
}
return _data;
}
template <typename ArchiveT>
void
inlined_symbol::serialize(ArchiveT& ar, const unsigned int)
{
using ::tim::cereal::make_nvp;
ar(make_nvp("func", func), make_nvp("file", file), make_nvp("line", line));
}
template <typename ArchiveT>
void
symbol::serialize(ArchiveT& ar, const unsigned int)
{
using ::tim::cereal::make_nvp;
ar(make_nvp("address", address), make_nvp("load_address", load_address),
make_nvp("line", line), make_nvp("func", func), make_nvp("file", file),
make_nvp("inlines", inlines), make_nvp("dwarf_info", dwarf_info));
if constexpr(concepts::is_output_archive<ArchiveT>::value)
ar(cereal::make_nvp("dfunc", demangle(func)));
}
template void
symbol::serialize<cereal::JSONInputArchive>(cereal::JSONInputArchive&,
const unsigned int);
template void
symbol::serialize<cereal::MinimalJSONOutputArchive>(cereal::MinimalJSONOutputArchive&,
const unsigned int);
template void
symbol::serialize<cereal::PrettyJSONOutputArchive>(cereal::PrettyJSONOutputArchive&,
const unsigned int);
template std::deque<symbol>
symbol::get_inline_symbols<std::deque<symbol>>(
const std::vector<scope_filter>& _filters) const;
template std::vector<inlined_symbol>
symbol::get_inline_symbols<std::vector<inlined_symbol>>(
const std::vector<scope_filter>& _filters) const;
template std::deque<symbol>
symbol::get_debug_line_info<std::deque<symbol>>(
const std::vector<scope_filter>& _filters) const;
template std::vector<dwarf_entry>
symbol::get_debug_line_info<std::vector<dwarf_entry>>(
const std::vector<scope_filter>& _filters) const;
} // namespace binary
} // namespace omnitrace
+98
Ver fichero
@@ -0,0 +1,98 @@
// 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.
#pragma once
#include "core/binary/address_range.hpp"
#include "core/binary/fwd.hpp"
#include <timemory/unwind/bfd.hpp>
#include <cstdint>
#include <deque>
#include <string_view>
#include <vector>
namespace omnitrace
{
namespace binary
{
struct inlined_symbol
{
unsigned int line = 0;
std::string file = {};
std::string func = {};
template <typename ArchiveT>
void serialize(ArchiveT&, const unsigned int);
};
struct symbol : private tim::unwind::bfd_file::symbol
{
using base_type = tim::unwind::bfd_file::symbol;
symbol() = default;
symbol(const base_type& _v);
~symbol() = default;
symbol(const symbol&) = default;
symbol(symbol&&) noexcept = default;
symbol& operator=(const symbol&) = default;
symbol& operator=(symbol&&) noexcept = default;
bool operator==(const symbol&) const;
bool operator<(const symbol&) const;
bool operator()(const std::vector<scope_filter>&) const;
symbol& operator+=(const symbol&);
explicit operator bool() const;
bool read_bfd(bfd_file&);
size_t read_dwarf_entries(const std::deque<dwarf_entry>&);
size_t read_dwarf_breakpoints(const std::vector<uintptr_t>&);
address_range ipaddr() const { return address + load_address; }
symbol clone() const;
template <typename Tp = std::deque<symbol>>
Tp get_inline_symbols(const std::vector<scope_filter>&) const;
template <typename Tp = std::deque<symbol>>
Tp get_debug_line_info(const std::vector<scope_filter>&) const;
template <typename ArchiveT>
void serialize(ArchiveT&, const unsigned int);
using base_type::binding;
using base_type::section;
using base_type::visibility;
unsigned int line = 0;
uintptr_t load_address = 0;
address_range address = {};
std::string func = {};
std::string file = {};
std::vector<uintptr_t> breakpoints = {};
std::vector<inlined_symbol> inlines = {};
std::vector<dwarf_entry> dwarf_info = {};
};
} // namespace binary
} // namespace omnitrace