Skip to content
Open
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
15 changes: 13 additions & 2 deletions resolve-facts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ file(GLOB_RECURSE SRC
file(GLOB_RECURSE LIB
"${CMAKE_CURRENT_SOURCE_DIR}/include/reach/*.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/libs/reach/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/libs/reach/*.hpp"
)

# reach lib
Expand All @@ -166,10 +167,20 @@ add_library(libreach
set_target_properties(libreach PROPERTIES OUTPUT_NAME "reach")

target_include_directories(libreach PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/include"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_link_libraries(libreach PUBLIC resolve_facts json)
target_include_directories(libreach PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/libs"
)
target_link_libraries(libreach PUBLIC
resolve_facts
facts_rs
json
Threads::Threads
${CMAKE_DL_LIBS}
m
)

target_compile_features(libreach PUBLIC cxx_std_23)

Expand Down
6 changes: 5 additions & 1 deletion resolve-facts/include/reach/distmap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ namespace distmap {
distmap_blacklist
gen(const reach_facts::database &db, const NNodeId &dst, bool dynlink = false,
const std::optional<std::vector<dlsym::loaded_symbol>> &loaded_syms = {});
}

distmap_blacklist
gen(const facts_rs::FactsBuf *facts, const NNodeId &dst, bool dynlink = false,
const std::optional<std::vector<dlsym::loaded_symbol>> &loaded_syms = {});
} // namespace distmap
9 changes: 9 additions & 0 deletions resolve-facts/include/reach/facts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <fstream>
#include <iostream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>

Expand All @@ -23,6 +24,10 @@ using NodeType = resolve_facts::NodeType;
using Linkage = resolve_facts::Linkage;
using CallType = resolve_facts::CallType;

namespace facts_rs {
struct FactsBuf;
}

namespace reach_facts {

enum class LoadOptions : int {
Expand Down Expand Up @@ -71,6 +76,10 @@ struct database {
database load(std::istream &facts, LoadOptions options);
database load(const std::filesystem::path &facts_dir, LoadOptions options);

std::vector<NamespacedNodeId>
find_functions_by_name_suffix(const facts_rs::FactsBuf *facts,
std::string_view suffix);

bool validate(const database &db);
} // namespace reach_facts

Expand Down
14 changes: 13 additions & 1 deletion resolve-facts/include/reach/graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

#include "reach/facts.hpp"

namespace facts_rs {
struct FactsBuf;
}

using NNodeId = resolve_facts::NamespacedNodeId;

namespace graph {
Expand Down Expand Up @@ -58,7 +62,11 @@ struct T {
bool wf(const E &g);

T build_from_program_facts(
const resolve_facts::ProgramFacts &pf, bool dynlink,
const resolve_facts::ProgramFacts &facts, bool dynlink,
const std::optional<std::vector<dlsym::loaded_symbol>> &loaded_syms);

T build_from_program_facts(
const facts_rs::FactsBuf *facts, bool dynlink,
const std::optional<std::vector<dlsym::loaded_symbol>> &loaded_syms);

constexpr reach_facts::LoadOptions SIMPLE_LOAD_OPTIONS =
Expand Down Expand Up @@ -104,6 +112,10 @@ T build_cfg(
T build_instr_cfg(
const reach_facts::database &db, bool dynlink = false,
const std::optional<std::vector<dlsym::loaded_symbol>> &loaded_syms = {});

T build_instr_cfg(
const facts_rs::FactsBuf *facts, bool dynlink = false,
const std::optional<std::vector<dlsym::loaded_symbol>> &loaded_syms = {});
} // namespace graph

namespace std {
Expand Down
86 changes: 86 additions & 0 deletions resolve-facts/libs/reach/distmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,97 @@
#include <vector>

#include "reach/distmap.hpp"
#include "reach/facts_view.hpp"
#include "reach/search.hpp"
#include "reach/util.hpp"

using namespace std;

namespace {

template <typename Function>
void for_each_function_instruction(const reach_facts::ProgramFactsView &pf,
const NNodeId function, Function callback) {
const auto [module_id, function_id] = function;
const auto module = pf.module(module_id);
for (const auto &contains_block : module.out_edges(function_id)) {
if (!reach_facts::edge_has_kind(contains_block,
facts_rs::EdgeKind::Contains) ||
module.node(contains_block.dst).type() !=
facts_rs::NodeType::BasicBlock) {
continue;
}
for (const auto &contains_instruction :
module.out_edges(contains_block.dst)) {
if (reach_facts::edge_has_kind(contains_instruction,
facts_rs::EdgeKind::Contains) &&
module.node(contains_instruction.dst).type() ==
facts_rs::NodeType::Instruction) {
callback(make_pair(module_id, contains_instruction.dst));
}
}
}
}

} // namespace

distmap_blacklist
distmap::gen(const facts_rs::FactsBuf *facts, const NNodeId &dst, bool dynlink,
const optional<vector<dlsym::loaded_symbol>> &loaded_syms) {
const reach_facts::ProgramFactsView pf{facts};
if (!pf.contains_node(dst)) {
throw runtime_error("distmap::gen: node not found");
}
const auto target = pf.node(dst);
if (target.type() != facts_rs::NodeType::Function) {
throw runtime_error("distmap::gen: node is not a function");
}
const auto target_name = target.name();
if (!target_name) {
throw runtime_error("distmap::gen: target function has no name");
}

const auto graph = graph::build_instr_cfg(facts, dynlink, loaded_syms);
auto distances = search::min_distances(graph.edges, dst);

for_each_function_instruction(
pf, dst, [&](const NNodeId instruction) { distances[instruction] = 0; });

for (uint32_t module_id = 0; module_id < pf.module_count(); ++module_id) {
const auto module = pf.module(module_id);
for (uint32_t node_id = 0; node_id < module.nodes().size(); ++node_id) {
const auto node = module.node(node_id);
if (node.linkage() == facts_rs::Linkage::ExternalLinkage &&
node.name() == target_name) {
for_each_function_instruction(
pf, make_pair(module_id, node_id),
[&](const NNodeId instruction) { distances[instruction] = 0; });
}
}
}

resolve_facts::NodeMap<size_t> instruction_distances;
for (const auto &[id, distance] : distances) {
if (pf.node(id).type() == facts_rs::NodeType::Instruction) {
instruction_distances.emplace(id, distance);
}
}

unordered_set<NNodeId, resolve_facts::pair_hash> blacklist;
for (uint32_t module_id = 0; module_id < pf.module_count(); ++module_id) {
const auto module = pf.module(module_id);
for (uint32_t node_id = 0; node_id < module.nodes().size(); ++node_id) {
const auto id = make_pair(module_id, node_id);
if (module.node(node_id).type() == facts_rs::NodeType::Instruction &&
!instruction_distances.contains(id)) {
blacklist.insert(id);
}
}
}

return {move(instruction_distances), move(blacklist)};
}

distmap_blacklist
distmap::gen(const reach_facts::database &db, const NNodeId &dst, bool dynlink,
const optional<vector<dlsym::loaded_symbol>> &loaded_syms) {
Expand Down
20 changes: 20 additions & 0 deletions resolve-facts/libs/reach/facts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <unordered_map>

#include "reach/facts.hpp"
#include "reach/facts_view.hpp"
#include "reach/util.hpp"

using namespace resolve_facts;
Expand Down Expand Up @@ -101,6 +102,25 @@ database reach_facts::load(const fs::path &facts_dir, LoadOptions options) {
return load(facts, options);
}

vector<NamespacedNodeId>
reach_facts::find_functions_by_name_suffix(const facts_rs::FactsBuf *facts,
const string_view suffix) {
const ProgramFactsView pf{facts};
vector<NamespacedNodeId> matches;
for (uint32_t mid = 0; mid < pf.module_count(); ++mid) {
const auto module = pf.module(mid);
for (uint32_t nid = 0; nid < module.nodes().size(); ++nid) {
const auto node = module.node(nid);
const auto name = node.name();
if (node.type() == facts_rs::NodeType::Function && name &&
name->ends_with(suffix)) {
matches.emplace_back(mid, nid);
}
}
}
return matches;
}

// These checks ensure that the hashmap lookups in
// graph::build_call_graph and graph::build_cfg will succeed.
bool reach_facts::validate(const database &db) {
Expand Down
Loading