mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Previously it was part of swiftBasic. The demangler library does not depend on llvm (except some header-only utilities like StringRef). Putting it into its own library makes sure that no llvm stuff will be linked into clients which use the demangler library. This change also contains other refactoring, like moving demangler code into different files. This makes it easier to remove the old demangler from the runtime library when we switch to the new symbol mangling. Also in this commit: remove some unused API functions from the demangler Context. fixes rdar://problem/30503344
218 lines
6.9 KiB
C++
218 lines
6.9 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"});
|
|
auto associatedTypeSection = findReflectionSection<AssociatedTypeSection>(
|
|
objectFile, {"__swift3_assocty", ".swift3_assocty"});
|
|
auto builtinTypeSection = findReflectionSection<BuiltinTypeSection>(
|
|
objectFile, {"__swift3_builtin", ".swift3_builtin"});
|
|
auto captureSection = findReflectionSection<CaptureSection>(
|
|
objectFile, {"__swift3_capture", ".swift3_capture"});
|
|
auto typeRefSection = findReflectionSection<GenericSection>(
|
|
objectFile, {"__swift3_typeref", ".swift3_typeref"});
|
|
auto reflectionStringsSection = findReflectionSection<GenericSection>(
|
|
objectFile, {"__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);
|
|
}
|
|
|