diff options
Diffstat (limited to 'tools/klee-ptree')
-rw-r--r-- | tools/klee-ptree/CMakeLists.txt | 16 | ||||
-rw-r--r-- | tools/klee-ptree/DFSVisitor.cpp | 46 | ||||
-rw-r--r-- | tools/klee-ptree/DFSVisitor.h | 31 | ||||
-rw-r--r-- | tools/klee-ptree/Printers.cpp | 266 | ||||
-rw-r--r-- | tools/klee-ptree/Printers.h | 30 | ||||
-rw-r--r-- | tools/klee-ptree/Tree.cpp | 208 | ||||
-rw-r--r-- | tools/klee-ptree/Tree.h | 53 | ||||
-rw-r--r-- | tools/klee-ptree/main.cpp | 68 |
8 files changed, 0 insertions, 718 deletions
diff --git a/tools/klee-ptree/CMakeLists.txt b/tools/klee-ptree/CMakeLists.txt deleted file mode 100644 index b5c3fa09..00000000 --- a/tools/klee-ptree/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -#===------------------------------------------------------------------------===# -# -# The KLEE Symbolic Virtual Machine -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -#===------------------------------------------------------------------------===# - -add_executable(klee-ptree main.cpp Tree.cpp DFSVisitor.cpp Printers.cpp) - -target_compile_features(klee-ptree PRIVATE cxx_std_17) -target_include_directories(klee-ptree PRIVATE ${KLEE_INCLUDE_DIRS} ${SQLite3_INCLUDE_DIRS}) -target_link_libraries(klee-ptree PUBLIC ${SQLite3_LIBRARIES}) - -install(TARGETS klee-ptree DESTINATION bin) diff --git a/tools/klee-ptree/DFSVisitor.cpp b/tools/klee-ptree/DFSVisitor.cpp deleted file mode 100644 index c87afc3e..00000000 --- a/tools/klee-ptree/DFSVisitor.cpp +++ /dev/null @@ -1,46 +0,0 @@ -//===-- DFSVisitor.cpp ------------------------------------------*- C++ -*-===// -// -// The KLEE Symbolic Virtual Machine -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DFSVisitor.h" - -#include <utility> - -DFSVisitor::DFSVisitor(const Tree &tree, callbackT cb_intermediate, - callbackT cb_leaf) noexcept - : tree{tree}, - cb_intermediate{std::move(cb_intermediate)}, cb_leaf{std::move(cb_leaf)} { - run(); -} - -void DFSVisitor::run() const noexcept { - // empty tree - if (tree.nodes.size() <= 1) - return; - - std::vector<std::tuple<std::uint32_t, std::uint32_t>> stack{ - {1, 1}}; // (id, depth) - while (!stack.empty()) { - std::uint32_t id, depth; - std::tie(id, depth) = stack.back(); - stack.pop_back(); - const auto &node = tree.nodes[id]; - - if (node.left || node.right) { - if (cb_intermediate) - cb_intermediate(id, node, depth); - if (node.right) - stack.emplace_back(node.right, depth + 1); - if (node.left) - stack.emplace_back(node.left, depth + 1); - } else { - if (cb_leaf) - cb_leaf(id, node, depth); - } - } -} diff --git a/tools/klee-ptree/DFSVisitor.h b/tools/klee-ptree/DFSVisitor.h deleted file mode 100644 index 60d7b3bd..00000000 --- a/tools/klee-ptree/DFSVisitor.h +++ /dev/null @@ -1,31 +0,0 @@ -//===-- DFSVisitor.h --------------------------------------------*- C++ -*-===// -// -// The KLEE Symbolic Virtual Machine -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "Tree.h" - -#include <functional> - -/// @brief Traverses a process tree and calls registered callbacks for -/// intermediate and leaf nodes (not the classical Visitor pattern). -class DFSVisitor { - // void _(node ID, node, depth) - using callbackT = std::function<void(std::uint32_t, Node, std::uint32_t)>; - - const Tree &tree; - callbackT cb_intermediate; - callbackT cb_leaf; - void run() const noexcept; - -public: - DFSVisitor(const Tree &tree, callbackT cb_intermediate, - callbackT cb_leaf) noexcept; - ~DFSVisitor() = default; -}; diff --git a/tools/klee-ptree/Printers.cpp b/tools/klee-ptree/Printers.cpp deleted file mode 100644 index 950d1b09..00000000 --- a/tools/klee-ptree/Printers.cpp +++ /dev/null @@ -1,266 +0,0 @@ -//===-- Printers.cpp --------------------------------------------*- C++ -*-===// -// -// The KLEE Symbolic Virtual Machine -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Printers.h" - -#include "DFSVisitor.h" -#include "klee/Core/BranchTypes.h" -#include "klee/Core/TerminationTypes.h" - -#include <algorithm> -#include <array> -#include <cstdlib> -#include <iostream> -#include <map> -#include <string> -#include <string_view> -#include <unordered_map> - -// branches - -void printBranches(const Tree &tree) { - if (tree.nodes.size() <= 1) { - std::cout << "Empty tree.\n"; - return; - } - - std::unordered_map<BranchType, std::uint32_t> branchTypes; - - DFSVisitor visitor( - tree, - [&branchTypes](std::uint32_t id, Node node, std::uint32_t depth) { - branchTypes[std::get<BranchType>(node.kind)]++; - }, - nullptr); - - // sort output - std::vector<std::pair<BranchType, std::uint32_t>> sortedBranchTypes( - branchTypes.begin(), branchTypes.end()); - std::sort(sortedBranchTypes.begin(), sortedBranchTypes.end(), - [](const auto &lhs, const auto &rhs) { - return (lhs.second > rhs.second) || - (lhs.second == rhs.second && lhs.first < rhs.first); - }); - - std::cout << "branch type,count\n"; - for (const auto &[branchType, count] : sortedBranchTypes) - std::cout << branchTypeNames[branchType] << ',' << count << '\n'; -} - -// depths - -struct DepthInfo { - std::vector<std::uint32_t> depths; - std::uint32_t maxDepth{0}; - std::uint32_t noLeaves{0}; - std::uint32_t noNodes{0}; -}; - -DepthInfo getDepthInfo(const Tree &tree) { - DepthInfo I; - - DFSVisitor visitor( - tree, - [&](std::uint32_t id, Node node, std::uint32_t depth) { ++I.noNodes; }, - [&I](std::uint32_t id, Node node, std::uint32_t depth) { - ++I.noLeaves; - ++I.noNodes; - if (depth > I.maxDepth) - I.maxDepth = depth; - if (depth >= I.depths.size()) - I.depths.resize(depth + 1, 0); - ++I.depths[depth]; - }); - - return I; -} - -void printDepths(const Tree &tree) { - if (tree.nodes.size() <= 1) { - std::cout << "Empty tree.\n"; - return; - } - - const auto DI = getDepthInfo(tree); - std::cout << "depth,count\n"; - for (size_t depth = 1; depth <= DI.maxDepth; ++depth) { - auto count = DI.depths[depth]; - if (count) - std::cout << depth << ',' << count << '\n'; - } -} - -// dot - -std::array<std::string, 6> NodeColours = {"green", "orange", "red", - "blue", "darkblue", "darkgrey"}; - -std::string_view terminationTypeColour(StateTerminationType type) { - // Exit - if (type == StateTerminationType::Exit) - return NodeColours[0]; - - // Early - if ((StateTerminationType::EXIT < type && - type <= StateTerminationType::EARLY) || - (StateTerminationType::EXECERR < type && - type <= StateTerminationType::END)) { - return NodeColours[1]; - } - - // Program error - if (StateTerminationType::SOLVERERR < type && - type <= StateTerminationType::PROGERR) - return NodeColours[2]; - - // User error - if (StateTerminationType::PROGERR < type && - type <= StateTerminationType::USERERR) - return NodeColours[3]; - - // Execution/Solver error - if ((StateTerminationType::USERERR < type && - type <= StateTerminationType::EXECERR) || - (StateTerminationType::EARLY < type && - type <= StateTerminationType::SOLVERERR)) - return NodeColours[4]; - - return NodeColours[5]; -} - -void printIntermediateNode(std::uint32_t id, Node node, std::uint32_t depth) { - std::cout << 'N' << id << '[' << "tooltip=\"" - << branchTypeNames[std::get<BranchType>(node.kind)] << "\\n" - << "node: " << id << "\\nstate: " << node.stateID - << "\\nasm: " << node.asmLine << "\"];\n"; -} - -void printLeafNode(std::uint32_t id, Node node, std::uint32_t depth) { - const auto terminationType = std::get<StateTerminationType>(node.kind); - const auto colour = terminationTypeColour(terminationType); - std::cout << 'N' << id << '[' << "tooltip=\"" - << terminationTypeNames[terminationType] << "\\n" - << "node: " << id << "\\nstate: " << node.stateID - << "\\nasm: " << node.asmLine << "\",color=" << colour << "];\n"; -} - -void printEdges(std::uint32_t id, Node node, std::uint32_t depth) { - std::cout << 'N' << id << "->{"; - if (node.left && node.right) { - std::cout << 'N' << node.left << " N" << node.right; - } else { - std::cout << 'N' << (node.left ? node.left : node.right); - } - std::cout << "};\n"; -} - -void printDOT(const Tree &tree) { - // header - // - style defaults to intermediate nodes - std::cout << "strict digraph PTree {\n" - "node[shape=point,width=0.15,color=darkgrey];\n" - "edge[color=darkgrey];\n\n"; - - // nodes - // - change colour for leaf nodes - // - attach branch and location info as tooltips - DFSVisitor nodeVisitor(tree, printIntermediateNode, printLeafNode); - - // edges - DFSVisitor edgeVisitor(tree, printEdges, nullptr); - - // footer - std::cout << '}' << std::endl; -} - -// instructions - -struct Info { - std::uint32_t noBranches{0}; - std::uint32_t noTerminations{0}; - std::map<StateTerminationType, std::uint32_t> terminationTypes; -}; - -void printInstructions(const Tree &tree) { - std::map<std::uint32_t, Info> asmInfo; - - DFSVisitor visitor( - tree, - [&asmInfo](std::uint32_t id, Node node, std::uint32_t depth) { - asmInfo[node.asmLine].noBranches++; - }, - [&asmInfo](std::uint32_t id, Node node, std::uint32_t depth) { - auto &info = asmInfo[node.asmLine]; - info.noTerminations++; - info.terminationTypes[std::get<StateTerminationType>(node.kind)]++; - }); - - std::cout << "asm line,branches,terminations,termination types\n"; - for (const auto &[asmLine, info] : asmInfo) { - std::cout << asmLine << ',' << info.noBranches << ',' << info.noTerminations - << ','; - std::string sep{""}; - for (const auto &[terminationType, count] : info.terminationTypes) { - std::cout << sep << terminationTypeNames[terminationType] << '(' << count - << ')'; - sep = ";"; - } - std::cout << '\n'; - } -} - -// terminations - -void printTerminations(const Tree &tree) { - if (tree.nodes.size() <= 1) { - std::cout << "Empty tree.\n"; - return; - } - - std::map<StateTerminationType, std::uint32_t> terminations; - - DFSVisitor visitor( - tree, nullptr, - [&terminations](std::uint32_t id, Node node, std::uint32_t depth) { - terminations[std::get<StateTerminationType>(node.kind)]++; - }); - - std::cout << "termination type,count\n"; - for (const auto &[terminationType, count] : terminations) - std::cout << terminationTypeNames[terminationType] << ',' << count << '\n'; -} - -// tree info - -void printTreeInfo(const Tree &tree) { - if (tree.nodes.size() <= 1) { - std::cout << "Empty tree.\n"; - return; - } - - const auto DI = getDepthInfo(tree); - - // determine average depth - std::uint64_t sum{0}; - for (size_t depth = 1; depth <= DI.maxDepth; ++depth) { - auto count = DI.depths[depth]; - if (count) - sum += count * depth; - } - double avgDepth = (double)sum / DI.noLeaves; - - std::cout << "nodes: " << DI.noNodes << '\n' - << "leaf nodes: " << DI.noLeaves - << (DI.noNodes && (DI.noLeaves != DI.noNodes / 2 + 1) - ? " (not a binary tree?!)" - : "") - << '\n' - << "max. depth: " << DI.maxDepth << '\n' - << "avg. depth: " << std::setprecision(2) << avgDepth << '\n'; -} diff --git a/tools/klee-ptree/Printers.h b/tools/klee-ptree/Printers.h deleted file mode 100644 index d20db4a1..00000000 --- a/tools/klee-ptree/Printers.h +++ /dev/null @@ -1,30 +0,0 @@ -//===-- Printers.h ----------------------------------------------*- C++ -*-===// -// -// The KLEE Symbolic Virtual Machine -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "Tree.h" - -/// print branch types in csv format -void printBranches(const Tree &tree); - -/// print depths in csv format -void printDepths(const Tree &tree); - -/// print tree in dot format -void printDOT(const Tree &tree); - -/// print instruction information in csv format -void printInstructions(const Tree &tree); - -/// print termination types in csv format -void printTerminations(const Tree &tree); - -/// print tree/node information -void printTreeInfo(const Tree &tree); diff --git a/tools/klee-ptree/Tree.cpp b/tools/klee-ptree/Tree.cpp deleted file mode 100644 index 20772600..00000000 --- a/tools/klee-ptree/Tree.cpp +++ /dev/null @@ -1,208 +0,0 @@ -//===-- Tree.cpp ------------------------------------------------*- C++ -*-===// -// -// The KLEE Symbolic Virtual Machine -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Tree.h" - -#include <sqlite3.h> - -#include <cassert> -#include <cstdlib> -#include <iostream> - -Tree::Tree(const std::filesystem::path &path) { - // open db - ::sqlite3 *db; - if (sqlite3_open_v2(path.c_str(), &db, SQLITE_OPEN_READONLY, nullptr) != - SQLITE_OK) { - std::cerr << "Can't open process tree database: " << sqlite3_errmsg(db) - << std::endl; - exit(EXIT_FAILURE); - } - - // initialise prepared statement - ::sqlite3_stmt *readStmt; - std::string query{ - "SELECT ID, stateID, leftID, rightID, asmLine, kind FROM nodes;"}; - if (sqlite3_prepare_v3(db, query.c_str(), -1, SQLITE_PREPARE_PERSISTENT, - &readStmt, nullptr) != SQLITE_OK) { - std::cerr << "Can't prepare read statement: " << sqlite3_errmsg(db) - << std::endl; - exit(EXIT_FAILURE); - } - - ::sqlite3_stmt *maxStmt; - query = "SELECT MAX(ID) FROM nodes;"; - if (sqlite3_prepare_v3(db, query.c_str(), -1, SQLITE_PREPARE_PERSISTENT, - &maxStmt, nullptr) != SQLITE_OK) { - std::cerr << "Can't prepare max statement: " << sqlite3_errmsg(db) - << std::endl; - exit(EXIT_FAILURE); - } - - // read max id - int rc; - std::uint64_t maxID; - if ((rc = sqlite3_step(maxStmt)) == SQLITE_ROW) { - maxID = static_cast<std::uint32_t>(sqlite3_column_int(maxStmt, 0)); - } else { - std::cerr << "Can't read maximum ID: " << sqlite3_errmsg(db) << std::endl; - exit(EXIT_FAILURE); - } - - // reserve space - nodes.resize(maxID + 1, {}); - - // read rows into vector - while ((rc = sqlite3_step(readStmt)) == SQLITE_ROW) { - const auto ID = static_cast<std::uint32_t>(sqlite3_column_int(readStmt, 0)); - const auto stateID = - static_cast<std::uint32_t>(sqlite3_column_int(readStmt, 1)); - const auto left = - static_cast<std::uint32_t>(sqlite3_column_int(readStmt, 2)); - const auto right = - static_cast<std::uint32_t>(sqlite3_column_int(readStmt, 3)); - const auto asmLine = - static_cast<std::uint32_t>(sqlite3_column_int(readStmt, 4)); - const auto tmpKind = - static_cast<std::uint8_t>(sqlite3_column_int(readStmt, 5)); - - // sanity checks: valid indices - if (ID == 0) { - std::cerr << "PTree DB contains illegal node ID (0)" << std::endl; - exit(EXIT_FAILURE); - } - - if (left > maxID || right > maxID) { - std::cerr << "PTree DB contains references to non-existing nodes (> max. " - "ID) in node " - << ID << std::endl; - exit(EXIT_FAILURE); - } - - if ((left == 0 && right != 0) || (left != 0 && right == 0)) { - std::cerr << "Warning: PTree DB contains ambiguous node (0 vs. non-0 " - "children): " - << ID << std::endl; - } - - // determine node kind (branch or leaf node) - decltype(Node::kind) kind; - if (left == 0 && right == 0) { - kind = static_cast<StateTerminationType>(tmpKind); - } else { - kind = static_cast<BranchType>(tmpKind); - } - - // store children - nodes[ID] = {.left = left, - .right = right, - .stateID = stateID, - .asmLine = asmLine, - .kind = kind}; - } - - if (rc != SQLITE_DONE) { - std::cerr << "Error while reading database: " << sqlite3_errmsg(db) - << std::endl; - exit(EXIT_FAILURE); - } - - // close db - sqlite3_finalize(maxStmt); - sqlite3_finalize(readStmt); - sqlite3_close(db); - - // initialise global sets/maps and sanity check - initialiseValidTypes(); - sanityCheck(); - initialiseTypeNames(); -} - -void Tree::initialiseTypeNames() { -// branch types -#undef BTYPE -#define BTYPE(Name, I) branchTypeNames[BranchType::Name] = #Name; - BRANCH_TYPES - -// termination types -#undef TTYPE -#define TTYPE(Name, I, S) \ - terminationTypeNames[StateTerminationType::Name] = #Name; - TERMINATION_TYPES -} - -void Tree::initialiseValidTypes() { -// branch types -#undef BTYPE -#define BTYPE(Name, I) validBranchTypes.insert(BranchType::Name); - BRANCH_TYPES - -// termination types -#undef TTYPE -#define TTYPE(Name, I, S) \ - validTerminationTypes.insert(StateTerminationType::Name); - TERMINATION_TYPES -} - -void Tree::sanityCheck() { - if (nodes.size() <= 1) // [0] is unused - return; - - std::vector<std::uint32_t> stack{1}; // root ID - std::unordered_set<std::uint32_t> visited; - while (!stack.empty()) { - const auto id = stack.back(); - stack.pop_back(); - - if (!visited.insert(id).second) { - std::cerr << "PTree DB contains duplicate child reference or circular " - "structure. Affected node: " - << id << std::endl; - exit(EXIT_FAILURE); - } - - const auto &node = nodes[id]; - - // default constructed "gap" in vector - if (!node.left && !node.right && - std::holds_alternative<BranchType>(node.kind) && - static_cast<std::uint8_t>(std::get<BranchType>(node.kind)) == 0u) { - std::cerr << "PTree DB references undefined node. Affected node: " << id - << std::endl; - exit(EXIT_FAILURE); - } - - if (node.left || node.right) { - if (node.right) - stack.push_back(node.right); - if (node.left) - stack.push_back(node.left); - // valid branch types - assert(std::holds_alternative<BranchType>(node.kind)); - const auto branchType = std::get<BranchType>(node.kind); - if (validBranchTypes.count(branchType) == 0) { - std::cerr << "PTree DB contains unknown branch type (" - << (unsigned)static_cast<std::uint8_t>(branchType) - << ") in node " << id << std::endl; - exit(EXIT_FAILURE); - } - } else { - // valid termination types - assert(std::holds_alternative<StateTerminationType>(node.kind)); - const auto terminationType = std::get<StateTerminationType>(node.kind); - if (validTerminationTypes.count(terminationType) == 0 || - terminationType == StateTerminationType::RUNNING) { - std::cerr << "PTree DB contains unknown termination type (" - << (unsigned)static_cast<std::uint8_t>(terminationType) - << ") in node " << id << std::endl; - exit(EXIT_FAILURE); - } - } - } -} diff --git a/tools/klee-ptree/Tree.h b/tools/klee-ptree/Tree.h deleted file mode 100644 index 65b7baeb..00000000 --- a/tools/klee-ptree/Tree.h +++ /dev/null @@ -1,53 +0,0 @@ -//===-- Tree.h --------------------------------------------------*- C++ -*-===// -// -// The KLEE Symbolic Virtual Machine -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "klee/Core/BranchTypes.h" -#include "klee/Core/TerminationTypes.h" - -#include <filesystem> -#include <string> -#include <unordered_map> -#include <unordered_set> -#include <variant> -#include <vector> - -inline std::unordered_set<BranchType> validBranchTypes; -inline std::unordered_set<StateTerminationType> validTerminationTypes; -inline std::unordered_map<BranchType, std::string> branchTypeNames; -inline std::unordered_map<StateTerminationType, std::string> - terminationTypeNames; - -///@brief A Tree node representing a PTreeNode -struct Node final { - std::uint32_t left{0}; - std::uint32_t right{0}; - std::uint32_t stateID{0}; - std::uint32_t asmLine{0}; - std::variant<BranchType, StateTerminationType> kind{BranchType::NONE}; -}; - -///@brief An in-memory representation of a complete process tree -class Tree final { - /// Creates branchTypeNames and terminationTypeNames maps - static void initialiseTypeNames(); - /// Creates validBranchTypes and validTerminationTypes sets - static void initialiseValidTypes(); - /// Checks tree properties (e.g. valid branch/termination types) - void sanityCheck(); - -public: - /// sorted vector of Nodes default initialised with BranchType::NONE - std::vector<Node> nodes; // PTree node IDs start with 1! - - /// Reads complete ptree.db into memory - explicit Tree(const std::filesystem::path &path); - ~Tree() = default; -}; diff --git a/tools/klee-ptree/main.cpp b/tools/klee-ptree/main.cpp deleted file mode 100644 index 96d2be75..00000000 --- a/tools/klee-ptree/main.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//===-- main.cpp ------------------------------------------------*- C++ -*-===// -// -// The KLEE Symbolic Virtual Machine -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <cstdlib> -#include <filesystem> -#include <iostream> - -#include "Printers.h" - -namespace fs = std::filesystem; - -void print_usage() { - std::cout << "Usage: klee-ptree <option> /path[/ptree.db]\n\n" - "Options:\n" - "\tbranches - print branch statistics in csv format\n" - "\tdepths - print depths statistics in csv format\n" - "\tinstructions - print asm line summary in csv format\n" - "\tterminations - print termination statistics in csv format\n" - "\ttree-dot - print tree in dot format\n" - "\ttree-info - print tree statistics" - "\n"; -} - -int main(int argc, char *argv[]) { - if (argc != 3) { - print_usage(); - exit(EXIT_FAILURE); - } - - // parse options - void (*action)(const Tree &); - std::string option(argv[1]); - if (option == "branches") { - action = printBranches; - } else if (option == "instructions") { - action = printInstructions; - } else if (option == "depths") { - action = printDepths; - } else if (option == "terminations") { - action = printTerminations; - } else if (option == "tree-dot") { - action = printDOT; - } else if (option == "tree-info") { - action = printTreeInfo; - } else { - print_usage(); - exit(EXIT_FAILURE); - } - - // create tree - fs::path path{argv[2]}; - if (fs::is_directory(path)) - path /= "ptree.db"; - if (!fs::exists(path)) { - std::cerr << "Cannot open " << path << '\n'; - exit(EXIT_FAILURE); - } - Tree tree(path); - - // print results - action(tree); -} |