Skip to content

Commit ad0a8d3

Browse files
authored
Merge pull request #31468 from mikeash/swiftdt
[Tools] Create swift-inspect, a debugging tool for dumping Swift runtime data from another process
2 parents 5342444 + 2a55b9d commit ad0a8d3

36 files changed

+1478
-73
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "swift/Remote/MemoryReader.h"
2828
#include "swift/Remote/MetadataReader.h"
2929
#include "swift/Reflection/Records.h"
30+
#include "swift/Reflection/RuntimeInternals.h"
3031
#include "swift/Reflection/TypeLowering.h"
3132
#include "swift/Reflection/TypeRef.h"
3233
#include "swift/Reflection/TypeRefBuilder.h"
@@ -104,7 +105,10 @@ class ReflectionContext
104105
using super::readMetadataAndValueOpaqueExistential;
105106
using super::readMetadataFromInstance;
106107
using super::readTypeFromMetadata;
108+
using super::stripSignedPointer;
107109
using typename super::StoredPointer;
110+
using typename super::StoredSignedPointer;
111+
using typename super::StoredSize;
108112

109113
explicit ReflectionContext(std::shared_ptr<MemoryReader> reader)
110114
: super(std::move(reader), *this)
@@ -768,6 +772,156 @@ class ReflectionContext
768772
}
769773
}
770774

775+
/// Iterate the protocol conformance cache tree rooted at NodePtr, calling
776+
/// Call with the type and protocol in each node.
777+
void iterateConformanceTree(StoredPointer NodePtr,
778+
std::function<void(StoredPointer Type, StoredPointer Proto)> Call) {
779+
if (!NodePtr)
780+
return;
781+
auto NodeBytes = getReader().readBytes(RemoteAddress(NodePtr), sizeof(Node));
782+
auto NodeData =
783+
reinterpret_cast<const ConformanceNode<Runtime> *>(NodeBytes.get());
784+
if (!NodeData)
785+
return;
786+
Call(NodeData->Type, NodeData->Proto);
787+
iterateConformanceTree(NodeData->Left, Call);
788+
iterateConformanceTree(NodeData->Right, Call);
789+
}
790+
791+
/// Iterate the protocol conformance cache in the target process, calling Call
792+
/// with the type and protocol of each conformance. Returns None on success,
793+
/// and a string describing the error on failure.
794+
llvm::Optional<std::string> iterateConformances(
795+
std::function<void(StoredPointer Type, StoredPointer Proto)> Call) {
796+
std::string ConformancesPointerName =
797+
"__swift_debug_protocolConformanceStatePointer";
798+
auto ConformancesAddrAddr =
799+
getReader().getSymbolAddress(ConformancesPointerName);
800+
if (!ConformancesAddrAddr)
801+
return "unable to look up debug variable " + ConformancesPointerName;
802+
803+
auto ConformancesAddr =
804+
getReader().readPointer(ConformancesAddrAddr, sizeof(StoredPointer));
805+
if (!ConformancesAddr)
806+
return "unable to read value of " + ConformancesPointerName;
807+
808+
auto Root = getReader().readPointer(ConformancesAddr->getResolvedAddress(),
809+
sizeof(StoredPointer));
810+
iterateConformanceTree(Root->getResolvedAddress().getAddressData(), Call);
811+
return llvm::None;
812+
}
813+
814+
/// Fetch the metadata pointer from a metadata allocation, or 0 if this
815+
/// allocation's tag is not handled or an error occurred.
816+
StoredPointer allocationMetadataPointer(
817+
MetadataAllocation<Runtime> Allocation) {
818+
if (Allocation.Tag == GenericMetadataCacheTag) {
819+
struct GenericMetadataCacheEntry {
820+
StoredPointer Left, Right;
821+
StoredPointer LockedStorage;
822+
uint8_t LockedStorageKind;
823+
uint8_t TrackingInfo;
824+
uint16_t NumKeyParameters;
825+
uint16_t NumWitnessTables;
826+
uint32_t Hash;
827+
StoredPointer Value;
828+
};
829+
auto AllocationBytes =
830+
getReader().readBytes(RemoteAddress(Allocation.Ptr),
831+
Allocation.Size);
832+
auto Entry = reinterpret_cast<const GenericMetadataCacheEntry *>(
833+
AllocationBytes.get());
834+
if (!Entry)
835+
return 0;
836+
return Entry->Value;
837+
}
838+
return 0;
839+
}
840+
841+
/// Iterate the metadata allocations in the target process, calling Call with
842+
/// each allocation found. Returns None on success, and a string describing
843+
/// the error on failure.
844+
llvm::Optional<std::string> iterateMetadataAllocations(
845+
std::function<void (MetadataAllocation<Runtime>)> Call) {
846+
std::string IterationEnabledName =
847+
"__swift_debug_metadataAllocationIterationEnabled";
848+
std::string AllocationPoolPointerName =
849+
"__swift_debug_allocationPoolPointer";
850+
851+
auto IterationEnabledAddr =
852+
getReader().getSymbolAddress(IterationEnabledName);
853+
if (!IterationEnabledAddr)
854+
return "unable to look up debug variable " + IterationEnabledName;
855+
char IterationEnabled;
856+
if (!getReader().readInteger(IterationEnabledAddr, &IterationEnabled))
857+
return "failed to read value of " + IterationEnabledName;
858+
if (!IterationEnabled)
859+
return std::string("remote process does not have metadata allocation "
860+
"iteration enabled");
861+
862+
auto AllocationPoolAddrAddr =
863+
getReader().getSymbolAddress(AllocationPoolPointerName);
864+
if (!AllocationPoolAddrAddr)
865+
return "unable to look up debug variable " + AllocationPoolPointerName;
866+
auto AllocationPoolAddr =
867+
getReader().readPointer(AllocationPoolAddrAddr, sizeof(StoredPointer));
868+
if (!AllocationPoolAddr)
869+
return "failed to read value of " + AllocationPoolPointerName;
870+
871+
struct PoolRange {
872+
StoredPointer Begin;
873+
StoredSize Remaining;
874+
};
875+
struct PoolTrailer {
876+
StoredPointer PrevTrailer;
877+
StoredSize PoolSize;
878+
};
879+
struct alignas(StoredPointer) AllocationHeader {
880+
uint16_t Size;
881+
uint16_t Tag;
882+
};
883+
884+
auto PoolBytes = getReader()
885+
.readBytes(AllocationPoolAddr->getResolvedAddress(), sizeof(PoolRange));
886+
auto Pool = reinterpret_cast<const PoolRange *>(PoolBytes.get());
887+
if (!Pool)
888+
return std::string("failure reading allocation pool contents");
889+
890+
auto TrailerPtr = Pool->Begin + Pool->Remaining;
891+
while (TrailerPtr) {
892+
auto TrailerBytes = getReader()
893+
.readBytes(RemoteAddress(TrailerPtr), sizeof(PoolTrailer));
894+
auto Trailer = reinterpret_cast<const PoolTrailer *>(TrailerBytes.get());
895+
if (!Trailer)
896+
break;
897+
auto PoolStart = TrailerPtr - Trailer->PoolSize;
898+
auto PoolBytes = getReader()
899+
.readBytes(RemoteAddress(PoolStart), Trailer->PoolSize);
900+
auto PoolPtr = (const char *)PoolBytes.get();
901+
if (!PoolPtr)
902+
break;
903+
904+
uintptr_t Offset = 0;
905+
while (Offset < Trailer->PoolSize) {
906+
auto AllocationPtr = PoolPtr + Offset;
907+
auto Header = (const AllocationHeader *)AllocationPtr;
908+
if (Header->Size == 0)
909+
break;
910+
auto RemoteAddr = PoolStart + Offset + sizeof(AllocationHeader);
911+
MetadataAllocation<Runtime> Allocation;
912+
Allocation.Tag = Header->Tag;
913+
Allocation.Ptr = RemoteAddr;
914+
Allocation.Size = Header->Size;
915+
Call(Allocation);
916+
917+
Offset += sizeof(AllocationHeader) + Header->Size;
918+
}
919+
920+
TrailerPtr = Trailer->PrevTrailer;
921+
}
922+
return llvm::None;
923+
}
924+
771925
private:
772926
const TypeInfo *getClosureContextInfo(StoredPointer Context,
773927
const ClosureContextInfo &Info) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===--- RuntimeInternals.h - Runtime Internal Structures -------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Runtime data structures that Reflection inspects externally.
14+
//
15+
// FIXME: Ideally the original definitions would be templatized on a Runtime
16+
// parameter and we could use the original definitions in both the runtime and
17+
// in Reflection.
18+
//
19+
//===----------------------------------------------------------------------===//
20+
21+
#ifndef SWIFT_REFLECTION_RUNTIME_INTERNALS_H
22+
#define SWIFT_REFLECTION_RUNTIME_INTERNALS_H
23+
24+
namespace swift {
25+
26+
namespace reflection {
27+
28+
template <typename Runtime>
29+
struct ConformanceNode {
30+
typename Runtime::StoredPointer Left, Right;
31+
typename Runtime::StoredPointer Type;
32+
typename Runtime::StoredPointer Proto;
33+
typename Runtime::StoredPointer Description;
34+
typename Runtime::StoredSize FailureGeneration;
35+
};
36+
37+
template <typename Runtime>
38+
struct MetadataAllocation {
39+
uint16_t Tag;
40+
typename Runtime::StoredPointer Ptr;
41+
unsigned Size;
42+
};
43+
44+
} // end namespace reflection
45+
} // end namespace swift
46+
47+
#endif // SWIFT_REFLECTION_RUNTIME_INTERNALS_H

include/swift/Remote/MetadataReader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,6 +2192,8 @@ class MetadataReader {
21922192
readMangledName(RemoteAddress(extendedContextAddress),
21932193
MangledNameKind::Type,
21942194
dem);
2195+
if (!demangledExtendedContext)
2196+
return nullptr;
21952197

21962198
auto demangling = dem.createNode(Node::Kind::Extension);
21972199
demangling->addChild(parentDemangling, dem);

include/swift/Runtime/Debug.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,14 @@ bool _swift_reportFatalErrorsToDebugger;
231231
SWIFT_RUNTIME_STDLIB_SPI
232232
bool _swift_shouldReportFatalErrorsToDebugger();
233233

234+
SWIFT_RUNTIME_STDLIB_SPI
235+
bool _swift_debug_metadataAllocationIterationEnabled;
236+
237+
SWIFT_RUNTIME_STDLIB_SPI
238+
const void * const _swift_debug_allocationPoolPointer;
239+
240+
SWIFT_RUNTIME_STDLIB_SPI
241+
const void * const _swift_debug_protocolConformanceStatePointer;
234242

235243
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
236244
inline static int swift_asprintf(char **strp, const char *fmt, ...) {

include/swift/Runtime/Metadata.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,35 @@ namespace swift {
2525
#pragma clang diagnostic push
2626
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
2727

28+
// Tags used to denote different kinds of allocations made with the metadata
29+
// allocator. This is encoded in a header on each allocation when metadata
30+
// iteration is enabled, and allows tools to know where each allocation came
31+
// from.
32+
//
33+
// Some of these values are also declared in SwiftRemoteMirrorTypes.h. Those
34+
// values must be kept stable to preserve compatibility.
35+
enum MetadataAllocatorTags : uint16_t {
36+
UnusedTag = 0,
37+
BoxesTag,
38+
ObjCClassWrappersTag,
39+
FunctionTypesTag,
40+
MetatypeTypesTag,
41+
ExistentialMetatypeValueWitnessTablesTag,
42+
ExistentialMetatypesTag,
43+
ExistentialTypesTag,
44+
OpaqueExistentialValueWitnessTablesTag,
45+
ClassExistentialValueWitnessTablesTag,
46+
ForeignWitnessTablesTag,
47+
ResilientMetadataAllocatorTag,
48+
MetadataTag,
49+
TupleCacheTag,
50+
GenericMetadataCacheTag,
51+
ForeignMetadataCacheTag,
52+
GenericWitnessTableCacheTag,
53+
GenericClassMetadataTag,
54+
GenericValueMetadataTag,
55+
};
56+
2857
/// The buffer used by a yield-once coroutine (such as the generalized
2958
/// accessors `read` and `modify`).
3059
struct YieldOnceBuffer {

include/swift/SwiftRemoteMirror/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ list(APPEND swift_remote_mirror_headers
33
MemoryReaderInterface.h
44
Platform.h
55
SwiftRemoteMirror.h
6-
SwiftRemoteMirrorTypes.h)
6+
SwiftRemoteMirrorTypes.h
7+
module.modulemap)
78
swift_install_in_component(FILES
89
${swift_remote_mirror_headers}
910
DESTINATION

include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ char *
159159
swift_reflection_copyDemangledNameForTypeRef(
160160
SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef);
161161

162+
SWIFT_REMOTE_MIRROR_LINKAGE
163+
char *
164+
swift_reflection_copyDemangledNameForProtocolDescriptor(
165+
SwiftReflectionContextRef ContextRef, swift_reflection_ptr_t Proto);
166+
162167
/// Returns a structure describing the layout of a value of a typeref.
163168
/// For classes, this returns the reference value itself.
164169
SWIFT_REMOTE_MIRROR_LINKAGE
@@ -283,6 +288,49 @@ SWIFT_REMOTE_MIRROR_LINKAGE
283288
size_t swift_reflection_demangle(const char *MangledName, size_t Length,
284289
char *OutDemangledName, size_t MaxLength);
285290

291+
/// Iterate over the process's protocol conformance cache.
292+
///
293+
/// Calls the passed in Call function for each protocol conformance found in
294+
/// the conformance cache. The function is passed the type which conforms and
295+
/// the protocol it conforms to. The ContextPtr is passed through unchanged.
296+
///
297+
/// Returns NULL on success. On error, returns a pointer to a C string
298+
/// describing the error. This pointer remains valid until the next
299+
/// swift_reflection call on the given context.
300+
SWIFT_REMOTE_MIRROR_LINKAGE
301+
const char *swift_reflection_iterateConformanceCache(
302+
SwiftReflectionContextRef ContextRef,
303+
void (*Call)(swift_reflection_ptr_t Type,
304+
swift_reflection_ptr_t Proto,
305+
void *ContextPtr),
306+
void *ContextPtr);
307+
308+
/// Iterate over the process's metadata allocations.
309+
///
310+
/// Calls the passed in Call function for each metadata allocation. The function
311+
/// is passed a structure that describes the allocation. The ContextPtr is
312+
/// passed through unchanged.
313+
///
314+
/// Returns NULL on success. On error, returns a pointer to a C string
315+
/// describing the error. This pointer remains valid until the next
316+
/// swift_reflection call on the given context.
317+
SWIFT_REMOTE_MIRROR_LINKAGE
318+
const char *swift_reflection_iterateMetadataAllocations(
319+
SwiftReflectionContextRef ContextRef,
320+
void (*Call)(swift_metadata_allocation_t Allocation,
321+
void *ContextPtr),
322+
void *ContextPtr);
323+
324+
/// Given a metadata allocation, return the metadata it points to. Returns NULL
325+
/// on failure. Despite the name, not all allocations point to metadata.
326+
/// Currently, this will return a metadata only for allocations with tag
327+
/// SWIFT_GENERIC_METADATA_CACHE_ALLOCATION. Support for additional tags may be
328+
/// added in the future. The caller must gracefully handle failure.
329+
SWIFT_REMOTE_MIRROR_LINKAGE
330+
swift_reflection_ptr_t swift_reflection_allocationMetadataPointer(
331+
SwiftReflectionContextRef ContextRef,
332+
swift_metadata_allocation_t Allocation);
333+
286334
#ifdef __cplusplus
287335
} // extern "C"
288336
#endif

include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,27 @@ typedef struct swift_childinfo {
141141
swift_typeref_t TR;
142142
} swift_childinfo_t;
143143

144+
// Values here match the values from MetadataAllocatorTags in Metadata.h.
145+
enum swift_metadata_allocation_tag {
146+
SWIFT_GENERIC_METADATA_CACHE_ALLOCATION = 14,
147+
};
148+
149+
typedef int swift_metadata_allocation_tag_t;
150+
151+
/// A metadata allocation made by the Swift runtime.
152+
typedef struct swift_metadata_allocation {
153+
/// The allocation's tag, which describes what kind of allocation it is. This
154+
/// may be one of the values in swift_metadata_allocation_tag, or something
155+
/// else, in which case the tag should be considered unknown.
156+
swift_metadata_allocation_tag_t Tag;
157+
158+
/// A pointer to the start of the allocation in the remote process.
159+
swift_reflection_ptr_t Ptr;
160+
161+
/// The size of the allocation in bytes.
162+
unsigned Size;
163+
} swift_metadata_allocation_t;
164+
144165
/// An opaque pointer to a context which maintains state and
145166
/// caching of reflection structure for heap instances.
146167
typedef struct SwiftReflectionContext *SwiftReflectionContextRef;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module SwiftRemoteMirror {
2+
header "SwiftRemoteMirror.h"
3+
export *
4+
}

lib/Demangling/Remangler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ class Remangler : public RemanglerBase {
268268
}
269269

270270
void mangleChildNode(Node *node, unsigned index) {
271-
assert(index < node->getNumChildren());
272-
mangle(node->begin()[index]);
271+
if (index < node->getNumChildren())
272+
mangle(node->begin()[index]);
273273
}
274274

275275
void manglePureProtocol(Node *Proto) {

0 commit comments

Comments
 (0)