* First part of multi-payload enum support
This handles multi-payload enums with fixed
layouts that don't use spare payload bits.
It includes XI calculations that allow us to
handle single-payload enums where the payload
ultimately includes a multi-payload enum
(For example, on 32-bit platforms, String uses
a multi-payload enum, so this now supports single-payload
enums carrying Strings.)
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>
As the base of the "remote" address space ObjectMemoryReader presents for an image, use the
image's own preferred VM address mappings. If there are multiple images loaded, differentiate
them by using the top 16 bits of the remote address space as an index into the array of images.
This should make it so that absolute pointers in the file Just Work without sliding in most
cases; we'd only need to mix in the image index in order to have a value that is also a valid
remote address.
Pointer data in some remote reflection targets may required relocation, or may not be
fully resolvable, such as when we're dumping info from a single image on disk that
references other dynamic libraries. Add a `RemoteAbsolutePointer` type that can hold a
symbol, offset, or combination of both, and add APIs to `MemoryReader` and `MetadataReader`
for reading pointers that can get unresolved relocation info from an image, or apply
relocations to pointer information. MetadataReader can use the symbol name information to
fill in demanglings of symbolic-reference-bearing mangled names by using the information
from the symbol name to fill in the name even though the context descriptors are not
available.
For now, this is NFC (MemoryReader::resolvePointer just forwards the pointer data), but
lays the groundwork for implementation of relocation in ObjectMemoryReader.
This removes it from the AST and largely replaces it with AnyObject
at the SIL and IRGen layers. Some notes:
- Reflection still uses the notion of "unknown object" to mean an
object with unknown refcounting. There's no real reason to make
this different from AnyObject (an existential containing a
single object with unknown refcounting), but this way nothing
changes for clients of Reflection, and it's consistent with how
native objects are represented.
- The value witness table and reflection descriptor for AnyObject
use the mangling "BO" instead of "yXl".
- The demangler and remangler continue to support "BO" because it's
still in use as a type encoding, even if it's not an AST-level
Type anymore.
- Type-based alias analysis for Builtin.UnknownObject was incorrect,
so it's a good thing we weren't using it.
- Same with enum layout. (This one assumed UnknownObject never
referred to an Objective-C tagged pointer. That certainly wasn't how
we were using it!)
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.
In principle, swift-reflection-* ought to work with cross-compiled binaries. Dispatch out to reading
MachO, PE, or ELF section metadata based on the magic of an image passed to `addImage` instead of
using #ifs to pick an implementation based on the host platform. (This still doesn't fully address
other host/target differences like word size or endianness, but is progress toward making the tool
target-agnostic.)
This makes for a cleaner and less implicit-context-heavy API, and makes it easier for symbolic
reference resolvers to do context-dependent things (like map the in-memory base address back to a
remote address in MetadataReader).
If a Mach-O image got emitted in just the wrong way, the range of `__TEXT,__swift*` sections to
read could end up starting at an unaligned address (because things like type refs have only one
byte alignment), and this would cause the reflection context to read an unaligned chunk of the
remote memory, causing alignment errors when addresses are mapped to the local copy. Keep the ranges
at least 8-byte-aligned to stave off the alignment issues we might run into with any metadata
structures, which are generally at most pointer aligned. Fixes rdar://problem/54556791
NOTE: I used YAMLIO to simplify dumping this information which required me to
use llvm::outs() instead of std::cout like the rest of libReflection. We really
should remove std::cout from libReflection (iostream is a smell we try to avoid
generally). As a result, there is a little bit of finagling in the commit to
work around flushing issues with respect to use llvm::outs(), std::cout... but
it isn't too bad overall.
Previously when ReflectionContext was parsing the image of a binary
(for ELF or COFF) it was making some incorrect assumptions about the location
of sections in the memory of a remote process. In particular, it was using the offsets
rather than the virtual addresses and it was incorrectly calculating the references (relative pointers)
inside the metadata. In this diff we address these issues and adjust swift-reflection-dump
(used in tests) to emulate the runtime behavior more closely.
This diff has been extensively tested, the reflection tests are green on OSX and Linux,
on Windows it fixes 2 new tests:
Reflection/typeref_decoding.swift
stdlib/ReflectionHashing.swift
So now (with some minor fixes to the lit testsing infrastructure) the following reflection
tests pass:
Reflection/box_descriptors.sil
Reflection/capture_descriptors.sil
Reflection/typeref_decoding.swift
stdlib/ReflectionHashing.swift
When we inspect a binary, verify that it is a PE/COFF binary before
trying to interpret it as a PE/COFF binary. This prepares the code
for extraction of the file inspection and will permit cross-platform
builds to introspect foreign binaries.
In this diff we add first bits to make reflection work on Windows,
in particular, properly extract the metadata from the corresponding sections.
With this diff box_descriptors.sil and capture_descriptors.sil start passing on Windows
after some minor tweaks to the lit testing infrastructure.
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).
Split the addImage method for ELF into two branches for ELF32 and for
ELF64 depending on the value stored in the identifier of the image.
Most of the code of the previous function moves into readELFSections,
which is build similar to the already existing readMachOSections. The
code is only modified to use the types from the template parameter.
This fixes a couple of reflection tests in Android armv7 (and I suppose
it should also fix the same problem in other 32 bits platforms which use
ELF).
An Error existential value can directly store a
reference to an NSError instance without wrapping
it in an Error container.
When "projecting" such an existential, the dynamic type
is the NSError's isa pointer, and the payload is the
address of the instance itself.
Bitwise takability is now part of the layout of a type, because
non-bitwise takable types are never stored inline in an
existential or resilient global's buffer, even if they would
fit.
The basic rule is that weak references, unknown-refcounted
unowned references, and aggregates that contain them, are not
bitwise takable, whereas everything else is bitwise takable.
Also, since the bitwise takable for an unowned reference
depends on the reference counting style, we have to record the
superclass of a protocol, if any, to correctly determine the
reference counting style of the protocol existential.
This comes back to the older approach of mapping all __TEXT, as
taking in account the delta between sections seems a little too
complicated for now. Hopefully we'll be back optimizing this
once we're done with debugger integration.
<rdar://problem/42306551>
There are several problems fixed by this commit.
-> It removes the dependency on a system header.
-> It works when the pointer size for host and target don't match
(i.e. 32-bits/64-bits and viceversa)
-> It reads the file lazily, mapping only the sections that are
needed. The old approach mapped the whole __TEXT segment, causing
significant slowdowns when trying to integrate this API in the
debugger. Now it's almost instant (10 seconds vs milliseconds).
<rdar://problem/42306551>