fix omnitrace print-* with libraries (#94)

* fix omnitrace print-* with libraries

* timemory submodule update

* Update workflows to use ./bin/omnitrace instead of ./omnitrace

* cmake format

* update timemory submodule

- fix ODR violations in utility/procfs

* cmake updates

- uniform find_package for all ROCm-based libraries

* tweak transpose example

- throw exception instead of std::exit

* Inspect cmdv name before assuming not exe

- some ELF execs "think" they are libraries so only assume rewrite + simulate + all-functions if filename looks like library
- adds some test for --print-available -- <library>

* Fix _has_lib_prefix when command is < 3

* Updates and reverts to omnitrace exe

- update module_function operator< and operator==
- add function_signature operator<
- refactor module_function ctor
- revert some previous changes w.r.t. simulate and include_unninstr

* Fix source/bin/tests to use same output dir as tests

* cmake format

* Segfault mitigation + refactor + modify function iteration

- refactor module_function ctor to avoid segfaults
- string_t -> std::string
- replace std::string with std::string_view in some places
- get_name(module_t*)
- get_name(procedure_t*)
- disable using both app_modules and app_functions
- new option: --parse-all-modules to iterate over app_modules
- removed some unused code w.r.t. debug info

* Disable module_function address range for uninstrumentable functions

* Disable module_function address range for uninstrumentable functions

* Refactored getting file/line info and init/fini

- use dyninst insertInitCallback and insertFiniCallback if main not found
- fixed all issues with segmentation faults in --simulate --all-functions

* revert changes to Findrocprofiler.cmake
Tento commit je obsažen v:
Jonathan R. Madsen authored and GitHub committed 2022-07-21 01:15:41 -05:00
1 rodič 6bc86d1111
revize d04cbe862e
29 files changed
+781 -531

No files matched your search

+190 -190
Zobrazit soubor
@@ -24,6 +24,9 @@
#include "fwd.hpp"
#include "omnitrace.hpp"
#include <string>
#include <vector>
static int expect_error = NO_ERROR;
static int error_print = 0;
@@ -513,6 +516,49 @@ get_whole_function_names()
#endif
}
//======================================================================================//
//
// Helper functions because the syntax for getting a function or module name is unwieldy
//
std::string_view
get_name(procedure_t* _func)
{
static auto _v = std::unordered_map<procedure_t*, std::string>{};
auto itr = _v.find(_func);
if(itr == _v.end())
{
_v.emplace(_func, (_func) ? _func->getDemangledName() : std::string{});
}
return _v.at(_func);
}
std::string_view
get_name(module_t* _module)
{
static auto _v = std::unordered_map<module_t*, std::string>{};
auto itr = _v.find(_module);
if(itr == _v.end())
{
char _name[FUNCNAMELEN + 1];
memset(_name, '\0', FUNCNAMELEN + 1);
if(_module)
{
_module->getFullName(_name, FUNCNAMELEN);
_v.emplace(_module, std::string{ _name });
}
else
{
_v.emplace(nullptr, std::string{});
}
}
return _v.at(_module);
}
//======================================================================================//
//
// For selective instrumentation (unused)
@@ -523,6 +569,69 @@ are_file_include_exclude_lists_empty()
return true;
}
namespace
{
std::string
get_return_type(procedure_t* func)
{
if(func && func->isInstrumentable() && func->getReturnType())
return func->getReturnType()->getName();
return std::string{};
}
auto
get_parameter_types(procedure_t* func)
{
auto _param_names = std::vector<std::string>{};
if(func && func->isInstrumentable())
{
auto* _params = func->getParams();
if(_params)
{
_param_names.reserve(_params->size());
for(auto* itr : *_params)
{
std::string _name = itr->getType()->getName();
if(_name.empty()) _name = itr->getName();
_param_names.emplace_back(_name);
}
}
}
return _param_names;
}
} // namespace
//======================================================================================//
//
// We create a new name that embeds the file and line information in the name
//
function_signature
get_func_file_line_info(module_t* module, procedure_t* func)
{
using address_t = Dyninst::Address;
auto _file_name = get_name(module);
auto _func_name = get_name(func);
auto _return_type = get_return_type(func);
auto _param_types = get_parameter_types(func);
auto _base_addr = address_t{};
auto _last_addr = address_t{};
auto _src_lines = std::vector<statement_t>{};
if(func->getAddressRange(_base_addr, _last_addr) &&
module->getSourceLines(_base_addr, _src_lines) && !_src_lines.empty())
{
auto _row = _src_lines.front().lineNumber();
return function_signature(_return_type, _func_name, _file_name, _param_types,
{ _row, 0 }, { 0, 0 }, false, true, false);
}
else
{
return function_signature(_return_type, _func_name, _file_name, _param_types,
{ 0, 0 }, { 0, 0 }, false, false, false);
}
}
//======================================================================================//
//
// Gets information (line number, filename, and column number) about
@@ -532,173 +641,84 @@ function_signature
get_loop_file_line_info(module_t* module, procedure_t* func, flow_graph_t*,
basic_loop_t* loopToInstrument)
{
std::vector<BPatch_basicBlock*> basic_blocks{};
auto basic_blocks = std::vector<BPatch_basicBlock*>{};
loopToInstrument->getLoopBasicBlocksExclusive(basic_blocks);
if(basic_blocks.empty()) return function_signature{ "", "", "" };
auto base_addr = basic_blocks.front()->getStartAddress();
auto last_addr = basic_blocks.front()->getEndAddress();
basic_block_t* block = basic_blocks.front();
auto* _block = basic_blocks.front();
auto _base_addr = _block->getStartAddress();
auto _last_addr = _block->getEndAddress();
for(const auto& itr : basic_blocks)
{
if(itr == block) continue;
if(itr->dominates(block))
if(itr == _block) continue;
if(itr->dominates(_block))
{
base_addr = itr->getStartAddress();
last_addr = itr->getEndAddress();
block = itr;
_base_addr = itr->getStartAddress();
_last_addr = itr->getEndAddress();
_block = itr;
}
}
verbprintf(4, "Loop: size = %lu: base_addr = %lu, last_addr = %lu\n",
(unsigned long) (last_addr - base_addr), base_addr, last_addr);
auto _file_name = get_name(module);
auto _func_name = get_name(func);
auto _return_type = get_return_type(func);
auto _param_types = get_parameter_types(func);
auto _lines_beg = std::vector<statement_t>{};
auto _lines_end = std::vector<statement_t>{};
char fname[FUNCNAMELEN + 1];
char mname[FUNCNAMELEN + 1];
std::string typeName = {};
memset(fname, '\0', FUNCNAMELEN + 1);
memset(mname, '\0', FUNCNAMELEN + 1);
module->getFullName(mname, FUNCNAMELEN);
func->getName(fname, FUNCNAMELEN);
auto* returnType = func->getReturnType();
if(returnType) typeName = returnType->getName();
auto* params = func->getParams();
std::vector<string_t> _params;
if(params)
{
for(auto* itr : *params)
{
string_t _name = itr->getType()->getName();
if(_name.empty()) _name = itr->getName();
_params.push_back(_name);
}
}
bpvector_t<BPatch_statement> lines{};
bpvector_t<BPatch_statement> linesEnd{};
bool info1 = module->getSourceLines(base_addr, lines);
string_t filename = mname;
if(info1)
if(module->getSourceLines(_base_addr, _lines_beg))
{
// filename = lines[0].fileName();
int row1 = 0;
int col1 = 0;
for(auto& itr : lines)
int _row1 = 0;
int _col1 = 0;
for(auto& itr : _lines_beg)
{
if(itr.lineNumber() > 0)
{
row1 = itr.lineNumber();
col1 = itr.lineOffset();
_row1 = itr.lineNumber();
_col1 = itr.lineOffset();
break;
}
}
if(row1 == 0 && col1 == 0)
return function_signature(typeName, fname, filename, _params);
if(_row1 == 0 && _col1 == 0)
return function_signature(_return_type, _func_name, _file_name, _param_types);
int row2 = 0;
int col2 = 0;
for(auto& itr : lines)
int _row2 = 0;
int _col2 = 0;
for(auto& itr : _lines_beg)
{
row2 = std::max(row2, itr.lineNumber());
col2 = std::max(col2, itr.lineOffset());
_row2 = std::max(_row2, itr.lineNumber());
_col2 = std::max(_col2, itr.lineOffset());
}
if(col1 < 0) col1 = 0;
if(_col1 < 0) _col1 = 0;
bool info2 = module->getSourceLines(last_addr, linesEnd);
verbprintf(4, "size of linesEnd = %lu\n", (unsigned long) linesEnd.size());
if(info2)
if(module->getSourceLines(_last_addr, _lines_end))
{
for(auto& itr : linesEnd)
for(auto& itr : _lines_end)
{
row2 = std::max(row2, itr.lineNumber());
col2 = std::max(col2, itr.lineOffset());
_row2 = std::max(_row2, itr.lineNumber());
_col2 = std::max(_col2, itr.lineOffset());
}
if(col2 < 0) col2 = 0;
if(row2 < row1) row1 = row2; // Fix for wrong line numbers
if(_col2 < 0) _col2 = 0;
if(_row2 < _row1) _row1 = _row2; // Fix for wrong line numbers
return function_signature(typeName, fname, filename, _params, { row1, row2 },
{ col1, col2 }, true, info1, info2);
return function_signature(_return_type, _func_name, _file_name, _param_types,
{ _row1, _row2 }, { _col1, _col2 }, true, true,
true);
}
else
{
return function_signature(typeName, fname, filename, _params, { row1, 0 },
{ col1, 0 }, true, info1, info2);
return function_signature(_return_type, _func_name, _file_name, _param_types,
{ _row1, 0 }, { _col1, 0 }, true, true, false);
}
}
else
{
return function_signature(typeName, fname, filename, _params, { 0, 0 }, { 0, 0 },
true, false, false);
}
}
//======================================================================================//
//
// We create a new name that embeds the file and line information in the name
//
function_signature
get_func_file_line_info(module_t* module, procedure_t* func)
{
using address_t = Dyninst::Address;
char fname[FUNCNAMELEN + 1];
char mname[FUNCNAMELEN + 1];
string_t typeName = {};
memset(fname, '\0', FUNCNAMELEN + 1);
memset(mname, '\0', FUNCNAMELEN + 1);
module->getFullName(mname, FUNCNAMELEN);
func->getName(fname, FUNCNAMELEN);
address_t base_addr{};
address_t last_addr{};
func->getAddressRange(base_addr, last_addr);
auto* returnType = func->getReturnType();
if(returnType) typeName = returnType->getName();
auto* params = func->getParams();
std::vector<string_t> _params = {};
if(params)
{
_params.reserve(params->size());
for(auto* itr : *params)
{
string_t _name = itr->getType()->getName();
if(_name.empty()) _name = itr->getName();
_params.emplace_back(_name);
}
}
bpvector_t<BPatch_statement> lines = {};
bool info = module->getSourceLines(base_addr, lines);
string_t filename = mname;
if(info && !lines.empty())
{
auto row = lines.front().lineNumber();
return function_signature(typeName, fname, filename, _params, { row, 0 },
{ 0, 0 }, false, info, false);
}
else
{
return function_signature(typeName, fname, filename, _params, { 0, 0 }, { 0, 0 },
false, false, false);
return function_signature(_return_type, _func_name, _file_name, _param_types,
{ 0, 0 }, { 0, 0 }, true, false, false);
}
}
@@ -713,89 +733,69 @@ get_basic_block_file_line_info(module_t* module, procedure_t* func)
std::map<basic_block_t*, basic_block_signature> _data{};
if(!func) return _data;
auto* _cfg = func->getCFG();
std::set<BPatch_basicBlock*> _basic_blocks{};
auto* _cfg = func->getCFG();
auto _basic_blocks = std::set<BPatch_basicBlock*>{};
_cfg->getAllBasicBlocks(_basic_blocks);
if(_basic_blocks.empty()) return _data;
char fname[FUNCNAMELEN + 1];
char mname[FUNCNAMELEN + 1];
std::string typeName = {};
memset(fname, '\0', FUNCNAMELEN + 1);
memset(mname, '\0', FUNCNAMELEN + 1);
module->getFullName(mname, FUNCNAMELEN);
func->getName(fname, FUNCNAMELEN);
auto* returnType = func->getReturnType();
if(returnType) typeName = returnType->getName();
auto* params = func->getParams();
std::vector<string_t> _params;
if(params)
{
for(auto* itr : *params)
{
string_t _name = itr->getType()->getName();
if(_name.empty()) _name = itr->getName();
_params.push_back(_name);
}
}
auto _file_name = get_name(module);
auto _func_name = get_name(func);
auto _return_type = get_return_type(func);
auto _param_types = get_parameter_types(func);
for(auto&& itr : _basic_blocks)
{
auto base_addr = itr->getStartAddress();
auto last_addr = itr->getEndAddress();
auto _base_addr = itr->getStartAddress();
auto _last_addr = itr->getEndAddress();
verbprintf(4, "BB: size = %lu: base_addr = %lu, last_addr = %lu\n",
(unsigned long) (last_addr - base_addr), base_addr, last_addr);
verbprintf(4,
"[%s][%s] basic_block: size = %lu: base_addr = %lu, last_addr = %lu\n",
_file_name.data(), _func_name.data(),
(unsigned long) (_last_addr - _base_addr), _base_addr, _last_addr);
bpvector_t<BPatch_statement> linesBeg{};
bpvector_t<BPatch_statement> linesEnd{};
auto _lines_beg = std::vector<statement_t>{};
auto _lines_end = std::vector<statement_t>{};
string_t filename = mname;
if(module->getSourceLines(base_addr, linesBeg) && !linesBeg.empty())
if(module->getSourceLines(_base_addr, _lines_beg) && !_lines_beg.empty())
{
int row1 = linesBeg.front().lineNumber();
int col1 = linesBeg.front().lineOffset();
int _row1 = _lines_beg.front().lineNumber();
int _col1 = _lines_beg.front().lineOffset();
verbprintf(4, "size of linesEnd = %lu\n", (unsigned long) linesEnd.size());
verbprintf(4, "size of _lines_end = %lu\n",
(unsigned long) _lines_end.size());
if(module->getSourceLines(last_addr, linesEnd) && !linesEnd.empty())
if(module->getSourceLines(_last_addr, _lines_end) && !_lines_end.empty())
{
int row2 = linesEnd.back().lineNumber();
int col2 = linesEnd.back().lineOffset();
int _row2 = _lines_end.back().lineNumber();
int _col2 = _lines_end.back().lineOffset();
if(row2 < row1) std::swap(row1, row2);
if(row1 == row2 && col2 < col1) std::swap(col1, col2);
if(_row2 < _row1) std::swap(_row1, _row2);
if(_row1 == _row2 && _col2 < _col1) std::swap(_col1, _col2);
_data.emplace(itr,
basic_block_signature{
base_addr, last_addr,
function_signature(typeName, fname, filename, _params,
{ row1, row2 }, { col1, col2 }, true,
true, true) });
_data.emplace(
itr, basic_block_signature{
_base_addr, _last_addr,
function_signature(_return_type, _func_name, _file_name,
_param_types, { _row1, _row2 },
{ _col1, _col2 }, true, true, true) });
}
else
{
_data.emplace(itr,
basic_block_signature{
base_addr, last_addr,
function_signature(typeName, fname, filename, _params,
{ row1, 0 }, { col1, 0 }, true, true,
false) });
_base_addr, _last_addr,
function_signature(_return_type, _func_name, _file_name,
_param_types, { _row1, 0 },
{ _col1, 0 }, true, true, false) });
}
}
else
{
_data.emplace(itr,
basic_block_signature{
base_addr, last_addr,
function_signature(typeName, fname, filename, _params) });
_data.emplace(itr, basic_block_signature{
_base_addr, _last_addr,
function_signature(_return_type, _func_name,
_file_name, _param_types) });
}
}
@@ -861,7 +861,7 @@ find_function(image_t* app_image, const std::string& _name, const strset_t& _ext
{
if(_name.empty()) return nullptr;
auto _find = [app_image](const string_t& _f) -> procedure_t* {
auto _find = [app_image](const std::string& _f) -> procedure_t* {
// Extract the vector of functions
bpvector_t<procedure_t*> _found;
auto* ret = app_image->findFunction(_f.c_str(), _found, false, true, true);