//===--- swift-reflection-dump.cpp - Reflection testing application -------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // This is a host-side tool to dump remote reflection sections in swift // binaries. //===----------------------------------------------------------------------===// #include "swift/ABI/MetadataValues.h" #include "swift/Basic/Demangle.h" #include "swift/Basic/LLVMInitialize.h" #include "swift/Reflection/TypeRef.h" #include "swift/Reflection/TypeRefBuilder.h" #include "llvm/Object/Archive.h" #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ELF.h" #include "llvm/Support/CommandLine.h" #if defined(_WIN32) #include #else #include #endif #include #include #include using llvm::dyn_cast; using llvm::StringRef; using llvm::ArrayRef; using namespace llvm::object; using namespace swift; using namespace swift::reflection; using namespace swift::remote; using namespace Demangle; enum class ActionType { DumpReflectionSections, DumpTypeLowering }; namespace options { static llvm::cl::opt Action(llvm::cl::desc("Mode:"), llvm::cl::values( clEnumValN(ActionType::DumpReflectionSections, "dump-reflection-sections", "Dump the field reflection section"), clEnumValN(ActionType::DumpTypeLowering, "dump-type-lowering", "Dump the field layout for typeref strings read from stdin")), llvm::cl::init(ActionType::DumpReflectionSections)); static llvm::cl::list BinaryFilename("binary-filename", llvm::cl::desc("Filenames of the binary files"), llvm::cl::OneOrMore); static llvm::cl::opt Architecture("arch", llvm::cl::desc("Architecture to inspect in the binary"), llvm::cl::Required); } // end namespace options template static T unwrap(llvm::Expected value) { if (value) return std::move(value.get()); std::cerr << "swift-reflection-test error: " << toString(value.takeError()) << "\n"; exit(EXIT_FAILURE); } static SectionRef getSectionRef(const ObjectFile *objectFile, ArrayRef anySectionNames) { for (auto section : objectFile->sections()) { StringRef sectionName; section.getName(sectionName); for (auto desiredName : anySectionNames) { if (sectionName.equals(desiredName)) { return section; } } } return SectionRef(); } template static Section findReflectionSection(const ObjectFile *objectFile, ArrayRef anySectionNames) { auto sectionRef = getSectionRef(objectFile, anySectionNames); if (sectionRef.getObject() == nullptr) return {nullptr, nullptr}; StringRef sectionContents; sectionRef.getContents(sectionContents); return { reinterpret_cast(sectionContents.begin()), reinterpret_cast(sectionContents.end()) }; } static ReflectionInfo findReflectionInfo(const ObjectFile *objectFile) { auto fieldSection = findReflectionSection( objectFile, {"__swift3_fieldmd", ".swift3_fieldmd"}); auto associatedTypeSection = findReflectionSection( objectFile, {"__swift3_assocty", ".swift3_assocty"}); auto builtinTypeSection = findReflectionSection( objectFile, {"__swift3_builtin", ".swift3_builtin"}); auto captureSection = findReflectionSection( objectFile, {"__swift3_capture", ".swift3_capture"}); auto typeRefSection = findReflectionSection( objectFile, {"__swift3_typeref", ".swift3_typeref"}); auto reflectionStringsSection = findReflectionSection( objectFile, {"__swift3_reflstr", ".swift3_reflstr"}); return { fieldSection, associatedTypeSection, builtinTypeSection, captureSection, typeRefSection, reflectionStringsSection, /*LocalStartAddress*/ 0, /*RemoteStartAddress*/ 0, }; } static int doDumpReflectionSections(ArrayRef binaryFilenames, StringRef arch, ActionType action, std::ostream &OS) { // Note: binaryOrError and objectOrError own the memory for our ObjectFile; // once they go out of scope, we can no longer do anything. std::vector> binaryOwners; std::vector> objectOwners; // Construct the TypeRefBuilder TypeRefBuilder builder; for (auto binaryFilename : binaryFilenames) { auto binaryOwner = unwrap(createBinary(binaryFilename)); Binary *binaryFile = binaryOwner.getBinary(); // The object file we are doing lookups in -- either the binary itself, or // a particular slice of a universal binary. std::unique_ptr objectOwner; const ObjectFile *objectFile; if (auto o = dyn_cast(binaryFile)) { objectFile = o; } else { auto universal = cast(binaryFile); objectOwner = unwrap(universal->getObjectForArch(arch)); objectFile = objectOwner.get(); } builder.addReflectionInfo(findReflectionInfo(objectFile)); // Retain the objects that own section memory binaryOwners.push_back(std::move(binaryOwner)); objectOwners.push_back(std::move(objectOwner)); } switch (action) { case ActionType::DumpReflectionSections: // Dump everything builder.dumpAllSections(OS); break; case ActionType::DumpTypeLowering: { for (std::string line; std::getline(std::cin, line); ) { if (line.empty()) continue; if (StringRef(line).startswith("//")) continue; auto demangled = Demangle::demangleTypeAsNode(line); auto *typeRef = swift::remote::decodeMangledType(builder, demangled); if (typeRef == nullptr) { OS << "Invalid typeref: " << line << "\n"; continue; } typeRef->dump(OS); auto *typeInfo = builder.getTypeConverter().getTypeInfo(typeRef); if (typeInfo == nullptr) { OS << "Invalid lowering\n"; continue; } typeInfo->dump(OS); } break; } } return EXIT_SUCCESS; } int main(int argc, char *argv[]) { llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Reflection Dump\n"); return doDumpReflectionSections(options::BinaryFilename, options::Architecture, options::Action, std::cout); }