Skip to content

Call-Graph Improvements #785

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

Open
wants to merge 8 commits into
base: development
Choose a base branch
from
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@
#include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h"
#include "phasar/Utils/MaybeUniquePtr.h"

namespace llvm {
class CallBase;
} // namespace llvm

namespace psr {
class DIBasedTypeHierarchy;

Expand Down
4 changes: 0 additions & 4 deletions include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@

#include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h"

namespace llvm {
class CallBase;
} // namespace llvm

namespace psr {

/// \brief A resolver that doesn't resolve indirect- and virtual calls
Expand Down
23 changes: 1 addition & 22 deletions include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,8 @@
#include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h"
#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h"

#include <set>
#include <string>
#include <utility>
#include <vector>

namespace llvm {
class CallBase;
class Function;
class Type;
class Value;
} // namespace llvm

namespace psr {

class DIBasedTypeHierarchy;

/// \brief A resolver that uses alias information to resolve indirect and
/// virtual calls
class OTFResolver : public Resolver {
Expand All @@ -52,18 +38,11 @@ class OTFResolver : public Resolver {

FunctionSetTy resolveFunctionPointer(const llvm::CallBase *CallSite) override;

static std::set<const llvm::Type *>
getReachableTypes(const LLVMAliasInfo::AliasSetTy &Values);

static std::vector<std::pair<const llvm::Value *, const llvm::Value *>>
getActualFormalPointerPairs(const llvm::CallBase *CallSite,
const llvm::Function *CalleeTarget);

[[nodiscard]] std::string str() const override;

[[nodiscard]] bool
mutatesHelperAnalysisInformation() const noexcept override {
return true;
return !PT.isInterProcedural();
}

protected:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@
#include <vector>

namespace llvm {
class CallBase;
class DICompositeType;
} // namespace llvm

namespace psr {
class DIBasedTypeHierarchy;

/// \brief A resolver that performs Rapid Type Analysis to resolve calls
/// to C++ virtual functions. Requires debug information.
Expand Down
63 changes: 42 additions & 21 deletions include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h"

#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/DerivedTypes.h"

#include <memory>
Expand All @@ -44,6 +45,10 @@ enum class CallGraphAnalysisType;
[[nodiscard]] std::optional<unsigned>
getVFTIndex(const llvm::CallBase *CallSite);

/// Similar to getVFTIndex(), but also returns a pointer to the vtable
[[nodiscard]] std::optional<std::pair<const llvm::Value *, uint64_t>>
getVFTIndexAndVT(const llvm::CallBase *CallSite);

/// Assuming that `CallSite` is a call to a non-static member function,
/// retrieves the type of the receiver. Returns nullptr, if the receiver-type
/// could not be extracted
Expand All @@ -68,37 +73,33 @@ getNonPureVirtualVFTEntry(const llvm::DIType *T, unsigned Idx,
[[nodiscard]] bool isVirtualCall(const llvm::Instruction *Inst,
const LLVMVFTableProvider &VTP);

/// A variant of F->hasAddressTaken() that is better suited for our use cases.
///
/// Especially, it filteres out global aliases.
[[nodiscard]] bool isAddressTakenFunction(const llvm::Function *F);

/// \brief A base class for call-target resolvers. Used to build call graphs.
///
/// Create a specific resolver by making a new class, inheriting this resolver
/// class and implementing the virtual functions as needed.
class Resolver {
protected:
const LLVMProjectIRDB *IRDB;
const LLVMVFTableProvider *VTP;

const llvm::Function *
getNonPureVirtualVFTEntry(const llvm::DIType *T, unsigned Idx,
const llvm::CallBase *CallSite) {
if (!VTP) {
return nullptr;
}
return psr::getNonPureVirtualVFTEntry(T, Idx, CallSite, *VTP);
}

public:
using FunctionSetTy = llvm::SmallDenseSet<const llvm::Function *, 4>;

Resolver(const LLVMProjectIRDB *IRDB, const LLVMVFTableProvider *VTP);

virtual ~Resolver() = default;

virtual void preCall(const llvm::Instruction *Inst);
[[deprecated("With the removal of DTAResolver, this is not used "
"anymore")]] virtual void
preCall(const llvm::Instruction *Inst);

virtual void handlePossibleTargets(const llvm::CallBase *CallSite,
FunctionSetTy &PossibleTargets);

virtual void postCall(const llvm::Instruction *Inst);
[[deprecated("With the removal of DTAResolver, this is not used "
"anymore")]] virtual void
postCall(const llvm::Instruction *Inst);

[[nodiscard]] FunctionSetTy
resolveIndirectCall(const llvm::CallBase *CallSite);
Expand All @@ -109,19 +110,39 @@ class Resolver {
[[nodiscard]] virtual FunctionSetTy
resolveFunctionPointer(const llvm::CallBase *CallSite);

virtual void otherInst(const llvm::Instruction *Inst);
[[deprecated("With the removal of DTAResolver, this is not used "
"anymore")]] virtual void
otherInst(const llvm::Instruction *Inst);

[[nodiscard]] virtual std::string str() const = 0;

[[nodiscard]] virtual bool mutatesHelperAnalysisInformation() const noexcept {
// Conservatively returns true. Override if possible
return true;
}
static std::unique_ptr<Resolver> create(CallGraphAnalysisType Ty,
const LLVMProjectIRDB *IRDB,
const LLVMVFTableProvider *VTP,
const DIBasedTypeHierarchy *TH,
LLVMAliasInfoRef PT = nullptr);

[[nodiscard]] llvm::ArrayRef<const llvm::Function *>
getAddressTakenFunctions();

[[nodiscard]] static std::unique_ptr<Resolver>
create(CallGraphAnalysisType Ty, const LLVMProjectIRDB *IRDB,
const LLVMVFTableProvider *VTP, const DIBasedTypeHierarchy *TH,
LLVMAliasInfoRef PT = nullptr);

protected:
const llvm::Function *
getNonPureVirtualVFTEntry(const llvm::DIType *T, unsigned Idx,
const llvm::CallBase *CallSite) {
if (!VTP) {
return nullptr;
}
return psr::getNonPureVirtualVFTEntry(T, Idx, CallSite, *VTP);
}

const LLVMProjectIRDB *IRDB{};
const LLVMVFTableProvider *VTP{};
std::optional<llvm::SmallVector<const llvm::Function *, 0>>
AddressTakenFunctions{};
};
} // namespace psr

Expand Down
17 changes: 5 additions & 12 deletions lib/PhasarLLVM/ControlFlow/LLVMBasedCallGraphBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ static bool fillPossibleTargets(
PossibleTargets.insert(StaticCallee);

PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedICFG",
"Found static call-site: "
<< " " << llvmIRToString(CS));
"Found static call-site: " << " "
<< llvmIRToString(CS));
return true;
}

Expand All @@ -122,8 +122,8 @@ static bool fillPossibleTargets(

// the function call must be resolved dynamically
PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedICFG",
"Found dynamic call-site: "
<< " " << llvmIRToString(CS));
"Found dynamic call-site: " << " "
<< llvmIRToString(CS));

PossibleTargets = Res.resolveIndirectCall(CS);

Expand Down Expand Up @@ -153,13 +153,9 @@ bool Builder::processFunction(const llvm::Function *F) {
for (const auto &I : llvm::instructions(F)) {
const auto *CS = llvm::dyn_cast<llvm::CallBase>(&I);
if (!CS) {
Res->otherInst(&I);
continue;
}

Res->preCall(&I);
scope_exit PostCall = [&] { Res->postCall(&I); };

FixpointReached &=
fillPossibleTargets(PossibleTargets, *Res, CS, IndirectCalls);

Expand Down Expand Up @@ -203,9 +199,6 @@ bool Builder::constructDynamicCall(const llvm::Instruction *CS) {
"Looking into dynamic call-site: ");
PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedICFG", " " << llvmIRToString(CS));

Res->preCall(CallSite);
scope_exit PostCall = [&] { Res->postCall(CallSite); };

// call the resolve routine

auto PossibleTargets = Res->resolveIndirectCall(CallSite);
Expand Down Expand Up @@ -275,7 +268,7 @@ auto psr::buildLLVMBasedCallGraph(
PT = PTOwn.asRef();
}

auto Res = Resolver::create(CGType, &IRDB, &VTP, &TH);
auto Res = Resolver::create(CGType, &IRDB, &VTP, &TH, PT);
return buildLLVMBasedCallGraph(IRDB, *Res, EntryPoints, S);
}

Expand Down
7 changes: 1 addition & 6 deletions lib/PhasarLLVM/ControlFlow/Resolver/CHAResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,10 @@
#include "phasar/PhasarLLVM/Utils/LLVMShorthands.h"
#include "phasar/Utils/Logger.h"

#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Module.h"

#include <memory>

using namespace std;
using namespace psr;

CHAResolver::CHAResolver(const LLVMProjectIRDB *IRDB,
Expand Down Expand Up @@ -76,7 +71,7 @@ auto CHAResolver::resolveVirtualCall(const llvm::CallBase *CallSite)
for (const auto &FallbackTy : FallbackTys) {
const auto *Target =
getNonPureVirtualVFTEntry(FallbackTy, VtableIndex, CallSite);
if (Target) {
if (Target && psr::isConsistentCall(CallSite, Target)) {
PossibleCallees.insert(Target);
}
}
Expand Down
6 changes: 0 additions & 6 deletions lib/PhasarLLVM/ControlFlow/Resolver/NOResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,8 @@

#include "phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h"

#include <set>

using namespace psr;

namespace psr {

NOResolver::NOResolver(const LLVMProjectIRDB *IRDB,
const LLVMVFTableProvider *VTP)
: Resolver(IRDB, VTP) {}
Expand All @@ -37,5 +33,3 @@ auto NOResolver::resolveFunctionPointer(const llvm::CallBase * /*CallSite*/)
}

std::string NOResolver::str() const { return "NOResolver"; }

} // namespace psr
Loading
Loading