Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

add code coverage host functions #10933

Open
wants to merge 35 commits into
base: develop-boxed
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7021484
add code coverage host functions
praphael Dec 6, 2021
9cbe513
code coverage now protocol feature instead of genesis
praphael Dec 7, 2021
1c67d03
add coverage_get_XXX() and coverage_reset() host functions
praphael Dec 7, 2021
f7d3423
correct intrinsic name
praphael Dec 7, 2021
2de3068
Revert "correct intrinsic name"
praphael Dec 8, 2021
4b5a68d
Revert "add coverage_get_XXX() and coverage_reset() host functions"
praphael Dec 8, 2021
57ca0e9
Revert "code coverage now protocol feature instead of genesis"
praphael Dec 8, 2021
73acc24
Revert "add code coverage host functions"
praphael Dec 8, 2021
74afa6f
add coverage intrinsics to eosio-tester
praphael Dec 8, 2021
9a05ec3
fix validation-reflect test failures, add param to covergae dump
praphael Dec 8, 2021
4a31d3b
rodeos coverage callbacks
praphael Dec 9, 2021
56e9f2f
add coverage intrinisic to eos-vm-oc
praphael Dec 9, 2021
ad65b38
whitelist tester intrinsics
praphael Dec 10, 2021
7e6b809
back to host function (verified working, generate coverage report)
praphael Dec 11, 2021
24ba301
missed changes from prior checkin
praphael Dec 14, 2021
c078fac
move rodoes coverage state to global
praphael Jan 4, 2022
033d0df
update programs/eosio-tester/main.cpp
praphael Jan 11, 2022
25c6b14
Refactor code coverage host functions to remove need for protocol fea…
heifner Jan 17, 2022
931775a
rm unused file
heifner Jan 17, 2022
e7ce00d
Additional cleanup
heifner Jan 17, 2022
1190d85
whitespace cleanup
heifner Jan 17, 2022
7d143da
Fix oc build
heifner Jan 18, 2022
52fe79e
Add missing returns
heifner Jan 21, 2022
475bc5a
Add missing returns
heifner Jan 25, 2022
443b964
new function coverage_dump_funcnt replaces coverage_dump
praphael Feb 2, 2022
9b75c43
separate coverage maps for chain/rodeos
praphael Feb 3, 2022
13a4795
reduce new coverage host functions to two
praphael Feb 3, 2022
c5d2347
Merge branch 'develop-boxed' of https://github.com/EOSIO/eos into pdr…
praphael Feb 4, 2022
7cd129d
remove improper semicolon in libraries/rodeos/include/eosio/coverage.hpp
praphael Feb 4, 2022
8308aa1
fix eosio-tester/main.cpp return paths
praphael Feb 4, 2022
2e3d942
address PR feedback
praphael Feb 7, 2022
ad98dff
address PR feedback
praphael Feb 7, 2022
284f478
address PR feedback
praphael Feb 7, 2022
60b8601
use static_cast to fix compile errors
praphael Feb 7, 2022
44720fd
Merge branch 'develop-boxed' of https://github.com/EOSIO/eos into pdr…
praphael Feb 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <eosio/chain/block_log_config.hpp>
#include <eosio/chain/backing_store.hpp>

struct test_chain;
namespace chainbase {
class database;
}
Expand Down Expand Up @@ -398,6 +399,7 @@ namespace eosio { namespace chain {
private:
friend class apply_context;
friend class transaction_context;
friend struct ::test_chain;
friend std::unique_ptr<kv_context> db_util::create_kv_context(const controller&, name,const kv_resource_manager&, const kv_database_config&);

chainbase::database& mutable_db()const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,9 @@ constexpr auto intrinsic_table = boost::hana::make_tuple(
"env.push_data"_s,
"env.print_time_us"_s,
"env.get_input_data"_s,
"env.set_output_data"_s
"env.set_output_data"_s,
"env.coverage_getinc"_s,
"env.coverage_dump"_s
);

}}}
4 changes: 4 additions & 0 deletions libraries/chain/include/eosio/chain/webassembly/interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1897,6 +1897,10 @@ namespace eosio { namespace chain { namespace webassembly {
int32_t __lttf2(uint64_t, uint64_t, uint64_t, uint64_t) const;
int32_t __unordtf2(uint64_t, uint64_t, uint64_t, uint64_t) const;

// code coverage support functions
uint32_t coverage_getinc(uint64_t code, uint32_t file_num, uint32_t func_or_line_num, uint32_t mode, bool inc);
uint64_t coverage_dump(uint64_t code, uint32_t file_num, span<const char> file_name, uint32_t max, bool append, uint32_t mode, bool reset);

private:
apply_context& context;
};
Expand Down
15 changes: 15 additions & 0 deletions libraries/chain/include/eosio/chain/webassembly/preconditions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
#include <eosio/chain/types.hpp>
#include <eosio/chain/webassembly/common.hpp>
#include <eosio/chain/webassembly/eos-vm.hpp>
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
#include <eosio/chain/webassembly/eos-vm-oc.hpp>
#endif

#include <eosio/vm/backend.hpp>
#include <eosio/vm/host_function.hpp>
Expand Down Expand Up @@ -167,4 +170,16 @@ namespace eosio { namespace chain { namespace webassembly {
static_assert( are_whitelisted_legacy_types_v<std::decay_t<decltype(args)>...>, "legacy whitelisted type violation");
}));

template <auto HostFunction, typename... Preconditions>
struct host_function_registrator {
template <typename Mod, typename Name>
constexpr host_function_registrator(Mod mod_name, Name fn_name) {
using rhf_t = eos_vm_host_functions_t;
rhf_t::add<HostFunction, Preconditions...>(mod_name.c_str(), fn_name.c_str());
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
eosvmoc::register_eosvm_oc<HostFunction, std::tuple<Preconditions...>>(mod_name + BOOST_HANA_STRING(".") + fn_name);
#endif
}
};

}}} // ns eosio::chain::webassembly
16 changes: 0 additions & 16 deletions libraries/chain/webassembly/runtimes/eos-vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
//eos-vm includes
#include <eosio/vm/backend.hpp>
#include <eosio/chain/webassembly/preconditions.hpp>
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
#include <eosio/chain/webassembly/eos-vm-oc.hpp>
#endif
#include <boost/hana/string.hpp>
#include <boost/hana/equal.hpp>

namespace eosio { namespace chain { namespace webassembly { namespace eos_vm_runtime {

Expand Down Expand Up @@ -289,18 +285,6 @@ std::unique_ptr<wasm_instantiated_module_interface> eos_vm_profile_runtime::inst

}

template <auto HostFunction, typename... Preconditions>
struct host_function_registrator {
template <typename Mod, typename Name>
constexpr host_function_registrator(Mod mod_name, Name fn_name) {
using rhf_t = eos_vm_host_functions_t;
rhf_t::add<HostFunction, Preconditions...>(mod_name.c_str(), fn_name.c_str());
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
eosvmoc::register_eosvm_oc<HostFunction, std::tuple<Preconditions...>>(mod_name + BOOST_HANA_STRING(".") + fn_name);
#endif
}
};

#define REGISTER_HOST_FUNCTION(NAME, ...) \
static host_function_registrator<&interface::NAME, core_precondition, context_aware_check, ##__VA_ARGS__> \
NAME##_registrator_impl() { \
Expand Down
63 changes: 63 additions & 0 deletions libraries/rodeos/include/b1/rodeos/callbacks/coverage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once

#include <b1/rodeos/callbacks/vm_types.hpp>
#include <eosio/coverage.hpp>

namespace b1::rodeos {

using eosio::coverage::coverage_maps;
using eosio::coverage::coverage_mode;

constexpr auto rodeos_n = eosio::name{"rodeos"}.value;

struct coverage_state {
};

template <typename Derived>
struct coverage_callbacks {
Derived& derived() { return static_cast<Derived&>(*this); }

uint32_t coverage_getinc(uint64_t code, uint32_t file_num, uint32_t func_or_line_num, uint32_t mode, bool inc) {
auto cov_mode = static_cast<coverage_mode>(mode);
if(inc) {
if (cov_mode == coverage_mode::func) {
eosio::coverage::coverage_inc_cnt(code, file_num, func_or_line_num, coverage_maps<rodeos_n>::instance().funcnt_map);
} else if (cov_mode == coverage_mode::line) {
eosio::coverage::coverage_inc_cnt(code, file_num, func_or_line_num, coverage_maps<rodeos_n>::instance().linecnt_map);
}
}
else {
if (cov_mode == coverage_mode::func) {
return eosio::coverage::coverage_get_cnt(code, file_num, func_or_line_num, coverage_maps<rodeos_n>::instance().funcnt_map);
}
else if (cov_mode == coverage_mode::line) {
return eosio::coverage::coverage_get_cnt(code, file_num, func_or_line_num, coverage_maps<rodeos_n>::instance().linecnt_map);
}
}
return 0;
}

uint64_t coverage_dump(uint64_t code, uint32_t file_num, eosio::vm::span<const char> file_name, uint32_t max, bool append, uint32_t mode, bool reset) {
auto cov_mode = static_cast<coverage_mode>(mode);
if (reset) {
coverage_maps<rodeos_n>::instance().funcnt_map.clear();
coverage_maps<rodeos_n>::instance().linecnt_map.clear();
}
else if (cov_mode == coverage_mode::func) {
return eosio::coverage::coverage_dump(code, file_num, file_name.data(), file_name.size(), max, append, coverage_maps<rodeos_n>::instance().funcnt_map);
}
else if (cov_mode == coverage_mode::line) {
return eosio::coverage::coverage_dump(code, file_num, file_name.data(), file_name.size(), max, append, coverage_maps<rodeos_n>::instance().linecnt_map);
}
return 0;
}

template <typename Rft>
static void register_callbacks() {
// todo: preconditions
RODEOS_REGISTER_CALLBACK(Rft, Derived, coverage_getinc);
RODEOS_REGISTER_CALLBACK(Rft, Derived, coverage_dump);
}
}; // coverage_callbacks

} // namespace b1::rodeos
12 changes: 9 additions & 3 deletions libraries/rodeos/include/b1/rodeos/filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <b1/rodeos/callbacks/system.hpp>
#include <b1/rodeos/callbacks/unimplemented.hpp>
#include <b1/rodeos/callbacks/unimplemented_filter.hpp>
#include <b1/rodeos/callbacks/coverage.hpp>
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
# include <eosio/chain/webassembly/eos-vm-oc/code_cache.hpp>
# include <eosio/chain/webassembly/eos-vm-oc/executor.hpp>
Expand Down Expand Up @@ -65,19 +66,23 @@ struct callbacks : b1::rodeos::chaindb_callbacks<callbacks>,
b1::rodeos::filter_callbacks<callbacks>,
b1::rodeos::memory_callbacks<callbacks>,
b1::rodeos::unimplemented_callbacks<callbacks>,
b1::rodeos::system_callbacks<callbacks> {
b1::rodeos::system_callbacks<callbacks>,
b1::rodeos::coverage_callbacks<callbacks> {
filter::filter_state& filter_state;
b1::rodeos::chaindb_state& chaindb_state;
b1::rodeos::db_view_state& db_view_state;
b1::rodeos::coverage_state& coverage_state;

callbacks(filter::filter_state& filter_state, b1::rodeos::chaindb_state& chaindb_state,
b1::rodeos::db_view_state& db_view_state)
: filter_state{ filter_state }, chaindb_state{ chaindb_state }, db_view_state{ db_view_state } {}
b1::rodeos::db_view_state& db_view_state, b1::rodeos::coverage_state& coverage_state)
: filter_state{ filter_state }, chaindb_state{ chaindb_state }, db_view_state{ db_view_state }
, coverage_state{ coverage_state } {}

auto& get_state() { return filter_state; }
auto& get_filter_callback_state() { return filter_state; }
auto& get_chaindb_state() { return chaindb_state; }
auto& get_db_view_state() { return db_view_state; }
auto& get_coverage_state() { return coverage_state; }
};

inline void register_callbacks() {
Expand All @@ -92,6 +97,7 @@ inline void register_callbacks() {
b1::rodeos::memory_callbacks<callbacks>::register_callbacks<rhf_t>();
b1::rodeos::system_callbacks<callbacks>::register_callbacks<rhf_t>();
b1::rodeos::unimplemented_callbacks<callbacks>::register_callbacks<rhf_t>();
b1::rodeos::coverage_callbacks<callbacks>::register_callbacks<rhf_t>();
}

} // namespace b1::rodeos::filter
110 changes: 110 additions & 0 deletions libraries/rodeos/include/eosio/coverage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#pragma once

#include <eosio/chain/name.hpp>
#include <unordered_map>
#include <string>
#include <fstream>

using cov_map_t = std::unordered_map<uint64_t, std::unordered_map<uint32_t, std::unordered_map<uint32_t, uint32_t> > >;

// rodeos lib is not the ideal location for this as it is also used by eosio-tester but rodeos lib keeps it out of nodeos
namespace eosio {
namespace coverage {

template<uint64_t Unique>
class coverage_maps {
public:
static coverage_maps& instance() {
static coverage_maps instance;
return instance;
}
coverage_maps(const coverage_maps&) = delete;
void operator=(const coverage_maps&) = delete;

cov_map_t funcnt_map;
cov_map_t linecnt_map;
private:
coverage_maps() = default;
};
heifner marked this conversation as resolved.
Show resolved Hide resolved

enum class coverage_mode : uint32_t {
func=0,
line=1
};

inline void coverage_inc_cnt( uint64_t code, uint32_t file_num, uint32_t func_or_line_num, cov_map_t& cov_map) {
auto& code_map = cov_map[code];
auto& cnt_map = code_map[file_num];
cnt_map[func_or_line_num]++;
}

inline uint32_t coverage_get_cnt( uint64_t code, uint32_t file_num, uint32_t func_or_line_num, cov_map_t& cov_map) {
auto& code_map = cov_map[code];
auto& cnt_map = code_map[file_num];
return cnt_map[func_or_line_num];
}

// dump coverage output (function or line) to binary file
// if code == 0, begin at first code in the map
// max is only checked for every code, so it is possible to exceed the number
// if max == 0, then only dump coverage for specific code and specific file_num
// in theis case code must be > 0
// returns the next code, or 0 if at end
inline uint64_t coverage_dump(uint64_t code, uint32_t file_num, const char* file_name, uint32_t file_name_size, uint32_t max, bool append, cov_map_t& cov_map) {
std::ofstream out_bin_file;
auto flags = std::ofstream::out | std::ofstream::binary;
if (append)
flags = flags | std::ofstream::app;
else
flags = flags | std::ofstream::trunc;

ilog("coverage_dump_funcnt: file_name= ${f} max= ${max} ${app}", ("f", file_name)("nax", max)("app", append));
out_bin_file.open(file_name, flags );
uint32_t i = 0;
auto code_itr = cov_map.begin();
if (max == 0 && code == 0) {
elog("coverage_dump_funcnt: when max == 0, code must be > 0");
return 0;
}
if (code > 0) {
code_itr = cov_map.find(code);
}
while (code_itr != cov_map.end() && (max == 0 || i < max)) {
auto codenum = code_itr->first;
auto& filenum_map = code_itr->second;
auto filenum_itr = filenum_map.begin();
if (max == 0) {
filenum_itr = filenum_map.find(file_num);
}
while (filenum_itr != filenum_map.end()) {
auto filenum = filenum_itr->first;
auto& funcnum_map = filenum_itr->second;
for (const auto& funcnum_itr : funcnum_map) {
auto func_or_line_num = funcnum_itr.first;
auto calls = funcnum_itr.second;
out_bin_file.write(reinterpret_cast<const char*>(&codenum), sizeof(code));
out_bin_file.write(reinterpret_cast<const char*>(&filenum), sizeof(filenum));
out_bin_file.write(reinterpret_cast<const char*>(&func_or_line_num), sizeof(func_or_line_num));
out_bin_file.write(reinterpret_cast<const char*>(&calls), sizeof(calls));
++i;
}
++filenum_itr;
if (max == 0)
break;
}
++code_itr;
if (max == 0)
break;
}

out_bin_file.flush();
out_bin_file.close();

uint64_t r = 0;
if(code_itr != cov_map.end())
r = code_itr->first;
return r;
}

} // namespace coverage
} // namespace eosio
3 changes: 2 additions & 1 deletion libraries/rodeos/rodeos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,9 @@ void rodeos_filter::process(rodeos_db_snapshot& snapshot, const ship_protocol::g
snapshot.check_write(result);
chaindb_state chaindb_state;
db_view_state view_state{ name, *snapshot.db, *snapshot.write_session, snapshot.partition->contract_kv_prefix };
coverage_state coverage_state;
view_state.kv_state.enable_write = true;
filter::callbacks cb{ *filter_state, chaindb_state, view_state };
filter::callbacks cb{ *filter_state, chaindb_state, view_state, coverage_state };
filter_state->max_console_size = 10000;
filter_state->console.clear();
filter_state->input_data = bin;
Expand Down
15 changes: 11 additions & 4 deletions libraries/rodeos/wasm_ql.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <b1/rodeos/callbacks/crypto.hpp>
#include <b1/rodeos/callbacks/memory.hpp>
#include <b1/rodeos/callbacks/unimplemented.hpp>
#include <b1/rodeos/callbacks/coverage.hpp>
#include <b1/rodeos/rodeos.hpp>
#include <boost/filesystem.hpp>
#include <boost/multi_index/member.hpp>
Expand Down Expand Up @@ -72,18 +73,22 @@ struct callbacks : action_callbacks<callbacks>,
db_callbacks<callbacks>,
memory_callbacks<callbacks>,
query_callbacks<callbacks>,
unimplemented_callbacks<callbacks> {
unimplemented_callbacks<callbacks>,
coverage_callbacks<callbacks> {
wasm_ql::thread_state& thread_state;
rodeos::chaindb_state& chaindb_state;
rodeos::db_view_state& db_view_state;
rodeos::coverage_state& coverage_state;

callbacks(wasm_ql::thread_state& thread_state, rodeos::chaindb_state& chaindb_state,
rodeos::db_view_state& db_view_state)
: thread_state{ thread_state }, chaindb_state{ chaindb_state }, db_view_state{ db_view_state } {}
rodeos::db_view_state& db_view_state, rodeos::coverage_state& coverage_state)
: thread_state{ thread_state }, chaindb_state{ chaindb_state }, db_view_state{ db_view_state }
, coverage_state{ coverage_state } {}

auto& get_state() { return thread_state; }
auto& get_chaindb_state() { return chaindb_state; }
auto& get_db_view_state() { return db_view_state; }
auto& get_coverage_state() { return coverage_state; }
};

std::once_flag registered_callbacks;
Expand All @@ -99,6 +104,7 @@ void register_callbacks() {
memory_callbacks<callbacks>::register_callbacks<rhf_t>();
query_callbacks<callbacks>::register_callbacks<rhf_t>();
unimplemented_callbacks<callbacks>::register_callbacks<rhf_t>();
coverage_callbacks<callbacks>::register_callbacks<rhf_t>();
}

struct backend_entry {
Expand Down Expand Up @@ -273,7 +279,8 @@ void run_action(wasm_ql::thread_state& thread_state, const std::vector<char>& co
thread_state.block_info.reset();

chaindb_state chaindb_state;
callbacks cb{ thread_state, chaindb_state, db_view_state };
coverage_state coverage_state;
callbacks cb{ thread_state, chaindb_state, db_view_state, coverage_state };
entry->backend->set_wasm_allocator(&thread_state.wa);

try {
Expand Down
Loading