Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uniform printing of simplified vs non-simplified #805

Merged
merged 2 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
51 changes: 51 additions & 0 deletions src/asm_cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,57 @@ cfg_t prepare_cfg(const InstructionSeq& prog, const program_info& info, const pr
return cfg;
}

std::set<basic_block_t> basic_block_t::collect_basic_blocks(const cfg_t& cfg, const bool simplify) {
elazarg marked this conversation as resolved.
Show resolved Hide resolved
if (!simplify) {
std::set<basic_block_t> res;
for (const label_t& label : cfg.labels()) {
if (label != cfg.entry_label() && label != cfg.exit_label()) {
res.insert(basic_block_t{label});
}
}
return res;
}

std::set<basic_block_t> res;
std::set worklist(cfg.label_begin(), cfg.label_end());
std::set<label_t> seen;
while (!worklist.empty()) {
elazarg marked this conversation as resolved.
Show resolved Hide resolved
const label_t label = *worklist.begin();
worklist.erase(label);
if (seen.contains(label)) {
continue;
}
seen.insert(label);

const value_t* current_value = &cfg.get_node(label);
if (current_value->in_degree() == 1 && cfg.get_parent(label).out_degree() == 1) {
continue;
}
elazarg marked this conversation as resolved.
Show resolved Hide resolved
basic_block_t bb{label};
while (current_value->out_degree() == 1) {
const value_t& next_value = cfg.get_child(bb.last_label());
const label_t& next_label = next_value.label();

if (seen.contains(next_label) || next_label == cfg.exit_label() || next_value.in_degree() != 1) {
break;
}

if (bb.first_label() == cfg.entry_label()) {
// Entry instruction is Undefined. We want to start with 0
bb.m_ts.clear();
}
bb.m_ts.push_back(next_label);

worklist.erase(next_label);
seen.insert(next_label);

current_value = &next_value;
}
res.emplace(std::move(bb));
}
return res;
}

template <typename T>
static vector<label_t> unique(const std::pair<T, T>& be) {
vector<label_t> res;
Expand Down
79 changes: 68 additions & 11 deletions src/asm_ostream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@

#include "asm_syntax.hpp"
#include "crab/cfg.hpp"
#include "crab/fwd_analyzer.hpp"
#include "crab/interval.hpp"
#include "crab/type_encoding.hpp"
#include "crab/variable.hpp"
#include "crab_utils/num_big.hpp"
#include "crab_verifier.hpp"
#include "helpers.hpp"
#include "platform.hpp"
#include "spec_type_descriptors.hpp"
Expand All @@ -21,6 +23,23 @@ using std::optional;
using std::string;
using std::vector;

struct LineInfoPrinter {
std::ostream& os;
std::string previous_source_line;

void print_line_info(const label_t& label) {
if (thread_local_options.verbosity_opts.print_line_info) {
const auto& line_info_map = thread_local_program_info.get().line_info;
const auto& line_info = line_info_map.find(label.from);
// Print line info only once.
if (line_info != line_info_map.end() && line_info->second.source_line != previous_source_line) {
os << "\n" << line_info->second << "\n";
previous_source_line = line_info->second.source_line;
}
}
}
};
elazarg marked this conversation as resolved.
Show resolved Hide resolved

namespace crab {

std::string number_t::to_string() const { return _n.str(); }
Expand Down Expand Up @@ -134,23 +153,61 @@ void print_from(std::ostream& o, const value_t& value) {
o << "\n";
}

std::ostream& operator<<(std::ostream& o, const cfg_t& cfg) {
for (const label_t& label : cfg.sorted_labels()) {
const auto& value = cfg.get_node(label);
print_label(o, value);
print_assertions(o, value);
print_instruction(o, value);
o << "edges to:";
for (const label_t& next_label : cfg.next_nodes(label)) {
o << " " << next_label;
static void print_cfg(std::ostream& os, const cfg_t& cfg, const bool simplify, const invariant_table_t* invariants) {
LineInfoPrinter printer{os};
for (const auto& bb : basic_block_t::collect_basic_blocks(cfg, simplify)) {
if (invariants) {
os << "\nPre-invariant : " << invariants->at(bb.first_label()).pre << "\n";
}
const value_t& first_node = cfg.get_node(bb.first_label());
print_from(os, first_node);
print_label(os, first_node);
for (const label_t& label : bb) {
printer.print_line_info(label);
const value_t& node = cfg.get_node(label);
print_assertions(os, node);
print_instruction(os, node);
}
print_goto(os, cfg.get_node(bb.last_label()));
if (invariants) {
os << "\nPost-invariant: " << invariants->at(bb.last_label()).post << "\n";
}
o << "\n";
}
return o;
os << "\n";
}
elazarg marked this conversation as resolved.
Show resolved Hide resolved
void print_cfg(std::ostream& os, const cfg_t& cfg, const bool simplify) { print_cfg(os, cfg, simplify, nullptr); }

} // namespace crab

void print_reachability(std::ostream& os, const Report& report) {
for (const auto& [label, notes] : report.reachability) {
for (const auto& msg : notes) {
os << label << ": " << msg << "\n";
}
}
os << "\n";
}

void print_warnings(std::ostream& os, const Report& report) {
LineInfoPrinter printer{os};
for (const auto& [label, warnings] : report.warnings) {
for (const auto& msg : warnings) {
printer.print_line_info(label);
os << label << ": " << msg << "\n";
}
}
os << "\n";
}

void print_all_messages(std::ostream& os, const Report& report) {
print_reachability(os, report);
print_warnings(os, report);
}

void print_invariants(std::ostream& os, const cfg_t& cfg, const bool simplify, const Invariants& invariants) {
print_cfg(os, cfg, simplify, &invariants.invariants);
}

namespace asm_syntax {
std::ostream& operator<<(std::ostream& os, const ArgSingle::Kind kind) {
switch (kind) {
Expand Down
40 changes: 2 additions & 38 deletions src/crab/cfg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,43 +385,7 @@ class basic_block_t final {
public:
std::strong_ordering operator<=>(const basic_block_t& other) const { return first_label() <=> other.first_label(); }

static std::set<basic_block_t> collect_basic_blocks(const cfg_t& cfg) {
std::set<basic_block_t> res;

std::set worklist(cfg.label_begin(), cfg.label_end());
std::set<label_t> seen;
while (!worklist.empty()) {
const label_t label = *worklist.begin();
worklist.erase(label);
if (seen.contains(label)) {
continue;
}
seen.insert(label);

const value_t* current_value = &cfg.get_node(label);
if (current_value->in_degree() == 1 && cfg.get_parent(label).out_degree() == 1) {
continue;
}
basic_block_t bb{label};
while (current_value->out_degree() == 1) {
const value_t& next_value = cfg.get_child(bb.last_label());
const label_t& next_label = next_value.label();

if (next_label == bb.first_label() || next_label == cfg.exit_label() || next_value.in_degree() != 1) {
break;
}

bb.m_ts.push_back(next_label);

worklist.erase(next_label);
seen.insert(next_label);

current_value = &next_value;
}
res.emplace(std::move(bb));
}
return res;
}
static std::set<basic_block_t> collect_basic_blocks(const cfg_t& cfg, bool simplify);

explicit basic_block_t(const label_t& first_label) : m_ts{first_label} {}
basic_block_t(basic_block_t&&) noexcept = default;
Expand Down Expand Up @@ -455,7 +419,7 @@ class basic_block_t final {
void print_dot(const cfg_t& cfg, std::ostream& out);
void print_dot(const cfg_t& cfg, const std::string& outfile);

std::ostream& operator<<(std::ostream& o, const cfg_t& cfg);
void print_cfg(std::ostream& os, const cfg_t& cfg, bool simplify);

} // end namespace crab

Expand Down
104 changes: 0 additions & 104 deletions src/crab_verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,61 +26,12 @@ thread_local crab::lazy_allocator<program_info> thread_local_program_info;
thread_local ebpf_verifier_options_t thread_local_options;
void ebpf_verifier_clear_before_analysis();

struct LineInfoPrinter {
std::ostream& os;
std::string previous_source_line;

void print_line_info(const label_t& label) {
if (thread_local_options.verbosity_opts.print_line_info) {
const auto& line_info_map = thread_local_program_info.get().line_info;
const auto& line_info = line_info_map.find(label.from);
// Print line info only once.
if (line_info != line_info_map.end() && line_info->second.source_line != previous_source_line) {
os << "\n" << line_info->second << "\n";
previous_source_line = line_info->second.source_line;
}
}
}
};

bool Invariants::is_valid_after(const label_t& label, const string_invariant& state) const {
const ebpf_domain_t abstract_state =
ebpf_domain_t::from_constraints(state.value(), thread_local_options.setup_constraints);
return abstract_state <= invariants.at(label).post;
}

void Invariants::print_invariants(std::ostream& os, const cfg_t& cfg) const {
if (thread_local_options.verbosity_opts.simplify) {
for (const auto& bb : basic_block_t::collect_basic_blocks(cfg)) {
os << "\nPre-invariant : " << invariants.at(bb.first_label()).pre << "\n";
print_from(os, cfg.get_node(bb.first_label()));
print_label(os, cfg.get_node(bb.first_label()));
for (const auto& label : bb) {
const auto& value = cfg.get_node(label);
print_assertions(os, value);
print_instruction(os, value);
}
print_goto(os, cfg.get_node(bb.last_label()));
os << "\nPost-invariant: " << invariants.at(bb.last_label()).post << "\n";
}
} else {
LineInfoPrinter printer{os};
for (const label_t& label : cfg.sorted_labels()) {
printer.print_line_info(label);
const auto& inv_pair = invariants.at(label);
os << "\nPre-invariant : " << inv_pair.pre << "\n";
const auto& value = cfg.get_node(label);
print_from(os, value);
print_label(os, value);
print_assertions(os, value);
print_instruction(os, value);
print_goto(os, value);
os << "\nPost-invariant: " << inv_pair.post << "\n";
}
}
os << "\n";
}

string_invariant Invariants::invariant_at(const label_t& label) const { return invariants.at(label).post.to_set(); }

crab::interval_t Invariants::exit_value() const { return invariants.at(label_t::exit).post.get_r0(); }
Expand Down Expand Up @@ -113,61 +64,6 @@ Invariants analyze(const cfg_t& cfg, const string_invariant& entry_invariant) {
ebpf_domain_t::from_constraints(entry_invariant.value(), thread_local_options.setup_constraints));
}

void Report::print_reachability(std::ostream& os) const {
for (const auto& [label, notes] : reachability) {
for (const auto& msg : notes) {
os << label << ": " << msg << "\n";
}
}
os << "\n";
}

void Report::print_warnings(std::ostream& os) const {
LineInfoPrinter printer{os};
for (const auto& [label, warnings] : warnings) {
for (const auto& msg : warnings) {
printer.print_line_info(label);
os << label << ": " << msg << "\n";
}
}
os << "\n";
}

void Report::print_all_messages(std::ostream& os) const {
print_reachability(os);
print_warnings(os);
}

std::set<std::string> Report::all_messages() const {
std::set<std::string> result = warning_set();
for (const auto& note : reachability_set()) {
result.insert(note);
}
return result;
}

std::set<std::string> Report::reachability_set() const {
std::set<std::string> result;
for (const auto& [label, warnings] : reachability) {
for (const auto& msg : warnings) {
result.insert(to_string(label) + ": " + msg);
}
}
return result;
}

std::set<std::string> Report::warning_set() const {
std::set<std::string> result;
for (const auto& [label, warnings] : warnings) {
for (const auto& msg : warnings) {
result.insert(to_string(label) + ": " + msg);
}
}
return result;
}

bool Report::verified() const { return warnings.empty(); }

bool Invariants::verified(const cfg_t& cfg) const {
for (const auto& [label, inv_pair] : invariants) {
if (inv_pair.pre.is_bottom()) {
Expand Down
Loading
Loading