Loading...
--- dyld/dyld-1340/common/SymbolsCache.cpp
+++ dyld/dyld-1235.2/common/SymbolsCache.cpp
@@ -439,9 +439,9 @@
return Error::none();
}
-static Error getBinaryUUID(sqlite3* symbolsDB, const std::string_view path,
- const Platform platform, const std::string_view arch,
- std::string& binaryUUID)
+static Error getDylibUUID(sqlite3* symbolsDB, std::string_view installName,
+ Platform platform, std::string_view arch,
+ std::string& binaryUUID)
{
// Check if the DB is new enough to have the UUID column. It appeared in 1.2
{
@@ -453,14 +453,14 @@
return Error();
}
- const char* selectQuery = "SELECT UUID FROM BINARY WHERE PATH = ? AND PLATFORM = ? AND ARCH = ?";
+ const char* selectQuery = "SELECT UUID FROM BINARY WHERE INSTALL_NAME = ? AND PLATFORM = ? AND ARCH = ?";
sqlite3_stmt *statement = nullptr;
if ( int result = sqlite3_prepare_v2(symbolsDB, selectQuery, -1, &statement, 0) ) {
Error err = Error("Could not prepare statement for table 'BINARY' because: %s", (const char*)strerror(result));
return err;
}
- if ( int result = sqlite3_bind_text(statement, 1, path.data(), -1, SQLITE_TRANSIENT) ) {
+ if ( int result = sqlite3_bind_text(statement, 1, installName.data(), -1, SQLITE_TRANSIENT) ) {
Error err = Error("Could not bind text for table 'BINARY' because: %s", (const char*)strerror(result));
return err;
}
@@ -488,7 +488,7 @@
return Error::none();
if ( results.size() > 1 ) {
- return Error("Too many binary results for binary UUID: %s", path.data());
+ return Error("Too many binary results for dylib: %s", installName.data());
}
binaryUUID = results.front();
@@ -496,9 +496,9 @@
return Error::none();
}
-static Error getBinaryProject(sqlite3* symbolsDB, const std::string_view path,
- const Platform platform, const std::string_view arch,
- std::string& projectName)
+static Error getDylibProject(sqlite3* symbolsDB, std::string_view installName,
+ Platform platform, std::string_view arch,
+ std::string& projectName)
{
// Check if the DB is new enough. The Project column appeared in version 3
{
@@ -510,14 +510,14 @@
return Error();
}
- const char* selectQuery = "SELECT PROJECT_NAME FROM BINARY WHERE PATH = ? AND PLATFORM = ? AND ARCH = ?";
+ const char* selectQuery = "SELECT PROJECT_NAME FROM BINARY WHERE INSTALL_NAME = ? AND PLATFORM = ? AND ARCH = ?";
sqlite3_stmt *statement = nullptr;
if ( int result = sqlite3_prepare_v2(symbolsDB, selectQuery, -1, &statement, 0) ) {
Error err = Error("Could not prepare statement for table 'BINARY' because: %s", (const char*)strerror(result));
return err;
}
- if ( int result = sqlite3_bind_text(statement, 1, path.data(), -1, SQLITE_TRANSIENT) ) {
+ if ( int result = sqlite3_bind_text(statement, 1, installName.data(), -1, SQLITE_TRANSIENT) ) {
Error err = Error("Could not bind text for table 'BINARY' because: %s", (const char*)strerror(result));
return err;
}
@@ -545,57 +545,10 @@
return Error::none();
if ( results.size() > 1 ) {
- return Error("Too many binary results for binary project name: %s", path.data());
+ return Error("Too many binary results for dylib: %s", installName.data());
}
projectName = results.front();
-
- return Error::none();
-}
-
-static Error getBinaryInstallName(sqlite3* symbolsDB, const std::string_view path,
- const Platform platform, const std::string_view arch,
- std::string& installName)
-{
- const char* selectQuery = "SELECT INSTALL_NAME FROM BINARY WHERE PATH = ? AND PLATFORM = ? AND ARCH = ?";
- sqlite3_stmt *statement = nullptr;
- if ( int result = sqlite3_prepare_v2(symbolsDB, selectQuery, -1, &statement, 0) ) {
- Error err = Error("Could not prepare statement for table 'BINARY' because: %s", (const char*)strerror(result));
- return err;
- }
-
- if ( int result = sqlite3_bind_text(statement, 1, path.data(), -1, SQLITE_TRANSIENT) ) {
- Error err = Error("Could not bind text for table 'BINARY' because: %s", (const char*)strerror(result));
- return err;
- }
-
- if ( int result = sqlite3_bind_int(statement, 2, platform.value()) ) {
- Error err = Error("Could not bind int for table 'BINARY' because: %s", (const char*)strerror(result));
- return err;
- }
-
- if ( int result = sqlite3_bind_text(statement, 3, arch.data(), -1, SQLITE_TRANSIENT) ) {
- Error err = Error("Could not bind text for table 'BINARY' because: %s", (const char*)strerror(result));
- return err;
- }
-
- // Get results
- std::vector<std::string> results;
- while( sqlite3_step(statement) == SQLITE_ROW ) {
- if ( sqlite3_column_type(statement, 0) != SQLITE_NULL )
- results.push_back((const char*)sqlite3_column_text(statement, 0));
- }
-
- sqlite3_finalize(statement);
-
- if ( results.empty() )
- return Error::none();
-
- if ( results.size() > 1 ) {
- return Error("Too many binary results for binary install name: %s", path.data());
- }
-
- installName = results.front();
return Error::none();
}
@@ -1037,17 +990,17 @@
return Error::none();
Error parseErr = mach_o::forEachHeader({ (uint8_t*)buffer, bufferSize }, path,
- ^(const Header *hdr, size_t sliceLength, bool &stop) {
+ ^(const Header *mh, size_t sliceLength, bool &stop) {
std::span<const Platform> supportedPlatforms;
if ( archPlatforms.empty() ) {
// support all platforms if there are no archs
- } else if ( auto it = archPlatforms.find(hdr->archName()); it != archPlatforms.end() ) {
+ } else if ( auto it = archPlatforms.find(mh->archName()); it != archPlatforms.end() ) {
supportedPlatforms = it->second;
} else {
return;
}
- PlatformAndVersions pvs = hdr->platformAndVersions();
+ PlatformAndVersions pvs = mh->platformAndVersions();
if ( pvs.platform.empty() )
return;
@@ -1061,43 +1014,36 @@
if ( !supportedPlatforms.empty() && (std::find(supportedPlatforms.begin(), supportedPlatforms.end(), platform) == supportedPlatforms.end()) )
return;
- if ( !hdr->isDylib() && !hdr->isDynamicExecutable() )
+ if ( !mh->isDylib() )
return;
- if ( hdr->isDylib() ) {
- std::string_view installName = hdr->installName();
- std::string_view dylibPath = path;
- if ( installName != dylibPath ) {
- // We now typically require that install names and paths match. However symlinks may allow us to bring in a path which
- // doesn't match its install name.
- // For example:
- // /usr/lib/libstdc++.6.0.9.dylib is a real file with install name /usr/lib/libstdc++.6.dylib
- // /usr/lib/libstdc++.6.dylib is a symlink to /usr/lib/libstdc++.6.0.9.dylib
- // So long as we add both paths (with one as an alias) then this will work, even if dylibs are removed from disk
- // but the symlink remains.
- // Apply the same symlink crawling for dylibs that will install their contents to Cryptex paths but will have
- // install names with the cryptex paths removed.
- char resolvedSymlinkPath[PATH_MAX];
- if ( fileSystem.getRealPath(installName.data(), resolvedSymlinkPath) ) {
- if ( resolvedSymlinkPath == dylibPath ) {
- // Symlink is the install name and points to the on-disk dylib
- //fprintf(stderr, "Symlink works: %s == %s\n", inputFile.path, installName.c_str());
- dylibPath = installName;
- }
- } else {
- // HACK: The build record doesn't have symlinks or anything to allow the above realpath code
- // to reason about the cryptex. So just look for it specifically
- if ( dylibPath == (std::string("/System/Cryptexes/OS") + std::string(installName)) )
- dylibPath = installName;
+ const dyld3::MachOFile* mf = (const dyld3::MachOFile*)mh;
+ std::string_view installName = mf->installName();
+ std::string_view dylibPath = path;
+ if ( installName != dylibPath ) {
+ // We now typically require that install names and paths match. However symlinks may allow us to bring in a path which
+ // doesn't match its install name.
+ // For example:
+ // /usr/lib/libstdc++.6.0.9.dylib is a real file with install name /usr/lib/libstdc++.6.dylib
+ // /usr/lib/libstdc++.6.dylib is a symlink to /usr/lib/libstdc++.6.0.9.dylib
+ // So long as we add both paths (with one as an alias) then this will work, even if dylibs are removed from disk
+ // but the symlink remains.
+ // Apply the same symlink crawling for dylibs that will install their contents to Cryptex paths but will have
+ // install names with the cryptex paths removed.
+ char resolvedSymlinkPath[PATH_MAX];
+ if ( fileSystem.getRealPath(installName.data(), resolvedSymlinkPath) ) {
+ if ( resolvedSymlinkPath == dylibPath ) {
+ // Symlink is the install name and points to the on-disk dylib
+ //fprintf(stderr, "Symlink works: %s == %s\n", inputFile.path, installName.c_str());
+ dylibPath = installName;
}
}
-
- const dyld3::MachOFile* mf = (const dyld3::MachOFile*)hdr;
- if ( !mf->canBePlacedInDyldCache(dylibPath.data(), false /* check objc */, ^(const char* format, ...){ }) )
- return;
- }
-
- slices.push_back({ hdr, sliceLength, platform });
+ }
+
+ if ( !mf->canBePlacedInDyldCache(dylibPath.data(), ^(const char* format, ...){ }) )
+ return;
+
+ slices.push_back({ mh, sliceLength, platform });
});
if ( parseErr ) {
@@ -1116,24 +1062,24 @@
}
static mach_o::Error makeBinaryFromJSON(const SymbolsCache::ArchPlatforms& archPlatforms,
- const json::Node& rootNode, std::string_view path,
+ const dyld3::json::Node& rootNode, std::string_view path,
std::string_view projectName,
bool allowExecutables,
std::vector<SymbolsCacheBinary>& binaries)
{
- using json::Node;
+ using dyld3::json::Node;
// In XBS we expect trace files to be decompressed along with some helpful preamble. The key for that is
// a node called "api-version" so if we see that, we know this file has a certain structure
Diagnostics diags;
- if ( json::getOptionalValue(diags, rootNode, "api-version") ) {
+ if ( dyld3::json::getOptionalValue(diags, rootNode, "api-version") ) {
// Walk the trace-files[] and then the contents[]
- const Node& traceFilesNode = json::getRequiredValue(diags, rootNode, "trace-files");
+ const Node& traceFilesNode = dyld3::json::getRequiredValue(diags, rootNode, "trace-files");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
for ( const Node& traceFileNode : traceFilesNode.array ) {
- const Node& contentsNode = json::getRequiredValue(diags, traceFileNode, "contents");
+ const Node& contentsNode = dyld3::json::getRequiredValue(diags, traceFileNode, "contents");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1146,32 +1092,32 @@
return Error::none();
}
- const Node& versionNode = json::getRequiredValue(diags, rootNode, "version");
+ const Node& versionNode = dyld3::json::getRequiredValue(diags, rootNode, "version");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
- uint64_t jsonVersion = json::parseRequiredInt(diags, versionNode);
+ uint64_t jsonVersion = dyld3::json::parseRequiredInt(diags, versionNode);
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
- if ( jsonVersion > 2 ) {
+ if ( jsonVersion != 1 ) {
// Is it ok to silently return? It allows old tools to ignore new JSON so maybe what we want
return Error::none();
}
// Skip binaries which aren't cache eligible
- const Node* sharedCacheEligibleNode = json::getOptionalValue(diags, rootNode, "shared-cache-eligible");
+ const Node* sharedCacheEligibleNode = dyld3::json::getOptionalValue(diags, rootNode, "shared-cache-eligible");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
if ( (sharedCacheEligibleNode != nullptr) && sharedCacheEligibleNode->value != "yes" )
return Error::none();
- const Node& archNode = json::getRequiredValue(diags, rootNode, "arch");
+ const Node& archNode = dyld3::json::getRequiredValue(diags, rootNode, "arch");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
- const std::string& archName = json::parseRequiredString(diags, archNode);
+ const std::string& archName = dyld3::json::parseRequiredString(diags, archNode);
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1184,7 +1130,7 @@
return Error::none();
}
- const Node& platformsNode = json::getRequiredValue(diags, rootNode, "platforms");
+ const Node& platformsNode = dyld3::json::getRequiredValue(diags, rootNode, "platforms");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1193,11 +1139,11 @@
Platform platform;
for ( const Node& platformNode : platformsNode.array ) {
- const Node& nameNode = json::getRequiredValue(diags, platformNode, "name");
+ const Node& nameNode = dyld3::json::getRequiredValue(diags, platformNode, "name");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
- const std::string& platformName = json::parseRequiredString(diags, nameNode);
+ const std::string& platformName = dyld3::json::parseRequiredString(diags, nameNode);
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1216,11 +1162,11 @@
if ( Error err = platform.valid() )
return Error::none();
- const Node* installNameNode = json::getOptionalValue(diags, rootNode, "install-name");
+ const Node* installNameNode = dyld3::json::getOptionalValue(diags, rootNode, "install-name");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
- const Node* finalPathNode = json::getOptionalValue(diags, rootNode, "final-output-path");
+ const Node* finalPathNode = dyld3::json::getOptionalValue(diags, rootNode, "final-output-path");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1232,51 +1178,51 @@
std::string_view installName;
if ( installNameNode != nullptr ) {
- installName = json::parseRequiredString(diags, *installNameNode);
+ installName = dyld3::json::parseRequiredString(diags, *installNameNode);
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
}
std::string_view finalPath;
if ( finalPathNode != nullptr ) {
- finalPath = json::parseRequiredString(diags, *finalPathNode);
+ finalPath = dyld3::json::parseRequiredString(diags, *finalPathNode);
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
} else {
finalPath = installName;
}
- const Node* uuidNode = json::getOptionalValue(diags, rootNode, "uuid");
+ const Node* uuidNode = dyld3::json::getOptionalValue(diags, rootNode, "uuid");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
std::string_view uuid;
if ( uuidNode ) {
- uuid = json::parseRequiredString(diags, *uuidNode);
+ uuid = dyld3::json::parseRequiredString(diags, *uuidNode);
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
}
std::vector<SymbolsCacheBinary::ImportedSymbol> importedSymbols;
std::vector<SymbolsCacheBinary::TargetBinary> reexports;
- const Node* linkedDylibsNode = json::getOptionalValue(diags, rootNode, "linked-dylibs");
+ const Node* linkedDylibsNode = dyld3::json::getOptionalValue(diags, rootNode, "linked-dylibs");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
if ( (linkedDylibsNode != nullptr) && !linkedDylibsNode->array.empty() ) {
for ( const Node& linkedDylibNode : linkedDylibsNode->array ) {
- const Node& targetInstallNameNode = json::getRequiredValue(diags, linkedDylibNode, "install-name");
+ const Node& targetInstallNameNode = dyld3::json::getRequiredValue(diags, linkedDylibNode, "install-name");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
- std::string_view targetInstallName = json::parseRequiredString(diags, targetInstallNameNode);
+ std::string_view targetInstallName = dyld3::json::parseRequiredString(diags, targetInstallNameNode);
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
- if ( !Header::isSharedCacheEligiblePath(targetInstallName.data()) )
+ if ( !dyld3::MachOFile::isSharedCacheEligiblePath(targetInstallName.data()) )
continue;
- const Node& importedSymbolsNode = json::getRequiredValue(diags, linkedDylibNode, "imported-symbols");
+ const Node& importedSymbolsNode = dyld3::json::getRequiredValue(diags, linkedDylibNode, "imported-symbols");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1287,7 +1233,7 @@
}
}
- const Node& attributesNode = json::getRequiredValue(diags, linkedDylibNode, "attributes");
+ const Node& attributesNode = dyld3::json::getRequiredValue(diags, linkedDylibNode, "attributes");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1301,8 +1247,8 @@
}
__block std::vector<std::string> exportedSymbols;
- if ( !installName.empty() && Header::isSharedCacheEligiblePath(installName.data()) ) {
- const Node* exportedSymbolsNode = json::getOptionalValue(diags, rootNode, "exports");
+ if ( !installName.empty() && dyld3::MachOFile::isSharedCacheEligiblePath(installName.data()) ) {
+ const Node* exportedSymbolsNode = dyld3::json::getOptionalValue(diags, rootNode, "exports");
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1330,7 +1276,7 @@
std::string_view projectName, bool allowExecutables,
std::vector<SymbolsCacheBinary>& binaries)
{
- using json::Node;
+ using dyld3::json::Node;
// The buffer is likely in the "JSON lines" format. If so, parse each line as its own JSON
{
@@ -1346,7 +1292,7 @@
if ( line.starts_with('{') && line.ends_with('}') ) {
Diagnostics diags;
- Node rootNode = json::readJSON(diags, line.data(), line.size(), false /* useJSON5 */);
+ Node rootNode = dyld3::json::readJSON(diags, line.data(), line.size());
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1363,7 +1309,7 @@
}
Diagnostics diags;
- Node rootNode = json::readJSON(diags, buffer, bufferSize, false /* useJSON5 */);
+ Node rootNode = dyld3::json::readJSON(diags, buffer, bufferSize);
if ( diags.hasError() )
return Error("Could not parse JSON '%s' because: %s", path.data(), diags.errorMessageCStr());
@@ -1391,7 +1337,7 @@
Platform platform = slice.platform;
const char* sliceArch = mh->archName();
- Image image(slice.sliceHeader, slice.sliceLength, Image::MappingKind::wholeSliceMapped);
+ Image image(slice.sliceHeader, slice.sliceLength, Image::MappingKind::unknown);
// printf("Processing: %s", &path[0]);
@@ -1425,8 +1371,7 @@
// Add re-exports
__block std::vector<SymbolsCacheBinary::TargetBinary> reexports;
if ( const char* installName = mh->installName(); (installName != nullptr) && (installName[0] == '/') ) {
- mh->forEachLinkedDylib(^(const char* loadPath, mach_o::LinkedDylibAttributes kind, Version32 compatVersion, Version32 curVersion,
- bool synthesizedLink, bool& stop) {
+ mh->forEachLinkedDylib(^(const char* loadPath, mach_o::LinkedDylibAttributes kind, Version32 compatVersion, Version32 curVersion, bool& stop) {
if ( kind.reExport )
reexports.push_back(loadPath);
});
@@ -1441,9 +1386,7 @@
uuidString = uuidStrBuffer;
}
- std::string_view binaryPath = mh->isDylib() ? binaryInstallName : path;
-
- SymbolsCacheBinary binary(std::string(binaryPath), platform, sliceArch,
+ SymbolsCacheBinary binary(std::string(binaryInstallName), platform, sliceArch,
std::string(uuidString), std::string(projectName));
binary.installName = binaryInstallName;
binary.exportedSymbols = std::move(exportedSymbols);
@@ -1730,7 +1673,7 @@
projectName = (const char*)sqlite3_column_text(statement, 4);
}
binaries.push_back({
- path, Platform((uint32_t)platform), arch,
+ path, mach_o::Platform((uint32_t)platform), arch,
(uuid != nullptr ? uuid : ""),
(projectName != nullptr ? projectName : "")
});
@@ -2012,12 +1955,11 @@
} // namespace std
-Error SymbolsCache::checkNewBinaries(bool warnOnRemovedSymbols, ExecutableMode executableMode,
+Error SymbolsCache::checkNewBinaries(bool warnOnRemovedSymbols,
std::vector<SymbolsCacheBinary>&& binaries,
const BinaryProjects& binaryProjects,
- std::vector<ResultBinary>& results,
- std::vector<mach_o::Error>& internalWarnings,
- std::vector<ExportsChangedBinary>* changedExports) const
+ std::vector<ErrorResultBinary>& errors,
+ std::vector<mach_o::Error>& warnings) const
{
// Split out in to OS dylibs vs other binaries
// We only want to verify the exports from OS binaries
@@ -2036,12 +1978,6 @@
for ( SymbolsCacheBinary& binary : osDylibs ) {
osDylibMap[{ binary.installName, binary.platform, binary.arch }] = &binary;
newClientsMap[{ binary.path, binary.platform, binary.arch }] = &binary;
-
- if ( binary.path.starts_with("/System/Cryptexes/OS/") ) {
- constexpr int prefixLen = std::string_view("/System/Cryptexes/OS").size();
- if ( binary.path.substr(prefixLen) == binary.installName )
- newClientsMap[{ binary.installName, binary.platform, binary.arch }] = &binary;
- }
}
for ( SymbolsCacheBinary* binary : otherBinaries )
@@ -2103,7 +2039,7 @@
std::vector<std::string> exports;
if ( Error err = ::getExports(this->symbolsDB, binaryID.value(), exports) ) {
// FIXME: What should we do here? For now log the error and skip the binary
- internalWarnings.push_back(Error("Skipping re-exported binary due to getExports(): %s", err.message()));
+ warnings.push_back(Error("Skipping re-exported binary due to getExports(): %s", err.message()));
continue;
}
@@ -2111,7 +2047,7 @@
std::vector<std::string> reexports;
if ( Error err = ::getReexports(this->symbolsDB, binaryID.value(), reexports) ) {
// FIXME: What should we do here? For now log the error and skip the binary
- internalWarnings.push_back(Error("Skipping re-exported binary due to getReexports(): %s", err.message()));
+ warnings.push_back(Error("Skipping re-exported binary due to getReexports(): %s", err.message()));
continue;
}
@@ -2157,7 +2093,7 @@
std::optional<int64_t> binaryID;
if ( Error err = getDylibID(this->symbolsDB, binary.installName, binary.platform, binary.arch, binaryID) ) {
// FIXME: What should we do here? For now log the error and skip the binary
- internalWarnings.push_back(Error("Skipping binary due to getDylibID(): %s", err.message()));
+ warnings.push_back(Error("Skipping binary due to getDylibID(): %s", err.message()));
continue;
}
@@ -2172,7 +2108,7 @@
std::vector<std::string> exports;
if ( Error err = ::getExports(this->symbolsDB, binaryID.value(), exports) ) {
// FIXME: What should we do here? For now log the error and skip the binary
- internalWarnings.push_back(Error("Skipping binary due to getExports(): %s", err.message()));
+ warnings.push_back(Error("Skipping binary due to getExports(): %s", err.message()));
continue;
}
@@ -2182,7 +2118,7 @@
std::vector<std::string> reexports;
if ( Error err = ::getReexports(this->symbolsDB, binaryID.value(), reexports) ) {
// FIXME: What should we do here? For now log the error and skip the binary
- internalWarnings.push_back(Error("Skipping re-exported binary due to getReexports(): %s", err.message()));
+ warnings.push_back(Error("Skipping re-exported binary due to getReexports(): %s", err.message()));
continue;
}
@@ -2216,7 +2152,7 @@
std::vector<std::string> nextReexports;
if ( Error err = ::getReexports(this->symbolsDB, reexportBinaryID.value(), nextReexports) ) {
// FIXME: What should we do here? For now log the error and skip the binary
- internalWarnings.push_back(Error("Skipping re-exported binary due to getReexports(): %s", err.message()));
+ warnings.push_back(Error("Skipping re-exported binary due to getReexports(): %s", err.message()));
continue;
}
@@ -2227,18 +2163,13 @@
std::vector<std::string> reexportedExports;
if ( Error err = ::getExports(this->symbolsDB, reexportedBinaryID, reexportedExports) ) {
// FIXME: What should we do here? For now log the error and skip the binary
- internalWarnings.push_back(Error("Skipping binary due to getExports(): %s", err.message()));
+ warnings.push_back(Error("Skipping binary due to getExports(): %s", err.message()));
continue;
}
exports.insert(exports.end(), reexportedExports.begin(), reexportedExports.end());
}
}
- }
-
- std::string binaryProject;
- if ( Error err = getBinaryProject(this->symbolsDB, binary.path, binary.platform, binary.arch, binaryProject) ) {
- // No project is ok. We can continue without it
}
// Work out if any exports were removed
@@ -2246,38 +2177,6 @@
removedExports.insert(exports.begin(), exports.end());
for ( std::string_view exp : binary.exportedSymbols )
removedExports.erase(exp);
-
- if ( changedExports != nullptr ) {
- // Find out if we added exports
- std::set<std::string_view> addedExports;
- addedExports.insert(binary.exportedSymbols.begin(), binary.exportedSymbols.end());
- for ( std::string_view exp : exports )
- addedExports.erase(exp);
-
- for ( std::string_view exp : removedExports ) {
- ExportsChangedBinary result;
- result.installName = binary.path;
- result.arch = binary.arch;
- result.uuid = binary.uuid;
- result.projectName = binaryProject;
- result.symbolName = exp;
- result.wasAdded = false;
-
- changedExports->push_back(std::move(result));
- }
-
- for ( std::string_view exp : addedExports ) {
- ExportsChangedBinary result;
- result.installName = binary.path;
- result.arch = binary.arch;
- result.uuid = binary.uuid;
- result.projectName = binaryProject;
- result.symbolName = exp;
- result.wasAdded = true;
-
- changedExports->push_back(std::move(result));
- }
- }
if ( removedExports.empty() ) {
if ( verbose )
@@ -2301,10 +2200,13 @@
// Note project name looks something like: dyld_tests-version.json
if ( binary.inputFileName.find("_tests-") != std::string_view::npos )
continue;
- if ( binary.inputFileName.find("Tests-") != std::string_view::npos )
- continue;
if ( binary.inputFileName.find("_lar-") != std::string_view::npos )
continue;
+ }
+
+ std::string binaryProject;
+ if ( Error err = getDylibProject(this->symbolsDB, binary.installName, binary.platform, binary.arch, binaryProject) ) {
+ // No project is ok. We can continue without it
}
// If we removed exports, now we need to see if they have uses
@@ -2312,14 +2214,14 @@
std::vector<std::string> clientPaths;
if ( Error err = getUsesOfExport(this->symbolsDB, binaryID.value(), exp, clientPaths) ) {
// FIXME: What should we do here? For now log the error and skip the binary export
- internalWarnings.push_back(Error("Skipping binary export due to getUsesOfExport(): %s", err.message()));
+ warnings.push_back(Error("Skipping binary export due to getUsesOfExport(): %s", err.message()));
continue;
}
// No uses. Skip this one
if ( clientPaths.empty() ) {
if ( warnOnRemovedSymbols )
- internalWarnings.push_back(Error("Binary '%s' removing unused export: '%s'", binary.path.data(), exp.data()));
+ warnings.push_back(Error("Binary '%s' removing unused export: '%s'", binary.path.data(), exp.data()));
continue;
}
@@ -2328,41 +2230,7 @@
std::string clientUUID;
std::string clientRootPath;
std::string clientProject;
- bool warnOnClient = false;
-
- // Skip executables and non-shared cache dylibs if we aren't verifying them
- {
- std::string clientInstallName;
- if ( Error err = getBinaryInstallName(this->symbolsDB, path, binary.platform, binary.arch, clientInstallName) ) {
- // Skip binaries if their install name generates some kind of error
- internalWarnings.push_back(Error("Skipping binary export due to getBinaryInstallName(): %s", err.message()));
- continue;
- }
-
- bool isCacheEligible = false;
- if ( !clientInstallName.empty() ) {
- isCacheEligible = Header::isSharedCacheEligiblePath(clientInstallName.data());
- }
-
- switch ( executableMode ) {
- case ExecutableMode::off:
- // This means we're verifying only shared cache dylibs. Skip everything else
- if ( !isCacheEligible )
- continue;
- break;
- case ExecutableMode::warn:
- // If we later find issues with this client, record them as errors
- // if its from the shared cache, but warnings otherwise
- if ( !isCacheEligible )
- warnOnClient = true;
- break;
- case ExecutableMode::error:
- // anu issues found here will be errors
- break;
- }
- }
-
- if ( Error err = getBinaryProject(this->symbolsDB, path, binary.platform, binary.arch, clientProject) ) {
+ if ( Error err = getDylibProject(this->symbolsDB, path, binary.platform, binary.arch, clientProject) ) {
// No project is ok. We can continue without it
}
if ( auto it = newClientsMap.find({ path, binary.platform, binary.arch }); it != newClientsMap.end() ) {
@@ -2392,26 +2260,25 @@
}
// See if we can get a UUID from the database
- if ( Error err = getBinaryUUID(this->symbolsDB, path, binary.platform, binary.arch, clientUUID) ) {
+ if ( Error err = getDylibUUID(this->symbolsDB, path, binary.platform, binary.arch, clientUUID) ) {
// No UUID is ok. We can continue without it
}
}
- ResultBinary result;
+ ErrorResultBinary result;
result.installName = binary.path;
result.arch = binary.arch;
result.uuid = binary.uuid;
result.rootPath = binary.rootPath;
- result.projectName = binaryProject;
- result.warn = warnOnClient;
-
- result.client.path = path;
+ result.projectName = binaryProject;;
+
+ result.client.installName = path;
result.client.uuid = clientUUID;
result.client.rootPath = clientRootPath;
result.client.projectName = clientProject;
result.client.symbolName = exp;
- results.push_back(std::move(result));
+ errors.push_back(std::move(result));
}
}
}
@@ -2473,303 +2340,3 @@
return Error::none();
}
-
-//
-// MARK: --- helper methods to output results ---
-//
-
-void printResultSummary(std::span<ResultBinary> verifyResults, bool bniOutput,
- FILE* summaryLogFile)
-{
- std::set<std::string> errorClientProjects;
- std::set<std::string> warnClientProjects;
-
- // Get the projects which are errors, then the list which are only warnings
- for ( const ResultBinary& result : verifyResults ) {
- if ( result.warn )
- continue;
-
- if ( result.client.projectName.empty())
- continue;
-
- errorClientProjects.insert(result.client.projectName);
- }
-
- // Get the projects which are errors, then the list which are only warnings
- for ( const ResultBinary& result : verifyResults ) {
- if ( !result.warn )
- continue;
-
- if ( result.client.projectName.empty())
- continue;
-
- // Skip projects also in the error list
- if ( errorClientProjects.count(result.client.projectName) )
- continue;
-
- warnClientProjects.insert(result.client.projectName);
- }
-
- if ( errorClientProjects.empty() && warnClientProjects.empty() )
- return;
-
- fprintf(summaryLogFile, "--- Summary ---\n\n");
-
- if ( !errorClientProjects.empty() )
- fprintf(summaryLogFile, "Error: some projects have removed symbols\n\n");
- else
- fprintf(summaryLogFile, "Warning: some projects have removed symbols\n\n");
-
- fprintf(summaryLogFile, "Expected resolution is to rebuild dependencies\n\n");
-
- auto printProjects = [&](const std::set<std::string>& clientProjects) {
- if ( bniOutput ) {
- fprintf(summaryLogFile, "Run command: xbs dispatch addProjects");
- for ( std::string_view project : clientProjects )
- fprintf(summaryLogFile, " %s", project.data());
- } else {
- fprintf(summaryLogFile, "Add the following to your submission notes, or container\n");
- fprintf(summaryLogFile, " REBUILD_DEPENDENCIES=");
- bool needsComma = false;
- for ( std::string_view project : clientProjects ) {
- if ( needsComma )
- fprintf(summaryLogFile, ",");
- else
- needsComma = true;
- fprintf(summaryLogFile, "%s", project.data());
- }
- }
- fprintf(summaryLogFile, "\n\n");
- };
-
- if ( !errorClientProjects.empty() )
- printProjects(errorClientProjects);
-
- if ( !warnClientProjects.empty() )
- printProjects(warnClientProjects);
-}
-
-void printResultsSymbolDetails(std::span<ResultBinary> verifyResults, FILE* detailsLogFile)
-{
- struct ProjectResult
- {
- struct Client
- {
- std::string path;
- std::string uuid;
- std::set<std::string> symbols;
- };
-
- struct ClientProject
- {
- // map from path to its results
- std::map<std::string, Client> clients;
- };
-
- struct Dylib
- {
- std::string uuid;
-
- // map from project name to its clients
- std::map<std::string, ClientProject> clientProjects;
- };
-
- // map from install name to its results
- std::map<std::string, Dylib> dylibs;
- };
-
- // map from project name to its results
- // loop twice. First iteration prints errors, second prints warnings
- for ( bool errors : { true, false } ) {
- std::map<std::string, ProjectResult> failingProjects;
- for ( const ResultBinary& result : verifyResults ) {
- if ( result.warn ) {
- // result is just a warning. Ok if we are generating warnings, but not if errors
- if ( errors )
- continue;
- } else {
- // result is an error. Ok if we are generating errors, but not if warnings
- if ( !errors )
- continue;
- }
-
- std::string projectName = result.projectName.empty() ? "<unknown project>" : result.projectName;
- std::string clientProjectName = result.client.projectName.empty() ? "<unknown project>" : result.client.projectName;
-
- ProjectResult& projectResult = failingProjects[projectName];
- ProjectResult::Dylib& dylib = projectResult.dylibs[result.installName];
-
- dylib.uuid = result.uuid;
- ProjectResult::ClientProject& clientProject = dylib.clientProjects[clientProjectName];
- ProjectResult::Client& client = clientProject.clients[result.client.path];
- client.path = result.client.path;
- client.uuid = result.client.uuid;
- client.symbols.insert(result.client.symbolName);
- }
-
- if ( failingProjects.empty() )
- continue;
-
- fprintf(detailsLogFile, "--- Detailed symbol information (%s) ---\n\n",
- errors ? "errors" : "warnings");
-
- for ( std::pair<std::string, ProjectResult> result : failingProjects ) {
- fprintf(detailsLogFile, "%s:\n", result.first.data());
- for ( std::pair<std::string, ProjectResult::Dylib> dylib : result.second.dylibs ) {
- std::string dylibUUID;
- if ( !dylib.second.uuid.empty())
- dylibUUID = " (" + dylib.second.uuid + ")";
- fprintf(detailsLogFile, " %s%s:\n", dylib.first.data(), dylibUUID.data());
-
- for ( std::pair<std::string, ProjectResult::ClientProject> clientProject : dylib.second.clientProjects ) {
- fprintf(detailsLogFile, " %s:\n", clientProject.first.data());
- for ( std::pair<std::string, ProjectResult::Client> client : clientProject.second.clients ) {
- std::string clientUUID;
- if ( !client.second.uuid.empty())
- clientUUID = " (" + client.second.uuid + ")";
- fprintf(detailsLogFile, " %s%s:\n", client.first.data(), clientUUID.data());
- for ( std::string_view symbolName : client.second.symbols )
- fprintf(detailsLogFile, " %s\n", symbolName.data());
- }
- }
- }
- fprintf(detailsLogFile, "\n");
- }
- }
-}
-
-void printResultsInternalInformation(std::span<ResultBinary> verifyResults,
- std::span<std::pair<std::string, std::string>> rootErrors,
- FILE* detailsLogFile)
-{
- std::set<std::string> usedRootPaths;
- for ( const ResultBinary& result : verifyResults ) {
- if ( !result.rootPath.empty() )
- usedRootPaths.insert(result.rootPath);
- if ( !result.client.rootPath.empty() )
- usedRootPaths.insert(result.client.rootPath);
- }
-
- if ( !usedRootPaths.empty() || !rootErrors.empty() ) {
- fprintf(detailsLogFile, "--- Internal information ---\n\n");
- }
-
- if ( !usedRootPaths.empty() ) {
- fprintf(detailsLogFile, "Note, the following root paths were used in the above errors:\n");
- for ( std::string_view usedRootPath : usedRootPaths ) {
- fprintf(detailsLogFile, " %s\n", usedRootPath.data());
- }
- fprintf(detailsLogFile, "\n");
- }
-
- if ( !rootErrors.empty() ) {
- fprintf(detailsLogFile, "Note, the following root paths were inaccessible:\n");
- for ( const auto& rootPathAndError : rootErrors ) {
- fprintf(detailsLogFile, " %s due to '%s'\n", rootPathAndError.first.data(), rootPathAndError.second.data());
- }
- fprintf(detailsLogFile, "\n");
- }
-}
-
-void printResultsJSON(std::span<ResultBinary> verifyResults,
- std::span<ExportsChangedBinary> exportsChanged,
- FILE* jsonFile)
-{
- fprintf(jsonFile, "{\n");
-
- {
- fprintf(jsonFile, " \"removed-used-symbols\" : [\n");
-
- bool needsComma = false;
- for ( const ResultBinary& binary : verifyResults ) {
- if ( needsComma )
- fprintf(jsonFile, ",\n");
- else
- needsComma = true;
-
- bool defInSharedCache = Header::isSharedCacheEligiblePath(binary.installName.c_str());
- bool useInSharedCache = Header::isSharedCacheEligiblePath(binary.client.path.c_str());
-
- fprintf(jsonFile, " {\n");
-
- fprintf(jsonFile, " \"arch\" : \"%s\",\n", binary.arch.c_str());
- fprintf(jsonFile, " \"symbol-name\" : \"%s\",\n", binary.client.symbolName.c_str());
-
- fprintf(jsonFile, " \"def-uuid\" : \"%s\",\n", binary.uuid.c_str());
- fprintf(jsonFile, " \"def-project-name\" : \"%s\",\n", binary.projectName.c_str());
- fprintf(jsonFile, " \"def-install-name\" : \"%s\",\n", binary.installName.c_str());
- fprintf(jsonFile, " \"def-shared-cache-eligible\" : \"%s\",\n", defInSharedCache ? "yes" : "no");
-
- fprintf(jsonFile, " \"use-uuid\" : \"%s\",\n", binary.client.uuid.c_str());
- fprintf(jsonFile, " \"use-project-name\" : \"%s\",\n", binary.client.projectName.c_str());
- fprintf(jsonFile, " \"use-path\" : \"%s\",\n", binary.client.path.c_str());
- fprintf(jsonFile, " \"use-shared-cache-eligible\" : \"%s\"\n", useInSharedCache ? "yes" : "no");
- fprintf(jsonFile, " }");
- }
- fprintf(jsonFile, "\n");
-
- fprintf(jsonFile, " ],\n");
- }
-
- {
- fprintf(jsonFile, " \"added-exports\" : [\n");
-
- bool needsComma = false;
- for ( const ExportsChangedBinary& binary : exportsChanged ) {
- if ( !binary.wasAdded )
- continue;
-
- if ( needsComma )
- fprintf(jsonFile, ",\n");
- else
- needsComma = true;
-
- bool inSharedCache = Header::isSharedCacheEligiblePath(binary.installName.c_str());
-
- fprintf(jsonFile, " {\n");
-
- fprintf(jsonFile, " \"arch\" : \"%s\",\n", binary.arch.c_str());
- fprintf(jsonFile, " \"symbol-name\" : \"%s\",\n", binary.symbolName.c_str());
- fprintf(jsonFile, " \"uuid\" : \"%s\",\n", binary.uuid.c_str());
- fprintf(jsonFile, " \"project-name\" : \"%s\",\n", binary.projectName.c_str());
- fprintf(jsonFile, " \"install-name\" : \"%s\",\n", binary.installName.c_str());
- fprintf(jsonFile, " \"shared-cache-eligible\" : \"%s\"\n", inSharedCache ? "yes" : "no");
- fprintf(jsonFile, " }");
- }
- fprintf(jsonFile, "\n");
-
- fprintf(jsonFile, " ],\n");
- }
-
- {
- fprintf(jsonFile, " \"removed-exports\" : [\n");
-
- bool needsComma = false;
- for ( const ExportsChangedBinary& binary : exportsChanged ) {
- if ( binary.wasAdded )
- continue;
-
- if ( needsComma )
- fprintf(jsonFile, ",\n");
- else
- needsComma = true;
-
- bool inSharedCache = Header::isSharedCacheEligiblePath(binary.installName.c_str());
-
- fprintf(jsonFile, " {\n");
-
- fprintf(jsonFile, " \"arch\" : \"%s\",\n", binary.arch.c_str());
- fprintf(jsonFile, " \"symbol-name\" : \"%s\",\n", binary.symbolName.c_str());
- fprintf(jsonFile, " \"uuid\" : \"%s\",\n", binary.uuid.c_str());
- fprintf(jsonFile, " \"project-name\" : \"%s\",\n", binary.projectName.c_str());
- fprintf(jsonFile, " \"install-name\" : \"%s\",\n", binary.installName.c_str());
- fprintf(jsonFile, " \"shared-cache-eligible\" : \"%s\"\n", inSharedCache ? "yes" : "no");
- fprintf(jsonFile, " }");
- }
- fprintf(jsonFile, "\n");
-
- fprintf(jsonFile, " ]\n");
- }
-
- fprintf(jsonFile, "}\n");
-}