Files
swift-mirror/include/swift/Remote/InProcessMemoryReader.h
tbkka 0d361bd3ea Teach RemoteMirror how to project enum values (#30161)
Teach RemoteMirror how to project enum values

This adds two new functions to the SwiftRemoteMirror
facility that support inspecting enum values.

Currently, these support non-payload enums and
single-payload enums, including nested enums and
payloads with struct, tuple, and reference payloads.
In particular, it handles nested `Optional` types.

TODO: Multi-payload enums use different strategies for
encoding the cases that aren't yet supported by this
code.

Note: This relies on information from dataLayoutQuery
to correctly decode invalid pointer values that are used
to encode enums.  Existing clients will need to augment
their DLQ functions before using these new APIs.

Resolves rdar://59961527

```
/// Projects the value of an enum.
///
/// Takes the address and typeref for an enum and determines the
/// index of the currently-selected case within the enum.
///
/// Returns true iff the enum case could be successfully determined.
/// In particular, note that this code may fail for valid in-memory data
/// if the compiler is using a strategy we do not yet understand.
SWIFT_REMOTE_MIRROR_LINKAGE
int swift_reflection_projectEnumValue(SwiftReflectionContextRef ContextRef,
                                      swift_addr_t EnumAddress,
                                      swift_typeref_t EnumTypeRef,
                                      uint64_t *CaseIndex);

/// Finds information about a particular enum case.
///
/// Given an enum typeref and index of a case, returns:
/// * Typeref of the associated payload or zero if there is no payload
/// * Name of the case if known.
///
/// The Name points to a freshly-allocated C string on the heap.  You
/// are responsible for freeing the string (via `free()`) when you are finished.
SWIFT_REMOTE_MIRROR_LINKAGE
int swift_reflection_getEnumCaseTypeRef(SwiftReflectionContextRef ContextRef,
                                        swift_typeref_t EnumTypeRef,
                                        unsigned CaseIndex,
                                        char **CaseName,
                                        swift_typeref_t *PayloadTypeRef);
```


Co-authored-by: Mike Ash <mikeash@apple.com>
2020-03-06 13:17:40 -08:00

102 lines
3.1 KiB
C++

//===--- InProcessMemoryReader.h - Access to local memory -------*- C++ -*-===//
//
// 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 file declares an abstract interface for working with remote memory.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_REMOTE_INPROCESSMEMORYREADER_H
#define SWIFT_REMOTE_INPROCESSMEMORYREADER_H
#include "swift/Remote/MemoryReader.h"
#include <cstring>
#if defined(__APPLE__) && defined(__MACH__)
#include <TargetConditionals.h>
#endif
namespace swift {
namespace remote {
/// An implementation of MemoryReader which simply reads from the current
/// address space.
class InProcessMemoryReader final : public MemoryReader {
bool queryDataLayout(DataLayoutQueryType type, void *inBuffer,
void *outBuffer) override {
#if defined(__APPLE__) && __APPLE__
auto applePlatform = true;
#else
auto applePlatform = false;
#endif
#if defined(__APPLE__) && __APPLE__ && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_IOS) && TARGET_OS_WATCH) || (defined(TARGET_OS_TV) && TARGET_OS_TV))
auto iosDerivedPlatform = true;
#else
auto iosDerivedPlatform = false;
#endif
switch (type) {
case DLQ_GetPointerSize: {
auto result = static_cast<uint8_t *>(outBuffer);
*result = sizeof(void *);
return true;
}
case DLQ_GetSizeSize: {
auto result = static_cast<uint8_t *>(outBuffer);
*result = sizeof(size_t);
return true;
}
case DLQ_GetObjCReservedLowBits: {
auto result = static_cast<uint8_t *>(outBuffer);
if (applePlatform && !iosDerivedPlatform && (sizeof(void *) == 8)) {
// Obj-C reserves low bit on 64-bit macOS only.
// Other Apple platforms don't reserve this bit (even when
// running on x86_64-based simulators).
*result = 1;
} else {
*result = 0;
}
return true;
}
case DLQ_GetLeastValidPointerValue: {
auto result = static_cast<uint64_t *>(outBuffer);
if (applePlatform && (sizeof(void *) == 8)) {
// Swift reserves the first 4GiB on Apple 64-bit platforms
*result = 0x100000000;
return 1;
} else {
// Swift reserves the first 4KiB everywhere else
*result = 0x1000;
}
return true;
}
}
return false;
}
RemoteAddress getSymbolAddress(const std::string &name) override;
bool readString(RemoteAddress address, std::string &dest) override {
dest = address.getLocalPointer<char>();
return true;
}
ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override {
return ReadBytesResult(address.getLocalPointer<void>(), [](const void *) {});
}
};
}
}
#endif