[InstallAPI] Verify that declarations in headers map to exports found in dylib (#85348)
* This completes support for verifying every declaration found in a header is discovered in the dylib. Diagnostics are reported for each class for differences that are representable in TBD files. * This patch also now captures unavailable attributes that depend on target triples. This is needed for proper tbd file generation.
This commit is contained in:
parent
de159aeca9
commit
936519f25c
@ -67,6 +67,7 @@ struct AvailabilityInfo {
|
||||
VersionTuple Introduced;
|
||||
VersionTuple Deprecated;
|
||||
VersionTuple Obsoleted;
|
||||
bool Unavailable = false;
|
||||
bool UnconditionallyDeprecated = false;
|
||||
bool UnconditionallyUnavailable = false;
|
||||
|
||||
@ -78,6 +79,12 @@ struct AvailabilityInfo {
|
||||
/// Check if the symbol has been obsoleted.
|
||||
bool isObsoleted() const { return !Obsoleted.empty(); }
|
||||
|
||||
/// Check if the symbol is unavailable unconditionally or
|
||||
/// on the active platform and os version.
|
||||
bool isUnavailable() const {
|
||||
return Unavailable || isUnconditionallyUnavailable();
|
||||
}
|
||||
|
||||
/// Check if the symbol is unconditionally deprecated.
|
||||
///
|
||||
/// i.e. \code __attribute__((deprecated)) \endcode
|
||||
@ -91,9 +98,10 @@ struct AvailabilityInfo {
|
||||
}
|
||||
|
||||
AvailabilityInfo(StringRef Domain, VersionTuple I, VersionTuple D,
|
||||
VersionTuple O, bool UD, bool UU)
|
||||
VersionTuple O, bool U, bool UD, bool UU)
|
||||
: Domain(Domain), Introduced(I), Deprecated(D), Obsoleted(O),
|
||||
UnconditionallyDeprecated(UD), UnconditionallyUnavailable(UU) {}
|
||||
Unavailable(U), UnconditionallyDeprecated(UD),
|
||||
UnconditionallyUnavailable(UU) {}
|
||||
|
||||
friend bool operator==(const AvailabilityInfo &Lhs,
|
||||
const AvailabilityInfo &Rhs);
|
||||
@ -105,10 +113,10 @@ public:
|
||||
inline bool operator==(const AvailabilityInfo &Lhs,
|
||||
const AvailabilityInfo &Rhs) {
|
||||
return std::tie(Lhs.Introduced, Lhs.Deprecated, Lhs.Obsoleted,
|
||||
Lhs.UnconditionallyDeprecated,
|
||||
Lhs.Unavailable, Lhs.UnconditionallyDeprecated,
|
||||
Lhs.UnconditionallyUnavailable) ==
|
||||
std::tie(Rhs.Introduced, Rhs.Deprecated, Rhs.Obsoleted,
|
||||
Rhs.UnconditionallyDeprecated,
|
||||
Rhs.Unavailable, Rhs.UnconditionallyDeprecated,
|
||||
Rhs.UnconditionallyUnavailable);
|
||||
}
|
||||
|
||||
|
@ -1508,3 +1508,7 @@ def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">;
|
||||
// Warnings and fixes to support the "safe buffers" programming model.
|
||||
def UnsafeBufferUsageInContainer : DiagGroup<"unsafe-buffer-usage-in-container">;
|
||||
def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer]>;
|
||||
|
||||
// Warnings and notes InstallAPI verification.
|
||||
def InstallAPIViolation : DiagGroup<"installapi-violation">;
|
||||
|
||||
|
@ -17,4 +17,27 @@ def err_no_install_name : Error<"no install name specified: add -install_name <p
|
||||
def err_no_output_file: Error<"no output file specified">;
|
||||
} // end of command line category.
|
||||
|
||||
let CategoryName = "Verification" in {
|
||||
def warn_target: Warning<"violations found for %0">, InGroup<InstallAPIViolation>;
|
||||
def err_library_missing_symbol : Error<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">;
|
||||
def warn_library_missing_symbol : Warning<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">, InGroup<InstallAPIViolation>;
|
||||
def err_library_hidden_symbol : Error<"declaration has external linkage, but symbol has internal linkage in dynamic library '%0'">;
|
||||
def warn_library_hidden_symbol : Warning<"declaration has external linkage, but symbol has internal linkage in dynamic library '%0'">, InGroup<InstallAPIViolation>;
|
||||
def warn_header_hidden_symbol : Warning<"symbol exported in dynamic library, but marked hidden in declaration '%0'">, InGroup<InstallAPIViolation>;
|
||||
def err_header_hidden_symbol : Error<"symbol exported in dynamic library, but marked hidden in declaration '%0'">;
|
||||
def err_header_symbol_missing : Error<"no declaration found for exported symbol '%0' in dynamic library">;
|
||||
def warn_header_availability_mismatch : Warning<"declaration '%0' is marked %select{available|unavailable}1,"
|
||||
" but symbol is %select{not |}2exported in dynamic library">, InGroup<InstallAPIViolation>;
|
||||
def err_header_availability_mismatch : Error<"declaration '%0' is marked %select{available|unavailable}1,"
|
||||
" but symbol is %select{not |}2exported in dynamic library">;
|
||||
def warn_dylib_symbol_flags_mismatch : Warning<"dynamic library symbol '%0' is "
|
||||
"%select{weak defined|thread local}1, but its declaration is not">, InGroup<InstallAPIViolation>;
|
||||
def warn_header_symbol_flags_mismatch : Warning<"declaration '%0' is "
|
||||
"%select{weak defined|thread local}1, but symbol is not in dynamic library">, InGroup<InstallAPIViolation>;
|
||||
def err_dylib_symbol_flags_mismatch : Error<"dynamic library symbol '%0' is "
|
||||
"%select{weak defined|thread local}1, but its declaration is not">;
|
||||
def err_header_symbol_flags_mismatch : Error<"declaration '%0' is "
|
||||
"%select{weak defined|thread local}1, but symbol is not in dynamic library">;
|
||||
} // end of Verification category.
|
||||
|
||||
} // end of InstallAPI component
|
||||
|
@ -38,19 +38,34 @@ public:
|
||||
// Current target being verified against the AST.
|
||||
llvm::MachO::Target Target;
|
||||
|
||||
// Target specific API from binary.
|
||||
RecordsSlice *DylibSlice = nullptr;
|
||||
|
||||
// Query state of verification after AST has been traversed.
|
||||
Result FrontendState;
|
||||
Result FrontendState = Result::Ignore;
|
||||
|
||||
// First error for AST traversal, which is tied to the target triple.
|
||||
bool DiscoveredFirstError;
|
||||
bool DiscoveredFirstError = false;
|
||||
|
||||
// Determines what kind of banner to print a violation for.
|
||||
bool PrintArch = false;
|
||||
|
||||
// Engine for reporting violations.
|
||||
DiagnosticsEngine *Diag = nullptr;
|
||||
|
||||
// Handle diagnostics reporting for target level violations.
|
||||
void emitDiag(llvm::function_ref<void()> Report);
|
||||
|
||||
VerifierContext() = default;
|
||||
VerifierContext(DiagnosticsEngine *Diag) : Diag(Diag) {}
|
||||
};
|
||||
|
||||
DylibVerifier() = default;
|
||||
|
||||
DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag,
|
||||
VerificationMode Mode, bool Demangle)
|
||||
: Dylib(std::move(Dylib)), Diag(Diag), Mode(Mode), Demangle(Demangle),
|
||||
Exports(std::make_unique<SymbolSet>()) {}
|
||||
: Dylib(std::move(Dylib)), Mode(Mode), Demangle(Demangle),
|
||||
Exports(std::make_unique<SymbolSet>()), Ctx(VerifierContext{Diag}) {}
|
||||
|
||||
Result verify(GlobalRecord *R, const FrontendAttrs *FA);
|
||||
Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA);
|
||||
@ -66,6 +81,13 @@ public:
|
||||
/// Get result of verification.
|
||||
Result getState() const { return Ctx.FrontendState; }
|
||||
|
||||
/// Set different source managers to the same diagnostics engine.
|
||||
void setSourceManager(SourceManager &SourceMgr) const {
|
||||
if (!Ctx.Diag)
|
||||
return;
|
||||
Ctx.Diag->setSourceManager(&SourceMgr);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Determine whether to compare declaration to symbol in binary.
|
||||
bool canVerify();
|
||||
@ -73,6 +95,29 @@ private:
|
||||
/// Shared implementation for verifying exported symbols.
|
||||
Result verifyImpl(Record *R, SymbolContext &SymCtx);
|
||||
|
||||
/// Check if declaration is marked as obsolete, they are
|
||||
// expected to result in a symbol mismatch.
|
||||
bool shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
|
||||
const Record *DR);
|
||||
|
||||
/// Compare the visibility declarations to the linkage of symbol found in
|
||||
/// dylib.
|
||||
Result compareVisibility(const Record *R, SymbolContext &SymCtx,
|
||||
const Record *DR);
|
||||
|
||||
/// An ObjCInterfaceRecord can represent up to three symbols. When verifying,
|
||||
// account for this granularity.
|
||||
bool compareObjCInterfaceSymbols(const Record *R, SymbolContext &SymCtx,
|
||||
const ObjCInterfaceRecord *DR);
|
||||
|
||||
/// Validate availability annotations against dylib.
|
||||
Result compareAvailability(const Record *R, SymbolContext &SymCtx,
|
||||
const Record *DR);
|
||||
|
||||
/// Compare and validate matching symbol flags.
|
||||
bool compareSymbolFlags(const Record *R, SymbolContext &SymCtx,
|
||||
const Record *DR);
|
||||
|
||||
/// Update result state on each call to `verify`.
|
||||
void updateState(Result State);
|
||||
|
||||
@ -80,14 +125,14 @@ private:
|
||||
void addSymbol(const Record *R, SymbolContext &SymCtx,
|
||||
TargetList &&Targets = {});
|
||||
|
||||
/// Find matching dylib slice for target triple that is being parsed.
|
||||
void assignSlice(const Target &T);
|
||||
|
||||
// Symbols in dylib.
|
||||
llvm::MachO::Records Dylib;
|
||||
|
||||
// Engine for reporting violations.
|
||||
[[maybe_unused]] DiagnosticsEngine *Diag = nullptr;
|
||||
|
||||
// Controls what class of violations to report.
|
||||
[[maybe_unused]] VerificationMode Mode = VerificationMode::Invalid;
|
||||
VerificationMode Mode = VerificationMode::Invalid;
|
||||
|
||||
// Attempt to demangle when reporting violations.
|
||||
bool Demangle = false;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/InstallAPI/Context.h"
|
||||
#include "clang/InstallAPI/DylibVerifier.h"
|
||||
#include "clang/InstallAPI/Visitor.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
@ -34,6 +35,8 @@ public:
|
||||
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) override {
|
||||
Ctx.Diags->getClient()->BeginSourceFile(CI.getLangOpts());
|
||||
Ctx.Verifier->setSourceManager(CI.getSourceManager());
|
||||
return std::make_unique<InstallAPIVisitor>(
|
||||
CI.getASTContext(), Ctx, CI.getSourceManager(), CI.getPreprocessor());
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ using ObjCInterfaceRecord = llvm::MachO::ObjCInterfaceRecord;
|
||||
using ObjCCategoryRecord = llvm::MachO::ObjCCategoryRecord;
|
||||
using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord;
|
||||
using Records = llvm::MachO::Records;
|
||||
using RecordsSlice = llvm::MachO::RecordsSlice;
|
||||
using BinaryAttrs = llvm::MachO::RecordsSlice::BinaryAttrs;
|
||||
using SymbolSet = llvm::MachO::SymbolSet;
|
||||
using SimpleSymbol = llvm::MachO::SimpleSymbol;
|
||||
|
@ -28,9 +28,9 @@ AvailabilityInfo AvailabilityInfo::createFromDecl(const Decl *Decl) {
|
||||
for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
|
||||
if (A->getPlatform()->getName() != PlatformName)
|
||||
continue;
|
||||
Availability =
|
||||
AvailabilityInfo(A->getPlatform()->getName(), A->getIntroduced(),
|
||||
A->getDeprecated(), A->getObsoleted(), false, false);
|
||||
Availability = AvailabilityInfo(
|
||||
A->getPlatform()->getName(), A->getIntroduced(), A->getDeprecated(),
|
||||
A->getObsoleted(), A->getUnavailable(), false, false);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "clang/InstallAPI/DylibVerifier.h"
|
||||
#include "clang/InstallAPI/FrontendRecords.h"
|
||||
#include "clang/InstallAPI/InstallAPIDiagnostic.h"
|
||||
#include "llvm/Demangle/Demangle.h"
|
||||
|
||||
using namespace llvm::MachO;
|
||||
@ -24,6 +25,9 @@ struct DylibVerifier::SymbolContext {
|
||||
|
||||
// The ObjCInterface symbol type, if applicable.
|
||||
ObjCIFSymbolKind ObjCIFKind = ObjCIFSymbolKind::None;
|
||||
|
||||
// Whether Decl is inlined.
|
||||
bool Inlined = false;
|
||||
};
|
||||
|
||||
static std::string
|
||||
@ -80,10 +84,11 @@ getAnnotatedName(const Record *R, EncodeKind Kind, StringRef Name,
|
||||
}
|
||||
|
||||
static std::string demangle(StringRef Name) {
|
||||
// Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'.
|
||||
if (!(Name.starts_with("_Z") || Name.starts_with("___Z")))
|
||||
// InstallAPI currently only supports itanium manglings.
|
||||
if (!(Name.starts_with("_Z") || Name.starts_with("__Z") ||
|
||||
Name.starts_with("___Z")))
|
||||
return Name.str();
|
||||
char *Result = llvm::itaniumDemangle(Name.data());
|
||||
char *Result = llvm::itaniumDemangle(Name);
|
||||
if (!Result)
|
||||
return Name.str();
|
||||
|
||||
@ -109,6 +114,30 @@ static DylibVerifier::Result updateResult(const DylibVerifier::Result Prev,
|
||||
|
||||
return Curr;
|
||||
}
|
||||
// __private_extern__ is a deprecated specifier that clang does not
|
||||
// respect in all contexts, it should just be considered hidden for InstallAPI.
|
||||
static bool shouldIgnorePrivateExternAttr(const Decl *D) {
|
||||
if (const FunctionDecl *FD = cast<FunctionDecl>(D))
|
||||
return FD->getStorageClass() == StorageClass::SC_PrivateExtern;
|
||||
if (const VarDecl *VD = cast<VarDecl>(D))
|
||||
return VD->getStorageClass() == StorageClass::SC_PrivateExtern;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Record *findRecordFromSlice(const RecordsSlice *Slice, StringRef Name,
|
||||
EncodeKind Kind) {
|
||||
switch (Kind) {
|
||||
case EncodeKind::GlobalSymbol:
|
||||
return Slice->findGlobal(Name);
|
||||
case EncodeKind::ObjectiveCInstanceVariable:
|
||||
return Slice->findObjCIVar(Name.contains('.'), Name);
|
||||
case EncodeKind::ObjectiveCClass:
|
||||
case EncodeKind::ObjectiveCClassEHType:
|
||||
return Slice->findObjCInterface(Name);
|
||||
}
|
||||
llvm_unreachable("unexpected end when finding record");
|
||||
}
|
||||
|
||||
void DylibVerifier::updateState(Result State) {
|
||||
Ctx.FrontendState = updateResult(Ctx.FrontendState, State);
|
||||
@ -122,17 +151,272 @@ void DylibVerifier::addSymbol(const Record *R, SymbolContext &SymCtx,
|
||||
Exports->addGlobal(SymCtx.Kind, SymCtx.SymbolName, R->getFlags(), Targets);
|
||||
}
|
||||
|
||||
bool DylibVerifier::shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
|
||||
const Record *DR) {
|
||||
return SymCtx.FA->Avail.isObsoleted();
|
||||
}
|
||||
|
||||
bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R,
|
||||
SymbolContext &SymCtx,
|
||||
const ObjCInterfaceRecord *DR) {
|
||||
const bool IsDeclVersionComplete =
|
||||
((SymCtx.ObjCIFKind & ObjCIFSymbolKind::Class) ==
|
||||
ObjCIFSymbolKind::Class) &&
|
||||
((SymCtx.ObjCIFKind & ObjCIFSymbolKind::MetaClass) ==
|
||||
ObjCIFSymbolKind::MetaClass);
|
||||
|
||||
const bool IsDylibVersionComplete = DR->isCompleteInterface();
|
||||
|
||||
// The common case, a complete ObjCInterface.
|
||||
if (IsDeclVersionComplete && IsDylibVersionComplete)
|
||||
return true;
|
||||
|
||||
auto PrintDiagnostic = [&](auto SymLinkage, const Record *Record,
|
||||
StringRef SymName, bool PrintAsWarning = false) {
|
||||
if (SymLinkage == RecordLinkage::Unknown)
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
|
||||
PrintAsWarning ? diag::warn_library_missing_symbol
|
||||
: diag::err_library_missing_symbol)
|
||||
<< SymName;
|
||||
});
|
||||
else
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
|
||||
PrintAsWarning ? diag::warn_library_hidden_symbol
|
||||
: diag::err_library_hidden_symbol)
|
||||
<< SymName;
|
||||
});
|
||||
};
|
||||
|
||||
if (IsDeclVersionComplete) {
|
||||
// The decl represents a complete ObjCInterface, but the symbols in the
|
||||
// dylib do not. Determine which symbol is missing. To keep older projects
|
||||
// building, treat this as a warning.
|
||||
if (!DR->isExportedSymbol(ObjCIFSymbolKind::Class))
|
||||
PrintDiagnostic(DR->getLinkageForSymbol(ObjCIFSymbolKind::Class), R,
|
||||
getAnnotatedName(R, SymCtx.Kind, SymCtx.PrettyPrintName,
|
||||
/*ValidSourceLoc=*/true,
|
||||
ObjCIFSymbolKind::Class),
|
||||
/*PrintAsWarning=*/true);
|
||||
|
||||
if (!DR->isExportedSymbol(ObjCIFSymbolKind::MetaClass))
|
||||
PrintDiagnostic(DR->getLinkageForSymbol(ObjCIFSymbolKind::MetaClass), R,
|
||||
getAnnotatedName(R, SymCtx.Kind, SymCtx.PrettyPrintName,
|
||||
/*ValidSourceLoc=*/true,
|
||||
ObjCIFSymbolKind::MetaClass),
|
||||
/*PrintAsWarning=*/true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DR->isExportedSymbol(SymCtx.ObjCIFKind)) {
|
||||
if (!IsDylibVersionComplete) {
|
||||
// Both the declaration and dylib have a non-complete interface.
|
||||
SymCtx.Kind = EncodeKind::GlobalSymbol;
|
||||
SymCtx.SymbolName = R->getName();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// At this point that means there was not a matching class symbol
|
||||
// to represent the one discovered as a declaration.
|
||||
PrintDiagnostic(DR->getLinkageForSymbol(SymCtx.ObjCIFKind), R,
|
||||
SymCtx.PrettyPrintName);
|
||||
return false;
|
||||
}
|
||||
|
||||
DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R,
|
||||
SymbolContext &SymCtx,
|
||||
const Record *DR) {
|
||||
|
||||
if (R->isExported()) {
|
||||
if (!DR) {
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
|
||||
diag::err_library_missing_symbol)
|
||||
<< SymCtx.PrettyPrintName;
|
||||
});
|
||||
return Result::Invalid;
|
||||
}
|
||||
if (DR->isInternal()) {
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
|
||||
diag::err_library_hidden_symbol)
|
||||
<< SymCtx.PrettyPrintName;
|
||||
});
|
||||
return Result::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit a diagnostic for hidden declarations with external symbols, except
|
||||
// when theres an inlined attribute.
|
||||
if ((R->isInternal() && !SymCtx.Inlined) && DR && DR->isExported()) {
|
||||
|
||||
if (Mode == VerificationMode::ErrorsOnly)
|
||||
return Result::Ignore;
|
||||
|
||||
if (shouldIgnorePrivateExternAttr(SymCtx.FA->D))
|
||||
return Result::Ignore;
|
||||
|
||||
unsigned ID;
|
||||
Result Outcome;
|
||||
if (Mode == VerificationMode::ErrorsAndWarnings) {
|
||||
ID = diag::warn_header_hidden_symbol;
|
||||
Outcome = Result::Ignore;
|
||||
} else {
|
||||
ID = diag::err_header_hidden_symbol;
|
||||
Outcome = Result::Invalid;
|
||||
}
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(), ID)
|
||||
<< SymCtx.PrettyPrintName;
|
||||
});
|
||||
return Outcome;
|
||||
}
|
||||
|
||||
if (R->isInternal())
|
||||
return Result::Ignore;
|
||||
|
||||
return Result::Valid;
|
||||
}
|
||||
|
||||
DylibVerifier::Result DylibVerifier::compareAvailability(const Record *R,
|
||||
SymbolContext &SymCtx,
|
||||
const Record *DR) {
|
||||
if (!SymCtx.FA->Avail.isUnavailable())
|
||||
return Result::Valid;
|
||||
|
||||
const bool IsDeclAvailable = SymCtx.FA->Avail.isUnavailable();
|
||||
|
||||
switch (Mode) {
|
||||
case VerificationMode::ErrorsAndWarnings:
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
|
||||
diag::warn_header_availability_mismatch)
|
||||
<< SymCtx.PrettyPrintName << IsDeclAvailable << IsDeclAvailable;
|
||||
});
|
||||
return Result::Ignore;
|
||||
case VerificationMode::Pedantic:
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
|
||||
diag::err_header_availability_mismatch)
|
||||
<< SymCtx.PrettyPrintName << IsDeclAvailable << IsDeclAvailable;
|
||||
});
|
||||
return Result::Invalid;
|
||||
case VerificationMode::ErrorsOnly:
|
||||
return Result::Ignore;
|
||||
case VerificationMode::Invalid:
|
||||
llvm_unreachable("Unexpected verification mode symbol verification");
|
||||
}
|
||||
llvm_unreachable("Unexpected verification mode symbol verification");
|
||||
}
|
||||
|
||||
bool DylibVerifier::compareSymbolFlags(const Record *R, SymbolContext &SymCtx,
|
||||
const Record *DR) {
|
||||
std::string DisplayName =
|
||||
Demangle ? demangle(DR->getName()) : DR->getName().str();
|
||||
|
||||
if (DR->isThreadLocalValue() && !R->isThreadLocalValue()) {
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
|
||||
diag::err_dylib_symbol_flags_mismatch)
|
||||
<< getAnnotatedName(DR, SymCtx.Kind, DisplayName)
|
||||
<< DR->isThreadLocalValue();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!DR->isThreadLocalValue() && R->isThreadLocalValue()) {
|
||||
Ctx.emitDiag([&]() {
|
||||
SymCtx.FA->D->getLocation(),
|
||||
Ctx.Diag->Report(diag::err_header_symbol_flags_mismatch)
|
||||
<< SymCtx.PrettyPrintName << R->isThreadLocalValue();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DR->isWeakDefined() && !R->isWeakDefined()) {
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
|
||||
diag::err_dylib_symbol_flags_mismatch)
|
||||
<< getAnnotatedName(DR, SymCtx.Kind, DisplayName)
|
||||
<< R->isWeakDefined();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!DR->isWeakDefined() && R->isWeakDefined()) {
|
||||
Ctx.emitDiag([&]() {
|
||||
Ctx.Diag->Report(SymCtx.FA->D->getLocation(),
|
||||
diag::err_header_symbol_flags_mismatch)
|
||||
<< SymCtx.PrettyPrintName << R->isWeakDefined();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DylibVerifier::Result DylibVerifier::verifyImpl(Record *R,
|
||||
SymbolContext &SymCtx) {
|
||||
R->setVerify();
|
||||
if (!canVerify()) {
|
||||
// Accumulate symbols when not in verifying against dylib.
|
||||
if (R->isExported() && !SymCtx.FA->Avail.isUnconditionallyUnavailable() &&
|
||||
if (R->isExported() && !SymCtx.FA->Avail.isUnavailable() &&
|
||||
!SymCtx.FA->Avail.isObsoleted()) {
|
||||
addSymbol(R, SymCtx);
|
||||
}
|
||||
return Ctx.FrontendState;
|
||||
}
|
||||
|
||||
Record *DR =
|
||||
findRecordFromSlice(Ctx.DylibSlice, SymCtx.SymbolName, SymCtx.Kind);
|
||||
if (DR)
|
||||
DR->setVerify();
|
||||
|
||||
if (shouldIgnoreObsolete(R, SymCtx, DR)) {
|
||||
updateState(Result::Ignore);
|
||||
return Ctx.FrontendState;
|
||||
}
|
||||
|
||||
// Unavailable declarations don't need matching symbols.
|
||||
if (SymCtx.FA->Avail.isUnavailable() && (!DR || DR->isInternal())) {
|
||||
updateState(Result::Valid);
|
||||
return Ctx.FrontendState;
|
||||
}
|
||||
|
||||
Result VisibilityCheck = compareVisibility(R, SymCtx, DR);
|
||||
if (VisibilityCheck != Result::Valid) {
|
||||
updateState(VisibilityCheck);
|
||||
return Ctx.FrontendState;
|
||||
}
|
||||
|
||||
// All missing symbol cases to diagnose have been handled now.
|
||||
if (!DR) {
|
||||
updateState(Result::Ignore);
|
||||
return Ctx.FrontendState;
|
||||
}
|
||||
|
||||
// Check for mismatching ObjC interfaces.
|
||||
if (SymCtx.ObjCIFKind != ObjCIFSymbolKind::None) {
|
||||
if (!compareObjCInterfaceSymbols(
|
||||
R, SymCtx, Ctx.DylibSlice->findObjCInterface(DR->getName()))) {
|
||||
updateState(Result::Invalid);
|
||||
return Ctx.FrontendState;
|
||||
}
|
||||
}
|
||||
|
||||
Result AvailabilityCheck = compareAvailability(R, SymCtx, DR);
|
||||
if (AvailabilityCheck != Result::Valid) {
|
||||
updateState(AvailabilityCheck);
|
||||
return Ctx.FrontendState;
|
||||
}
|
||||
|
||||
if (!compareSymbolFlags(R, SymCtx, DR)) {
|
||||
updateState(Result::Invalid);
|
||||
return Ctx.FrontendState;
|
||||
}
|
||||
|
||||
addSymbol(R, SymCtx);
|
||||
updateState(Result::Valid);
|
||||
return Ctx.FrontendState;
|
||||
}
|
||||
|
||||
@ -140,10 +424,29 @@ bool DylibVerifier::canVerify() {
|
||||
return Ctx.FrontendState != Result::NoVerify;
|
||||
}
|
||||
|
||||
void DylibVerifier::assignSlice(const Target &T) {
|
||||
assert(T == Ctx.Target && "Active targets should match.");
|
||||
if (Dylib.empty())
|
||||
return;
|
||||
|
||||
// Note: there are no reexport slices with binaries, as opposed to TBD files,
|
||||
// so it can be assumed that the target match is the active top-level library.
|
||||
auto It = find_if(
|
||||
Dylib, [&T](const auto &Slice) { return T == Slice->getTarget(); });
|
||||
|
||||
assert(It != Dylib.end() && "Target slice should always exist.");
|
||||
Ctx.DylibSlice = It->get();
|
||||
}
|
||||
|
||||
void DylibVerifier::setTarget(const Target &T) {
|
||||
Ctx.Target = T;
|
||||
Ctx.DiscoveredFirstError = false;
|
||||
updateState(Dylib.empty() ? Result::NoVerify : Result::Ignore);
|
||||
if (Dylib.empty()) {
|
||||
updateState(Result::NoVerify);
|
||||
return;
|
||||
}
|
||||
updateState(Result::Ignore);
|
||||
assignSlice(T);
|
||||
}
|
||||
|
||||
DylibVerifier::Result DylibVerifier::verify(ObjCIVarRecord *R,
|
||||
@ -205,8 +508,21 @@ DylibVerifier::Result DylibVerifier::verify(GlobalRecord *R,
|
||||
getAnnotatedName(R, Sym.Kind, Demangle ? demangle(Sym.Name) : Sym.Name);
|
||||
SymCtx.Kind = Sym.Kind;
|
||||
SymCtx.FA = FA;
|
||||
SymCtx.Inlined = R->isInlined();
|
||||
return verifyImpl(R, SymCtx);
|
||||
}
|
||||
|
||||
void DylibVerifier::VerifierContext::emitDiag(
|
||||
llvm::function_ref<void()> Report) {
|
||||
if (!DiscoveredFirstError) {
|
||||
Diag->Report(diag::warn_target)
|
||||
<< (PrintArch ? getArchitectureName(Target.Arch)
|
||||
: getTargetTripleName(Target));
|
||||
DiscoveredFirstError = true;
|
||||
}
|
||||
|
||||
Report();
|
||||
}
|
||||
|
||||
} // namespace installapi
|
||||
} // namespace clang
|
||||
|
@ -681,7 +681,7 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
|
||||
|
||||
std::string Name = getMangledName(M);
|
||||
auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
|
||||
GlobalRecord::Kind::Function, Avail, D,
|
||||
GlobalRecord::Kind::Function, Avail, M,
|
||||
*Access, getFlags(WeakDef));
|
||||
Ctx.Verifier->verify(GR, FA);
|
||||
}
|
||||
|
631
clang/test/InstallAPI/availability.test
Normal file
631
clang/test/InstallAPI/availability.test
Normal file
@ -0,0 +1,631 @@
|
||||
; RUN: rm -rf %t
|
||||
; RUN: split-file %s %t
|
||||
; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json
|
||||
|
||||
; RUN: yaml2obj %t/Availability.yaml -o %t/System/Library/Frameworks/Availability.framework/Availability
|
||||
|
||||
; RUN: clang-installapi \
|
||||
; RUN: --target=x86_64-apple-macos13 \
|
||||
; RUN: -install_name /System/Library/Frameworks/Availability.framework/Versions/A/Availability \
|
||||
; RUN: -current_version 1 -compatibility_version 1 \
|
||||
; RUN: -F %t/System/Library/Frameworks \
|
||||
; RUN: %t/inputs.json -o %t/output.tbd \
|
||||
; RUN: --verify-against=%t/System/Library/Frameworks/Availability.framework/Availability \
|
||||
; RUN: --verify-mode=ErrorsOnly --filetype=tbd-v5 2> %t/errors.log
|
||||
; RUN: FileCheck -allow-empty -check-prefix=ERRORSONLY -input-file %t/errors.log %s
|
||||
|
||||
; RUN: clang-installapi \
|
||||
; RUN: --target=x86_64-apple-macos13 \
|
||||
; RUN: -install_name /System/Library/Frameworks/Availability.framework/Versions/A/Availability \
|
||||
; RUN: -current_version 1 -compatibility_version 1 \
|
||||
; RUN: -F %t/System/Library/Frameworks \
|
||||
; RUN: %t/inputs.json -o %t/output-warnings.tbd \
|
||||
; RUN: --verify-against=%t/System/Library/Frameworks/Availability.framework/Availability \
|
||||
; RUN: --verify-mode=ErrorsAndWarnings 2> %t/errors.log
|
||||
; RUN: FileCheck -check-prefixes=VIOLATIONS,ERRORSANDWARNINGS -input-file %t/errors.log %s
|
||||
|
||||
; RUN: not clang-installapi \
|
||||
; RUN: --target=x86_64-apple-macos13 \
|
||||
; RUN: -install_name /System/Library/Frameworks/Availability.framework/Versions/A/Availability \
|
||||
; RUN: -current_version 1 -compatibility_version 1 \
|
||||
; RUN: -F %t/System/Library/Frameworks \
|
||||
; RUN: %t/inputs.json -o %t/output-pedantic.tbd \
|
||||
; RUN: --verify-against=%t/System/Library/Frameworks/Availability.framework/Availability \
|
||||
; RUN: --verify-mode=Pedantic 2> %t/errors.log
|
||||
; RUN: FileCheck -check-prefixes=VIOLATIONS,PEDANTIC -input-file %t/errors.log %s
|
||||
|
||||
; ERRORSONLY-NOT: error
|
||||
; ERRORSONLY-NOT: warning
|
||||
|
||||
; ERRORSANDWARNINGS-NOT: error
|
||||
; VIOLATIONS: warning: violations found for x86_64-apple-macos
|
||||
; VIOLATIONS: declaration 'publicGlobalVariable' is marked unavailable, but symbol is exported in dynamic library
|
||||
; VIOLATIONS-NEXT: extern int publicGlobalVariable NS_AVAILABLE
|
||||
; VIOLATIONS: declaration 'Foo' is marked unavailable, but symbol is exported in dynamic library
|
||||
; VIOLATIONS-NEXT: @interface Foo : NSObject
|
||||
; VIOLATIONS: declaration 'publicGlobalVariable3' is marked unavailable, but symbol is exported in dynamic library
|
||||
; VIOLATIONS-NEXT: extern int publicGlobalVariable3 __attribute__((unavailable))
|
||||
; VIOLATIONS: declaration 'privateGlobalVariable' is marked unavailable, but symbol is exported in dynamic library
|
||||
; VIOLATIONS-NEXT: extern int privateGlobalVariable;
|
||||
|
||||
; ERRORSANDWARNINGS-NOT: warning
|
||||
; PEDANTIC-NOT: error
|
||||
|
||||
;--- inputs.json.in
|
||||
{
|
||||
"headers": [ {
|
||||
"path" : "DSTROOT/System/Library/Frameworks/Availability.framework/Headers/Availability.h",
|
||||
"type" : "public"
|
||||
},
|
||||
{
|
||||
"path" : "DSTROOT/System/Library/Frameworks/Availability.framework/PrivateHeaders/AvailabilityPrivate.h",
|
||||
"type" : "private"
|
||||
}
|
||||
],
|
||||
"version": "3"
|
||||
}
|
||||
|
||||
;--- System/Library/Frameworks/Availability.framework/Headers/AV_Defines.h
|
||||
#ifndef AV_DEFINES
|
||||
#define AV_DEFINES
|
||||
|
||||
#define NS_AVAILABLE __attribute__((availability(macosx,introduced=NA)))
|
||||
|
||||
@interface NSObject
|
||||
@end
|
||||
|
||||
#endif //AV_DEFINES
|
||||
|
||||
;--- System/Library/Frameworks/Availability.framework/PrivateHeaders/AvailabilityPrivate.h
|
||||
#import <Availability/AV_Defines.h>
|
||||
// Test private global variable.
|
||||
NS_AVAILABLE
|
||||
extern int privateGlobalVariable;
|
||||
|
||||
;--- System/Library/Frameworks/Availability.framework/Headers/Availability.h
|
||||
#import <Availability/AV_Defines.h>
|
||||
extern int publicGlobalVariable NS_AVAILABLE;
|
||||
|
||||
// Test public ObjC class
|
||||
NS_AVAILABLE
|
||||
@interface Foo : NSObject
|
||||
@end
|
||||
|
||||
// Test unavailable attribute.
|
||||
#ifdef __i386__
|
||||
#define UNAVAILABLE_I386 __attribute__((unavailable))
|
||||
#else
|
||||
#define UNAVAILABLE_I386
|
||||
#endif
|
||||
extern int publicGlobalVariable2 UNAVAILABLE_I386;
|
||||
|
||||
extern int publicGlobalVariable3 __attribute__((unavailable))
|
||||
__attribute__((availability(macosx, introduced = 10.9)));
|
||||
|
||||
// Test obsoleted with exported variable.
|
||||
extern int publicGlobalVariable4 __attribute__((availability(
|
||||
macosx, introduced = 10.9, deprecated = 10.10, obsoleted = 10.11)));
|
||||
// Test obsoleted with non-existent variable.
|
||||
extern int publicGlobalVariable5 __attribute__((availability(
|
||||
macosx, introduced = 10.9, deprecated = 10.10, obsoleted = 10.11)));
|
||||
|
||||
#ifdef __i386__
|
||||
#define OBSOLETE_I386 __attribute__((availability(macosx, obsoleted = 10.11)))
|
||||
#else
|
||||
#define OBSOLETE_I386
|
||||
#endif
|
||||
extern int publicGlobalVariable6 OBSOLETE_I386;
|
||||
|
||||
|
||||
/// Created from:
|
||||
// int publicGlobalVariable; int privateGlobalVariable;
|
||||
//
|
||||
// @implementation Foo
|
||||
// @end
|
||||
//
|
||||
// #ifndef __i386__
|
||||
// int publicGlobalVariable2;
|
||||
// #endif
|
||||
//
|
||||
// int publicGlobalVariable3;
|
||||
// int publicGlobalVariable4;
|
||||
//
|
||||
// #ifndef __i386__
|
||||
// int publicGlobalVariable6;
|
||||
// #endif
|
||||
;--- Availability.yaml
|
||||
--- !mach-o
|
||||
FileHeader:
|
||||
magic: 0xFEEDFACF
|
||||
cputype: 0x1000007
|
||||
cpusubtype: 0x3
|
||||
filetype: 0x6
|
||||
ncmds: 14
|
||||
sizeofcmds: 1312
|
||||
flags: 0x100085
|
||||
reserved: 0x0
|
||||
LoadCommands:
|
||||
- cmd: LC_SEGMENT_64
|
||||
cmdsize: 232
|
||||
segname: __TEXT
|
||||
vmaddr: 0
|
||||
vmsize: 8192
|
||||
fileoff: 0
|
||||
filesize: 8192
|
||||
maxprot: 5
|
||||
initprot: 5
|
||||
nsects: 2
|
||||
flags: 0
|
||||
Sections:
|
||||
- sectname: __text
|
||||
segname: __TEXT
|
||||
addr: 0x1140
|
||||
size: 0
|
||||
offset: 0x1140
|
||||
align: 0
|
||||
reloff: 0x0
|
||||
nreloc: 0
|
||||
flags: 0x80000000
|
||||
reserved1: 0x0
|
||||
reserved2: 0x0
|
||||
reserved3: 0x0
|
||||
content: ''
|
||||
- sectname: __cstring
|
||||
segname: __TEXT
|
||||
addr: 0x1140
|
||||
size: 4
|
||||
offset: 0x1140
|
||||
align: 0
|
||||
reloff: 0x0
|
||||
nreloc: 0
|
||||
flags: 0x2
|
||||
reserved1: 0x0
|
||||
reserved2: 0x0
|
||||
reserved3: 0x0
|
||||
content: 466F6F00
|
||||
- cmd: LC_SEGMENT_64
|
||||
cmdsize: 232
|
||||
segname: __DATA_CONST
|
||||
vmaddr: 8192
|
||||
vmsize: 4096
|
||||
fileoff: 8192
|
||||
filesize: 4096
|
||||
maxprot: 3
|
||||
initprot: 3
|
||||
nsects: 2
|
||||
flags: 16
|
||||
Sections:
|
||||
- sectname: __objc_classlist
|
||||
segname: __DATA_CONST
|
||||
addr: 0x2000
|
||||
size: 8
|
||||
offset: 0x2000
|
||||
align: 3
|
||||
reloff: 0x0
|
||||
nreloc: 0
|
||||
flags: 0x10000000
|
||||
reserved1: 0x0
|
||||
reserved2: 0x0
|
||||
reserved3: 0x0
|
||||
content: B830000000000000
|
||||
- sectname: __objc_imageinfo
|
||||
segname: __DATA_CONST
|
||||
addr: 0x2008
|
||||
size: 8
|
||||
offset: 0x2008
|
||||
align: 0
|
||||
reloff: 0x0
|
||||
nreloc: 0
|
||||
flags: 0x0
|
||||
reserved1: 0x0
|
||||
reserved2: 0x0
|
||||
reserved3: 0x0
|
||||
content: '0000000040000000'
|
||||
- cmd: LC_SEGMENT_64
|
||||
cmdsize: 312
|
||||
segname: __DATA
|
||||
vmaddr: 12288
|
||||
vmsize: 4096
|
||||
fileoff: 12288
|
||||
filesize: 4096
|
||||
maxprot: 3
|
||||
initprot: 3
|
||||
nsects: 3
|
||||
flags: 0
|
||||
Sections:
|
||||
- sectname: __objc_const
|
||||
segname: __DATA
|
||||
addr: 0x3000
|
||||
size: 144
|
||||
offset: 0x3000
|
||||
align: 3
|
||||
reloff: 0x0
|
||||
nreloc: 0
|
||||
flags: 0x0
|
||||
reserved1: 0x0
|
||||
reserved2: 0x0
|
||||
reserved3: 0x0
|
||||
content: '010000002800000028000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
- sectname: __objc_data
|
||||
segname: __DATA
|
||||
addr: 0x3090
|
||||
size: 80
|
||||
offset: 0x3090
|
||||
align: 3
|
||||
reloff: 0x0
|
||||
nreloc: 0
|
||||
flags: 0x0
|
||||
reserved1: 0x0
|
||||
reserved2: 0x0
|
||||
reserved3: 0x0
|
||||
content: '0000000000000000000000000000000000000000000000000000000000000000003000000000000090300000000000000000000000000000000000000000000000000000000000004830000000000000'
|
||||
- sectname: __common
|
||||
segname: __DATA
|
||||
addr: 0x30E0
|
||||
size: 24
|
||||
offset: 0x0
|
||||
align: 2
|
||||
reloff: 0x0
|
||||
nreloc: 0
|
||||
flags: 0x1
|
||||
reserved1: 0x0
|
||||
reserved2: 0x0
|
||||
reserved3: 0x0
|
||||
- cmd: LC_SEGMENT_64
|
||||
cmdsize: 72
|
||||
segname: __LINKEDIT
|
||||
vmaddr: 16384
|
||||
vmsize: 824
|
||||
fileoff: 16384
|
||||
filesize: 824
|
||||
maxprot: 1
|
||||
initprot: 1
|
||||
nsects: 0
|
||||
flags: 0
|
||||
- cmd: LC_DYLD_INFO_ONLY
|
||||
cmdsize: 48
|
||||
rebase_off: 16384
|
||||
rebase_size: 16
|
||||
bind_off: 16400
|
||||
bind_size: 104
|
||||
weak_bind_off: 0
|
||||
weak_bind_size: 0
|
||||
lazy_bind_off: 0
|
||||
lazy_bind_size: 0
|
||||
export_off: 16504
|
||||
export_size: 152
|
||||
- cmd: LC_SYMTAB
|
||||
cmdsize: 24
|
||||
symoff: 16664
|
||||
nsyms: 14
|
||||
stroff: 16888
|
||||
strsize: 320
|
||||
- cmd: LC_DYSYMTAB
|
||||
cmdsize: 80
|
||||
ilocalsym: 0
|
||||
nlocalsym: 2
|
||||
iextdefsym: 2
|
||||
nextdefsym: 8
|
||||
iundefsym: 10
|
||||
nundefsym: 4
|
||||
tocoff: 0
|
||||
ntoc: 0
|
||||
modtaboff: 0
|
||||
nmodtab: 0
|
||||
extrefsymoff: 0
|
||||
nextrefsyms: 0
|
||||
indirectsymoff: 0
|
||||
nindirectsyms: 0
|
||||
extreloff: 0
|
||||
nextrel: 0
|
||||
locreloff: 0
|
||||
nlocrel: 0
|
||||
- cmd: LC_ID_DYLIB
|
||||
cmdsize: 112
|
||||
dylib:
|
||||
name: 24
|
||||
timestamp: 0
|
||||
current_version: 65536
|
||||
compatibility_version: 65536
|
||||
Content: '/System/Library/Frameworks/Availability.framework/Versions/A/Availability'
|
||||
ZeroPadBytes: 7
|
||||
- cmd: LC_UUID
|
||||
cmdsize: 24
|
||||
uuid: 4C4C4470-5555-3144-A142-4EE44DA08D2F
|
||||
- cmd: LC_BUILD_VERSION
|
||||
cmdsize: 32
|
||||
platform: 1
|
||||
minos: 851968
|
||||
sdk: 983040
|
||||
ntools: 1
|
||||
Tools:
|
||||
- tool: 4
|
||||
version: 1245184
|
||||
- cmd: LC_LOAD_DYLIB
|
||||
cmdsize: 56
|
||||
dylib:
|
||||
name: 24
|
||||
timestamp: 0
|
||||
current_version: 14942208
|
||||
compatibility_version: 65536
|
||||
Content: '/usr/lib/libobjc.A.dylib'
|
||||
ZeroPadBytes: 8
|
||||
- cmd: LC_LOAD_DYLIB
|
||||
cmdsize: 56
|
||||
dylib:
|
||||
name: 24
|
||||
timestamp: 0
|
||||
current_version: 88473600
|
||||
compatibility_version: 65536
|
||||
Content: '/usr/lib/libSystem.B.dylib'
|
||||
ZeroPadBytes: 6
|
||||
- cmd: LC_FUNCTION_STARTS
|
||||
cmdsize: 16
|
||||
dataoff: 16656
|
||||
datasize: 8
|
||||
- cmd: LC_DATA_IN_CODE
|
||||
cmdsize: 16
|
||||
dataoff: 16664
|
||||
datasize: 0
|
||||
LinkEditData:
|
||||
RebaseOpcodes:
|
||||
- Opcode: REBASE_OPCODE_SET_TYPE_IMM
|
||||
Imm: 1
|
||||
- Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
|
||||
Imm: 1
|
||||
ExtraData: [ 0x0 ]
|
||||
- Opcode: REBASE_OPCODE_DO_REBASE_IMM_TIMES
|
||||
Imm: 1
|
||||
- Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
|
||||
Imm: 2
|
||||
ExtraData: [ 0x18 ]
|
||||
- Opcode: REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
|
||||
Imm: 0
|
||||
ExtraData: [ 0x2, 0x40 ]
|
||||
- Opcode: REBASE_OPCODE_ADD_ADDR_IMM_SCALED
|
||||
Imm: 1
|
||||
- Opcode: REBASE_OPCODE_DO_REBASE_IMM_TIMES
|
||||
Imm: 2
|
||||
- Opcode: REBASE_OPCODE_ADD_ADDR_IMM_SCALED
|
||||
Imm: 3
|
||||
- Opcode: REBASE_OPCODE_DO_REBASE_IMM_TIMES
|
||||
Imm: 1
|
||||
- Opcode: REBASE_OPCODE_DONE
|
||||
Imm: 0
|
||||
BindOpcodes:
|
||||
- Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
|
||||
Imm: 0
|
||||
Symbol: '_OBJC_METACLASS_$_NSObject'
|
||||
- Opcode: BIND_OPCODE_SET_TYPE_IMM
|
||||
Imm: 1
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
|
||||
Imm: 1
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
|
||||
Imm: 2
|
||||
ULEBExtraData: [ 0x90 ]
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_DO_BIND
|
||||
Imm: 0
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_DO_BIND
|
||||
Imm: 0
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
|
||||
Imm: 0
|
||||
Symbol: __objc_empty_cache
|
||||
- Opcode: BIND_OPCODE_SET_TYPE_IMM
|
||||
Imm: 1
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_DO_BIND
|
||||
Imm: 0
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_ADD_ADDR_ULEB
|
||||
Imm: 0
|
||||
ULEBExtraData: [ 0x20 ]
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_DO_BIND
|
||||
Imm: 0
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
|
||||
Imm: 0
|
||||
Symbol: '_OBJC_CLASS_$_NSObject'
|
||||
- Opcode: BIND_OPCODE_SET_TYPE_IMM
|
||||
Imm: 1
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_ADD_ADDR_ULEB
|
||||
Imm: 0
|
||||
ULEBExtraData: [ 0xFFFFFFFFFFFFFFF0 ]
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_DO_BIND
|
||||
Imm: 0
|
||||
Symbol: ''
|
||||
- Opcode: BIND_OPCODE_DONE
|
||||
Imm: 0
|
||||
Symbol: ''
|
||||
ExportTrie:
|
||||
TerminalSize: 0
|
||||
NodeOffset: 0
|
||||
Name: ''
|
||||
Flags: 0x0
|
||||
Address: 0x0
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
Children:
|
||||
- TerminalSize: 0
|
||||
NodeOffset: 5
|
||||
Name: _
|
||||
Flags: 0x0
|
||||
Address: 0x0
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
Children:
|
||||
- TerminalSize: 0
|
||||
NodeOffset: 17
|
||||
Name: OBJC_
|
||||
Flags: 0x0
|
||||
Address: 0x0
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
Children:
|
||||
- TerminalSize: 3
|
||||
NodeOffset: 49
|
||||
Name: 'METACLASS_$_Foo'
|
||||
Flags: 0x0
|
||||
Address: 0x3090
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
- TerminalSize: 3
|
||||
NodeOffset: 54
|
||||
Name: 'CLASS_$_Foo'
|
||||
Flags: 0x0
|
||||
Address: 0x30B8
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
- TerminalSize: 0
|
||||
NodeOffset: 59
|
||||
Name: p
|
||||
Flags: 0x0
|
||||
Address: 0x0
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
Children:
|
||||
- TerminalSize: 3
|
||||
NodeOffset: 104
|
||||
Name: rivateGlobalVariable
|
||||
Flags: 0x0
|
||||
Address: 0x30E0
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
- TerminalSize: 3
|
||||
NodeOffset: 109
|
||||
Name: ublicGlobalVariable
|
||||
Flags: 0x0
|
||||
Address: 0x30E4
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
Children:
|
||||
- TerminalSize: 3
|
||||
NodeOffset: 130
|
||||
Name: '4'
|
||||
Flags: 0x0
|
||||
Address: 0x30F0
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
- TerminalSize: 3
|
||||
NodeOffset: 135
|
||||
Name: '3'
|
||||
Flags: 0x0
|
||||
Address: 0x30EC
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
- TerminalSize: 3
|
||||
NodeOffset: 140
|
||||
Name: '2'
|
||||
Flags: 0x0
|
||||
Address: 0x30E8
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
- TerminalSize: 3
|
||||
NodeOffset: 145
|
||||
Name: '6'
|
||||
Flags: 0x0
|
||||
Address: 0x30F4
|
||||
Other: 0x0
|
||||
ImportName: ''
|
||||
NameList:
|
||||
- n_strx: 2
|
||||
n_type: 0xE
|
||||
n_sect: 5
|
||||
n_desc: 0
|
||||
n_value: 12288
|
||||
- n_strx: 28
|
||||
n_type: 0xE
|
||||
n_sect: 5
|
||||
n_desc: 0
|
||||
n_value: 12360
|
||||
- n_strx: 50
|
||||
n_type: 0xF
|
||||
n_sect: 7
|
||||
n_desc: 0
|
||||
n_value: 12512
|
||||
- n_strx: 73
|
||||
n_type: 0xF
|
||||
n_sect: 7
|
||||
n_desc: 0
|
||||
n_value: 12516
|
||||
- n_strx: 95
|
||||
n_type: 0xF
|
||||
n_sect: 7
|
||||
n_desc: 0
|
||||
n_value: 12520
|
||||
- n_strx: 118
|
||||
n_type: 0xF
|
||||
n_sect: 7
|
||||
n_desc: 0
|
||||
n_value: 12524
|
||||
- n_strx: 141
|
||||
n_type: 0xF
|
||||
n_sect: 7
|
||||
n_desc: 0
|
||||
n_value: 12528
|
||||
- n_strx: 164
|
||||
n_type: 0xF
|
||||
n_sect: 7
|
||||
n_desc: 0
|
||||
n_value: 12532
|
||||
- n_strx: 187
|
||||
n_type: 0xF
|
||||
n_sect: 6
|
||||
n_desc: 0
|
||||
n_value: 12432
|
||||
- n_strx: 209
|
||||
n_type: 0xF
|
||||
n_sect: 6
|
||||
n_desc: 0
|
||||
n_value: 12472
|
||||
- n_strx: 227
|
||||
n_type: 0x1
|
||||
n_sect: 0
|
||||
n_desc: 256
|
||||
n_value: 0
|
||||
- n_strx: 250
|
||||
n_type: 0x1
|
||||
n_sect: 0
|
||||
n_desc: 256
|
||||
n_value: 0
|
||||
- n_strx: 277
|
||||
n_type: 0x1
|
||||
n_sect: 0
|
||||
n_desc: 256
|
||||
n_value: 0
|
||||
- n_strx: 296
|
||||
n_type: 0x1
|
||||
n_sect: 0
|
||||
n_desc: 512
|
||||
n_value: 0
|
||||
StringTable:
|
||||
- ' '
|
||||
- '__OBJC_METACLASS_RO_$_Foo'
|
||||
- '__OBJC_CLASS_RO_$_Foo'
|
||||
- _privateGlobalVariable
|
||||
- _publicGlobalVariable
|
||||
- _publicGlobalVariable2
|
||||
- _publicGlobalVariable3
|
||||
- _publicGlobalVariable4
|
||||
- _publicGlobalVariable6
|
||||
- '_OBJC_METACLASS_$_Foo'
|
||||
- '_OBJC_CLASS_$_Foo'
|
||||
- '_OBJC_CLASS_$_NSObject'
|
||||
- '_OBJC_METACLASS_$_NSObject'
|
||||
- __objc_empty_cache
|
||||
- dyld_stub_binder
|
||||
- ''
|
||||
- ''
|
||||
- ''
|
||||
- ''
|
||||
- ''
|
||||
- ''
|
||||
- ''
|
||||
...
|
462
clang/test/InstallAPI/diagnostics-cpp.test
Normal file
462
clang/test/InstallAPI/diagnostics-cpp.test
Normal file
File diff suppressed because one or more lines are too long
262
clang/test/InstallAPI/hiddens.test
Normal file
262
clang/test/InstallAPI/hiddens.test
Normal file
File diff suppressed because one or more lines are too long
@ -111,17 +111,15 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
|
||||
// Execute and gather AST results.
|
||||
// An invocation is ran for each unique target triple and for each header
|
||||
// access level.
|
||||
Records FrontendResults;
|
||||
for (const auto &[Targ, Trip] : Opts.DriverOpts.Targets) {
|
||||
Ctx.Verifier->setTarget(Targ);
|
||||
Ctx.Slice = std::make_shared<FrontendRecordsSlice>(Trip);
|
||||
for (const HeaderType Type :
|
||||
{HeaderType::Public, HeaderType::Private, HeaderType::Project}) {
|
||||
Ctx.Slice = std::make_shared<FrontendRecordsSlice>(Trip);
|
||||
Ctx.Verifier->setTarget(Targ);
|
||||
Ctx.Type = Type;
|
||||
if (!runFrontend(ProgName, Opts.DriverOpts.Verbose, Ctx,
|
||||
InMemoryFileSystem.get(), Opts.getClangFrontendArgs()))
|
||||
return EXIT_FAILURE;
|
||||
FrontendResults.emplace_back(std::move(Ctx.Slice));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,6 +261,9 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
|
||||
if (!processFrontendOptions(ArgList))
|
||||
return;
|
||||
|
||||
/// Force cc1 options that should always be on.
|
||||
FrontendArgs = {"-fsyntax-only", "-Wprivate-extern"};
|
||||
|
||||
/// Any unclaimed arguments should be handled by invoking the clang frontend.
|
||||
for (const Arg *A : ArgList) {
|
||||
if (A->isClaimed())
|
||||
@ -268,7 +271,6 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
|
||||
FrontendArgs.emplace_back(A->getSpelling());
|
||||
llvm::copy(A->getValues(), std::back_inserter(FrontendArgs));
|
||||
}
|
||||
FrontendArgs.push_back("-fsyntax-only");
|
||||
}
|
||||
|
||||
InstallAPIContext Options::createContext() {
|
||||
|
@ -42,6 +42,7 @@ static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
|
||||
#include "clang/Basic/DiagnosticSemaKinds.inc"
|
||||
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
|
||||
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
|
||||
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
|
||||
#undef DIAG
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user