mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
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:
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user