Files
rocm-systems/source/bin/omnitrace/omnitrace.hpp
T

361 lines
11 KiB
C++
Raw Normal View History

2022-01-26 23:25:00 -06:00
// MIT License
//
// Copyright (c) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
2021-08-06 13:08:57 -05:00
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
2022-01-26 23:25:00 -06:00
// 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
2021-08-06 13:08:57 -05:00
// furnished to do so, subject to the following conditions:
//
2022-01-26 23:25:00 -06:00
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
2021-08-06 13:08:57 -05:00
//
// 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
2022-01-26 23:25:00 -06:00
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2021-08-06 13:08:57 -05:00
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2022-01-26 23:25:00 -06:00
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
2021-08-06 13:08:57 -05:00
#pragma once
2022-03-07 20:40:48 -06:00
#include "function_signature.hpp"
#include "fwd.hpp"
#include "info.hpp"
#include "module_function.hpp"
2021-08-06 13:08:57 -05:00
//======================================================================================//
inline string_t
get_absolute_path(const char* fname)
{
char path_save[PATH_MAX];
char abs_exe_path[PATH_MAX];
char* p = nullptr;
if(!(p = strrchr((char*) fname, '/')))
{
auto* ret = getcwd(abs_exe_path, sizeof(abs_exe_path));
2021-08-06 13:08:57 -05:00
consume_parameters(ret);
}
else
{
auto* rets = getcwd(path_save, sizeof(path_save));
auto retf = chdir(fname);
auto* reta = getcwd(abs_exe_path, sizeof(abs_exe_path));
auto retp = chdir(path_save);
2021-08-06 13:08:57 -05:00
consume_parameters(rets, retf, reta, retp);
}
return string_t(abs_exe_path);
}
//======================================================================================//
inline string_t
to_lower(string_t s)
{
for(auto& itr : s)
itr = tolower(itr);
return s;
}
//
//======================================================================================//
//
template <typename Tp, std::enable_if_t<!std::is_same<Tp, std::string>::value, int> = 0>
2021-08-06 13:08:57 -05:00
snippet_pointer_t
get_snippet(Tp arg)
{
return std::make_shared<snippet_t>(const_expr_t{ arg });
2021-08-06 13:08:57 -05:00
}
//
//======================================================================================//
//
template <typename Tp, std::enable_if_t<std::is_same<Tp, std::string>::value, int> = 0>
snippet_pointer_t
get_snippet(const Tp& arg)
2021-08-06 13:08:57 -05:00
{
return std::make_shared<snippet_t>(const_expr_t{ arg.c_str() });
2021-08-06 13:08:57 -05:00
}
//
//======================================================================================//
//
template <typename... Args>
snippet_pointer_vec_t
get_snippets(Args&&... args)
{
snippet_pointer_vec_t _tmp{};
2021-08-06 13:08:57 -05:00
TIMEMORY_FOLD_EXPRESSION(_tmp.push_back(get_snippet(std::forward<Args>(args))));
return _tmp;
}
//
//======================================================================================//
//
2021-11-24 04:59:59 -06:00
struct omnitrace_call_expr
2021-08-06 13:08:57 -05:00
{
using snippet_pointer_t = std::shared_ptr<snippet_t>;
template <typename... Args>
2021-11-24 04:59:59 -06:00
omnitrace_call_expr(Args&&... args)
2021-08-06 13:08:57 -05:00
: m_params(get_snippets(std::forward<Args>(args)...))
{}
snippet_vec_t get_params()
{
snippet_vec_t _ret;
for(auto& itr : m_params)
_ret.push_back(itr.get());
return _ret;
}
inline call_expr_pointer_t get(procedure_t* func)
{
return call_expr_pointer_t((func) ? new call_expr_t(*func, get_params())
: nullptr);
}
private:
snippet_pointer_vec_t m_params;
};
//
//======================================================================================//
//
2021-11-24 04:59:59 -06:00
struct omnitrace_snippet_vec
2021-08-06 13:08:57 -05:00
{
2021-11-24 04:59:59 -06:00
using entry_type = std::vector<omnitrace_call_expr>;
2021-08-06 13:08:57 -05:00
using value_type = std::vector<call_expr_pointer_t>;
template <typename... Args>
void generate(procedure_t* func, Args&&... args)
{
2021-11-24 04:59:59 -06:00
auto _expr = omnitrace_call_expr(std::forward<Args>(args)...);
2021-08-06 13:08:57 -05:00
auto _call = _expr.get(func);
if(_call)
{
m_entries.push_back(_expr);
m_data.push_back(_call);
// m_data.push_back(entry_type{ _call, _expr });
}
}
void append(snippet_vec_t& _obj)
{
for(auto& itr : m_data)
_obj.push_back(itr.get());
}
private:
entry_type m_entries;
value_type m_data;
};
//
//======================================================================================//
//
static inline address_space_t*
omnitrace_get_address_space(patch_pointer_t& _bpatch, int _cmdc, char** _cmdv,
bool _rewrite, int _pid = -1, const string_t& _name = {})
2021-08-06 13:08:57 -05:00
{
address_space_t* mutatee = nullptr;
if(_rewrite)
{
verbprintf(1, "Opening '%s' for binary rewrite... ", _name.c_str());
fflush(stderr);
2021-09-20 11:12:06 -05:00
if(!_name.empty()) mutatee = _bpatch->openBinary(_name.c_str(), false);
2021-08-06 13:08:57 -05:00
if(!mutatee)
{
fprintf(stderr, "[omnitrace][exe] Failed to open binary '%s'\n",
_name.c_str());
2021-08-06 13:08:57 -05:00
throw std::runtime_error("Failed to open binary");
}
2022-02-08 17:42:17 -06:00
verbprintf_bare(1, "Done\n");
2021-08-06 13:08:57 -05:00
}
else if(_pid >= 0)
{
verbprintf(1, "Attaching to process %i... ", _pid);
fflush(stderr);
char* _cmdv0 = (_cmdc > 0) ? _cmdv[0] : nullptr;
mutatee = _bpatch->processAttach(_cmdv0, _pid);
if(!mutatee)
{
fprintf(stderr, "[omnitrace][exe] Failed to connect to process %i\n",
(int) _pid);
2021-08-06 13:08:57 -05:00
throw std::runtime_error("Failed to attach to process");
}
2022-02-08 17:42:17 -06:00
verbprintf_bare(1, "Done\n");
2021-08-06 13:08:57 -05:00
}
else
{
verbprintf(1, "Creating process '%s'... ", _cmdv[0]);
fflush(stderr);
mutatee = _bpatch->processCreate(_cmdv[0], (const char**) _cmdv, nullptr);
if(!mutatee)
{
std::stringstream ss;
for(int i = 0; i < _cmdc; ++i)
{
2021-09-20 11:12:06 -05:00
if(!_cmdv[i]) continue;
2021-08-06 13:08:57 -05:00
ss << _cmdv[i] << " ";
}
fprintf(stderr, "[omnitrace][exe] Failed to create process: '%s'\n",
2021-08-06 13:08:57 -05:00
ss.str().c_str());
throw std::runtime_error("Failed to create process");
}
2022-02-08 17:42:17 -06:00
verbprintf_bare(1, "Done\n");
2021-08-06 13:08:57 -05:00
}
return mutatee;
}
//
//======================================================================================//
//
TIMEMORY_NOINLINE inline void
2021-11-24 04:59:59 -06:00
omnitrace_thread_exit(thread_t* thread, BPatch_exitType exit_type)
2021-08-06 13:08:57 -05:00
{
2021-09-20 11:12:06 -05:00
if(!thread) return;
2021-08-06 13:08:57 -05:00
BPatch_process* app = thread->getProcess();
if(!terminate_expr)
{
fprintf(stderr, "[omnitrace][exe] continuing execution\n");
2021-08-06 13:08:57 -05:00
app->continueExecution();
return;
}
switch(exit_type)
{
2021-09-20 11:12:06 -05:00
case ExitedNormally:
{
fprintf(stderr, "[omnitrace][exe] Thread exited normally\n");
2021-08-06 13:08:57 -05:00
break;
}
2021-09-20 11:12:06 -05:00
case ExitedViaSignal:
{
fprintf(stderr, "[omnitrace][exe] Thread terminated unexpectedly\n");
2021-08-06 13:08:57 -05:00
break;
}
case NoExit:
2021-09-20 11:12:06 -05:00
default:
{
fprintf(stderr, "[omnitrace][exe] %s invoked with NoExit\n", __FUNCTION__);
2021-08-06 13:08:57 -05:00
break;
}
}
// terminate_expr = nullptr;
thread->oneTimeCode(*terminate_expr);
fprintf(stderr, "[omnitrace][exe] continuing execution\n");
2021-08-06 13:08:57 -05:00
app->continueExecution();
}
//
//======================================================================================//
//
TIMEMORY_NOINLINE inline void
2021-11-24 04:59:59 -06:00
omnitrace_fork_callback(thread_t* parent, thread_t* child)
2021-08-06 13:08:57 -05:00
{
if(child)
{
auto* app = child->getProcess();
if(app)
{
verbprintf(4, "Stopping execution and detaching child fork...\n");
app->stopExecution();
app->detach(true);
// app->terminateExecution();
// app->continueExecution();
}
}
if(parent)
{
auto* app = parent->getProcess();
2021-08-06 13:08:57 -05:00
if(app)
{
verbprintf(4, "Continuing execution on parent after fork callback...\n");
app->continueExecution();
}
}
}
//
//======================================================================================//
2022-03-07 20:40:48 -06:00
// insert_instr -- generic insert instrumentation function
2021-08-06 13:08:57 -05:00
//
2022-03-07 20:40:48 -06:00
template <typename Tp>
bool
insert_instr(address_space_t* mutatee, procedure_t* funcToInstr, Tp traceFunc,
procedure_loc_t traceLoc, flow_graph_t* cfGraph,
basic_loop_t* loopToInstrument, bool allow_traps)
{
module_t* module = funcToInstr->getModule();
if(!module || !traceFunc) return false;
bpvector_t<point_t*>* _points = nullptr;
auto _trace = traceFunc.get();
if(cfGraph && loopToInstrument)
{
if(traceLoc == BPatch_entry)
_points = cfGraph->findLoopInstPoints(BPatch_locLoopEntry, loopToInstrument);
else if(traceLoc == BPatch_exit)
_points = cfGraph->findLoopInstPoints(BPatch_locLoopExit, loopToInstrument);
}
else
{
_points = funcToInstr->findPoint(traceLoc);
}
if(_points == nullptr) return false;
if(_points->empty()) return false;
/*if(loop_level_instr)
{
flow_graph_t* flow = funcToInstr->getCFG();
bpvector_t<basic_loop_t*> basicLoop;
flow->getOuterLoops(basicLoop);
for(auto litr = basicLoop.begin(); litr != basicLoop.end(); ++litr)
{
bpvector_t<point_t*>* _tmp;
if(traceLoc == BPatch_entry)
_tmp = cfGraph->findLoopInstPoints(BPatch_locLoopEntry, *litr);
else if(traceLoc == BPatch_exit)
_tmp = cfGraph->findLoopInstPoints(BPatch_locLoopExit, *litr);
if(!_tmp)
continue;
for(auto& itr : *_tmp)
_points->push_back(itr);
}
}*/
// verbprintf(0, "Instrumenting |> [ %s ]\n", name.m_name.c_str());
std::set<point_t*> _traps{};
if(!allow_traps)
{
for(auto& itr : *_points)
{
if(itr && itr->usesTrap_NP()) _traps.insert(itr);
}
}
size_t _n = 0;
for(auto& itr : *_points)
{
if(!itr || _traps.count(itr) > 0)
continue;
else if(traceLoc == BPatch_entry)
mutatee->insertSnippet(*_trace, *itr, BPatch_callBefore, BPatch_firstSnippet);
// else if(traceLoc == BPatch_exit)
// mutatee->insertSnippet(*_trace, *itr, BPatch_callAfter,
// BPatch_firstSnippet);
else
mutatee->insertSnippet(*_trace, *itr);
++_n;
}
return (_n > 0);
}