Introduce ImportPrototypesFromDatabase

This commit introduces an analysis to import prototypes from a SQLite
database of well-known prototypes, typically built from debug info of
operating systems.

This analysis supersedes import-well-known-models.
This commit is contained in:
Alessandro Di Federico
2026-04-07 16:22:11 +02:00
parent 09dfccec91
commit ee3bb0dfb0
15 changed files with 598 additions and 174 deletions
-29
View File
@@ -292,35 +292,6 @@ foreach(
strip-dead-debug-info)
endforeach()
# Produce well-known-models
file(
GLOB
WELL_KNOWN_BINARIES
"${CMAKE_INSTALL_PREFIX}/share/revng/test/tests/well-known-models/*revng-qa.compiled-with-debug*"
)
add_custom_target(well-known-binaries ALL)
foreach(WELL_KNOWN_BINARY IN LISTS WELL_KNOWN_BINARIES)
get_filename_component(BASENAME "${WELL_KNOWN_BINARY}" NAME)
set(MODEL_PATH "share/revng/well-known-models/${BASENAME}.yml")
set(FULL_MODEL_PATH "${CMAKE_BINARY_DIR}/${MODEL_PATH}")
add_custom_command(
OUTPUT "${FULL_MODEL_PATH}"
COMMAND "./bin/revng" analyze import-binary -o "${FULL_MODEL_PATH}"
"${WELL_KNOWN_BINARY}"
MAIN_DEPENDENCY "${WELL_KNOWN_BINARY}"
DEPENDS revng-all-binaries generate-revngModel-tuple-tree-code
generate-revngPipeline-tuple-tree-code
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
add_custom_target("import-${BASENAME}" DEPENDS "${FULL_MODEL_PATH}")
add_dependencies(well-known-binaries "import-${BASENAME}")
endforeach()
# Custom command to create .clang-format file from revng-check-conventions
add_custom_command(
OUTPUT "${CMAKE_BINARY_DIR}/share/revng/.clang-format"
@@ -9,9 +9,9 @@
namespace revng::pypeline::analyses {
class ImportWellKnownModelsAnalysis {
class ImportPrototypesFromDatabase {
public:
static constexpr llvm::StringRef Name = "import-well-known-models";
static constexpr llvm::StringRef Name = "import-prototypes-from-db";
llvm::Error
run(Model &Model, const Request &Incoming, llvm::StringRef Configuration);
+11 -3
View File
@@ -2,10 +2,18 @@
# This file is distributed under the MIT License. See LICENSE.md for details.
#
revng_add_analyses_library_internal(revngModelImporter WellKnownModels.cpp)
revng_add_analyses_library_internal(revngModelImporter
ImportPrototypesFromDatabase.cpp)
target_link_libraries(revngModelImporter revngModel revngModelPasses
revngPipeline ${LLVM_LIBRARIES})
target_link_libraries(
revngModelImporter
revngModel
revngModelPasses
revngPipeline
revngPipes
revngSupport
${LLVM_LIBRARIES}
sqlite3)
add_subdirectory(Binary)
add_subdirectory(DebugInfo)
@@ -0,0 +1,470 @@
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <map>
#include <string>
#include <vector>
#include "revng/Model/Architecture.h"
#include "revng/Model/Binary.h"
#include "revng/Model/Importer/ImportPrototypesFromDatabase.h"
#include "revng/Model/Importer/TypeCopier.h"
#include "revng/Model/Pass/DeduplicateCollidingNames.h"
#include "revng/Model/Pass/DeduplicateEquivalentTypes.h"
#include "revng/Model/Pass/FlattenPrimitiveTypedefs.h"
#include "revng/Pipeline/RegisterAnalysis.h"
#include "revng/Pipes/ModelGlobal.h"
#include "revng/Support/Debug.h"
#include "revng/Support/ResourceFinder.h"
#include "revng/Support/SQLite.h"
static Logger Log("import-prototypes-from-db");
/// Turn a TypeDefinition body (flat YAML mapping) into a YAML list item
/// indented for inclusion under a top-level key.
///
/// Input (each line at column 0):
/// ID: 123
/// Kind: CABIFunctionDefinition
/// ...
///
/// Output:
/// - ID: 123
/// Kind: CABIFunctionDefinition
/// ...
static std::string indentAsListItem(llvm::StringRef Body) {
std::string Result;
llvm::raw_string_ostream Stream(Result);
bool FirstLine = true;
while (not Body.empty()) {
auto [Line, Rest] = Body.split('\n');
if (FirstLine) {
Stream << " - " << Line << "\n";
FirstLine = false;
} else if (not Line.empty()) {
Stream << " " << Line << "\n";
}
Body = Rest;
if (Body.empty() && Line.empty())
break;
}
return Result;
}
struct LibraryInfo {
int64_t LibraryID;
std::string Header;
};
class PrototypeDatabase {
sqlite::Database Database;
public:
PrototypeDatabase(llvm::StringRef Path) : Database(Path) {}
/// Find a platform by its exact name.
/// Returns -1 if no platform with that name exists.
int64_t findPlatformByName(llvm::StringRef PlatformName) {
auto Statement = Database.makeStatement("SELECT PlatformID FROM Platform "
"WHERE Name = ?1");
Statement.bind(1, PlatformName);
int64_t PlatformID = -1;
for (auto [ID] : Statement.execute<int64_t>())
PlatformID = ID;
return PlatformID;
}
/// Find the platform that resolves the most symbols among those compatible
/// with the given architecture and operating system.
/// Returns -1 if no matching platform is found.
int64_t electPlatform(const std::vector<std::string> &SymbolNames,
llvm::StringRef ArchitectureName,
llvm::StringRef OperatingSystemName) {
std::string SymbolPlaceholders = sqlite::buildInClause(SymbolNames.size());
int ArchitectureParamIndex = SymbolNames.size() + 1;
int OperatingSystemParamIndex = SymbolNames.size() + 2;
std::string Query;
{
llvm::raw_string_ostream Stream(Query);
Stream << R"(
SELECT p.PlatformID, COUNT(DISTINCT s.Name) AS SymbolCount
FROM Platform p
JOIN Library l ON l.PlatformID = p.PlatformID
JOIN Symbol s ON s.LibraryID = l.LibraryID
WHERE p.Architecture = ?)"
<< ArchitectureParamIndex << R"(
AND p.OperatingSystem = ?)"
<< OperatingSystemParamIndex << R"(
AND s.Name IN ()"
<< SymbolPlaceholders << R"()
GROUP BY p.PlatformID
ORDER BY SymbolCount DESC
LIMIT 1
)";
}
auto Statement = Database.makeStatement(Query);
Statement.bind(SymbolNames);
Statement.bind(ArchitectureParamIndex, ArchitectureName);
Statement.bind(OperatingSystemParamIndex, OperatingSystemName);
int64_t PlatformID = -1;
for (auto [ID, Count] : Statement.execute<int64_t, int64_t>())
PlatformID = ID;
return PlatformID;
}
/// Enumerate libraries on the given platform that provide at least one of
/// the requested symbols.
std::vector<LibraryInfo>
enumerateLibraries(int64_t PlatformID,
const std::vector<std::string> &SymbolNames) {
std::string SymbolPlaceholders = sqlite::buildInClause(SymbolNames.size());
int PlatformParamIndex = SymbolNames.size() + 1;
std::string Query;
{
llvm::raw_string_ostream Stream(Query);
Stream << R"(
SELECT DISTINCT l.LibraryID, l.Header
FROM Library l
JOIN Symbol s ON s.LibraryID = l.LibraryID
WHERE l.PlatformID = ?)"
<< PlatformParamIndex << R"(
AND s.Name IN ()"
<< SymbolPlaceholders << R"()
)";
}
auto Statement = Database.makeStatement(Query);
Statement.bind(SymbolNames);
Statement.bind(PlatformParamIndex, static_cast<int>(PlatformID));
std::vector<LibraryInfo> Libraries;
for (auto [LibraryID, HeaderText] :
Statement.execute<int64_t, llvm::StringRef>())
Libraries.push_back({ LibraryID, HeaderText.str() });
return Libraries;
}
/// Build a model from a single library's symbols and type definitions,
/// parse it, then use a TypeCopier to import the prototypes into Binary.
///
/// OriginalIDs in type definition bodies are scoped per-library, so each
/// library must be imported independently.
void importLibrary(const LibraryInfo &Library,
const std::vector<std::string> &SymbolNames,
TupleTree<model::Binary> &Binary) {
std::string SymbolPlaceholders = sqlite::buildInClause(SymbolNames.size());
int LibraryParamIndex = SymbolNames.size() + 1;
// Query type definitions for this library
std::string TypeDefinitionsQuery;
{
llvm::raw_string_ostream Stream(TypeDefinitionsQuery);
Stream << R"(
WITH RECURSIVE DependentTypeDefinitions AS ( --
SELECT td.TypeDefinitionID, td.Body, td.OriginalID
FROM TypeDefinition td
JOIN Symbol s ON s.TypeDefinitionID = td.TypeDefinitionID
WHERE s.LibraryID = ?)"
<< LibraryParamIndex << R"(
AND s.Name IN ()"
<< SymbolPlaceholders << R"()
UNION
SELECT t.TypeDefinitionID, t.Body, t.OriginalID
FROM TypeDefinition t
JOIN TypeDefinitionDependencies dependency
ON dependency.SourceTypeDefinitionID = t.TypeDefinitionID
JOIN DependentTypeDefinitions dt
ON dependency.DestinationTypeDefinitionID = dt.TypeDefinitionID
)
SELECT DISTINCT Body, OriginalID
FROM DependentTypeDefinitions
ORDER BY OriginalID
)";
}
auto TypeDefinitionsStatement = Database
.makeStatement(TypeDefinitionsQuery);
TypeDefinitionsStatement.bind(SymbolNames);
TypeDefinitionsStatement.bind(LibraryParamIndex,
static_cast<int>(Library.LibraryID));
struct TypeInfo {
std::string Body;
int64_t OriginalID;
std::string Kind;
};
std::vector<TypeInfo> TypeDefinitions;
std::map<int64_t, std::string> OriginalIDToKind;
for (auto [Body, OriginalID] :
TypeDefinitionsStatement.execute<llvm::StringRef, int64_t>()) {
std::string BodyString = Body.str();
// Extract Kind from the YAML body
std::string Kind;
llvm::StringRef BodyReference(BodyString);
while (not BodyReference.empty()) {
auto [Line, Rest] = BodyReference.split('\n');
if (Line.starts_with("Kind: ")) {
Kind = Line.substr(6).str();
break;
}
BodyReference = Rest;
}
OriginalIDToKind[OriginalID] = Kind;
TypeDefinitions.push_back({ std::move(BodyString), OriginalID, Kind });
}
revng_log(Log, "Found " << TypeDefinitions.size() << " type definitions");
// Query symbols for this library
std::string SymbolsQuery;
{
llvm::raw_string_ostream Stream(SymbolsQuery);
Stream << R"(
SELECT s.Name, COALESCE(td.OriginalID, -1)
FROM Symbol s
LEFT JOIN TypeDefinition td
ON s.TypeDefinitionID = td.TypeDefinitionID
WHERE s.LibraryID = ?)"
<< LibraryParamIndex << R"(
AND s.Name IN ()"
<< SymbolPlaceholders << R"()
)";
}
auto SymbolsStatement = Database.makeStatement(SymbolsQuery);
SymbolsStatement.bind(SymbolNames);
SymbolsStatement.bind(LibraryParamIndex,
static_cast<int>(Library.LibraryID));
struct SymbolInfo {
std::string Name;
int64_t OriginalID;
bool HasType;
};
std::vector<SymbolInfo> Symbols;
for (auto [Name, OriginalID] :
SymbolsStatement.execute<llvm::StringRef, int64_t>()) {
bool HasType = OriginalID >= 0 and OriginalIDToKind.count(OriginalID) > 0;
Symbols.push_back({ Name.str(), OriginalID, HasType });
}
if (Symbols.empty()) {
revng_log(Log, "No matching symbols found");
return;
}
revng_log(Log, "Found " << Symbols.size() << " matching symbols");
// Compose the model YAML for this library
std::string ModelYAML;
llvm::raw_string_ostream YAMLStream(ModelYAML);
YAMLStream << "---\n";
llvm::StringRef HeaderReference(Library.Header);
HeaderReference = HeaderReference.rtrim();
YAMLStream << HeaderReference << "\n";
YAMLStream << "ImportedDynamicFunctions:\n";
for (const auto &Symbol : Symbols) {
YAMLStream << " - Name: " << Symbol.Name << "\n";
if (Symbol.HasType) {
auto KindIterator = OriginalIDToKind.find(Symbol.OriginalID);
if (KindIterator != OriginalIDToKind.end()) {
YAMLStream << " Prototype:\n";
YAMLStream << " Kind: DefinedType\n";
YAMLStream << " Definition: \"/TypeDefinitions/"
<< Symbol.OriginalID << "-" << KindIterator->second
<< "\"\n";
}
}
}
if (not TypeDefinitions.empty()) {
YAMLStream << "TypeDefinitions:\n";
for (const auto &TypeDefinition : TypeDefinitions)
YAMLStream << indentAsListItem(TypeDefinition.Body);
}
YAMLStream << "...\n";
YAMLStream.flush();
// Parse the composed YAML into a model
auto MaybeModel = TupleTree<model::Binary>::fromString(ModelYAML);
if (not MaybeModel) {
revng_log(Log, "Failed to parse composed model YAML");
llvm::consumeError(MaybeModel.takeError());
return;
}
// Use TypeCopier to import prototypes into the destination model.
// The copier is fully created, used, and finalized within this scope.
TupleTree<model::Binary> &ParsedModel = *MaybeModel;
TypeCopier Copier(ParsedModel, Binary);
unsigned ImportedCount = 0;
auto CopyPrototype = [&](auto &Function) {
if (Function.prototype() != nullptr or Function.Name().empty())
return;
auto Iterator = ParsedModel->ImportedDynamicFunctions()
.find(Function.Name());
if (Iterator == ParsedModel->ImportedDynamicFunctions().end())
return;
if (const auto *Prototype = Iterator->prototype()) {
Function.Prototype() = Copier.copyTypeInto(*Prototype);
++ImportedCount;
revng_log(Log, "Imported prototype for " << Function.Name());
}
};
for (auto &Function : Binary->Functions())
CopyPrototype(Function);
for (auto &DynamicFunction : Binary->ImportedDynamicFunctions())
CopyPrototype(DynamicFunction);
Copier.finalize();
revng_log(Log, "Imported " << ImportedCount << " prototypes");
}
/// Main entry point: find the database, collect symbols without prototypes,
/// elect a platform, and import prototypes from each library.
static void run(TupleTree<model::Binary> &Binary) {
revng_log(Log, "Starting prototype import from database");
LoggerIndent Indent(Log);
// Find the database
using revng::ResourceFinder;
auto MaybeDbPath = ResourceFinder.findFile("share/revng/prototypes.sqlite");
if (not MaybeDbPath) {
revng_log(Log, "Database not found, skipping");
return;
}
revng_log(Log, "Using database: " << *MaybeDbPath);
PrototypeDatabase Database(*MaybeDbPath);
// Collect symbol names from functions without a prototype
std::vector<std::string> SymbolNames;
for (const auto &Function : Binary->Functions())
if (Function.prototype() == nullptr and not Function.Name().empty())
SymbolNames.push_back(Function.Name());
for (const auto &DynamicFunction : Binary->ImportedDynamicFunctions())
if (DynamicFunction.prototype() == nullptr
and not DynamicFunction.Name().empty())
SymbolNames.push_back(DynamicFunction.Name());
if (SymbolNames.empty()) {
revng_log(Log, "No functions without prototypes, skipping");
return;
}
revng_log(Log,
"Collected " << SymbolNames.size()
<< " symbols without prototypes");
// Phase 1: elect the best platform.
// If PlatformName is set, try to find it by name first.
int64_t PlatformID = -1;
if (not Binary->PlatformName().empty()) {
revng_log(Log, "Looking up platform by name: " << Binary->PlatformName());
PlatformID = Database.findPlatformByName(Binary->PlatformName());
}
if (PlatformID < 0) {
using namespace model;
auto ArchitectureName = Architecture::getName(Binary->Architecture());
auto OperatingSystem = Binary->OperatingSystem();
auto OperatingSystemName = OperatingSystem::getName(OperatingSystem);
revng_log(Log,
"Electing platform for " << ArchitectureName << "/"
<< OperatingSystemName);
PlatformID = Database.electPlatform(SymbolNames,
ArchitectureName,
OperatingSystemName);
}
if (PlatformID < 0) {
revng_log(Log, "No matching platform found, skipping");
return;
}
revng_log(Log, "Selected platform ID: " << PlatformID);
// Phase 2: enumerate libraries with matching symbols
auto Libraries = Database.enumerateLibraries(PlatformID, SymbolNames);
if (Libraries.empty()) {
revng_log(Log, "No libraries with matching symbols found");
return;
}
revng_log(Log, "Found " << Libraries.size() << " libraries to import");
// Phase 3: import each library independently
for (const auto &Library : Libraries) {
revng_log(Log, "Importing library " << Library.LibraryID);
LoggerIndent LibraryIndent(Log);
Database.importLibrary(Library, SymbolNames, Binary);
}
model::flattenPrimitiveTypedefs(Binary);
deduplicateEquivalentTypes(Binary);
model::deduplicateCollidingNames(Binary);
revng_log(Log, "Import complete");
}
};
namespace revng::pypeline::analyses {
llvm::Error ImportPrototypesFromDatabase::run(Model &TheModel,
const Request &Incoming,
llvm::StringRef Configuration) {
PrototypeDatabase::run(TheModel.get());
return llvm::Error::success();
}
} // namespace revng::pypeline::analyses
namespace {
class ImportPrototypesFromDatabasePipelineAnalysis {
public:
static constexpr auto Name = "import-prototypes-from-db";
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds;
void run(pipeline::ExecutionContext &Context) {
TupleTree<model::Binary>
&Model = revng::getWritableModelFromContext(Context);
PrototypeDatabase::run(Model);
}
};
} // namespace
static pipeline::RegisterAnalysis<ImportPrototypesFromDatabasePipelineAnalysis>
RegisterImportPrototypesFromDatabase;
-131
View File
@@ -1,131 +0,0 @@
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "revng/Model/Binary.h"
#include "revng/Model/Importer/TypeCopier.h"
#include "revng/Model/Importer/WellKnownModels.h"
#include "revng/Model/Pass/DeduplicateCollidingNames.h"
#include "revng/Model/Pass/FlattenPrimitiveTypedefs.h"
#include "revng/Pipeline/RegisterAnalysis.h"
#include "revng/Pipes/ModelGlobal.h"
#include "revng/Support/ResourceFinder.h"
namespace revng::pipes {
class WellKnownFunctionKey {
public:
model::Architecture::Values Architecture;
model::ABI::Values ABI;
std::string Name;
private:
auto tie() const { return std::tie(Architecture, ABI, Name); }
public:
bool operator<(const WellKnownFunctionKey &Other) const {
return tie() < Other.tie();
}
};
class WellKnownModel {
public:
TupleTree<model::Binary> FromModel;
TypeCopier Copier;
public:
WellKnownModel(TupleTree<model::Binary> &&FromModel,
TupleTree<model::Binary> &DestinationModel) :
FromModel(FromModel), Copier(this->FromModel, DestinationModel) {}
};
class ImportWellKnownModelsAnalysis {
public:
static constexpr auto Name = "import-well-known-models";
public:
std::vector<std::vector<pipeline::Kind *>> AcceptedKinds;
public:
void run(pipeline::ExecutionContext &Context);
};
} // namespace revng::pipes
static void importWellKnownModels(TupleTree<model::Binary> &Model) {
using namespace revng::pipes;
std::vector<std::unique_ptr<WellKnownModel>> WellKnownModels;
std::map<WellKnownFunctionKey, std::pair<WellKnownModel *, model::Function *>>
WellKnownFunctions;
// Load all well-known models
for (const std::string &Path :
revng::ResourceFinder.list("share/revng/well-known-models", ".yml")) {
auto NewModel = llvm::cantFail(TupleTree<model::Binary>::fromFile(Path));
auto NewWKM = std::make_unique<WellKnownModel>(std::move(NewModel), Model);
WellKnownModels.push_back(std::move(NewWKM));
}
// Create an index of well-known functions
for (auto &WellKnownModel : WellKnownModels) {
auto &Model = WellKnownModel->FromModel;
// Collect exported functions
for (model::Function &F : Model->Functions()) {
for (const std::string &ExportedName : F.ExportedNames()) {
WellKnownFunctions[{
Model->Architecture(), Model->DefaultABI(), ExportedName }] = {
WellKnownModel.get(), &F
};
}
}
}
for (model::DynamicFunction &F : Model->ImportedDynamicFunctions()) {
// Compose the key
WellKnownFunctionKey Key = { Model->Architecture(),
Model->DefaultABI(),
F.Name() };
// See if it's a well-known function
auto It = WellKnownFunctions.find(Key);
if (It != WellKnownFunctions.end()) {
model::Function *WellKnownFunction = It->second.second;
// Copy attributes
F.Attributes() = WellKnownFunction->Attributes();
// Copy prototype
if (const auto *NewPrototype = WellKnownFunction->prototype()) {
TypeCopier &Copier = It->second.first->Copier;
F.Prototype() = Copier.copyTypeInto(*NewPrototype);
}
}
}
for (auto &WLF : WellKnownModels)
WLF->Copier.finalize();
model::flattenPrimitiveTypedefs(Model);
model::deduplicateCollidingNames(Model);
}
void revng::pipes::ImportWellKnownModelsAnalysis::run(pipeline::ExecutionContext
&Context) {
TupleTree<model::Binary> &Model = getWritableModelFromContext(Context);
importWellKnownModels(Model);
}
static pipeline::RegisterAnalysis<revng::pipes::ImportWellKnownModelsAnalysis>
E;
namespace revng::pypeline::analyses {
llvm::Error ImportWellKnownModelsAnalysis::run(Model &Model,
const Request &Incoming,
llvm::StringRef Configuration) {
importWellKnownModels(Model.get());
return llvm::Error::success();
}
} // namespace revng::pypeline::analyses
+2 -2
View File
@@ -26,7 +26,7 @@
#include "revng/Lift/Lift.h"
#include "revng/Lift/LinkSupportPipe.h"
#include "revng/Model/Importer/Binary/ImportBinaryAnalysis.h"
#include "revng/Model/Importer/WellKnownModels.h"
#include "revng/Model/Importer/ImportPrototypesFromDatabase.h"
#include "revng/Pipebox/LLVMPipe.h"
#include "revng/Pipebox/MLIRPipe.h"
#include "revng/Pipebox/MergeLLVMModules.h"
@@ -138,7 +138,7 @@ static RegisterAnalysis<VerifyDiff> A2;
static RegisterAnalysis<SetModel> A3;
static RegisterAnalysis<VerifyModel> A4;
static RegisterAnalysis<ParseBinaryAnalysis> A5;
static RegisterAnalysis<ImportWellKnownModelsAnalysis> A6;
static RegisterAnalysis<ImportPrototypesFromDatabase> A6;
static RegisterAnalysis<DetectABI> A7;
static RegisterAnalysis<DetectStackSize> A8;
static RegisterAnalysis<AnalyzeDataLayout> A9;
+2 -2
View File
@@ -65,7 +65,7 @@ analyses:
- verify-diff
- set-model
- verify-model
- import-well-known-models
- import-prototypes-from-db
- convert-functions-to-cabi
- import-from-c
@@ -73,7 +73,7 @@ analysis-lists:
- name: initial-auto-analysis
analyses:
- parse-binary
- import-well-known-models
- import-prototypes-from-db
- detect-abi
- detect-stack-size
- analyze-data-layout
+4 -5
View File
@@ -88,12 +88,11 @@ Branches:
From debug information, all the data structures and function
prototypes are imported.
We currently support DWARF and CodeView (`.pdb`) debug info.
- Name: import-well-known-models
Type: import-well-known-models
- Name: import-prototypes-from-db
Type: import-prototypes-from-db
UsedContainers: []
Docs: |-
Import the prototype of certain well-known functions from the C
standard library.
Import function prototypes from a database.
- Name: convert-functions-to-cabi
Type: convert-functions-to-cabi
UsedContainers: []
@@ -725,7 +724,7 @@ AnalysesLists:
- Name: revng-initial-auto-analysis
Analyses:
- import-binary
- import-well-known-models
- import-prototypes-from-db
- detect-abi
- detect-stack-size
- analyze-data-layout
@@ -0,0 +1,25 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
tags:
- name: import-prototypes-from-db
sources:
- tags: [import-prototypes-from-db]
prefix: share/revng/test/tests/import-prototypes-from-db
members:
- windows-x86-64.yml
- arch-mismatch.yml
- platform-name.yml
commands:
- type: revng-db.import-prototypes-from-db-test
from:
- type: source
filter: import-prototypes-from-db
command: |-
revng analyze import-prototypes-from-db /dev/null
--model "$INPUT"
| revng model opt -verify
| FileCheck "${SOURCE}.filecheck"
@@ -0,0 +1,10 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
---
Architecture: arm
OperatingSystem: Windows
ImportedDynamicFunctions:
- Name: CreateFileW
- Name: ExitProcess
@@ -0,0 +1,10 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
# No matching platform for arm/Windows, so no prototypes should be imported
CHECK: - Name:{{.*}}CreateFileW
CHECK-NOT: Prototype:
CHECK: - Name:{{.*}}ExitProcess
CHECK-NOT: Prototype:
CHECK-NOT: TypeDefinitions:
@@ -0,0 +1,11 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
---
Architecture: x86_64
OperatingSystem: Windows
PlatformName: windows-pdb
ImportedDynamicFunctions:
- Name: ExitProcess
- Name: GetLastError
@@ -0,0 +1,15 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
# Verify that PlatformName direct lookup works
CHECK: - Name:{{.*}}ExitProcess
CHECK-NEXT: Prototype:
CHECK-NEXT: Kind:{{.*}}DefinedType
CHECK: - Name:{{.*}}GetLastError
CHECK-NEXT: Prototype:
CHECK-NEXT: Kind:{{.*}}DefinedType
CHECK: TypeDefinitions:
CHECK: Kind:{{.*}}CABIFunctionDefinition
@@ -0,0 +1,12 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
---
Architecture: x86_64
OperatingSystem: Windows
ImportedDynamicFunctions:
- Name: CloseHandle
- Name: ExitProcess
- Name: GetLastError
- Name: NonExistentFunction
@@ -0,0 +1,24 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
# Verify that typed symbols get prototypes imported
CHECK: - Name:{{.*}}CloseHandle
CHECK-NEXT: Prototype:
CHECK-NEXT: Kind:{{.*}}DefinedType
CHECK: - Name:{{.*}}ExitProcess
CHECK-NEXT: Prototype:
CHECK-NEXT: Kind:{{.*}}DefinedType
CHECK: - Name:{{.*}}GetLastError
CHECK-NEXT: Prototype:
CHECK-NEXT: Kind:{{.*}}DefinedType
# NonExistentFunction should have no prototype
CHECK: - Name:{{.*}}NonExistentFunction
CHECK-NOT: Prototype:
CHECK: TypeDefinitions:
# Verify that type definitions were imported
CHECK: Kind:{{.*}}CABIFunctionDefinition