DwarfImporteR: handle STT_GNU_IFUNC symbols

In DWARF, `STT_GNU_IFUNC` symbols are associated to a function prototype
returning the actual prototype.
This commit is contained in:
Alessandro Di Federico
2026-05-26 14:51:01 +02:00
parent 2e72494cb1
commit 4c2eb97a18
13 changed files with 226 additions and 157 deletions
@@ -94,65 +94,37 @@ public:
return &Binary->Functions()[Address];
}
/// Similar to registerFunctionEntry but if another function at the same
/// address already exists, return that one. This is necessary in certain
/// situations where the raw address is available but it's not known its type
/// (e.g., Thumb vs regular ARM).
model::Function *matchFunctionEntry(const MetaAddress &Address) {
revng_assert(Address.isValid());
if (not isExecutable(Address)) {
report("match Function", Address);
return nullptr;
}
llvm::SmallVector<MetaAddress> Candidates;
Candidates.push_back(Address);
/// \return the MetaAddress of a function at the relocated address \p Address,
/// possibly already existing in the model.
MetaAddress
matchFunctionEntry(uint64_t Address,
model::Architecture::Values Architecture) const {
using namespace MetaAddressType;
for (auto CodeType : archCodeTypes(arch(Address.type()))) {
if (CodeType == Address.type())
llvm::SmallVector<MetaAddress, 2> Candidates;
auto Primary = MetaAddress::fromPC(Architecture, Address);
if (Primary.isValid())
Candidates.push_back(Primary);
uint64_t BareAddress = Primary.isValid() ? Primary.address() : Address;
for (auto CodeType : archCodeTypes(Architecture)) {
if (Primary.isValid() and CodeType == Primary.type())
continue;
auto NewAddress = Address.replaceType(CodeType);
if (NewAddress.isValid())
Candidates.push_back(std::move(NewAddress));
MetaAddress Alternative(BareAddress, CodeType);
if (Alternative.isValid())
Candidates.push_back(Alternative);
}
unsigned Matches = 0;
auto EndIt = Binary->Functions().end();
auto ResultIt = EndIt;
for (const auto &Candidate : Candidates) {
auto MatchIt = Binary->Functions().find(Candidate);
if (MatchIt != EndIt) {
++Matches;
if (ResultIt == EndIt) {
// Take the first match
ResultIt = MatchIt;
}
}
}
if (Candidates.empty())
return MetaAddress::invalid();
if (ResultIt == EndIt) {
revng_log(Logger,
"Warning: no match for function at "
<< Address.toString() << ". Creating it despite this.");
return &Binary->Functions()[Address];
} else if (Matches == 1 and ResultIt->Entry() != Address) {
revng_log(Logger,
"Matching " << ResultIt->Entry().toString() << " for "
<< Address.toString());
return &*ResultIt;
} else if (Matches > 1 and ResultIt->Entry() != Address) {
revng_log(Logger,
"Warning: multiple matches for "
<< Address.toString() << ". Returning "
<< ResultIt->Entry().toString() << ".");
return &*ResultIt;
} else {
// We have a single match of the given address
return &*ResultIt;
}
for (const auto &Candidate : Candidates)
if (Binary->Functions().contains(Candidate))
return Candidate;
return Candidates.front();
}
void setEntryPoint(const MetaAddress &Address) {
@@ -170,7 +142,7 @@ public:
static uint64_t u64(uint64_t Value) { return Value; }
private:
void report(const char *Action, const MetaAddress &Address) {
void report(const char *Action, const MetaAddress &Address) const {
revng_log(Logger,
"Cannot " << Action << " " << Address.toString()
<< " since it's not in an executable segment.");
@@ -9,27 +9,28 @@
#include "revng/Model/Binary.h"
#include "revng/Model/Importer/Binary/BinaryDescriptor.h"
#include "revng/Support/Configuration.h"
#include "revng/Support/LDDTree.h"
struct ImporterOptions;
class DwarfImporter {
public:
using AddressWhitelist = std::set<uint64_t>;
private:
TupleTree<model::Binary> &Model;
std::vector<std::string> LoadedFiles;
using DwarfID = std::pair<size_t, size_t>;
std::map<DwarfID, model::UpcastableType> DwarfToModel;
const AddressWhitelist *FunctionWhitelist = nullptr;
/// When unset the importer accepts every subprogram; otherwise only those
/// whose MetaAddress appears in the map are kept. Keys carry the code type
/// (Code_arm vs Code_arm_thumb, etc.), so the lookup is exact and
/// architecture-aware.
std::optional<std::map<MetaAddress, LDDTree::Symbol>> WhitelistByAddress;
public:
DwarfImporter(TupleTree<model::Binary> &Model,
const std::optional<AddressWhitelist> &FunctionWhitelist) :
Model(Model),
FunctionWhitelist(FunctionWhitelist.has_value() ?
&*FunctionWhitelist :
static_cast<const AddressWhitelist *>(nullptr)) {}
std::optional<std::map<MetaAddress, LDDTree::Symbol>>
Whitelist) :
Model(Model), WhitelistByAddress(std::move(Whitelist)) {}
public:
model::UpcastableType findType(DwarfID ID) {
@@ -46,11 +47,21 @@ public:
TupleTree<model::Binary> &getModel() { return Model; }
bool isFunctionAllowed(uint64_t Address) const {
if (FunctionWhitelist == nullptr)
bool isFunctionAllowed(const MetaAddress &Address) const {
if (not WhitelistByAddress.has_value())
return true;
return FunctionWhitelist->contains(Address);
return WhitelistByAddress->contains(Address);
}
bool isIfunc(const MetaAddress &Address) const {
if (not WhitelistByAddress.has_value())
return false;
auto It = WhitelistByAddress->find(Address);
if (It == WhitelistByAddress->end())
return false;
return It->second.IsIfunc;
}
public:
@@ -17,31 +17,29 @@
#include "revng/Model/Importer/Binary/BinaryDescriptor.h"
#include "revng/Model/Importer/Binary/BinaryImporterHelper.h"
#include "revng/Support/Configuration.h"
#include "revng/Support/LDDTree.h"
struct ImporterOptions;
class PDBImporter : public BinaryImporterHelper {
public:
using AddressWhitelist = std::set<uint64_t>;
private:
MetaAddress ImageBase;
llvm::pdb::PDBFile *ThePDBFile = nullptr;
llvm::pdb::NativeSession *TheNativeSession = nullptr;
std::unique_ptr<llvm::pdb::IPDBSession> Session;
std::optional<llvm::codeview::GUID> ExpectedGUID;
const AddressWhitelist *FunctionWhitelist = nullptr;
std::optional<std::map<MetaAddress, LDDTree::Symbol>> WhitelistByAddress;
public:
PDBImporter(TupleTree<model::Binary> &Model,
const MetaAddress &ImageBase,
const std::optional<AddressWhitelist> &FunctionWhitelist);
std::optional<std::map<MetaAddress, LDDTree::Symbol>> Whitelist);
PDBImporter(TupleTree<model::Binary> &Model,
const std::optional<AddressWhitelist> &FunctionWhitelist) :
std::optional<std::map<MetaAddress, LDDTree::Symbol>> Whitelist) :
PDBImporter(Model,
MetaAddress::fromGeneric(Model->Architecture(), 0),
FunctionWhitelist) {}
std::move(Whitelist)) {}
TupleTree<model::Binary> &getModel() { return Binary; }
const MetaAddress &getBaseAddress() { return ImageBase; }
@@ -56,10 +54,10 @@ public:
bool loadDataFromPDB(llvm::StringRef PDBFileName);
bool isFunctionAllowed(uint64_t Address) const {
if (FunctionWhitelist == nullptr)
bool isFunctionAllowed(const MetaAddress &Address) const {
if (not WhitelistByAddress.has_value())
return true;
return FunctionWhitelist->contains(Address);
return WhitelistByAddress->contains(Address);
}
};
+14 -6
View File
@@ -21,6 +21,7 @@
#include "revng/Model/OperatingSystem.h"
#include "revng/Support/Configuration.h"
#include "revng/Support/Debug.h"
#include "revng/Support/MetaAddress.h"
namespace revng {
class RootEntry;
@@ -34,7 +35,14 @@ concept IsObjectFile = std::derived_from<T, llvm::object::ObjectFile>;
class LDDTree {
public:
using SymbolSet = std::set<std::string>;
using SymbolAddressMap = std::map<std::string, uint64_t>;
struct Symbol {
MetaAddress Address = MetaAddress::invalid();
bool IsIfunc = false;
};
using SymbolMap = std::map<std::string, Symbol>;
class DependencyFile;
class Dependency;
@@ -217,14 +225,14 @@ public:
class LDDTree::Dependency : public DependencyFile {
private:
/// Subset of the requested symbols that are provided by this library.
SymbolAddressMap ProvidedSymbols;
SymbolMap ProvidedSymbols;
/// Identifier the library requesting this.
std::string RequestedBy;
public:
Dependency(DependencyFile &&TheDependencyFile,
SymbolAddressMap ProvidedSymbols,
SymbolMap ProvidedSymbols,
std::string RequestedBy) :
DependencyFile(std::move(TheDependencyFile)),
ProvidedSymbols(std::move(ProvidedSymbols)),
@@ -252,9 +260,9 @@ public:
Stream << " none\n";
} else {
Stream << "\n";
for (auto &[Name, Address] : ProvidedSymbols)
Stream << Prefix << " " << Name << " at 0x"
<< llvm::utohexstr(Address, true) << "\n";
for (auto &[Name, Symbol] : ProvidedSymbols)
Stream << Prefix << " " << Name << " at " << Symbol.Address.toString()
<< (Symbol.IsIfunc ? " (IFUNC)" : "") << "\n";
}
}
};
+45 -10
View File
@@ -366,7 +366,7 @@ Error ELFImporter<T, HasAddend>::import(const ImporterOptions &Options) {
Task.advance("Parse debug info", true);
{
auto ImportLogger = importLogger(TheBinary.canonicalPath());
DwarfImporter Importer(Model, std::nullopt);
DwarfImporter Importer(Model, SymbolsByAddress);
Importer.import(Root, TheBinary, AdjustedOptions);
}
@@ -717,6 +717,21 @@ uint64_t ELFImporter<T, HasAddend>::gnuHashSymbolCount() const {
return FirstSymbolIndex + *Index + 1;
}
template<typename T, bool HasAddend>
void ELFImporter<T, HasAddend>::recordSymbol(const MetaAddress &Address,
bool IsIfunc) {
revng_assert(Address.isValid());
auto Inserted = SymbolsByAddress
.try_emplace(Address,
LDDTree::Symbol{ .Address = Address,
.IsIfunc = IsIfunc })
.second;
if (not Inserted) {
revng_log(ELFImporterLog,
"Duplicate symbol entry at " << Address.toString() << " ignored");
}
}
// TODO: we might want to return an error from here so we can propagate it
// further up.
template<typename T, bool HasAddend>
@@ -771,6 +786,8 @@ void ELFImporter<T, HasAddend>::parseSymbols(object::ELFFile<T> &TheELF,
if (IsCode) {
revng_assert(Address.isValid());
recordSymbol(Address, Symbol.getType() == ELF::STT_GNU_IFUNC);
if (Model->Functions().tryGet(Address) == nullptr) {
auto *Function = registerFunctionEntry(Address);
if (Function != nullptr and MaybeName and MaybeName->size() > 0) {
@@ -950,9 +967,12 @@ void ELFImporter<T, HasAddend>::parseDynamicSymbol(Elf_Sym_Impl<T> &Symbol,
if (IsCode) {
Address = relocate(fromPC(Symbol.st_value));
revng_assert(Address.isValid());
recordSymbol(Address, Symbol.getType() == ELF::STT_GNU_IFUNC);
// TODO: record model::Function::IsDynamic = true
model::Function *Function = nullptr;
revng_assert(Address.isValid());
auto It = Model->Functions().find(Address);
if (It != Model->Functions().end()) {
Function = &*It;
@@ -1459,10 +1479,8 @@ Error importELF(TupleTree<model::Binary> &Model,
return Importer->import(Options);
}
std::vector<std::pair<std::string, uint64_t>>
LDDTree::SymbolMap
elfExportedSymbols(const llvm::object::ELFObjectFileBase &ObjectFile) {
std::vector<std::pair<std::string, uint64_t>> Result;
TupleTree<model::Binary> Model;
auto Architecture = model::Architecture::fromLLVMArchitecture(ObjectFile
.makeTriple()
@@ -1471,7 +1489,7 @@ elfExportedSymbols(const llvm::object::ELFObjectFileBase &ObjectFile) {
revng_log(ELFImporterLog,
"Cannot derive architecture for the ELF, skipping its "
"exported symbols");
return Result;
return {};
}
Model->Architecture() = Architecture;
@@ -1490,12 +1508,29 @@ elfExportedSymbols(const llvm::object::ELFObjectFileBase &ObjectFile) {
if (auto Error = Importer->parseDynamicSymbolsOnly()) {
revng_log(ELFImporterLog, "parseDynamicSymbolsOnly failed: " << Error);
consumeError(std::move(Error));
return Result;
return {};
}
for (model::Function &Function : Model->Functions())
for (const auto &Name : Function.ExportedNames())
Result.push_back({ Name, Function.Entry().asPC() });
// Project SymbolsByAddress through `ExportedNames()` to get the name-keyed
// dynamic-exports view. Function.Entry() already carries the typed
// MetaAddress, so the lookup against SymbolsByAddress is exact.
LDDTree::SymbolMap Result;
for (model::Function &Function : Model->Functions()) {
MetaAddress Address = Function.Entry();
auto It = Importer->SymbolsByAddress.find(Address);
auto End = Importer->SymbolsByAddress.end();
bool IsIfunc = It != End and It->second.IsIfunc;
for (const auto &Name : Function.ExportedNames()) {
LDDTree::Symbol Symbol{ .Address = Address, .IsIfunc = IsIfunc };
auto [Slot, Inserted] = Result.try_emplace(Name, Symbol);
if (not Inserted) {
// TODO: this should probably be invalid
revng_log(ELFImporterLog,
"Duplicate exported symbol " << Name << " ignored");
}
}
}
return Result;
}
+11 -1
View File
@@ -9,6 +9,7 @@
#include "revng/Model/Importer/Binary/BinaryImporterHelper.h"
#include "revng/Model/Importer/Binary/Options.h"
#include "revng/Model/RawBinaryView.h"
#include "revng/Support/LDDTree.h"
#include "revng/Support/MetaAddress.h"
#include "DwarfReader.h"
@@ -52,6 +53,12 @@ public:
};
class ELFImporterBase {
public:
/// Every defined function symbol encountered while parsing the static
/// and/or dynamic symbol tables, keyed by the relocated MetaAddress that
/// matches the function's entry in `Model->Functions()`.
std::map<MetaAddress, LDDTree::Symbol> SymbolsByAddress;
public:
virtual ~ELFImporterBase() = default;
@@ -161,6 +168,9 @@ private:
void parseDynamicSymbol(llvm::object::Elf_Sym_Impl<T> &Symbol,
llvm::StringRef Dynstr);
/// Record a defined code symbol in SymbolsByAddress, logging duplicates.
void recordSymbol(const MetaAddress &Address, bool IsIfunc);
protected:
template<typename Q>
using SmallVectorImpl = llvm::SmallVectorImpl<Q>;
@@ -186,5 +196,5 @@ protected:
/// Enumerate the function symbols exported through the dynamic symbol table
/// of an ELF binary
std::vector<std::pair<std::string, uint64_t>>
LDDTree::SymbolMap
elfExportedSymbols(const llvm::object::ELFObjectFileBase &ObjectFile);
+1 -2
View File
@@ -116,8 +116,7 @@ public:
using QueueEntry = typename Queue<ResolutionInfo>::Entry;
public:
static std::vector<std::pair<std::string, uint64_t>>
getExportedSymbols(const T &ELFObjectFile) {
static LDDTree::SymbolMap getExportedSymbols(const T &ELFObjectFile) {
return elfExportedSymbols(ELFObjectFile);
}
+7 -7
View File
@@ -82,13 +82,13 @@ void findMissingTypes(LDDTree &Dependencies,
Dependency.fullPathForExternalTools(),
BinaryReference);
std::optional<std::set<uint64_t>> RequestedFunctions;
RequestedFunctions.emplace();
for (const auto &[Name, Address] : Dependency.providedSymbols()) {
RequestedFunctions->insert(Address);
std::optional<std::map<MetaAddress, LDDTree::Symbol>> Whitelist;
Whitelist.emplace();
for (const auto &[Name, Symbol] : Dependency.providedSymbols()) {
// TODO: usually this reponsability is demanded to BinaryImporterHelper
auto FunctionAddress = MetaAddress::fromPC(Binary->Architecture(),
Options.BaseAddress + Address);
auto FunctionAddress = Symbol.Address + Options.BaseAddress;
(*Whitelist)[FunctionAddress] = Symbol;
auto &Function = DependencyModel->Functions()[FunctionAddress];
Function.Name() = Name;
Function.ExportedNames().insert(Name);
@@ -97,7 +97,7 @@ void findMissingTypes(LDDTree &Dependencies,
ImportLogger ImportLogger(DependencyModel,
Logger,
TheBinary.canonicalPath());
ImporterType Importer(DependencyModel, RequestedFunctions);
ImporterType Importer(DependencyModel, std::move(Whitelist));
Importer.import(Dependencies.Root, TheBinary, AdjustedOptions);
revng_log(Logger, DependencyName << " imported successfully");
@@ -74,9 +74,7 @@ concept LDDTreeObjectFileTraitsConcept = requires(T Trait,
&Root) {
typename T::ResolutionInfo;
{
T::getExportedSymbols(Object)
} -> std::same_as<std::vector<std::pair<std::string, uint64_t>>>;
{ T::getExportedSymbols(Object) } -> std::same_as<LDDTree::SymbolMap>;
{
T::getDependencies(Root, String, String, Object)
@@ -220,15 +218,15 @@ const LDDTree LDDTree::fromPath(const revng::RootEntry &Root,
continue;
}
LDDTree::SymbolAddressMap ProvidedSymbols;
LDDTree::SymbolMap ProvidedSymbols;
// Purge from MissingSymbols those exported
if (SymbolsRequested) {
for (auto &[SymbolName, SymbolAddress] :
for (auto &[SymbolName, SymbolData] :
ObjectFileTraits::getExportedSymbols(*Binary)) {
if (Result.MissingSymbols->contains(SymbolName)) {
Result.MissingSymbols->erase(SymbolName);
ProvidedSymbols[SymbolName] = SymbolAddress;
ProvidedSymbols[SymbolName] = SymbolData;
}
}
}
+12 -3
View File
@@ -34,9 +34,14 @@ public:
using QueueEntry = typename Queue<ResolutionInfo>::Entry;
public:
static std::vector<std::pair<std::string, uint64_t>>
static LDDTree::SymbolMap
getExportedSymbols(const COFFObjectFile &COFFObjectFile) {
std::vector<std::pair<std::string, uint64_t>> Result;
LDDTree::SymbolMap Result;
auto FromLLVMArchitecture = model::Architecture::fromLLVMArchitecture;
auto Architecture = FromLLVMArchitecture(COFFObjectFile.getArch());
if (Architecture == model::Architecture::Invalid)
return Result;
for (const ExportDirectoryEntryRef &Entry :
COFFObjectFile.export_directories()) {
@@ -56,7 +61,11 @@ public:
continue;
}
Result.push_back({ SymbolName.str(), RVA });
MetaAddress Address = MetaAddress::fromPC(Architecture, RVA);
if (not Address.isValid())
continue;
Result[SymbolName.str()] = LDDTree::Symbol{ .Address = Address };
}
return Result;
@@ -861,6 +861,33 @@ DwarfToModelConverter::getSubprogramPrototype(const DWARFDie &InitialDie) {
return Model->recordNewType(std::move(NewType)).second;
}
/// Substitute a glibc IFUNC resolver prototype (no args, returns a pointer
/// to a CABIFunctionDefinition) with the pointee prototype.
static model::UpcastableType
unwrapIfuncResolverPrototype(model::Binary &Binary,
const MetaAddress &Address,
model::UpcastableType Prototype) {
auto *Definition = Prototype->tryGetAsDefinition();
auto *Resolver = dyn_cast_or_null<model::CABIFunctionDefinition>(Definition);
if (Resolver == nullptr or not Resolver->Arguments().empty()
or Resolver->ReturnType().isEmpty()
or not Resolver->ReturnType()->isPointer())
return Prototype;
auto *PointeeDefinition = Resolver->ReturnType()
->getPointee()
.tryGetAsDefinition();
if (not isa_and_nonnull<model::CABIFunctionDefinition>(PointeeDefinition))
return Prototype;
revng_log(DILogger,
"Ifunc resolver at " << Address.toString()
<< ": substituting resolver prototype "
<< Resolver->ID() << " with pointee CABI "
<< PointeeDefinition->ID());
return Binary.makeType(PointeeDefinition->key());
}
void DwarfToModelConverter::createFunctions() {
revng_log(DILogger, "createFunctions");
LoggerIndent Indent(DILogger);
@@ -879,8 +906,13 @@ void DwarfToModelConverter::createFunctions() {
if (auto MaybeLowPC = getAddress(Die)) {
// TODO: do a proper check to see if it's in a valid segment
if (*MaybeLowPC != 0) {
if (Importer.isFunctionAllowed(*MaybeLowPC)) {
LowPC = relocate(fromPC(*MaybeLowPC));
// Relocate the raw DWARF address first, then let matchFunctionEntry
// pick the code type that matches the model.
uint64_t Relocated = relocate(*MaybeLowPC).address();
MetaAddress Match = matchFunctionEntry(Relocated,
Model->Architecture());
if (Match.isValid() and Importer.isFunctionAllowed(Match)) {
LowPC = Match;
} else {
revng_log(DILogger,
"Ignoring disallowed function at 0x"
@@ -903,46 +935,44 @@ void DwarfToModelConverter::createFunctions() {
<< LowPC.toString() << " and name \"" << SymbolName
<< "\"");
// Get/create the local function
// Note: here we use matchFunctionEntry because, just being fed the
// DWARF, we don't have enough information to determine whether this
// function is regular ARM or is Thumb.
// matchFunctionEntry relies on previously available functions to
// determine this. DwarfToModelConverter should not use without
// processing ELF symbols first.
// Newer DWARF versions have DW_LNS_set_isa, but currently we can't rely
// on that.
if (auto *Function = matchFunctionEntry(LowPC)) {
// Use the existing model::Function or create a new one at LowPC.
auto &Function = Model->Functions()[LowPC];
if (Prototype.isEmpty()) {
revng_log(DILogger, "Can't get the prototype");
} else if (not Function->prototype()) {
revng_log(DILogger,
"Assigning prototype "
<< Prototype->tryGetAsDefinition()->ID());
Function->Prototype() = std::move(Prototype);
if (Prototype.isEmpty()) {
revng_log(DILogger, "Can't get the prototype");
} else if (not Function.prototype()) {
// For STT_GNU_IFUNC the DWARF describes the resolver, not the
// resolved function; unwrap it.
if (Importer.isIfunc(LowPC))
Prototype = unwrapIfuncResolverPrototype(*Model,
LowPC,
std::move(Prototype));
revng_log(DILogger,
"Assigning prototype "
<< Prototype->tryGetAsDefinition()->ID());
Function.Prototype() = std::move(Prototype);
} else {
revng_log(DILogger,
"Function already has a prototype, not setting it.");
}
if (SymbolName.size() != 0) {
// Note: DWARF support
if (Function.Name().empty()) {
Function.Name() = SymbolName;
} else {
revng_log(DILogger,
"Function already has a prototype, not setting it.");
"Function already has a name: " << Function.Name()
<< ". Not updating "
"it.");
}
if (SymbolName.size() != 0) {
// Note: DWARF support
if (Function->Name().empty()) {
Function->Name() = SymbolName;
} else {
revng_log(DILogger,
"Function already has a name: " << Function->Name()
<< ". Not updating "
"it.");
}
Function->ExportedNames().insert(SymbolName);
}
if (isNoReturn(*CU.get(), Die))
Function->Attributes().insert(model::FunctionAttribute::NoReturn);
Function.ExportedNames().insert(SymbolName);
}
if (isNoReturn(*CU.get(), Die))
Function.Attributes().insert(model::FunctionAttribute::NoReturn);
} else if (not SymbolName.empty()
and DynamicFunctions.contains(SymbolName)) {
// It's a dynamic function
+3 -5
View File
@@ -32,15 +32,13 @@ using namespace llvm::pdb;
PDBImporter::PDBImporter(TupleTree<model::Binary> &Model,
const MetaAddress &ImageBase,
const std::optional<AddressWhitelist>
&FunctionWhitelist) :
std::optional<std::map<MetaAddress, LDDTree::Symbol>>
Whitelist) :
BinaryImporterHelper(Model,
ImageBase.isValid() ? ImageBase.address() : 0,
Log),
ImageBase(ImageBase),
FunctionWhitelist(FunctionWhitelist.has_value() ?
&*FunctionWhitelist :
static_cast<const AddressWhitelist *>(nullptr)) {
WhitelistByAddress(std::move(Whitelist)) {
// When we import debug info, we assume we already have parsed Segments
processSegments();
@@ -693,15 +693,16 @@ void PDBImporterImpl::handleProcedureSymbol(ProcSym &Procedure) {
Procedure
.CodeOffset);
if (not Importer.isFunctionAllowed(FunctionVirtualAddress)) {
revng_log(Log, "Ignoring disallowed function");
return;
}
// Relocate the symbol.
MetaAddress FunctionAddress = Importer.toPC(Importer.getBaseAddress()
+ FunctionVirtualAddress);
if (not FunctionAddress.isValid()
or not Importer.isFunctionAllowed(FunctionAddress)) {
revng_log(Log, "Ignoring disallowed function");
return;
}
if (not Model->Functions().contains(FunctionAddress)) {
if (auto *Function = Importer.registerFunctionEntry(FunctionAddress)) {
revng_log(Log, "New function registered");