mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Split swift-refleciton-test into host and target test targets
swift-reflection-test is now the test that forks a swift executable and performs remote reflection, making it runnable on other targets, such as the iOS simulator. swift-reflection-dump is now a host-side tool that dumps the remote reflection sections for any platform binary and will continue to link in LLVM object file support. This necessitates finally moving lib/Refleciton into stdlib/public, since we're linking target-specific versions of the test tool and we would eventually like to adopt some of this functionality in the runtime anyway.
This commit is contained in:
@@ -699,6 +699,12 @@ if(SWIFT_BUILD_TOOLS)
|
||||
endif()
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(stdlib)
|
||||
|
||||
if(SWIFT_BUILD_TOOLS)
|
||||
add_subdirectory(tools/swift-reflection-test)
|
||||
add_subdirectory(tools/swift-reflection-dump)
|
||||
endif()
|
||||
|
||||
if(SWIFT_BUILD_PERF_TESTSUITE AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
||||
add_subdirectory(benchmark)
|
||||
endif()
|
||||
|
||||
@@ -1847,7 +1847,7 @@ endfunction()
|
||||
function(add_swift_target_executable name)
|
||||
# Parse the arguments we were given.
|
||||
cmake_parse_arguments(SWIFTEXE_TARGET
|
||||
"EXCLUDE_FROM_ALL;DONT_STRIP_NON_MAIN_SYMBOLS;DISABLE_ASLR"
|
||||
"EXCLUDE_FROM_ALL;DONT_STRIP_NON_MAIN_SYMBOLS;DISABLE_ASLR;BUILD_WITH_STDLIB"
|
||||
""
|
||||
"DEPENDS;COMPONENT_DEPENDS;LINK_FAT_LIBRARIES"
|
||||
${ARGN})
|
||||
@@ -1887,6 +1887,10 @@ function(add_swift_target_executable name)
|
||||
set(SWIFTEXE_TARGET_EXCLUDE_FROM_ALL_FLAG_CURRENT "EXCLUDE_FROM_ALL")
|
||||
endif()
|
||||
|
||||
if(SWIFTEXE_TARGET_BUILD_WITH_STDLIB)
|
||||
add_dependencies("swift-test-stdlib${VARIANT_SUFFIX}" ${VARIANT_NAME})
|
||||
endif()
|
||||
|
||||
# Don't add the ${arch} to the suffix. We want to link against fat
|
||||
# libraries.
|
||||
_list_add_string_suffix(
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ add_subdirectory(Markup)
|
||||
add_subdirectory(Option)
|
||||
add_subdirectory(Parse)
|
||||
add_subdirectory(PrintAsObjC)
|
||||
add_subdirectory(Reflection)
|
||||
add_subdirectory(Sema)
|
||||
add_subdirectory(Serialization)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
add_swift_library(swiftReflection
|
||||
TypeRef.cpp
|
||||
LINK_LIBRARIES swiftBasic)
|
||||
@@ -187,8 +187,8 @@ internal func sendReflectionInfos() {
|
||||
for info in infos {
|
||||
debugLog("Sending info for \(info.imageName)")
|
||||
let imageNameBytes = Array(info.imageName.utf8)
|
||||
var imageNameLength = UInt64(imageNameBytes.count)
|
||||
fwrite(&imageNameLength, sizeof(UInt64.self), 1, stdout)
|
||||
var imageNameLength = UInt(imageNameBytes.count)
|
||||
fwrite(&imageNameLength, sizeof(UInt.self), 1, stdout)
|
||||
fflush(stdout)
|
||||
fwrite(imageNameBytes, 1, imageNameBytes.count, stdout)
|
||||
fflush(stdout)
|
||||
@@ -235,7 +235,7 @@ internal func sendSymbolAddress() {
|
||||
name.withCString {
|
||||
let handle = unsafeBitCast(Int(-2), to: UnsafeMutablePointer<Void>.self)
|
||||
let symbol = dlsym(handle, $0)
|
||||
let symbolAddress = unsafeBitCast(symbol, to: UInt64.self)
|
||||
let symbolAddress = unsafeBitCast(symbol, to: UInt.self)
|
||||
sendValue(symbolAddress)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ if(SWIFT_BUILD_STDLIB)
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(SwiftOnoneSupport)
|
||||
add_subdirectory(Platform)
|
||||
add_subdirectory(Reflection)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
|
||||
5
stdlib/public/Reflection/CMakeLists.txt
Normal file
5
stdlib/public/Reflection/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
add_swift_library(swiftReflection IS_STDLIB
|
||||
Demangle.cpp
|
||||
Remangle.cpp
|
||||
TypeRef.cpp
|
||||
INSTALL_IN_COMPONENT stdlib)
|
||||
3
stdlib/public/Reflection/Demangle.cpp
Normal file
3
stdlib/public/Reflection/Demangle.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "../../../lib/Basic/Demangle.cpp"
|
||||
#include "../../../lib/Basic/Punycode.cpp"
|
||||
#include "../../../lib/Basic/PunycodeUTF8.cpp"
|
||||
1
stdlib/public/Reflection/Remangle.cpp
Normal file
1
stdlib/public/Reflection/Remangle.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "../../../lib/Basic/Remangle.cpp"
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "swift/Basic/Demangle.h"
|
||||
#include "swift/Reflection/ReflectionContext.h"
|
||||
#include "swift/Reflection/TypeRef.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
using namespace swift;
|
||||
using namespace reflection;
|
||||
@@ -396,7 +395,7 @@ static unsigned _getDepth(TypeRef *TR) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Unexpected type ref kind asked for parent type");
|
||||
assert(false && "Asked for depth on non-nominal typeref");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// UNSUPPORTED: objc_interop
|
||||
// RUN: rm -rf %t && mkdir -p %t
|
||||
// RUN: %target-swiftc_driver %S/Inputs/ConcreteTypes.swift %S/Inputs/GenericTypes.swift %S/Inputs/Protocols.swift -emit-module -emit-library -module-name TypesToReflect -Xfrontend -enable-reflection-metadata -o %t/libTypesToReflect
|
||||
// RUN: %target-swift-reflection-test -binary-filename %t/libTypesToReflect -dump-reflection-sections > %t/typeref_decoding.txt
|
||||
// RUN: %target-swift-reflection-dump -binary-filename %t/libTypesToReflect > %t/typeref_decoding.txt
|
||||
// RUN: diff -u %S/typeref_decoding.result.txt %t/typeref_decoding.txt
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// RUN: rm -rf %t && mkdir -p %t
|
||||
// RUN: %target-swiftc_driver %S/Inputs/ConcreteTypes.swift %S/Inputs/GenericTypes.swift %S/Inputs/Protocols.swift -emit-module -emit-library -module-name TypesToReflect -Xfrontend -enable-reflection-metadata -o %t/libTypesToReflect
|
||||
// RUN: %target-swift-reflection-test -binary-filename %t/libTypesToReflect -dump-reflection-sections > %t/typeref_decoding.txt
|
||||
// RUN: %target-swift-reflection-dump -binary-filename %t/libTypesToReflect > %t/typeref_decoding.txt
|
||||
// RUN: diff -u %S/typeref_decoding_objc.result.txt %t/typeref_decoding.txt
|
||||
// REQUIRES: objc_interop
|
||||
|
||||
@@ -272,6 +272,7 @@ config.sil_extract = inferSwiftBinary('sil-extract')
|
||||
config.lldb_moduleimport_test = inferSwiftBinary('lldb-moduleimport-test')
|
||||
config.swift_ide_test = inferSwiftBinary('swift-ide-test')
|
||||
config.swift_reflection_test = inferSwiftBinary('swift-reflection-test')
|
||||
config.swift_reflection_dump = inferSwiftBinary('swift-reflection-dump')
|
||||
config.clang = inferSwiftBinary('clang')
|
||||
config.llvm_link = inferSwiftBinary('llvm-link')
|
||||
config.swift_llvm_opt = inferSwiftBinary('swift-llvm-opt')
|
||||
@@ -840,7 +841,8 @@ config.substitutions.append(
|
||||
(subst_target_swift_ide_test_mock_sdk,
|
||||
subst_target_swift_ide_test_mock_sdk_after)))
|
||||
config.substitutions.append(('%target-swift-ide-test', config.target_swift_ide_test))
|
||||
config.substitutions.append(('%target-swift-reflection-test', '{} {} {}'.format(config.swift_reflection_test, '-arch', run_cpu)))
|
||||
config.substitutions.append(('%target-swift-reflection-test', '{test_runner}{variant_suffix} {arch}'.format(test_runner=config.swift_reflection_test, variant_suffix=config.variant_suffix, arch=run_cpu)))
|
||||
config.substitutions.append(('%target-swift-reflection-dump', '{} {} {}'.format(config.swift_reflection_dump, '-arch', run_cpu)))
|
||||
config.substitutions.append(('%target-swiftc_driver', config.target_swiftc_driver))
|
||||
|
||||
if hasattr(config, 'target_swift_autolink_extract'):
|
||||
|
||||
@@ -15,6 +15,7 @@ config.target_triple = "@TARGET_TRIPLE@"
|
||||
config.targets_to_build = "@TARGETS_TO_BUILD@"
|
||||
config.variant_triple = "@VARIANT_TRIPLE@"
|
||||
config.variant_sdk = "@VARIANT_SDK@"
|
||||
config.variant_suffix = "@VARIANT_SUFFIX@"
|
||||
config.swiftlib_dir = "@LIT_SWIFTLIB_DIR@"
|
||||
config.darwin_xcrun_toolchain = "@SWIFT_DARWIN_XCRUN_TOOLCHAIN@"
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ add_subdirectory(swift-demangle)
|
||||
add_subdirectory(lldb-moduleimport-test)
|
||||
add_subdirectory(sil-extract)
|
||||
add_subdirectory(swift-llvm-opt)
|
||||
add_subdirectory(swift-reflection-test)
|
||||
|
||||
if(SWIFT_BUILD_SOURCEKIT)
|
||||
add_subdirectory(SourceKit)
|
||||
|
||||
11
tools/swift-reflection-dump/CMakeLists.txt
Normal file
11
tools/swift-reflection-dump/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
add_swift_executable(swift-reflection-dump
|
||||
swift-reflection-dump.cpp
|
||||
LINK_FAT_LIBRARIES
|
||||
swiftReflection
|
||||
COMPONENT_DEPENDS object support
|
||||
)
|
||||
|
||||
swift_install_in_component(tools
|
||||
TARGETS swift-reflection-dump
|
||||
RUNTIME DESTINATION bin)
|
||||
|
||||
202
tools/swift-reflection-dump/swift-reflection-dump.cpp
Normal file
202
tools/swift-reflection-dump/swift-reflection-dump.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
//===--- swift-reflection-test.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 http://swift.org/LICENSE.txt for license information
|
||||
// See http://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/ReflectionContext.h"
|
||||
#include "swift/Reflection/TypeRef.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"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#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 reflection;
|
||||
using namespace Demangle;
|
||||
|
||||
enum class ActionType {
|
||||
None,
|
||||
DumpReflectionSections,
|
||||
DumpHeapInstance
|
||||
};
|
||||
|
||||
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::DumpHeapInstance,
|
||||
"dump-heap-instance",
|
||||
"Dump the field layout for a heap instance by running "
|
||||
"a Swift executable"),
|
||||
clEnumValEnd));
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
BinaryFilename("binary-filename", llvm::cl::desc("Filename of the binary file"),
|
||||
llvm::cl::Required);
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
Architecture("arch", llvm::cl::desc("Architecture to inspect in the binary"),
|
||||
llvm::cl::Required);
|
||||
} // end namespace options
|
||||
|
||||
static void guardError(std::error_code error) {
|
||||
if (!error) return;
|
||||
std::cerr << "swift-reflection-test error: " << error.message() << "\n";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static llvm::object::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 llvm::object::SectionRef();
|
||||
}
|
||||
|
||||
static llvm::object::SectionRef
|
||||
getSectionRef(const Binary *binaryFile, StringRef arch,
|
||||
ArrayRef<StringRef> anySectionNames) {
|
||||
if (auto objectFile = dyn_cast<ObjectFile>(binaryFile))
|
||||
return getSectionRef(objectFile, anySectionNames);
|
||||
if (auto machoUniversal = dyn_cast<MachOUniversalBinary>(binaryFile)) {
|
||||
const auto objectOrError = machoUniversal->getObjectForArch(arch);
|
||||
guardError(objectOrError.getError());
|
||||
return getSectionRef(objectOrError.get().get(), anySectionNames);
|
||||
}
|
||||
return SectionRef();
|
||||
}
|
||||
|
||||
static int doDumpReflectionSections(std::string BinaryFilename,
|
||||
StringRef arch) {
|
||||
auto binaryOrError = llvm::object::createBinary(BinaryFilename);
|
||||
guardError(binaryOrError.getError());
|
||||
|
||||
const auto binary = binaryOrError.get().getBinary();
|
||||
|
||||
auto FieldSectionRef = getSectionRef(binary, arch, {
|
||||
"__swift3_fieldmd", ".swift3_fieldmd"
|
||||
});
|
||||
|
||||
if (FieldSectionRef.getObject() == nullptr) {
|
||||
std::cerr << BinaryFilename;
|
||||
std::cerr << " doesn't have a field reflection section!\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto AssociatedTypeSectionRef = getSectionRef(binary, arch, {
|
||||
"__swift3_assocty", ".swift3_assocty"
|
||||
});
|
||||
|
||||
if (AssociatedTypeSectionRef.getObject() == nullptr) {
|
||||
std::cerr << BinaryFilename;
|
||||
std::cerr << " doesn't have an associated type reflection section!\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto ReflectionStringsSectionRef = getSectionRef(binary, arch, {
|
||||
"__swift3_reflstr", ".swift3_reflstr"
|
||||
});
|
||||
|
||||
if (ReflectionStringsSectionRef.getObject() == nullptr) {
|
||||
std::cerr << BinaryFilename;
|
||||
std::cerr << " doesn't have an associated reflection strings section!\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto TypeRefSectionRef = getSectionRef(binary, arch, {
|
||||
"__swift3_typeref", ".swift3_typeref"
|
||||
});
|
||||
|
||||
if (TypeRefSectionRef.getObject() == nullptr) {
|
||||
std::cerr << BinaryFilename;
|
||||
std::cerr << " doesn't have an associated typeref section!\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
StringRef FieldSectionContents;
|
||||
FieldSectionRef.getContents(FieldSectionContents);
|
||||
|
||||
const FieldSection fieldSection {
|
||||
reinterpret_cast<const void *>(FieldSectionContents.begin()),
|
||||
reinterpret_cast<const void *>(FieldSectionContents.end())
|
||||
};
|
||||
|
||||
StringRef AssociatedTypeSectionContents;
|
||||
AssociatedTypeSectionRef.getContents(AssociatedTypeSectionContents);
|
||||
|
||||
const AssociatedTypeSection associatedTypeSection {
|
||||
reinterpret_cast<const void *>(AssociatedTypeSectionContents.begin()),
|
||||
reinterpret_cast<const void *>(AssociatedTypeSectionContents.end())
|
||||
};
|
||||
|
||||
StringRef ReflectionStringsSectionContents;
|
||||
ReflectionStringsSectionRef.getContents(ReflectionStringsSectionContents);
|
||||
|
||||
const GenericSection ReflectionStringsSection {
|
||||
reinterpret_cast<const void *>(ReflectionStringsSectionContents.begin()),
|
||||
reinterpret_cast<const void *>(ReflectionStringsSectionContents.end())
|
||||
};
|
||||
|
||||
StringRef TypeRefSectionContents;
|
||||
AssociatedTypeSectionRef.getContents(TypeRefSectionContents);
|
||||
|
||||
const GenericSection TypeRefSection {
|
||||
reinterpret_cast<const void *>(TypeRefSectionContents.begin()),
|
||||
reinterpret_cast<const void *>(TypeRefSectionContents.end())
|
||||
};
|
||||
|
||||
InProcessMemoryReader Reader;
|
||||
ReflectionContext<External<RuntimeTarget<8>>> RC(Reader);
|
||||
RC.addReflectionInfo({
|
||||
BinaryFilename,
|
||||
fieldSection,
|
||||
associatedTypeSection,
|
||||
ReflectionStringsSection,
|
||||
TypeRefSection,
|
||||
});
|
||||
RC.dumpAllSections(std::cout);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Reflection Dump\n");
|
||||
return doDumpReflectionSections(options::BinaryFilename,
|
||||
options::Architecture);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
add_swift_executable(swift-reflection-test
|
||||
add_swift_target_executable(swift-reflection-test BUILD_WITH_STDLIB
|
||||
swift-reflection-test.cpp
|
||||
LINK_LIBRARIES
|
||||
swiftBasic
|
||||
swiftReflection
|
||||
|
||||
COMPONENT_DEPENDS object support
|
||||
)
|
||||
|
||||
swift_install_in_component(tools
|
||||
TARGETS swift-reflection-test
|
||||
RUNTIME DESTINATION bin)
|
||||
LINK_FAT_LIBRARIES
|
||||
swiftReflection)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===--- swift-reflection-test.cpp - Reflection testing application -------===//
|
||||
//===--- swift-reflection-dump.cpp - Reflection testing application -------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
@@ -9,200 +9,26 @@
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This file supports performing target-specific remote reflection tests
|
||||
// on live swift executables.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "swift/ABI/MetadataValues.h"
|
||||
#include "swift/Basic/Demangle.h"
|
||||
#include "swift/Basic/LLVMInitialize.h"
|
||||
#include "swift/Reflection/ReflectionContext.h"
|
||||
#include "swift/Reflection/TypeRef.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"
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "messages.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#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 reflection;
|
||||
using namespace Demangle;
|
||||
|
||||
namespace {
|
||||
|
||||
enum class ActionType {
|
||||
None,
|
||||
DumpReflectionSections,
|
||||
DumpHeapInstance
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
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::DumpHeapInstance,
|
||||
"dump-heap-instance",
|
||||
"Dump the field layout for a heap instance by running "
|
||||
"a Swift executable"),
|
||||
clEnumValEnd));
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
BinaryFilename("binary-filename", llvm::cl::desc("Filename of the binary file"),
|
||||
llvm::cl::Required);
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
Architecture("arch", llvm::cl::desc("Architecture to inspect in the binary"),
|
||||
llvm::cl::Required);
|
||||
} // end namespace options
|
||||
|
||||
|
||||
static void guardError(std::error_code error) {
|
||||
if (!error) return;
|
||||
std::cerr << "swift-reflection-test error: " << error.message() << "\n";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void errorAndExit(const std::string &message) {
|
||||
std::cerr << message << ": " << strerror(errno) << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static llvm::object::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 llvm::object::SectionRef();
|
||||
}
|
||||
|
||||
static llvm::object::SectionRef
|
||||
getSectionRef(const Binary *binaryFile, StringRef arch,
|
||||
ArrayRef<StringRef> anySectionNames) {
|
||||
if (auto objectFile = dyn_cast<ObjectFile>(binaryFile))
|
||||
return getSectionRef(objectFile, anySectionNames);
|
||||
if (auto machoUniversal = dyn_cast<MachOUniversalBinary>(binaryFile)) {
|
||||
const auto objectOrError = machoUniversal->getObjectForArch(arch);
|
||||
guardError(objectOrError.getError());
|
||||
return getSectionRef(objectOrError.get().get(), anySectionNames);
|
||||
}
|
||||
return SectionRef();
|
||||
}
|
||||
|
||||
static int doDumpReflectionSections(std::string BinaryFilename,
|
||||
StringRef arch) {
|
||||
auto binaryOrError = llvm::object::createBinary(BinaryFilename);
|
||||
guardError(binaryOrError.getError());
|
||||
|
||||
const auto binary = binaryOrError.get().getBinary();
|
||||
|
||||
auto FieldSectionRef = getSectionRef(binary, arch, {
|
||||
"__swift3_fieldmd", ".swift3_fieldmd"
|
||||
});
|
||||
|
||||
if (FieldSectionRef.getObject() == nullptr) {
|
||||
std::cerr << BinaryFilename;
|
||||
std::cerr << " doesn't have a field reflection section!\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto AssociatedTypeSectionRef = getSectionRef(binary, arch, {
|
||||
"__swift3_assocty", ".swift3_assocty"
|
||||
});
|
||||
|
||||
if (AssociatedTypeSectionRef.getObject() == nullptr) {
|
||||
std::cerr << BinaryFilename;
|
||||
std::cerr << " doesn't have an associated type reflection section!\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto ReflectionStringsSectionRef = getSectionRef(binary, arch, {
|
||||
"__swift3_reflstr", ".swift3_reflstr"
|
||||
});
|
||||
|
||||
if (ReflectionStringsSectionRef.getObject() == nullptr) {
|
||||
std::cerr << BinaryFilename;
|
||||
std::cerr << " doesn't have an associated reflection strings section!\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto TypeRefSectionRef = getSectionRef(binary, arch, {
|
||||
"__swift3_typeref", ".swift3_typeref"
|
||||
});
|
||||
|
||||
if (TypeRefSectionRef.getObject() == nullptr) {
|
||||
std::cerr << BinaryFilename;
|
||||
std::cerr << " doesn't have an associated typeref section!\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
StringRef FieldSectionContents;
|
||||
FieldSectionRef.getContents(FieldSectionContents);
|
||||
|
||||
const FieldSection fieldSection {
|
||||
reinterpret_cast<const void *>(FieldSectionContents.begin()),
|
||||
reinterpret_cast<const void *>(FieldSectionContents.end())
|
||||
};
|
||||
|
||||
StringRef AssociatedTypeSectionContents;
|
||||
AssociatedTypeSectionRef.getContents(AssociatedTypeSectionContents);
|
||||
|
||||
const AssociatedTypeSection associatedTypeSection {
|
||||
reinterpret_cast<const void *>(AssociatedTypeSectionContents.begin()),
|
||||
reinterpret_cast<const void *>(AssociatedTypeSectionContents.end())
|
||||
};
|
||||
|
||||
StringRef ReflectionStringsSectionContents;
|
||||
ReflectionStringsSectionRef.getContents(ReflectionStringsSectionContents);
|
||||
|
||||
const GenericSection ReflectionStringsSection {
|
||||
reinterpret_cast<const void *>(ReflectionStringsSectionContents.begin()),
|
||||
reinterpret_cast<const void *>(ReflectionStringsSectionContents.end())
|
||||
};
|
||||
|
||||
StringRef TypeRefSectionContents;
|
||||
AssociatedTypeSectionRef.getContents(TypeRefSectionContents);
|
||||
|
||||
const GenericSection TypeRefSection {
|
||||
reinterpret_cast<const void *>(TypeRefSectionContents.begin()),
|
||||
reinterpret_cast<const void *>(TypeRefSectionContents.end())
|
||||
};
|
||||
|
||||
InProcessMemoryReader Reader;
|
||||
ReflectionContext<External<RuntimeTarget<8>>> RC(Reader);
|
||||
RC.addReflectionInfo({
|
||||
BinaryFilename,
|
||||
fieldSection,
|
||||
associatedTypeSection,
|
||||
ReflectionStringsSection,
|
||||
TypeRefSection,
|
||||
});
|
||||
RC.dumpAllSections(std::cout);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename Runtime>
|
||||
struct Section {
|
||||
@@ -255,9 +81,11 @@ struct RemoteReflectionInfo {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
template <typename Runtime>
|
||||
class PipeMemoryReader : public MemoryReader {
|
||||
using StoredPointer = typename Runtime::StoredPointer;
|
||||
using StoredSize = typename Runtime::StoredSize;
|
||||
|
||||
static constexpr size_t ReadEnd = 0;
|
||||
static constexpr size_t WriteEnd = 1;
|
||||
@@ -318,7 +146,7 @@ public:
|
||||
StoredPointer TargetAddress = (StoredPointer)Address;
|
||||
write(getParentWriteFD(), REQUEST_READ_BYTES, 2);
|
||||
write(getParentWriteFD(), &TargetAddress, sizeof(TargetAddress));
|
||||
write(getParentWriteFD(), &Size, sizeof(Size));
|
||||
write(getParentWriteFD(), &Size, sizeof(StoredSize));
|
||||
collectBytesFromPipe(Dest, Size);
|
||||
return true;
|
||||
}
|
||||
@@ -360,16 +188,16 @@ public:
|
||||
|
||||
std::vector<ReflectionInfo> receiveReflectionInfo() {
|
||||
write(getParentWriteFD(), REQUEST_REFLECTION_INFO, 2);
|
||||
uint64_t NumReflectionInfos = 0;
|
||||
StoredSize NumReflectionInfos = 0;
|
||||
collectBytesFromPipe(&NumReflectionInfos, sizeof(NumReflectionInfos));
|
||||
|
||||
std::vector<RemoteReflectionInfo<Runtime>> RemoteInfos;
|
||||
for (uint64_t i = 0; i < NumReflectionInfos; ++i) {
|
||||
uint64_t ImageNameLength;
|
||||
for (StoredSize i = 0; i < NumReflectionInfos; ++i) {
|
||||
StoredSize ImageNameLength;
|
||||
collectBytesFromPipe(&ImageNameLength, sizeof(ImageNameLength));
|
||||
char c;
|
||||
std::string ImageName;
|
||||
for (uint64_t i = 0; i < ImageNameLength; ++i) {
|
||||
for (StoredSize i = 0; i < ImageNameLength; ++i) {
|
||||
collectBytesFromPipe(&c, 1);
|
||||
ImageName.push_back(c);
|
||||
}
|
||||
@@ -456,6 +284,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Runtime>
|
||||
static int doDumpHeapInstance(std::string BinaryFilename) {
|
||||
using StoredPointer = typename Runtime::StoredPointer;
|
||||
@@ -487,8 +316,8 @@ static int doDumpHeapInstance(std::string BinaryFilename) {
|
||||
|
||||
StoredPointer instance = Pipe.receiveInstanceAddress();
|
||||
assert(instance);
|
||||
std::cerr << "Parent: instance pointer in child address space: 0x";
|
||||
std::cerr << std::hex << instance << std::endl;
|
||||
std::cout << "Parent: instance pointer in child address space: 0x";
|
||||
std::cout << std::hex << instance << std::endl;
|
||||
|
||||
StoredPointer isa;
|
||||
if (!Pipe.readInteger(instance, &isa))
|
||||
@@ -497,17 +326,17 @@ static int doDumpHeapInstance(std::string BinaryFilename) {
|
||||
for (auto &Info : Pipe.receiveReflectionInfo())
|
||||
RC.addReflectionInfo(Info);
|
||||
|
||||
std::cerr << "Parent: metadata pointer in child address space: 0x";
|
||||
std::cerr << std::hex << isa << std::endl;
|
||||
std::cout << "Parent: metadata pointer in child address space: 0x";
|
||||
std::cout << std::hex << isa << std::endl;
|
||||
|
||||
std::cerr << "Decoding type reference ..." << std::endl;
|
||||
std::cout << "Decoding type reference ..." << std::endl;
|
||||
auto TR = RC.getTypeRef(isa);
|
||||
TR->dump();
|
||||
TR->dump(std::cout, 0);
|
||||
|
||||
auto Fields = RC.getFieldTypeRefs(isa);
|
||||
for (auto &Field : Fields) {
|
||||
std::cout << Field.first << ":\n";
|
||||
Field.second->dump();
|
||||
Field.second->dump(std::cout , 0);
|
||||
// TODO: Print field layout here.
|
||||
std::cout << std::endl;
|
||||
}
|
||||
@@ -519,14 +348,19 @@ static int doDumpHeapInstance(std::string BinaryFilename) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void printUsageAndExit() {
|
||||
std::cerr << "swift-reflection-test <arch> <binary filename>" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Reflection Test\n");
|
||||
switch (options::Action) {
|
||||
case ActionType::DumpReflectionSections:
|
||||
return doDumpReflectionSections(options::BinaryFilename,
|
||||
options::Architecture);
|
||||
case ActionType::DumpHeapInstance: {
|
||||
StringRef arch = options::Architecture;
|
||||
|
||||
if (argc != 3)
|
||||
printUsageAndExit();
|
||||
|
||||
std::string arch(argv[1]);
|
||||
std::string BinaryFilename(argv[2]);
|
||||
|
||||
unsigned PointerSize = 0;
|
||||
if (arch == "x86_64")
|
||||
PointerSize = 8;
|
||||
@@ -542,13 +376,7 @@ int main(int argc, char *argv[]) {
|
||||
errorAndExit("Unsupported architecture");
|
||||
|
||||
if (PointerSize == 4)
|
||||
return doDumpHeapInstance<External<RuntimeTarget<4>>>(options::BinaryFilename);
|
||||
return doDumpHeapInstance<External<RuntimeTarget<4>>>(BinaryFilename);
|
||||
else
|
||||
return doDumpHeapInstance<External<RuntimeTarget<8>>>(options::BinaryFilename);
|
||||
}
|
||||
case ActionType::None:
|
||||
llvm::cl::PrintHelpMessage();
|
||||
return EXIT_FAILURE;
|
||||
break;
|
||||
}
|
||||
return doDumpHeapInstance<External<RuntimeTarget<8>>>(BinaryFilename);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ config.swift_obj_root = "@SWIFT_BINARY_DIR@"
|
||||
config.target_triple = "@TARGET_TRIPLE@"
|
||||
config.targets_to_build = "@TARGETS_TO_BUILD@"
|
||||
config.variant_triple = "@VARIANT_TRIPLE@"
|
||||
config.variant_suffix = "@VARIANT_SUFFIX@"
|
||||
config.variant_sdk = "@VARIANT_SDK@"
|
||||
config.darwin_xcrun_toolchain = "@SWIFT_DARWIN_XCRUN_TOOLCHAIN@"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user