We remove the existing `swift_reflection_iterateAsyncTaskAllocations` API that attempts to provide all necessary information about a tasks's allocations starting from the task. Instead, we split it into two pieces: `swift_reflection_asyncTaskSlabPointer` to get the first slab for a task, and `+swift_reflection_asyncTaskSlabAllocations` to get the allocations in a slab, and a pointer to the next slab.
We also add a dummy metadata pointer to the beginning of each slab. This allows tools to identify slab allocations on the heap without needing to locate every single async task object. They can then use `swift_reflection_asyncTaskSlabAllocations` on such allocations to find out about the contents.
rdar://82549631
We remove the existing `swift_reflection_iterateAsyncTaskAllocations` API that attempts to provide all necessary information about a tasks's allocations starting from the task. Instead, we split it into two pieces: `swift_reflection_asyncTaskSlabPointer` to get the first slab for a task, and `+swift_reflection_asyncTaskSlabAllocations` to get the allocations in a slab, and a pointer to the next slab.
We also add a dummy metadata pointer to the beginning of each slab. This allows tools to identify slab allocations on the heap without needing to locate every single async task object. They can then use `swift_reflection_asyncTaskSlabAllocations` on such allocations to find out about the contents.
rdar://82549631
We were missing a Status field. The reflect_task test didn't catch this becasue it was reading LastAllocation as FirstSlab, which still worked well enough in that context.
rdar://81427584
Added a counterpart to the swift_reflection_projectEnumValue() API for the
legacy interop support in SwiftRemoteMirrorLegacyInterop.h.
Also updated the test to use it to extract information from an enum.
rdar://62128103
Fix the declaration of AsyncTask and add a test for iterateAsyncTaskAllocations. Reflection's declaration of AsyncTask had fallen out of sync with the real thing. The test that was supposed to catch this was never actually committed, oops.
Add a swift_reflection_libraryVersion variable to Remote Mirror to indicate the presence of this fix. In the future, the value can be incremented to signal the presence of other changes that can't otherwise be detected.
rdar://80035307
This will allow the heap tool to work out which binary a dynamically allocated
class comes from, by looking up its nominal type descriptor address and then
seeing which binary contains that.
Fixes rdar://65742351.
Implement a version of projectExistential tailored for LLDB. There are 2
differences when projecting existentials for LLDB:
1 - When it comes to existentials, LLDB stores the address of the error
pointer, which must be dereferenced.
2 - When the existential wraps a class type, LLDB expects the address
returned is the class instance itself and not the address of the
reference.
This patch also adapts the swift reflection test machinery to test
projectExistentialAndUnwrapClass as well. This is done by exposing
the new functionality from swift reflection test. It is tested in
existentials.swift, and ensures that the typeref information is
exactly the same as what is expected from projectExistential,
except the out address.
(cherry picked from commit 55e971e06750c3ba29722d558cc5400298f6bdaf)
This code rearchitects and simplifies the projectEnumValue support by
introducing a new `TypeInfo` subclass for each kind of enum, including trivial,
no-payload, single-payload, and three different classes for multi-payload enums:
* "UnsupportedEnum" that we don't understand. This returns "don't know" answers for all requests in cases where the runtime lacks enough information to accurately handle a particular enum.
* MP Enums that only use a separate tag value. This includes generic enums and other dynamic layouts, as well as enums whose payloads have no spare bits.
* MP Enums that use spare bits, possibly in addition to a separate tag. This logic can only be used, of course, if we can in fact compute a spare bit mask that agrees with the compiler.
The final challenge is to choose one of the above three handlings for every MPE. Currently, we do not have an accurate source of information for the spare bit mask, so we never choose the third option above. We use the second option for dynamic MPE layouts (including generics) and the first for everything else.
TODO: Once we can arrange for the compiler to expose spare bit mask data, we'll be able to use that to drive more MPE cases.
ownsAddress was a simple range check on images, but that won't find Metadatas that get allocated on the heap. If an address isn't found, try reading it as a Metadata and doing a range check on the type context descriptor too.
rdar://problem/60981575
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>
TypeRefBuilder and MetadataReader had nearly identical symbolic reference resolvers,
but diverged because TypeRefBuilder had its own local/remote address management mechanism,
and because TypeRefBuilder tries to resolve opaque types to their underlying types, whereas
other MetadataReader clients want to preserve them as written in source. The first problem
has been addressed by making TypeRefBuilder use `RemoteRef` everywhere, and the second
can be handled with a flag (and might be able to be handled more elegantly with some more
refactoring of general opaque type handling in MetadataReader).
Instead of passing around raw local pointers and references, and spreading
tricky offset arithmetic around with the Local/RemoteAddress fields in
ReflectionInfo, have the TypeRefBuilder code use RemoteRefs everywhere,
which keep the remote/local mapping together in one unit and provide
centralized API for this logic.
This doesn't yet change how code uses the RemoteRef address data to
follow pointers across objects, for things like reading type refs, but
that should be much easier to do after this lands.
These are now always zero, because memory readers handle virtual address mapping.
The `swift_reflection_info_t` structure used by the C RemoteMirror API keeps
its offset fields because it's supposed to be a stable API, but we now assert that
the values are always zero.
Remote Mirror added a new callback, QueryDataLayoutFunction, which provides a nicer and more extensible way to provide things like the target pointer size. Add support for that in the interop header. Search for and call the new creation function when it exists, and shim in support for older libraries that don't have it.
rdar://problem/52849572
While we're in there, make SwiftReflectionTest's debugLog function take an @autoclosure so we don't waste a ton of time constructing log messages that are never logged.
Existing Remote Mirror dylibs are compiled this way, and changing it breaks binary compatibility. We want to use uint64_t everywhere else, since the target's pointer size may not match ours.
rdar://problem/50279443
Weak import semantics are not available on PE/COFF. Ensure that we do not mark
the type as having weak import semantics. Otherwise, the dllimport'ed symbol is
marked as `dso_local` which is invalid.
Also have swift-reflection-test check if the symbol exists. This allows swift-reflection-test to work with older Remote Mirror dylibs that don't have it.
rdar://problem/50030805
CMake supports the notion of installation components. Right now we have some
custom code for supporting swift components. I think that for installation
purposes, it would be nice to use the CMake component system.
This should be a non-functional change. We should still only be generating
install rules for targets and files in components we want to install, and we
still use the install ninja target to install everything.
This symbol is meant to be exposed to users of the SwiftRemoteMirror
library which requires that it is explicitly marked with the appropriate
DLL storage on Windows. This should repair the Windows build.
Recent Swift uses 2 as the is-Swift bit when running on newer versions, and 1 on older versions. Since it's difficult or impossible to know what we'll be running on at build time, make the selection at runtime.
When compiling for a 32 bit machine, uintptr_t from ReflectionInfo will
be the integer sized to hold a 32 bit pointer, so a 64 bit pointer might
not fit.
This commit removes the solution in
0f20c486e0 and does a runtime check that
the calculated offset will fit into the target machine uintptr_t, which
might not be true for 32 bits machines trying to read 64 bits images,
which should not be that common (and those images have to have offsets
bigger than what a 32 bits number can hold).