mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Restructure the ELF handling to be completely agnostic to the OS. Rather than usng the loader to query the section information, use the linker to construct linker tables and synthetic markers for the beginning and of the table. Save off the values of these pointers and pass them along through the constructor to the runtime for registration. This removes the need for the begin/end objects. Remove the special construction of the begin/end objects through the special assembly constructs, preferring to do this in C with a bit of inline assembly to ensure that the section is always allocated. Remove the special handling for the various targets, the empty object file can be linked on all the targets. The new object file has no requirements on the ordering. It needs to simply be injected into the link. Name the replacement file `swiftrt.o` mirroring `crt.o` from libc. Merge the constructor and the definition into a single object file. This approach is generally more portable, overall simpler to implement, and more robust. Thanks to Orlando Bassotto for help analyzing some of the odd behaviours when switching over.
218 lines
7.0 KiB
C++
218 lines
7.0 KiB
C++
//===--- swift-reflection-dump.cpp - Reflection testing application -------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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/Demangling/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 <io.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <csignal>
|
|
|
|
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<ActionType>
|
|
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<std::string>
|
|
BinaryFilename("binary-filename", llvm::cl::desc("Filenames of the binary files"),
|
|
llvm::cl::OneOrMore);
|
|
|
|
static llvm::cl::opt<std::string>
|
|
Architecture("arch", llvm::cl::desc("Architecture to inspect in the binary"),
|
|
llvm::cl::Required);
|
|
} // end namespace options
|
|
|
|
template<typename T>
|
|
static T unwrap(llvm::Expected<T> 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<StringRef> anySectionNames) {
|
|
for (auto section : objectFile->sections()) {
|
|
StringRef sectionName;
|
|
section.getName(sectionName);
|
|
for (auto desiredName : anySectionNames) {
|
|
if (sectionName.equals(desiredName)) {
|
|
return section;
|
|
}
|
|
}
|
|
}
|
|
return SectionRef();
|
|
}
|
|
|
|
template <typename Section>
|
|
static Section findReflectionSection(const ObjectFile *objectFile,
|
|
ArrayRef<StringRef> anySectionNames) {
|
|
auto sectionRef = getSectionRef(objectFile, anySectionNames);
|
|
|
|
if (sectionRef.getObject() == nullptr)
|
|
return {nullptr, nullptr};
|
|
|
|
StringRef sectionContents;
|
|
sectionRef.getContents(sectionContents);
|
|
|
|
return {
|
|
reinterpret_cast<const void *>(sectionContents.begin()),
|
|
reinterpret_cast<const void *>(sectionContents.end())
|
|
};
|
|
}
|
|
|
|
static ReflectionInfo findReflectionInfo(const ObjectFile *objectFile) {
|
|
auto fieldSection = findReflectionSection<FieldSection>(
|
|
objectFile, {"__swift3_fieldmd", ".swift3_fieldmd", "swift3_fieldmd"});
|
|
auto associatedTypeSection = findReflectionSection<AssociatedTypeSection>(
|
|
objectFile, {"__swift3_assocty", ".swift3_assocty", "swift3_assocty"});
|
|
auto builtinTypeSection = findReflectionSection<BuiltinTypeSection>(
|
|
objectFile, {"__swift3_builtin", ".swift3_builtin", "swift3_builtin"});
|
|
auto captureSection = findReflectionSection<CaptureSection>(
|
|
objectFile, {"__swift3_capture", ".swift3_capture", "swift3_capture"});
|
|
auto typeRefSection = findReflectionSection<GenericSection>(
|
|
objectFile, {"__swift3_typeref", ".swift3_typeref", "swift3_typeref"});
|
|
auto reflectionStringsSection = findReflectionSection<GenericSection>(
|
|
objectFile, {"__swift3_reflstr", ".swift3_reflstr", "swift3_reflstr"});
|
|
|
|
return {
|
|
fieldSection,
|
|
associatedTypeSection,
|
|
builtinTypeSection,
|
|
captureSection,
|
|
typeRefSection,
|
|
reflectionStringsSection,
|
|
/*LocalStartAddress*/ 0,
|
|
/*RemoteStartAddress*/ 0,
|
|
};
|
|
}
|
|
|
|
static int doDumpReflectionSections(ArrayRef<std::string> 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<OwningBinary<Binary>> binaryOwners;
|
|
std::vector<std::unique_ptr<ObjectFile>> 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<ObjectFile> objectOwner;
|
|
const ObjectFile *objectFile;
|
|
|
|
if (auto o = dyn_cast<ObjectFile>(binaryFile)) {
|
|
objectFile = o;
|
|
} else {
|
|
auto universal = cast<MachOUniversalBinary>(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;
|
|
|
|
Demangle::Demangler Dem;
|
|
auto demangled = Dem.demangleType(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);
|
|
}
|
|
|